scatrans 0.9.4.dev0__tar.gz → 0.9.5.dev0__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 (53) hide show
  1. scatrans-0.9.5.dev0/.github/workflows/ci.yml +70 -0
  2. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/.gitignore +2 -0
  3. scatrans-0.9.5.dev0/CITATION.cff +20 -0
  4. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/MANIFEST.in +5 -0
  5. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/PKG-INFO +1 -1
  6. scatrans-0.9.5.dev0/conftest.py +15 -0
  7. scatrans-0.9.5.dev0/conftest_fixtures.py +146 -0
  8. scatrans-0.9.5.dev0/coverage +0 -0
  9. {scatrans-0.9.4.dev0/.github → scatrans-0.9.5.dev0/github}/workflows/ci.yml +16 -6
  10. scatrans-0.9.5.dev0/github/workflows/publish.yml +74 -0
  11. scatrans-0.9.5.dev0/gitignore +174 -0
  12. scatrans-0.9.5.dev0/pre-commit-config.yaml +34 -0
  13. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/pyproject.toml +3 -0
  14. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/scatrans.egg-info/SOURCES.txt +19 -2
  15. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/_de.py +9 -5
  16. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/_permutation.py +6 -2
  17. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/_version.py +3 -3
  18. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/enrich.py +68 -71
  19. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/pl.py +53 -44
  20. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/pp_bias.py +14 -9
  21. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/qc.py +0 -2
  22. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/tl.py +18 -13
  23. scatrans-0.9.5.dev0/tests/__init__.py +0 -0
  24. scatrans-0.9.5.dev0/tests/conftest.py +7 -0
  25. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/tests/test_basic.py +15 -5
  26. scatrans-0.9.5.dev0/tests/test_de_backends.py +196 -0
  27. scatrans-0.9.5.dev0/tests/test_enrich_api.py +140 -0
  28. scatrans-0.9.5.dev0/tests/test_enrich_go.py +42 -0
  29. scatrans-0.9.5.dev0/tests/test_pl_coverage.py +61 -0
  30. scatrans-0.9.5.dev0/tests/test_pl_extended.py +59 -0
  31. scatrans-0.9.5.dev0/tests/test_pp_bias_cli.py +37 -0
  32. scatrans-0.9.5.dev0/tests/test_public_api.py +50 -0
  33. scatrans-0.9.5.dev0/tests/test_tl_coverage.py +301 -0
  34. scatrans-0.9.4.dev0/src/scatrans/_bias.py +0 -24
  35. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/.github/workflows/publish.yml +0 -0
  36. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/CHANGELOG.md +0 -0
  37. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/LICENSE +0 -0
  38. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/README.md +0 -0
  39. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/examples/memento_de_example.py +0 -0
  40. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/examples/real_data_template.py +0 -0
  41. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/examples/synthetic_active_transcription.py +0 -0
  42. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/setup.cfg +0 -0
  43. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/__init__.py +0 -0
  44. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/_utils.py +0 -0
  45. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/_velocity.py +0 -0
  46. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/data/Hs_GO_Biological_Process_2026.txt +0 -0
  47. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/data/Hs_KEGG_2026.txt +0 -0
  48. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/data/Mm_GO_Biological_Process_2026.txt +0 -0
  49. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/data/Mm_KEGG_2026.txt +0 -0
  50. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/data/Mus_musculus.GRCm39.115_gene_features.parquet +0 -0
  51. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/data/README.md +0 -0
  52. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/data/mouse_2020A_gene_features.parquet +0 -0
  53. {scatrans-0.9.4.dev0 → scatrans-0.9.5.dev0}/src/scatrans/generate_gene_features.py +0 -0
@@ -0,0 +1,70 @@
1
+ name: CI
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.9", "3.10", "3.11", "3.12"]
16
+ install-extra:
17
+ - ""
18
+ - "advanced"
19
+ - "pseudobulk"
20
+ - "gene_features"
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0
26
+
27
+ - name: Set up Python ${{ matrix.python-version }}
28
+ uses: actions/setup-python@v5
29
+ with:
30
+ python-version: ${{ matrix.python-version }}
31
+ cache: "pip"
32
+
33
+ - name: Install package with extras
34
+ run: |
35
+ pip install --upgrade pip
36
+ EXTRA="${{ matrix.install-extra }}"
37
+ if [ -n "$EXTRA" ]; then
38
+ pip install -e ".[dev,$EXTRA]"
39
+ else
40
+ pip install -e ".[dev]"
41
+ fi
42
+
43
+ - name: Ruff lint
44
+ run: |
45
+ ruff check src/scatrans tests
46
+ ruff format --check src/scatrans tests
47
+
48
+ - name: Run fast tests
49
+ run: PYTHONPATH=src:. python -m pytest -m "not plot and not slow" -q
50
+
51
+ - name: Run slow tests (core / Python 3.11 only)
52
+ if: matrix.python-version == '3.11' && matrix.install-extra == ''
53
+ run: PYTHONPATH=src:. python -m pytest -m "slow and not plot" -q
54
+
55
+ - name: Run plot tests (core / Python 3.11 only)
56
+ if: matrix.python-version == '3.11' && matrix.install-extra == ''
57
+ run: PYTHONPATH=src:. python -m pytest -m plot -q
58
+
59
+ - name: Coverage report (core / Python 3.11 only)
60
+ if: matrix.python-version == '3.11' && matrix.install-extra == ''
61
+ run: |
62
+ PYTHONPATH=src:. python -m pytest -m "not plot" --cov=src/scatrans --cov-report=xml -q \
63
+ || PYTHONPATH=src:. python -m pytest -m "not plot" -q
64
+
65
+ - name: Upload coverage (optional)
66
+ if: matrix.python-version == '3.11' && matrix.install-extra == ''
67
+ uses: codecov/codecov-action@v4
68
+ with:
69
+ files: ./coverage.xml
70
+ fail_ci_if_error: false
@@ -21,6 +21,8 @@ sdist/
21
21
  var/
22
22
  wheels/
23
23
  *.egg-info/
24
+ scatrans.egg-info/
25
+ src/scatrans.egg-info/
24
26
  .installed.cfg
25
27
  *.egg
26
28
  MANIFEST
@@ -0,0 +1,20 @@
1
+ cff-version: 1.2.0
2
+ title: "scATrans: Single-cell Active Transcription Analysis"
3
+ message: >-
4
+ If you use this software, please cite it using the metadata below.
5
+ type: software
6
+ authors:
7
+ - name: "scATrans Developers"
8
+ repository-code: "https://github.com/scATrans/scatrans"
9
+ url: "https://github.com/scATrans/scatrans"
10
+ license: Apache-2.0
11
+ version: 0.9.2
12
+ keywords:
13
+ - single-cell
14
+ - RNA-seq
15
+ - unspliced RNA
16
+ - nascent RNA
17
+ - active transcription
18
+ - bioinformatics
19
+ - differential expression
20
+ - gene set enrichment
@@ -7,6 +7,11 @@ include README.md
7
7
  include CHANGELOG.md
8
8
  include CITATION.cff
9
9
  include pyproject.toml
10
+ include conftest.py
11
+ include conftest_fixtures.py
12
+
13
+ # Include the full test suite so that `pytest` can be run from sdist/unpacked source
14
+ graft tests
10
15
 
11
16
  # Include the GitHub Actions workflows (requested)
12
17
  include .github/workflows/ci.yml
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scatrans
3
- Version: 0.9.4.dev0
3
+ Version: 0.9.5.dev0
4
4
  Summary: Single-cell Active Transcription Analysis
5
5
  Author: scATrans Developers
6
6
  License: Apache-2.0
@@ -0,0 +1,15 @@
1
+ """Root-level conftest.py.
2
+
3
+ Ensures project root and src/ are on sys.path (CI, --cov, editable installs,
4
+ unpacked sdists) and registers shared test fixtures via pytest_plugins.
5
+ """
6
+
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ root = Path(__file__).resolve().parent
11
+ for p in (str(root), str(root / "src")):
12
+ if p not in sys.path:
13
+ sys.path.insert(0, p)
14
+
15
+ pytest_plugins = ["conftest_fixtures"]
@@ -0,0 +1,146 @@
1
+ """Pytest plugin: shared AnnData fixtures for the scATrans test suite.
2
+
3
+ Loaded via ``pytest_plugins`` from root ``conftest.py`` (and ``tests/conftest.py``)
4
+ so fixtures are registered even when nested conftest discovery fails in CI.
5
+ """
6
+
7
+ import numpy as np
8
+ import pandas as pd
9
+ import pytest
10
+ import scanpy as sc
11
+
12
+
13
+ @pytest.fixture(scope="module")
14
+ def adata_basic():
15
+ """AnnData with spliced/unspliced layers + gene features."""
16
+ np.random.seed(42)
17
+ n_cells, n_genes = 120, 250
18
+ X = np.random.negative_binomial(4, 0.45, size=(n_cells, n_genes)).astype(float)
19
+ ad = sc.AnnData(X)
20
+ ad.obs["condition"] = ["Disease"] * 60 + ["Control"] * 60
21
+ ad.obs["sample"] = ["s" + str(i % 8) for i in range(n_cells)]
22
+ ad.layers["spliced"] = X.copy()
23
+ ad.layers["unspliced"] = X * 0.55
24
+ ad.var["gene_length"] = np.random.randint(700, 4500, n_genes)
25
+ ad.var["intron_number"] = np.random.randint(0, 12, n_genes)
26
+ return ad
27
+
28
+
29
+ @pytest.fixture(scope="module")
30
+ def adata_de_only():
31
+ """Count AnnData without velocity layers (pure DE path)."""
32
+ np.random.seed(99)
33
+ n_cells, n_genes = 80, 120
34
+ X = np.random.negative_binomial(5, 0.4, size=(n_cells, n_genes)).astype(float)
35
+ ad = sc.AnnData(X)
36
+ ad.obs["condition"] = ["Disease"] * 40 + ["Control"] * 40
37
+ ad.obs["sample"] = ["s" + str(i % 6) for i in range(n_cells)]
38
+ return ad
39
+
40
+
41
+ @pytest.fixture(scope="module")
42
+ def adata_small_reference():
43
+ """Synthetic data with a small reference group (empirical Bayes gamma)."""
44
+ np.random.seed(123)
45
+ n_ref, n_tgt, n_genes = 18, 80, 200
46
+ n_cells = n_ref + n_tgt
47
+ X = np.random.negative_binomial(4, 0.45, size=(n_cells, n_genes)).astype(float)
48
+ ad = sc.AnnData(X)
49
+ ad.obs["condition"] = ["Control"] * n_ref + ["Disease"] * n_tgt
50
+ ad.layers["spliced"] = X.copy()
51
+ ad.layers["unspliced"] = X * 0.5
52
+ ad.var["gene_length"] = np.random.randint(700, 4500, n_genes)
53
+ ad.var["intron_number"] = np.random.randint(0, 12, n_genes)
54
+ return ad
55
+
56
+
57
+ @pytest.fixture(scope="module")
58
+ def adata_high_unspliced():
59
+ """Very high unspliced fraction for qc warning path."""
60
+ np.random.seed(7)
61
+ n_cells, n_genes = 40, 50
62
+ X = np.random.negative_binomial(3, 0.5, size=(n_cells, n_genes)).astype(float)
63
+ ad = sc.AnnData(X)
64
+ ad.obs["condition"] = ["A"] * 20 + ["B"] * 20
65
+ ad.layers["spliced"] = X * 0.2
66
+ ad.layers["unspliced"] = X * 2.0
67
+ return ad
68
+
69
+
70
+ @pytest.fixture(scope="module")
71
+ def adata_mature_nascent():
72
+ """kb_python style layer names."""
73
+ np.random.seed(123)
74
+ n_cells, n_genes = 80, 180
75
+ X = np.random.negative_binomial(3, 0.5, size=(n_cells, n_genes)).astype(float)
76
+ ad = sc.AnnData(X)
77
+ ad.obs["condition"] = ["GA"] * 40 + ["Ctrl"] * 40
78
+ ad.layers["mature"] = X.copy()
79
+ ad.layers["nascent"] = X * 0.5
80
+ ad.var["gene_length"] = np.random.randint(800, 4000, n_genes)
81
+ ad.var["intron_number"] = np.random.randint(1, 9, n_genes)
82
+ return ad
83
+
84
+
85
+ @pytest.fixture(scope="module")
86
+ def adata_mixed_small():
87
+ """Small fixture for mixed-model + filter_active_genes tests."""
88
+ np.random.seed(42)
89
+ n_cells, n_genes = 60, 70
90
+ X = np.random.negative_binomial(3, 0.5, size=(n_cells, n_genes)).astype(float)
91
+ ad = sc.AnnData(X)
92
+ ad.obs["condition"] = ["Disease"] * 30 + ["Control"] * 30
93
+ ad.obs["sample"] = ["s" + str(i % 6) for i in range(n_cells)]
94
+ ad.layers["spliced"] = X.copy()
95
+ ad.layers["unspliced"] = X * 0.45
96
+ ad.var["gene_length"] = np.random.randint(600, 3500, n_genes)
97
+ ad.var["intron_number"] = np.random.randint(0, 8, n_genes)
98
+ return ad
99
+
100
+
101
+ @pytest.fixture(scope="module")
102
+ def adata_pb():
103
+ """Pseudobulk-oriented fixture (4 samples per group)."""
104
+ np.random.seed(11)
105
+ n_cells, n_genes = 96, 80
106
+ X = np.random.negative_binomial(6, 0.35, size=(n_cells, n_genes)).astype(float)
107
+ ad = sc.AnnData(X)
108
+ ad.obs["condition"] = ["Disease"] * 48 + ["Control"] * 48
109
+ ad.obs["sample"] = [f"S{i // 12}" for i in range(n_cells)]
110
+ ad.layers["spliced"] = X.copy()
111
+ ad.layers["unspliced"] = X * 0.5
112
+ return ad
113
+
114
+
115
+ @pytest.fixture(scope="module")
116
+ def results_df(adata_basic):
117
+ """Shared active_score table for plotting tests (one run per module)."""
118
+ import scatrans as scat
119
+
120
+ _, _, allr = scat.active_score(
121
+ adata_basic,
122
+ groupby="condition",
123
+ target_group="Disease",
124
+ reference_group="Control",
125
+ use_permutation=False,
126
+ show_plot=False,
127
+ )
128
+ return allr
129
+
130
+
131
+ @pytest.fixture(scope="module")
132
+ def enrich_df():
133
+ """Minimal enrichment result for plotting smoke tests."""
134
+ return pd.DataFrame(
135
+ {
136
+ "Term": ["T1", "T2", "T3"],
137
+ "Description": ["desc1", "desc2", "desc3"],
138
+ "Count": [5, 3, 8],
139
+ "GeneRatio": [0.1, 0.05, 0.2],
140
+ "FoldEnrichment": [2.0, 1.5, 3.0],
141
+ "pvalue": [0.001, 0.01, 0.0001],
142
+ "p.adjust": [0.01, 0.05, 0.001],
143
+ "neg_log10_padj": [2.0, 1.3, 3.0],
144
+ "Genes": ["G1;G2", "G2;G3", "G4;G5;G6"],
145
+ }
146
+ )
Binary file
@@ -13,7 +13,6 @@ jobs:
13
13
  fail-fast: false
14
14
  matrix:
15
15
  python-version: ["3.9", "3.10", "3.11", "3.12"]
16
- # Core + each optional extra (some may be heavy / have native deps)
17
16
  install-extra:
18
17
  - ""
19
18
  - "advanced"
@@ -23,7 +22,7 @@ jobs:
23
22
  steps:
24
23
  - uses: actions/checkout@v4
25
24
  with:
26
- fetch-depth: 0 # Good practice for setuptools_scm (version detection)
25
+ fetch-depth: 0
27
26
 
28
27
  - name: Set up Python ${{ matrix.python-version }}
29
28
  uses: actions/setup-python@v5
@@ -46,13 +45,24 @@ jobs:
46
45
  ruff check src/scatrans tests
47
46
  ruff format --check src/scatrans tests
48
47
 
49
- - name: Run tests (with coverage when possible)
50
- run: |
51
- pytest --cov=src/scatrans --cov-report=xml -q || pytest -q
48
+ - name: Run fast tests
49
+ run: PYTHONPATH=src:. python -m pytest -m "not plot and not slow" -q
50
+
51
+ - name: Run slow tests (core / Python 3.11 only)
52
+ if: matrix.python-version == '3.11' && matrix.install-extra == ''
53
+ run: PYTHONPATH=src:. python -m pytest -m "slow and not plot" -q
54
+
55
+ - name: Run plot tests (core / Python 3.11 only)
56
+ if: matrix.python-version == '3.11' && matrix.install-extra == ''
57
+ run: PYTHONPATH=src:. python -m pytest -m plot -q
58
+
59
+ - name: Coverage report (core / Python 3.11 only)
60
+ if: matrix.python-version == '3.11' && matrix.install-extra == ''
61
+ run: PYTHONPATH=src:. python -m pytest -m "not plot" --cov=src/scatrans --cov-report=xml -q
52
62
 
53
63
  - name: Upload coverage (optional)
54
64
  if: matrix.python-version == '3.11' && matrix.install-extra == ''
55
65
  uses: codecov/codecov-action@v4
56
66
  with:
57
67
  files: ./coverage.xml
58
- fail_ci_if_error: false
68
+ fail_ci_if_error: false
@@ -0,0 +1,74 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ release:
8
+ types: [published]
9
+ workflow_dispatch:
10
+ inputs:
11
+ version:
12
+ description: "Force a specific version (SETUPTOOLS_SCM_PRETEND_VERSION). Useful for dev releases when not on a tag."
13
+ required: false
14
+ default: ""
15
+
16
+ jobs:
17
+ build:
18
+ name: Build distribution 📦
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ with:
23
+ fetch-depth: 0 # Critical for setuptools_scm to detect tags and produce correct version
24
+
25
+ - name: Set up Python
26
+ uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.11"
29
+
30
+ - name: Install build tools
31
+ run: python -m pip install --upgrade build
32
+
33
+ - name: Build source and wheel distributions
34
+ run: |
35
+ if [ -n "${{ github.event.inputs.version }}" ]; then
36
+ echo "Using forced version: ${{ github.event.inputs.version }}"
37
+ SETUPTOOLS_SCM_PRETEND_VERSION="${{ github.event.inputs.version }}" python -m build
38
+ else
39
+ python -m build
40
+ fi
41
+
42
+ - name: Upload distribution artifacts
43
+ uses: actions/upload-artifact@v4
44
+ with:
45
+ name: python-package-distributions
46
+ path: dist/
47
+
48
+ publish:
49
+ name: Publish to PyPI
50
+ needs: build
51
+ runs-on: ubuntu-latest
52
+
53
+ # Required for Trusted Publishing (OIDC) - no API token secret needed
54
+ permissions:
55
+ id-token: write
56
+
57
+ # Recommended: tie to a protected GitHub Environment (create "pypi" environment in repo settings)
58
+ # You can add required reviewers or branch restrictions in the environment settings.
59
+ # environment:
60
+ # name: pypi
61
+
62
+ steps:
63
+ - name: Download all dists
64
+ uses: actions/download-artifact@v4
65
+ with:
66
+ name: python-package-distributions
67
+ path: dist/
68
+
69
+ - name: Publish distribution 📦 to PyPI
70
+ uses: pypa/gh-action-pypi-publish@release/v1
71
+ # For publishing to TestPyPI instead (for testing the workflow):
72
+ # with:
73
+ # repository-url: https://test.pypi.org/legacy/
74
+ # verbose: true
@@ -0,0 +1,174 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ scatrans.egg-info/
25
+ src/scatrans.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ *.manifest
32
+ *.spec
33
+
34
+ # Installer logs
35
+ pip-log.txt
36
+ pip-delete-this-directory.txt
37
+
38
+ # Unit test / coverage reports
39
+ htmlcov/
40
+ .tox/
41
+ .nox/
42
+ .coverage
43
+ .coverage.*
44
+ .cache
45
+ nosetests.xml
46
+ coverage.xml
47
+ *.cover
48
+ *.py,cover
49
+ .hypothesis/
50
+ .pytest_cache/
51
+ cover/
52
+
53
+ # Translations
54
+ *.mo
55
+ *.pot
56
+
57
+ # Django stuff:
58
+ *.log
59
+ local_settings.py
60
+ db.sqlite3
61
+ db.sqlite3-journal
62
+
63
+ # Flask stuff:
64
+ instance/
65
+ .webassets-cache
66
+
67
+ # Scrapy stuff:
68
+ .scrapy
69
+
70
+ # Sphinx documentation
71
+ docs/_build/
72
+
73
+ # PyBuilder
74
+ .pybuilder/
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ Pipfile.lock
89
+
90
+ # poetry
91
+ poetry.lock
92
+
93
+ # pdm
94
+ .pdm.toml
95
+ .pdm-python
96
+ .pdm-build/
97
+
98
+ # PEP 582
99
+ __pypackages__/
100
+
101
+ # Celery stuff
102
+ celerybeat-schedule
103
+ celerybeat.pid
104
+
105
+ # SageMath parsed files
106
+ *.sage.py
107
+
108
+ # Environments
109
+ .env
110
+ .venv
111
+ env/
112
+ venv/
113
+ ENV/
114
+ env.bak/
115
+ venv.bak/
116
+
117
+ # Spyder project settings
118
+ .spyderproject
119
+ .spyproject
120
+
121
+ # Rope project settings
122
+ .ropeproject
123
+
124
+ # mkdocs documentation
125
+ /site
126
+
127
+ # mypy
128
+ .mypy_cache/
129
+ .dmypy.json
130
+ dmypy.json
131
+
132
+ # Pyre type checker
133
+ .pyre/
134
+
135
+ # pytype static type analyzer
136
+ .pytype/
137
+
138
+ # Cython debug symbols
139
+ cython_debug/
140
+
141
+ # Ruff
142
+ .ruff_cache/
143
+
144
+ # IDE / editors
145
+ .idea/
146
+ .vscode/
147
+ *.swp
148
+ *.swo
149
+ *~
150
+
151
+ # OS generated files
152
+ .DS_Store
153
+ .DS_Store?
154
+ ._*
155
+ .Spotlight-V100
156
+ .Trashes
157
+ ehthumbs.db
158
+ Thumbs.db
159
+
160
+ # Project specific
161
+ # Bundled large data is committed intentionally (gene features)
162
+ # but do not add user-generated .parquet outputs here by mistake
163
+ *.h5ad
164
+ *.loom
165
+ *.zarr
166
+ # Keep source data/ but ignore generated outputs at root
167
+ gene_features.parquet
168
+ *_gene_features.parquet
169
+ *_features.parquet
170
+ # Temporary analysis outputs
171
+ *.pdf
172
+ *.png
173
+ *.svg
174
+ active_results/
@@ -0,0 +1,34 @@
1
+ # Pre-commit hooks for scATrans
2
+ # Install: pip install pre-commit
3
+ # Setup: pre-commit install
4
+ # Run manually: pre-commit run --all-files
5
+
6
+ repos:
7
+ - repo: https://github.com/astral-sh/ruff-pre-commit
8
+ rev: v0.4.4
9
+ hooks:
10
+ - id: ruff
11
+ args: [--fix, --exit-non-zero-on-fix]
12
+ - id: ruff-format
13
+
14
+ - repo: https://github.com/pre-commit/mirrors-mypy
15
+ rev: v1.10.0
16
+ hooks:
17
+ - id: mypy
18
+ additional_dependencies: []
19
+ args: [--ignore-missing-imports, --no-error-summary]
20
+ # mypy on the src layout; relax for now to avoid blocking on third-party stubs
21
+ exclude: |
22
+ (?x)^(
23
+ tests/|
24
+ backup/|
25
+ src/scatrans/_version.py
26
+ )
27
+
28
+ # Optional pyright (static type checker, often stricter). Requires node + pyright.
29
+ # Uncomment if you have pyright in your env (npm i -g pyright or via pyright package).
30
+ # - repo: https://github.com/RobertCraigie/pyright-python
31
+ # rev: v1.1.367
32
+ # hooks:
33
+ # - id: pyright
34
+ # additional_dependencies: [".[dev]"]
@@ -108,6 +108,9 @@ indent-style = "space"
108
108
  [tool.pytest.ini_options]
109
109
  minversion = "7.0"
110
110
  testpaths = ["tests"]
111
+ # Ensure the project root is on sys.path for fixture discovery and src-layout editable installs
112
+ # (helps in CI, zip extractions, and when cwd differs slightly)
113
+ pythonpath = ["src", "."]
111
114
  # Daily dev: skip plot + slow. Override examples:
112
115
  # pytest -m "not plot" # include slow integration tests
113
116
  # pytest -m plot # plotting only
@@ -1,9 +1,15 @@
1
1
  .gitignore
2
2
  CHANGELOG.md
3
+ CITATION.cff
3
4
  LICENSE
4
5
  MANIFEST.in
5
6
  PKG-INFO
6
7
  README.md
8
+ conftest.py
9
+ conftest_fixtures.py
10
+ coverage
11
+ gitignore
12
+ pre-commit-config.yaml
7
13
  pyproject.toml
8
14
  setup.cfg
9
15
  .github/workflows/ci.yml
@@ -11,8 +17,9 @@ setup.cfg
11
17
  examples/memento_de_example.py
12
18
  examples/real_data_template.py
13
19
  examples/synthetic_active_transcription.py
20
+ github/workflows/ci.yml
21
+ github/workflows/publish.yml
14
22
  src/scatrans/__init__.py
15
- src/scatrans/_bias.py
16
23
  src/scatrans/_de.py
17
24
  src/scatrans/_permutation.py
18
25
  src/scatrans/_utils.py
@@ -31,4 +38,14 @@ src/scatrans/data/Mm_KEGG_2026.txt
31
38
  src/scatrans/data/Mus_musculus.GRCm39.115_gene_features.parquet
32
39
  src/scatrans/data/README.md
33
40
  src/scatrans/data/mouse_2020A_gene_features.parquet
34
- tests/test_basic.py
41
+ tests/__init__.py
42
+ tests/conftest.py
43
+ tests/test_basic.py
44
+ tests/test_de_backends.py
45
+ tests/test_enrich_api.py
46
+ tests/test_enrich_go.py
47
+ tests/test_pl_coverage.py
48
+ tests/test_pl_extended.py
49
+ tests/test_pp_bias_cli.py
50
+ tests/test_public_api.py
51
+ tests/test_tl_coverage.py