code-sandboxes 1.9.11__tar.gz → 1.9.14__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.
Files changed (264) hide show
  1. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/CHANGELOG.md +36 -12
  2. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/PKG-INFO +3 -1
  3. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/__version__.py +1 -1
  4. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/__init__.py +8 -0
  5. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/adapters/datalayer.py +58 -46
  6. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/adapters/daytona.py +36 -11
  7. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/adapters/e2b.py +38 -5
  8. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/adapters/managed.py +61 -29
  9. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/adapters/modal.py +29 -9
  10. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/bases.py +5 -4
  11. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/builders.py +40 -0
  12. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/conformance.py +19 -4
  13. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/constraints/sandbox-contract-v1.txt +10 -0
  14. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/constraints/wheelhouse/README.md +7 -0
  15. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/contract.py +97 -1
  16. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/resolve.py +25 -1
  17. code_sandboxes-1.9.14/code_sandboxes/environments/resolve_conda.py +913 -0
  18. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/spec.py +180 -31
  19. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/environments/specification.mdx +2 -2
  20. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/pyproject.toml +2 -1
  21. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/schemas/environment-v1alpha1.json +3 -2
  22. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_conformance.py +30 -0
  23. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_constraints.py +1 -0
  24. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_contract.py +51 -0
  25. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_datalayer_builder.py +43 -0
  26. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_daytona_builder.py +33 -0
  27. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_e2b_builder.py +45 -0
  28. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_managed_builders.py +46 -6
  29. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_modal_builder.py +43 -0
  30. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_resolve.py +52 -1
  31. code_sandboxes-1.9.14/tests/test_environment_resolve_conda.py +476 -0
  32. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_spec.py +67 -4
  33. code_sandboxes-1.9.11/build.log +0 -5
  34. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.github/workflows/build.yml +0 -0
  35. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.github/workflows/environments-live.yml +0 -0
  36. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.github/workflows/py-code-style.yml +0 -0
  37. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.github/workflows/py-tests.yml +0 -0
  38. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.github/workflows/py-typing.yml +0 -0
  39. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.github/workflows/reusable-python.yml +0 -0
  40. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.gitignore +0 -0
  41. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.licenserc.yaml +0 -0
  42. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.pre-commit-config.yaml +0 -0
  43. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/.vscode/settings.json +0 -0
  44. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/Dockerfile +0 -0
  45. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/LICENSE +0 -0
  46. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/Makefile +0 -0
  47. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/README.md +0 -0
  48. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/__init__.py +0 -0
  49. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/base.py +0 -0
  50. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/bridge_mount.py +0 -0
  51. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/builds.py +0 -0
  52. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/cli.py +0 -0
  53. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/client.py +0 -0
  54. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/cloudflare_sandbox.py +0 -0
  55. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/commands.py +0 -0
  56. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/console.py +0 -0
  57. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/contents.py +0 -0
  58. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/coreweave_sandbox.py +0 -0
  59. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/datalayer_sandbox.py +0 -0
  60. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/daytona_sandbox.py +0 -0
  61. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/docker_sandbox.py +0 -0
  62. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/e2b_sandbox.py +0 -0
  63. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/__main__.py +0 -0
  64. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/accounts.py +0 -0
  65. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/adapters/__init__.py +0 -0
  66. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/attest.py +0 -0
  67. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/breaker.py +0 -0
  68. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/build_secrets.py +0 -0
  69. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/canonical.py +0 -0
  70. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/constraints/wheelhouse/jupyter_server-2.21.0+datalayer.1-py3-none-any.whl +0 -0
  71. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/doctor/__init__.py +0 -0
  72. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/doctor/build.py +0 -0
  73. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/doctor/datalayer_sandbox.py +0 -0
  74. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/doctor/report.schema.json +0 -0
  75. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/errors.py +0 -0
  76. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/files.py +0 -0
  77. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/image_import.py +0 -0
  78. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/lifecycle.py +0 -0
  79. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/policy.py +0 -0
  80. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/redact.py +0 -0
  81. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/environments/schema.py +0 -0
  82. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/eval_sandbox.py +0 -0
  83. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/exceptions.py +0 -0
  84. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/filesystem.py +0 -0
  85. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/google_colab.py +0 -0
  86. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/google_colab_sandbox.py +0 -0
  87. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/interfaces.py +0 -0
  88. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/jupyter_ingress.py +0 -0
  89. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/jupyter_server_sandbox.py +0 -0
  90. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/kaggle.py +0 -0
  91. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/kaggle_execute.py +0 -0
  92. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/kaggle_live.py +0 -0
  93. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/kaggle_sandbox.py +0 -0
  94. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/lifecycle.py +0 -0
  95. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/manage.py +0 -0
  96. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/modal_sandbox.py +0 -0
  97. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/models.py +0 -0
  98. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/monty_sandbox.py +0 -0
  99. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/provider_ingress.py +0 -0
  100. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/code_sandboxes/providers.py +0 -0
  101. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docker/Dockerfile +0 -0
  102. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/.gitignore +0 -0
  103. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/LICENSE +0 -0
  104. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/Makefile +0 -0
  105. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/README.md +0 -0
  106. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/babel.config.js +0 -0
  107. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/api-reference/_category_.yml +0 -0
  108. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/api-reference/index.mdx +0 -0
  109. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/cli/_category_.yml +0 -0
  110. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/cli/index.mdx +0 -0
  111. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/contribute/_category_.yml +0 -0
  112. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/contribute/index.mdx +0 -0
  113. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/environments/_category_.yml +0 -0
  114. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/environments/contract.mdx +0 -0
  115. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/environments/index.mdx +0 -0
  116. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/environments/spike-2026-09.mdx +0 -0
  117. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/examples/_category_.yml +0 -0
  118. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/examples/index.mdx +0 -0
  119. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/guide/_category_.yml +0 -0
  120. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/guide/index.mdx +0 -0
  121. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/index.mdx +0 -0
  122. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/install/_category_.yml +0 -0
  123. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/install/index.mdx +0 -0
  124. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/provider-ingress.mdx +0 -0
  125. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/_category_.yml +0 -0
  126. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/cloudflare.mdx +0 -0
  127. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/coreweave.mdx +0 -0
  128. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/datalayer.mdx +0 -0
  129. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/daytona.mdx +0 -0
  130. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/docker.mdx +0 -0
  131. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/e2b.mdx +0 -0
  132. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/eval.mdx +0 -0
  133. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/google-colab.mdx +0 -0
  134. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/index.mdx +0 -0
  135. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/jupyter-server.mdx +0 -0
  136. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/kaggle.mdx +0 -0
  137. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/modal.mdx +0 -0
  138. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docs/providers/monty.mdx +0 -0
  139. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/docusaurus.config.js +0 -0
  140. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/package.json +0 -0
  141. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/sidebars.js +0 -0
  142. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/components/HomepageRow1.js +0 -0
  143. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/components/HomepageRow1.module.css +0 -0
  144. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/components/HomepageRow2.js +0 -0
  145. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/components/HomepageRow2.module.css +0 -0
  146. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/components/HomepageRow3.js +0 -0
  147. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/components/HomepageRow3.module.css +0 -0
  148. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/css/custom.css +0 -0
  149. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/pages/index.module.css +0 -0
  150. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/pages/markdown-page.md +0 -0
  151. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/theme/CustomDocItem.tsx +0 -0
  152. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/src/theme/IconsTitle.tsx +0 -0
  153. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/bricks.svg +0 -0
  154. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/building-construction.svg +0 -0
  155. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/cloud-sun.svg +0 -0
  156. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/cloud.svg +0 -0
  157. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/collaboration.svg +0 -0
  158. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/copy-left.svg +0 -0
  159. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/datalayer/logo.png +0 -0
  160. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/datalayer/logo.svg +0 -0
  161. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/datalayer/personas/business.svg +0 -0
  162. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/datalayer/personas/data-scientist.svg +0 -0
  163. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/datalayer/personas/devops.svg +0 -0
  164. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/datalayer/project/project-line.svg +0 -0
  165. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/favicon.ico +0 -0
  166. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/jupyter.svg +0 -0
  167. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/open-source.svg +0 -0
  168. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/react-js.svg +0 -0
  169. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/react-js2.svg +0 -0
  170. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/ringed-planet.svg +0 -0
  171. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/robot.svg +0 -0
  172. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/rocket.svg +0 -0
  173. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/shield.svg +0 -0
  174. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/sparkles.svg +0 -0
  175. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/streamlit.gif +0 -0
  176. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/super-hero.svg +0 -0
  177. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/target.svg +0 -0
  178. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/docs/static/img/thumbs-up.svg +0 -0
  179. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/README.md +0 -0
  180. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/Makefile +0 -0
  181. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/cloudflare_sandbox_example.py +0 -0
  182. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/coreweave_sandbox_example.py +0 -0
  183. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/datalayer_sandbox_example.py +0 -0
  184. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/daytona_sandbox_example.py +0 -0
  185. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/docker_sandbox_example.py +0 -0
  186. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/e2b_sandbox_example.py +0 -0
  187. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/eval_sandbox_example.py +0 -0
  188. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/google_colab_sandbox_example.py +0 -0
  189. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/jupyter_server_sandbox_example.py +0 -0
  190. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/kaggle_sandbox_example.py +0 -0
  191. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/modal_sandbox_example.py +0 -0
  192. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/exec/monty_sandbox_example.py +0 -0
  193. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/Makefile +0 -0
  194. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/cloudflare_sandbox_example.py +0 -0
  195. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/coreweave_sandbox_example.py +0 -0
  196. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/datalayer_sandbox_example.py +0 -0
  197. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/daytona_sandbox_example.py +0 -0
  198. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/docker_sandbox_example.py +0 -0
  199. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/e2b_sandbox_example.py +0 -0
  200. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/eval_sandbox_example.py +0 -0
  201. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/google_colab_sandbox_example.py +0 -0
  202. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/jupyter_server_sandbox_example.py +0 -0
  203. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/kaggle_sandbox_example.py +0 -0
  204. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/modal_sandbox_example.py +0 -0
  205. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/examples/repl/monty_sandbox_example.py +0 -0
  206. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/__init__.py +0 -0
  207. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/conftest.py +0 -0
  208. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_a_datalayer_sandbox_can_be_interrupted.py +0 -0
  209. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_bridge_mount.py +0 -0
  210. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_builds.py +0 -0
  211. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_cli_exec.py +0 -0
  212. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_cli_repl.py +0 -0
  213. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_client.py +0 -0
  214. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_client_contents.py +0 -0
  215. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_client_files.py +0 -0
  216. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_client_outcome_error_output.py +0 -0
  217. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_cloudflare.py +0 -0
  218. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_commands_envelope.py +0 -0
  219. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_console.py +0 -0
  220. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_contents_contract.py +0 -0
  221. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_contents_live_matrix.py +0 -0
  222. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_coreweave.py +0 -0
  223. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_datalayer_sandbox.py +0 -0
  224. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_daytona.py +0 -0
  225. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_e2b.py +0 -0
  226. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_accounts.py +0 -0
  227. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_attest.py +0 -0
  228. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_bases.py +0 -0
  229. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_breaker.py +0 -0
  230. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_build_secrets.py +0 -0
  231. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_builders.py +0 -0
  232. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_canonical.py +0 -0
  233. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_cross_variant_report.py +0 -0
  234. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_doctor.py +0 -0
  235. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_errors.py +0 -0
  236. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_image_import.py +0 -0
  237. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_lifecycle.py +0 -0
  238. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_live_matrix.py +0 -0
  239. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_environment_redact.py +0 -0
  240. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_eval.py +0 -0
  241. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_every_variant_has_a_real_interrupt.py +0 -0
  242. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_factory.py +0 -0
  243. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_google_colab.py +0 -0
  244. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_integration.py +0 -0
  245. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_jupyter_ingress.py +0 -0
  246. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_jupyter_server.py +0 -0
  247. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_jupyter_server_streaming.py +0 -0
  248. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_kaggle.py +0 -0
  249. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_kaggle_execute.py +0 -0
  250. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_kaggle_live.py +0 -0
  251. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_kaggle_session.py +0 -0
  252. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_kernel_client_compatibility.py +0 -0
  253. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_lifecycle_vocabulary.py +0 -0
  254. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_manage.py +0 -0
  255. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_manage_datalayer.py +0 -0
  256. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_modal_google_colab_sandbox.py +0 -0
  257. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_modal_session.py +0 -0
  258. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_models.py +0 -0
  259. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_output_line_fidelity.py +0 -0
  260. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_provider_catalog_names.py +0 -0
  261. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_provider_ingress.py +0 -0
  262. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_providers.py +0 -0
  263. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_sandboxes.py +0 -0
  264. {code_sandboxes-1.9.11 → code_sandboxes-1.9.14}/tests/test_the_kill_relaunch_drill.py +0 -0
@@ -8,6 +8,36 @@
8
8
 
9
9
  ## Unreleased
10
10
 
11
+ ## 1.9.14
12
+
13
+ - **`datalayer/python-cpu:2026.09` base channel repinned** to the rebuilt
14
+ `jupyter-python:0.2.2` (now carrying `jupyter-kernels==1.2.23`) plus the
15
+ contract layer, digest
16
+ `sha256:aa5413000bb5b6ecd0a0cf03959b107f0d572f65bf230c08bbdf9a4569775545`,
17
+ released 2026-09-16 to `environments/base/python-cpu`. Every variant pins the
18
+ same digest.
19
+
20
+ ## 1.9.13
21
+
22
+ - **`jupyter-kernels==1.2.23` forced into `sandbox-contract/v1`**: it carries
23
+ the pooled kernel manager the runtime's Jupyter config selects
24
+ (`kernel_manager_class = jupyter_kernels.pool.mapping.PooledMappingKernelManager`),
25
+ replacing the deprecated private `datalayer-kernels`. PyPI serves it, so a
26
+ resolve satisfies it from the index and the wheelhouse carries no wheel for
27
+ it; the pin keeps `uv pip sync --require-hashes` from stripping it out of a
28
+ user environment's image.
29
+
30
+ ## 1.9.12
31
+
32
+ - **`owner_repository`, `owner_cache_repository` and `ECR_ENVIRONMENT_PREFIX`
33
+ moved from `environments.adapters.datalayer` to `environments.builders`**
34
+ (PLAN_ENV E1-14): Runtimes now validates a smoke-test launch's artifact
35
+ against this same repository shape, and `builders` is the neutral module a
36
+ service may import — `adapters.datalayer` is not, and importing it from a
37
+ service binds that service to the Datalayer provider the way
38
+ `check_provider_boundary.py` exists to prevent. Re-exported from the
39
+ adapter unchanged, so every existing `from .datalayer import owner_repository` still works. No behavior change; 78 tests still pass.
40
+
11
41
  ## 1.9.11
12
42
 
13
43
  - **1.9.10's own fix did not work: `--registry-referrers-mode` only ever
@@ -17,8 +47,7 @@
17
47
  landed as an OCI 1.1 referrer, no legacy tag. `Attestor` no longer tries
18
48
  to force cosign's own storage choice. Its replay check and its own
19
49
  `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
50
+ verify will: `can_verify(reference)` runs `cosign verify --key <key> --insecure-ignore-tlog=true <reference>` and answers its exit code, and
22
51
  `signature_ref` is the digest reference itself — what `cosign verify`
23
52
  takes, not a tag it may or may not have written. Signing the same digest
24
53
  twice no longer errors the way a second push under the old immutable tag
@@ -31,8 +60,7 @@
31
60
  - **cosign signs the legacy tag again, not just an OCI referrer**
32
61
  (`environments.attest`; PLAN_ENV.md E1-09). cosign 3.1.3 defaults to the
33
62
  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
63
+ `sha256-<hex>.sig` sidecar tag. Found live on r1, 2026-09-14: `cosign sign` reported success — the first artifact this pipeline ever actually
36
64
  signed — but pushed no such tag; `_signature_exists`'s own replay check
37
65
  and the `signature_ref` this workflow records both assume one exists.
38
66
  `--registry-referrers-mode=legacy` restores it. `cosign verify` needs no
@@ -54,8 +82,7 @@
54
82
  ## 1.9.8
55
83
 
56
84
  - **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
85
+ (`environments.attest`; PLAN_ENV.md E1-08, D-11). `describe_image_scan_ findings` paginates, and the attestor called it exactly once. Found live
59
86
  on r1, 2026-09-14: the first real image with more findings than one page
60
87
  had 1,547 enhanced findings, 31 of them critical, and the single-page read
61
88
  saw a small enough slice that the decision passed — an image with real,
@@ -66,8 +93,7 @@
66
93
 
67
94
  ## 1.9.7
68
95
 
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`
96
+ - **cosign signs again under `--use-signing-config=false`** (`environments .attest`; PLAN_ENV.md E1-09). cosign 3.1.3 defaults `--use-signing-config`
71
97
  to `true`: a TUF-provided signing config now names the service URLs,
72
98
  including a transparency log, and `--tlog-upload=false` alone no longer
73
99
  overrides that — cosign refused the combination outright (found live on
@@ -100,8 +126,7 @@
100
126
  from the same snapshot. This replaces a `deb` line that named only `main`
101
127
  (`gdal-bin` is in `universe`) and left the live mirror enabled beside it.
102
128
  `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).
129
+ - **A private registry's credential is resolved and used** (`environments .image_import`, `environments.resolve`; PLAN_ENV.md E3-04's second half).
105
130
  `image.credentialSecretId` used to only clear the allowlist check; nothing
106
131
  fetched or used the credential it named. It is now fetched through the
107
132
  same IAM route a build secret is (E3-05), and sent as HTTP Basic on the
@@ -113,8 +138,7 @@
113
138
  - **The Datalayer base channel's own five ESM-locked advisories are allowed**
114
139
  (`environments.policy`; PLAN_ENV.md E1-08). Amazon Inspector marks all five
115
140
  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,
141
+ `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
142
  and any other critical still blocks.
119
143
 
120
144
  ## 1.9.4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: code_sandboxes
3
- Version: 1.9.11
3
+ Version: 1.9.14
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
  <!--
@@ -3,4 +3,4 @@
3
3
 
4
4
  """Code Sandboxes."""
5
5
 
6
- __version__ = "1.9.11"
6
+ __version__ = "1.9.14"
@@ -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
  ]
@@ -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
- def owner_repository(owner_uid: str, environment_name: str) -> str:
103
- """The owner's repository for one environment: ``environments/u/<owner>/<name>``.
104
-
105
- Lowercased: an ECR repository name matches
106
- ``[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*`` per path segment, and this
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 environments are resolved by their own solver, "
255
- "which is not built yet",
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
- if lock_text is not None and not locked_versions(lock_text):
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
- lines.extend(
349
- [
350
- "COPY lock.txt /opt/datalayer/lock.txt",
351
- # `sync` and not `install`: the artifact holds the lock's set,
352
- # and `--require-hashes` means every byte was the resolved one.
353
- # `--find-links` for what no index has — a protected pin's
354
- # own wheel, the fork's local version above all (E1-04).
355
- "RUN --mount=type=cache,target=/root/.cache/uv "
356
- f"uv pip sync --system --require-hashes --find-links {find_links} "
357
- "/opt/datalayer/lock.txt",
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
@@ -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
- image.add_local_file(str(lock_file), _LOCK_PATH)
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"), and this phase's `build_sources` is
352
- # `("packages",)` only, so every build starts from that
353
- # base. Reinstalling it added an extra un-hashed network
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
- .run_cmd(f'pip install --no-cache-dir "uv=={_UV_VERSION}"', user="root")
394
- # Packages install as root (E0-04): a user install lands
395
- # under /home/user, which the runtime mounts over.
396
- .run_cmd(
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:
@@ -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
- # A GPU is asked for two ways, and the spec's own validation
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]: