-
-
Notifications
You must be signed in to change notification settings - Fork 36
refactor: API-first positioning, Python client library, and tests #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
abhishek-anand
wants to merge
7
commits into
main
Choose a base branch
from
refactor-api-and-docs
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ba53ee7
refactor: API-first positioning and Python client library
abhishek-anand b2177b1
test: add unit tests and container best practices
abhishek-anand 87c161c
fix: graceful shutdown, refactor tests, and update install instructions
abhishek-anand ae745a3
Fix PR review issues: remove unused event, use specific exception
abhishek-anand c64db55
Add AI agents and cloud CLIs to container image
abhishek-anand b733e7c
Fix PR review issues: security and DRY
abhishek-anand cba73aa
fix: correct route ordering for deprecated session endpoints
abhishek-anand File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,38 @@ | ||
| sudo pkill -f container | ||
| #!/bin/bash | ||
| # | ||
| # CodeRunner Cleanup Script | ||
| # Gracefully stops containers and cleans up resources | ||
| # | ||
|
|
||
| echo "CodeRunner Cleanup" | ||
| echo "==================" | ||
|
|
||
| container system start | ||
| # Step 1: Try graceful stop of coderunner container | ||
| echo "→ Stopping coderunner container gracefully..." | ||
| container stop coderunner 2>/dev/null && echo " Stopped coderunner" || echo " coderunner not running" | ||
|
|
||
| # Wait for graceful shutdown | ||
| sleep 2 | ||
|
|
||
| container rm buildkit | ||
| # Step 2: Remove coderunner container if it still exists | ||
| echo "→ Removing coderunner container..." | ||
| container rm coderunner 2>/dev/null || true | ||
|
|
||
| # Step 3: Stop the container system | ||
| echo "→ Stopping container system..." | ||
| container system stop 2>/dev/null || true | ||
|
|
||
| # Step 4: Clean up buildkit if requested | ||
| if [ "$1" = "--full" ]; then | ||
| echo "→ Full cleanup: removing buildkit..." | ||
| container rm buildkit 2>/dev/null || true | ||
| fi | ||
|
|
||
| echo "" | ||
| echo "✅ Cleanup complete" | ||
| echo "" | ||
| echo "To restart CodeRunner:" | ||
| echo " ./install.sh" | ||
| echo "" | ||
| echo "For full cleanup (including buildkit):" | ||
| echo " ./cleanup.sh --full" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| """ | ||
| CodeRunner - Sandboxed Python execution for Mac. | ||
|
|
||
| Usage: | ||
| from coderunner import CodeRunner, execute | ||
|
|
||
| # Using the client | ||
| cr = CodeRunner() | ||
| result = cr.execute("print('hello')") | ||
| print(result.stdout) | ||
|
|
||
| # One-liner | ||
| print(execute("2 + 2")) | ||
| """ | ||
|
|
||
| from .client import CodeRunner, ExecutionResult, BrowserResult, execute | ||
|
|
||
| __all__ = ["CodeRunner", "ExecutionResult", "BrowserResult", "execute"] | ||
| __version__ = "0.1.0" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| """ | ||
| CodeRunner Python Client | ||
|
|
||
| Simple wrapper for the CodeRunner REST API. | ||
|
|
||
| Usage: | ||
| from coderunner import CodeRunner | ||
|
|
||
| cr = CodeRunner() # defaults to http://coderunner.local:8222 | ||
| result = cr.execute("print('hello')") | ||
| print(result.stdout) | ||
| """ | ||
|
|
||
| import httpx | ||
| from dataclasses import dataclass | ||
| from typing import Optional | ||
|
|
||
|
|
||
| @dataclass | ||
| class ExecutionResult: | ||
| """Result of code execution.""" | ||
| stdout: str | ||
| stderr: str | ||
| execution_time: float | ||
| success: bool | ||
|
|
||
|
|
||
| @dataclass | ||
| class BrowserResult: | ||
| """Result of browser content extraction.""" | ||
| content: str | ||
| url: str | ||
| success: bool | ||
| error: Optional[str] = None | ||
|
|
||
|
|
||
| class CodeRunner: | ||
| """ | ||
| Python client for CodeRunner API. | ||
|
|
||
| Args: | ||
| base_url: Server URL. Defaults to http://coderunner.local:8222 | ||
| timeout: Request timeout in seconds. Defaults to 300 (5 minutes). | ||
|
|
||
| Example: | ||
| >>> cr = CodeRunner() | ||
| >>> result = cr.execute("print('hello')") | ||
| >>> print(result.stdout) | ||
| hello | ||
| """ | ||
|
|
||
| def __init__( | ||
| self, | ||
| base_url: str = "http://coderunner.local:8222", | ||
| timeout: float = 300.0 | ||
| ): | ||
| self.base_url = base_url.rstrip("/") | ||
| self._client = httpx.Client(timeout=timeout) | ||
|
|
||
| def execute(self, code: str) -> ExecutionResult: | ||
| """ | ||
| Execute Python code and return result. | ||
|
|
||
| Args: | ||
| code: Python code to execute. | ||
|
|
||
| Returns: | ||
| ExecutionResult with stdout, stderr, execution_time, and success. | ||
|
|
||
| Example: | ||
| >>> result = cr.execute("print(2 + 2)") | ||
| >>> result.stdout | ||
| '4\\n' | ||
| """ | ||
| response = self._client.post( | ||
| f"{self.base_url}/v1/execute", | ||
| json={"code": code} | ||
| ) | ||
| response.raise_for_status() | ||
| data = response.json() | ||
| return ExecutionResult( | ||
| stdout=data.get("stdout", ""), | ||
| stderr=data.get("stderr", ""), | ||
| execution_time=data.get("execution_time", 0.0), | ||
| success=not data.get("stderr") | ||
| ) | ||
|
|
||
| def browse(self, url: str) -> BrowserResult: | ||
| """ | ||
| Navigate to URL and extract text content. | ||
|
|
||
| Args: | ||
| url: URL to navigate to. | ||
|
|
||
| Returns: | ||
| BrowserResult with extracted content. | ||
|
|
||
| Example: | ||
| >>> result = cr.browse("https://example.com") | ||
| >>> print(result.content[:50]) | ||
| """ | ||
| response = self._client.post( | ||
| f"{self.base_url}/v1/browser/content", | ||
| json={"url": url} | ||
| ) | ||
| response.raise_for_status() | ||
| data = response.json() | ||
| return BrowserResult( | ||
| content=data.get("readable_content", {}).get("content", ""), | ||
| url=url, | ||
| success=data.get("status") == "success", | ||
| error=data.get("error") | ||
| ) | ||
|
|
||
| def health(self) -> bool: | ||
| """ | ||
| Check if server is healthy. | ||
|
|
||
| Returns: | ||
| True if server is healthy, False otherwise. | ||
| """ | ||
| try: | ||
| response = self._client.get(f"{self.base_url}/health") | ||
| return response.status_code == 200 | ||
| except Exception: | ||
| return False | ||
|
|
||
| def close(self): | ||
| """Close the HTTP client.""" | ||
| self._client.close() | ||
|
|
||
| def __enter__(self): | ||
| return self | ||
|
|
||
| def __exit__(self, *args): | ||
| self.close() | ||
|
|
||
|
|
||
| def execute(code: str, base_url: str = "http://coderunner.local:8222") -> str: | ||
| """ | ||
| Execute Python code and return stdout. | ||
|
|
||
| Convenience function for one-off execution. | ||
|
|
||
| Args: | ||
| code: Python code to execute. | ||
| base_url: Server URL. Defaults to http://coderunner.local:8222 | ||
|
|
||
| Returns: | ||
| stdout from execution. | ||
|
|
||
| Raises: | ||
| RuntimeError: If execution produces stderr. | ||
|
|
||
| Example: | ||
| >>> from coderunner import execute | ||
| >>> execute("print(2 + 2)") | ||
| '4\\n' | ||
| """ | ||
| with CodeRunner(base_url) as cr: | ||
| result = cr.execute(code) | ||
| if result.stderr: | ||
| raise RuntimeError(result.stderr) | ||
| return result.stdout | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| [build-system] | ||
| requires = ["setuptools>=61.0", "wheel"] | ||
| build-backend = "setuptools.build_meta" | ||
|
|
||
| [project] | ||
| name = "coderunner" | ||
| version = "0.1.0" | ||
| description = "Python client for CodeRunner - sandboxed code execution on Mac" | ||
| readme = "README.md" | ||
| license = {text = "Apache-2.0"} | ||
| requires-python = ">=3.10" | ||
| authors = [ | ||
| {name = "InstaVM", email = "hello@instavm.io"} | ||
| ] | ||
| keywords = ["sandbox", "code-execution", "jupyter", "mac", "apple-silicon"] | ||
| classifiers = [ | ||
| "Development Status :: 3 - Alpha", | ||
| "Intended Audience :: Developers", | ||
| "License :: OSI Approved :: Apache Software License", | ||
| "Operating System :: MacOS", | ||
| "Programming Language :: Python :: 3", | ||
| "Programming Language :: Python :: 3.10", | ||
| "Programming Language :: Python :: 3.11", | ||
| "Programming Language :: Python :: 3.12", | ||
| "Topic :: Software Development :: Libraries :: Python Modules", | ||
| ] | ||
| dependencies = [ | ||
| "httpx>=0.24.0", | ||
| ] | ||
|
|
||
| [project.urls] | ||
| Homepage = "https://github.com/instavm/coderunner" | ||
| Repository = "https://github.com/instavm/coderunner" | ||
| Issues = "https://github.com/instavm/coderunner/issues" | ||
|
|
||
| [project.optional-dependencies] | ||
| dev = [ | ||
| "pytest>=7.0", | ||
| "pytest-asyncio>=0.21", | ||
| ] | ||
|
|
||
| [tool.setuptools.packages.find] | ||
| include = ["coderunner*"] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Catching a generic
Exceptionis too broad and can mask underlying issues in the code. It's better to catch more specific exceptions related to network requests. Forhttpx,httpx.RequestErroris the base exception for request-related problems and would be more appropriate here.