Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0f6e130
Fix Python SDK type issues with ty type checker
mishushakov Feb 9, 2026
71716b3
Remove invalid overloads for class_method_variant methods
mishushakov Feb 9, 2026
af0f97b
Replace type: ignore[invalid-argument-type] with proper fixes
mishushakov Feb 9, 2026
b68fb31
fix: rename _cls_connect to _cls_connect_sandbox to fix invalid-metho…
mishushakov Feb 9, 2026
0a9376e
refactor: clean up SandboxCreateResponse construction
mishushakov Feb 9, 2026
9579ac6
refactor: use res.parsed directly instead of local alias
mishushakov Feb 9, 2026
6e169f7
chore: add ty type checker as dev dependency
mishushakov Feb 9, 2026
5a41999
fix: use None instead of empty string for missing envd_access_token
mishushakov Feb 9, 2026
c090080
feat: add overloads for class_method_variant methods
mishushakov Feb 9, 2026
a397a4a
fix: use @classmethod overloads for basedpyright compatibility
mishushakov Feb 9, 2026
ccf8f2a
docs: restore docstrings on overloaded method variants
mishushakov Feb 9, 2026
9e8f1cf
fix: use @staticmethod overloads to avoid reportInconsistentOverload
mishushakov Feb 9, 2026
c6995c1
fix: suppress reportInconsistentOverload in basedpyright config
mishushakov Feb 9, 2026
cadbcfc
ci: add typecheck workflow and pnpm typecheck script
mishushakov Feb 9, 2026
bf2e5e7
chore: remove typecheck script from apps/web
mishushakov Feb 9, 2026
4be79c5
Potential fix for code scanning alert no. 14: Workflow does not conta…
mishushakov Feb 9, 2026
5ddeb44
fix: resolve 57 ty type checker diagnostics
mishushakov Feb 9, 2026
b5868c6
chore: replace ty type checker with basedpyright
mishushakov Feb 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Typecheck

on:
pull_request:

jobs:
typecheck:
name: Typecheck
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout Repo
uses: actions/checkout@v4

- name: Parse .tool-versions
uses: wistia/parse-tool-versions@v2.1.1
with:
filename: '.tool-versions'
uppercase: 'true'
prefix: 'tool_version_'

- uses: pnpm/action-setup@v4
with:
version: '${{ env.TOOL_VERSION_PNPM }}'

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '${{ env.TOOL_VERSION_NODEJS }}'
cache: pnpm

- name: Configure pnpm
run: |
pnpm config set auto-install-peers true
pnpm config set exclude-links-from-lockfile true

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '${{ env.TOOL_VERSION_PYTHON }}'

- name: Install and configure Poetry
uses: snok/install-poetry@v1
with:
version: '${{ env.TOOL_VERSION_POETRY }}'
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: Install Python dependencies
working-directory: packages/python-sdk
run: |
poetry install --with dev

- name: Run typecheck
run: |
pnpm run typecheck
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"pnpm-install-hack": "cd packages/js-sdk && sed -i '' 's/\"version\": \".*\"/\"version\": \"9.9.9\"/g' package.json && cd ../.. && pnpm i && git checkout -- packages/js-sdk/package.json",
"generate-sdk-reference": "pnpm --if-present --recursive run generate-sdk-reference",
"lint": "pnpm --if-present --recursive run lint",
"typecheck": "pnpm --if-present --recursive run typecheck",
"format": "pnpm --if-present --recursive run format",
"changeset": "pnpx @changesets/cli"
},
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"prepublishOnly": "pnpm build",
"build": "tsc --noEmit --skipLibCheck && tsup --minify",
"dev": "tsup --watch",
"typecheck": "tsc --noEmit --skipLibCheck",
"lint": "eslint src",
"format": "prettier --write src",
"test:interactive": "pnpm build && ./dist/index.js",
Expand Down
1 change: 1 addition & 0 deletions packages/js-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"test:bun": "bun test tests/runtimes/bun --env-file=.env",
"test:deno": "deno test tests/runtimes/deno/ --allow-net --allow-read --allow-env --unstable-sloppy-imports --trace-leaks",
"test:integration": "E2B_INTEGRATION_TEST=1 vitest run tests/integration/**",
"typecheck": "tsc --noEmit",
"lint": "eslint src/ tests/",
"format": "prettier --write src/ tests/ example.mts"
},
Expand Down
3 changes: 3 additions & 0 deletions packages/python-sdk/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ generate: generate-api generate-envd generate-mcp
init:
pip install openapi-python-client datamodel-code-generator

typecheck:
basedpyright

lint:
ruff check .
ruff format --check .
Expand Down
4 changes: 2 additions & 2 deletions packages/python-sdk/e2b/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class SandboxCreateResponse:
sandbox_id: str
sandbox_domain: Optional[str]
envd_version: str
envd_access_token: str
envd_access_token: Optional[str]
traffic_access_token: Optional[str]


Expand Down Expand Up @@ -135,7 +135,7 @@ def __init__(
"transport": transport,
},
headers=headers,
token=token,
token=token or "",
auth_header_name=auth_header_name,
prefix=prefix,
*args,
Expand Down
4 changes: 1 addition & 3 deletions packages/python-sdk/e2b/api/client_async/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

from typing import Optional

from typing_extensions import Self

from e2b.connection_config import ConnectionConfig
from e2b.api import limits, AsyncApiClient

Expand All @@ -21,7 +19,7 @@ def get_api_client(config: ConnectionConfig, **kwargs) -> AsyncApiClient:


class AsyncTransportWithLogger(httpx.AsyncHTTPTransport):
singleton: Optional[Self] = None
singleton: Optional["AsyncTransportWithLogger"] = None

async def handle_async_request(self, request):
url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
Expand Down
4 changes: 1 addition & 3 deletions packages/python-sdk/e2b/api/client_sync/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import httpx
import logging

from typing_extensions import Self

from e2b.api import ApiClient, limits
from e2b.connection_config import ConnectionConfig

Expand All @@ -20,7 +18,7 @@ def get_api_client(config: ConnectionConfig, **kwargs) -> ApiClient:


class TransportWithLogger(httpx.HTTPTransport):
singleton: Optional[Self] = None
singleton: Optional["TransportWithLogger"] = None

def handle_request(self, request):
url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
Expand Down
11 changes: 7 additions & 4 deletions packages/python-sdk/e2b/connection_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def _api_url():
return os.getenv("E2B_API_URL")

@staticmethod
def _sandbox_url():
def _sandbox_url_env():
return os.getenv("E2B_SANDBOX_URL")

@staticmethod
Expand Down Expand Up @@ -117,7 +117,9 @@ def __init__(
or ("http://localhost:3000" if self.debug else f"https://api.{self.domain}")
)

self._sandbox_url = sandbox_url or ConnectionConfig._sandbox_url()
self._sandbox_url: Optional[str] = (
sandbox_url or ConnectionConfig._sandbox_url_env()
)

@staticmethod
def _get_request_timeout(
Expand All @@ -135,8 +137,9 @@ def get_request_timeout(self, request_timeout: Optional[float] = None):
return self._get_request_timeout(self.request_timeout, request_timeout)

def get_sandbox_url(self, sandbox_id: str, sandbox_domain: str) -> str:
if self._sandbox_url:
return self._sandbox_url
sandbox_url: Optional[str] = self._sandbox_url
if sandbox_url:
return sandbox_url

return f"{'http' if self.debug else 'https'}://{self.get_host(sandbox_id, sandbox_domain, self.envd_port)}"

Expand Down
3 changes: 1 addition & 2 deletions packages/python-sdk/e2b/sandbox/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class SandboxOpts(TypedDict):
sandbox_domain: Optional[str]
envd_version: Version
envd_access_token: Optional[str]
sandbox_url: Optional[str]
traffic_access_token: Optional[str]
connection_config: ConnectionConfig

Expand Down Expand Up @@ -73,7 +72,7 @@ def traffic_access_token(self) -> Optional[str]:
return self.__traffic_access_token

@property
def sandbox_domain(self) -> Optional[str]:
def sandbox_domain(self) -> str:
return self.__sandbox_domain

@property
Expand Down
7 changes: 5 additions & 2 deletions packages/python-sdk/e2b/sandbox/sandbox_api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from dataclasses import dataclass
from datetime import datetime
from typing import Any, Dict, List, Optional, TypedDict, Union
from typing import Any, Dict, List, Optional, TypedDict, Union, cast

from typing_extensions import NotRequired, Unpack

Expand Down Expand Up @@ -117,7 +117,10 @@ def _from_sandbox_data(
sandbox_id=sandbox.sandbox_id,
template_id=sandbox.template_id,
name=(sandbox.alias if isinstance(sandbox.alias, str) else None),
metadata=(sandbox.metadata if isinstance(sandbox.metadata, dict) else {}),
metadata=cast(
Dict[str, str],
sandbox.metadata if isinstance(sandbox.metadata, dict) else {},
),
started_at=sandbox.started_at,
end_at=sandbox.end_at,
state=sandbox.state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ async def _start(
self,
cmd: str,
envs: Optional[Dict[str, str]],
user: Username,
user: Optional[Username],
cwd: Optional[str],
timeout: Optional[float],
request_timeout: Optional[float],
Expand Down
21 changes: 13 additions & 8 deletions packages/python-sdk/e2b/sandbox_async/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,12 @@ async def connect(
...

@overload
@classmethod
@staticmethod
async def connect(
cls,
sandbox_id: str,
timeout: Optional[int] = None,
**opts: Unpack[ApiParams],
) -> Self:
) -> "AsyncSandbox":
"""
Connect to a sandbox. If the sandbox is paused, it will be automatically resumed.
Sandbox must be either running or be paused.
Expand All @@ -271,7 +270,7 @@ async def connect(
"""
...

@class_method_variant("_cls_connect")
@class_method_variant("_cls_connect_sandbox")
async def connect(
self,
timeout: Optional[int] = None,
Expand Down Expand Up @@ -643,7 +642,7 @@ async def get_mcp_token(self) -> Optional[str]:
return self._mcp_token

@classmethod
async def _cls_connect(
async def _cls_connect_sandbox(
cls,
sandbox_id: str,
timeout: Optional[int] = None,
Expand All @@ -667,10 +666,16 @@ async def _cls_connect(

return cls(
sandbox_id=sandbox.sandbox_id,
sandbox_domain=sandbox.domain,
sandbox_domain=sandbox.domain
if not isinstance(sandbox.domain, Unset)
else None,
envd_version=Version(sandbox.envd_version),
envd_access_token=envd_access_token,
traffic_access_token=sandbox.traffic_access_token,
envd_access_token=envd_access_token
if not isinstance(envd_access_token, Unset)
else None,
traffic_access_token=sandbox.traffic_access_token
if not isinstance(sandbox.traffic_access_token, Unset)
else None,
connection_config=connection_config,
)

Expand Down
25 changes: 20 additions & 5 deletions packages/python-sdk/e2b/sandbox_async/sandbox_api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import datetime
from typing import Dict, List, Optional
from typing import Any, Dict, List, Optional, cast

from packaging.version import Version
from typing_extensions import Unpack
Expand Down Expand Up @@ -171,7 +171,7 @@ async def _create_sandbox(
metadata=metadata or {},
timeout=timeout,
env_vars=env_vars or {},
mcp=mcp or UNSET,
mcp=cast(Any, mcp) if mcp is not None else UNSET,
secure=secure,
allow_internet_access=allow_internet_access,
network=SandboxNetworkConfig(**network) if network else UNSET,
Expand All @@ -195,12 +195,24 @@ async def _create_sandbox(
"You can do this by running `e2b template build` in the directory with the template."
)

domain = res.parsed.domain if isinstance(res.parsed.domain, str) else None
envd_token = (
res.parsed.envd_access_token
if isinstance(res.parsed.envd_access_token, str)
else None
)
traffic_token = (
res.parsed.traffic_access_token
if isinstance(res.parsed.traffic_access_token, str)
else None
)

return SandboxCreateResponse(
sandbox_id=res.parsed.sandbox_id,
sandbox_domain=res.parsed.domain,
sandbox_domain=domain,
envd_version=res.parsed.envd_version,
envd_access_token=res.parsed.envd_access_token,
traffic_access_token=res.parsed.traffic_access_token,
envd_access_token=envd_token,
traffic_access_token=traffic_token,
)

@classmethod
Expand Down Expand Up @@ -322,4 +334,7 @@ async def _cls_connect(
if isinstance(res.parsed, Error):
raise SandboxException(f"{res.parsed.message}: Request failed")

if res.parsed is None:
raise SandboxException("Body of the request is None")

return res.parsed
2 changes: 1 addition & 1 deletion packages/python-sdk/e2b/sandbox_sync/commands/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def _start(
self,
cmd: str,
envs: Optional[Dict[str, str]],
user: Username,
user: Optional[Username],
cwd: Optional[str],
stdin: bool,
timeout: Optional[float],
Expand Down
Loading
Loading