code-sandboxes 1.4.5__tar.gz → 1.7.0__tar.gz
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.
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/CHANGELOG.md +47 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/Makefile +18 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/PKG-INFO +1 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/__version__.py +1 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/base.py +52 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/cloudflare_sandbox.py +2 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/coreweave_sandbox.py +2 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/datalayer_sandbox.py +13 -13
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/daytona_sandbox.py +2 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/docker_sandbox.py +19 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/e2b_sandbox.py +2 -1
- code_sandboxes-1.7.0/code_sandboxes/environments/__init__.py +119 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/__main__.py +31 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/adapters/__init__.py +11 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/bases.py +194 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/builders.py +272 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/canonical.py +121 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/conformance.py +655 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/constraints/sandbox-contract-v1.txt +27 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/contract.py +559 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/doctor/__init__.py +13 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/doctor/build.py +47 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/doctor/datalayer_sandbox.py +441 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/doctor/report.schema.json +112 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/errors.py +316 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/files.py +73 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/lifecycle.py +237 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/redact.py +424 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/resolve.py +887 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/schema.py +68 -0
- code_sandboxes-1.7.0/code_sandboxes/environments/spec.py +598 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/eval_sandbox.py +2 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/google_colab_sandbox.py +14 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/jupyter_ingress.py +30 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/jupyter_server_sandbox.py +13 -6
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/kaggle_sandbox.py +14 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/manage.py +43 -6
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/modal_sandbox.py +2 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/models.py +8 -1
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/monty_sandbox.py +21 -1
- code_sandboxes-1.7.0/docs/docs/environments/_category_.yml +2 -0
- code_sandboxes-1.7.0/docs/docs/environments/contract.mdx +57 -0
- code_sandboxes-1.7.0/docs/docs/environments/index.mdx +167 -0
- code_sandboxes-1.7.0/docs/docs/environments/specification.mdx +53 -0
- code_sandboxes-1.7.0/docs/docs/environments/spike-2026-09.mdx +114 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/pyproject.toml +9 -0
- code_sandboxes-1.7.0/schemas/environment-v1alpha1.json +497 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_a_datalayer_sandbox_can_be_interrupted.py +11 -93
- code_sandboxes-1.7.0/tests/test_environment_bases.py +100 -0
- code_sandboxes-1.7.0/tests/test_environment_builders.py +281 -0
- code_sandboxes-1.7.0/tests/test_environment_canonical.py +121 -0
- code_sandboxes-1.7.0/tests/test_environment_conformance.py +357 -0
- code_sandboxes-1.7.0/tests/test_environment_constraints.py +64 -0
- code_sandboxes-1.7.0/tests/test_environment_contract.py +159 -0
- code_sandboxes-1.7.0/tests/test_environment_doctor.py +259 -0
- code_sandboxes-1.7.0/tests/test_environment_errors.py +184 -0
- code_sandboxes-1.7.0/tests/test_environment_lifecycle.py +170 -0
- code_sandboxes-1.7.0/tests/test_environment_redact.py +269 -0
- code_sandboxes-1.7.0/tests/test_environment_resolve.py +495 -0
- code_sandboxes-1.7.0/tests/test_environment_spec.py +345 -0
- code_sandboxes-1.7.0/tests/test_every_variant_has_a_real_interrupt.py +262 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_jupyter_server.py +24 -0
- code_sandboxes-1.7.0/tests/test_manage_datalayer.py +102 -0
- code_sandboxes-1.7.0/tests/test_the_kill_relaunch_drill.py +131 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.github/workflows/build.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.github/workflows/py-code-style.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.github/workflows/py-tests.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.github/workflows/py-typing.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.github/workflows/reusable-python.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.gitignore +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.licenserc.yaml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.pre-commit-config.yaml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/.vscode/settings.json +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/Dockerfile +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/LICENSE +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/README.md +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/__init__.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/bridge_mount.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/builds.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/cli.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/client.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/commands.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/console.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/contents.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/exceptions.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/filesystem.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/google_colab.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/interfaces.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/kaggle.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/kaggle_execute.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/kaggle_live.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/lifecycle.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/provider_ingress.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/code_sandboxes/providers.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docker/Dockerfile +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/.gitignore +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/LICENSE +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/Makefile +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/README.md +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/babel.config.js +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/api-reference/_category_.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/api-reference/index.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/cli/_category_.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/cli/index.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/contribute/_category_.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/contribute/index.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/examples/_category_.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/examples/index.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/guide/_category_.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/guide/index.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/index.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/install/_category_.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/install/index.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/provider-ingress.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/_category_.yml +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/cloudflare.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/coreweave.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/datalayer.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/daytona.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/docker.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/e2b.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/eval.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/google-colab.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/index.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/jupyter-server.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/kaggle.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/modal.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docs/providers/monty.mdx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/docusaurus.config.js +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/package.json +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/sidebars.js +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/components/HomepageRow1.js +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/components/HomepageRow1.module.css +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/components/HomepageRow2.js +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/components/HomepageRow2.module.css +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/components/HomepageRow3.js +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/components/HomepageRow3.module.css +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/css/custom.css +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/pages/index.module.css +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/pages/markdown-page.md +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/theme/CustomDocItem.tsx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/src/theme/IconsTitle.tsx +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/bricks.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/building-construction.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/cloud-sun.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/cloud.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/collaboration.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/copy-left.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/datalayer/logo.png +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/datalayer/logo.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/datalayer/personas/business.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/datalayer/personas/data-scientist.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/datalayer/personas/devops.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/datalayer/project/project-line.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/favicon.ico +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/jupyter.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/open-source.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/react-js.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/react-js2.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/ringed-planet.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/robot.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/rocket.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/shield.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/sparkles.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/streamlit.gif +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/super-hero.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/target.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/docs/static/img/thumbs-up.svg +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/README.md +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/Makefile +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/exec/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/Makefile +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/examples/repl/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/__init__.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/conftest.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_bridge_mount.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_builds.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_cli_exec.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_cli_repl.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_client.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_client_contents.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_client_files.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_client_outcome_error_output.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_cloudflare.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_commands_envelope.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_console.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_contents_contract.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_contents_live_matrix.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_coreweave.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_datalayer_sandbox.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_daytona.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_e2b.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_eval.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_factory.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_google_colab.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_integration.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_jupyter_ingress.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_jupyter_server_streaming.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_kaggle.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_kaggle_execute.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_kaggle_live.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_kaggle_session.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_kernel_client_compatibility.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_lifecycle_vocabulary.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_manage.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_modal_google_colab_sandbox.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_modal_session.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_models.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_output_line_fidelity.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_provider_catalog_names.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_provider_ingress.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_providers.py +0 -0
- {code_sandboxes-1.4.5 → code_sandboxes-1.7.0}/tests/test_sandboxes.py +0 -0
|
@@ -8,6 +8,53 @@
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 1.7.0
|
|
12
|
+
|
|
13
|
+
- **A version is resolved into one lock** (`code_sandboxes.environments.resolve`,
|
|
14
|
+
PLAN_ENV.md E1-04, D-9). Datalayer's protected constraints are merged over the
|
|
15
|
+
user's requirements — a requirement that agrees with a pin is dropped for it,
|
|
16
|
+
one that contradicts it is `DL_ENV_PROTECTED_PACKAGE` with the supported range
|
|
17
|
+
— the base is resolved to a digest per requested variant, and uv's refusals
|
|
18
|
+
are read into the error taxonomy: a conflict with the pair that cannot hold, a
|
|
19
|
+
package no index has, a protected pin, and `DL_ENV_PROVIDER_ERROR`, which is
|
|
20
|
+
retryable, for a failure that is not about the version.
|
|
21
|
+
|
|
22
|
+
The lock is uv's hashed output with the apt pins and the protected pins above
|
|
23
|
+
it as comments: one document that says everything a build installs, and still
|
|
24
|
+
a requirements file. `BuildkitResolveRunner` is D-9's solve, `FROM` the
|
|
25
|
+
resolved base digest; `LocalResolveRunner` runs `uv` where it is called, for
|
|
26
|
+
`plane local`, and refuses to pin apt rather than lock another
|
|
27
|
+
distribution's versions.
|
|
28
|
+
|
|
29
|
+
- **Every variant has a real interrupt now, and can be reached to give it.**
|
|
30
|
+
`Sandbox.interrupt` is two gates — `_executing_event` must be set, then
|
|
31
|
+
`_do_interrupt` must answer — and seven variants failed one of them, each in
|
|
32
|
+
a way that looked like success:
|
|
33
|
+
|
|
34
|
+
- `docker`, `google_colab`, `kaggle` and `monty` had no `_do_interrupt`, so
|
|
35
|
+
the base default ran: set a flag, return `True`, stop nothing. `True` means
|
|
36
|
+
"the interrupt was delivered", and nothing had been. `google_colab` and
|
|
37
|
+
`kaggle` did read the flag, but only *after* the run, to label a finished
|
|
38
|
+
result as `interrupted` — labelling a run is not stopping one.
|
|
39
|
+
- `cloudflare`, `coreweave`, `daytona`, `e2b` and `modal` answered honestly
|
|
40
|
+
(`False`: this provider takes no interrupt) but never marked their execution
|
|
41
|
+
window, so `interrupt()` returned at the first gate and their answer was
|
|
42
|
+
never reached — and `is_executing` was always False, which every status
|
|
43
|
+
above them believed.
|
|
44
|
+
|
|
45
|
+
Docker, Colab and Kaggle now interrupt for real, delegating to the
|
|
46
|
+
`JupyterKernelClient` that already knows how to authenticate to their server
|
|
47
|
+
rather than rebuilding the request. Monty answers `False` with its reason:
|
|
48
|
+
`feed_run` executes a snippet in one blocking call with no limits and no
|
|
49
|
+
callable hook, so there is no point at which a flag could be read.
|
|
50
|
+
|
|
51
|
+
The execution window is `@marks_execution` on `run_code` rather than a line
|
|
52
|
+
in each body, because it has to close on *every* path out — including the
|
|
53
|
+
early `return ExecutionResult(...)` each adapter uses for an infrastructure
|
|
54
|
+
failure — and a `finally` in the decorator cannot be forgotten in one branch
|
|
55
|
+
of one variant. Both invariants are asserted across the package with no
|
|
56
|
+
pinned exceptions left.
|
|
57
|
+
|
|
11
58
|
- A Datalayer sandbox says when it is running code, so an interrupt can reach
|
|
12
59
|
it. `Sandbox.interrupt` refuses before it delegates — `if not
|
|
13
60
|
self._executing_event.is_set(): return False` — and `run_code` never set that
|
|
@@ -32,10 +32,28 @@ build:
|
|
|
32
32
|
test:
|
|
33
33
|
pytest -q
|
|
34
34
|
|
|
35
|
+
## Build the datalayer-sandbox doctor as a single-file zipapp.
|
|
36
|
+
doctor-zipapp:
|
|
37
|
+
python -m code_sandboxes.environments.doctor.build dist/datalayer-sandbox
|
|
38
|
+
|
|
39
|
+
## Regenerate the Environment JSON Schema and the sandbox contract page.
|
|
40
|
+
environments-generate:
|
|
41
|
+
python -m code_sandboxes.environments schema --write
|
|
42
|
+
python -m code_sandboxes.environments contract --markdown docs/docs/environments/contract.mdx
|
|
43
|
+
|
|
44
|
+
## Fail when the Environment JSON Schema or the sandbox contract page has drifted.
|
|
45
|
+
environments-check:
|
|
46
|
+
python -m code_sandboxes.environments schema --check
|
|
47
|
+
python -m code_sandboxes.environments contract --check docs/docs/environments/contract.mdx
|
|
48
|
+
|
|
35
49
|
## The Contents provider matrix against the real providers (skips those without credentials).
|
|
36
50
|
live-matrix:
|
|
37
51
|
CODE_SANDBOXES_LIVE=1 pytest -q -m live tests/test_contents_live_matrix.py
|
|
38
52
|
|
|
53
|
+
## Lose a sandbox on each live provider and check the harness says so.
|
|
54
|
+
kill-relaunch:
|
|
55
|
+
CODE_SANDBOXES_LIVE=1 pytest -q -m live tests/test_the_kill_relaunch_drill.py
|
|
56
|
+
|
|
39
57
|
clean: ## clean
|
|
40
58
|
git clean -fdx
|
|
41
59
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import functools
|
|
9
10
|
import threading
|
|
10
11
|
import uuid
|
|
11
12
|
from abc import ABC, abstractmethod
|
|
@@ -82,6 +83,49 @@ def generate_sandbox_name() -> str:
|
|
|
82
83
|
DEFAULT_ENVIRONMENT = "ai-agents-env"
|
|
83
84
|
|
|
84
85
|
|
|
86
|
+
def marks_execution(run):
|
|
87
|
+
"""Say, for the duration of the call, that this sandbox is running code.
|
|
88
|
+
|
|
89
|
+
`Sandbox.interrupt` refuses before it delegates::
|
|
90
|
+
|
|
91
|
+
if not self._executing_event.is_set():
|
|
92
|
+
return False
|
|
93
|
+
self._interrupt_requested.set()
|
|
94
|
+
return self._do_interrupt()
|
|
95
|
+
|
|
96
|
+
So a variant that never sets the event has an interrupt nothing can
|
|
97
|
+
reach, and an `is_executing` that is always False — every status and
|
|
98
|
+
every cancel decision above it silently wrong. `DatalayerSandbox` was in
|
|
99
|
+
exactly that state, and implementing `_do_interrupt` for it changed the
|
|
100
|
+
measurement on prod1 from 60.8 seconds to 60.5: a fix that reads as
|
|
101
|
+
complete and measures as nothing.
|
|
102
|
+
|
|
103
|
+
A decorator rather than a line in each body, because the window has to
|
|
104
|
+
close on *every* path out — including the several early `return
|
|
105
|
+
ExecutionResult(...)`s that each adapter uses for an infrastructure
|
|
106
|
+
failure — and a `finally` here cannot be forgotten in one branch of one
|
|
107
|
+
variant. It also gives the invariant something to test that is not a
|
|
108
|
+
grep for a line of source.
|
|
109
|
+
|
|
110
|
+
`_interrupt_requested` is cleared on the way in, so a stale request from
|
|
111
|
+
a previous call cannot stop this one, and deliberately *not* on the way
|
|
112
|
+
out: the cooperative variants read it after the run to report that the
|
|
113
|
+
execution was interrupted.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
@functools.wraps(run)
|
|
117
|
+
def marked(self, *args, **kwargs):
|
|
118
|
+
self._interrupt_requested.clear()
|
|
119
|
+
self._executing_event.set()
|
|
120
|
+
try:
|
|
121
|
+
return run(self, *args, **kwargs)
|
|
122
|
+
finally:
|
|
123
|
+
self._executing_event.clear()
|
|
124
|
+
|
|
125
|
+
marked._marks_execution = True
|
|
126
|
+
return marked
|
|
127
|
+
|
|
128
|
+
|
|
85
129
|
class Sandbox(ABC):
|
|
86
130
|
"""Abstract base class for code execution sandboxes.
|
|
87
131
|
|
|
@@ -455,6 +499,7 @@ class Sandbox(ABC):
|
|
|
455
499
|
timeout: float | None = None,
|
|
456
500
|
name: str | None = None,
|
|
457
501
|
environment: str | None = None,
|
|
502
|
+
environment_version: str | int | None = None,
|
|
458
503
|
gpu: str | None = None,
|
|
459
504
|
cpu: float | None = None,
|
|
460
505
|
memory: int | None = None,
|
|
@@ -481,7 +526,12 @@ class Sandbox(ABC):
|
|
|
481
526
|
config: Optional full configuration object (overrides individual params).
|
|
482
527
|
timeout: Default timeout for code execution in seconds.
|
|
483
528
|
name: Optional name for the sandbox.
|
|
484
|
-
environment: Runtime environment (e.g., "ai-agents-env")
|
|
529
|
+
environment: Runtime environment (e.g., "ai-agents-env"), or a user
|
|
530
|
+
environment as "<account-handle>/<name>" or by its uid.
|
|
531
|
+
environment_version: Which version of a user environment to launch:
|
|
532
|
+
its number, or a version uid. Without one the promoted version
|
|
533
|
+
launches, which is what a platform environment always does.
|
|
534
|
+
Only the datalayer variant has versions (PLAN_ENV.md, E1-19).
|
|
485
535
|
gpu: GPU type to use (e.g., "T4", "A100", "H100"). Only for datalayer.
|
|
486
536
|
cpu: CPU cores to allocate.
|
|
487
537
|
memory: Memory limit in MB.
|
|
@@ -515,6 +565,7 @@ class Sandbox(ABC):
|
|
|
515
565
|
config = SandboxConfig(
|
|
516
566
|
timeout=timeout or 30.0,
|
|
517
567
|
environment=environment or DEFAULT_ENVIRONMENT,
|
|
568
|
+
environment_version=environment_version,
|
|
518
569
|
memory_limit=memory * 1024 * 1024 if memory else None,
|
|
519
570
|
cpu_limit=cpu,
|
|
520
571
|
env_vars=env or {},
|
|
@@ -43,7 +43,7 @@ from collections.abc import Iterator
|
|
|
43
43
|
from typing import Any
|
|
44
44
|
from urllib.parse import quote
|
|
45
45
|
|
|
46
|
-
from .base import Sandbox
|
|
46
|
+
from .base import Sandbox, marks_execution
|
|
47
47
|
from .exceptions import (
|
|
48
48
|
SandboxConfigurationError,
|
|
49
49
|
SandboxConnectionError,
|
|
@@ -370,6 +370,7 @@ class CloudflareSandbox(Sandbox):
|
|
|
370
370
|
except Exception:
|
|
371
371
|
return False
|
|
372
372
|
|
|
373
|
+
@marks_execution
|
|
373
374
|
def run_code(
|
|
374
375
|
self,
|
|
375
376
|
code: str,
|
|
@@ -31,7 +31,7 @@ import math
|
|
|
31
31
|
import time
|
|
32
32
|
from typing import Any
|
|
33
33
|
|
|
34
|
-
from .base import Sandbox
|
|
34
|
+
from .base import Sandbox, marks_execution
|
|
35
35
|
from .exceptions import (
|
|
36
36
|
SandboxConfigurationError,
|
|
37
37
|
SandboxExecutionError,
|
|
@@ -521,6 +521,7 @@ class CoreWeaveSandbox(Sandbox):
|
|
|
521
521
|
if self._info:
|
|
522
522
|
self._info.status = SandboxStatus.STOPPED
|
|
523
523
|
|
|
524
|
+
@marks_execution
|
|
524
525
|
def run_code(
|
|
525
526
|
self,
|
|
526
527
|
code: str,
|
|
@@ -17,7 +17,7 @@ from typing import TYPE_CHECKING, Any, Optional
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
18
|
from .filesystem import SandboxFileHandle
|
|
19
19
|
|
|
20
|
-
from .base import Sandbox
|
|
20
|
+
from .base import Sandbox, marks_execution
|
|
21
21
|
from .contents import (
|
|
22
22
|
FILESYSTEM_PRIMITIVES,
|
|
23
23
|
LOCAL_BRIDGE_MOUNT,
|
|
@@ -475,11 +475,19 @@ class DatalayerSandbox(Sandbox):
|
|
|
475
475
|
# Build sandbox name
|
|
476
476
|
sandbox_name = self.config.name or f"sandbox-{self._sandbox_id[:8]}"
|
|
477
477
|
|
|
478
|
+
# Which VERSION of that environment, passed through as the
|
|
479
|
+
# environment is (PLAN_ENV.md, E1-19). `None` means the promoted
|
|
480
|
+
# version, which is what every platform environment launches — and
|
|
481
|
+
# what every sandbox launched before there were versions asked for.
|
|
482
|
+
# The GPU rewrite above is left exactly as it is until E4-11 (D-20).
|
|
483
|
+
environment_version = self.config.environment_version
|
|
484
|
+
|
|
478
485
|
# Create the runtime (optionally from snapshot)
|
|
479
486
|
if self._snapshot_name:
|
|
480
487
|
self._runtime = self._client.create_runtime(
|
|
481
488
|
name=sandbox_name,
|
|
482
489
|
environment=environment,
|
|
490
|
+
version=environment_version,
|
|
483
491
|
time_reservation=time_reservation,
|
|
484
492
|
snapshot_name=self._snapshot_name,
|
|
485
493
|
)
|
|
@@ -487,6 +495,7 @@ class DatalayerSandbox(Sandbox):
|
|
|
487
495
|
self._runtime = self._client.create_runtime(
|
|
488
496
|
name=sandbox_name,
|
|
489
497
|
environment=environment,
|
|
498
|
+
version=environment_version,
|
|
490
499
|
time_reservation=time_reservation,
|
|
491
500
|
)
|
|
492
501
|
|
|
@@ -761,6 +770,7 @@ class DatalayerSandbox(Sandbox):
|
|
|
761
770
|
return None
|
|
762
771
|
return 0
|
|
763
772
|
|
|
773
|
+
@marks_execution
|
|
764
774
|
def run_code(
|
|
765
775
|
self,
|
|
766
776
|
code: str,
|
|
@@ -801,17 +811,9 @@ class DatalayerSandbox(Sandbox):
|
|
|
801
811
|
|
|
802
812
|
started_at = time.time()
|
|
803
813
|
|
|
804
|
-
#
|
|
805
|
-
#
|
|
806
|
-
# before reaching `_do_interrupt` when `_executing_event` is clear,
|
|
807
|
-
# and this variant never set it — so `is_executing` was always False,
|
|
808
|
-
# every interrupt was refused at the door, and the refusal was
|
|
809
|
-
# reported as "no code was running" to a caller watching a cell run.
|
|
810
|
-
# Implementing `_do_interrupt` alone did not fix cancellation for
|
|
811
|
-
# exactly this reason: nothing ever called it.
|
|
814
|
+
# The execution window is `@marks_execution`'s, not this body's — see
|
|
815
|
+
# its docstring for why the interrupt is refused without one.
|
|
812
816
|
execution_timeout = timeout or self.config.timeout
|
|
813
|
-
self._interrupt_requested.clear()
|
|
814
|
-
self._executing_event.set()
|
|
815
817
|
try:
|
|
816
818
|
# Set environment variables if provided
|
|
817
819
|
if envs:
|
|
@@ -831,8 +833,6 @@ class DatalayerSandbox(Sandbox):
|
|
|
831
833
|
started_at=started_at,
|
|
832
834
|
completed_at=time.time(),
|
|
833
835
|
)
|
|
834
|
-
finally:
|
|
835
|
-
self._executing_event.clear()
|
|
836
836
|
|
|
837
837
|
# Parse the response
|
|
838
838
|
stdout_messages: list[OutputMessage] = []
|
|
@@ -30,7 +30,7 @@ import textwrap
|
|
|
30
30
|
import time
|
|
31
31
|
from typing import Any
|
|
32
32
|
|
|
33
|
-
from .base import Sandbox
|
|
33
|
+
from .base import Sandbox, marks_execution
|
|
34
34
|
from .contents import (
|
|
35
35
|
FILESYSTEM_PRIMITIVES,
|
|
36
36
|
ContentAttachmentSpec,
|
|
@@ -701,6 +701,7 @@ class DaytonaSandbox(Sandbox):
|
|
|
701
701
|
self._contexts[context.id] = existing
|
|
702
702
|
return existing
|
|
703
703
|
|
|
704
|
+
@marks_execution
|
|
704
705
|
def run_code( # noqa: C901
|
|
705
706
|
self,
|
|
706
707
|
code: str,
|
|
@@ -15,9 +15,12 @@ import tempfile
|
|
|
15
15
|
import time
|
|
16
16
|
import uuid
|
|
17
17
|
|
|
18
|
+
import logging
|
|
19
|
+
|
|
18
20
|
import requests
|
|
19
21
|
|
|
20
|
-
from .base import Sandbox
|
|
22
|
+
from .base import Sandbox, marks_execution
|
|
23
|
+
from .jupyter_ingress import interrupt_kernel_client
|
|
21
24
|
from .exceptions import SandboxConfigurationError, SandboxNotStartedError
|
|
22
25
|
from .interfaces import ISandboxClient
|
|
23
26
|
from .models import (
|
|
@@ -34,6 +37,8 @@ from .models import (
|
|
|
34
37
|
SandboxStatus,
|
|
35
38
|
)
|
|
36
39
|
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
37
42
|
DEFAULT_IMAGE = "code-sandboxes-jupyter:latest"
|
|
38
43
|
DEFAULT_PORT = 8888
|
|
39
44
|
|
|
@@ -194,6 +199,18 @@ class DockerSandbox(Sandbox):
|
|
|
194
199
|
"""The underlying kernel client for this sandbox, if started."""
|
|
195
200
|
return self._client
|
|
196
201
|
|
|
202
|
+
def _do_interrupt(self) -> bool:
|
|
203
|
+
"""Interrupt the container's kernel, through the client that runs it.
|
|
204
|
+
|
|
205
|
+
This variant runs a Jupyter Server in a container and executes
|
|
206
|
+
through `jupyter-kernel-client`, so it can be interrupted — and it
|
|
207
|
+
had no `_do_interrupt` at all, so the base class's default ran: sets
|
|
208
|
+
a flag, returns `True`, stops nothing. A caller that cancelled a long
|
|
209
|
+
cell here was told the interrupt had been delivered while the
|
|
210
|
+
container went on computing.
|
|
211
|
+
"""
|
|
212
|
+
return interrupt_kernel_client(self._client, variant="container's")
|
|
213
|
+
|
|
197
214
|
def stop(self) -> None:
|
|
198
215
|
if not self._started:
|
|
199
216
|
return
|
|
@@ -225,6 +242,7 @@ class DockerSandbox(Sandbox):
|
|
|
225
242
|
if self._info:
|
|
226
243
|
self._info.status = SandboxStatus.STOPPED
|
|
227
244
|
|
|
245
|
+
@marks_execution
|
|
228
246
|
def run_code(
|
|
229
247
|
self,
|
|
230
248
|
code: str,
|
|
@@ -28,7 +28,7 @@ import logging
|
|
|
28
28
|
import time
|
|
29
29
|
from typing import Any
|
|
30
30
|
|
|
31
|
-
from .base import Sandbox
|
|
31
|
+
from .base import Sandbox, marks_execution
|
|
32
32
|
from .contents import (
|
|
33
33
|
FILESYSTEM_PRIMITIVES,
|
|
34
34
|
ContentAttachmentSpec,
|
|
@@ -471,6 +471,7 @@ class E2BSandbox(Sandbox):
|
|
|
471
471
|
self._contexts[context.id] = existing
|
|
472
472
|
return existing
|
|
473
473
|
|
|
474
|
+
@marks_execution
|
|
474
475
|
def run_code(
|
|
475
476
|
self,
|
|
476
477
|
code: str,
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026 Datalayer, Inc.
|
|
2
|
+
#
|
|
3
|
+
# BSD 3-Clause License
|
|
4
|
+
|
|
5
|
+
"""Environments: define once, resolve once, build an immutable artifact per variant.
|
|
6
|
+
|
|
7
|
+
An **Environment** is the stable object a person names. An **Environment
|
|
8
|
+
Version** is immutable once it leaves draft: its spec, the lock resolved from
|
|
9
|
+
it, and its build outcome. An **Environment Artifact** is the build output of
|
|
10
|
+
one version on one variant — an OCI digest for Datalayer, a build id for E2B,
|
|
11
|
+
a snapshot id for Daytona, an image id for Modal.
|
|
12
|
+
|
|
13
|
+
This package holds what every party to that life shares, and nothing
|
|
14
|
+
provider-specific:
|
|
15
|
+
|
|
16
|
+
- :mod:`.spec` — the canonical specification and its rules;
|
|
17
|
+
- :mod:`.resolve` — the lock a version is resolved into, once (D-9);
|
|
18
|
+
- :mod:`.contract` — ``sandbox-contract/v1`` and the Dockerfile validator;
|
|
19
|
+
- :mod:`.lifecycle` — the version states and their legal moves;
|
|
20
|
+
- :mod:`.errors` — the error taxonomy every provider error maps into;
|
|
21
|
+
- :mod:`.builders` — the builder interface and its neutral types;
|
|
22
|
+
- :mod:`.conformance` — the checks an artifact passes before it is ready;
|
|
23
|
+
- :mod:`.redact` — a build's log with its secrets taken out before it is stored;
|
|
24
|
+
- :mod:`.doctor` — the in-sandbox contract checker.
|
|
25
|
+
|
|
26
|
+
The builders themselves are in :mod:`.adapters`, loaded by variant.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
from .bases import APPROVED_BASES, ApprovedBase
|
|
32
|
+
from .builders import (
|
|
33
|
+
ArtifactReference,
|
|
34
|
+
BuildRequest,
|
|
35
|
+
CapabilityReport,
|
|
36
|
+
CapabilitySet,
|
|
37
|
+
CheckResult,
|
|
38
|
+
EnvironmentBuilder,
|
|
39
|
+
ValidationResult,
|
|
40
|
+
get_builder,
|
|
41
|
+
)
|
|
42
|
+
from .canonical import canonical_digest, canonical_json
|
|
43
|
+
from .contract import (
|
|
44
|
+
CONTRACT_V1,
|
|
45
|
+
SANDBOX_CONTRACT_V1,
|
|
46
|
+
SUPPORTED_CONTRACTS,
|
|
47
|
+
SandboxContract,
|
|
48
|
+
check_dockerfile,
|
|
49
|
+
validate_dockerfile,
|
|
50
|
+
)
|
|
51
|
+
from .errors import ERROR_CODES, EnvironmentsError, ErrorCode, map_provider_error
|
|
52
|
+
from .lifecycle import VersionState, build_outcome, can_transition, transition
|
|
53
|
+
from .resolve import (
|
|
54
|
+
LOCK_FORMAT,
|
|
55
|
+
BuildkitResolveRunner,
|
|
56
|
+
LocalResolveRunner,
|
|
57
|
+
ResolveRunner,
|
|
58
|
+
locked_versions,
|
|
59
|
+
merge_requirements,
|
|
60
|
+
parse_resolver_failure,
|
|
61
|
+
protected_pins,
|
|
62
|
+
resolve_environment,
|
|
63
|
+
)
|
|
64
|
+
from .spec import (
|
|
65
|
+
API_VERSION,
|
|
66
|
+
VARIANTS,
|
|
67
|
+
Environment,
|
|
68
|
+
EnvironmentSpec,
|
|
69
|
+
parse_environment,
|
|
70
|
+
spec_digest,
|
|
71
|
+
spec_findings,
|
|
72
|
+
validate_environment,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
__all__ = [
|
|
76
|
+
"API_VERSION",
|
|
77
|
+
"APPROVED_BASES",
|
|
78
|
+
"CONTRACT_V1",
|
|
79
|
+
"ERROR_CODES",
|
|
80
|
+
"LOCK_FORMAT",
|
|
81
|
+
"SANDBOX_CONTRACT_V1",
|
|
82
|
+
"SUPPORTED_CONTRACTS",
|
|
83
|
+
"VARIANTS",
|
|
84
|
+
"ApprovedBase",
|
|
85
|
+
"ArtifactReference",
|
|
86
|
+
"BuildkitResolveRunner",
|
|
87
|
+
"BuildRequest",
|
|
88
|
+
"CapabilityReport",
|
|
89
|
+
"CapabilitySet",
|
|
90
|
+
"CheckResult",
|
|
91
|
+
"Environment",
|
|
92
|
+
"EnvironmentBuilder",
|
|
93
|
+
"EnvironmentSpec",
|
|
94
|
+
"EnvironmentsError",
|
|
95
|
+
"ErrorCode",
|
|
96
|
+
"LocalResolveRunner",
|
|
97
|
+
"ResolveRunner",
|
|
98
|
+
"SandboxContract",
|
|
99
|
+
"ValidationResult",
|
|
100
|
+
"VersionState",
|
|
101
|
+
"build_outcome",
|
|
102
|
+
"can_transition",
|
|
103
|
+
"canonical_digest",
|
|
104
|
+
"canonical_json",
|
|
105
|
+
"check_dockerfile",
|
|
106
|
+
"get_builder",
|
|
107
|
+
"locked_versions",
|
|
108
|
+
"merge_requirements",
|
|
109
|
+
"map_provider_error",
|
|
110
|
+
"parse_environment",
|
|
111
|
+
"parse_resolver_failure",
|
|
112
|
+
"protected_pins",
|
|
113
|
+
"resolve_environment",
|
|
114
|
+
"spec_digest",
|
|
115
|
+
"spec_findings",
|
|
116
|
+
"transition",
|
|
117
|
+
"validate_dockerfile",
|
|
118
|
+
"validate_environment",
|
|
119
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026 Datalayer, Inc.
|
|
2
|
+
#
|
|
3
|
+
# BSD 3-Clause License
|
|
4
|
+
|
|
5
|
+
"""Generate what is generated from the Environment models.
|
|
6
|
+
|
|
7
|
+
python -m code_sandboxes.environments schema --write [PATH]
|
|
8
|
+
python -m code_sandboxes.environments schema --check [PATH]
|
|
9
|
+
python -m code_sandboxes.environments contract --markdown docs/docs/environments/contract.mdx
|
|
10
|
+
python -m code_sandboxes.environments contract --check docs/docs/environments/contract.mdx
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
from . import contract, schema
|
|
18
|
+
|
|
19
|
+
_COMMANDS = {"schema": schema.main, "contract": contract.main}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main(argv: list[str] | None = None) -> int:
|
|
23
|
+
arguments = list(sys.argv[1:] if argv is None else argv)
|
|
24
|
+
if not arguments or arguments[0] not in _COMMANDS:
|
|
25
|
+
print(__doc__.strip(), file=sys.stderr) # noqa: T201 - a command's own output
|
|
26
|
+
return 2
|
|
27
|
+
return _COMMANDS[arguments[0]](arguments[1:])
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if __name__ == "__main__":
|
|
31
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026 Datalayer, Inc.
|
|
2
|
+
#
|
|
3
|
+
# BSD 3-Clause License
|
|
4
|
+
|
|
5
|
+
"""The provider-specific Environment builders, one module per variant.
|
|
6
|
+
|
|
7
|
+
Not neutral: each module speaks its provider's SDK. They are loaded only by
|
|
8
|
+
:func:`code_sandboxes.environments.builders.get_builder`, and only where the
|
|
9
|
+
build runs — the durable worker — never by a service that merely describes
|
|
10
|
+
or launches an Environment.
|
|
11
|
+
"""
|