cleverly 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.
- cleverly-0.1.0/.codex/config.toml +2 -0
- cleverly-0.1.0/.gitattributes +15 -0
- cleverly-0.1.0/.github/actions/setup-env/action.yml +58 -0
- cleverly-0.1.0/.github/pull_request_template.md +23 -0
- cleverly-0.1.0/.github/workflows/ci.yml +143 -0
- cleverly-0.1.0/.github/workflows/pages.yml +45 -0
- cleverly-0.1.0/.github/workflows/publish.yml +81 -0
- cleverly-0.1.0/.github/workflows/validation.yml +39 -0
- cleverly-0.1.0/.gitignore +20 -0
- cleverly-0.1.0/AGENTS.md +3 -0
- cleverly-0.1.0/CLAUDE.md +113 -0
- cleverly-0.1.0/CONTRIBUTING.md +60 -0
- cleverly-0.1.0/LICENSE +21 -0
- cleverly-0.1.0/PKG-INFO +257 -0
- cleverly-0.1.0/README.md +195 -0
- cleverly-0.1.0/docs/README.md +46 -0
- cleverly-0.1.0/docs/_static/custom.css +382 -0
- cleverly-0.1.0/docs/_static/custom.js +514 -0
- cleverly-0.1.0/docs/_templates/autosummary/class.rst +29 -0
- cleverly-0.1.0/docs/api/datasets.md +31 -0
- cleverly-0.1.0/docs/api/estimands.md +28 -0
- cleverly-0.1.0/docs/api/exceptions.md +22 -0
- cleverly-0.1.0/docs/api/index.md +24 -0
- cleverly-0.1.0/docs/api/interventions.md +26 -0
- cleverly-0.1.0/docs/api/learners.md +22 -0
- cleverly-0.1.0/docs/api/methods.md +20 -0
- cleverly-0.1.0/docs/api/object-index.rst +160 -0
- cleverly-0.1.0/docs/api/results-assessment.md +34 -0
- cleverly-0.1.0/docs/api/sensitivity-validation.md +72 -0
- cleverly-0.1.0/docs/api/study-design.md +21 -0
- cleverly-0.1.0/docs/architecture-invariants.md +320 -0
- cleverly-0.1.0/docs/conf.py +117 -0
- cleverly-0.1.0/docs/development/contributing.md +176 -0
- cleverly-0.1.0/docs/development/index.md +23 -0
- cleverly-0.1.0/docs/development/method-benchmarking.md +250 -0
- cleverly-0.1.0/docs/development/pull-requests.md +123 -0
- cleverly-0.1.0/docs/development/releases.md +77 -0
- cleverly-0.1.0/docs/development/testing-strategy.md +163 -0
- cleverly-0.1.0/docs/examples/collaborative-tmle.md +278 -0
- cleverly-0.1.0/docs/examples/cross-fitting.md +346 -0
- cleverly-0.1.0/docs/examples/dr-tmle.md +241 -0
- cleverly-0.1.0/docs/examples/index.md +93 -0
- cleverly-0.1.0/docs/examples/interventions.md +311 -0
- cleverly-0.1.0/docs/examples/longitudinal-survival.md +312 -0
- cleverly-0.1.0/docs/examples/longitudinal-tmle.md +348 -0
- cleverly-0.1.0/docs/examples/msm-projections.md +276 -0
- cleverly-0.1.0/docs/examples/point-treatment-tmle.md +440 -0
- cleverly-0.1.0/docs/examples/survey-nonresponse.md +346 -0
- cleverly-0.1.0/docs/examples/twins-causal-inference.ipynb +1628 -0
- cleverly-0.1.0/docs/getting-started/index.md +16 -0
- cleverly-0.1.0/docs/getting-started/installation.md +68 -0
- cleverly-0.1.0/docs/getting-started/quickstart.md +73 -0
- cleverly-0.1.0/docs/index.md +142 -0
- cleverly-0.1.0/docs/references.md +346 -0
- cleverly-0.1.0/docs/roadmap.md +501 -0
- cleverly-0.1.0/docs/technical-reference/collaborative-tmle.md +132 -0
- cleverly-0.1.0/docs/technical-reference/cv-tmle.md +146 -0
- cleverly-0.1.0/docs/technical-reference/dr-tmle/diagnostics.md +80 -0
- cleverly-0.1.0/docs/technical-reference/dr-tmle/index.md +224 -0
- cleverly-0.1.0/docs/technical-reference/dr-tmle/nuisance-conditions.md +37 -0
- cleverly-0.1.0/docs/technical-reference/dr-tmle/supported-estimands.md +111 -0
- cleverly-0.1.0/docs/technical-reference/dr-tmle/targeting.md +280 -0
- cleverly-0.1.0/docs/technical-reference/dr-tmle/theorem.md +256 -0
- cleverly-0.1.0/docs/technical-reference/dr-tmle/validation-programme.md +45 -0
- cleverly-0.1.0/docs/technical-reference/evidence.md +315 -0
- cleverly-0.1.0/docs/technical-reference/index.md +63 -0
- cleverly-0.1.0/docs/technical-reference/inference.md +103 -0
- cleverly-0.1.0/docs/technical-reference/longitudinal-tmle.md +264 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/canonical-dr-tmle.md +247 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/canonical-point-treatment-tmle.md +234 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/clustered-point-treatment-cv-tmle.md +136 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/continuous-modified-treatment-policies.md +135 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/controlled-direct-effect-tmle.md +200 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/cross-fitted-categorical-longitudinal-tmle.md +189 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/cross-fitted-competing-risk-longitudinal-tmle.md +225 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/cross-fitted-end-of-study-longitudinal-tmle.md +213 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/cross-fitted-survival-curve-longitudinal-tmle.md +233 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/cross-fitted-weighted-end-of-study-longitudinal-tmle.md +198 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/deterministic-point-treatment-regimes.md +112 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/fold-evaluated-point-treatment-cv-tmle.md +157 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/fold-targeted-point-treatment-cv-tmle.md +156 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/how-to-read.md +97 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/incremental-propensity-interventions.md +132 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/index.md +59 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/learned-weighted-point-treatment-tmle.md +167 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/multi-arm-dr-tmle.md +150 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/ordinary-categorical-longitudinal-tmle.md +183 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/ordinary-competing-risk-longitudinal-tmle.md +215 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/ordinary-end-of-study-longitudinal-tmle.md +202 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/ordinary-longitudinal-msm-projection.md +140 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/ordinary-missing-outcome-tmle.md +133 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/ordinary-multi-arm-tmle.md +121 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/ordinary-survival-curve-longitudinal-tmle.md +254 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/ordinary-weighted-end-of-study-longitudinal-tmle.md +193 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/outcome-adaptive-multi-arm-c-tmle.md +124 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/outcome-adaptive-point-treatment-c-tmle.md +184 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/point-treatment-msm-projection.md +154 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/randomized-missing-outcome-dr-tmle.md +129 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/repeated-cross-fitting.md +164 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/selector-based-multi-arm-c-tmle.md +130 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/selector-based-point-treatment-c-tmle.md +159 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/stacked-point-treatment-cv-tmle.md +207 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/stochastic-point-treatment-regimes.md +123 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/validation-grid.md +66 -0
- cleverly-0.1.0/docs/technical-reference/method-evidence/weighted-point-treatment-tmle.md +175 -0
- cleverly-0.1.0/docs/technical-reference/msm-projections.md +181 -0
- cleverly-0.1.0/docs/technical-reference/point-treatment-tmle.md +308 -0
- cleverly-0.1.0/docs/technical-reference/scope-and-refusals.md +134 -0
- cleverly-0.1.0/docs/technical-reference/validation-methods.md +515 -0
- cleverly-0.1.0/docs/user-guide/capabilities.md +45 -0
- cleverly-0.1.0/docs/user-guide/data-design.md +78 -0
- cleverly-0.1.0/docs/user-guide/estimands.md +120 -0
- cleverly-0.1.0/docs/user-guide/index.md +29 -0
- cleverly-0.1.0/docs/user-guide/longitudinal.md +101 -0
- cleverly-0.1.0/docs/user-guide/methods-learners.md +129 -0
- cleverly-0.1.0/docs/user-guide/results-assessment.md +182 -0
- cleverly-0.1.0/docs/workflow.md +110 -0
- cleverly-0.1.0/noxfile.py +110 -0
- cleverly-0.1.0/pyproject.toml +167 -0
- cleverly-0.1.0/scripts/check_distribution.py +77 -0
- cleverly-0.1.0/scripts/check_release.py +41 -0
- cleverly-0.1.0/scripts/execute_notebook.py +48 -0
- cleverly-0.1.0/scripts/smoke_backend.py +103 -0
- cleverly-0.1.0/src/cleverly/__init__.py +162 -0
- cleverly-0.1.0/src/cleverly/_typing.py +121 -0
- cleverly-0.1.0/src/cleverly/_version.py +5 -0
- cleverly-0.1.0/src/cleverly/assessment.py +2324 -0
- cleverly-0.1.0/src/cleverly/data/__init__.py +8 -0
- cleverly-0.1.0/src/cleverly/data/causal_data.py +1249 -0
- cleverly-0.1.0/src/cleverly/data/validate.py +453 -0
- cleverly-0.1.0/src/cleverly/data/weighting.py +627 -0
- cleverly-0.1.0/src/cleverly/datasets/__init__.py +97 -0
- cleverly-0.1.0/src/cleverly/datasets/longitudinal.py +894 -0
- cleverly-0.1.0/src/cleverly/datasets/synthetic.py +1708 -0
- cleverly-0.1.0/src/cleverly/estimators/__init__.py +43 -0
- cleverly-0.1.0/src/cleverly/estimators/_nuisance.py +1320 -0
- cleverly-0.1.0/src/cleverly/estimators/base.py +1233 -0
- cleverly-0.1.0/src/cleverly/estimators/ctmle.py +1461 -0
- cleverly-0.1.0/src/cleverly/estimators/direct_effect.py +387 -0
- cleverly-0.1.0/src/cleverly/estimators/drtmle.py +996 -0
- cleverly-0.1.0/src/cleverly/estimators/reduced.py +964 -0
- cleverly-0.1.0/src/cleverly/estimators/serialize.py +99 -0
- cleverly-0.1.0/src/cleverly/estimators/targeting.py +2610 -0
- cleverly-0.1.0/src/cleverly/estimators/tmle.py +2809 -0
- cleverly-0.1.0/src/cleverly/exceptions.py +108 -0
- cleverly-0.1.0/src/cleverly/fluctuation/__init__.py +74 -0
- cleverly-0.1.0/src/cleverly/fluctuation/_score.py +72 -0
- cleverly-0.1.0/src/cleverly/fluctuation/iterative.py +820 -0
- cleverly-0.1.0/src/cleverly/fluctuation/mechanism.py +641 -0
- cleverly-0.1.0/src/cleverly/fluctuation/one_step.py +176 -0
- cleverly-0.1.0/src/cleverly/fluctuation/reduced.py +273 -0
- cleverly-0.1.0/src/cleverly/fluctuation/submodel.py +1362 -0
- cleverly-0.1.0/src/cleverly/inference/__init__.py +64 -0
- cleverly-0.1.0/src/cleverly/inference/bootstrap.py +305 -0
- cleverly-0.1.0/src/cleverly/inference/cluster.py +267 -0
- cleverly-0.1.0/src/cleverly/inference/delta.py +173 -0
- cleverly-0.1.0/src/cleverly/inference/influence.py +1449 -0
- cleverly-0.1.0/src/cleverly/inference/multiplier.py +471 -0
- cleverly-0.1.0/src/cleverly/inference/results.py +98 -0
- cleverly-0.1.0/src/cleverly/interventions/__init__.py +49 -0
- cleverly-0.1.0/src/cleverly/interventions/base.py +582 -0
- cleverly-0.1.0/src/cleverly/interventions/incremental.py +564 -0
- cleverly-0.1.0/src/cleverly/interventions/shift.py +558 -0
- cleverly-0.1.0/src/cleverly/interventions/support.py +238 -0
- cleverly-0.1.0/src/cleverly/learners/__init__.py +61 -0
- cleverly-0.1.0/src/cleverly/learners/_fitting.py +256 -0
- cleverly-0.1.0/src/cleverly/learners/_threads.py +322 -0
- cleverly-0.1.0/src/cleverly/learners/crossfit.py +520 -0
- cleverly-0.1.0/src/cleverly/learners/density.py +507 -0
- cleverly-0.1.0/src/cleverly/learners/library.py +153 -0
- cleverly-0.1.0/src/cleverly/learners/screeners.py +170 -0
- cleverly-0.1.0/src/cleverly/learners/super_learner.py +631 -0
- cleverly-0.1.0/src/cleverly/longitudinal/__init__.py +69 -0
- cleverly-0.1.0/src/cleverly/longitudinal/data.py +1378 -0
- cleverly-0.1.0/src/cleverly/longitudinal/estimator.py +1701 -0
- cleverly-0.1.0/src/cleverly/longitudinal/msm.py +1069 -0
- cleverly-0.1.0/src/cleverly/longitudinal/regimen.py +346 -0
- cleverly-0.1.0/src/cleverly/longitudinal/sequential.py +1261 -0
- cleverly-0.1.0/src/cleverly/methods.py +866 -0
- cleverly-0.1.0/src/cleverly/msm.py +1029 -0
- cleverly-0.1.0/src/cleverly/provenance.py +232 -0
- cleverly-0.1.0/src/cleverly/py.typed +0 -0
- cleverly-0.1.0/src/cleverly/sensitivity/__init__.py +39 -0
- cleverly-0.1.0/src/cleverly/sensitivity/_parameters.py +188 -0
- cleverly-0.1.0/src/cleverly/sensitivity/evalue.py +321 -0
- cleverly-0.1.0/src/cleverly/sensitivity/missingness.py +392 -0
- cleverly-0.1.0/src/cleverly/sensitivity/omitted_variable.py +883 -0
- cleverly-0.1.0/src/cleverly/sensitivity/positivity.py +839 -0
- cleverly-0.1.0/src/cleverly/study.py +2071 -0
- cleverly-0.1.0/src/cleverly/targets/__init__.py +240 -0
- cleverly-0.1.0/src/cleverly/targets/base.py +484 -0
- cleverly-0.1.0/src/cleverly/targets/builtin.py +637 -0
- cleverly-0.1.0/src/cleverly/utils/__init__.py +31 -0
- cleverly-0.1.0/src/cleverly/utils/bounds.py +272 -0
- cleverly-0.1.0/src/cleverly/utils/frames.py +195 -0
- cleverly-0.1.0/src/cleverly/utils/parallel.py +52 -0
- cleverly-0.1.0/src/cleverly/utils/phases.py +300 -0
- cleverly-0.1.0/src/cleverly/utils/records.py +101 -0
- cleverly-0.1.0/src/cleverly/utils/text.py +49 -0
- cleverly-0.1.0/src/cleverly/validation/__init__.py +70 -0
- cleverly-0.1.0/src/cleverly/validation/drtmle.py +840 -0
- cleverly-0.1.0/src/cleverly/validation/nuisance.py +555 -0
- cleverly-0.1.0/src/cleverly/validation/refute.py +1743 -0
- cleverly-0.1.0/src/cleverly/validation/score.py +745 -0
- cleverly-0.1.0/src/cleverly/validation/simulation.py +650 -0
- cleverly-0.1.0/src/cleverly/variable_importance.py +240 -0
- cleverly-0.1.0/uv.lock +3110 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# A checkout must produce the same bytes on every platform, because some of these
|
|
2
|
+
# bytes are hashed. `tests/studies/evidence/manifest.py` records a sha256 over each
|
|
3
|
+
# published study artifact and `tests/unit/test_method_evidence.py` checks it, so a
|
|
4
|
+
# line ending rewritten at checkout time turns a provenance claim into a statement
|
|
5
|
+
# about the machine that ran `git clone`. Without this file and with the common
|
|
6
|
+
# `core.autocrlf=true`, the canonical TMLE and CV-TMLE manifests verified on Windows
|
|
7
|
+
# and failed on Linux CI, which is the one thing a byte-exact claim must not do.
|
|
8
|
+
#
|
|
9
|
+
# `text=auto` still lets git detect binary content; `eol=lf` fixes the working-tree
|
|
10
|
+
# ending for everything it does classify as text. The compressed replicate archives
|
|
11
|
+
# are marked explicitly rather than left to detection, since they are the artifacts
|
|
12
|
+
# whose bytes matter most and a misdetection there would corrupt them silently.
|
|
13
|
+
* text=auto eol=lf
|
|
14
|
+
|
|
15
|
+
*.gz binary
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Set up cleverly's environment
|
|
2
|
+
description: >-
|
|
3
|
+
uv, a pinned interpreter, a virtual environment on PATH, and the package installed
|
|
4
|
+
editable from the committed lock. Jobs that need a working cleverly do this identically.
|
|
5
|
+
|
|
6
|
+
inputs:
|
|
7
|
+
python-version:
|
|
8
|
+
description: The interpreter to install and build the virtual environment against.
|
|
9
|
+
required: true
|
|
10
|
+
extra:
|
|
11
|
+
description: Which optional-dependency group to install; "dev" for anything running pytest.
|
|
12
|
+
required: false
|
|
13
|
+
default: dev
|
|
14
|
+
packages:
|
|
15
|
+
description: >-
|
|
16
|
+
Further requirements to install after the locked project, space-separated.
|
|
17
|
+
required: false
|
|
18
|
+
default: ""
|
|
19
|
+
|
|
20
|
+
runs:
|
|
21
|
+
using: composite
|
|
22
|
+
steps:
|
|
23
|
+
- uses: astral-sh/setup-uv@v5
|
|
24
|
+
|
|
25
|
+
- run: uv python install "${PYTHON_VERSION}"
|
|
26
|
+
shell: bash
|
|
27
|
+
env:
|
|
28
|
+
PYTHON_VERSION: ${{ inputs.python-version }}
|
|
29
|
+
|
|
30
|
+
# A virtual environment rather than `--system`, and the reason is not only that
|
|
31
|
+
# `--system` stopped working. `ubuntu-latest`'s Debian Python is marked externally
|
|
32
|
+
# managed (PEP 668), so `uv pip install --system` is now refused outright -- which
|
|
33
|
+
# turned every job in this repository except `lint` red, with no commit to blame, and
|
|
34
|
+
# kept them red while the merges went on. The manually dispatched workflows failed
|
|
35
|
+
# the same way and more quietly still: a run that dies at its install step reports a
|
|
36
|
+
# failed tier rather than a missing one.
|
|
37
|
+
#
|
|
38
|
+
# But `--system` was the wrong instrument even while it worked: it installs into
|
|
39
|
+
# whichever interpreter `/usr` holds, *not* the one `uv python install` just placed, so
|
|
40
|
+
# the version named and the version tested were only ever the same by accident. Doing
|
|
41
|
+
# it here makes them the same by construction, which is what `ci.yml`'s matrix needs.
|
|
42
|
+
- run: |
|
|
43
|
+
uv venv --python "${PYTHON_VERSION}"
|
|
44
|
+
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
|
|
45
|
+
shell: bash
|
|
46
|
+
env:
|
|
47
|
+
PYTHON_VERSION: ${{ inputs.python-version }}
|
|
48
|
+
|
|
49
|
+
- run: uv sync --locked --extra "${EXTRA}"
|
|
50
|
+
shell: bash
|
|
51
|
+
env:
|
|
52
|
+
EXTRA: ${{ inputs.extra }}
|
|
53
|
+
|
|
54
|
+
- if: ${{ inputs.packages != '' }}
|
|
55
|
+
run: uv pip install ${PACKAGES}
|
|
56
|
+
shell: bash
|
|
57
|
+
env:
|
|
58
|
+
PACKAGES: ${{ inputs.packages }}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!-- Guides: docs/development/contributing.md and docs/development/pull-requests.md -->
|
|
2
|
+
|
|
3
|
+
## What this changes
|
|
4
|
+
|
|
5
|
+
<!-- The claim this change makes, and the reason for it. Name the file to read first. -->
|
|
6
|
+
|
|
7
|
+
## Evidence
|
|
8
|
+
|
|
9
|
+
<!-- What moved, what stayed identical, and the gate you ran. For example:
|
|
10
|
+
pytest -m "not slow": 5081 passed, 113 skipped. -->
|
|
11
|
+
|
|
12
|
+
## Checks
|
|
13
|
+
|
|
14
|
+
- [ ] `ruff check .` and `ruff format --check .` pass
|
|
15
|
+
- [ ] `mypy` passes
|
|
16
|
+
- [ ] `pytest -m "not slow" -q` passes
|
|
17
|
+
- [ ] `python -m tests.prose` findings are fixed, or carry `accepted: <reason>` in `tests/prose-report.md`
|
|
18
|
+
- [ ] `nox -s docs` passes, if a document or a docstring changed
|
|
19
|
+
- [ ] `python -m build`, strict Twine validation, archive checks, and clean install checks pass
|
|
20
|
+
- [ ] regenerated artifacts carry matching manifest hashes and line-feed endings
|
|
21
|
+
|
|
22
|
+
<!-- CI runs all of these except the prose report. Running them locally first saves a round trip,
|
|
23
|
+
and `nox -s docs` is the slowest one to learn about from a runner. -->
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: ./.github/actions/setup-env
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
extra: dev
|
|
22
|
+
- run: ruff check .
|
|
23
|
+
- run: ruff format --check .
|
|
24
|
+
# Prose is not linted here. `tests/prose.py` reports on it and the fast tier gates the
|
|
25
|
+
# *report*: a finding with no recorded judgment fails, the prose itself never does. The
|
|
26
|
+
# reason is on record -- when the dash rule was a build error, the sweep that followed
|
|
27
|
+
# optimized for green and broke six sentences to satisfy it.
|
|
28
|
+
|
|
29
|
+
typecheck:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
# The install steps live in the composite action; it says why they are what they are.
|
|
34
|
+
# The interpreter matches `[tool.mypy]`'s `python_version`, which is `3.12` and says at
|
|
35
|
+
# length why it is not the `3.11` of `requires-python`: numpy's stubs use PEP 695 `type`
|
|
36
|
+
# statements, which a 3.11 target refuses to parse. Running the job on the interpreter it
|
|
37
|
+
# targets keeps the two from drifting apart silently. **3.11 is still supported and still
|
|
38
|
+
# tested**. The `tests` matrix below runs the fast tier on it.
|
|
39
|
+
- uses: ./.github/actions/setup-env
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.12"
|
|
42
|
+
extra: dev
|
|
43
|
+
- run: mypy
|
|
44
|
+
|
|
45
|
+
# The site that `pages.yml` deploys, built here before the merge rather than after it.
|
|
46
|
+
#
|
|
47
|
+
# This is not the removed documentation dispatch, and `docs/architecture-invariants.md` still
|
|
48
|
+
# rules that one out. That job re-ran what the fast tier already runs. This one covers what no
|
|
49
|
+
# fast test can see: numpydoc validation of every rendered docstring, a document that no
|
|
50
|
+
# toctree references, and a cross-reference Sphinx cannot resolve. `pages.yml` triggers on a
|
|
51
|
+
# push to `main`, so until now the first run of `-W` happened after the merge, and a broken
|
|
52
|
+
# docstring took the published site down rather than failing a pull request.
|
|
53
|
+
#
|
|
54
|
+
# 3.12 is the interpreter `pages.yml` deploys from, so this job answers the question that
|
|
55
|
+
# matters: does the site that will ship build clean. The `docs` extra is what that build needs,
|
|
56
|
+
# and this job is the one that installs it.
|
|
57
|
+
docs:
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
- uses: ./.github/actions/setup-env
|
|
62
|
+
with:
|
|
63
|
+
python-version: "3.12"
|
|
64
|
+
extra: docs
|
|
65
|
+
- run: sphinx-build -W --keep-going -b html docs docs/_build/html
|
|
66
|
+
|
|
67
|
+
tests:
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
strategy:
|
|
70
|
+
fail-fast: false
|
|
71
|
+
matrix:
|
|
72
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
73
|
+
steps:
|
|
74
|
+
- uses: actions/checkout@v4
|
|
75
|
+
# The matrix version is threaded through to `uv venv --python`; without that, every
|
|
76
|
+
# row of the matrix would install into `/usr`'s interpreter and exercise the same one.
|
|
77
|
+
- uses: ./.github/actions/setup-env
|
|
78
|
+
with:
|
|
79
|
+
python-version: ${{ matrix.python-version }}
|
|
80
|
+
# `-n auto` resolves through psutil, else `os.cpu_count()` -- neither of which reads a
|
|
81
|
+
# container's CFS quota, so on a quota-limited runner it asks for the *host's* cores.
|
|
82
|
+
# `tests.parallel` goes through joblib/loky, which does read it.
|
|
83
|
+
- name: Size the worker pool from the cores this job may actually use
|
|
84
|
+
run: |
|
|
85
|
+
echo "PYTEST_XDIST_AUTO_NUM_WORKERS=$(python -m tests.parallel --workers)" >> "$GITHUB_ENV"
|
|
86
|
+
python -m tests.parallel
|
|
87
|
+
# Behavioral examples belong in this fast unit/integration/e2e tier, and so do the
|
|
88
|
+
# static documentation checks -- links resolve, every `python` fence parses. Neither
|
|
89
|
+
# executes an example, and both are cheap, so there is no documentation dispatch.
|
|
90
|
+
- run: pytest -m "not slow" -q -n auto
|
|
91
|
+
|
|
92
|
+
# One backend at a time, which the `tests` job above cannot check: it installs `.[dev]`,
|
|
93
|
+
# which pulls pandas *and* polars, so the single-backend and neither-installed branches of
|
|
94
|
+
# `cleverly.utils.frames` had never executed anywhere. That is how `make_longitudinal_weighted`
|
|
95
|
+
# came to hard-code `backend="pandas"` and call `.loc` -- unusable on a polars-only install,
|
|
96
|
+
# and invisible to a suite that always had both.
|
|
97
|
+
#
|
|
98
|
+
# The test suite itself imports pandas and polars freely, so it cannot be the check here.
|
|
99
|
+
# What runs instead is the import and a fit end to end through the one backend present.
|
|
100
|
+
minimal-install:
|
|
101
|
+
runs-on: ubuntu-latest
|
|
102
|
+
strategy:
|
|
103
|
+
fail-fast: false
|
|
104
|
+
matrix:
|
|
105
|
+
backend: [pandas, polars]
|
|
106
|
+
steps:
|
|
107
|
+
- uses: actions/checkout@v4
|
|
108
|
+
- uses: ./.github/actions/setup-env
|
|
109
|
+
with:
|
|
110
|
+
python-version: "3.11"
|
|
111
|
+
extra: ${{ matrix.backend }}
|
|
112
|
+
- name: A fit, its reports and the generators, on one backend
|
|
113
|
+
run: python scripts/smoke_backend.py ${{ matrix.backend }}
|
|
114
|
+
|
|
115
|
+
package:
|
|
116
|
+
runs-on: ubuntu-latest
|
|
117
|
+
steps:
|
|
118
|
+
- uses: actions/checkout@v4
|
|
119
|
+
- uses: ./.github/actions/setup-env
|
|
120
|
+
with:
|
|
121
|
+
python-version: "3.12"
|
|
122
|
+
extra: dev
|
|
123
|
+
- name: Build the wheel and source distribution
|
|
124
|
+
run: python -m build
|
|
125
|
+
- name: Validate package metadata and archive contents
|
|
126
|
+
run: |
|
|
127
|
+
python -m twine check --strict dist/*
|
|
128
|
+
python scripts/check_distribution.py dist
|
|
129
|
+
- name: Install and exercise the wheel in a clean environment
|
|
130
|
+
run: |
|
|
131
|
+
uv venv --python 3.12 /tmp/cleverly-wheel
|
|
132
|
+
uv pip install --python /tmp/cleverly-wheel/bin/python pandas "$(find dist -name '*.whl')"
|
|
133
|
+
/tmp/cleverly-wheel/bin/python scripts/smoke_backend.py pandas
|
|
134
|
+
- name: Install and exercise the source distribution in a clean environment
|
|
135
|
+
run: |
|
|
136
|
+
uv venv --python 3.12 /tmp/cleverly-source
|
|
137
|
+
uv pip install --python /tmp/cleverly-source/bin/python polars "$(find dist -name '*.tar.gz')"
|
|
138
|
+
/tmp/cleverly-source/bin/python scripts/smoke_backend.py polars
|
|
139
|
+
- uses: actions/upload-artifact@v5
|
|
140
|
+
with:
|
|
141
|
+
name: distributions
|
|
142
|
+
path: dist/
|
|
143
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: pages
|
|
15
|
+
cancel-in-progress: false
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: astral-sh/setup-uv@v5
|
|
23
|
+
with:
|
|
24
|
+
enable-cache: true
|
|
25
|
+
- name: Install Python
|
|
26
|
+
run: uv python install 3.12
|
|
27
|
+
- name: Install documentation dependencies
|
|
28
|
+
run: uv sync --locked --extra docs
|
|
29
|
+
- name: Build documentation
|
|
30
|
+
run: uv run --no-sync sphinx-build -W --keep-going -b html docs docs/_build/html
|
|
31
|
+
- uses: actions/configure-pages@v5
|
|
32
|
+
- uses: actions/upload-pages-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
path: docs/_build/html
|
|
35
|
+
|
|
36
|
+
deploy:
|
|
37
|
+
environment:
|
|
38
|
+
name: github-pages
|
|
39
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
needs: build
|
|
42
|
+
steps:
|
|
43
|
+
- name: Deploy to GitHub Pages
|
|
44
|
+
id: deployment
|
|
45
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v0.1.*"]
|
|
6
|
+
|
|
7
|
+
permissions: {}
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
validate:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
- name: Match the tag, package version, and reviewed main history
|
|
20
|
+
run: |
|
|
21
|
+
python scripts/check_release.py "$GITHUB_REF_NAME"
|
|
22
|
+
git fetch --no-tags origin main
|
|
23
|
+
git merge-base --is-ancestor "$GITHUB_SHA" origin/main
|
|
24
|
+
|
|
25
|
+
build:
|
|
26
|
+
needs: validate
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
permissions:
|
|
29
|
+
contents: read
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v6
|
|
32
|
+
with:
|
|
33
|
+
persist-credentials: false
|
|
34
|
+
- uses: ./.github/actions/setup-env
|
|
35
|
+
with:
|
|
36
|
+
python-version: "3.12"
|
|
37
|
+
extra: dev
|
|
38
|
+
- run: python -m build
|
|
39
|
+
- run: python -m twine check --strict dist/*
|
|
40
|
+
- run: python scripts/check_distribution.py dist
|
|
41
|
+
- uses: actions/upload-artifact@v5
|
|
42
|
+
with:
|
|
43
|
+
name: release-distributions
|
|
44
|
+
path: dist/
|
|
45
|
+
if-no-files-found: error
|
|
46
|
+
|
|
47
|
+
publish-testpypi:
|
|
48
|
+
needs: build
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
environment:
|
|
51
|
+
name: testpypi
|
|
52
|
+
url: https://test.pypi.org/p/cleverly
|
|
53
|
+
permissions:
|
|
54
|
+
actions: read
|
|
55
|
+
id-token: write
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/download-artifact@v6
|
|
58
|
+
with:
|
|
59
|
+
name: release-distributions
|
|
60
|
+
path: dist/
|
|
61
|
+
# pypa/gh-action-pypi-publish v1.14.2 from the official upstream repository.
|
|
62
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33
|
|
63
|
+
with:
|
|
64
|
+
repository-url: https://test.pypi.org/legacy/
|
|
65
|
+
|
|
66
|
+
publish-pypi:
|
|
67
|
+
needs: publish-testpypi
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
environment:
|
|
70
|
+
name: pypi
|
|
71
|
+
url: https://pypi.org/p/cleverly
|
|
72
|
+
permissions:
|
|
73
|
+
actions: read
|
|
74
|
+
id-token: write
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/download-artifact@v6
|
|
77
|
+
with:
|
|
78
|
+
name: release-distributions
|
|
79
|
+
path: dist/
|
|
80
|
+
# pypa/gh-action-pypi-publish v1.14.2 from the official upstream repository.
|
|
81
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: manual-validation
|
|
2
|
+
|
|
3
|
+
# Statistical validation only. Documentation has no dispatch of its own on purpose: the
|
|
4
|
+
# links and example-syntax checks are ordinary fast-tier tests and the markdown formatter
|
|
5
|
+
# runs in `ci.yml`'s lint job, so a documentation suite here would re-run checks that
|
|
6
|
+
# already run unconditionally -- which reads as a separate gate while adding no coverage.
|
|
7
|
+
on:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
inputs:
|
|
10
|
+
selection:
|
|
11
|
+
description: Optional pytest node id; the whole evidence re-execution tier when empty
|
|
12
|
+
type: string
|
|
13
|
+
default: ""
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
validation:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
timeout-minutes: 360
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: ./.github/actions/setup-env
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
- name: Size the worker pool from the cores this job may actually use
|
|
28
|
+
run: |
|
|
29
|
+
echo "PYTEST_XDIST_AUTO_NUM_WORKERS=$(python -m tests.parallel --workers)" >> "$GITHUB_ENV"
|
|
30
|
+
python -m tests.parallel
|
|
31
|
+
- name: Statistical validation
|
|
32
|
+
env:
|
|
33
|
+
SELECTION: ${{ inputs.selection }}
|
|
34
|
+
run: |
|
|
35
|
+
if [ -n "$SELECTION" ]; then
|
|
36
|
+
pytest "$SELECTION" -q -n auto --durations=20
|
|
37
|
+
else
|
|
38
|
+
pytest -m slow -q -n auto --durations=20
|
|
39
|
+
fi
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
.nox/
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
.mypy_cache/
|
|
11
|
+
.ruff_cache/
|
|
12
|
+
.coverage
|
|
13
|
+
.claude/
|
|
14
|
+
htmlcov/
|
|
15
|
+
target/
|
|
16
|
+
docs/_build/
|
|
17
|
+
docs/api/generated/
|
|
18
|
+
|
|
19
|
+
# Where every canonical study's README sends a disposable regeneration.
|
|
20
|
+
.tmp/
|
cleverly-0.1.0/AGENTS.md
ADDED
cleverly-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Working on cleverly
|
|
2
|
+
|
|
3
|
+
`cleverly` is alpha software under heavy development. Treat the current architecture as
|
|
4
|
+
provisional: inspect the code and tests before changing it, and do not preserve an implementation
|
|
5
|
+
shape solely because this file once described it.
|
|
6
|
+
|
|
7
|
+
This file holds only the working agreements that no other file states and no test enforces.
|
|
8
|
+
Everything else is routed:
|
|
9
|
+
|
|
10
|
+
| for | read |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| setup, development commands, the public overview | `README.md` |
|
|
13
|
+
| making a change, and the checks it needs | `docs/development/contributing.md` |
|
|
14
|
+
| opening a pull request, and the commit style | `docs/development/pull-requests.md` |
|
|
15
|
+
| where technical documentation lives | `docs/README.md` |
|
|
16
|
+
| cross-module constraints not derivable from one implementation | `docs/architecture-invariants.md` |
|
|
17
|
+
| test tiers, and which deprecated studies no longer run | `docs/development/testing-strategy.md` |
|
|
18
|
+
| designing and registering a validation study | `docs/development/method-benchmarking.md` |
|
|
19
|
+
| which instrument covers which estimand | `docs/technical-reference/evidence.md` |
|
|
20
|
+
| what each shipped method was validated against | `docs/technical-reference/index.md` |
|
|
21
|
+
|
|
22
|
+
Current behavior is determined by code and tests, not by historical plans or investigation notes.
|
|
23
|
+
|
|
24
|
+
## Scientific changes
|
|
25
|
+
|
|
26
|
+
- Exact-law checks are blind to terms that vanish at the truth. When a sign, mask, guard, or
|
|
27
|
+
counterfactual block can disappear, add a nonzero witness or a deliberate-mutation control that
|
|
28
|
+
fails when that component is wrong.
|
|
29
|
+
- Refuse unsupported but well-posed compositions explicitly and explain what is missing. Do not
|
|
30
|
+
silently return a convenient approximation to a different estimand.
|
|
31
|
+
|
|
32
|
+
## Tests and tooling
|
|
33
|
+
|
|
34
|
+
- Read `docs/development/testing-strategy.md` before choosing a tier. The fast tier is the default
|
|
35
|
+
handoff gate. The repeated-sampling studies that predate the registered rows are deprecated
|
|
36
|
+
and skipped; do not re-enable one to justify a change. A shipped method is validated by its rows
|
|
37
|
+
in the implementation validation grid, which the fast tier recomputes from committed artifacts.
|
|
38
|
+
Nothing is contingent on `pytest -m slow` running.
|
|
39
|
+
- A refactor is not a reason to regenerate a study. The Python module hashes in a study's
|
|
40
|
+
`manifest.json` record the run; no test gates them, so cleaning shared code under
|
|
41
|
+
`tests/studies/evidence/` is free. The container and R-runner hashes *are* gated. Declare a
|
|
42
|
+
result-neutral edit in `tests/canonical/provenance-revisions.md` rather than rewriting a
|
|
43
|
+
recorded hash, which would leave the manifest describing bytes that never ran.
|
|
44
|
+
`docs/development/method-benchmarking.md` says how to tell the two kinds of change apart.
|
|
45
|
+
- Ruff and mypy are pinned once in `pyproject.toml`'s `dev` extra, which resolves to
|
|
46
|
+
`cleverly[all]` plus tooling. An optional extra kept out of `dev` *and* out of a dedicated CI job
|
|
47
|
+
is installed by no session, so its tests can only skip, and a skipped correctness check reads
|
|
48
|
+
exactly like a passing one. Put a new extra in `dev`, or give it a job that installs and runs its
|
|
49
|
+
tests.
|
|
50
|
+
- Ruff *formats* the Python examples in Markdown, so run it over the whole tree. Its linter does
|
|
51
|
+
not read Markdown at all, and the formatter skips any block it cannot parse. Neither one sees a
|
|
52
|
+
syntax error in an example.
|
|
53
|
+
- Follow `docs/development/pull-requests.md` when you prepare a handoff. It gives the commit
|
|
54
|
+
subject and body style, the evidence line the body carries, and what each CI job checks. The
|
|
55
|
+
`docs` job builds the site with `-W` on every pull request, so a docstring that numpydoc rejects
|
|
56
|
+
now fails the request rather than the deploy. Run `nox -s docs` before you hand off.
|
|
57
|
+
|
|
58
|
+
## Documentation writing
|
|
59
|
+
|
|
60
|
+
The root `README.md` and reader-facing documents under `docs/` align with Issue 9 of
|
|
61
|
+
ASD-STE100 Simplified Technical English. This project does not claim certified compliance.
|
|
62
|
+
|
|
63
|
+
- Write one idea per sentence. Keep sentences to 20 words in procedures and 25 in descriptions.
|
|
64
|
+
- Keep paragraphs to six sentences. Prefer three.
|
|
65
|
+
- Use the active voice, the present tense, and a named actor.
|
|
66
|
+
- Give the instruction first and the reason second.
|
|
67
|
+
- Use one word for one meaning, and do not use the same word as two parts of speech.
|
|
68
|
+
- Keep articles. Do not build a noun cluster longer than three words.
|
|
69
|
+
- Do not join clauses with an em dash or `--`. Use a full stop, or a table.
|
|
70
|
+
- When the content is parallel, write a table. In the technical reference the table is the primary
|
|
71
|
+
communication device and the prose exists to define its terms.
|
|
72
|
+
- Statistical terms of art are exempt from the vocabulary restriction: influence curve, nuisance,
|
|
73
|
+
targeting, remainder, estimand names, and any API identifier.
|
|
74
|
+
- Give evidence for each material claim. Cite the source, name the test or artifact, or state the
|
|
75
|
+
applicable condition. Remove adjectives and transitions that add no verifiable information.
|
|
76
|
+
|
|
77
|
+
When you change a reader-facing document, run `python -m tests.prose`, review every finding it
|
|
78
|
+
reports, and plan a fix that keeps the sentence whole. Where the standard should not apply, record
|
|
79
|
+
`accepted: <reason>` against that finding in `tests/prose-report.md`; that is a passing outcome and
|
|
80
|
+
the reason is the point. The fast tier fails on a finding nobody has judged, never on the prose
|
|
81
|
+
itself, because a mechanical edit that satisfies a rule and breaks a sentence is the failure this
|
|
82
|
+
report exists to prevent. No tool here certifies STE compliance or verifies a scientific claim.
|
|
83
|
+
Check those against the code, tests, artifacts, and sources.
|
|
84
|
+
|
|
85
|
+
Scope is `README.md` and every reader-facing Markdown, RST, or notebook source under `docs/`.
|
|
86
|
+
Generated API pages and `docs/_build/` are not source. Rewrite the text a change touches. Do not
|
|
87
|
+
sweep unrelated pages unless the user requests a broad documentation review.
|
|
88
|
+
|
|
89
|
+
## Docstrings
|
|
90
|
+
|
|
91
|
+
Docstrings are numpydoc, and `sphinx.ext.napoleon` is not installed. The loose `name:` form that
|
|
92
|
+
napoleon accepted is now a build error, because `pages.yml` builds with `-W` and `docs/conf.py`
|
|
93
|
+
enables `GL06, GL07, PR01, PR02, PR04, PR10, RT01`. Write `name : type` always, one entry per
|
|
94
|
+
parameter. Two names on one line become one parameter with a comma in its name.
|
|
95
|
+
|
|
96
|
+
- Document a frozen dataclass's fields under `Parameters`. numpydoc reads the generated signature,
|
|
97
|
+
so a field described only under `Attributes` reads as undocumented. Reserve `Attributes` for
|
|
98
|
+
derived properties.
|
|
99
|
+
- Give a property-backed attribute its name and type and no description. numpydoc renders the
|
|
100
|
+
property's own docstring over anything written there.
|
|
101
|
+
- Where a synthetic signature produces a finding nobody can fix, use the inline
|
|
102
|
+
`# numpydoc ignore=PR01` form on the definition line. Do not use `numpydoc_validation_exclude`,
|
|
103
|
+
which drops the object from every check rather than one.
|
|
104
|
+
- `Examples` and `See Also` are required on the task spine only, which
|
|
105
|
+
`tests/unit/test_documentation_api.py:EXAMPLE_TARGETS` declares. The targets include core
|
|
106
|
+
methods so a direct method anchor explains its own call. Every See Also entry carries a
|
|
107
|
+
description.
|
|
108
|
+
- Show the smallest normal use of the documented object or method. Start with the common case.
|
|
109
|
+
Include every import, use compact data, and check deterministic output. Do not use an example
|
|
110
|
+
to assert a statistical guarantee from one sample.
|
|
111
|
+
- An example must run in the fast tier without `doctest.SKIP`. Pass explicit learners to fits;
|
|
112
|
+
the default learner library costs 30 to 120 seconds per fit. Put expensive studies and extended
|
|
113
|
+
comparisons in narrative documentation and test them separately.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Contributing to cleverly
|
|
2
|
+
|
|
3
|
+
`cleverly` is alpha software for causal studies built on targeted maximum likelihood estimation.
|
|
4
|
+
One person maintains it, so a review can take several days. Open an issue before you start a large
|
|
5
|
+
change.
|
|
6
|
+
|
|
7
|
+
The full guides live in the documentation site.
|
|
8
|
+
|
|
9
|
+
| for | read |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| setup, branch names, the checks, documentation and docstring rules | [Contributing](https://esbraun.github.io/cleverly-tmle/development/contributing.html) |
|
|
12
|
+
| the commit style, the pull request body, what CI does and does not check | [Pull requests](https://esbraun.github.io/cleverly-tmle/development/pull-requests.html) |
|
|
13
|
+
| alpha versions, package checks, tags, and Trusted Publishing | [Releases](https://esbraun.github.io/cleverly-tmle/development/releases.html) |
|
|
14
|
+
| which tier a change has to satisfy | [Test tiers and gates](https://esbraun.github.io/cleverly-tmle/development/testing-strategy.html) |
|
|
15
|
+
| designing and registering a validation study | [Method benchmarking strategy](https://esbraun.github.io/cleverly-tmle/development/method-benchmarking.html) |
|
|
16
|
+
|
|
17
|
+
The sources are `docs/development/contributing.md` and `docs/development/pull-requests.md`.
|
|
18
|
+
|
|
19
|
+
## Set up
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git clone https://github.com/esbraun/cleverly-tmle.git
|
|
23
|
+
cd cleverly-tmle
|
|
24
|
+
uv venv
|
|
25
|
+
uv pip install -e ".[dev,docs]"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Run the checks
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
ruff check .
|
|
32
|
+
ruff format --check .
|
|
33
|
+
python -m tests.prose
|
|
34
|
+
mypy
|
|
35
|
+
pytest -m "not slow" -q
|
|
36
|
+
sphinx-build -W --keep-going -b html docs docs/_build/html
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`nox` with no argument runs the `lint`, `typecheck`, `docs`, and `tests` sessions, which mirror the
|
|
40
|
+
CI jobs. `nox -s docs` runs the last command in an isolated environment, which is what CI uses. Run
|
|
41
|
+
one test tier at a time, because each tier expects the whole machine.
|
|
42
|
+
|
|
43
|
+
`python -m tests.prose` reports on the reader-facing prose. It changes nothing and it fails
|
|
44
|
+
nothing. Fix each finding, or record `accepted: <reason>` against it in `tests/prose-report.md`.
|
|
45
|
+
The fast tier fails only on a finding with no recorded judgment.
|
|
46
|
+
|
|
47
|
+
## Working agreements
|
|
48
|
+
|
|
49
|
+
`CLAUDE.md` holds the working agreements that no other file states and no test enforces. Read it
|
|
50
|
+
before you change scientific code, documentation prose, or a docstring.
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
`cleverly` is under the [MIT License](LICENSE). Your contribution to the project is licensed
|
|
55
|
+
under the same terms.
|
|
56
|
+
|
|
57
|
+
One directory differs. `tests/canonical/` is under the
|
|
58
|
+
[GNU General Public License v3.0](tests/canonical/LICENSE), because its R runners call
|
|
59
|
+
reference packages in the same process. A contribution to that directory is licensed under
|
|
60
|
+
the GPL. No published distribution carries it.
|
cleverly-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eric Braun
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|