scatrans 0.9.6.dev0__tar.gz → 0.9.8.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.
- scatrans-0.9.8.dev0/.pre-commit-config.yaml +34 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/CHANGELOG.md +10 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/PKG-INFO +1 -1
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/scatrans.egg-info/SOURCES.txt +1 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/_permutation.py +0 -1
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/_version.py +3 -3
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/tl.py +12 -11
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_basic.py +19 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_enrich_api.py +6 -4
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_pp_bias_cli.py +2 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/.github/workflows/ci.yml +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/.github/workflows/publish.yml +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/.gitignore +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/CITATION.cff +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/LICENSE +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/MANIFEST.in +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/README.md +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/conftest.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/conftest_fixtures.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/examples/memento_de_example.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/examples/real_data_template.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/examples/synthetic_active_transcription.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/pyproject.toml +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/setup.cfg +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/__init__.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/_bias.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/_de.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/_utils.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/_velocity.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/DATA_LICENSES.md +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/Hs_GO_Biological_Process_2026.txt +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/Hs_KEGG_2026.txt +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/Mm_GO_Biological_Process_2026.txt +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/Mm_KEGG_2026.txt +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/Mus_musculus.GRCm39.115_gene_features.parquet +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/README.md +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/human_GRCh38_2024A_gene_features.parquet +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/mouse_2020A_gene_features.parquet +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/enrich.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/generate_gene_features.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/pl.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/pp_bias.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/qc.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/__init__.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/conftest.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_de_backends.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_enrich_go.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_pl_coverage.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_pl_extended.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_public_api.py +0 -0
- {scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/tests/test_tl_coverage.py +0 -0
|
@@ -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]"]
|
|
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.9.2 bugfix 2026-07-02]
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **filter_active_genes permissive mode**: default/permissive thresholds for `pval_cutoff`, `active_score_fdr_cutoff`, and `unspliced_excess_fdr_cutoff` now use `float("inf")` instead of `1.0`, so genes with adjusted p-value or permutation FDR exactly equal to 1.0 are no longer silently dropped (strict `<` vs `1.0` bug).
|
|
12
|
+
- **CI lint**: removed unused `import scanpy as sc` from `tl.py` and `_permutation.py` (leftover from permutation refactor); fixed `test_enrich_api.py` formatting.
|
|
13
|
+
- **CI tests**: `test_pp_bias_cli` GTF generator tests now `pytest.importorskip("gtfparse")` so base installs without `scatrans[gene_features]` skip instead of failing.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Regression test `test_filter_active_genes_permissive_keeps_padj_one`.
|
|
17
|
+
|
|
8
18
|
## [Unreleased / Review 2026-06-27]
|
|
9
19
|
### Added / Improved
|
|
10
20
|
- Clarified and documented the `gamma_method="empirical_bayes"` implementation as **hierarchical (分层) gamma estimation** for the reference U/S ratio (README keeps the CN term; source now English-only).
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.9.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 9,
|
|
21
|
+
__version__ = version = '0.9.8.dev0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 9, 8, 'dev0')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id =
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -23,7 +23,6 @@ import anndata as ad
|
|
|
23
23
|
import joblib
|
|
24
24
|
import numpy as np
|
|
25
25
|
import pandas as pd
|
|
26
|
-
import scanpy as sc
|
|
27
26
|
import scipy.sparse as sparse # for type hints in signatures (e.g. spmatrix)
|
|
28
27
|
|
|
29
28
|
# qc is imported lazily inside active_score to keep startup light, but exposed at package level
|
|
@@ -36,13 +35,13 @@ from ._utils import (
|
|
|
36
35
|
UNSPLICED_EXCESS_FDR_COL,
|
|
37
36
|
UNSPLICED_EXCESS_PVAL_COL,
|
|
38
37
|
UNSPLICED_EXCESS_RESIDUAL_COL,
|
|
38
|
+
_apply_de_preprocess,
|
|
39
|
+
_clear_log_preprocess_metadata,
|
|
39
40
|
_get_exponential_scale_lambda,
|
|
40
41
|
_is_integer_counts_like,
|
|
41
42
|
_normalize_group_label,
|
|
42
43
|
_normalize_velocity_layers_by_size_factor,
|
|
43
44
|
_pseudobulk_with_layers,
|
|
44
|
-
_apply_de_preprocess,
|
|
45
|
-
_clear_log_preprocess_metadata,
|
|
46
45
|
_resolve_aligned_raw_counts,
|
|
47
46
|
_soft_scale,
|
|
48
47
|
_validate_group_contrast,
|
|
@@ -2104,12 +2103,12 @@ def filter_active_genes(
|
|
|
2104
2103
|
elif p in ("permissive", "none", "all", "no_filter"):
|
|
2105
2104
|
preset_vals = {
|
|
2106
2105
|
"active_score_cutoff": 0.0,
|
|
2107
|
-
"pval_cutoff":
|
|
2106
|
+
"pval_cutoff": float("inf"),
|
|
2108
2107
|
"velocity_residual_cutoff": float("-inf"),
|
|
2109
2108
|
"unspliced_excess_residual_cutoff": float("-inf"),
|
|
2110
2109
|
"logfc_cutoff": float("inf"),
|
|
2111
|
-
"active_score_fdr_cutoff":
|
|
2112
|
-
"unspliced_excess_fdr_cutoff":
|
|
2110
|
+
"active_score_fdr_cutoff": float("inf"),
|
|
2111
|
+
"unspliced_excess_fdr_cutoff": float("inf"),
|
|
2113
2112
|
"effective_gamma_min": float("-inf"),
|
|
2114
2113
|
"effective_gamma_max": None,
|
|
2115
2114
|
"delta_variance_min": None,
|
|
@@ -2143,10 +2142,10 @@ def filter_active_genes(
|
|
|
2143
2142
|
"active_score_cutoff",
|
|
2144
2143
|
)
|
|
2145
2144
|
pval_cutoff = _coerce_numeric_cutoff(
|
|
2146
|
-
_resolve("pval_cutoff", pval_cutoff,
|
|
2145
|
+
_resolve("pval_cutoff", pval_cutoff, float("inf")), float("inf"), "pval_cutoff"
|
|
2147
2146
|
)
|
|
2148
|
-
if not math.isfinite(pval_cutoff)
|
|
2149
|
-
raise ValueError("pval_cutoff must be
|
|
2147
|
+
if pval_cutoff < 0 or (not math.isfinite(pval_cutoff) and not math.isinf(pval_cutoff)):
|
|
2148
|
+
raise ValueError("pval_cutoff must be non-negative, finite, or +inf (permissive).")
|
|
2150
2149
|
if (
|
|
2151
2150
|
velocity_residual_cutoff is not _NOT_PROVIDED
|
|
2152
2151
|
and unspliced_excess_residual_cutoff is _NOT_PROVIDED
|
|
@@ -2175,9 +2174,11 @@ def filter_active_genes(
|
|
|
2175
2174
|
raise ValueError(
|
|
2176
2175
|
f'logfc_direction={logfc_direction!r} not recognized. Use one of: "up", "down", "both".'
|
|
2177
2176
|
)
|
|
2178
|
-
active_score_fdr_cutoff = _resolve(
|
|
2177
|
+
active_score_fdr_cutoff = _resolve(
|
|
2178
|
+
"active_score_fdr_cutoff", active_score_fdr_cutoff, float("inf")
|
|
2179
|
+
)
|
|
2179
2180
|
unspliced_excess_fdr_cutoff = _resolve(
|
|
2180
|
-
"unspliced_excess_fdr_cutoff", unspliced_excess_fdr_cutoff,
|
|
2181
|
+
"unspliced_excess_fdr_cutoff", unspliced_excess_fdr_cutoff, float("inf")
|
|
2181
2182
|
)
|
|
2182
2183
|
effective_gamma_min = _resolve("effective_gamma_min", effective_gamma_min, float("-inf"))
|
|
2183
2184
|
effective_gamma_max = _resolve("effective_gamma_max", effective_gamma_max, None)
|
|
@@ -161,6 +161,25 @@ def test_filter_active_genes_permissive_inf_logfc(adata_basic):
|
|
|
161
161
|
assert len(out) == len(allr)
|
|
162
162
|
|
|
163
163
|
|
|
164
|
+
def test_filter_active_genes_permissive_keeps_padj_one():
|
|
165
|
+
"""Default/permissive mode must not drop genes with p_adj or FDR exactly 1.0."""
|
|
166
|
+
df = pd.DataFrame(
|
|
167
|
+
{
|
|
168
|
+
"logFC": [0.1, -0.2, 0.5, -0.9, 0.0],
|
|
169
|
+
"p_val": [1.0, 0.9, 0.5, 0.2, 1.0],
|
|
170
|
+
"p_adj": [1.0, 1.0, 0.8, 0.3, 1.0],
|
|
171
|
+
"active_score_fdr": [1.0, 0.9, 0.5, 0.2, 1.0],
|
|
172
|
+
"unspliced_excess_fdr": [1.0, 1.0, 0.8, 0.3, 1.0],
|
|
173
|
+
},
|
|
174
|
+
index=[f"g{i}" for i in range(5)],
|
|
175
|
+
)
|
|
176
|
+
out_default = scat.filter_active_genes(df)
|
|
177
|
+
out_permissive = scat.filter_active_genes(df, preset="permissive")
|
|
178
|
+
assert len(out_default) == 5
|
|
179
|
+
assert len(out_permissive) == 5
|
|
180
|
+
assert set(out_default.index) == set(df.index)
|
|
181
|
+
|
|
182
|
+
|
|
164
183
|
def test_add_gene_features_and_list(adata_basic):
|
|
165
184
|
# Should not crash even if features are incomplete
|
|
166
185
|
adata_basic.var.columns.tolist()
|
|
@@ -53,7 +53,11 @@ def test_extract_gene_lists_single_df():
|
|
|
53
53
|
def test_extract_gene_lists_prefers_gene_column_over_range_index():
|
|
54
54
|
"""Scanpy-style DE tables use a 'gene'/'names' column with a default RangeIndex."""
|
|
55
55
|
df = pd.DataFrame(
|
|
56
|
-
{
|
|
56
|
+
{
|
|
57
|
+
"gene": ["G_up", "G_down", "G_ns"],
|
|
58
|
+
"logFC": [1.2, -0.9, 0.1],
|
|
59
|
+
"p_adj": [0.01, 0.02, 0.5],
|
|
60
|
+
},
|
|
57
61
|
)
|
|
58
62
|
out = scat.extract_gene_lists(df, logfc_cutoff=0.5, pval_cutoff=0.05, logfc_direction="up")
|
|
59
63
|
assert out["contrast"] == ["G_up"]
|
|
@@ -67,9 +71,7 @@ def test_extract_gene_lists_separate_directions_single_df_matches_dict():
|
|
|
67
71
|
single = scat.extract_gene_lists(
|
|
68
72
|
df, logfc_direction="up", separate_directions=True, name_prefix="X"
|
|
69
73
|
)
|
|
70
|
-
multi = scat.extract_gene_lists(
|
|
71
|
-
{"X": df}, logfc_direction="up", separate_directions=True
|
|
72
|
-
)
|
|
74
|
+
multi = scat.extract_gene_lists({"X": df}, logfc_direction="up", separate_directions=True)
|
|
73
75
|
assert single == multi
|
|
74
76
|
assert single == {"X_up": ["G1", "G3"], "X_down": ["G2", "G4"]}
|
|
75
77
|
|
|
@@ -8,6 +8,7 @@ import scatrans as scat
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def test_generate_gene_features_no_exon_rows(tmp_path):
|
|
11
|
+
pytest.importorskip("gtfparse")
|
|
11
12
|
from scatrans.pp_bias import generate_gene_features_from_gtf
|
|
12
13
|
|
|
13
14
|
gtf = tmp_path / "no_exon.gtf"
|
|
@@ -22,6 +23,7 @@ def test_generate_gene_features_no_exon_rows(tmp_path):
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def test_generate_gene_features_dedup_gene_names(tmp_path):
|
|
26
|
+
pytest.importorskip("gtfparse")
|
|
25
27
|
from scatrans.pp_bias import generate_gene_features_from_gtf
|
|
26
28
|
|
|
27
29
|
gtf = tmp_path / "dup.gtf"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/Hs_GO_Biological_Process_2026.txt
RENAMED
|
File without changes
|
|
File without changes
|
{scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/Mm_GO_Biological_Process_2026.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scatrans-0.9.6.dev0 → scatrans-0.9.8.dev0}/src/scatrans/data/mouse_2020A_gene_features.parquet
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|