Skip to content

Commit f293a7e

Browse files
FisherXZclaude
andcommitted
fix: forward envs through _cls_connect_sandbox to prevent TypeError
Sandbox.connect(sandbox_id, envs=...) routed through _cls_connect_sandbox, which lacked an explicit envs param. envs fell into **opts and was later passed to ConnectionConfig(**opts), raising TypeError on the class-call path. Added envs as an explicit param to both sync and async _cls_connect_sandbox so it is forwarded to _cls_connect and kept out of the opts spread into ConnectionConfig. Added regression tests covering the class-call path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b40c885 commit f293a7e

4 files changed

Lines changed: 60 additions & 0 deletions

File tree

packages/python-sdk/e2b/sandbox_async/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,11 +862,13 @@ async def _cls_connect_sandbox(
862862
cls,
863863
sandbox_id: str,
864864
timeout: Optional[int] = None,
865+
envs: Optional[Dict[str, str]] = None,
865866
**opts: Unpack[ApiParams],
866867
) -> Self:
867868
sandbox = await SandboxApi._cls_connect(
868869
sandbox_id=sandbox_id,
869870
timeout=timeout,
871+
envs=envs,
870872
**opts,
871873
)
872874

packages/python-sdk/e2b/sandbox_sync/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,11 +857,13 @@ def _cls_connect_sandbox(
857857
cls,
858858
sandbox_id: str,
859859
timeout: Optional[int] = None,
860+
envs: Optional[Dict[str, str]] = None,
860861
**opts: Unpack[ApiParams],
861862
) -> Self:
862863
sandbox = SandboxApi._cls_connect(
863864
sandbox_id=sandbox_id,
864865
timeout=timeout,
866+
envs=envs,
865867
**opts,
866868
)
867869

packages/python-sdk/tests/async/sandbox_async/test_config_propagation.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,34 @@ async def test_connect_envs_is_none_when_not_provided(monkeypatch):
9191
assert mock_connect.call_args.kwargs.get("envs") is None
9292

9393

94+
@pytest.mark.skip_debug()
95+
async def test_classmethod_connect_forwards_envs_without_polluting_opts(monkeypatch):
96+
# Regression: AsyncSandbox.connect(id, envs=...) previously passed envs into
97+
# **opts, which then reached ConnectionConfig(**opts) and raised TypeError.
98+
mock_cls_connect = AsyncMock(return_value=SimpleNamespace(
99+
sandbox_id="sbx-test",
100+
domain="sandbox.e2b.dev",
101+
envd_version="0.2.4",
102+
envd_access_token="tok",
103+
traffic_access_token="tok",
104+
))
105+
monkeypatch.setattr(sandbox_async_main.SandboxApi, "_cls_connect", mock_cls_connect)
106+
monkeypatch.setattr(
107+
sandbox_async_main, "get_transport", lambda *_args, **_kwargs: SimpleNamespace(pool=object())
108+
)
109+
monkeypatch.setattr(sandbox_async_main.httpx, "AsyncClient", lambda *args, **kwargs: object())
110+
monkeypatch.setattr(sandbox_async_main, "Filesystem", lambda *args, **kwargs: object())
111+
monkeypatch.setattr(sandbox_async_main, "Commands", lambda *args, **kwargs: object())
112+
monkeypatch.setattr(sandbox_async_main, "Pty", lambda *args, **kwargs: object())
113+
monkeypatch.setattr(sandbox_async_main, "Git", lambda *args, **kwargs: object())
114+
115+
# This must not raise TypeError: ConnectionConfig() got unexpected keyword 'envs'
116+
await sandbox_async_main.AsyncSandbox.connect("sbx-test", envs={"MY_KEY": "my_value"}, api_key="test-key")
117+
118+
mock_cls_connect.assert_awaited_once()
119+
assert mock_cls_connect.call_args.kwargs["envs"] == {"MY_KEY": "my_value"}
120+
121+
94122
@pytest.mark.skip_debug()
95123
async def test_pause_applies_overrides(monkeypatch):
96124
mock_pause = AsyncMock(return_value="sbx-test")

packages/python-sdk/tests/sync/sandbox_sync/test_config_propagation.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,34 @@ def test_connect_envs_is_none_when_not_provided(monkeypatch):
8989
assert mock_connect.call_args.kwargs.get("envs") is None
9090

9191

92+
@pytest.mark.skip_debug()
93+
def test_classmethod_connect_forwards_envs_without_polluting_opts(monkeypatch):
94+
# Regression: Sandbox.connect(id, envs=...) previously passed envs into
95+
# **opts, which then reached ConnectionConfig(**opts) and raised TypeError.
96+
mock_cls_connect = Mock(return_value=SimpleNamespace(
97+
sandbox_id="sbx-test",
98+
domain="sandbox.e2b.dev",
99+
envd_version="0.2.4",
100+
envd_access_token="tok",
101+
traffic_access_token="tok",
102+
))
103+
monkeypatch.setattr(sandbox_sync_main.SandboxApi, "_cls_connect", mock_cls_connect)
104+
monkeypatch.setattr(
105+
sandbox_sync_main, "get_transport", lambda *_args, **_kwargs: SimpleNamespace(pool=object())
106+
)
107+
monkeypatch.setattr(sandbox_sync_main.httpx, "Client", lambda *args, **kwargs: object())
108+
monkeypatch.setattr(sandbox_sync_main, "Filesystem", lambda *args, **kwargs: object())
109+
monkeypatch.setattr(sandbox_sync_main, "Commands", lambda *args, **kwargs: object())
110+
monkeypatch.setattr(sandbox_sync_main, "Pty", lambda *args, **kwargs: object())
111+
monkeypatch.setattr(sandbox_sync_main, "Git", lambda *args, **kwargs: object())
112+
113+
# This must not raise TypeError: ConnectionConfig() got unexpected keyword 'envs'
114+
sandbox_sync_main.Sandbox.connect("sbx-test", envs={"MY_KEY": "my_value"}, api_key="test-key")
115+
116+
mock_cls_connect.assert_called_once()
117+
assert mock_cls_connect.call_args.kwargs["envs"] == {"MY_KEY": "my_value"}
118+
119+
92120
@pytest.mark.skip_debug()
93121
def test_pause_applies_overrides(monkeypatch):
94122
mock_pause = Mock(return_value="sbx-test")

0 commit comments

Comments
 (0)