impello 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
impello/__init__.py ADDED
@@ -0,0 +1,84 @@
1
+ """The Python SDK for Impello sandboxes.
2
+
3
+ Impello runs its own build of E2B's open-source ``infra``, so the sandbox API
4
+ is the same API. Unlike the TypeScript client, the Python one needs no changes
5
+ to work against it: there is no ``e2b_`` key pattern anywhere in ``e2b``, so it
6
+ takes an ``imp_`` key today. All this package has to supply is where to send
7
+ the request.
8
+
9
+ So this is a wrapper, and it is deliberately thin. It will be replaced by a
10
+ full clone before we take payments, for the same reason the TypeScript client
11
+ is one: ``pip show impello`` printing ``e2b`` is a poor thing for a paid
12
+ product to say about itself, and the client sends a ``publisher: e2b`` header
13
+ to our own servers. See ``docs/decisions/sdk-self-contained.md``.
14
+
15
+ Usage is E2B's, unchanged::
16
+
17
+ from impello import Sandbox
18
+
19
+ sandbox = Sandbox.create()
20
+ result = sandbox.commands.run("echo hello")
21
+ sandbox.pause()
22
+ """
23
+
24
+ import e2b as _e2b
25
+ from e2b import * # noqa: F401,F403
26
+ from e2b.connection_config import ApiParams, merge_api_params
27
+
28
+ from ._defaults import DEFAULT_DOMAIN, defaults
29
+
30
+ __version__ = "0.2.0"
31
+
32
+
33
+ class _ImpelloDefaults:
34
+ """Bind Impello's settings underneath every call.
35
+
36
+ ``ClientFactory._resolve_api_params`` is E2B's own seam for this: every
37
+ class method funnels through it, and ``merge_api_params`` already gives
38
+ per-call params precedence over bound ones. So this overrides one method
39
+ instead of mirroring the twelve descriptors on ``Sandbox``, and it changes
40
+ nothing about ``e2b`` itself. Importing this package does not retarget a
41
+ plain ``e2b`` call in the same process, and it does not touch ``os.environ``.
42
+ """
43
+
44
+ @classmethod
45
+ def _resolve_api_params(cls, **opts: "ApiParams") -> "ApiParams":
46
+ return merge_api_params(defaults(), super()._resolve_api_params(**opts))
47
+
48
+
49
+ class Sandbox(_ImpelloDefaults, _e2b.Sandbox):
50
+ """An Impello sandbox."""
51
+
52
+
53
+ class AsyncSandbox(_ImpelloDefaults, _e2b.AsyncSandbox):
54
+ """An Impello sandbox, async."""
55
+
56
+
57
+ class Impello(_e2b.E2B):
58
+ """A client with its connection settings bound explicitly.
59
+
60
+ Use this instead of the module-level ``Sandbox`` when one process talks to
61
+ more than one account or more than one fleet. Clients are isolated from
62
+ each other. Params passed here beat the environment; params passed to a
63
+ single call beat both.
64
+
65
+ Example::
66
+
67
+ from impello import Impello
68
+
69
+ client = Impello(api_key="imp_...")
70
+ sandbox = client.Sandbox.create()
71
+ """
72
+
73
+ def __init__(self, **opts: "ApiParams"):
74
+ super().__init__(**merge_api_params(defaults(), opts))
75
+
76
+
77
+ __all__ = [
78
+ *[name for name in dir(_e2b) if not name.startswith("_")],
79
+ "Sandbox",
80
+ "AsyncSandbox",
81
+ "Impello",
82
+ "DEFAULT_DOMAIN",
83
+ "__version__",
84
+ ]
impello/_defaults.py ADDED
@@ -0,0 +1,57 @@
1
+ """Where an Impello setting comes from, and in what order.
2
+
3
+ Every setting reads an ``IMPELLO_`` name first, then the matching ``E2B_``
4
+ name. The fallback is the migration, not politeness: callers already export
5
+ ``E2B_API_KEY``, ``E2B_API_URL`` and ``E2B_DOMAIN``, and the flag day that
6
+ changes the key prefix is hard enough without renaming every environment on the
7
+ same afternoon. Rename when convenient. Nothing breaks if you never do.
8
+ """
9
+
10
+ import os
11
+ from typing import Optional
12
+
13
+ from e2b.connection_config import ApiParams
14
+
15
+ DEFAULT_DOMAIN = "sandbox.impello.ai"
16
+
17
+ # Each entry is one setting and the ``ApiParams`` key it fills.
18
+ _SETTINGS = (
19
+ ("API_KEY", "api_key"),
20
+ ("API_URL", "api_url"),
21
+ ("DOMAIN", "domain"),
22
+ ("SANDBOX_URL", "sandbox_url"),
23
+ )
24
+
25
+
26
+ def _read(name: str) -> Optional[str]:
27
+ """Read one setting, Impello's name first."""
28
+ return os.getenv(f"IMPELLO_{name}") or os.getenv(f"E2B_{name}")
29
+
30
+
31
+ def defaults() -> ApiParams:
32
+ """The params bound to every Impello call, resolved fresh each time.
33
+
34
+ Read at call time rather than at import, so a test or a caller that sets an
35
+ environment variable after importing this package still gets it.
36
+
37
+ A setting that is absent is left out of the result. It must not appear as
38
+ ``None``, because ``merge_api_params`` drops a ``None`` from the per-call
39
+ params but keeps one in the bound params, where it would clear the value
40
+ the SDK would otherwise resolve for itself.
41
+ """
42
+ params = {}
43
+
44
+ for name, key in _SETTINGS:
45
+ value = _read(name)
46
+ if value:
47
+ params[key] = value
48
+
49
+ debug = _read("DEBUG")
50
+ if debug:
51
+ params["debug"] = debug.lower() == "true"
52
+
53
+ # Only the domain has a default. Without one the SDK falls back to E2B's
54
+ # own `e2b.app`, and the failure is a connection to somebody else's fleet.
55
+ params.setdefault("domain", DEFAULT_DOMAIN)
56
+
57
+ return params
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.5
2
+ Name: impello
3
+ Version: 0.2.0
4
+ Summary: Python SDK for Impello sandboxes.
5
+ Project-URL: Homepage, https://impello.ai
6
+ Project-URL: Repository, https://github.com/21-Dreams/impello
7
+ License-Expression: MIT
8
+ Keywords: agents,code-interpreter,impello,microvm,sandbox
9
+ Requires-Python: >=3.9
10
+ Requires-Dist: e2b<3,>=2.46.0
11
+ Description-Content-Type: text/markdown
12
+
13
+ # `impello`
14
+
15
+ The Python SDK for Impello sandboxes.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ pip install impello
21
+ ```
22
+
23
+ ## Use
24
+
25
+ ```python
26
+ from impello import Sandbox
27
+
28
+ sandbox = Sandbox.create()
29
+ result = sandbox.commands.run("echo hello")
30
+
31
+ print(result.stdout)
32
+
33
+ sandbox.pause()
34
+ ```
35
+
36
+ Set your key in the environment, or pass it to each call:
37
+
38
+ ```bash
39
+ export IMPELLO_API_KEY=imp_...
40
+ ```
41
+
42
+ ```python
43
+ Sandbox.list(api_key="imp_...")
44
+ ```
45
+
46
+ For a process that talks to more than one account or more than one fleet, bind
47
+ the settings to a client instead:
48
+
49
+ ```python
50
+ from impello import Impello
51
+
52
+ client = Impello(api_key="imp_...")
53
+ sandbox = client.Sandbox.create()
54
+ ```
55
+
56
+ ## Settings
57
+
58
+ Every setting reads an `IMPELLO_` name first, then the matching `E2B_` name.
59
+
60
+ | Variable | Default | What it does |
61
+ |---|---|---|
62
+ | `IMPELLO_API_KEY` | none | The key. Starts with `imp_` |
63
+ | `IMPELLO_DOMAIN` | `sandbox.impello.ai` | The domain the API and the sandboxes sit on |
64
+ | `IMPELLO_API_URL` | `https://api.<domain>` | The API address. Set this to reach a self-hosted API |
65
+ | `IMPELLO_SANDBOX_URL` | derived from the domain | The address a sandbox is reached at |
66
+ | `IMPELLO_DEBUG` | `false` | Talk to `http://localhost:3000` |
67
+
68
+ The `E2B_` fallback is the migration, not politeness. Callers already export
69
+ `E2B_API_KEY`, `E2B_API_URL` and `E2B_DOMAIN`. Rename when it suits you.
70
+ Nothing breaks if you never do.
71
+
72
+ Only the domain has a default. Without one the SDK falls back to E2B's own
73
+ `e2b.app`, and the failure is a connection to somebody else's fleet.
74
+
75
+ Params passed to a single call beat a client's params, which beat the
76
+ environment. That is E2B's own rule and this package keeps it.
77
+
78
+ ## Why this one is a wrapper, when the TypeScript one is a copy
79
+
80
+ The TypeScript client cannot talk to Impello at all. Its `validateApiKey` runs
81
+ inside the `ApiClient` constructor, is not exported, has no off switch, and
82
+ accepts only `e2b_`. So `@impello/sdk` had to be a copy.
83
+
84
+ Python has no `e2b_` pattern anywhere. It takes an `imp_` key today. So the
85
+ only thing missing is where to send the request, and that is all this package
86
+ supplies.
87
+
88
+ It supplies it through `ClientFactory._resolve_api_params`, which is E2B's own
89
+ seam for binding defaults. That means one method is overridden rather than the
90
+ twelve descriptors on `Sandbox`, and **`e2b` itself is untouched**: importing
91
+ `impello` does not retarget a plain `e2b` call in the same process, and it
92
+ never writes to `os.environ`. A test holds that.
93
+
94
+ ## This package will be replaced
95
+
96
+ A permanent wrapper is the worst outcome. `pip show impello` prints `e2b`, and
97
+ the client sends a `publisher: e2b` header to our own servers. So the wrapper
98
+ ships now and the full clone lands before we take payments, with
99
+ `e2b/api/client/` regenerated from our own spec.
100
+
101
+ See `docs/decisions/sdk-self-contained.md`.
102
+
103
+ ## Develop
104
+
105
+ ```bash
106
+ python -m venv .venv
107
+ ./.venv/bin/pip install -e . pytest
108
+ ./.venv/bin/python -m pytest
109
+ ```
@@ -0,0 +1,5 @@
1
+ impello/__init__.py,sha256=q0y_VBGCMoc7I2rejzF_2BjBgz-jltSmT87aExAwolE,2773
2
+ impello/_defaults.py,sha256=CXTF0-azML2Ph1el9Rr1P0Fgd9ZKHVLfUIcGOm5Z89M,1910
3
+ impello-0.2.0.dist-info/METADATA,sha256=viSALj9ELZONVDtmF1KipvR7HGSuDIxjvkIkUn5musk,3287
4
+ impello-0.2.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
5
+ impello-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any