datalab-capsule 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. datalab_capsule-0.1.0/CHANGELOG.md +24 -0
  2. datalab_capsule-0.1.0/LICENSE +28 -0
  3. datalab_capsule-0.1.0/MANIFEST.in +9 -0
  4. datalab_capsule-0.1.0/PKG-INFO +170 -0
  5. datalab_capsule-0.1.0/README.md +138 -0
  6. datalab_capsule-0.1.0/benchmarks/_harness.py +511 -0
  7. datalab_capsule-0.1.0/benchmarks/capsule_cost.py +451 -0
  8. datalab_capsule-0.1.0/benchmarks/fingerprint_cost.py +237 -0
  9. datalab_capsule-0.1.0/doc/api.md +110 -0
  10. datalab_capsule-0.1.0/doc/decisions/0001-processing-chain-foundations.md +42 -0
  11. datalab_capsule-0.1.0/doc/decisions/0002-generic-contracts-and-generalized-replay.md +33 -0
  12. datalab_capsule-0.1.0/doc/deployment.md +64 -0
  13. datalab_capsule-0.1.0/doc/development.md +69 -0
  14. datalab_capsule-0.1.0/doc/interoperability.md +100 -0
  15. datalab_capsule-0.1.0/doc/performance.md +191 -0
  16. datalab_capsule-0.1.0/doc/rules.md +87 -0
  17. datalab_capsule-0.1.0/doc/scenario.md +117 -0
  18. datalab_capsule-0.1.0/doc/security.md +46 -0
  19. datalab_capsule-0.1.0/examples/third_party_reader.py +279 -0
  20. datalab_capsule-0.1.0/examples/workspace_to_capsule.py +37 -0
  21. datalab_capsule-0.1.0/pyproject.toml +67 -0
  22. datalab_capsule-0.1.0/scripts/check_dist.py +175 -0
  23. datalab_capsule-0.1.0/scripts/check_profile.py +177 -0
  24. datalab_capsule-0.1.0/scripts/corpus_desktop_sources.py +96 -0
  25. datalab_capsule-0.1.0/scripts/corpus_families_reports.py +60 -0
  26. datalab_capsule-0.1.0/setup.cfg +4 -0
  27. datalab_capsule-0.1.0/src/datalab_capsule/__init__.py +10 -0
  28. datalab_capsule-0.1.0/src/datalab_capsule/_schema.py +31 -0
  29. datalab_capsule-0.1.0/src/datalab_capsule/archive.py +420 -0
  30. datalab_capsule-0.1.0/src/datalab_capsule/calls.py +155 -0
  31. datalab_capsule-0.1.0/src/datalab_capsule/cli.py +496 -0
  32. datalab_capsule-0.1.0/src/datalab_capsule/compare.py +517 -0
  33. datalab_capsule-0.1.0/src/datalab_capsule/contexts/ro-crate-1.3.jsonld +3104 -0
  34. datalab_capsule-0.1.0/src/datalab_capsule/diff.py +199 -0
  35. datalab_capsule-0.1.0/src/datalab_capsule/environment.py +86 -0
  36. datalab_capsule-0.1.0/src/datalab_capsule/exchange.py +316 -0
  37. datalab_capsule-0.1.0/src/datalab_capsule/hdf5.py +703 -0
  38. datalab_capsule-0.1.0/src/datalab_capsule/inspection.py +749 -0
  39. datalab_capsule-0.1.0/src/datalab_capsule/integrity.py +637 -0
  40. datalab_capsule-0.1.0/src/datalab_capsule/ledger.py +473 -0
  41. datalab_capsule-0.1.0/src/datalab_capsule/legacy.py +279 -0
  42. datalab_capsule-0.1.0/src/datalab_capsule/manifest.py +816 -0
  43. datalab_capsule-0.1.0/src/datalab_capsule/recorder.py +1224 -0
  44. datalab_capsule-0.1.0/src/datalab_capsule/registry.py +455 -0
  45. datalab_capsule-0.1.0/src/datalab_capsule/registry_app.py +211 -0
  46. datalab_capsule-0.1.0/src/datalab_capsule/registry_client.py +269 -0
  47. datalab_capsule-0.1.0/src/datalab_capsule/replay.py +274 -0
  48. datalab_capsule-0.1.0/src/datalab_capsule/review.py +114 -0
  49. datalab_capsule-0.1.0/src/datalab_capsule/schemas/ledger-1.schema.json +255 -0
  50. datalab_capsule-0.1.0/src/datalab_capsule/schemas/report-1.schema.json +146 -0
  51. datalab_capsule-0.1.0/src/datalab_capsule/schemas/review-1.schema.json +40 -0
  52. datalab_capsule-0.1.0/src/datalab_capsule/verify.py +198 -0
  53. datalab_capsule-0.1.0/src/datalab_capsule.egg-info/PKG-INFO +170 -0
  54. datalab_capsule-0.1.0/src/datalab_capsule.egg-info/SOURCES.txt +156 -0
  55. datalab_capsule-0.1.0/src/datalab_capsule.egg-info/dependency_links.txt +1 -0
  56. datalab_capsule-0.1.0/src/datalab_capsule.egg-info/entry_points.txt +3 -0
  57. datalab_capsule-0.1.0/src/datalab_capsule.egg-info/requires.txt +18 -0
  58. datalab_capsule-0.1.0/src/datalab_capsule.egg-info/top_level.txt +1 -0
  59. datalab_capsule-0.1.0/tests/__init__.py +0 -0
  60. datalab_capsule-0.1.0/tests/corpus.py +331 -0
  61. datalab_capsule-0.1.0/tests/fixtures/corpus/README.md +66 -0
  62. datalab_capsule-0.1.0/tests/fixtures/corpus/expected.json +364 -0
  63. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/altered-state.dlcapsule +0 -0
  64. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/attachment-altered.dlcapsule +0 -0
  65. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/attachment-undeclared.dlcapsule +0 -0
  66. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/bad-revision.dlcapsule +0 -0
  67. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/compressed-entry.dlcapsule +0 -0
  68. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/duplicate-entry.dlcapsule +0 -0
  69. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/ledger-mismatch.dlcapsule +0 -0
  70. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/missing-manifest.dlcapsule +0 -0
  71. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/path-traversal.dlcapsule +0 -0
  72. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/referenced-with-workspace.dlcapsule +0 -0
  73. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/report-invalid.json +62 -0
  74. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/report-unknown-activity.json +62 -0
  75. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/review-tampered.json +19 -0
  76. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/review-wrong-target.json +14 -0
  77. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/tampered-manifest.dlcapsule +0 -0
  78. datalab_capsule-0.1.0/tests/fixtures/corpus/invalid/workspace-mismatch.dlcapsule +0 -0
  79. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/capture_desktop.h5 +0 -0
  80. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/capture_web.h5 +0 -0
  81. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/chain_altered.h5 +0 -0
  82. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/chain_missing.h5 +0 -0
  83. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/difference_desktop.h5 +0 -0
  84. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/difference_web.h5 +0 -0
  85. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/families_desktop.h5 +0 -0
  86. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/families_web.h5 +0 -0
  87. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/legacy_continued.h5 +0 -0
  88. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/legacy_imported.h5 +0 -0
  89. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/report_difference_altered.json +52 -0
  90. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/report_difference_exact.json +62 -0
  91. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/report_families_centroid.json +140 -0
  92. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/report_families_convolution.json +122 -0
  93. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/report_families_detection.json +82 -0
  94. datalab_capsule-0.1.0/tests/fixtures/corpus/sources/report_legacy_opaque.json +21 -0
  95. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/attachments.dlcapsule +0 -0
  96. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/capture-desktop.dlcapsule +0 -0
  97. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/capture-web.dlcapsule +0 -0
  98. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/chain-desktop.dlcapsule +0 -0
  99. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/chain-renamed.dlcapsule +0 -0
  100. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/chain-web.dlcapsule +0 -0
  101. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/difference-desktop.dlcapsule +0 -0
  102. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/difference-web.dlcapsule +0 -0
  103. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/families-desktop.dlcapsule +0 -0
  104. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/families-web.dlcapsule +0 -0
  105. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/legacy-revision.dlcapsule +0 -0
  106. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/legacy.dlcapsule +0 -0
  107. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/missing-resource.dlcapsule +0 -0
  108. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/referenced.dlcapsule +0 -0
  109. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/report-difference-altered.json +52 -0
  110. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/report-difference-exact.json +62 -0
  111. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/report-families-centroid.json +140 -0
  112. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/report-families-convolution.json +122 -0
  113. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/report-families-detection.json +82 -0
  114. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/report-legacy-opaque.json +21 -0
  115. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/report-numeric-different.json +44 -0
  116. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/review-comment.json +19 -0
  117. datalab_capsule-0.1.0/tests/fixtures/corpus/valid/review-endorsed.json +19 -0
  118. datalab_capsule-0.1.0/tests/fixtures/expressiveness/analysis_artifact.json +104 -0
  119. datalab_capsule-0.1.0/tests/fixtures/expressiveness/average_fan_in.json +188 -0
  120. datalab_capsule-0.1.0/tests/fixtures/expressiveness/difference.json +160 -0
  121. datalab_capsule-0.1.0/tests/fixtures/expressiveness/fan_out_missing_intermediate.json +255 -0
  122. datalab_capsule-0.1.0/tests/fixtures/expressiveness/generate.py +339 -0
  123. datalab_capsule-0.1.0/tests/fixtures/expressiveness/one_to_n.json +159 -0
  124. datalab_capsule-0.1.0/tests/fixtures/expressiveness/opaque_not_encoded.json +127 -0
  125. datalab_capsule-0.1.0/tests/fixtures/expressiveness/parameter_types.json +137 -0
  126. datalab_capsule-0.1.0/tests/fixtures/expressiveness/report_within_tolerance.json +55 -0
  127. datalab_capsule-0.1.0/tests/fixtures/workspaces/desktop_chain.h5 +0 -0
  128. datalab_capsule-0.1.0/tests/fixtures/workspaces/web_chain.h5 +0 -0
  129. datalab_capsule-0.1.0/tests/golden/check_golden.py +94 -0
  130. datalab_capsule-0.1.0/tests/golden/jcs/rfc8785-sample.json +5 -0
  131. datalab_capsule-0.1.0/tests/golden/jcs/rfc8785-sample.out +1 -0
  132. datalab_capsule-0.1.0/tests/golden/vectors.json +66 -0
  133. datalab_capsule-0.1.0/tests/helpers.py +79 -0
  134. datalab_capsule-0.1.0/tests/pyodide/package.json +9 -0
  135. datalab_capsule-0.1.0/tests/pyodide/run_benchmark.mjs +135 -0
  136. datalab_capsule-0.1.0/tests/pyodide/run_pyodide.mjs +92 -0
  137. datalab_capsule-0.1.0/tests/test_attachments.py +218 -0
  138. datalab_capsule-0.1.0/tests/test_benchmarks.py +60 -0
  139. datalab_capsule-0.1.0/tests/test_capsule.py +367 -0
  140. datalab_capsule-0.1.0/tests/test_corpus.py +112 -0
  141. datalab_capsule-0.1.0/tests/test_cross_edition.py +66 -0
  142. datalab_capsule-0.1.0/tests/test_diff_verify.py +458 -0
  143. datalab_capsule-0.1.0/tests/test_environment.py +49 -0
  144. datalab_capsule-0.1.0/tests/test_exchange.py +188 -0
  145. datalab_capsule-0.1.0/tests/test_hdf5_block.py +617 -0
  146. datalab_capsule-0.1.0/tests/test_hostile_inputs.py +225 -0
  147. datalab_capsule-0.1.0/tests/test_inspection.py +703 -0
  148. datalab_capsule-0.1.0/tests/test_integrity.py +315 -0
  149. datalab_capsule-0.1.0/tests/test_ledger.py +305 -0
  150. datalab_capsule-0.1.0/tests/test_legacy.py +359 -0
  151. datalab_capsule-0.1.0/tests/test_no_app_imports.py +26 -0
  152. datalab_capsule-0.1.0/tests/test_operator_cli.py +226 -0
  153. datalab_capsule-0.1.0/tests/test_profile_resources.py +81 -0
  154. datalab_capsule-0.1.0/tests/test_recorder.py +643 -0
  155. datalab_capsule-0.1.0/tests/test_registry.py +339 -0
  156. datalab_capsule-0.1.0/tests/test_replay.py +620 -0
  157. datalab_capsule-0.1.0/tests/test_revisions.py +161 -0
  158. datalab_capsule-0.1.0/tests/test_third_party_example.py +125 -0
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to DataLab-Capsule are documented in this file. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The capsule format itself is versioned by its profile (<https://datalab-platform.com/capsule/0.1>).
4
+
5
+ ## [0.1.0] - 2026-10-19
6
+
7
+ First public release, shared by DataLab Desktop and DataLab-Web.
8
+
9
+ ### Added
10
+
11
+ - **Workspace provenance model:** a neutral record of processing (operation calls with their parameters, input and output states, activities, execution environments) stored in DataLab workspaces (`/DataLab_Provenance`) and read and written with h5py alone. Signal and image states are identified by fingerprints of their data, coordinates or calibration and units, and by their regions of interest; analysis results by the digest of their stored value. A state whose saved data no longer match is reported as altered.
12
+ - **Replay preparation and verification reports:** an edition can recompute a recorded activity and compare it with the stored result (`exact`, `within_tolerance` under the tolerance declared for the operation, `different`, or `not_verified` with its reason); only operations with a qualified contract are replayed, and nothing named in a file is ever executed. An input whose data are unchanged but whose region of interest changed since the activity (for example regions added by a detection) is replayed on a copy carrying the recorded region of interest, never modified itself. A recorded result whose data or region of interest changed since the activity is reported as altered and never used as reference.
13
+ - **Provenance of a result:** an edition can describe, for one signal or image, the recorded activity that produced its state (parameters, ordered inputs and their ancestors, expanded on demand), what is still available, the analyses recorded on it and whether the local library knows and qualifies the operation, without computing, and check the data of the object and of the direct inputs against the recorded states. Processing restores the call that produced the latest recorded state of an object, every input included; knowing an operation and qualifying its verification are kept apart. When a workspace file is appended to the current one, its provenance is not imported, and objects holding an identifier already known to the current ledger never inherit what was recorded for another object.
14
+ - **Legacy workspaces:** processing records stored by earlier DataLab versions become legacy activities that keep the record as stored, invent nothing and are never replayed.
15
+ - **Capsules (`.dlcapsule`):** a ZIP archive with the workspace and an RO-Crate 1.3 manifest (Process Run Crate 0.6 and the DataLab capsule profile 0.1). The safe reader refuses path traversal, links, duplicates, encrypted, compressed or damaged entries and oversized archives, and never accesses the network. A capsule may reference its workspace by an address instead of including it; the bytes supplied must match the manifest.
16
+ - **Revisions and reviews:** a capsule may name its parent revision; reviews are separate documents about one revision, with their own fingerprint. The capsule a workspace was opened from is saved with the workspace file, so that a revision exported after the workspace was saved and opened again still names its parent.
17
+ - **Light attachments:** up to 8 files of 16 MiB (protocol, notes, small tables) declared in the manifest with their size and SHA-256; checked, returned as data, never opened or executed.
18
+ - **Comparison (`diff`) and verification (`verify`):** changes between two revisions sorted into scientific, presentation, storage, environment and attachment changes, with a scientific conclusion that never claims equality beyond what the manifests record; verification of the archive, the workspace, the stored states and supplied reports and reviews, without computation.
19
+ - **Command line `workspace-capsule`:** `validate`, `inspect`, `diff`, `verify`, `attachment`, `workspace`, `create`, `review`, and `registry list | publish | fetch`.
20
+ - **Optional registry (`registry` extra):** publishes and serves manifests, their attachments and reviews (never workspaces), with checks on every document, an OpenAPI description, open reading and token-protected publishing (`workspace-capsule-registry`). Its client reads each response up to a size limit and checks everything it fetches; it also gives the registry status and each publishing step apart (manifest, attachment, review), and downloads an attachment checked against its manifest.
21
+ - **Capsule interfaces (`exchange`):** inspection, opening, attachment download, registry checks, comparison and reviews as offered by the capsule dialogs of DataLab Desktop and DataLab-Web, so that both editions give the same answers. Supplied reports and reviews are checked apart from the integrity of the capsule.
22
+ - Runs on CPython 3.9 to 3.14 and in Pyodide (registry excepted).
23
+ - **Measured costs:** benchmarks of fingerprints and capsules (`benchmarks/`, in CPython and in Pyodide) with one command line and one report format shared with the benchmarks of DataLab Desktop and DataLab-Web; method, results and recommended sizes in [doc/performance.md](doc/performance.md).
24
+ - **Release checks:** the distributions are checked to carry every module (including `exchange`) and, on release tags, schemas and context with the SHA-256 published by the profile page (`scripts/check_profile.py`, also usable offline against a checkout of the profile).
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, DataLab Platform
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,9 @@
1
+ include CHANGELOG.md README.md LICENSE
2
+ recursive-include doc *.md
3
+ recursive-include examples *.py
4
+ recursive-include benchmarks *.py
5
+ recursive-include scripts *.py
6
+ graft tests
7
+ prune tests/pyodide/node_modules
8
+ exclude tests/pyodide/package-lock.json
9
+ global-exclude __pycache__ *.py[cod]
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.4
2
+ Name: datalab-capsule
3
+ Version: 0.1.0
4
+ Summary: Exchange and verify scientific workspace provenance as open RO-Crate capsules (library and CLI, no DataLab required)
5
+ Author: DataLab Platform Developers
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/DataLab-Platform/DataLab-Capsule
8
+ Classifier: Development Status :: 2 - Pre-Alpha
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Topic :: Scientific/Engineering
14
+ Requires-Python: <4,>=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: jsonschema>=4.17
18
+ Provides-Extra: hdf5
19
+ Requires-Dist: NumPy>=1.22; extra == "hdf5"
20
+ Requires-Dist: h5py>=3.6; extra == "hdf5"
21
+ Provides-Extra: registry
22
+ Requires-Dist: fastapi>=0.110; extra == "registry"
23
+ Requires-Dist: uvicorn>=0.27; extra == "registry"
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest>=7; extra == "test"
26
+ Requires-Dist: NumPy>=1.22; extra == "test"
27
+ Requires-Dist: h5py>=3.6; extra == "test"
28
+ Requires-Dist: httpx>=0.27; extra == "test"
29
+ Provides-Extra: dev
30
+ Requires-Dist: ruff; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # DataLab-Capsule
34
+
35
+ Exchange and verify scientific workspace provenance as open RO-Crate capsules (library and CLI, no DataLab required).
36
+
37
+ Status: experimental. Version 0.1.0 is the first public release, on PyPI as `datalab-capsule`; it implements the experimental [DataLab capsule profile 0.1](https://datalab-platform.com/capsule/0.1), which may still change.
38
+
39
+ ## Scope
40
+
41
+ - Neutral provenance model shared by DataLab Desktop and DataLab-Web: operation calls, states, activities, environments (JSON Schemas under `src/datalab_capsule/schemas`).
42
+ - Shared replay preparation (eligibility codes), comparison rules and verification reports. A report states one of four verdicts: `exact` (same values), `within_tolerance` (values within the tolerance declared and justified for that operation), `different`, or `not_verified` (with the reason: opaque operation, missing input, unavailable reference...). A rule is never widened to hide a difference; see [rules](doc/rules.md).
43
+ - HDF5 provenance block (`/DataLab_Provenance`) read and written with h5py alone; links and virtual datasets are refused.
44
+ - Integrity primitives: RFC 8785 canonical JSON, SHA-256 digests, the `datalab-signal-v1` and `datalab-image-v1` state fingerprints (data, coordinates or calibration, units). A state also records the digest of its ROI definition, and an analysis result the digest of its stored value: a saved object whose data, calibration, units or ROI differ from its state is `altered`, and a result replaced by a later analysis is never attributed to the earlier one. Fingerprints are streamed into SHA-256 without copying the arrays.
45
+ - Legacy workspaces: processing records stored by DataLab in object metadata (`__processing_parameters`, `__analysis_parameters`) of objects unknown to the ledger become `legacy_metadata` activities. They keep the record as stored and invent nothing: inputs are bound to the recorded objects (state unknown), the call is opaque without parameters, environment, edition and times are null, and import issues (missing ancestry, unavailable inputs, unsupported operations, version warnings...) are listed. They claim no result: the state of the holding object observed when the workspace was opened is named separately (`observed_state_id`), as an observed state that no activity produced. They are never replayed.
46
+ - Capsules (`.dlcapsule`): a ZIP archive holding `workspace.h5` and an RO-Crate 1.3 manifest (`ro-crate-metadata.json`) that conforms to Process Run Crate 0.6 and to the experimental [DataLab capsule profile 0.1](https://datalab-platform.com/capsule/0.1) (terms: `https://datalab-platform.com/capsule/terms#`). The reader refuses unsafe archives (path traversal, duplicates, links, encryption, compressed entries, size limits) and never accesses the network. It holds the whole archive in memory: it checks the archive size before reading it, then the size of each entry. Each edition passes its own `SizePolicy`; the default one (4 GiB workspace) is an accepted upper bound, not a tested capacity.
47
+ - Revisions and reviews: a capsule may name one parent revision by its manifest fingerprint (`dlc:revisionOf`), which is part of its own fingerprint. A review is a separate JSON document (`review-1` schema) that targets one revision by fingerprint, states who reviewed it and what was found (`endorsed`, `disputed` or `comment`), may cite verification reports by fingerprint, and has its own fingerprint. A review never modifies the capsule.
48
+ - Referenced workspaces: a capsule may reference its workspace by an absolute IRI instead of including `workspace.h5` (`dlc:referenced`). The library never fetches it: the caller passes an explicit resolver, and the bytes obtained must match the SHA-256 and size recorded in the manifest.
49
+ - Light attachments: up to 8 files of at most 16 MiB each, chosen by the author (protocol, notes, small tables...), stored under `attachments/` and declared in the manifest (`dlc:attachment`) with their media type, size and SHA-256. They are part of the manifest fingerprint. The reader refuses undeclared, missing or altered attachments. They are returned as bytes, written to disk only on explicit request, and never opened or executed.
50
+ - Semantic diff (`diff_manifests`): changes between two capsules are sorted into scientific (activities, parameters, states, fingerprints, ROI), presentation (name, description, licence, date), storage (workspace file SHA-256 and size, included or referenced, locators: different bytes do not show a scientific change), environment (environments, packages, the environment of each activity) and attachments (added, removed or changed; their content is not interpreted, since a protocol or a calibration certificate may matter scientifically). `scientific_conclusion` says what can be concluded: `differences`, `none` (no scientific change, the same workspace file and the same attachment contents) or `none_detected` (nothing differs in the recorded activities and states, but the workspace files or the attachment contents differ, so equality is not established).
51
+ - Verification without computation (`verify_capsule`): the archive and manifest, the workspace integrity, the match between the manifest and the workspace ledger, the fingerprints and ROI of every stored state (with h5py), and supplied verification reports and reviews. Recomputing an activity is the replay of an edition, never this package's job.
52
+ - Pure Python for CPython 3.9+ and Pyodide (Python 3.12). The core only needs the standard library and `jsonschema`; HDF5 helpers use NumPy and h5py.
53
+ - The package never imports DataLab, Sigima, SigimaX or Qt, and never executes code named in a file.
54
+
55
+ ## Installation
56
+
57
+ Users of DataLab Desktop and DataLab-Web need nothing more than their edition: both handle capsules from _File > Workspace capsule…_ (export, inspection, local replay, revisions, registry) and use the same functions of this package (`datalab_capsule.exchange`). The [two-operator scenario](doc/scenario.md) follows that path.
58
+
59
+ The package itself is installed in one of three ways, which must not be mixed up:
60
+
61
+ - **Released version**, for users of the command line and third-party readers: `pip install datalab-capsule`, with the `hdf5` extra to create capsules or check stored states and the `registry` extra to run a registry.
62
+ - **Candidate qualification**, before a release: a wheel and an sdist built from the commit to qualify (`python -m build`), checked with `scripts/check_dist.py` and `scripts/check_profile.py`, then installed in a clean environment, outside the checkout.
63
+ - **Development**: editable install of this checkout, used by the sibling checkouts of DataLab and DataLab-Web (see [developer notes](doc/development.md)).
64
+
65
+ ## Command line
66
+
67
+ Validating, inspecting and comparing capsules needs neither NumPy nor h5py:
68
+
69
+ ```powershell
70
+ workspace-capsule validate workspace.dlcapsule
71
+ workspace-capsule inspect workspace.dlcapsule [--json]
72
+ workspace-capsule diff old.dlcapsule new.dlcapsule [--json]
73
+ ```
74
+
75
+ `diff` exits with 0 when the capsules are the same revision (same manifest fingerprint) and 1 when they differ.
76
+
77
+ Writing one attachment to a new file (an existing file is never overwritten, and the attachment is never opened):
78
+
79
+ ```powershell
80
+ workspace-capsule attachment workspace.dlcapsule protocol.txt protocol.txt
81
+ ```
82
+
83
+ Commands for an operator working with DataLab Desktop (`create` needs the `hdf5` extra): create a capsule from a saved workspace (optionally a revision of another capsule, with light attachments), write a review, extract the checked workspace to open it in DataLab, and exchange through a registry (only these commands use the network; everything fetched is checked):
84
+
85
+ ```powershell
86
+ workspace-capsule create workspace.h5 workspace.dlcapsule [--name NAME] [--description TEXT] [--revision-of PARENT.dlcapsule] [--workspace-ref IRI] [--attach FILE]...
87
+ workspace-capsule review workspace.dlcapsule review.json --reviewer NAME --statement TEXT [--verdict endorsed|disputed|comment] [--report report.json]...
88
+ workspace-capsule workspace workspace.dlcapsule workspace.h5
89
+ workspace-capsule registry list URL [--json]
90
+ workspace-capsule registry publish URL workspace.dlcapsule [--review review.json]... --token-env VARIABLE
91
+ workspace-capsule registry fetch URL FINGERPRINT FOLDER
92
+ ```
93
+
94
+ `diff` also compares manifest files (`.json`) fetched from a registry. `registry fetch` does not save an attachment whose name Windows reserves for a device (`NUL`, `CON`...). The [two-operator scenario](doc/scenario.md) puts these commands together with DataLab Desktop and DataLab-Web.
95
+
96
+ Verifying a capsule reads the stored states with h5py; without h5py, it checks only the workspace SHA-256 and size and says so (`integrity_only`). A referenced workspace is checked only when its file is given; reports and reviews are optional:
97
+
98
+ ```powershell
99
+ workspace-capsule verify workspace.dlcapsule [--workspace workspace.h5] [--report report.json]... [--review review.json]... [--json]
100
+ ```
101
+
102
+ `verify` exits with 0 when no problem is found and 1 otherwise. It never computes or fetches anything.
103
+
104
+ Creating a capsule from a workspace saved by DataLab (needs the `hdf5` extra):
105
+
106
+ ```powershell
107
+ python examples/workspace_to_capsule.py workspace.h5 workspace.dlcapsule
108
+ ```
109
+
110
+ Reading and checking a capsule without this package, with `json`, `zipfile`, `hashlib` and h5py only (a third-party example that follows the published profile):
111
+
112
+ ```powershell
113
+ python examples/third_party_reader.py workspace.dlcapsule
114
+ ```
115
+
116
+ ## Registry (optional)
117
+
118
+ A small registry publishes and serves capsule manifests, the attachments they declare and their reviews, so that revisions can be found, compared and discussed. It never stores workspaces: a manifest names its workspace by SHA-256 and size (and by address when it is referenced). Everything keeps working without a registry. Manifests are validated and identified by their fingerprint, attachments must match their declared size and SHA-256, reviews must target a published revision. Metadata is kept in SQLite and documents in files.
119
+
120
+ ```powershell
121
+ pip install "datalab-capsule[registry]"
122
+ $env:REGISTRY_TOKEN = "<secret>"
123
+ workspace-capsule-registry registry-data --token-env REGISTRY_TOKEN --origin https://web.example
124
+ ```
125
+
126
+ Reading is open; publishing needs `Authorization: Bearer <token>` when a token is set (without one, publishing is open: local use only). The API is described at `/docs` and `/openapi.json`; see [API](doc/api.md#registry).
127
+
128
+ ## Documentation
129
+
130
+ - [Two-operator scenario](doc/scenario.md): DataLab Desktop and DataLab-Web, without server and with a registry
131
+ - [Interoperability report](doc/interoperability.md): what the editions exchange, check and replay, findings and limits
132
+ - [Performance and capacity](doc/performance.md): how costs are measured, results and recommended sizes
133
+ - [Developer notes](doc/development.md) and [deployment notes](doc/deployment.md) (registry, profile pages)
134
+ - [Identity, compatibility and restoration rules](doc/rules.md)
135
+ - [API](doc/api.md)
136
+ - [Security analysis](doc/security.md)
137
+ - [Decision 0001: foundations of the processing chain](doc/decisions/0001-processing-chain-foundations.md)
138
+ - [Fixture corpus](tests/fixtures/corpus/README.md), valid and invalid, with the expected command-line results
139
+ - Profile and terms: <https://datalab-platform.com/capsule/0.1>
140
+
141
+ ## Development
142
+
143
+ ```powershell
144
+ python -m venv .venv
145
+ .\.venv\Scripts\python.exe -m pip install -e ".[test,dev]"
146
+ .\.venv\Scripts\python.exe -m pytest
147
+ ```
148
+
149
+ Golden vectors and the test suite in Pyodide (Node 22):
150
+
151
+ ```powershell
152
+ .\.venv\Scripts\python.exe -m pip wheel . --no-deps -w dist
153
+ cd tests\pyodide
154
+ npm install
155
+ node run_pyodide.mjs (Resolve-Path ..\..\dist\datalab_capsule-*.whl)
156
+ ```
157
+
158
+ Cost of fingerprints and of capsules (time and memory), in CPython and in Pyodide (see [performance](doc/performance.md)):
159
+
160
+ ```powershell
161
+ .\.venv\Scripts\python.exe -m pip install -r benchmarks\requirements.txt
162
+ .\.venv\Scripts\python.exe benchmarks\fingerprint_cost.py --profile quick --output build\bench\fingerprints.json
163
+ .\.venv\Scripts\python.exe benchmarks\capsule_cost.py --profile representative --output build\bench\capsules.json
164
+ cd tests\pyodide
165
+ node run_benchmark.mjs (Resolve-Path ..\..\dist\datalab_capsule-*.whl) capsule_cost.py --profile quick --output ..\..\build\bench\capsules-pyodide.json
166
+ ```
167
+
168
+ ## License
169
+
170
+ BSD 3-Clause, see [LICENSE](LICENSE). The embedded RO-Crate 1.3 JSON-LD context (`src/datalab_capsule/contexts/ro-crate-1.3.jsonld`) is distributed by its authors under CC0 1.0.
@@ -0,0 +1,138 @@
1
+ # DataLab-Capsule
2
+
3
+ Exchange and verify scientific workspace provenance as open RO-Crate capsules (library and CLI, no DataLab required).
4
+
5
+ Status: experimental. Version 0.1.0 is the first public release, on PyPI as `datalab-capsule`; it implements the experimental [DataLab capsule profile 0.1](https://datalab-platform.com/capsule/0.1), which may still change.
6
+
7
+ ## Scope
8
+
9
+ - Neutral provenance model shared by DataLab Desktop and DataLab-Web: operation calls, states, activities, environments (JSON Schemas under `src/datalab_capsule/schemas`).
10
+ - Shared replay preparation (eligibility codes), comparison rules and verification reports. A report states one of four verdicts: `exact` (same values), `within_tolerance` (values within the tolerance declared and justified for that operation), `different`, or `not_verified` (with the reason: opaque operation, missing input, unavailable reference...). A rule is never widened to hide a difference; see [rules](doc/rules.md).
11
+ - HDF5 provenance block (`/DataLab_Provenance`) read and written with h5py alone; links and virtual datasets are refused.
12
+ - Integrity primitives: RFC 8785 canonical JSON, SHA-256 digests, the `datalab-signal-v1` and `datalab-image-v1` state fingerprints (data, coordinates or calibration, units). A state also records the digest of its ROI definition, and an analysis result the digest of its stored value: a saved object whose data, calibration, units or ROI differ from its state is `altered`, and a result replaced by a later analysis is never attributed to the earlier one. Fingerprints are streamed into SHA-256 without copying the arrays.
13
+ - Legacy workspaces: processing records stored by DataLab in object metadata (`__processing_parameters`, `__analysis_parameters`) of objects unknown to the ledger become `legacy_metadata` activities. They keep the record as stored and invent nothing: inputs are bound to the recorded objects (state unknown), the call is opaque without parameters, environment, edition and times are null, and import issues (missing ancestry, unavailable inputs, unsupported operations, version warnings...) are listed. They claim no result: the state of the holding object observed when the workspace was opened is named separately (`observed_state_id`), as an observed state that no activity produced. They are never replayed.
14
+ - Capsules (`.dlcapsule`): a ZIP archive holding `workspace.h5` and an RO-Crate 1.3 manifest (`ro-crate-metadata.json`) that conforms to Process Run Crate 0.6 and to the experimental [DataLab capsule profile 0.1](https://datalab-platform.com/capsule/0.1) (terms: `https://datalab-platform.com/capsule/terms#`). The reader refuses unsafe archives (path traversal, duplicates, links, encryption, compressed entries, size limits) and never accesses the network. It holds the whole archive in memory: it checks the archive size before reading it, then the size of each entry. Each edition passes its own `SizePolicy`; the default one (4 GiB workspace) is an accepted upper bound, not a tested capacity.
15
+ - Revisions and reviews: a capsule may name one parent revision by its manifest fingerprint (`dlc:revisionOf`), which is part of its own fingerprint. A review is a separate JSON document (`review-1` schema) that targets one revision by fingerprint, states who reviewed it and what was found (`endorsed`, `disputed` or `comment`), may cite verification reports by fingerprint, and has its own fingerprint. A review never modifies the capsule.
16
+ - Referenced workspaces: a capsule may reference its workspace by an absolute IRI instead of including `workspace.h5` (`dlc:referenced`). The library never fetches it: the caller passes an explicit resolver, and the bytes obtained must match the SHA-256 and size recorded in the manifest.
17
+ - Light attachments: up to 8 files of at most 16 MiB each, chosen by the author (protocol, notes, small tables...), stored under `attachments/` and declared in the manifest (`dlc:attachment`) with their media type, size and SHA-256. They are part of the manifest fingerprint. The reader refuses undeclared, missing or altered attachments. They are returned as bytes, written to disk only on explicit request, and never opened or executed.
18
+ - Semantic diff (`diff_manifests`): changes between two capsules are sorted into scientific (activities, parameters, states, fingerprints, ROI), presentation (name, description, licence, date), storage (workspace file SHA-256 and size, included or referenced, locators: different bytes do not show a scientific change), environment (environments, packages, the environment of each activity) and attachments (added, removed or changed; their content is not interpreted, since a protocol or a calibration certificate may matter scientifically). `scientific_conclusion` says what can be concluded: `differences`, `none` (no scientific change, the same workspace file and the same attachment contents) or `none_detected` (nothing differs in the recorded activities and states, but the workspace files or the attachment contents differ, so equality is not established).
19
+ - Verification without computation (`verify_capsule`): the archive and manifest, the workspace integrity, the match between the manifest and the workspace ledger, the fingerprints and ROI of every stored state (with h5py), and supplied verification reports and reviews. Recomputing an activity is the replay of an edition, never this package's job.
20
+ - Pure Python for CPython 3.9+ and Pyodide (Python 3.12). The core only needs the standard library and `jsonschema`; HDF5 helpers use NumPy and h5py.
21
+ - The package never imports DataLab, Sigima, SigimaX or Qt, and never executes code named in a file.
22
+
23
+ ## Installation
24
+
25
+ Users of DataLab Desktop and DataLab-Web need nothing more than their edition: both handle capsules from _File > Workspace capsule…_ (export, inspection, local replay, revisions, registry) and use the same functions of this package (`datalab_capsule.exchange`). The [two-operator scenario](doc/scenario.md) follows that path.
26
+
27
+ The package itself is installed in one of three ways, which must not be mixed up:
28
+
29
+ - **Released version**, for users of the command line and third-party readers: `pip install datalab-capsule`, with the `hdf5` extra to create capsules or check stored states and the `registry` extra to run a registry.
30
+ - **Candidate qualification**, before a release: a wheel and an sdist built from the commit to qualify (`python -m build`), checked with `scripts/check_dist.py` and `scripts/check_profile.py`, then installed in a clean environment, outside the checkout.
31
+ - **Development**: editable install of this checkout, used by the sibling checkouts of DataLab and DataLab-Web (see [developer notes](doc/development.md)).
32
+
33
+ ## Command line
34
+
35
+ Validating, inspecting and comparing capsules needs neither NumPy nor h5py:
36
+
37
+ ```powershell
38
+ workspace-capsule validate workspace.dlcapsule
39
+ workspace-capsule inspect workspace.dlcapsule [--json]
40
+ workspace-capsule diff old.dlcapsule new.dlcapsule [--json]
41
+ ```
42
+
43
+ `diff` exits with 0 when the capsules are the same revision (same manifest fingerprint) and 1 when they differ.
44
+
45
+ Writing one attachment to a new file (an existing file is never overwritten, and the attachment is never opened):
46
+
47
+ ```powershell
48
+ workspace-capsule attachment workspace.dlcapsule protocol.txt protocol.txt
49
+ ```
50
+
51
+ Commands for an operator working with DataLab Desktop (`create` needs the `hdf5` extra): create a capsule from a saved workspace (optionally a revision of another capsule, with light attachments), write a review, extract the checked workspace to open it in DataLab, and exchange through a registry (only these commands use the network; everything fetched is checked):
52
+
53
+ ```powershell
54
+ workspace-capsule create workspace.h5 workspace.dlcapsule [--name NAME] [--description TEXT] [--revision-of PARENT.dlcapsule] [--workspace-ref IRI] [--attach FILE]...
55
+ workspace-capsule review workspace.dlcapsule review.json --reviewer NAME --statement TEXT [--verdict endorsed|disputed|comment] [--report report.json]...
56
+ workspace-capsule workspace workspace.dlcapsule workspace.h5
57
+ workspace-capsule registry list URL [--json]
58
+ workspace-capsule registry publish URL workspace.dlcapsule [--review review.json]... --token-env VARIABLE
59
+ workspace-capsule registry fetch URL FINGERPRINT FOLDER
60
+ ```
61
+
62
+ `diff` also compares manifest files (`.json`) fetched from a registry. `registry fetch` does not save an attachment whose name Windows reserves for a device (`NUL`, `CON`...). The [two-operator scenario](doc/scenario.md) puts these commands together with DataLab Desktop and DataLab-Web.
63
+
64
+ Verifying a capsule reads the stored states with h5py; without h5py, it checks only the workspace SHA-256 and size and says so (`integrity_only`). A referenced workspace is checked only when its file is given; reports and reviews are optional:
65
+
66
+ ```powershell
67
+ workspace-capsule verify workspace.dlcapsule [--workspace workspace.h5] [--report report.json]... [--review review.json]... [--json]
68
+ ```
69
+
70
+ `verify` exits with 0 when no problem is found and 1 otherwise. It never computes or fetches anything.
71
+
72
+ Creating a capsule from a workspace saved by DataLab (needs the `hdf5` extra):
73
+
74
+ ```powershell
75
+ python examples/workspace_to_capsule.py workspace.h5 workspace.dlcapsule
76
+ ```
77
+
78
+ Reading and checking a capsule without this package, with `json`, `zipfile`, `hashlib` and h5py only (a third-party example that follows the published profile):
79
+
80
+ ```powershell
81
+ python examples/third_party_reader.py workspace.dlcapsule
82
+ ```
83
+
84
+ ## Registry (optional)
85
+
86
+ A small registry publishes and serves capsule manifests, the attachments they declare and their reviews, so that revisions can be found, compared and discussed. It never stores workspaces: a manifest names its workspace by SHA-256 and size (and by address when it is referenced). Everything keeps working without a registry. Manifests are validated and identified by their fingerprint, attachments must match their declared size and SHA-256, reviews must target a published revision. Metadata is kept in SQLite and documents in files.
87
+
88
+ ```powershell
89
+ pip install "datalab-capsule[registry]"
90
+ $env:REGISTRY_TOKEN = "<secret>"
91
+ workspace-capsule-registry registry-data --token-env REGISTRY_TOKEN --origin https://web.example
92
+ ```
93
+
94
+ Reading is open; publishing needs `Authorization: Bearer <token>` when a token is set (without one, publishing is open: local use only). The API is described at `/docs` and `/openapi.json`; see [API](doc/api.md#registry).
95
+
96
+ ## Documentation
97
+
98
+ - [Two-operator scenario](doc/scenario.md): DataLab Desktop and DataLab-Web, without server and with a registry
99
+ - [Interoperability report](doc/interoperability.md): what the editions exchange, check and replay, findings and limits
100
+ - [Performance and capacity](doc/performance.md): how costs are measured, results and recommended sizes
101
+ - [Developer notes](doc/development.md) and [deployment notes](doc/deployment.md) (registry, profile pages)
102
+ - [Identity, compatibility and restoration rules](doc/rules.md)
103
+ - [API](doc/api.md)
104
+ - [Security analysis](doc/security.md)
105
+ - [Decision 0001: foundations of the processing chain](doc/decisions/0001-processing-chain-foundations.md)
106
+ - [Fixture corpus](tests/fixtures/corpus/README.md), valid and invalid, with the expected command-line results
107
+ - Profile and terms: <https://datalab-platform.com/capsule/0.1>
108
+
109
+ ## Development
110
+
111
+ ```powershell
112
+ python -m venv .venv
113
+ .\.venv\Scripts\python.exe -m pip install -e ".[test,dev]"
114
+ .\.venv\Scripts\python.exe -m pytest
115
+ ```
116
+
117
+ Golden vectors and the test suite in Pyodide (Node 22):
118
+
119
+ ```powershell
120
+ .\.venv\Scripts\python.exe -m pip wheel . --no-deps -w dist
121
+ cd tests\pyodide
122
+ npm install
123
+ node run_pyodide.mjs (Resolve-Path ..\..\dist\datalab_capsule-*.whl)
124
+ ```
125
+
126
+ Cost of fingerprints and of capsules (time and memory), in CPython and in Pyodide (see [performance](doc/performance.md)):
127
+
128
+ ```powershell
129
+ .\.venv\Scripts\python.exe -m pip install -r benchmarks\requirements.txt
130
+ .\.venv\Scripts\python.exe benchmarks\fingerprint_cost.py --profile quick --output build\bench\fingerprints.json
131
+ .\.venv\Scripts\python.exe benchmarks\capsule_cost.py --profile representative --output build\bench\capsules.json
132
+ cd tests\pyodide
133
+ node run_benchmark.mjs (Resolve-Path ..\..\dist\datalab_capsule-*.whl) capsule_cost.py --profile quick --output ..\..\build\bench\capsules-pyodide.json
134
+ ```
135
+
136
+ ## License
137
+
138
+ BSD 3-Clause, see [LICENSE](LICENSE). The embedded RO-Crate 1.3 JSON-LD context (`src/datalab_capsule/contexts/ro-crate-1.3.jsonld`) is distributed by its authors under CC0 1.0.