diff --git a/.changeset/tangy-kiwis-repeat.md b/.changeset/tangy-kiwis-repeat.md new file mode 100644 index 0000000000..71e65e15a7 --- /dev/null +++ b/.changeset/tangy-kiwis-repeat.md @@ -0,0 +1,5 @@ +--- +'@e2b/python-sdk': patch +--- + +fixes type errors when using with ty diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml new file mode 100644 index 0000000000..09e33d32cd --- /dev/null +++ b/.github/workflows/typecheck.yml @@ -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 diff --git a/package.json b/package.json index 801a51370d..c68c763931 100644 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/packages/cli/package.json b/packages/cli/package.json index edf669e4dc..15ba170801 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -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", diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json index f609b4913f..73df64b434 100644 --- a/packages/js-sdk/package.json +++ b/packages/js-sdk/package.json @@ -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" }, diff --git a/packages/python-sdk/Makefile b/packages/python-sdk/Makefile index 271b0887a5..38f4eb1e89 100644 --- a/packages/python-sdk/Makefile +++ b/packages/python-sdk/Makefile @@ -23,6 +23,9 @@ generate: generate-api generate-envd generate-mcp init: pip install openapi-python-client datamodel-code-generator +typecheck: + ty check + lint: ruff check . ruff format --check . diff --git a/packages/python-sdk/e2b/api/__init__.py b/packages/python-sdk/e2b/api/__init__.py index 4aed46582f..7f7cb6ae0f 100644 --- a/packages/python-sdk/e2b/api/__init__.py +++ b/packages/python-sdk/e2b/api/__init__.py @@ -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] @@ -135,7 +135,7 @@ def __init__( "transport": transport, }, headers=headers, - token=token, + token=token or "", auth_header_name=auth_header_name, prefix=prefix, *args, diff --git a/packages/python-sdk/e2b/api/client_async/__init__.py b/packages/python-sdk/e2b/api/client_async/__init__.py index 5d5c51c28b..7c592ac68d 100644 --- a/packages/python-sdk/e2b/api/client_async/__init__.py +++ b/packages/python-sdk/e2b/api/client_async/__init__.py @@ -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 @@ -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}" diff --git a/packages/python-sdk/e2b/api/client_sync/__init__.py b/packages/python-sdk/e2b/api/client_sync/__init__.py index 029b3e4e9d..f3d62ca729 100644 --- a/packages/python-sdk/e2b/api/client_sync/__init__.py +++ b/packages/python-sdk/e2b/api/client_sync/__init__.py @@ -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 @@ -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}" diff --git a/packages/python-sdk/e2b/connection_config.py b/packages/python-sdk/e2b/connection_config.py index adc4908591..987d5c9e37 100644 --- a/packages/python-sdk/e2b/connection_config.py +++ b/packages/python-sdk/e2b/connection_config.py @@ -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() + ) @staticmethod def _get_request_timeout( @@ -136,7 +138,7 @@ def get_request_timeout(self, request_timeout: Optional[float] = None): def get_sandbox_url(self, sandbox_id: str, sandbox_domain: str) -> str: if self._sandbox_url: - return self._sandbox_url + return self._sandbox_url # type: ignore[return-value] return f"{'http' if self.debug else 'https'}://{self.get_host(sandbox_id, sandbox_domain, self.envd_port)}" diff --git a/packages/python-sdk/e2b/sandbox/main.py b/packages/python-sdk/e2b/sandbox/main.py index cdfc63a1b2..d9e42645af 100644 --- a/packages/python-sdk/e2b/sandbox/main.py +++ b/packages/python-sdk/e2b/sandbox/main.py @@ -73,7 +73,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 diff --git a/packages/python-sdk/e2b/sandbox/sandbox_api.py b/packages/python-sdk/e2b/sandbox/sandbox_api.py index 3245a512f8..961d853d0a 100644 --- a/packages/python-sdk/e2b/sandbox/sandbox_api.py +++ b/packages/python-sdk/e2b/sandbox/sandbox_api.py @@ -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 @@ -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, diff --git a/packages/python-sdk/e2b/sandbox_async/commands/command.py b/packages/python-sdk/e2b/sandbox_async/commands/command.py index 7c94d85671..32b75fd26b 100644 --- a/packages/python-sdk/e2b/sandbox_async/commands/command.py +++ b/packages/python-sdk/e2b/sandbox_async/commands/command.py @@ -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], diff --git a/packages/python-sdk/e2b/sandbox_async/main.py b/packages/python-sdk/e2b/sandbox_async/main.py index bc592f139e..42df814e62 100644 --- a/packages/python-sdk/e2b/sandbox_async/main.py +++ b/packages/python-sdk/e2b/sandbox_async/main.py @@ -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. @@ -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, @@ -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, diff --git a/packages/python-sdk/e2b/sandbox_async/sandbox_api.py b/packages/python-sdk/e2b/sandbox_async/sandbox_api.py index aabbd709c3..5f842c86f9 100644 --- a/packages/python-sdk/e2b/sandbox_async/sandbox_api.py +++ b/packages/python-sdk/e2b/sandbox_async/sandbox_api.py @@ -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 @@ -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) or UNSET, secure=secure, allow_internet_access=allow_internet_access, network=SandboxNetworkConfig(**network) if network else UNSET, @@ -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 @@ -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 diff --git a/packages/python-sdk/e2b/sandbox_sync/commands/command.py b/packages/python-sdk/e2b/sandbox_sync/commands/command.py index 79c1b951c8..512b7d9923 100644 --- a/packages/python-sdk/e2b/sandbox_sync/commands/command.py +++ b/packages/python-sdk/e2b/sandbox_sync/commands/command.py @@ -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], diff --git a/packages/python-sdk/e2b/sandbox_sync/main.py b/packages/python-sdk/e2b/sandbox_sync/main.py index 366def2234..dcc056232f 100644 --- a/packages/python-sdk/e2b/sandbox_sync/main.py +++ b/packages/python-sdk/e2b/sandbox_sync/main.py @@ -241,13 +241,12 @@ def connect( ... @overload - @classmethod + @staticmethod def connect( - cls, sandbox_id: str, timeout: Optional[int] = None, **opts: Unpack[ApiParams], - ) -> Self: + ) -> "Sandbox": """ Connect to a sandbox. If the sandbox is paused, it will be automatically resumed. Sandbox must be either running or be paused. @@ -270,7 +269,7 @@ def connect( """ ... - @class_method_variant("_cls_connect") + @class_method_variant("_cls_connect_sandbox") def connect( self, timeout: Optional[int] = None, @@ -595,9 +594,8 @@ def beta_pause( ... @overload - @classmethod + @staticmethod def beta_pause( - cls, sandbox_id: str, **opts: Unpack[ApiParams], ) -> None: @@ -639,7 +637,7 @@ def get_mcp_token(self) -> Optional[str]: return self._mcp_token @classmethod - def _cls_connect( + def _cls_connect_sandbox( cls, sandbox_id: str, timeout: Optional[int] = None, diff --git a/packages/python-sdk/e2b/sandbox_sync/sandbox_api.py b/packages/python-sdk/e2b/sandbox_sync/sandbox_api.py index 18a3af798d..87b4bd6fad 100644 --- a/packages/python-sdk/e2b/sandbox_sync/sandbox_api.py +++ b/packages/python-sdk/e2b/sandbox_sync/sandbox_api.py @@ -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 @@ -170,7 +170,7 @@ def _create_sandbox( metadata=metadata or {}, timeout=timeout, env_vars=env_vars or {}, - mcp=mcp or UNSET, + mcp=cast(Any, mcp) or UNSET, secure=secure, allow_internet_access=allow_internet_access, network=SandboxNetworkConfig(**network) if network else UNSET, @@ -194,12 +194,24 @@ 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 @@ -219,8 +231,8 @@ def _cls_get_metrics( api_client = get_api_client(config) res = get_sandboxes_sandbox_id_metrics.sync_detailed( sandbox_id, - start=int(start.timestamp()) if start else None, - end=int(end.timestamp()) if end else None, + start=int(start.timestamp()) if start else UNSET, + end=int(end.timestamp()) if end else UNSET, client=api_client, ) @@ -280,6 +292,9 @@ 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 @classmethod diff --git a/packages/python-sdk/e2b/template/dockerfile_parser.py b/packages/python-sdk/e2b/template/dockerfile_parser.py index c03b164478..7c5c34ce47 100644 --- a/packages/python-sdk/e2b/template/dockerfile_parser.py +++ b/packages/python-sdk/e2b/template/dockerfile_parser.py @@ -5,7 +5,6 @@ from typing import Dict, List, Optional, Protocol, Union, Literal from dockerfile_parse import DockerfileParser -from e2b.template.types import CopyItem class DockerfFileFinalParserInterface(Protocol): @@ -23,12 +22,12 @@ def run_cmd( def copy( self, - src: Union[str, List[CopyItem]], - dest: Optional[str] = None, + src: str, + dest: str, force_upload: Optional[Literal[True]] = None, - resolve_symlinks: Optional[bool] = None, user: Optional[str] = None, mode: Optional[int] = None, + resolve_symlinks: Optional[bool] = None, ) -> "DockerfileParserInterface": """Handle COPY instruction.""" ... diff --git a/packages/python-sdk/package.json b/packages/python-sdk/package.json index fa3a2696fa..0006cc1c59 100644 --- a/packages/python-sdk/package.json +++ b/packages/python-sdk/package.json @@ -9,6 +9,7 @@ "postPublish": "poetry build && poetry config pypi-token.pypi ${PYPI_TOKEN} && poetry publish --skip-existing", "pretest": "poetry install", "generate-ref": "poetry install && ./scripts/generate_sdk_ref.sh", + "typecheck": "poetry run make typecheck", "lint": "poetry run make lint", "format": "poetry run make format" } diff --git a/packages/python-sdk/poetry.lock b/packages/python-sdk/poetry.lock index 3c180a9120..468fc4b543 100644 --- a/packages/python-sdk/poetry.lock +++ b/packages/python-sdk/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -277,7 +277,7 @@ description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] -markers = "platform_system == \"Windows\" or sys_platform == \"win32\"" +markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -449,7 +449,7 @@ description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main", "dev"] -markers = "python_version == \"3.10\"" +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, @@ -1483,6 +1483,33 @@ files = [ {file = "tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021"}, ] +[[package]] +name = "ty" +version = "0.0.15" +description = "An extremely fast Python type checker, written in Rust." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "ty-0.0.15-py3-none-linux_armv6l.whl", hash = "sha256:68e092458516c61512dac541cde0a5e4e5842df00b4e81881ead8f745ddec794"}, + {file = "ty-0.0.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:79f2e75289eae3cece94c51118b730211af4ba5762906f52a878041b67e54959"}, + {file = "ty-0.0.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:112a7b26e63e48cc72c8c5b03227d1db280cfa57a45f2df0e264c3a016aa8c3c"}, + {file = "ty-0.0.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71f62a2644972975a657d9dc867bf901235cde51e8d24c20311067e7afd44a56"}, + {file = "ty-0.0.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e48b42be2d257317c85b78559233273b655dd636fc61e7e1d69abd90fd3cba4"}, + {file = "ty-0.0.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27dd5b52a421e6871c5bfe9841160331b60866ed2040250cb161886478ab3e4f"}, + {file = "ty-0.0.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76b85c9ec2219e11c358a7db8e21b7e5c6674a1fb9b6f633836949de98d12286"}, + {file = "ty-0.0.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9e8204c61d8ede4f21f2975dce74efdb80fafb2fae1915c666cceb33ea3c90b"}, + {file = "ty-0.0.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af87c3be7c944bb4d6609d6c63e4594944b0028c7bd490a525a82b88fe010d6d"}, + {file = "ty-0.0.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50dccf7398505e5966847d366c9e4c650b8c225411c2a68c32040a63b9521eea"}, + {file = "ty-0.0.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:bd797b8f231a4f4715110259ad1ad5340a87b802307f3e06d92bfb37b858a8f3"}, + {file = "ty-0.0.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9deb7f20e18b25440a9aa4884f934ba5628ef456dbde91819d5af1a73da48af3"}, + {file = "ty-0.0.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7b31b3de031255b90a5f4d9cb3d050feae246067c87130e5a6861a8061c71754"}, + {file = "ty-0.0.15-py3-none-win32.whl", hash = "sha256:9362c528ceb62c89d65c216336d28d500bc9f4c10418413f63ebc16886e16cc1"}, + {file = "ty-0.0.15-py3-none-win_amd64.whl", hash = "sha256:4db040695ae67c5524f59cb8179a8fa277112e69042d7dfdac862caa7e3b0d9c"}, + {file = "ty-0.0.15-py3-none-win_arm64.whl", hash = "sha256:e5a98d4119e77d6136461e16ae505f8f8069002874ab073de03fbcb1a5e8bf25"}, + {file = "ty-0.0.15.tar.gz", hash = "sha256:4f9a5b8df208c62dba56e91b93bed8b5bb714839691b8cff16d12c983bfa1174"}, +] + [[package]] name = "typeapi" version = "2.2.4" @@ -1726,4 +1753,4 @@ tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "95c546174e29cc21728f79280a8bd0c33d363455ab215ada6f007d0174002297" +content-hash = "043f819ede85ad6c0e8d1292c8c62ef037dceb274c2e81230493af3ae5ce14d5" diff --git a/packages/python-sdk/pyproject.toml b/packages/python-sdk/pyproject.toml index 6bec502bd8..20fb06d3ed 100644 --- a/packages/python-sdk/pyproject.toml +++ b/packages/python-sdk/pyproject.toml @@ -32,6 +32,7 @@ pydoc-markdown = "^4.8.2" datamodel-code-generator = "^0.34.0" ruff = "^0.11.12" pytest-timeout = "^2.4.0" +ty = "^0.0.15" [build-system] requires = ["poetry-core"] @@ -40,6 +41,21 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.urls] "Bug Tracker" = "https://github.com/e2b-dev/e2b/issues" +[tool.basedpyright] +reportInconsistentOverload = false + +[tool.ty.rules] +invalid-overload = "ignore" +no-matching-overload = "ignore" + +[[tool.ty.overrides]] +include = ["e2b/api/client/models/**"] +rules = { invalid-argument-type = "ignore" } + +[[tool.ty.overrides]] +include = ["e2b/envd/**/*.pyi"] +rules = { conflicting-metaclass = "ignore", unresolved-attribute = "ignore" } + [tool.ruff] exclude = [ "e2b/envd/filesystem/filesystem_pb2.py" diff --git a/packages/python-sdk/tests/async/sandbox_async/files/test_files_list.py b/packages/python-sdk/tests/async/sandbox_async/files/test_files_list.py index bc876b1068..12daab0174 100644 --- a/packages/python-sdk/tests/async/sandbox_async/files/test_files_list.py +++ b/packages/python-sdk/tests/async/sandbox_async/files/test_files_list.py @@ -1,4 +1,5 @@ import uuid +from typing import Any from e2b import AsyncSandbox, FileType @@ -16,7 +17,7 @@ async def test_list_directory(async_sandbox: AsyncSandbox): await async_sandbox.files.make_dir(f"{parent_dir_name}/subdir2/subdir2_2") await async_sandbox.files.write(f"{parent_dir_name}/file1.txt", "Hello, world!") - test_cases = [ + test_cases: list[dict[str, Any]] = [ { "name": "default depth (1)", "depth": None, diff --git a/packages/python-sdk/tests/conftest.py b/packages/python-sdk/tests/conftest.py index 313bdc1ca7..3a614e0856 100644 --- a/packages/python-sdk/tests/conftest.py +++ b/packages/python-sdk/tests/conftest.py @@ -190,7 +190,9 @@ def debug(): def skip_by_debug(request, debug): if request.node.get_closest_marker("skip_debug"): if debug: - pytest.skip("skipped because E2B_DEBUG is set") + pytest.skip( + "skipped because E2B_DEBUG is set" # ty: ignore[too-many-positional-arguments] + ) # ty: ignore[invalid-argument-type] class Helpers: diff --git a/packages/python-sdk/tests/shared/template/utils/test_tar_file_stream.py b/packages/python-sdk/tests/shared/template/utils/test_tar_file_stream.py index 672b937e99..119df8041b 100644 --- a/packages/python-sdk/tests/shared/template/utils/test_tar_file_stream.py +++ b/packages/python-sdk/tests/shared/template/utils/test_tar_file_stream.py @@ -92,7 +92,9 @@ def test_should_handle_nested_files(self, test_dir): def test_should_resolve_symlinks_when_enabled(self, test_dir): """Test that function resolves symlinks when resolve_symlinks=True.""" if not hasattr(os, "symlink"): - pytest.skip("Symlinks not supported on this platform") + pytest.skip( + "Symlinks not supported on this platform" # ty: ignore[too-many-positional-arguments] + ) # ty: ignore[invalid-argument-type] # Create original file original_path = os.path.join(test_dir, "original.txt") @@ -117,7 +119,9 @@ def test_should_resolve_symlinks_when_enabled(self, test_dir): def test_should_preserve_symlinks_when_disabled(self, test_dir): """Test that function preserves symlinks when resolve_symlinks=False.""" if not hasattr(os, "symlink"): - pytest.skip("Symlinks not supported on this platform") + pytest.skip( + "Symlinks not supported on this platform" # ty: ignore[too-many-positional-arguments] + ) # ty: ignore[invalid-argument-type] # Create original file original_path = os.path.join(test_dir, "original.txt") diff --git a/packages/python-sdk/tests/sync/sandbox_sync/files/test_files_list.py b/packages/python-sdk/tests/sync/sandbox_sync/files/test_files_list.py index f4fbfebbbd..a3622c2c3d 100644 --- a/packages/python-sdk/tests/sync/sandbox_sync/files/test_files_list.py +++ b/packages/python-sdk/tests/sync/sandbox_sync/files/test_files_list.py @@ -1,4 +1,5 @@ import uuid +from typing import Any from e2b import Sandbox, FileType @@ -16,7 +17,7 @@ def test_list_directory(sandbox: Sandbox): sandbox.files.make_dir(f"{parent_dir_name}/subdir2/subdir2_2") sandbox.files.write(f"{parent_dir_name}/file1.txt", "Hello, world!") - test_cases = [ + test_cases: list[dict[str, Any]] = [ { "name": "default depth (1)", "depth": None,