code-sandboxes 1.9.11__tar.gz → 1.9.13__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.9.11 → code_sandboxes-1.9.13}/CHANGELOG.md +17 -12
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/PKG-INFO +3 -1
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/__version__.py +1 -1
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/__init__.py +8 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/datalayer.py +58 -46
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/daytona.py +36 -11
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/e2b.py +38 -5
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/managed.py +61 -29
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/modal.py +29 -9
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/builders.py +40 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/conformance.py +19 -4
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/constraints/sandbox-contract-v1.txt +10 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/constraints/wheelhouse/README.md +7 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/contract.py +97 -1
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/resolve.py +25 -1
- code_sandboxes-1.9.13/code_sandboxes/environments/resolve_conda.py +913 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/spec.py +180 -31
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/environments/specification.mdx +2 -2
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/pyproject.toml +2 -1
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/schemas/environment-v1alpha1.json +3 -2
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_conformance.py +30 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_constraints.py +1 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_contract.py +51 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_datalayer_builder.py +43 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_daytona_builder.py +33 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_e2b_builder.py +45 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_managed_builders.py +46 -6
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_modal_builder.py +43 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_resolve.py +52 -1
- code_sandboxes-1.9.13/tests/test_environment_resolve_conda.py +476 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_spec.py +67 -4
- code_sandboxes-1.9.11/build.log +0 -5
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.github/workflows/build.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.github/workflows/environments-live.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.github/workflows/py-code-style.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.github/workflows/py-tests.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.github/workflows/py-typing.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.github/workflows/reusable-python.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.gitignore +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.licenserc.yaml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.pre-commit-config.yaml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/.vscode/settings.json +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/Dockerfile +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/LICENSE +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/Makefile +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/README.md +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/__init__.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/base.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/bridge_mount.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/builds.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/cli.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/client.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/cloudflare_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/commands.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/console.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/contents.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/coreweave_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/daytona_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/docker_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/e2b_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/__main__.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/accounts.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/__init__.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/attest.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/bases.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/breaker.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/build_secrets.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/canonical.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/constraints/wheelhouse/jupyter_server-2.21.0+datalayer.1-py3-none-any.whl +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/doctor/__init__.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/doctor/build.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/doctor/datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/doctor/report.schema.json +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/errors.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/files.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/image_import.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/lifecycle.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/policy.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/redact.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/schema.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/eval_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/exceptions.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/filesystem.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/google_colab.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/google_colab_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/interfaces.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/jupyter_ingress.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/jupyter_server_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/kaggle.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/kaggle_execute.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/kaggle_live.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/kaggle_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/lifecycle.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/manage.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/modal_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/models.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/monty_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/provider_ingress.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/providers.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docker/Dockerfile +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/.gitignore +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/LICENSE +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/Makefile +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/README.md +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/babel.config.js +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/api-reference/_category_.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/api-reference/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/cli/_category_.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/cli/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/contribute/_category_.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/contribute/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/environments/_category_.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/environments/contract.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/environments/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/environments/spike-2026-09.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/examples/_category_.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/examples/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/guide/_category_.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/guide/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/install/_category_.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/install/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/provider-ingress.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/_category_.yml +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/cloudflare.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/coreweave.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/datalayer.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/daytona.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/docker.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/e2b.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/eval.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/google-colab.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/index.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/jupyter-server.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/kaggle.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/modal.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docs/providers/monty.mdx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/docusaurus.config.js +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/package.json +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/sidebars.js +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/components/HomepageRow1.js +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/components/HomepageRow1.module.css +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/components/HomepageRow2.js +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/components/HomepageRow2.module.css +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/components/HomepageRow3.js +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/components/HomepageRow3.module.css +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/css/custom.css +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/pages/index.module.css +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/pages/markdown-page.md +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/theme/CustomDocItem.tsx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/src/theme/IconsTitle.tsx +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/bricks.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/building-construction.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/cloud-sun.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/cloud.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/collaboration.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/copy-left.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/datalayer/logo.png +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/datalayer/logo.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/datalayer/personas/business.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/datalayer/personas/data-scientist.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/datalayer/personas/devops.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/datalayer/project/project-line.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/favicon.ico +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/jupyter.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/open-source.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/react-js.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/react-js2.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/ringed-planet.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/robot.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/rocket.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/shield.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/sparkles.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/streamlit.gif +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/super-hero.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/target.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/docs/static/img/thumbs-up.svg +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/README.md +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/Makefile +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/exec/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/Makefile +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/examples/repl/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/__init__.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/conftest.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_a_datalayer_sandbox_can_be_interrupted.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_bridge_mount.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_builds.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_cli_exec.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_cli_repl.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_client.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_client_contents.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_client_files.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_client_outcome_error_output.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_cloudflare.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_commands_envelope.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_console.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_contents_contract.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_contents_live_matrix.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_coreweave.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_daytona.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_e2b.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_accounts.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_attest.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_bases.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_breaker.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_build_secrets.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_builders.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_canonical.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_cross_variant_report.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_doctor.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_errors.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_image_import.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_lifecycle.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_live_matrix.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_environment_redact.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_eval.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_every_variant_has_a_real_interrupt.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_factory.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_google_colab.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_integration.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_jupyter_ingress.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_jupyter_server.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_jupyter_server_streaming.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_kaggle.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_kaggle_execute.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_kaggle_live.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_kaggle_session.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_kernel_client_compatibility.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_lifecycle_vocabulary.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_manage.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_manage_datalayer.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_modal_google_colab_sandbox.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_modal_session.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_models.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_output_line_fidelity.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_provider_catalog_names.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_provider_ingress.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_providers.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_sandboxes.py +0 -0
- {code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/tests/test_the_kill_relaunch_drill.py +0 -0
|
@@ -8,6 +8,17 @@
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 1.9.12
|
|
12
|
+
|
|
13
|
+
- **`owner_repository`, `owner_cache_repository` and `ECR_ENVIRONMENT_PREFIX`
|
|
14
|
+
moved from `environments.adapters.datalayer` to `environments.builders`**
|
|
15
|
+
(PLAN_ENV E1-14): Runtimes now validates a smoke-test launch's artifact
|
|
16
|
+
against this same repository shape, and `builders` is the neutral module a
|
|
17
|
+
service may import — `adapters.datalayer` is not, and importing it from a
|
|
18
|
+
service binds that service to the Datalayer provider the way
|
|
19
|
+
`check_provider_boundary.py` exists to prevent. Re-exported from the
|
|
20
|
+
adapter unchanged, so every existing `from .datalayer import owner_repository` still works. No behavior change; 78 tests still pass.
|
|
21
|
+
|
|
11
22
|
## 1.9.11
|
|
12
23
|
|
|
13
24
|
- **1.9.10's own fix did not work: `--registry-referrers-mode` only ever
|
|
@@ -17,8 +28,7 @@
|
|
|
17
28
|
landed as an OCI 1.1 referrer, no legacy tag. `Attestor` no longer tries
|
|
18
29
|
to force cosign's own storage choice. Its replay check and its own
|
|
19
30
|
`signature_ref` now ask cosign directly, the same way the Operator's own
|
|
20
|
-
verify will: `can_verify(reference)` runs `cosign verify --key <key>
|
|
21
|
-
--insecure-ignore-tlog=true <reference>` and answers its exit code, and
|
|
31
|
+
verify will: `can_verify(reference)` runs `cosign verify --key <key> --insecure-ignore-tlog=true <reference>` and answers its exit code, and
|
|
22
32
|
`signature_ref` is the digest reference itself — what `cosign verify`
|
|
23
33
|
takes, not a tag it may or may not have written. Signing the same digest
|
|
24
34
|
twice no longer errors the way a second push under the old immutable tag
|
|
@@ -31,8 +41,7 @@
|
|
|
31
41
|
- **cosign signs the legacy tag again, not just an OCI referrer**
|
|
32
42
|
(`environments.attest`; PLAN_ENV.md E1-09). cosign 3.1.3 defaults to the
|
|
33
43
|
OCI 1.1 referrers API for a signature's own storage, not the classic
|
|
34
|
-
`sha256-<hex>.sig` sidecar tag. Found live on r1, 2026-09-14: `cosign
|
|
35
|
-
sign` reported success — the first artifact this pipeline ever actually
|
|
44
|
+
`sha256-<hex>.sig` sidecar tag. Found live on r1, 2026-09-14: `cosign sign` reported success — the first artifact this pipeline ever actually
|
|
36
45
|
signed — but pushed no such tag; `_signature_exists`'s own replay check
|
|
37
46
|
and the `signature_ref` this workflow records both assume one exists.
|
|
38
47
|
`--registry-referrers-mode=legacy` restores it. `cosign verify` needs no
|
|
@@ -54,8 +63,7 @@
|
|
|
54
63
|
## 1.9.8
|
|
55
64
|
|
|
56
65
|
- **Every page of a scan's findings is read before deciding**
|
|
57
|
-
(`environments.attest`; PLAN_ENV.md E1-08, D-11). `describe_image_scan_
|
|
58
|
-
findings` paginates, and the attestor called it exactly once. Found live
|
|
66
|
+
(`environments.attest`; PLAN_ENV.md E1-08, D-11). `describe_image_scan_ findings` paginates, and the attestor called it exactly once. Found live
|
|
59
67
|
on r1, 2026-09-14: the first real image with more findings than one page
|
|
60
68
|
had 1,547 enhanced findings, 31 of them critical, and the single-page read
|
|
61
69
|
saw a small enough slice that the decision passed — an image with real,
|
|
@@ -66,8 +74,7 @@
|
|
|
66
74
|
|
|
67
75
|
## 1.9.7
|
|
68
76
|
|
|
69
|
-
- **cosign signs again under `--use-signing-config=false`** (`environments
|
|
70
|
-
.attest`; PLAN_ENV.md E1-09). cosign 3.1.3 defaults `--use-signing-config`
|
|
77
|
+
- **cosign signs again under `--use-signing-config=false`** (`environments .attest`; PLAN_ENV.md E1-09). cosign 3.1.3 defaults `--use-signing-config`
|
|
71
78
|
to `true`: a TUF-provided signing config now names the service URLs,
|
|
72
79
|
including a transparency log, and `--tlog-upload=false` alone no longer
|
|
73
80
|
overrides that — cosign refused the combination outright (found live on
|
|
@@ -100,8 +107,7 @@
|
|
|
100
107
|
from the same snapshot. This replaces a `deb` line that named only `main`
|
|
101
108
|
(`gdal-bin` is in `universe`) and left the live mirror enabled beside it.
|
|
102
109
|
`DATALAYER_APT_SNAPSHOT` must now be a snapshot id.
|
|
103
|
-
- **A private registry's credential is resolved and used** (`environments
|
|
104
|
-
.image_import`, `environments.resolve`; PLAN_ENV.md E3-04's second half).
|
|
110
|
+
- **A private registry's credential is resolved and used** (`environments .image_import`, `environments.resolve`; PLAN_ENV.md E3-04's second half).
|
|
105
111
|
`image.credentialSecretId` used to only clear the allowlist check; nothing
|
|
106
112
|
fetched or used the credential it named. It is now fetched through the
|
|
107
113
|
same IAM route a build secret is (E3-05), and sent as HTTP Basic on the
|
|
@@ -113,8 +119,7 @@
|
|
|
113
119
|
- **The Datalayer base channel's own five ESM-locked advisories are allowed**
|
|
114
120
|
(`environments.policy`; PLAN_ENV.md E1-08). Amazon Inspector marks all five
|
|
115
121
|
fixable, but the fix is an Ubuntu ESM package version a plain
|
|
116
|
-
`apt-get upgrade` cannot reach. Reviewed and added to `DEFAULT_POLICY
|
|
117
|
-
.allowed`, 2026-09-14, so they are recorded as allowed rather than missed,
|
|
122
|
+
`apt-get upgrade` cannot reach. Reviewed and added to `DEFAULT_POLICY .allowed`, 2026-09-14, so they are recorded as allowed rather than missed,
|
|
118
123
|
and any other critical still blocks.
|
|
119
124
|
|
|
120
125
|
## 1.9.4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: code_sandboxes
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.13
|
|
4
4
|
Project-URL: Home, https://github.com/datalayer/code-sandboxes
|
|
5
5
|
Author-email: Datalayer <info@datalayer.io>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -45,6 +45,7 @@ Requires-Dist: jupyter-kernel-client>=1.0.2
|
|
|
45
45
|
Requires-Dist: jupyter-server
|
|
46
46
|
Requires-Dist: jupyter-server-client
|
|
47
47
|
Requires-Dist: pydantic>=2.0
|
|
48
|
+
Requires-Dist: pyyaml
|
|
48
49
|
Requires-Dist: rich
|
|
49
50
|
Requires-Dist: typer>=0.12.0
|
|
50
51
|
Provides-Extra: all
|
|
@@ -96,6 +97,7 @@ Requires-Dist: pytest-cov>=4.0; extra == 'test'
|
|
|
96
97
|
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
97
98
|
Provides-Extra: typing
|
|
98
99
|
Requires-Dist: mypy>=0.990; extra == 'typing'
|
|
100
|
+
Requires-Dist: types-pyyaml; extra == 'typing'
|
|
99
101
|
Description-Content-Type: text/markdown
|
|
100
102
|
|
|
101
103
|
<!--
|
|
@@ -49,8 +49,12 @@ from .contract import (
|
|
|
49
49
|
CONTRACT_V1,
|
|
50
50
|
SANDBOX_CONTRACT_V1,
|
|
51
51
|
SUPPORTED_CONTRACTS,
|
|
52
|
+
BuildContextEntry,
|
|
53
|
+
BuildContextFinding,
|
|
52
54
|
SandboxContract,
|
|
55
|
+
check_build_context,
|
|
53
56
|
check_dockerfile,
|
|
57
|
+
validate_build_context,
|
|
54
58
|
validate_dockerfile,
|
|
55
59
|
)
|
|
56
60
|
from .errors import ERROR_CODES, EnvironmentsError, ErrorCode, map_provider_error
|
|
@@ -91,6 +95,8 @@ __all__ = [
|
|
|
91
95
|
"ApprovedBase",
|
|
92
96
|
"ArtifactReference",
|
|
93
97
|
"Attestor",
|
|
98
|
+
"BuildContextEntry",
|
|
99
|
+
"BuildContextFinding",
|
|
94
100
|
"BuildRequest",
|
|
95
101
|
"BuildkitResolveRunner",
|
|
96
102
|
"CapabilityReport",
|
|
@@ -114,6 +120,7 @@ __all__ = [
|
|
|
114
120
|
"can_transition",
|
|
115
121
|
"canonical_digest",
|
|
116
122
|
"canonical_json",
|
|
123
|
+
"check_build_context",
|
|
117
124
|
"check_dockerfile",
|
|
118
125
|
"decide",
|
|
119
126
|
"fingerprint_matches",
|
|
@@ -131,6 +138,7 @@ __all__ = [
|
|
|
131
138
|
"spec_digest",
|
|
132
139
|
"spec_findings",
|
|
133
140
|
"transition",
|
|
141
|
+
"validate_build_context",
|
|
134
142
|
"validate_dockerfile",
|
|
135
143
|
"validate_environment",
|
|
136
144
|
]
|
{code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/datalayer.py
RENAMED
|
@@ -50,6 +50,7 @@ from typing import Any, Callable
|
|
|
50
50
|
|
|
51
51
|
from ..build_secrets import resolve_build_secret
|
|
52
52
|
from ..builders import (
|
|
53
|
+
ECR_ENVIRONMENT_PREFIX,
|
|
53
54
|
ArtifactMetadata,
|
|
54
55
|
ArtifactReference,
|
|
55
56
|
BuildRequest,
|
|
@@ -57,6 +58,8 @@ from ..builders import (
|
|
|
57
58
|
CapabilityReport,
|
|
58
59
|
CapabilitySet,
|
|
59
60
|
ValidationResult,
|
|
61
|
+
owner_cache_repository,
|
|
62
|
+
owner_repository,
|
|
60
63
|
)
|
|
61
64
|
from ..contract import SANDBOX_CONTRACT_V1
|
|
62
65
|
from ..errors import (
|
|
@@ -75,6 +78,12 @@ from ..resolve import (
|
|
|
75
78
|
apt_snapshot_in,
|
|
76
79
|
locked_versions,
|
|
77
80
|
)
|
|
81
|
+
from ..resolve_conda import (
|
|
82
|
+
MICROMAMBA_BINARY,
|
|
83
|
+
conda_lock_pip_requirements,
|
|
84
|
+
is_conda_lock,
|
|
85
|
+
micromamba_bootstrap_dockerfile_line,
|
|
86
|
+
)
|
|
78
87
|
from ..spec import BuildSecret, Environment, command_names_secret
|
|
79
88
|
|
|
80
89
|
__all__ = [
|
|
@@ -84,9 +93,6 @@ __all__ = [
|
|
|
84
93
|
"owner_repository",
|
|
85
94
|
]
|
|
86
95
|
|
|
87
|
-
#: Where an owner's environments live in ECR (D-10).
|
|
88
|
-
ECR_ENVIRONMENT_PREFIX = "environments/u/"
|
|
89
|
-
|
|
90
96
|
#: The size classes a Datalayer sandbox runs (D-4). The GPU ones stay in the
|
|
91
97
|
#: specification and run on Modal or Daytona until E4-11 (D-20).
|
|
92
98
|
CPU_SIZE_CLASSES = ("small", "medium", "large")
|
|
@@ -98,34 +104,12 @@ DEFAULT_MAX_BUILD_SECONDS = 45 * 60
|
|
|
98
104
|
#: and waited for at every cold start.
|
|
99
105
|
DEFAULT_MAX_ARTIFACT_BYTES = 20 * 1024**3
|
|
100
106
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
project's own uids are ULIDs, conventionally uppercase — found live,
|
|
108
|
-
2026-09-14, the first real build ever run for a real account's own
|
|
109
|
-
uid rather than a lowercase test fixture: ``DescribeRepositories``
|
|
110
|
-
refused it outright, "Invalid parameter at 'repositoryName'". Lowering
|
|
111
|
-
both segments here, the one place this reference is built, keeps every
|
|
112
|
-
caller (create, inspect, exists, delete) consistent with itself without
|
|
113
|
-
each needing to remember to.
|
|
114
|
-
"""
|
|
115
|
-
if not owner_uid or not environment_name:
|
|
116
|
-
raise ValueError("an owner and an environment name make the repository")
|
|
117
|
-
return f"{ECR_ENVIRONMENT_PREFIX}{owner_uid}/{environment_name}".lower()
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def owner_cache_repository(owner_uid: str) -> str:
|
|
121
|
-
"""The owner's own BuildKit cache repository: ``environments/cache/u/<owner>``.
|
|
122
|
-
|
|
123
|
-
Lowercased for the same reason ``owner_repository`` is (a ULID, not a
|
|
124
|
-
lowercase test fixture, is what a real build actually names).
|
|
125
|
-
"""
|
|
126
|
-
if not owner_uid:
|
|
127
|
-
raise ValueError("an owner makes the cache repository")
|
|
128
|
-
return f"environments/cache/u/{owner_uid}".lower()
|
|
107
|
+
# `ECR_ENVIRONMENT_PREFIX`, `owner_repository` and `owner_cache_repository`
|
|
108
|
+
# moved to `..builders` (E1-14): Runtimes validates a smoke-test launch's
|
|
109
|
+
# artifact against this same repository shape, and `builders` is the neutral
|
|
110
|
+
# module a service may import — this adapter is not. Re-exported here, still
|
|
111
|
+
# `from .datalayer import owner_repository`, for every caller that already
|
|
112
|
+
# does; nothing about their behavior changed.
|
|
129
113
|
|
|
130
114
|
|
|
131
115
|
def _secret_mount(secret: BuildSecret) -> str:
|
|
@@ -251,8 +235,8 @@ class Builder:
|
|
|
251
235
|
findings.append(
|
|
252
236
|
CapabilityFinding(
|
|
253
237
|
code=CAPABILITY_UNSUPPORTED.code,
|
|
254
|
-
message="conda
|
|
255
|
-
"
|
|
238
|
+
message="a conda environment is brought as a `dependencyFile` "
|
|
239
|
+
"whose `sourceFormat` is `conda`, not through `packages`",
|
|
256
240
|
field="spec.packages.python.manager",
|
|
257
241
|
)
|
|
258
242
|
)
|
|
@@ -275,7 +259,8 @@ class Builder:
|
|
|
275
259
|
field="spec.platform.architecture",
|
|
276
260
|
)
|
|
277
261
|
)
|
|
278
|
-
|
|
262
|
+
pins_or_lock = lock_text is not None and not is_conda_lock(lock_text)
|
|
263
|
+
if pins_or_lock and not locked_versions(lock_text):
|
|
279
264
|
findings.append(
|
|
280
265
|
CapabilityFinding(
|
|
281
266
|
code=SPEC_INVALID.code,
|
|
@@ -345,18 +330,45 @@ class Builder:
|
|
|
345
330
|
f"COPY wheelhouse/ {imported_wheelhouse}/",
|
|
346
331
|
'RUN pip install --no-cache-dir "uv==0.12.11"',
|
|
347
332
|
]
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
333
|
+
if is_conda_lock(request.lock_text):
|
|
334
|
+
# A conda source (E3-02): the lock is an `@EXPLICIT` file
|
|
335
|
+
# `micromamba install --file` installs without re-solving, and the
|
|
336
|
+
# pip layer the solve resolved — the user's own pip requirements and
|
|
337
|
+
# the protected pins forced over them — is in the lock's own
|
|
338
|
+
# `# datalayer-pip:` header. The conda layer goes into the base's
|
|
339
|
+
# own environment; the pip layer follows, so the kernel stack
|
|
340
|
+
# (E1-04) and everything the solve installed is present the same as
|
|
341
|
+
# every source. micromamba is copied in from its pinned image
|
|
342
|
+
# first: the approved base bakes uv and the wheelhouse but not it.
|
|
343
|
+
pip_requirements = conda_lock_pip_requirements(request.lock_text)
|
|
344
|
+
lines.extend(
|
|
345
|
+
[
|
|
346
|
+
micromamba_bootstrap_dockerfile_line(),
|
|
347
|
+
"COPY lock.txt /opt/datalayer/lock.txt",
|
|
348
|
+
"RUN --mount=type=cache,target=/opt/conda/pkgs "
|
|
349
|
+
f"{MICROMAMBA_BINARY} install --yes --name base "
|
|
350
|
+
"--file /opt/datalayer/lock.txt",
|
|
351
|
+
]
|
|
352
|
+
)
|
|
353
|
+
if pip_requirements:
|
|
354
|
+
requirements = " ".join(shlex.quote(req) for req in pip_requirements)
|
|
355
|
+
lines.append(
|
|
356
|
+
"RUN --mount=type=cache,target=/root/.cache/uv "
|
|
357
|
+
f"uv pip install --system --find-links {find_links} {requirements}"
|
|
358
|
+
)
|
|
359
|
+
else:
|
|
360
|
+
lines.extend(
|
|
361
|
+
[
|
|
362
|
+
"COPY lock.txt /opt/datalayer/lock.txt",
|
|
363
|
+
# `sync` and not `install`: the artifact holds the lock's set,
|
|
364
|
+
# and `--require-hashes` means every byte was the resolved one.
|
|
365
|
+
# `--find-links` for what no index has — a protected pin's
|
|
366
|
+
# own wheel, the fork's local version above all (E1-04).
|
|
367
|
+
"RUN --mount=type=cache,target=/root/.cache/uv "
|
|
368
|
+
f"uv pip sync --system --require-hashes --find-links {find_links} "
|
|
369
|
+
"/opt/datalayer/lock.txt",
|
|
370
|
+
]
|
|
371
|
+
)
|
|
360
372
|
# A build secret is mounted on the postInstall commands that name it
|
|
361
373
|
# and nowhere else (§4.1, D-11): never an `ARG` or `ENV`, which bakes a
|
|
362
374
|
# value into the image's history, never the package-install or files
|
{code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/daytona.py
RENAMED
|
@@ -87,6 +87,7 @@ item 7).
|
|
|
87
87
|
|
|
88
88
|
from __future__ import annotations
|
|
89
89
|
|
|
90
|
+
import shlex
|
|
90
91
|
import tempfile
|
|
91
92
|
import uuid
|
|
92
93
|
from collections.abc import Callable
|
|
@@ -110,6 +111,11 @@ from ..errors import (
|
|
|
110
111
|
)
|
|
111
112
|
from ..files import files_step
|
|
112
113
|
from ..resolve import WHEELHOUSE_IMAGE_PATH, apt_pins_in
|
|
114
|
+
from ..resolve_conda import (
|
|
115
|
+
conda_lock_pip_requirements,
|
|
116
|
+
is_conda_lock,
|
|
117
|
+
micromamba_bootstrap_command,
|
|
118
|
+
)
|
|
113
119
|
from ..spec import GPU_SIZE_CLASSES, Environment
|
|
114
120
|
from .managed import ManagedBuilder
|
|
115
121
|
|
|
@@ -171,6 +177,10 @@ class Builder(ManagedBuilder):
|
|
|
171
177
|
variant = "daytona"
|
|
172
178
|
item = "E2-04"
|
|
173
179
|
title = "Daytona"
|
|
180
|
+
#: A `packages` list and, for conda (E3-02), an `environment.yml`
|
|
181
|
+
#: dependency file installed with `micromamba`.
|
|
182
|
+
build_sources = ("packages", "dependencyFile")
|
|
183
|
+
dependency_formats = ("conda",)
|
|
174
184
|
#: Daytona runs GPUs, on its own hardware and the owner's account (E2-17).
|
|
175
185
|
#: This builder does not build one yet: see `_own_findings`.
|
|
176
186
|
gpu = True
|
|
@@ -343,28 +353,43 @@ class Builder(ManagedBuilder):
|
|
|
343
353
|
# wheelhouse again would only duplicate what `uv pip sync`
|
|
344
354
|
# can already reach at `WHEELHOUSE_IMAGE_PATH`. Only the
|
|
345
355
|
# lock is genuinely per-build.
|
|
346
|
-
image = (
|
|
347
|
-
|
|
356
|
+
image = image.add_local_file(str(lock_file), _LOCK_PATH)
|
|
357
|
+
if is_conda_lock(request.lock_text):
|
|
358
|
+
# A conda source (E3-02): `micromamba install --file`
|
|
359
|
+
# reads the `@EXPLICIT` lock without re-solving, and the
|
|
360
|
+
# pip layer the solve resolved — the user's pip
|
|
361
|
+
# requirements and the protected pins over them — comes
|
|
362
|
+
# from the lock's own `# datalayer-pip:` header, so the
|
|
363
|
+
# kernel stack (E1-04) and everything the solve installed is
|
|
364
|
+
# present the same as for a pip source. micromamba is
|
|
365
|
+
# installed first: the approved base bakes uv but not it.
|
|
366
|
+
image = image.run_commands(micromamba_bootstrap_command())
|
|
367
|
+
image = image.run_commands(
|
|
368
|
+
f"micromamba install --yes --name base --file {_LOCK_PATH}"
|
|
369
|
+
)
|
|
370
|
+
pip_requirements = conda_lock_pip_requirements(request.lock_text)
|
|
371
|
+
if pip_requirements:
|
|
372
|
+
requirements = " ".join(shlex.quote(req) for req in pip_requirements)
|
|
373
|
+
image = image.run_commands(
|
|
374
|
+
"pip install --no-cache-dir "
|
|
375
|
+
f"--find-links {WHEELHOUSE_IMAGE_PATH} {requirements}"
|
|
376
|
+
)
|
|
377
|
+
else:
|
|
348
378
|
# `uv` is not installed here: the approved base already
|
|
349
379
|
# bakes it (E1-05, `resolve.py`'s own `bootstrap_uv`
|
|
350
380
|
# docstring — "an approved Datalayer base already has it
|
|
351
|
-
# baked in")
|
|
352
|
-
#
|
|
353
|
-
#
|
|
354
|
-
# fetch outside the resolved lock for no reason (found in
|
|
355
|
-
# review) — matching the Datalayer builder's own
|
|
356
|
-
# `dockerfile()`, which installs `uv` only for the
|
|
357
|
-
# `image` source, not implemented for this variant yet.
|
|
381
|
+
# baked in"). Reinstalling it added an extra un-hashed
|
|
382
|
+
# network fetch outside the resolved lock for no reason
|
|
383
|
+
# (found in review).
|
|
358
384
|
#
|
|
359
385
|
# Packages install as root, the same reason the
|
|
360
386
|
# Datalayer and E2B builders give: a user install lands
|
|
361
387
|
# under the content directory's own home, which the
|
|
362
388
|
# runtime mounts over.
|
|
363
|
-
.run_commands(
|
|
389
|
+
image = image.run_commands(
|
|
364
390
|
"uv pip sync --system --require-hashes "
|
|
365
391
|
f"--find-links {WHEELHOUSE_IMAGE_PATH} {_LOCK_PATH}"
|
|
366
392
|
)
|
|
367
|
-
)
|
|
368
393
|
image = image.dockerfile_commands([f"USER 1000:100\nWORKDIR {_CONTENT_DIR}"])
|
|
369
394
|
for command in files_step(request.environment, variant=self.variant):
|
|
370
395
|
image = image.run_commands(command)
|
|
@@ -119,6 +119,7 @@ never went through a `smoke_test` method either.
|
|
|
119
119
|
|
|
120
120
|
from __future__ import annotations
|
|
121
121
|
|
|
122
|
+
import shlex
|
|
122
123
|
import tempfile
|
|
123
124
|
from collections.abc import Callable
|
|
124
125
|
from pathlib import Path
|
|
@@ -140,6 +141,11 @@ from ..errors import (
|
|
|
140
141
|
)
|
|
141
142
|
from ..files import files_step
|
|
142
143
|
from ..resolve import WHEELHOUSE_PATH, apt_pins_in
|
|
144
|
+
from ..resolve_conda import (
|
|
145
|
+
conda_lock_pip_requirements,
|
|
146
|
+
is_conda_lock,
|
|
147
|
+
micromamba_bootstrap_command,
|
|
148
|
+
)
|
|
143
149
|
from ..spec import Environment
|
|
144
150
|
from .managed import ManagedBuilder
|
|
145
151
|
|
|
@@ -191,6 +197,10 @@ class Builder(ManagedBuilder):
|
|
|
191
197
|
variant = "e2b"
|
|
192
198
|
item = "E2-03"
|
|
193
199
|
title = "E2B"
|
|
200
|
+
#: A `packages` list and, for conda (E3-02), an `environment.yml`
|
|
201
|
+
#: dependency file installed with `micromamba`.
|
|
202
|
+
build_sources = ("packages", "dependencyFile")
|
|
203
|
+
dependency_formats = ("conda",)
|
|
194
204
|
#: Firecracker microVMs: no GPU passthrough.
|
|
195
205
|
gpu = False
|
|
196
206
|
#: E0-04's spike found only a registry login for the private base, never
|
|
@@ -390,15 +400,38 @@ class Builder(ManagedBuilder):
|
|
|
390
400
|
chain.copy("datalayer-sandbox", _DOCTOR_PATH, mode=0o755, user="root")
|
|
391
401
|
.copy("wheelhouse", _WHEELHOUSE_PATH, user="root")
|
|
392
402
|
.copy("lock.txt", _LOCK_PATH, user="root")
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
#
|
|
396
|
-
|
|
403
|
+
)
|
|
404
|
+
if is_conda_lock(request.lock_text):
|
|
405
|
+
# A conda source (E3-02): `micromamba install --file` reads the
|
|
406
|
+
# `@EXPLICIT` lock without re-solving, and the pip layer the
|
|
407
|
+
# solve resolved — the user's pip requirements and the protected
|
|
408
|
+
# pins over them — comes from the lock's own `# datalayer-pip:`
|
|
409
|
+
# header, so the kernel stack (E1-04) and everything the solve
|
|
410
|
+
# installed is present the same as for a pip source. micromamba
|
|
411
|
+
# is installed first: the approved base bakes uv but not it.
|
|
412
|
+
chain = chain.run_cmd(micromamba_bootstrap_command(), user="root")
|
|
413
|
+
chain = chain.run_cmd(
|
|
414
|
+
f"micromamba install --yes --name base --file {_LOCK_PATH}",
|
|
415
|
+
user="root",
|
|
416
|
+
)
|
|
417
|
+
pip_requirements = conda_lock_pip_requirements(request.lock_text)
|
|
418
|
+
if pip_requirements:
|
|
419
|
+
requirements = " ".join(shlex.quote(req) for req in pip_requirements)
|
|
420
|
+
chain = chain.run_cmd(
|
|
421
|
+
f"pip install --no-cache-dir --find-links {_WHEELHOUSE_PATH} "
|
|
422
|
+
f"{requirements}",
|
|
423
|
+
user="root",
|
|
424
|
+
)
|
|
425
|
+
else:
|
|
426
|
+
chain = chain.run_cmd(
|
|
427
|
+
f'pip install --no-cache-dir "uv=={_UV_VERSION}"', user="root"
|
|
428
|
+
).run_cmd(
|
|
429
|
+
# Packages install as root (E0-04): a user install lands
|
|
430
|
+
# under /home/user, which the runtime mounts over.
|
|
397
431
|
"uv pip sync --system --require-hashes "
|
|
398
432
|
f"--find-links {_WHEELHOUSE_PATH} {_LOCK_PATH}",
|
|
399
433
|
user="root",
|
|
400
434
|
)
|
|
401
|
-
)
|
|
402
435
|
for command in files_step(request.environment, variant=self.variant):
|
|
403
436
|
chain = chain.run_cmd(command)
|
|
404
437
|
for command in spec.commands.post_install:
|
{code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/managed.py
RENAMED
|
@@ -36,7 +36,7 @@ from ..builders import (
|
|
|
36
36
|
ValidationResult,
|
|
37
37
|
)
|
|
38
38
|
from ..errors import CAPABILITY_UNSUPPORTED, SPEC_INVALID, EnvironmentsError
|
|
39
|
-
from ..spec import GPU_SIZE_CLASSES, Environment
|
|
39
|
+
from ..spec import GPU_SIZE_CLASSES, Environment, EnvironmentSpec
|
|
40
40
|
|
|
41
41
|
__all__ = ["ManagedBuilder"]
|
|
42
42
|
|
|
@@ -67,6 +67,11 @@ class ManagedBuilder:
|
|
|
67
67
|
supports_build_secrets = True
|
|
68
68
|
#: The build sources it will accept in this phase.
|
|
69
69
|
build_sources: tuple[str, ...] = ("packages",)
|
|
70
|
+
#: When `dependencyFile` is among `build_sources`, the `sourceFormat`s the
|
|
71
|
+
#: variant's own build actually installs. A conda source (E3-02) installs
|
|
72
|
+
#: with `micromamba`; a `pyproject`/`requirements` dependencyFile is not
|
|
73
|
+
#: built for a managed variant yet (E3-01), so it is not listed here.
|
|
74
|
+
dependency_formats: tuple[str, ...] = ()
|
|
70
75
|
package_managers: tuple[str, ...] = ("uv", "pip")
|
|
71
76
|
#: Dockerfile instructions its own builder does not implement (§6).
|
|
72
77
|
forbidden_instructions: tuple[str, ...] = ()
|
|
@@ -121,6 +126,8 @@ class ManagedBuilder:
|
|
|
121
126
|
field="spec.build.source",
|
|
122
127
|
)
|
|
123
128
|
)
|
|
129
|
+
elif spec.build.source == "dependencyFile":
|
|
130
|
+
findings.extend(self._dependency_file_findings(spec))
|
|
124
131
|
if spec.packages.python.manager not in self.package_managers:
|
|
125
132
|
findings.append(
|
|
126
133
|
CapabilityFinding(
|
|
@@ -141,34 +148,7 @@ class ManagedBuilder:
|
|
|
141
148
|
)
|
|
142
149
|
)
|
|
143
150
|
if not self.gpu:
|
|
144
|
-
|
|
145
|
-
# couples them; a `validate` can be reached before that, so both
|
|
146
|
-
# are read here rather than trusting the coupling.
|
|
147
|
-
if spec.resources.size_class in GPU_SIZE_CLASSES:
|
|
148
|
-
findings.append(
|
|
149
|
-
CapabilityFinding(
|
|
150
|
-
code=CAPABILITY_UNSUPPORTED.code,
|
|
151
|
-
message=(
|
|
152
|
-
f"{self.title} has no GPU, so `{spec.resources.size_class}` cannot be "
|
|
153
|
-
f"built for it. Drop {self.variant} from the variants, or build "
|
|
154
|
-
"the GPU classes for modal or daytona, which run them on their "
|
|
155
|
-
"own hardware"
|
|
156
|
-
),
|
|
157
|
-
field="spec.resources.sizeClass",
|
|
158
|
-
)
|
|
159
|
-
)
|
|
160
|
-
elif spec.resources.accelerator != "none":
|
|
161
|
-
findings.append(
|
|
162
|
-
CapabilityFinding(
|
|
163
|
-
code=CAPABILITY_UNSUPPORTED.code,
|
|
164
|
-
message=(
|
|
165
|
-
f"{self.title} has no GPU, so an accelerator cannot be built for it. "
|
|
166
|
-
f"Drop {self.variant} from the variants, or build the GPU classes for "
|
|
167
|
-
"modal or daytona, which run them on their own hardware"
|
|
168
|
-
),
|
|
169
|
-
field="spec.resources.accelerator",
|
|
170
|
-
)
|
|
171
|
-
)
|
|
151
|
+
findings.extend(self._gpu_findings(spec))
|
|
172
152
|
if self.regions:
|
|
173
153
|
asked = [
|
|
174
154
|
region
|
|
@@ -201,6 +181,58 @@ class ManagedBuilder:
|
|
|
201
181
|
)
|
|
202
182
|
return findings
|
|
203
183
|
|
|
184
|
+
def _gpu_findings(self, spec: EnvironmentSpec) -> list[CapabilityFinding]:
|
|
185
|
+
"""A variant with no GPU refuses either way a GPU is asked for. A GPU
|
|
186
|
+
is asked two ways, and the spec's own validation couples them; a
|
|
187
|
+
`validate` can be reached before that, so both are read here rather
|
|
188
|
+
than trusting the coupling."""
|
|
189
|
+
if spec.resources.size_class in GPU_SIZE_CLASSES:
|
|
190
|
+
return [
|
|
191
|
+
CapabilityFinding(
|
|
192
|
+
code=CAPABILITY_UNSUPPORTED.code,
|
|
193
|
+
message=(
|
|
194
|
+
f"{self.title} has no GPU, so `{spec.resources.size_class}` cannot be "
|
|
195
|
+
f"built for it. Drop {self.variant} from the variants, or build "
|
|
196
|
+
"the GPU classes for modal or daytona, which run them on their "
|
|
197
|
+
"own hardware"
|
|
198
|
+
),
|
|
199
|
+
field="spec.resources.sizeClass",
|
|
200
|
+
)
|
|
201
|
+
]
|
|
202
|
+
if spec.resources.accelerator != "none":
|
|
203
|
+
return [
|
|
204
|
+
CapabilityFinding(
|
|
205
|
+
code=CAPABILITY_UNSUPPORTED.code,
|
|
206
|
+
message=(
|
|
207
|
+
f"{self.title} has no GPU, so an accelerator cannot be built for it. "
|
|
208
|
+
f"Drop {self.variant} from the variants, or build the GPU classes for "
|
|
209
|
+
"modal or daytona, which run them on their own hardware"
|
|
210
|
+
),
|
|
211
|
+
field="spec.resources.accelerator",
|
|
212
|
+
)
|
|
213
|
+
]
|
|
214
|
+
return []
|
|
215
|
+
|
|
216
|
+
def _dependency_file_findings(self, spec: EnvironmentSpec) -> list[CapabilityFinding]:
|
|
217
|
+
"""A `dependencyFile` this variant accepts still only builds the
|
|
218
|
+
`sourceFormat`s it has an install step for (E3-01, E3-02): a conda
|
|
219
|
+
file installs with `micromamba`, but a `pyproject` or `requirements`
|
|
220
|
+
one is not built for a managed variant yet."""
|
|
221
|
+
source_format = spec.build.dependency_file.source_format
|
|
222
|
+
if source_format in self.dependency_formats:
|
|
223
|
+
return []
|
|
224
|
+
return [
|
|
225
|
+
CapabilityFinding(
|
|
226
|
+
code=CAPABILITY_UNSUPPORTED.code,
|
|
227
|
+
message=(
|
|
228
|
+
f"a `{source_format}` dependency file is not built for "
|
|
229
|
+
f"{self.title} yet; it builds "
|
|
230
|
+
f"{', '.join(self.dependency_formats) or 'no dependency file'}"
|
|
231
|
+
),
|
|
232
|
+
field="spec.build.dependencyFile.sourceFormat",
|
|
233
|
+
)
|
|
234
|
+
]
|
|
235
|
+
|
|
204
236
|
def _own_findings(
|
|
205
237
|
self, environment: Environment, lock_text: str | None
|
|
206
238
|
) -> list[CapabilityFinding]:
|
{code_sandboxes-1.9.11 → code_sandboxes-1.9.13}/code_sandboxes/environments/adapters/modal.py
RENAMED
|
@@ -147,6 +147,7 @@ from ..errors import (
|
|
|
147
147
|
from ..files import files_step
|
|
148
148
|
from ..redact import redact
|
|
149
149
|
from ..resolve import WHEELHOUSE_IMAGE_PATH, apt_pins_in
|
|
150
|
+
from ..resolve_conda import conda_lock_pip_requirements, is_conda_lock
|
|
150
151
|
from ..spec import GPU_SIZE_CLASSES, BuildSecret, Environment, command_names_secret
|
|
151
152
|
from .managed import ManagedBuilder
|
|
152
153
|
|
|
@@ -211,6 +212,29 @@ def _scrubbed(text: str, values: dict[str, str]) -> str:
|
|
|
211
212
|
return redact(text, values.values()) if values else text
|
|
212
213
|
|
|
213
214
|
|
|
215
|
+
def _install_packages(image: Any, lock_text: str) -> Any:
|
|
216
|
+
"""The package layer for this lock: a conda source (E3-02) installs the
|
|
217
|
+
`@EXPLICIT` lock with Modal's own `micromamba_install` — which brings
|
|
218
|
+
micromamba itself, so no bootstrap is needed here — and layers the pip
|
|
219
|
+
layer the solve resolved (the user's pip requirements and the protected
|
|
220
|
+
pins over them, from the lock's own `# datalayer-pip:` header); a pip
|
|
221
|
+
source runs `uv pip sync`."""
|
|
222
|
+
if is_conda_lock(lock_text):
|
|
223
|
+
image = image.micromamba_install(spec_file=_LOCK_PATH)
|
|
224
|
+
pip_requirements = conda_lock_pip_requirements(lock_text)
|
|
225
|
+
if pip_requirements:
|
|
226
|
+
image = image.pip_install(*pip_requirements, find_links=WHEELHOUSE_IMAGE_PATH)
|
|
227
|
+
return image
|
|
228
|
+
return image.run_commands(
|
|
229
|
+
f'pip install --no-cache-dir "uv=={_UV_VERSION}"',
|
|
230
|
+
# Packages install as root: every Modal build step already runs as
|
|
231
|
+
# root regardless of any `USER` line (see the module docstring), so
|
|
232
|
+
# this is stating what is already true rather than asking for it.
|
|
233
|
+
"uv pip sync --system --require-hashes "
|
|
234
|
+
f"--find-links {WHEELHOUSE_IMAGE_PATH} {_LOCK_PATH}",
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
|
|
214
238
|
def _post_install(
|
|
215
239
|
image: Any, commands: list[str], declared: list[BuildSecret], step_secrets: dict[str, Any]
|
|
216
240
|
) -> Any:
|
|
@@ -227,6 +251,10 @@ class Builder(ManagedBuilder):
|
|
|
227
251
|
variant = "modal"
|
|
228
252
|
item = "E2-05"
|
|
229
253
|
title = "Modal"
|
|
254
|
+
#: A `packages` list and, for conda (E3-02), an `environment.yml`
|
|
255
|
+
#: dependency file installed with `micromamba_install`.
|
|
256
|
+
build_sources = ("packages", "dependencyFile")
|
|
257
|
+
dependency_formats = ("conda",)
|
|
230
258
|
#: Modal runs GPUs, in the owner's workspace (E2-17). This builder does
|
|
231
259
|
#: not build one yet: see `build`'s own guard.
|
|
232
260
|
gpu = True
|
|
@@ -403,15 +431,7 @@ class Builder(ManagedBuilder):
|
|
|
403
431
|
image = image.add_local_file(
|
|
404
432
|
str(entrypoint_file), _ENTRYPOINT_PATH, copy=True
|
|
405
433
|
).run_commands(f"chmod +x {_ENTRYPOINT_PATH}")
|
|
406
|
-
image = image.
|
|
407
|
-
f'pip install --no-cache-dir "uv=={_UV_VERSION}"',
|
|
408
|
-
# Packages install as root: every Modal build step
|
|
409
|
-
# already runs as root regardless of any `USER` line
|
|
410
|
-
# (see the module docstring), so this is stating what
|
|
411
|
-
# is already true rather than asking for it.
|
|
412
|
-
"uv pip sync --system --require-hashes "
|
|
413
|
-
f"--find-links {WHEELHOUSE_IMAGE_PATH} {_LOCK_PATH}",
|
|
414
|
-
)
|
|
434
|
+
image = _install_packages(image, request.lock_text)
|
|
415
435
|
for command in files_step(request.environment, variant=self.variant):
|
|
416
436
|
image = image.run_commands(command)
|
|
417
437
|
image = _post_install(image, spec.commands.post_install, declared, step_secrets)
|