runprov 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.
- runprov-0.1.0/.gitignore +46 -0
- runprov-0.1.0/.pre-commit-config.yaml +26 -0
- runprov-0.1.0/.ruff.toml +79 -0
- runprov-0.1.0/CHANGELOG.md +732 -0
- runprov-0.1.0/CITATION.cff +95 -0
- runprov-0.1.0/CODE_OF_CONDUCT.md +57 -0
- runprov-0.1.0/CONTRIBUTING.md +179 -0
- runprov-0.1.0/DCO.txt +34 -0
- runprov-0.1.0/GETTING-STARTED.md +520 -0
- runprov-0.1.0/LICENSE +28 -0
- runprov-0.1.0/PKG-INFO +142 -0
- runprov-0.1.0/README-pypi.md +105 -0
- runprov-0.1.0/README.md +2276 -0
- runprov-0.1.0/SECURITY.md +68 -0
- runprov-0.1.0/WHY.md +552 -0
- runprov-0.1.0/ci.py +496 -0
- runprov-0.1.0/docs/adr/0001-provenance-layout-and-overrides.md +114 -0
- runprov-0.1.0/docs/adr/0002-detecting-unregistered-reads.md +141 -0
- runprov-0.1.0/docs/adr/0003-a-module-all-ratifies-it-does-not-decide.md +92 -0
- runprov-0.1.0/docs/adr/0004-a-pin-states-what-it-covers.md +130 -0
- runprov-0.1.0/docs/adr/0005-a-record-is-written-whole-or-not-at-all.md +123 -0
- runprov-0.1.0/docs/adr/0006-an-artifact-answers-for-itself.md +93 -0
- runprov-0.1.0/docs/adr/0007-the-gate-passes-the-exit-code-through.md +75 -0
- runprov-0.1.0/docs/adr/0008-capture-observes-what-declaration-cannot-reach.md +75 -0
- runprov-0.1.0/docs/adr/0009-export-is-a-derived-view-in-two-vocabularies.md +76 -0
- runprov-0.1.0/docs/adr/0010-a-record-states-what-it-was-able-to-observe.md +155 -0
- runprov-0.1.0/docs/adr/README.md +39 -0
- runprov-0.1.0/docs/public-surface.txt +82 -0
- runprov-0.1.0/examples/.gitignore +2 -0
- runprov-0.1.0/examples/data/measurements.tsv +5 -0
- runprov-0.1.0/examples/format_compatibility.py +1117 -0
- runprov-0.1.0/examples/summarise.py +91 -0
- runprov-0.1.0/pyproject.toml +226 -0
- runprov-0.1.0/runprov/__init__.py +189 -0
- runprov-0.1.0/runprov/__main__.py +1816 -0
- runprov-0.1.0/runprov/_atomic.py +180 -0
- runprov-0.1.0/runprov/_report.py +126 -0
- runprov-0.1.0/runprov/environment.py +409 -0
- runprov-0.1.0/runprov/export.py +258 -0
- runprov-0.1.0/runprov/hashing.py +639 -0
- runprov-0.1.0/runprov/project.py +703 -0
- runprov-0.1.0/runprov/prune.py +277 -0
- runprov-0.1.0/runprov/py.typed +0 -0
- runprov-0.1.0/runprov/run.py +3309 -0
- runprov-0.1.0/runprov/show.py +1089 -0
- runprov-0.1.0/runprov/sinks.py +309 -0
- runprov-0.1.0/runprov/terminal.py +512 -0
- runprov-0.1.0/runprov/verify.py +742 -0
- runprov-0.1.0/runprov/watch.py +277 -0
- runprov-0.1.0/tests/fixtures/README.md +59 -0
- runprov-0.1.0/tests/fixtures/artifact_v1.tsv +8 -0
- runprov-0.1.0/tests/fixtures/history_v1.jsonl +2 -0
- runprov-0.1.0/tests/fixtures/history_v2_then_v1.jsonl +2 -0
- runprov-0.1.0/tests/test_runprov.py +19813 -0
- runprov-0.1.0/tools/torture.py +558 -0
runprov-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# A provenance tool whose own repository tracks a stale coverage database is a poor
|
|
2
|
+
# advertisement. `.coverage` was committed until 2026-08-11.
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
.coverage
|
|
6
|
+
.coverage.*
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.mypy_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
dist/
|
|
11
|
+
build/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.venv/
|
|
14
|
+
|
|
15
|
+
# Written by running `examples/summarise.py` from the repository. The example configures
|
|
16
|
+
# the root as this repository, so its history lands here — which is the correct behaviour
|
|
17
|
+
# and not something to commit.
|
|
18
|
+
/provenance/
|
|
19
|
+
examples/results/
|
|
20
|
+
|
|
21
|
+
# THE TWO INTERNAL DRAFTS, untracked 2026-09-08 when the repository went public.
|
|
22
|
+
#
|
|
23
|
+
# L-08 had already kept `PUBLISHING.md` and `LICENSING.md` out of the sdist and off the
|
|
24
|
+
# README, on the grounds that they address one person and keep superseded reasoning on
|
|
25
|
+
# purpose. A private repository made that enough. A public one does not: below their
|
|
26
|
+
# "SUPERSEDED IN PART" banners they still recommend MIT with the CHU as holder, which is
|
|
27
|
+
# neither the licence nor the rights holder the source headers assert — and the DRCI has
|
|
28
|
+
# not yet answered which is correct. A reader following the repository link from the letter
|
|
29
|
+
# that asks that question would find the project appearing to answer it two ways.
|
|
30
|
+
#
|
|
31
|
+
# They stay on disk because the reasoning in them is worth having; they are simply not the
|
|
32
|
+
# project's public position. Untracking is not deleting, and it does not remove them from
|
|
33
|
+
# history — that would need a rewrite.
|
|
34
|
+
/LICENSING.md
|
|
35
|
+
/PUBLISHING.md
|
|
36
|
+
|
|
37
|
+
# AGENT WORKING STATE. `.claude/` is a tool's scratch directory, and it was NOT ignored — it
|
|
38
|
+
# happens to be empty, so nothing has leaked, but a `git add -A` would have committed whatever
|
|
39
|
+
# it contained into a public repository. That is the shape of the incident this file's first
|
|
40
|
+
# rule records: a swap file committed by the initial `git add -A`, holding text that had been
|
|
41
|
+
# written and deliberately cut.
|
|
42
|
+
#
|
|
43
|
+
# Worse here than a swap file, because the repository is public and the directory can hold
|
|
44
|
+
# session transcripts, worktrees and prompts. Nothing belongs in the project's history that
|
|
45
|
+
# nobody chose to put there.
|
|
46
|
+
/.claude/
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Same checks as CI, run locally. `pre-commit install` once, then a failing push is
|
|
2
|
+
# something you find in a second rather than in a queue.
|
|
3
|
+
repos:
|
|
4
|
+
# PINNED TO THE VERSION THE GATE ENFORCES, and it has to stay that way. This said v0.6.9
|
|
5
|
+
# against a gate on 0.16.2 -- ten minor versions apart -- and with `--fix` that is worse
|
|
6
|
+
# than a version skew: the hook REWRITES code to satisfy an old ruff, then CI rejects it
|
|
7
|
+
# with the new one, so the tool that exists to catch a failure early creates one. There is
|
|
8
|
+
# a test asserting these two agree.
|
|
9
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
10
|
+
rev: v0.16.2
|
|
11
|
+
hooks:
|
|
12
|
+
- id: ruff
|
|
13
|
+
args: [--fix]
|
|
14
|
+
- id: ruff-format
|
|
15
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
16
|
+
rev: v4.6.0
|
|
17
|
+
hooks:
|
|
18
|
+
- id: end-of-file-fixer
|
|
19
|
+
- id: trailing-whitespace
|
|
20
|
+
- id: check-yaml
|
|
21
|
+
- id: check-toml
|
|
22
|
+
- id: check-added-large-files
|
|
23
|
+
# This package has no data files. Anything large is a mistake, and a provenance
|
|
24
|
+
# tool that ships someone's parquet by accident would be a poor advertisement.
|
|
25
|
+
args: [--maxkb=200]
|
|
26
|
+
- id: check-merge-conflict
|
runprov-0.1.0/.ruff.toml
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Ruff config for the runprov package, kept beside the code so it travels with it into the
|
|
2
|
+
# standalone repository. Ruff replaces black + isort + flake8: `ruff format` is
|
|
3
|
+
# black-compatible byte for byte, and the `I` rules ARE isort.
|
|
4
|
+
#
|
|
5
|
+
# target-version is py310, NOT the repository's py311. Without it, UP017 rewrites
|
|
6
|
+
# `dt.timezone.utc` to `dt.UTC` — an alias added in 3.11 — and the package silently stops
|
|
7
|
+
# importing on the oldest interpreter it claims to support. A linter that breaks your
|
|
8
|
+
# declared support floor is worse than no linter.
|
|
9
|
+
line-length = 100
|
|
10
|
+
target-version = "py310"
|
|
11
|
+
|
|
12
|
+
[lint]
|
|
13
|
+
select = ["E", "F", "I", "N", "UP", "ANN", "S", "B", "C4", "PT", "RUF"]
|
|
14
|
+
|
|
15
|
+
# RUF003 flags an "ambiguous" EN DASH in a comment and suggests a hyphen. The comment is
|
|
16
|
+
# the copyright notice, and the en dash is part of "Assistance Publique – Hôpitaux de
|
|
17
|
+
# Paris" -- the institution's registered name. A linter does not get to respell a legal
|
|
18
|
+
# entity, and a copyright line that names the holder inexactly is worse than a lint
|
|
19
|
+
# warning. Ignored deliberately, everywhere, for that reason.
|
|
20
|
+
ignore = ["RUF003"]
|
|
21
|
+
|
|
22
|
+
[lint.per-file-ignores]
|
|
23
|
+
# project.py holds the ONE subprocess call in the package: `git`, resolved from PATH.
|
|
24
|
+
# S603 the argv is a literal program name plus the caller's own arguments, no shell.
|
|
25
|
+
# S607 `git` is deliberately taken from PATH. Pinning an absolute path would break
|
|
26
|
+
# every environment whose git is not where this machine's is, which is most.
|
|
27
|
+
# Scoped to the file rather than inline because `ruff format` moves which physical line a
|
|
28
|
+
# multi-line call reports on, and an inline noqa silently stops applying when it does.
|
|
29
|
+
"project.py" = ["S603", "S607"]
|
|
30
|
+
# `"__main__.py" = ["ANN401"]` used to sit here and suppressed NOTHING: that file has
|
|
31
|
+
# no `Any` annotation, and its stated reason ("main returns an int exit code and its
|
|
32
|
+
# locals are obvious") describes ANN201/ANN001, a different rule family. A per-file
|
|
33
|
+
# ignore that ignores nothing is the ADR-015 shape inside the linter's own config --
|
|
34
|
+
# a rule declared and not in effect. Removed rather than corrected: there was nothing
|
|
35
|
+
# to correct.
|
|
36
|
+
|
|
37
|
+
# Tests are not library code and linting them as if they were produces 198 findings that
|
|
38
|
+
# all say the same thing. What is switched off and why:
|
|
39
|
+
# S101 `assert` IS the test. Flagging it is the rule misapplied.
|
|
40
|
+
# ANN a test's arguments are fixtures and its return is None; annotating them adds
|
|
41
|
+
# nothing a reader did not already know.
|
|
42
|
+
# S108 /tmp paths in fixtures are the point.
|
|
43
|
+
# PT011 pytest.raises(Exception) is deliberate where the type IS the assertion.
|
|
44
|
+
# PT018 a compound assert is often the clearest statement of one fact.
|
|
45
|
+
# PT012 the crash tests need a `with Run(...)` INSIDE pytest.raises; that nesting is
|
|
46
|
+
# the behaviour under test, not sloppiness.
|
|
47
|
+
# RUF012 test doubles declare class attributes to imitate a real object's shape. The
|
|
48
|
+
# rule guards against shared mutable state across instances; a stub built and
|
|
49
|
+
# discarded inside one test has no instances to share anything with.
|
|
50
|
+
# S603/S607 the tests shell out to `git` to build a real repository to detect. That is
|
|
51
|
+
# the subject under test, not an injection risk.
|
|
52
|
+
# ci.py exists to run other tools; S603 is the rule describing its entire job. Scoped to
|
|
53
|
+
# the file, with the reason here, for the same reason as project.py: an inline directive
|
|
54
|
+
# detaches the next time the formatter moves the line it sits on.
|
|
55
|
+
# `run.py` and `__main__.py` each execute a program the CALLER named: `run.tool("samtools")`
|
|
56
|
+
# asks a binary for its version, and `runprov exec -- <cmd>` exists to run the command in
|
|
57
|
+
# front of it. S603 describes exactly what those two do on purpose, and there is no
|
|
58
|
+
# untrusted input to check -- the argv came from the person typing it. Scoped to the files
|
|
59
|
+
# rather than inline, for the reason given above project.py: `ruff format` moves which
|
|
60
|
+
# physical line a multi-line call reports on, and a detached noqa is a coincidence.
|
|
61
|
+
"run.py" = ["S603", "S607"]
|
|
62
|
+
"__main__.py" = ["S603"]
|
|
63
|
+
"ci.py" = ["S603"]
|
|
64
|
+
|
|
65
|
+
# `examples/` is teaching code that a reader copies, and it is linted as such. What is
|
|
66
|
+
# switched off and why:
|
|
67
|
+
# ANN an example annotated to library standards reads like library code, which is
|
|
68
|
+
# exactly the wrong signal for a file whose job is to show the shortest honest
|
|
69
|
+
# version of a call. `summarise.py` keeps its annotations; the format matrix is a
|
|
70
|
+
# table of lambdas where they would be noise.
|
|
71
|
+
# S301 `pickle.loads` IS the format under test in format_compatibility.py. The rule is
|
|
72
|
+
# about untrusted input; this input was written two lines earlier by the same file.
|
|
73
|
+
# S314 likewise `ElementTree.parse`, which is how you check an SVG is still well-formed.
|
|
74
|
+
# N802 `CASE(...)` is a table constructor, and shouting it is what makes the table
|
|
75
|
+
# readable as data rather than as calls.
|
|
76
|
+
"examples/*" = ["ANN", "S301", "S314", "N802"]
|
|
77
|
+
|
|
78
|
+
"tests/*" = ["S101", "S105", "S106", "S108", "ANN", "PT011", "PT012", "PT018", "RUF012", "S603", "S607",
|
|
79
|
+
"N802"]
|