imperandi 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 (138) hide show
  1. imperandi-0.1.0/.gitattributes +1 -0
  2. imperandi-0.1.0/.githooks/pre-push +83 -0
  3. imperandi-0.1.0/.githooks/strip_notebook_outputs.py +63 -0
  4. imperandi-0.1.0/.github/workflows/release.yml +206 -0
  5. imperandi-0.1.0/.github/workflows/tests.yml +39 -0
  6. imperandi-0.1.0/.gitignore +230 -0
  7. imperandi-0.1.0/.readthedocs.yaml +16 -0
  8. imperandi-0.1.0/LICENSE +201 -0
  9. imperandi-0.1.0/PKG-INFO +449 -0
  10. imperandi-0.1.0/README.md +400 -0
  11. imperandi-0.1.0/dashboards/dicom_tags_snapshot_analysis.ipynb +543 -0
  12. imperandi-0.1.0/dashboards/interactive_viewer.ipynb +103 -0
  13. imperandi-0.1.0/dashboards/radiomics_descriptive_stats.ipynb +432 -0
  14. imperandi-0.1.0/dataset_configs/README.md +11 -0
  15. imperandi-0.1.0/dataset_configs/hooks/__init__.py +1 -0
  16. imperandi-0.1.0/dataset_configs/hooks/operandi.py +91 -0
  17. imperandi-0.1.0/dataset_configs/manifests/operandi.yaml +261 -0
  18. imperandi-0.1.0/docs/Makefile +20 -0
  19. imperandi-0.1.0/docs/README.md +9 -0
  20. imperandi-0.1.0/docs/make.bat +35 -0
  21. imperandi-0.1.0/docs/requirements.txt +4 -0
  22. imperandi-0.1.0/docs/source/api/extract.rst +17 -0
  23. imperandi-0.1.0/docs/source/api/imperandi.rst +14 -0
  24. imperandi-0.1.0/docs/source/api/ingest.rst +24 -0
  25. imperandi-0.1.0/docs/source/api/process.rst +17 -0
  26. imperandi-0.1.0/docs/source/api/qc.rst +24 -0
  27. imperandi-0.1.0/docs/source/cli.md +123 -0
  28. imperandi-0.1.0/docs/source/conf.py +64 -0
  29. imperandi-0.1.0/docs/source/index.rst +58 -0
  30. imperandi-0.1.0/docs/source/installation.md +79 -0
  31. imperandi-0.1.0/docs/source/manifests.md +274 -0
  32. imperandi-0.1.0/docs/source/outputs.md +53 -0
  33. imperandi-0.1.0/docs/source/quickstart.md +92 -0
  34. imperandi-0.1.0/docs/source/troubleshooting.md +77 -0
  35. imperandi-0.1.0/docs/source/workflow.md +161 -0
  36. imperandi-0.1.0/pyproject.toml +101 -0
  37. imperandi-0.1.0/setup.cfg +4 -0
  38. imperandi-0.1.0/src/imperandi/__init__.py +18 -0
  39. imperandi-0.1.0/src/imperandi/__main__.py +4 -0
  40. imperandi-0.1.0/src/imperandi/builtin_datasets_config/__init__.py +1 -0
  41. imperandi-0.1.0/src/imperandi/builtin_datasets_config/hooks/__init__.py +1 -0
  42. imperandi-0.1.0/src/imperandi/builtin_datasets_config/hooks/generic.py +30 -0
  43. imperandi-0.1.0/src/imperandi/builtin_datasets_config/manifests/blueprint_manifest_example.yaml +344 -0
  44. imperandi-0.1.0/src/imperandi/builtin_datasets_config/manifests/generic.yaml +252 -0
  45. imperandi-0.1.0/src/imperandi/cli.py +339 -0
  46. imperandi-0.1.0/src/imperandi/curation/__init__.py +115 -0
  47. imperandi-0.1.0/src/imperandi/curation/common.py +106 -0
  48. imperandi-0.1.0/src/imperandi/curation/ct/__init__.py +5 -0
  49. imperandi-0.1.0/src/imperandi/curation/ct/curate.py +201 -0
  50. imperandi-0.1.0/src/imperandi/curation/ct/rules.py +38 -0
  51. imperandi-0.1.0/src/imperandi/curation/mri/__init__.py +5 -0
  52. imperandi-0.1.0/src/imperandi/curation/mri/curate.py +1929 -0
  53. imperandi-0.1.0/src/imperandi/curation/mri/rules.py +232 -0
  54. imperandi-0.1.0/src/imperandi/curation/phase.py +414 -0
  55. imperandi-0.1.0/src/imperandi/extract/phase.py +450 -0
  56. imperandi-0.1.0/src/imperandi/extract/radiomics.py +1027 -0
  57. imperandi-0.1.0/src/imperandi/ingest/apply_hook_manifests.py +107 -0
  58. imperandi-0.1.0/src/imperandi/ingest/clean.py +2501 -0
  59. imperandi-0.1.0/src/imperandi/ingest/defaults.py +111 -0
  60. imperandi-0.1.0/src/imperandi/ingest/hooks.py +114 -0
  61. imperandi-0.1.0/src/imperandi/ingest/parse.py +1512 -0
  62. imperandi-0.1.0/src/imperandi/process/convert.py +759 -0
  63. imperandi-0.1.0/src/imperandi/process/registration/_legacy_register.py +1265 -0
  64. imperandi-0.1.0/src/imperandi/process/segment.py +1904 -0
  65. imperandi-0.1.0/src/imperandi/qc/viewer.py +1543 -0
  66. imperandi-0.1.0/src/imperandi/qc/viewer_resample.py +64 -0
  67. imperandi-0.1.0/src/imperandi/qc/viewer_web.py +1280 -0
  68. imperandi-0.1.0/src/imperandi/qc/viewer_web_data.py +295 -0
  69. imperandi-0.1.0/src/imperandi/qc/viewer_windowing.py +36 -0
  70. imperandi-0.1.0/src/imperandi/utils/__init__.py +20 -0
  71. imperandi-0.1.0/src/imperandi/utils/archive_io.py +496 -0
  72. imperandi-0.1.0/src/imperandi/utils/checkpoint_cli.py +49 -0
  73. imperandi-0.1.0/src/imperandi/utils/datetime.py +309 -0
  74. imperandi-0.1.0/src/imperandi/utils/files.py +119 -0
  75. imperandi-0.1.0/src/imperandi/utils/geometry.py +105 -0
  76. imperandi-0.1.0/src/imperandi/utils/logging.py +122 -0
  77. imperandi-0.1.0/src/imperandi/utils/manifest.py +82 -0
  78. imperandi-0.1.0/src/imperandi/utils/misc.py +154 -0
  79. imperandi-0.1.0/src/imperandi/utils/multiprocessing.py +357 -0
  80. imperandi-0.1.0/src/imperandi/utils/run_state.py +464 -0
  81. imperandi-0.1.0/src/imperandi.egg-info/PKG-INFO +449 -0
  82. imperandi-0.1.0/src/imperandi.egg-info/SOURCES.txt +136 -0
  83. imperandi-0.1.0/src/imperandi.egg-info/dependency_links.txt +1 -0
  84. imperandi-0.1.0/src/imperandi.egg-info/entry_points.txt +2 -0
  85. imperandi-0.1.0/src/imperandi.egg-info/requires.txt +39 -0
  86. imperandi-0.1.0/src/imperandi.egg-info/scm_file_list.json +132 -0
  87. imperandi-0.1.0/src/imperandi.egg-info/scm_version.json +8 -0
  88. imperandi-0.1.0/src/imperandi.egg-info/top_level.txt +1 -0
  89. imperandi-0.1.0/static/imperandi-logo.png +0 -0
  90. imperandi-0.1.0/static/viewer-demo.png +0 -0
  91. imperandi-0.1.0/static/viewer-demo_old.png +0 -0
  92. imperandi-0.1.0/tests/__init__.py +1 -0
  93. imperandi-0.1.0/tests/conftest.py +12 -0
  94. imperandi-0.1.0/tests/slow/README.md +31 -0
  95. imperandi-0.1.0/tests/slow/__init__.py +1 -0
  96. imperandi-0.1.0/tests/slow/assertions.py +37 -0
  97. imperandi-0.1.0/tests/slow/conftest.py +31 -0
  98. imperandi-0.1.0/tests/slow/ircad/README.md +36 -0
  99. imperandi-0.1.0/tests/slow/ircad/__init__.py +1 -0
  100. imperandi-0.1.0/tests/slow/ircad/data/README.md +4 -0
  101. imperandi-0.1.0/tests/slow/ircad/download.py +97 -0
  102. imperandi-0.1.0/tests/slow/ircad/pipeline.ps1 +59 -0
  103. imperandi-0.1.0/tests/slow/ircad/pipeline.sh +55 -0
  104. imperandi-0.1.0/tests/slow/ircad/test_pipeline.py +44 -0
  105. imperandi-0.1.0/tests/slow/run_pipeline.py +123 -0
  106. imperandi-0.1.0/tests/slow/tcga_lihc/README.md +32 -0
  107. imperandi-0.1.0/tests/slow/tcga_lihc/__init__.py +1 -0
  108. imperandi-0.1.0/tests/slow/tcga_lihc/data/README.md +4 -0
  109. imperandi-0.1.0/tests/slow/tcga_lihc/download.py +85 -0
  110. imperandi-0.1.0/tests/slow/tcga_lihc/pipeline.ps1 +59 -0
  111. imperandi-0.1.0/tests/slow/tcga_lihc/pipeline.sh +55 -0
  112. imperandi-0.1.0/tests/slow/tcga_lihc/test_pipeline.py +44 -0
  113. imperandi-0.1.0/tests/unit/curation/ct/test_ct_curation.py +129 -0
  114. imperandi-0.1.0/tests/unit/curation/mri/test_dixon_classification.py +151 -0
  115. imperandi-0.1.0/tests/unit/curation/mri/test_mri_curation.py +1269 -0
  116. imperandi-0.1.0/tests/unit/curation/mri/test_volume_order_features.py +114 -0
  117. imperandi-0.1.0/tests/unit/curation/test_phase_curation.py +215 -0
  118. imperandi-0.1.0/tests/unit/curation/test_router.py +45 -0
  119. imperandi-0.1.0/tests/unit/test_archive_io.py +341 -0
  120. imperandi-0.1.0/tests/unit/test_clean.py +1369 -0
  121. imperandi-0.1.0/tests/unit/test_cli.py +456 -0
  122. imperandi-0.1.0/tests/unit/test_convert.py +594 -0
  123. imperandi-0.1.0/tests/unit/test_datetime.py +222 -0
  124. imperandi-0.1.0/tests/unit/test_geometry.py +157 -0
  125. imperandi-0.1.0/tests/unit/test_ingest_hooks.py +215 -0
  126. imperandi-0.1.0/tests/unit/test_logging.py +63 -0
  127. imperandi-0.1.0/tests/unit/test_manifest.py +78 -0
  128. imperandi-0.1.0/tests/unit/test_misc.py +107 -0
  129. imperandi-0.1.0/tests/unit/test_parse.py +842 -0
  130. imperandi-0.1.0/tests/unit/test_phase.py +398 -0
  131. imperandi-0.1.0/tests/unit/test_radiomics.py +1200 -0
  132. imperandi-0.1.0/tests/unit/test_run_state.py +399 -0
  133. imperandi-0.1.0/tests/unit/test_segment.py +2024 -0
  134. imperandi-0.1.0/tests/unit/test_slow_test_tools.py +49 -0
  135. imperandi-0.1.0/tests/unit/test_utils_files.py +111 -0
  136. imperandi-0.1.0/tests/unit/test_utils_multiprocessing.py +197 -0
  137. imperandi-0.1.0/tests/unit/test_viewer.py +784 -0
  138. imperandi-0.1.0/tests/unit/test_viewer_web_data.py +309 -0
@@ -0,0 +1 @@
1
+ .githooks/* text eol=lf
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ zero_sha="0000000000000000000000000000000000000000"
5
+ repo_root="$(git rev-parse --show-toplevel)"
6
+ cd "$repo_root"
7
+
8
+ if command -v py >/dev/null 2>&1 && py -3 -c "import sys" >/dev/null 2>&1; then
9
+ python_launcher="py"
10
+ elif command -v python >/dev/null 2>&1 && python -c "import sys" >/dev/null 2>&1; then
11
+ python_launcher="python"
12
+ elif command -v python3 >/dev/null 2>&1 && python3 -c "import sys" >/dev/null 2>&1; then
13
+ python_launcher="python3"
14
+ elif command -v py >/dev/null 2>&1; then
15
+ python_launcher="py"
16
+ else
17
+ echo "No Python interpreter was found. Cannot clean notebook outputs." >&2
18
+ exit 1
19
+ fi
20
+
21
+ tmp_refs="$(mktemp 2>/dev/null || mktemp -t imperandi_nbpush_refs)"
22
+ tmp_files="$(mktemp 2>/dev/null || mktemp -t imperandi_nbpush_files)"
23
+ cleanup() {
24
+ rm -f "$tmp_refs" "$tmp_files"
25
+ }
26
+ trap cleanup EXIT INT TERM
27
+
28
+ cat > "$tmp_refs"
29
+
30
+ while IFS=' ' read -r local_ref local_sha remote_ref remote_sha; do
31
+ local_ref="$(printf '%s' "${local_ref:-}" | tr -d '\r')"
32
+ local_sha="$(printf '%s' "${local_sha:-}" | tr -d '\r')"
33
+ remote_ref="$(printf '%s' "${remote_ref:-}" | tr -d '\r')"
34
+ remote_sha="$(printf '%s' "${remote_sha:-}" | tr -d '\r')"
35
+
36
+ [ -n "${local_ref:-}" ] || continue
37
+ [ "$local_sha" = "$zero_sha" ] && continue
38
+
39
+ if [ "$remote_sha" = "$zero_sha" ]; then
40
+ revs="$(git rev-list "$local_sha" --not --remotes)"
41
+ else
42
+ revs="$(git rev-list "$remote_sha..$local_sha")"
43
+ fi
44
+
45
+ [ -n "$revs" ] || continue
46
+ printf '%s\n' "$revs" | git diff-tree --stdin --no-commit-id --name-only -r --diff-filter=ACMRT -- '*.ipynb' >> "$tmp_files"
47
+ done < "$tmp_refs"
48
+
49
+ if [ ! -s "$tmp_files" ]; then
50
+ exit 0
51
+ fi
52
+
53
+ sort -u "$tmp_files" > "${tmp_files}.sorted"
54
+ mv "${tmp_files}.sorted" "$tmp_files"
55
+
56
+ changed=0
57
+ while IFS= read -r notebook_path; do
58
+ [ -n "$notebook_path" ] || continue
59
+ [ -f "$notebook_path" ] || continue
60
+
61
+ status=0
62
+ if [ "$python_launcher" = "py" ]; then
63
+ py -3 ".githooks/strip_notebook_outputs.py" "$notebook_path" || status=$?
64
+ else
65
+ "$python_launcher" ".githooks/strip_notebook_outputs.py" "$notebook_path" || status=$?
66
+ fi
67
+
68
+ if [ "$status" -eq 2 ]; then
69
+ git add "$notebook_path"
70
+ changed=1
71
+ elif [ "$status" -ne 0 ]; then
72
+ echo "Failed to strip outputs from $notebook_path." >&2
73
+ exit "$status"
74
+ fi
75
+ done < "$tmp_files"
76
+
77
+ if [ "$changed" -eq 1 ]; then
78
+ echo "Notebook outputs were stripped and staged."
79
+ echo "Create a commit for the cleaned notebook(s), then push again."
80
+ exit 1
81
+ fi
82
+
83
+ exit 0
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+ """Strip execution outputs from Jupyter notebooks."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ import sys
8
+ from pathlib import Path
9
+
10
+
11
+ def strip_notebook(path: Path) -> bool:
12
+ notebook = json.loads(path.read_text(encoding="utf-8-sig"))
13
+ changed = False
14
+
15
+ cells = notebook.get("cells", [])
16
+ if isinstance(cells, list):
17
+ for cell in cells:
18
+ if not isinstance(cell, dict) or cell.get("cell_type") != "code":
19
+ continue
20
+
21
+ outputs = cell.get("outputs")
22
+ if outputs:
23
+ cell["outputs"] = []
24
+ changed = True
25
+
26
+ if cell.get("execution_count") is not None:
27
+ cell["execution_count"] = None
28
+ changed = True
29
+
30
+ metadata = notebook.get("metadata")
31
+ if isinstance(metadata, dict) and "widgets" in metadata:
32
+ metadata.pop("widgets", None)
33
+ changed = True
34
+
35
+ if changed:
36
+ rendered = json.dumps(notebook, ensure_ascii=False, indent=1)
37
+ path.write_text(rendered + "\n", encoding="utf-8")
38
+
39
+ return changed
40
+
41
+
42
+ def main(argv: list[str]) -> int:
43
+ if len(argv) < 2:
44
+ print(
45
+ "Usage: strip_notebook_outputs.py <notebook.ipynb> [...]", file=sys.stderr
46
+ )
47
+ return 1
48
+
49
+ any_changed = False
50
+ for raw_path in argv[1:]:
51
+ path = Path(raw_path)
52
+ try:
53
+ if strip_notebook(path):
54
+ any_changed = True
55
+ except Exception as exc: # pragma: no cover - defensive for hook execution
56
+ print(f"{path}: {exc}", file=sys.stderr)
57
+ return 1
58
+
59
+ return 2 if any_changed else 0
60
+
61
+
62
+ if __name__ == "__main__":
63
+ raise SystemExit(main(sys.argv))
@@ -0,0 +1,206 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v[0-9]*.[0-9]*.[0-9]*"
7
+ release:
8
+ types: [published]
9
+
10
+ concurrency:
11
+ group: release-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ test:
19
+ name: Test on Python ${{ matrix.python-version }}
20
+ runs-on: ubuntu-latest
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ python-version: ["3.10", "3.11", "3.12"]
25
+
26
+ steps:
27
+ - name: Checkout tagged source
28
+ uses: actions/checkout@v6
29
+ with:
30
+ fetch-depth: 0
31
+ persist-credentials: false
32
+
33
+ - name: Set up Python
34
+ uses: actions/setup-python@v6
35
+ with:
36
+ python-version: ${{ matrix.python-version }}
37
+
38
+ - name: Install package and test dependencies
39
+ run: |
40
+ python -m pip install --upgrade pip
41
+ python -m pip install ".[all-dev]"
42
+ python -m pip install "pyradiomics @ git+https://github.com/AIM-Harvard/pyradiomics.git@master"
43
+
44
+ - name: Run lint
45
+ run: python -m ruff check .
46
+
47
+ - name: Run unit tests
48
+ run: >-
49
+ python -m pytest -m "not slow"
50
+ --cov=imperandi
51
+ --cov-report=term-missing
52
+ --cov-fail-under=70
53
+
54
+ build:
55
+ name: Build and verify distributions
56
+ needs: test
57
+ runs-on: ubuntu-latest
58
+ outputs:
59
+ prerelease: ${{ steps.validate-tag.outputs.prerelease }}
60
+
61
+ steps:
62
+ - name: Checkout tagged source
63
+ uses: actions/checkout@v6
64
+ with:
65
+ fetch-depth: 0
66
+ persist-credentials: false
67
+
68
+ - name: Set up Python
69
+ uses: actions/setup-python@v6
70
+ with:
71
+ python-version: "3.12"
72
+
73
+ - name: Install release tooling
74
+ run: python -m pip install --upgrade build packaging twine
75
+
76
+ - name: Validate release tag
77
+ id: validate-tag
78
+ env:
79
+ RELEASE_TAG: ${{ github.ref_name }}
80
+ run: |
81
+ python - <<'PY'
82
+ import os
83
+ from packaging.version import InvalidVersion, Version
84
+
85
+ tag = os.environ["RELEASE_TAG"]
86
+ if not tag.startswith("v"):
87
+ raise SystemExit(f"Release tag must start with 'v': {tag}")
88
+ try:
89
+ release = Version(tag[1:])
90
+ except InvalidVersion as exc:
91
+ raise SystemExit(f"Release tag is not a valid version: {tag}") from exc
92
+ if release.local is not None:
93
+ raise SystemExit("PyPI release tags cannot contain a local version segment")
94
+ with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
95
+ is_prerelease = release.is_prerelease or release.is_devrelease
96
+ print(f"prerelease={str(is_prerelease).lower()}", file=output)
97
+ print(f"Validated release version {release}")
98
+ PY
99
+
100
+ - name: Build wheel and source distribution
101
+ run: python -m build
102
+
103
+ - name: Verify project-local configuration is excluded
104
+ run: |
105
+ python - <<'PY'
106
+ import tarfile
107
+ import zipfile
108
+ from pathlib import Path, PurePosixPath
109
+
110
+ artifacts = [
111
+ *Path("dist").glob("*.whl"),
112
+ *Path("dist").glob("*.tar.gz"),
113
+ ]
114
+ if len(artifacts) != 2:
115
+ raise SystemExit(f"Expected one wheel and one sdist, found: {artifacts}")
116
+ PY
117
+
118
+ - name: Check distribution metadata
119
+ run: python -m twine check --strict dist/*
120
+
121
+ - name: Verify built version matches tag
122
+ env:
123
+ RELEASE_TAG: ${{ github.ref_name }}
124
+ run: |
125
+ python -m pip install --force-reinstall --no-deps dist/*.whl
126
+ python - <<'PY'
127
+ import os
128
+ from importlib.metadata import version
129
+ from packaging.version import Version
130
+
131
+ expected = Version(os.environ["RELEASE_TAG"][1:])
132
+ built = Version(version("imperandi"))
133
+ if built != expected:
134
+ raise SystemExit(
135
+ f"Built distribution version {built} does not match tag {expected}"
136
+ )
137
+ print(f"Verified imperandi {built}")
138
+ PY
139
+
140
+ - name: Store distributions
141
+ uses: actions/upload-artifact@v7
142
+ with:
143
+ name: python-package-distributions
144
+ path: dist/
145
+ if-no-files-found: error
146
+ retention-days: 30
147
+ overwrite: true
148
+
149
+ publish-github:
150
+ name: Publish GitHub Release assets
151
+ if: github.repository == 'dmandache/IMPERANDI'
152
+ needs: build
153
+ runs-on: ubuntu-latest
154
+ permissions:
155
+ contents: write
156
+
157
+ steps:
158
+ - name: Download distributions
159
+ uses: actions/download-artifact@v8
160
+ with:
161
+ name: python-package-distributions
162
+ path: dist/
163
+
164
+ - name: Create or update release assets
165
+ env:
166
+ EVENT_NAME: ${{ github.event_name }}
167
+ GH_TOKEN: ${{ github.token }}
168
+ GH_REPO: ${{ github.repository }}
169
+ PRERELEASE: ${{ needs.build.outputs.prerelease }}
170
+ run: |
171
+ if [[ "${EVENT_NAME}" == "release" ]]; then
172
+ gh release upload "${GITHUB_REF_NAME}" dist/* --clobber
173
+ exit 0
174
+ fi
175
+
176
+ release_flags=()
177
+ if [[ "${PRERELEASE}" == "true" ]]; then
178
+ release_flags+=(--prerelease)
179
+ fi
180
+ gh release create "${GITHUB_REF_NAME}" \
181
+ dist/* \
182
+ --verify-tag \
183
+ --generate-notes \
184
+ --title "${GITHUB_REF_NAME}" \
185
+ "${release_flags[@]}"
186
+
187
+ publish-pypi:
188
+ name: Publish to PyPI
189
+ if: github.repository == 'dmandache/IMPERANDI'
190
+ needs: [build, publish-github]
191
+ runs-on: ubuntu-latest
192
+ environment:
193
+ name: pypi
194
+ url: https://pypi.org/p/imperandi
195
+ permissions:
196
+ id-token: write
197
+
198
+ steps:
199
+ - name: Download distributions
200
+ uses: actions/download-artifact@v8
201
+ with:
202
+ name: python-package-distributions
203
+ path: dist/
204
+
205
+ - name: Publish distributions
206
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,39 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: ["main", "master"]
6
+ pull_request:
7
+ branches: ["main", "master"]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12"]
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v5
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v6
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ - name: Install dependencies
24
+ run: |
25
+ python -m pip install -U pip
26
+ python -m pip install -e ".[all-dev]"
27
+ python -m pip install "pyradiomics @ git+https://github.com/AIM-Harvard/pyradiomics.git@master"
28
+ - name: Run lint
29
+ run: |
30
+ python -m ruff check .
31
+ - name: Run tests
32
+ run: |
33
+ python -m pytest -m "not slow" --cov=imperandi --cov-report=xml --cov-fail-under=70
34
+ - name: Upload coverage to Codecov
35
+ uses: codecov/codecov-action@v5
36
+ with:
37
+ files: ./coverage.xml
38
+ token: ${{ secrets.CODECOV_TOKEN }}
39
+ fail_ci_if_error: false
@@ -0,0 +1,230 @@
1
+ .codex
2
+
3
+ # Generic temp directories
4
+ .tmp/
5
+ .temp/
6
+ tmp/
7
+ temp/
8
+
9
+ # Generic temp files
10
+ *.tmp
11
+ *.temp
12
+ *.bak
13
+ *.swp
14
+ *.swo
15
+ *.orig
16
+ *~
17
+
18
+ # Big test data
19
+ tests/data/
20
+ tests/slow/*/data/input/
21
+ tests/slow/*/data/work/
22
+
23
+ # Byte-compiled / optimized / DLL files
24
+ __pycache__/
25
+ *.py[codz]
26
+ *$py.class
27
+
28
+ # C extensions
29
+ *.so
30
+
31
+ # Distribution / packaging
32
+ .Python
33
+ build/
34
+ develop-eggs/
35
+ dist/
36
+ downloads/
37
+ eggs/
38
+ .eggs/
39
+ lib/
40
+ lib64/
41
+ parts/
42
+ sdist/
43
+ var/
44
+ wheels/
45
+ share/python-wheels/
46
+ *.egg-info/
47
+ .installed.cfg
48
+ *.egg
49
+ MANIFEST
50
+
51
+ # PyInstaller
52
+ # Usually these files are written by a python script from a template
53
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
54
+ *.manifest
55
+ *.spec
56
+
57
+ # Installer logs
58
+ pip-log.txt
59
+ pip-delete-this-directory.txt
60
+
61
+ # Unit test / coverage reports
62
+ htmlcov/
63
+ .tox/
64
+ .nox/
65
+ .coverage
66
+ .coverage.*
67
+ .cache
68
+ nosetests.xml
69
+ #coverage.xml
70
+ *.cover
71
+ *.py.cover
72
+ .hypothesis/
73
+ .pytest_cache/
74
+ cover/
75
+
76
+ # Translations
77
+ *.mo
78
+ *.pot
79
+
80
+ # Django stuff:
81
+ *.log
82
+ local_settings.py
83
+ db.sqlite3
84
+ db.sqlite3-journal
85
+
86
+ # Flask stuff:
87
+ instance/
88
+ .webassets-cache
89
+
90
+ # Scrapy stuff:
91
+ .scrapy
92
+
93
+ # Sphinx documentation
94
+ docs/_build/
95
+
96
+ # PyBuilder
97
+ .pybuilder/
98
+ target/
99
+
100
+ # Jupyter Notebook
101
+ .ipynb_checkpoints
102
+
103
+ # IPython
104
+ profile_default/
105
+ ipython_config.py
106
+
107
+ # pyenv
108
+ # For a library or package, you might want to ignore these files since the code is
109
+ # intended to run in multiple environments; otherwise, check them in:
110
+ # .python-version
111
+
112
+ # pipenv
113
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
114
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
115
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
116
+ # install all needed dependencies.
117
+ #Pipfile.lock
118
+
119
+ # UV
120
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
121
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
122
+ # commonly ignored for libraries.
123
+ #uv.lock
124
+
125
+ # poetry
126
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
127
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
128
+ # commonly ignored for libraries.
129
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
130
+ #poetry.lock
131
+ #poetry.toml
132
+
133
+ # pdm
134
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
135
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
136
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
137
+ #pdm.lock
138
+ #pdm.toml
139
+ .pdm-python
140
+ .pdm-build/
141
+
142
+ # pixi
143
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
144
+ #pixi.lock
145
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
146
+ # in the .venv directory. It is recommended not to include this directory in version control.
147
+ .pixi
148
+
149
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
150
+ __pypackages__/
151
+
152
+ # Celery stuff
153
+ celerybeat-schedule
154
+ celerybeat.pid
155
+
156
+ # SageMath parsed files
157
+ *.sage.py
158
+
159
+ # Environments
160
+ .env
161
+ .envrc
162
+ .venv
163
+ .conda
164
+ env/
165
+ venv/
166
+ ENV/
167
+ env.bak/
168
+ venv.bak/
169
+
170
+ # Spyder project settings
171
+ .spyderproject
172
+ .spyproject
173
+
174
+ # Rope project settings
175
+ .ropeproject
176
+
177
+ # mkdocs documentation
178
+ /site
179
+
180
+ # mypy
181
+ .mypy_cache/
182
+ .dmypy.json
183
+ dmypy.json
184
+
185
+ # Pyre type checker
186
+ .pyre/
187
+
188
+ # pytype static type analyzer
189
+ .pytype/
190
+
191
+ # Cython debug symbols
192
+ cython_debug/
193
+
194
+ # PyCharm
195
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
196
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
197
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
198
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
199
+ .idea/
200
+
201
+ # Abstra
202
+ # Abstra is an AI-powered process automation framework.
203
+ # Ignore directories containing user credentials, local state, and settings.
204
+ # Learn more at https://abstra.io/docs
205
+ .abstra/
206
+
207
+ # Visual Studio Code
208
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
209
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
210
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
211
+ # you could uncomment the following to ignore the entire vscode folder
212
+ .vscode/
213
+
214
+ # Ruff stuff:
215
+ .ruff_cache/
216
+
217
+ # PyPI configuration file
218
+ .pypirc
219
+
220
+ # Cursor
221
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
222
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
223
+ # refer to https://docs.cursor.com/context/ignore-files
224
+ .cursorignore
225
+ .cursorindexingignore
226
+
227
+ # Marimo
228
+ marimo/_static/
229
+ marimo/_lsp/
230
+ __marimo__/
@@ -0,0 +1,16 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-24.04
5
+ tools:
6
+ python: "3.10"
7
+
8
+ sphinx:
9
+ configuration: docs/source/conf.py
10
+ fail_on_warning: false
11
+
12
+ python:
13
+ install:
14
+ - requirements: docs/requirements.txt
15
+ - method: pip
16
+ path: .