selexprep 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.
- selexprep-0.1.0/.Rhistory +0 -0
- selexprep-0.1.0/.claudeignore +33 -0
- selexprep-0.1.0/.dockerignore +23 -0
- selexprep-0.1.0/.github/workflows/release.yml +62 -0
- selexprep-0.1.0/.github/workflows/tests.yml +47 -0
- selexprep-0.1.0/.gitignore +72 -0
- selexprep-0.1.0/.pre-commit-config.yaml +29 -0
- selexprep-0.1.0/CHANGELOG.md +81 -0
- selexprep-0.1.0/CLAUDE.md +94 -0
- selexprep-0.1.0/Dockerfile +45 -0
- selexprep-0.1.0/LICENSE +21 -0
- selexprep-0.1.0/PKG-INFO +408 -0
- selexprep-0.1.0/README.md +351 -0
- selexprep-0.1.0/benchmarks/README.md +245 -0
- selexprep-0.1.0/benchmarks/Snakefile +172 -0
- selexprep-0.1.0/benchmarks/audit.smk +156 -0
- selexprep-0.1.0/benchmarks/audit_results/audit_accessions.manifest.json +6 -0
- selexprep-0.1.0/benchmarks/audit_results/audit_accessions.tsv +24 -0
- selexprep-0.1.0/benchmarks/audit_results/audit_metrics.json +263 -0
- selexprep-0.1.0/benchmarks/audit_results/eligibility.tsv +126 -0
- selexprep-0.1.0/benchmarks/audit_results/table_audit.md +37 -0
- selexprep-0.1.0/benchmarks/build_project_metadata.py +482 -0
- selexprep-0.1.0/benchmarks/candidates.tsv +10 -0
- selexprep-0.1.0/benchmarks/catalog_annotations.tsv +228 -0
- selexprep-0.1.0/benchmarks/catalog_completeness_audit.json +12 -0
- selexprep-0.1.0/benchmarks/catalog_completeness_audit.py +253 -0
- selexprep-0.1.0/benchmarks/catalog_completeness_audit.tsv +104 -0
- selexprep-0.1.0/benchmarks/excluded_datasets.tsv +6 -0
- selexprep-0.1.0/benchmarks/ground_truth.tsv +12 -0
- selexprep-0.1.0/benchmarks/project_annotations.tsv +12 -0
- selexprep-0.1.0/benchmarks/project_metadata.csv +294 -0
- selexprep-0.1.0/benchmarks/project_metadata.json +5238 -0
- selexprep-0.1.0/benchmarks/project_metadata.trajectories.json +5946 -0
- selexprep-0.1.0/benchmarks/read_level_flanks.py +393 -0
- selexprep-0.1.0/benchmarks/read_level_flanks_tables.txt +301 -0
- selexprep-0.1.0/benchmarks/read_level_truth_provenance.tsv +4 -0
- selexprep-0.1.0/benchmarks/read_state_evidence.tsv +12 -0
- selexprep-0.1.0/benchmarks/round_maps/PRJEB28411.rounds.tsv +13 -0
- selexprep-0.1.0/benchmarks/round_maps/PRJNA883192.rounds.tsv +5 -0
- selexprep-0.1.0/benchmarks/round_maps/PRJNA935703.rounds.tsv +2 -0
- selexprep-0.1.0/benchmarks/round_maps/PRJNA975735.rounds.tsv +6 -0
- selexprep-0.1.0/benchmarks/screening_log.tsv +17 -0
- selexprep-0.1.0/conda-recipe/meta.yaml +70 -0
- selexprep-0.1.0/docs/api.md +24 -0
- selexprep-0.1.0/docs/batch.md +37 -0
- selexprep-0.1.0/docs/cli.md +92 -0
- selexprep-0.1.0/docs/examples.md +23 -0
- selexprep-0.1.0/docs/index.md +19 -0
- selexprep-0.1.0/docs/library-report.md +67 -0
- selexprep-0.1.0/docs/limitations.md +20 -0
- selexprep-0.1.0/docs/quickstart.md +49 -0
- selexprep-0.1.0/docs/roadmap.md +11 -0
- selexprep-0.1.0/examples/01_offline_toy_pipeline.ipynb +441 -0
- selexprep-0.1.0/examples/02_library_report_interpretation.ipynb +268 -0
- selexprep-0.1.0/examples/README.md +39 -0
- selexprep-0.1.0/examples/data/PRJEB62495.library_report.json +55 -0
- selexprep-0.1.0/examples/data/PRJEB70964.library_report.json +33 -0
- selexprep-0.1.0/examples/data/PRJNA615076.library_report.json +105 -0
- selexprep-0.1.0/examples/run_public_accession.sh +18 -0
- selexprep-0.1.0/mkdocs.yml +62 -0
- selexprep-0.1.0/pyproject.toml +152 -0
- selexprep-0.1.0/selexprep.def +54 -0
- selexprep-0.1.0/src/selexprep/__init__.py +3 -0
- selexprep-0.1.0/src/selexprep/_common.py +78 -0
- selexprep-0.1.0/src/selexprep/_io.py +80 -0
- selexprep-0.1.0/src/selexprep/benchmark/__init__.py +20 -0
- selexprep-0.1.0/src/selexprep/benchmark/corpus_audit.py +741 -0
- selexprep-0.1.0/src/selexprep/benchmark/eligibility.py +472 -0
- selexprep-0.1.0/src/selexprep/benchmark/equivalence.py +228 -0
- selexprep-0.1.0/src/selexprep/benchmark/figure_a.py +155 -0
- selexprep-0.1.0/src/selexprep/benchmark/figure_b.py +164 -0
- selexprep-0.1.0/src/selexprep/benchmark/metrics.py +1214 -0
- selexprep-0.1.0/src/selexprep/catalog/__init__.py +24 -0
- selexprep-0.1.0/src/selexprep/catalog/cli.py +149 -0
- selexprep-0.1.0/src/selexprep/catalog/data/__init__.py +1 -0
- selexprep-0.1.0/src/selexprep/catalog/data/bioprojects.csv +294 -0
- selexprep-0.1.0/src/selexprep/catalog/data/bioprojects_excluded.csv +62 -0
- selexprep-0.1.0/src/selexprep/catalog/filter.py +97 -0
- selexprep-0.1.0/src/selexprep/catalog/reader.py +62 -0
- selexprep-0.1.0/src/selexprep/catalog/rebuild.py +627 -0
- selexprep-0.1.0/src/selexprep/cli.py +695 -0
- selexprep-0.1.0/src/selexprep/count/__init__.py +1 -0
- selexprep-0.1.0/src/selexprep/count/counter.py +639 -0
- selexprep-0.1.0/src/selexprep/extract/__init__.py +6 -0
- selexprep-0.1.0/src/selexprep/extract/demux.py +355 -0
- selexprep-0.1.0/src/selexprep/extract/runner.py +752 -0
- selexprep-0.1.0/src/selexprep/extract/strand.py +181 -0
- selexprep-0.1.0/src/selexprep/extract/trim.py +309 -0
- selexprep-0.1.0/src/selexprep/fetch/__init__.py +27 -0
- selexprep-0.1.0/src/selexprep/fetch/discover.py +1145 -0
- selexprep-0.1.0/src/selexprep/fetch/download.py +844 -0
- selexprep-0.1.0/src/selexprep/fetch/inspect.py +195 -0
- selexprep-0.1.0/src/selexprep/fetch/library_strategy.py +203 -0
- selexprep-0.1.0/src/selexprep/fetch/metadata.py +459 -0
- selexprep-0.1.0/src/selexprep/fetch/plan.py +243 -0
- selexprep-0.1.0/src/selexprep/fetch/runner.py +403 -0
- selexprep-0.1.0/src/selexprep/library/__init__.py +25 -0
- selexprep-0.1.0/src/selexprep/library/adapters.py +127 -0
- selexprep-0.1.0/src/selexprep/library/audit.py +258 -0
- selexprep-0.1.0/src/selexprep/library/detect.py +1038 -0
- selexprep-0.1.0/src/selexprep/library/report.py +393 -0
- selexprep-0.1.0/src/selexprep/manifest.py +286 -0
- selexprep-0.1.0/src/selexprep/qc/__init__.py +1 -0
- selexprep-0.1.0/src/selexprep/qc/consistency.py +320 -0
- selexprep-0.1.0/src/selexprep/qc/coverage.py +188 -0
- selexprep-0.1.0/src/selexprep/qc/diversity.py +99 -0
- selexprep-0.1.0/src/selexprep/qc/flags.py +464 -0
- selexprep-0.1.0/src/selexprep/qc/plots.py +227 -0
- selexprep-0.1.0/src/selexprep/qc/readiness.py +887 -0
- selexprep-0.1.0/src/selexprep/qc/runner.py +156 -0
- selexprep-0.1.0/src/selexprep/run/__init__.py +5 -0
- selexprep-0.1.0/src/selexprep/run/runner.py +638 -0
- selexprep-0.1.0/tests/__init__.py +0 -0
- selexprep-0.1.0/tests/conftest.py +13 -0
- selexprep-0.1.0/tests/fixtures/.gitkeep +0 -0
- selexprep-0.1.0/tests/test_adapters.py +124 -0
- selexprep-0.1.0/tests/test_audit.py +145 -0
- selexprep-0.1.0/tests/test_benchmark_corpus_audit.py +636 -0
- selexprep-0.1.0/tests/test_benchmark_eligibility.py +412 -0
- selexprep-0.1.0/tests/test_benchmark_equivalence.py +124 -0
- selexprep-0.1.0/tests/test_benchmark_figure_a.py +123 -0
- selexprep-0.1.0/tests/test_benchmark_figure_b.py +113 -0
- selexprep-0.1.0/tests/test_benchmark_metrics.py +932 -0
- selexprep-0.1.0/tests/test_benchmark_tier1_curation.py +310 -0
- selexprep-0.1.0/tests/test_build_project_metadata.py +277 -0
- selexprep-0.1.0/tests/test_catalog.py +444 -0
- selexprep-0.1.0/tests/test_cli.py +779 -0
- selexprep-0.1.0/tests/test_common.py +69 -0
- selexprep-0.1.0/tests/test_consistency.py +140 -0
- selexprep-0.1.0/tests/test_counter.py +180 -0
- selexprep-0.1.0/tests/test_coverage.py +125 -0
- selexprep-0.1.0/tests/test_demux.py +186 -0
- selexprep-0.1.0/tests/test_detect.py +260 -0
- selexprep-0.1.0/tests/test_discover.py +304 -0
- selexprep-0.1.0/tests/test_diversity.py +151 -0
- selexprep-0.1.0/tests/test_download.py +301 -0
- selexprep-0.1.0/tests/test_extract_override.py +426 -0
- selexprep-0.1.0/tests/test_extract_runner.py +478 -0
- selexprep-0.1.0/tests/test_fetch_cli.py +447 -0
- selexprep-0.1.0/tests/test_fetch_plan.py +379 -0
- selexprep-0.1.0/tests/test_flags.py +429 -0
- selexprep-0.1.0/tests/test_inspect.py +214 -0
- selexprep-0.1.0/tests/test_io.py +92 -0
- selexprep-0.1.0/tests/test_library_strategy.py +193 -0
- selexprep-0.1.0/tests/test_manifest.py +288 -0
- selexprep-0.1.0/tests/test_metadata.py +388 -0
- selexprep-0.1.0/tests/test_plots.py +104 -0
- selexprep-0.1.0/tests/test_qc_runner.py +200 -0
- selexprep-0.1.0/tests/test_read_level_flanks.py +95 -0
- selexprep-0.1.0/tests/test_readiness.py +285 -0
- selexprep-0.1.0/tests/test_report.py +569 -0
- selexprep-0.1.0/tests/test_run_runner.py +671 -0
- selexprep-0.1.0/tests/test_strand.py +212 -0
- selexprep-0.1.0/tests/test_trim.py +206 -0
- selexprep-0.1.0/uv.lock +4311 -0
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Build artifacts
|
|
2
|
+
dist/
|
|
3
|
+
build/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
htmlcov/
|
|
6
|
+
coverage.xml
|
|
7
|
+
|
|
8
|
+
# Caches (regenerated on demand)
|
|
9
|
+
.venv/
|
|
10
|
+
__pycache__/
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.mypy_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
.coverage.*
|
|
16
|
+
|
|
17
|
+
# Lockfile — large; regenerated by `uv sync`. Excluding keeps a fresh
|
|
18
|
+
# Claude session from indexing thousands of resolved-package entries.
|
|
19
|
+
uv.lock
|
|
20
|
+
|
|
21
|
+
# Editor / OS
|
|
22
|
+
.DS_Store
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
25
|
+
|
|
26
|
+
# Built docs (the source is in docs/, not docs/site/)
|
|
27
|
+
docs/site/
|
|
28
|
+
site/
|
|
29
|
+
|
|
30
|
+
# Local scratch
|
|
31
|
+
scratch/
|
|
32
|
+
tmp/
|
|
33
|
+
*.log
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Keep the Docker build context small and reproducible: only pyproject,
|
|
2
|
+
# README, LICENSE, and src/ are needed to build the wheel (see Dockerfile).
|
|
3
|
+
.git
|
|
4
|
+
.github
|
|
5
|
+
.venv
|
|
6
|
+
venv
|
|
7
|
+
__pycache__
|
|
8
|
+
*.pyc
|
|
9
|
+
.pytest_cache
|
|
10
|
+
.mypy_cache
|
|
11
|
+
.ruff_cache
|
|
12
|
+
htmlcov
|
|
13
|
+
.coverage
|
|
14
|
+
coverage.xml
|
|
15
|
+
dist
|
|
16
|
+
build
|
|
17
|
+
*.egg-info
|
|
18
|
+
docs
|
|
19
|
+
site
|
|
20
|
+
examples
|
|
21
|
+
tests
|
|
22
|
+
benchmarks
|
|
23
|
+
*.sif
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
|
|
19
|
+
- name: Build sdist + wheel
|
|
20
|
+
run: |
|
|
21
|
+
python -m pip install --upgrade pip build
|
|
22
|
+
python -m build
|
|
23
|
+
|
|
24
|
+
- name: Upload build artifacts
|
|
25
|
+
uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: dist
|
|
28
|
+
path: dist/
|
|
29
|
+
|
|
30
|
+
publish-testpypi:
|
|
31
|
+
needs: build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
environment: testpypi
|
|
34
|
+
permissions:
|
|
35
|
+
id-token: write
|
|
36
|
+
if: github.event_name == 'workflow_dispatch'
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/download-artifact@v4
|
|
39
|
+
with:
|
|
40
|
+
name: dist
|
|
41
|
+
path: dist/
|
|
42
|
+
|
|
43
|
+
- name: Publish to TestPyPI
|
|
44
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
45
|
+
with:
|
|
46
|
+
repository-url: https://test.pypi.org/legacy/
|
|
47
|
+
|
|
48
|
+
publish-pypi:
|
|
49
|
+
needs: build
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
environment: pypi
|
|
52
|
+
permissions:
|
|
53
|
+
id-token: write
|
|
54
|
+
if: github.event_name == 'release'
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/download-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: dist
|
|
59
|
+
path: dist/
|
|
60
|
+
|
|
61
|
+
- name: Publish to PyPI
|
|
62
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
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
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
cache: pip
|
|
25
|
+
|
|
26
|
+
- name: Install package + dev deps
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
pip install -e ".[dev]"
|
|
30
|
+
|
|
31
|
+
- name: Lint with ruff
|
|
32
|
+
run: |
|
|
33
|
+
ruff check src/ tests/
|
|
34
|
+
ruff format --check src/ tests/
|
|
35
|
+
|
|
36
|
+
- name: Type-check with mypy
|
|
37
|
+
run: mypy src/
|
|
38
|
+
|
|
39
|
+
- name: Run pytest with coverage
|
|
40
|
+
run: pytest --cov=selexprep --cov-report=term-missing --cov-report=xml
|
|
41
|
+
|
|
42
|
+
- name: Upload coverage
|
|
43
|
+
if: matrix.python-version == '3.12'
|
|
44
|
+
uses: actions/upload-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: coverage-report
|
|
47
|
+
path: coverage.xml
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg-info/
|
|
7
|
+
*.egg
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
wheels/
|
|
11
|
+
|
|
12
|
+
# Testing & coverage
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.tox/
|
|
15
|
+
.coverage
|
|
16
|
+
.coverage.*
|
|
17
|
+
htmlcov/
|
|
18
|
+
coverage.xml
|
|
19
|
+
*.cover
|
|
20
|
+
|
|
21
|
+
# Type-checking & linting
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
|
|
25
|
+
# Snakemake (created by --dry-run too — both repo-root and benchmarks/)
|
|
26
|
+
.snakemake/
|
|
27
|
+
|
|
28
|
+
# Virtual environments
|
|
29
|
+
.venv/
|
|
30
|
+
venv/
|
|
31
|
+
env/
|
|
32
|
+
.python-version
|
|
33
|
+
|
|
34
|
+
# Environment files
|
|
35
|
+
.env
|
|
36
|
+
.env.local
|
|
37
|
+
|
|
38
|
+
# Documentation
|
|
39
|
+
docs/site/
|
|
40
|
+
site/
|
|
41
|
+
|
|
42
|
+
# OS
|
|
43
|
+
.DS_Store
|
|
44
|
+
Thumbs.db
|
|
45
|
+
|
|
46
|
+
# IDE
|
|
47
|
+
.idea/
|
|
48
|
+
.vscode/
|
|
49
|
+
*.swp
|
|
50
|
+
*.swo
|
|
51
|
+
|
|
52
|
+
# Local data / scratch
|
|
53
|
+
scratch/
|
|
54
|
+
tmp/
|
|
55
|
+
*.log
|
|
56
|
+
|
|
57
|
+
# Benchmark candidate-curation: local-only tools + scratch (not package content;
|
|
58
|
+
# the curation decisions they produced are captured in the committed evidence
|
|
59
|
+
# files: ground_truth.tsv / read_state_evidence.tsv / screening_log.tsv)
|
|
60
|
+
benchmarks/screen_read_state.py
|
|
61
|
+
benchmarks/*_screen.tsv
|
|
62
|
+
|
|
63
|
+
# Project-metadata builder API caches (regenerable from OpenAlex / figshare / Zenodo)
|
|
64
|
+
benchmarks/.oa_cache.json
|
|
65
|
+
benchmarks/.discovery_doi_cache.json
|
|
66
|
+
|
|
67
|
+
# Example run artifacts — notebooks self-generate demo/, run_public_accession.sh writes demo_public/
|
|
68
|
+
examples/**/demo*/
|
|
69
|
+
.ipynb_checkpoints/
|
|
70
|
+
|
|
71
|
+
# Transient HPC run-result tarballs (scp'd back for analysis, not repo content)
|
|
72
|
+
full_list_*.tar.gz
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v4.6.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: end-of-file-fixer
|
|
6
|
+
- id: trailing-whitespace
|
|
7
|
+
- id: check-yaml
|
|
8
|
+
- id: check-toml
|
|
9
|
+
- id: check-added-large-files
|
|
10
|
+
args: [--maxkb=500]
|
|
11
|
+
- id: check-merge-conflict
|
|
12
|
+
|
|
13
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
14
|
+
rev: v0.6.0
|
|
15
|
+
hooks:
|
|
16
|
+
- id: ruff
|
|
17
|
+
args: [--fix]
|
|
18
|
+
- id: ruff-format
|
|
19
|
+
|
|
20
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
21
|
+
rev: v1.10.0
|
|
22
|
+
hooks:
|
|
23
|
+
- id: mypy
|
|
24
|
+
additional_dependencies:
|
|
25
|
+
- pydantic>=2.0
|
|
26
|
+
- types-pyyaml
|
|
27
|
+
- types-requests
|
|
28
|
+
args: [--config-file=pyproject.toml]
|
|
29
|
+
files: ^src/
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `selexprep` are documented here.
|
|
4
|
+
|
|
5
|
+
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [SemVer](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
_No unreleased changes yet._
|
|
10
|
+
|
|
11
|
+
## [0.1.0] - 2026-06-13
|
|
12
|
+
|
|
13
|
+
First public release: accession-first preprocessing for high-throughput SELEX
|
|
14
|
+
(HT-SELEX) sequencing deposits, with automatic primer / constant-region
|
|
15
|
+
inference. Give it an INSDC accession (ENA / SRA / DDBJ) and it fetches the
|
|
16
|
+
runs, infers the library's flanking constants from the reads, and extracts the
|
|
17
|
+
random regions — no manual primer entry required.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Command-line interface** (`selexprep <verb>`):
|
|
22
|
+
- `inspect` — summarize an accession's runs and metadata.
|
|
23
|
+
- `fetch` — download FASTQs for an accession (ENA-direct by default).
|
|
24
|
+
- `detect` — infer the 5′/3′ constant regions (primers) from the reads.
|
|
25
|
+
- `extract` — strip the inferred constants and emit the random-region reads.
|
|
26
|
+
- `count` — collapse extracted reads to unique-sequence counts per round.
|
|
27
|
+
- `qc` — quality-control flags and plots.
|
|
28
|
+
- `run` — end-to-end fetch → detect → extract → count, with `--resume`.
|
|
29
|
+
- `catalog` — browse the bundled discovery catalog of SELEX deposits.
|
|
30
|
+
- **Primer / constant-region inference** (`detect`): position-anchored
|
|
31
|
+
consensus over the read pool, with a typed `LibraryReport` describing the
|
|
32
|
+
inferred 5′/3′ constants, random-region length, match rates, read state
|
|
33
|
+
(raw vs. pre-trimmed), and a confidence-graded status. Cross-round inference
|
|
34
|
+
reconciles evidence across selection rounds.
|
|
35
|
+
- **Adapter awareness**: known Illumina sequencing adapters (e.g. TruSeq) are
|
|
36
|
+
recorded where present and excluded from primer candidates, so adapter
|
|
37
|
+
read-through is reported as diagnostic information rather than mistaken for a
|
|
38
|
+
library constant.
|
|
39
|
+
- **`extract`**: paired-end handling, strand-orientation detection, and
|
|
40
|
+
per-mode adapter handling. cutadapt is invoked as a subprocess (its CLI is
|
|
41
|
+
the stable contract). Supports `--override-primer-{5p,3p}` to bypass
|
|
42
|
+
inference, and a rebuild path for manually corrected primers.
|
|
43
|
+
- **Discovery catalog** (`catalog`): a bundled, refreshable index of public
|
|
44
|
+
SELEX deposits built from INSDC `library_strategy="SELEX"` queries, with
|
|
45
|
+
per-run and per-BioProject strategy filtering and manual exclusions for
|
|
46
|
+
mislabelled deposits.
|
|
47
|
+
- **Quality control** (`qc`): diversity / rarefaction helpers and depth-aware
|
|
48
|
+
flags (e.g. unexpected rarefied-diversity increase, modal-length spread,
|
|
49
|
+
orientation skew, low read depth, adapter contamination).
|
|
50
|
+
- **Deterministic outputs**: all gzip writes are byte-identical across reruns
|
|
51
|
+
(gzip header `mtime=0`) and JSON is written with sorted keys, so a
|
|
52
|
+
`SelexprepManifestV1` run manifest carries reproducible `sha256` hashes.
|
|
53
|
+
- **Benchmark suite** (under `benchmarks/`, not shipped on PyPI): a Tier 1
|
|
54
|
+
primer-recovery benchmark against paper-grounded ground truth and a Tier 2
|
|
55
|
+
corpus-audit pipeline over the discovery catalog.
|
|
56
|
+
|
|
57
|
+
### Known limitations (v0.2 carry-forward)
|
|
58
|
+
|
|
59
|
+
- **Multiplexed (inline-barcoded) deposits** need a user-supplied sample sheet;
|
|
60
|
+
automatic demultiplex detection is deferred.
|
|
61
|
+
- **Read merging** of overlapping mates is not implemented.
|
|
62
|
+
- **`qc.readiness`** (clustering / enrichment review) is a faithful library
|
|
63
|
+
API but expects clustering artifacts that v0.1 does not produce; it is not
|
|
64
|
+
wired into the `qc` verb.
|
|
65
|
+
- **`count.counter`** can still trim raw FASTQs inline; the clean split
|
|
66
|
+
(`extract` strips, `count` only counts) is partial.
|
|
67
|
+
- **`--from-pretrimmed-fastq`** validates record completeness but not per-line
|
|
68
|
+
FASTQ conformance — adequate for the power-user opt-in.
|
|
69
|
+
- **Network coverage**: the non-ENA fetch backends still lack offline mocked
|
|
70
|
+
tests (carried into v0.2).
|
|
71
|
+
|
|
72
|
+
### Packaging
|
|
73
|
+
|
|
74
|
+
- MIT-licensed. A default `pip install selexprep` pulls only MIT-compatible
|
|
75
|
+
dependencies (pydantic v2, Typer, pandas, numpy); cutadapt is invoked as a
|
|
76
|
+
subprocess.
|
|
77
|
+
- `kingfisher` (GPL-3.0) is an optional, runtime-detected subprocess backend —
|
|
78
|
+
not a declared dependency — so the default install stays MIT-only.
|
|
79
|
+
|
|
80
|
+
[Unreleased]: https://github.com/marcorotanegroni/selexprep/compare/v0.1.0...HEAD
|
|
81
|
+
[0.1.0]: https://github.com/marcorotanegroni/selexprep/releases/tag/v0.1.0
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# selexprep — Claude Code project context
|
|
2
|
+
|
|
3
|
+
Accession-first preprocessing for public HT-SELEX datasets with empirical
|
|
4
|
+
primer / constant-region inference. v0.1 ships a CLI + bundled discovery
|
|
5
|
+
catalog. Target venues: Bioinformatics Advances Application Note (tool) +
|
|
6
|
+
NAR Database Issue (catalog, v0.2).
|
|
7
|
+
|
|
8
|
+
The locked Codex-peer-reviewed implementation plan lives at
|
|
9
|
+
`~/.claude/plans/unified-seeking-treehouse.md` (four review passes; treat
|
|
10
|
+
as a contract — don't rewrite for additive extensions, just commit +
|
|
11
|
+
CHANGELOG entry).
|
|
12
|
+
|
|
13
|
+
## Commands
|
|
14
|
+
|
|
15
|
+
| Task | Command |
|
|
16
|
+
| ------------------- | ---------------------------------------- |
|
|
17
|
+
| Tests | `uv run pytest` |
|
|
18
|
+
| Lint | `uv run ruff check src/ tests/` |
|
|
19
|
+
| Format | `uv run ruff format src/ tests/` |
|
|
20
|
+
| Type-check | `uv run mypy src/` |
|
|
21
|
+
| Catalog browse | `uv run selexprep catalog list --target X --insdc-only` |
|
|
22
|
+
| Catalog refresh | `uv run selexprep catalog refresh` |
|
|
23
|
+
|
|
24
|
+
CI runs lint + format + mypy + pytest on Python 3.10 / 3.11 / 3.12.
|
|
25
|
+
Always run all four locally before committing.
|
|
26
|
+
|
|
27
|
+
## Layout
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
src/selexprep/
|
|
31
|
+
├── _common.py shared utilities (iter_srr_files, load_csv, …)
|
|
32
|
+
├── _io.py deterministic gzip + sha256 helpers
|
|
33
|
+
├── cli.py Typer dispatcher (root)
|
|
34
|
+
├── catalog/ bundled public-SELEX catalog + filters + CLI subapp
|
|
35
|
+
├── count/ per-round sequence counting
|
|
36
|
+
├── extract/ demux + trim (sample-sheet driven; deterministic gzip)
|
|
37
|
+
├── fetch/ accession discovery + download (ENA-first)
|
|
38
|
+
├── library/ primer detection + audit (Phase 2: LibraryReport)
|
|
39
|
+
└── qc/ round coverage, consistency, readiness, plots
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Strict-mypy boundary
|
|
43
|
+
|
|
44
|
+
Only `selexprep.library.report` is strict-mypy (Phase 2 LibraryReport
|
|
45
|
+
schema — type precision matters for confidence calibration). Other
|
|
46
|
+
modules use the permissive profile declared in `pyproject.toml`'s
|
|
47
|
+
`[tool.mypy] disable_error_code`.
|
|
48
|
+
|
|
49
|
+
## Critical gotchas (do not relearn)
|
|
50
|
+
|
|
51
|
+
- **macOS TCC** blocks `~/Documents` on this Mac → repo lives at
|
|
52
|
+
`/Users/marcorotanegroni/selexprep`, NOT under `~/Documents/...`.
|
|
53
|
+
- **`detect.detect_from_parquet`** defaults to `top_n=None` (no
|
|
54
|
+
subsampling). Don't reintroduce the 10_000 cap — the long tail of
|
|
55
|
+
rare uniques confirms primer consensus.
|
|
56
|
+
- **`download_srr`** defaults to `backend="auto"` → ENA-direct first
|
|
57
|
+
(MIT-licensed path). kingfisher is GPL-3.0 and only invoked as
|
|
58
|
+
opt-in fallback (with a loud GPL notice). Never promote it to default.
|
|
59
|
+
- **All `.gz` writes** must go through
|
|
60
|
+
`selexprep._io.open_gzip_text_deterministic` (mtime=0 + suppressed
|
|
61
|
+
FNAME). Plain `gzip.open` breaks SHA256 reproducibility.
|
|
62
|
+
- **Curation flags** (`include`, `manual_curation_notes`,
|
|
63
|
+
`library_type_verification`, `library_type_evidence`,
|
|
64
|
+
`has_processed_counts`) are NEVER in the package catalog or in any
|
|
65
|
+
user-facing output. Curation is the user's downstream job; the
|
|
66
|
+
package reflects the public archives.
|
|
67
|
+
- **Phase 2 centerpiece** is `LibraryReport` with explicit
|
|
68
|
+
`extraction_mode` × `read_source` × `required_action` matrix
|
|
69
|
+
(see the plan file for the full pydantic schema and the
|
|
70
|
+
cross-round-persistence inference algorithm).
|
|
71
|
+
|
|
72
|
+
## Workflow
|
|
73
|
+
|
|
74
|
+
- **Big design decisions** → user cross-checks with Codex
|
|
75
|
+
(independent peer-review). Don't self-approve scope changes. Trigger
|
|
76
|
+
phrase: *"let me run this through Codex"*. Wait for the response
|
|
77
|
+
before applying changes.
|
|
78
|
+
- **Per-feature implementations** → use `EnterPlanMode` to get plan
|
|
79
|
+
approval before writing code on anything > a one-file change.
|
|
80
|
+
- **Subagents** → `Explore` agent for read-only mapping when the
|
|
81
|
+
surface area is unclear; do edits in the main context.
|
|
82
|
+
- **Background polling** (CI, long-running jobs) → use `Bash` with
|
|
83
|
+
`run_in_background: true` + a sha-aware Python poll script at
|
|
84
|
+
`/tmp/wait_for_sha_ci.py`. Don't write nested `python -c` with
|
|
85
|
+
escaped quotes — they break and run forever silently.
|
|
86
|
+
|
|
87
|
+
## Where context lives
|
|
88
|
+
|
|
89
|
+
- **Plan (locked contract):** `~/.claude/plans/unified-seeking-treehouse.md`
|
|
90
|
+
- **Change log + v0.1 follow-ups:** `CHANGELOG.md` in this repo
|
|
91
|
+
- **Project memory** (durable user preferences, project state):
|
|
92
|
+
`~/.claude/projects/-Users-marcorotanegroni-Documents-subtractive-proteomics-pipeline-aptameri-selex-corpus/memory/MEMORY.md`
|
|
93
|
+
(the path is keyed on the original thesis directory, not on this
|
|
94
|
+
repo — index file lists every memory note).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
#
|
|
3
|
+
# selexprep container image.
|
|
4
|
+
#
|
|
5
|
+
# Build: docker build -t selexprep:0.1.0 .
|
|
6
|
+
# Run: docker run --rm selexprep:0.1.0 inspect SRR1234567
|
|
7
|
+
# docker run --rm -v "$PWD":/data selexprep:0.1.0 run /data/accessions.tsv --outdir /data/out
|
|
8
|
+
#
|
|
9
|
+
# The image installs selexprep from the local source tree (this checkout), so it
|
|
10
|
+
# is buildable before the PyPI release. cutadapt arrives as a declared pip
|
|
11
|
+
# dependency and is invoked as a subprocess at runtime — no apt package needed
|
|
12
|
+
# (its manylinux wheel runs on the debian-slim base).
|
|
13
|
+
|
|
14
|
+
FROM python:3.12-slim
|
|
15
|
+
|
|
16
|
+
LABEL org.opencontainers.image.title="selexprep" \
|
|
17
|
+
org.opencontainers.image.description="Accession-first preprocessing for public HT-SELEX with primer auto-inference" \
|
|
18
|
+
org.opencontainers.image.source="https://github.com/marcorotanegroni/selexprep" \
|
|
19
|
+
org.opencontainers.image.licenses="MIT" \
|
|
20
|
+
org.opencontainers.image.version="0.1.0"
|
|
21
|
+
|
|
22
|
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
23
|
+
PYTHONUNBUFFERED=1 \
|
|
24
|
+
PIP_NO_CACHE_DIR=1 \
|
|
25
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
26
|
+
|
|
27
|
+
WORKDIR /build
|
|
28
|
+
|
|
29
|
+
# Copy only the files the build backend (hatchling) needs to produce the wheel.
|
|
30
|
+
# pyproject references README.md (readme) and LICENSE (license-files); the
|
|
31
|
+
# package code and bundled catalog CSV live under src/.
|
|
32
|
+
COPY pyproject.toml README.md LICENSE ./
|
|
33
|
+
COPY src ./src
|
|
34
|
+
|
|
35
|
+
RUN python -m pip install --upgrade pip \
|
|
36
|
+
&& python -m pip install . \
|
|
37
|
+
&& rm -rf /build
|
|
38
|
+
|
|
39
|
+
# Run as an unprivileged user; default working dir is a writable home.
|
|
40
|
+
RUN useradd --create-home --uid 1000 selex
|
|
41
|
+
USER selex
|
|
42
|
+
WORKDIR /home/selex
|
|
43
|
+
|
|
44
|
+
ENTRYPOINT ["selexprep"]
|
|
45
|
+
CMD ["--help"]
|
selexprep-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marco Rota Negroni
|
|
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.
|