data-annotations 2.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,616 @@
1
+ Metadata-Version: 2.4
2
+ Name: data-annotations
3
+ Version: 2.1.2
4
+ Summary: Annotate generated data artifacts
5
+ Keywords: annotations,data,metadata,provenance,reproducibility
6
+ Author: Rodrigo C. G. Pena
7
+ Author-email: Rodrigo C. G. Pena <rodrigo.cerqueiragonzalezpena@unibas.ch>
8
+ License-Expression: BSD-3-Clause
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Dist: pydantic>=2.13.1
21
+ Requires-Dist: questionary>=2.1.1 ; extra == 'cli'
22
+ Requires-Dist: typer>=0.16.0 ; extra == 'cli'
23
+ Requires-Python: >=3.12
24
+ Project-URL: Source, https://gitlab.com/ceda-unibas/tools/data-annotations
25
+ Project-URL: Changelog, https://gitlab.com/ceda-unibas/tools/data-annotations/-/blob/main/CHANGELOG.md
26
+ Project-URL: Issues, https://gitlab.com/ceda-unibas/tools/data-annotations/-/issues
27
+ Provides-Extra: cli
28
+ Description-Content-Type: text/markdown
29
+
30
+ # data-annotations
31
+
32
+ A small Python package for attaching provenance and structured descriptions to the
33
+ files and directories your workflows produce.
34
+
35
+ It is designed for lightweight research and reproducibility pipelines where you want
36
+ generated datasets, tables, plots, or reports to carry enough context to explain
37
+ where they came from and what they contain.
38
+
39
+ The package captures common provenance automatically and writes plain JSON and
40
+ Markdown artifacts that are easy to inspect or archive. The canonical on-disk format
41
+ is now a single annotation document:
42
+
43
+ - Files use `artifact.ext.meta.json`
44
+ - Directories use `manifest.json`
45
+
46
+ Each annotation document stores four top-level sections:
47
+
48
+ - `annotation_version`
49
+ - `subject`
50
+ - `provenance`
51
+ - `description`
52
+
53
+ See the [changelog](CHANGELOG.md) for release history and upgrade-oriented notes.
54
+
55
+ ## Installation
56
+
57
+ Install the core library from PyPI with `pip`:
58
+
59
+ ```bash
60
+ pip install data-annotations
61
+ ```
62
+
63
+ Or add it to a project with [uv](https://astral.sh/uv/):
64
+
65
+ ```bash
66
+ uv add data-annotations
67
+ ```
68
+
69
+ The command-line interface uses optional dependencies. Install the package with
70
+ CLI support when you want to run `data-annotations` commands:
71
+
72
+ ```bash
73
+ pip install "data-annotations[cli]"
74
+ uv add "data-annotations[cli]"
75
+ ```
76
+
77
+ For development or unreleased source installs, install directly from GitLab:
78
+
79
+ ```bash
80
+ uv add "data-annotations @ git+https://gitlab.com/ceda-unibas/tools/data-annotations.git"
81
+ pip install "data-annotations @ git+https://gitlab.com/ceda-unibas/tools/data-annotations.git"
82
+ ```
83
+
84
+ Pin a source install to a particular release tag `x.y.z` with:
85
+
86
+ ```bash
87
+ uv add "data-annotations @ git+https://gitlab.com/ceda-unibas/tools/data-annotations.git@x.y.z"
88
+ ```
89
+
90
+ ## What gets captured automatically
91
+
92
+ Every annotation document includes provenance with:
93
+
94
+ - A UTC creation timestamp
95
+ - Hostname and username
96
+ - The script path and command-line arguments
97
+ - The script path relative to the Git repo root when it can be determined
98
+ - Git commit, branch, dirty state, and canonical repository remote when available
99
+ - The current `SLURM_JOB_ID` when available
100
+
101
+ You can also attach your own parameters, input file paths, and function names.
102
+ Local filesystem paths in provenance are stored as absolute paths. URI-style inputs
103
+ such as `s3://...` or `https://...` are preserved as provided.
104
+
105
+ ## Quick Start
106
+
107
+ The recommended way to annotate your data artifacts is to decorate pipeline
108
+ functions that consume some inputs and parameters, then write those artifacts.
109
+ This keeps the artifact-writing logic explicit while letting `data-annotations` capture
110
+ provenance and emit sidecars automatically.
111
+
112
+ For example, here is a complete file-level annotation workflow using the
113
+ `record_file_annotation(...)` decorator. Once `write_participants` is called, it
114
+ automatically generates sidecars `participants.csv.meta.json` and `participants.csv.README.md`.
115
+ The JSON sidecar will contain provenance and description metadata, and the Markdown sidecar
116
+ will have a human-friendly rendering of the description provided in the decorator.
117
+
118
+ ```python
119
+ from pathlib import Path
120
+
121
+ from data_annotations.annotations import record_file_annotation
122
+ from data_annotations.description import AllowedValue, FieldDefinition
123
+
124
+ @record_file_annotation(
125
+ title="Participant Cohort",
126
+ summary="Participant-level cohort assignments for the validation split.",
127
+ fields=[
128
+ FieldDefinition(
129
+ name="participant_id",
130
+ data_type="string",
131
+ summary="Stable participant identifier.",
132
+ required=True,
133
+ nullable=False,
134
+ ),
135
+ FieldDefinition(
136
+ name="group",
137
+ data_type="string",
138
+ summary="Assigned study group.",
139
+ allowed_values=[
140
+ AllowedValue(value="control"),
141
+ AllowedValue(value="treatment"),
142
+ ],
143
+ ),
144
+ ],
145
+ primary_key=["participant_id"],
146
+ artifact_kind="dataset",
147
+ acquisition_context={"source": "Study A registry export"},
148
+ generation_context={"pipeline": "baseline-v1"},
149
+ )
150
+ def write_participants(
151
+ artifact_path: Path,
152
+ input_path: Path,
153
+ split: str,
154
+ ) -> Path:
155
+ participant_ids = [
156
+ line.strip()
157
+ for line in input_path.read_text(encoding="utf-8").splitlines()[1:]
158
+ if line.strip()
159
+ ]
160
+ artifact_path.parent.mkdir(parents=True, exist_ok=True)
161
+ artifact_path.write_text(
162
+ "\n".join(
163
+ [
164
+ "participant_id,group,split",
165
+ *[
166
+ f"{participant_id},control,{split}"
167
+ for participant_id in participant_ids
168
+ ],
169
+ ]
170
+ )
171
+ + "\n",
172
+ encoding="utf-8",
173
+ )
174
+ return artifact_path
175
+
176
+ # Annotation sidecars are written automatically
177
+ # when the decorated function is called:
178
+ artifact_path = Path("outputs") / "participants.csv"
179
+ write_participants(
180
+ artifact_path=artifact_path,
181
+ input_path=Path("data/raw/participants.csv"),
182
+ split="validation",
183
+ )
184
+
185
+ print(f"{artifact_path}.meta.json")
186
+ print(f"{artifact_path}.README.md")
187
+ ```
188
+
189
+ ### Decorator Contract
190
+
191
+ You write a normal Python function and the decorator returns that function's
192
+ original return value unchanged.
193
+
194
+ For provenance-bearing decorators, recorded inputs are inferred from named
195
+ function arguments such as `input_path` and `input_paths`. Those arguments
196
+ should correspond to real data dependencies used inside the wrapped function.
197
+
198
+ For file decorators:
199
+
200
+ - `record_file_manifest(...)`
201
+ - `record_file_annotation(...)`
202
+ - `record_file_description(...)`
203
+
204
+ Your function should:
205
+
206
+ - accept one argument pointing at the output file path. By default this argument
207
+ is named `artifact_path`, but you can change the expected name with
208
+ `artifact_path_arg=...`.
209
+ - use any other normal Python arguments you need for the pipeline step.
210
+ - for provenance-bearing decorators, use argument names listed in `input_args`
211
+ for real upstream dependencies you want recorded as provenance inputs. By
212
+ default those names are `("input_path", "input_paths")`.
213
+
214
+ Your function may return any value. File decorators do not inspect that return
215
+ value. Returning the generated `artifact_path` is recommended because it is
216
+ convenient for callers, but it is not required.
217
+
218
+ For directory decorators:
219
+
220
+ - `record_directory_manifest(...)`
221
+ - `record_directory_annotation(...)`
222
+ - `record_directory_description(...)`
223
+
224
+ Your function should:
225
+
226
+ - accept one argument pointing at the output directory. By default this argument
227
+ is named `output_dir`, but you can change the expected name with
228
+ `output_dir_arg=...`.
229
+ - return a materialized iterable, usually a `list`, describing the files that
230
+ were produced in that directory.
231
+ - prefer returning a `list` or `tuple` rather than a generator, since the
232
+ decorator needs to iterate over the outputs to write sidecars.
233
+
234
+ Accepted directory return items are:
235
+
236
+ - `DocumentedArtifact` when you want per-artifact title, summary, fields,
237
+ keys, or missing-value metadata.
238
+ - `ProducedFile` when you only need path, kind, and optional precomputed hash.
239
+ - `(path, kind)` tuples when path and artifact kind are enough.
240
+ - plain path-like values when the artifact kind can default to `"other"`.
241
+
242
+ For provenance-bearing directory decorators, `input_args` works the same way as
243
+ for file decorators: matching argument names are recorded as inputs, and the
244
+ remaining bound arguments become provenance params.
245
+
246
+ Here is another decorator pattern example with `record_directory_annotation(...)`:
247
+
248
+ ```python
249
+ from pathlib import Path
250
+
251
+ from data_annotations.annotations import record_directory_annotation
252
+ from data_annotations.description import DocumentedArtifact, FieldDefinition
253
+ from data_annotations.provenance import ProducedFile
254
+
255
+ @record_directory_annotation(
256
+ title="Validation Outputs",
257
+ summary="Directory-level documentation for the validation run outputs.",
258
+ acquisition_context={"source": "Study A registry export"},
259
+ generation_context={"pipeline": "baseline-v1"},
260
+ )
261
+ def build_outputs(
262
+ output_dir: Path,
263
+ input_path: Path,
264
+ split: str,
265
+ ):
266
+ participant_ids = [
267
+ line.strip()
268
+ for line in input_path.read_text(encoding="utf-8").splitlines()[1:]
269
+ if line.strip()
270
+ ]
271
+ output_dir.mkdir(parents=True, exist_ok=True)
272
+
273
+ table_path = output_dir / "scores.csv"
274
+ table_path.write_text(
275
+ "\n".join(
276
+ [
277
+ "participant_id,score,split",
278
+ *[
279
+ f"{participant_id},0.94,{split}"
280
+ for participant_id in participant_ids
281
+ ],
282
+ ]
283
+ )
284
+ + "\n",
285
+ encoding="utf-8",
286
+ )
287
+
288
+ report_path = output_dir / "summary.txt"
289
+ report_path.write_text(
290
+ (
291
+ f"Validated {len(participant_ids)} participants from "
292
+ f"{input_path.name} for the {split} split.\n"
293
+ ),
294
+ encoding="utf-8",
295
+ )
296
+
297
+ plot_path = output_dir / "roc.png"
298
+ plot_path.write_bytes(
299
+ (
300
+ f"plot placeholder derived from {input_path.name} "
301
+ f"({len(participant_ids)} participants)\n"
302
+ ).encode("utf-8")
303
+ )
304
+
305
+ return [
306
+ DocumentedArtifact(
307
+ path=str(table_path),
308
+ kind="dataset",
309
+ title="Metrics Table",
310
+ fields=[
311
+ FieldDefinition(
312
+ name="metric",
313
+ data_type="string",
314
+ summary="Metric name.",
315
+ ),
316
+ FieldDefinition(
317
+ name="value",
318
+ data_type="float",
319
+ summary="Metric value.",
320
+ ),
321
+ ],
322
+ ),
323
+ ProducedFile(path=str(report_path), kind="report"),
324
+ (plot_path, "plot"),
325
+ ]
326
+
327
+
328
+ output_dir = Path("outputs") / "run-001"
329
+ build_outputs(
330
+ output_dir=output_dir,
331
+ input_path=Path("data/raw/participants.csv"),
332
+ split="validation",
333
+ )
334
+
335
+ print(output_dir / "manifest.json")
336
+ print(output_dir / "README.md")
337
+ ```
338
+
339
+ The decorator and direct APIs write the same canonical document shape. If you need
340
+ metadata to vary per call instead of staying fixed at decoration time, use
341
+ `annotate_file(...)`, `annotate_directory(...)`, `write_file_annotation(...)`, or
342
+ `write_directory_annotation(...)` directly instead. See the example gallery in
343
+ `examples/` for runnable examples of all approaches.
344
+
345
+ ### When To Use Decorators Vs Direct Functions
346
+
347
+ If a function is only a final serializer for already-prepared data, prefer the
348
+ direct annotation and writer APIs. They let you attach `inputs=[...]` explicitly.
349
+
350
+ ## Canonical Document Shape
351
+
352
+ File annotations store:
353
+
354
+ - `subject.path`
355
+ - `subject.kind`
356
+ - `subject.sha256`
357
+ - `provenance.*`
358
+ - `description.title`
359
+ - `description.summary`
360
+ - `description.fields`
361
+ - `description.primary_key`
362
+ - `description.missing_value_codes`
363
+ - `description.acquisition_context`
364
+ - `description.generation_context`
365
+ - `description.description_updated_at`
366
+
367
+ Directory annotations store:
368
+
369
+ - `subject.path`
370
+ - `subject.produced_files[]`
371
+ - `provenance.*`
372
+ - `description.title`
373
+ - `description.summary`
374
+ - `description.artifacts[]`
375
+ - `description.acquisition_context`
376
+ - `description.generation_context`
377
+ - `description.description_updated_at`
378
+
379
+ The `description` section intentionally excludes provenance linkage fields and
380
+ file kinds for directory artifacts. Kinds live in `subject.produced_files`.
381
+
382
+ ## Provenance Decorators And Writers
383
+
384
+ The `data_annotations.provenance` namespace provides provenance-only entry points.
385
+ Prefer the decorators when you already have a small function that writes artifacts:
386
+
387
+ ```python
388
+ from pathlib import Path
389
+
390
+ from data_annotations.provenance import record_file_manifest
391
+
392
+
393
+ @record_file_manifest(artifact_kind="report")
394
+ def write_report(
395
+ artifact_path: Path,
396
+ input_path: Path,
397
+ threshold: float = 0.5,
398
+ ):
399
+ artifact_path.parent.mkdir(parents=True, exist_ok=True)
400
+ artifact_path.write_text(
401
+ f"threshold applied: {threshold}\nsource={input_path.name}\n",
402
+ encoding="utf-8",
403
+ )
404
+
405
+
406
+ write_report(
407
+ artifact_path=Path("outputs/summary.txt"),
408
+ input_path=Path("data/raw/participants.csv"),
409
+ threshold=0.75,
410
+ )
411
+ ```
412
+
413
+ Use `record_directory_manifest(...)` for directory outputs. Directory decorators
414
+ accept `DocumentedArtifact`, `ProducedFile`, `(path, kind)`, and plain path-like
415
+ return values.
416
+
417
+ If you want the direct writer approach instead, use `write_file_manifest(...)` and
418
+ `write_directory_manifest(...)` (see `examples/`).
419
+
420
+ ## Description Layer
421
+
422
+ The `data_annotations.description` sub-package provides the structured description
423
+ models used by annotation writers and the Markdown sidecar renderers.
424
+ Within those models, the primary human-written narrative field is named `summary`.
425
+
426
+ Key public description models:
427
+
428
+ - `AllowedValue`
429
+ - `FieldDefinition`
430
+ - `DocumentedArtifact`
431
+ - `ArtifactDescription`
432
+ - `FileDescription`
433
+ - `DirectoryDescription`
434
+
435
+ Description decorators and helpers:
436
+
437
+ - `record_file_description(...)`
438
+ - `record_directory_description(...)`
439
+ - `write_file_description(...)`
440
+ - `write_directory_description(...)`
441
+ - `render_file_readme(...)`
442
+ - `render_directory_readme(...)`
443
+
444
+ Alias helpers `write_file_readme(...)` and `write_directory_readme(...)` are supported.
445
+
446
+ Use the decorator forms when the description metadata is stable
447
+ for a function, and use the direct helpers when you want to assemble descriptions
448
+ per call.
449
+
450
+ ## Recovery Helpers
451
+
452
+ Use `artifact_matches_manifest(...)` to verify whether a detached artifact still
453
+ matches an annotation document, and `checkout_manifest_source(...)` to recover the
454
+ recorded code state from Git metadata.
455
+
456
+ ```python
457
+ from pathlib import Path
458
+
459
+ from data_annotations.provenance import (
460
+ artifact_matches_manifest,
461
+ checkout_manifest_source,
462
+ )
463
+
464
+ annotation_path = Path("outputs/participants.csv.meta.json")
465
+ artifact_path = Path("downloads/participants.csv")
466
+
467
+ if artifact_matches_manifest(artifact_path, annotation_path):
468
+ recovered = checkout_manifest_source(annotation_path)
469
+ print(recovered.checkout_path)
470
+ print(recovered.script_path)
471
+ ```
472
+
473
+ ## Post-Hoc Annotation
474
+
475
+ The strongest workflow is to create provenance and description at the same time
476
+ as the artifact itself. When annotations are written during generation, the
477
+ package can capture runtime context directly and the resulting records are
478
+ typically more complete, precise, and trustworthy.
479
+
480
+ For existing artifacts, the CLI provides a post-hoc annotation path so you can
481
+ still attach provenance and description after the fact.
482
+
483
+ Post-hoc descriptions can still be very useful, but the quality of post-hoc
484
+ provenance depends on how exact the supplied answers are. In particular, fields
485
+ such as the generating script, command, function, Git commit, repository path,
486
+ inputs, and parameters are only as reliable as the information entered during
487
+ annotation.
488
+
489
+ ## CLI Workflow
490
+
491
+ This package provides a command-line interface (CLI) for retrospective annotation
492
+ and provenance inspection.
493
+
494
+ For post-hoc annotation:
495
+
496
+ ```bash
497
+ data-annotations annotate file path/to/participants.csv
498
+ data-annotations annotate directory path/to/run-001
499
+ ```
500
+
501
+ These commands prompt for missing details, write `*.meta.json` or `manifest.json`,
502
+ and optionally derive README sidecars. Post-hoc records are marked with
503
+ `capture_mode="post_hoc"`.
504
+
505
+ For provenance inspection and source recovery:
506
+
507
+ ```bash
508
+ data-annotations provenance match path/to/artifact
509
+ data-annotations provenance checkout path/to/artifact
510
+ ```
511
+
512
+ Command `match` auto-discovers `*.meta.json` for files and `manifest.json` for
513
+ directories, prints a verification summary, and suggests the exact `checkout`
514
+ command to run next when Git recovery metadata is available.
515
+
516
+ ### Run With `uvx`
517
+
518
+ ```bash
519
+ uvx --from "data-annotations[cli]" data-annotations provenance match path/to/participants.csv
520
+ ```
521
+
522
+ ### Install And Use With `uv tool`
523
+
524
+ ```bash
525
+ uv tool install "data-annotations[cli]"
526
+ data-annotations provenance match path/to/participants.csv
527
+ ```
528
+
529
+ ### Run From Repository Root
530
+
531
+ From the repository root while developing locally, run `task install` first.
532
+ That task uses `uv sync --extra cli`, so the CLI commands are available in
533
+ the project environment. You can then run:
534
+
535
+ ```bash
536
+ uv run data-annotations annotate file path/to/participants.csv
537
+ uv run data-annotations annotate directory path/to/run-001
538
+ uv run data-annotations provenance match path/to/participants.csv
539
+ uv run data-annotations provenance checkout path/to/participants.csv
540
+ ```
541
+
542
+ ## API Overview
543
+
544
+ ### Annotation Models
545
+
546
+ - `FileArtifactSubject`
547
+ - `DirectoryArtifactSubject`
548
+ - `FileAnnotationDocument`
549
+ - `DirectoryAnnotationDocument`
550
+ - `FileAnnotationResult`
551
+ - `DirectoryAnnotationResult`
552
+
553
+ ### Annotation Decorators
554
+
555
+ - `record_file_annotation(...)`
556
+ - `record_directory_annotation(...)`
557
+
558
+ ### Annotation Functions
559
+
560
+ - `write_file_annotation(...)`
561
+ - `write_directory_annotation(...)`
562
+ - `annotate_file(...)`
563
+ - `annotate_directory(...)`
564
+
565
+ ### Description Functions
566
+
567
+ - `record_file_description(...)`
568
+ - `record_directory_description(...)`
569
+ - `write_file_description(...)`
570
+ - `write_directory_description(...)`
571
+ - `write_file_readme(...)`
572
+ - `write_directory_readme(...)`
573
+ - `render_file_readme(...)`
574
+ - `render_directory_readme(...)`
575
+
576
+ ### Provenance Models
577
+
578
+ - `ProducedFile`
579
+ - `BaseProvenance`
580
+ - `FileManifest`
581
+ - `DirectoryManifest`
582
+ - `RecoveredSource`
583
+
584
+ ### Provenance Functions
585
+
586
+ - `record_file_manifest(...)`
587
+ - `record_directory_manifest(...)`
588
+ - `write_file_manifest(...)`
589
+ - `write_directory_manifest(...)`
590
+ - `artifact_matches_manifest(...)`
591
+ - `checkout_manifest_source(...)`
592
+
593
+ ## Examples
594
+
595
+ Runnable examples live in `examples/` and mirror the README workflows.
596
+ Run them from the repository root with:
597
+
598
+ ```bash
599
+ uv run python examples/record_file_annotation.py
600
+ uv run python examples/record_directory_annotation.py
601
+ uv run python examples/record_file_manifest.py
602
+ uv run python examples/record_directory_manifest.py
603
+ uv run python examples/record_file_description.py
604
+ uv run python examples/record_directory_description.py
605
+ uv run python examples/annotate_file.py
606
+ uv run python examples/annotate_directory.py
607
+ uv run python examples/write_file_manifest.py
608
+ uv run python examples/write_directory_manifest.py
609
+ uv run python examples/write_file_description.py
610
+ uv run python examples/write_directory_description.py
611
+ uv run python examples/recover_provenance.py
612
+ uv run python examples/recover_provenance_cli.py
613
+ ```
614
+
615
+ Each example writes its outputs to a fresh temporary directory and prints the
616
+ location so you can inspect the generated annotation documents and README sidecars.
@@ -0,0 +1,28 @@
1
+ data_annotations/__init__.py,sha256=h77yx_iWu2epFs7Jiy1Eq9DkiYFkYaTjAebci8e7F54,62
2
+ data_annotations/_decorators.py,sha256=G59revt4jwbgdYyQ0-S-RvgKa5mmNfEY0JXIrBeE_R0,4169
3
+ data_annotations/annotations/__init__.py,sha256=xEaWtbBeocT3_C7aPbwM6XJU4xBbzILynLrJDC71B70,775
4
+ data_annotations/annotations/decorators.py,sha256=doM75F3Uzx97_UlsiV_Yo7C1H3HhWcY5aTNusRpPazg,5185
5
+ data_annotations/annotations/models.py,sha256=SViVdGKLzNfuQLadGqFBcOD6y9i2GOsVbPhvyWPTlck,1182
6
+ data_annotations/annotations/writers.py,sha256=L6wpwEIEZfoswoDMe-RpkyJKgUHKSebjn5HeLptC-Vc,12176
7
+ data_annotations/cli.py,sha256=lkFdRoSgZhEmDc2MAXcHJYxx-RTNY4yqR0ReV-gZZmM,1166
8
+ data_annotations/cli_app/__init__.py,sha256=jt61kC9fbNQF-g2l_0l74H3jhZICduvW0JuGQneX59o,48
9
+ data_annotations/cli_app/annotate.py,sha256=-PKKqYyW0iJVvVzKe5aq7hAUMbzXUhRw6if-zSkfcBU,9981
10
+ data_annotations/cli_app/common.py,sha256=zuhixhra7mPgCoJ2bHZ-RAtQvYjyK3s3R6qKa1_coho,8692
11
+ data_annotations/cli_app/prompts.py,sha256=c0Ic7uAdE712pxWGOjBMY_aokYj_ER9r80So6IAWLnw,15861
12
+ data_annotations/cli_app/provenance_commands.py,sha256=Tl6N8OMH5sCMbEW4nxy6dw7wxHxhplLeEITT7PZb4bI,3534
13
+ data_annotations/description/__init__.py,sha256=egGBeC8XFeIaOaQoFAHXCo2FRkdNWhcZLJoHf854UMI,914
14
+ data_annotations/description/decorators.py,sha256=Q87xHD8d-bQ6oUQOmtWF-FjY-pIazgFJDfyQBkVcrRI,4893
15
+ data_annotations/description/models.py,sha256=ONUCzHGHAC5-Vt--zHtghMSHRvkn4JW1OUqc0R7bdlA,2037
16
+ data_annotations/description/writers.py,sha256=Xmmd0s3Z7XLCi4HDDIj4_8ZzEQjkeQHLi6gAtVX_at8,9611
17
+ data_annotations/provenance/__init__.py,sha256=7tUZwU3d3f95AhmbeAAqGPAaj9cA9ptoIntrkL_6EDU,902
18
+ data_annotations/provenance/decorators.py,sha256=1e_1FPho4K4oZBk3NldlRqIvZuRVjcI6fLwEKXXRSNc,3444
19
+ data_annotations/provenance/git.py,sha256=mmg0Yz4xt0IS9o3918aLCLx_aAXyfSUpQI3PZ5_t8cg,3567
20
+ data_annotations/provenance/models.py,sha256=3Xr1KEw-gR8eU0j6eQJiFLt4ql1ksu_lfdwkZQigP3U,1373
21
+ data_annotations/provenance/recovery.py,sha256=mkXxRAv4iDEC3q6yPFG0X8N70GDxv4y7s1CNLAj0rfA,15495
22
+ data_annotations/provenance/runtime.py,sha256=RTDlVdu8OoDir3Yrq4RbKYAdCoeVbeitOJdqJNBUgG4,7601
23
+ data_annotations/provenance/writers.py,sha256=LmXrGMAgswJloPVann18Nac6q9NOdIJEsHn5QZtXxc4,6271
24
+ data_annotations-2.1.2.dist-info/licenses/LICENSE,sha256=vSASxJqHJtQLK_RLnAc7fOHlVB-cO-ZbhEtZSYf21hI,1512
25
+ data_annotations-2.1.2.dist-info/WHEEL,sha256=q5IF0q2xCp3ktUFRCVWsQLjl2ChNlWXBJtnI1LCGdJ8,80
26
+ data_annotations-2.1.2.dist-info/entry_points.txt,sha256=RmyZW2enCx9sFC5loiitumW5JLjSztNlX9Kxv1hrzW8,64
27
+ data_annotations-2.1.2.dist-info/METADATA,sha256=YFoVdX9RV6sVNRIIQo7f-XyrB6vRNT19wsPbM3kN1KI,19791
28
+ data_annotations-2.1.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.11.8
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ data-annotations = data_annotations.cli:main
3
+
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, CeDA, University of Basel
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.