tablassert 7.4.13__tar.gz → 7.5.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.
- {tablassert-7.4.13 → tablassert-7.5.0}/CHANGELOG.md +18 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/PKG-INFO +1 -1
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/api/lib.md +18 -14
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/api/qc.md +6 -6
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/api/utils.md +26 -7
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/changelog.md +7 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/cli.md +2 -2
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/configuration/advanced-example.md +19 -21
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/configuration/graph.md +16 -16
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/configuration/table.md +37 -30
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/docker.md +6 -4
- {tablassert-7.4.13 → tablassert-7.5.0}/pyproject.toml +2 -2
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/lib.py +22 -7
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_lib.py +89 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/uv.lock +153 -128
- {tablassert-7.4.13 → tablassert-7.5.0}/.github/workflows/docker.yml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/.github/workflows/docs.yml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/.github/workflows/pipy.yml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/.gitignore +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/.pre-commit-config.yaml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/AGENTS.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/CITATION.cff +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/CONTRIBUTING.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/Dockerfile +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/LICENSE +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/README.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/api/fullmap.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/datassert.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/examples/tutorial-data.csv +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/examples/tutorial-graph.yaml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/examples/tutorial-table.yaml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/examples.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/index.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/installation.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/docs/tutorial.md +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/llms.txt +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/mkdocs.yml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/__init__.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/cli.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/downloader.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/enums.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/fullmap.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/ingests.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/log.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/models.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/nlp.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/progress.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/qc.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/src/tablassert/utils.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/__init__.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/conftest.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/fixtures/invalid_section_missing_source.yaml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/fixtures/minimal_section.yaml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/fixtures/minimal_section_with_sections.yaml +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_downloader.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_enums.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_fullmap.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_ingests.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_models.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_nlp.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_qc.py +0 -0
- {tablassert-7.4.13 → tablassert-7.5.0}/tests/test_utils.py +0 -0
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## 7.5.0 - 2026-07-01
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Publication CURIEs in `compile_subgraph()` (`lib.py`) now use the `PMCID:` namespace prefix for PubMed Central sources. A `repo: PMC` section with `publication: PMC11708054` is emitted as `PMCID:PMC11708054` (previously `PMC:PMC11708054`); non-PMC repos such as `PMID` are unaffected and continue to emit `<repo>:<publication>` (e.g., `PMID:11708054`). The `repository` edge column is unchanged and still records the raw `repo` value. Extracted via a new `publication_curie()` helper.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- New `<col> table literal value` edge column for subject, object, and qualifier nodes encoded with `method: column`. Unlike the existing `original <col>` column (which snapshots the value *after* all `fill`/`explode_by`/`regex`/`remove`/`prefix`/`suffix`/`transformations`), `<col> table literal value` captures the pristine source-cell value *before* any transformation. Emitted only for column-encoded nodes; annotations and `method: value` nodes are unaffected. Implemented via a `table_literal` flag on `Tcode.encoding()`, enabled by `Tcode.node()`.
|
|
12
|
+
- Four regression tests in `test_lib.py`: `publication_curie()` for PMC and PMID namespaces, and two `Tcode` tcode-inspection tests covering presence/ordering of the table-literal column for column encodings and its absence for value encodings.
|
|
13
|
+
|
|
14
|
+
### Documentation
|
|
15
|
+
- Comprehensive accuracy pass across the API, configuration, and Docker documentation, reconciling every page against the current codebase. Highlights: corrected invalid examples that would not load (`syntax: TC2`; `publication` integers and missing `PMC` prefixes; a non-existent `Qualifiers` member; `reindex` placed at section level; a subject missing `method: column`), fixed wrong field types (`rows`/`row_slice`/`taxon` → `PositiveInt`, `remove` → regex patterns), corrected the QC fuzzy thresholds (`fuzz.ratio >= 20 OR partial_token_sort_ratio >= 30`), removed a non-existent `uuid:` prefix from `utils.md` return examples, fixed the `resolve_many()` parameter order and added the original-column-capture and optional QC-audit pipeline steps, corrected graph-config path resolution (CWD, not config-relative) and processing-flow ordering, documented the strict QC GPU no-fallback behavior and the `.cachassert/` working directory, and aligned `Categories` enum member names (`GENE`/`PROTEIN`) and Docker CI triggers with the source.
|
|
16
|
+
|
|
17
|
+
## 7.4.14 - 2026-06-30
|
|
18
|
+
|
|
19
|
+
### Changes
|
|
20
|
+
- Extended `sig()` in `lib.py` to select a p-value column by fuzzy matching rather than requiring an exact `"p value"` name. All schema columns whose names contain the substring `"p value"` are now considered candidates; `fuzz.ratio` (rapidfuzz) scores each against the literal `"p value"` and the highest-scoring column is used to compute the `"significant"` output. An exact `"p value"` column scores 100 and is always preferred; columns like `"adjusted p value"` or `"log p value"` are used only when no exact match is present. If no column contains the substring the function continues to emit `"UNSURE"` for all rows.
|
|
21
|
+
- Added five regression tests in `test_lib.py` covering: exact-match preference, non-exact fallback, closest-match selection among multiple non-exact candidates, no-p-value column (UNSURE), and null value handling.
|
|
22
|
+
|
|
5
23
|
## 7.4.13 - 2026-06-30
|
|
6
24
|
|
|
7
25
|
### Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tablassert
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.5.0
|
|
4
4
|
Summary: Extract knowledge assertions from tabular data into NCATS Translator-compliant KGX NDJSON — declaratively, with entity resolution and quality control built in.
|
|
5
5
|
Project-URL: Homepage, https://github.com/SkyeAv/Tablassert
|
|
6
6
|
Project-URL: Source, https://github.com/SkyeAv/Tablassert
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The `lib` module exposes `resolve_many()`, a high-level convenience function for resolving an iterable of entity strings to CURIEs without requiring manual LazyFrame construction, NLP preprocessing, or DuckDB shard management.
|
|
4
4
|
|
|
5
|
-
It wraps the lower-level [`resolve()`](fullmap.md) pipeline — applying `level_one` and `level_two` normalization, opening all 10 DuckDB shard connections, executing entity resolution, and returning results as a plain Python list of row dictionaries.
|
|
5
|
+
It wraps the lower-level [`resolve()`](fullmap.md) pipeline — preserving the original input text, applying `level_one` and `level_two` normalization, opening all 10 DuckDB shard connections, executing entity resolution, optionally running the QC audit (when `qc=True`), and returning results as a plain Python list of row dictionaries.
|
|
6
6
|
|
|
7
7
|
## resolve_many()
|
|
8
8
|
|
|
@@ -18,8 +18,8 @@ def resolve_many(
|
|
|
18
18
|
taxon: Optional[str] = None,
|
|
19
19
|
prioritize: Optional[list[Categories]] = None,
|
|
20
20
|
avoid: Optional[list[Categories]] = None,
|
|
21
|
-
column_context: bool = True,
|
|
22
21
|
qc: bool = False,
|
|
22
|
+
column_context: bool = True,
|
|
23
23
|
) -> list[dict[str, Any]]
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -52,29 +52,29 @@ Each shard contains:
|
|
|
52
52
|
|
|
53
53
|
Optional NCBI Taxon ID for filtering results to a specific organism.
|
|
54
54
|
|
|
55
|
-
Example: `"9606"` restricts matches to human-specific
|
|
55
|
+
Example: `"9606"` restricts **gene** matches to human-specific entries; non-gene categories (e.g., diseases, chemicals) are returned regardless of taxon. When `None`, no taxon filtering is applied and matches from all organisms are returned.
|
|
56
56
|
|
|
57
57
|
**`prioritize: Optional[list[Categories]]` (default: `None`)**
|
|
58
58
|
|
|
59
59
|
Optional list of Biolink categories to prefer when multiple matches exist for the same input term. Categories listed here receive higher ranking scores during resolution.
|
|
60
60
|
|
|
61
|
-
Example: `[Categories.
|
|
61
|
+
Example: `[Categories.GENE, Categories.PROTEIN]` prefers gene and protein mappings over other categories like diseases or chemicals.
|
|
62
62
|
|
|
63
63
|
**`avoid: Optional[list[Categories]]` (default: `None`)**
|
|
64
64
|
|
|
65
65
|
Optional list of Biolink categories to exclude from results entirely. Any match belonging to an avoided category is filtered out before ranking.
|
|
66
66
|
|
|
67
|
-
Example: `[Categories.
|
|
67
|
+
Example: `[Categories.GENE]` prevents gene mappings from appearing in the output, even if they would otherwise be the best match.
|
|
68
68
|
|
|
69
69
|
**`column_context: bool` (default: `True`)**
|
|
70
70
|
|
|
71
|
-
Controls category-frequency tie-breaking when multiple matches exist for a term. When `True`, the
|
|
71
|
+
Controls category-frequency tie-breaking when multiple matches exist for a term. When `True`, the deduplication stage adds a category-frequency score (computed in Polars after the SQL query) and prefers the category that appears most frequently across all matched terms in the batch. When `False`, frequency-based tie-breaking is disabled.
|
|
72
72
|
|
|
73
73
|
This is useful when resolving a column of related entities (e.g., all genes) — the shared context helps disambiguate terms that map to multiple categories.
|
|
74
74
|
|
|
75
75
|
**`qc: bool` (default: `False`)**
|
|
76
76
|
|
|
77
|
-
When `True`, runs the QC audit stage after entity resolution. The QC pipeline validates mappings through a three-stage audit: exact match, fuzzy matching via rapidfuzz, and BioBERT sentence embeddings with cosine similarity. Requires a QC runtime to be installed (`tablassert[qc]` or `tablassert[qc-cuda]`). The ONNX Runtime provider is auto-detected based on the installed package — CUDA is preferred when `onnxruntime-gpu` is available
|
|
77
|
+
When `True`, runs the QC audit stage after entity resolution. The QC pipeline validates mappings through a three-stage audit: exact match, fuzzy matching via rapidfuzz, and BioBERT sentence embeddings with cosine similarity. Mappings that fail all three stages are dropped from the returned list (in addition to the unresolved-entity filtering performed by `resolve()`). Requires a QC runtime to be installed (`tablassert[qc]` or `tablassert[qc-cuda]`). The ONNX Runtime provider is auto-detected based on the installed package — CUDA is preferred when `onnxruntime-gpu` is installed and `CUDAExecutionProvider` is available; if only `onnxruntime` (CPU) is installed, CPU is used. Note: if `onnxruntime-gpu` is installed but `CUDAExecutionProvider` is unavailable, QC raises rather than falling back to CPU.
|
|
78
78
|
|
|
79
79
|
### Return Value
|
|
80
80
|
|
|
@@ -101,13 +101,17 @@ Each dictionary contains the following keys (where `{col}` is the value of the `
|
|
|
101
101
|
|
|
102
102
|
1. **Series construction** — Wraps the input iterable in a `pl.Series` with the given column name, then converts to a single-column `pl.LazyFrame`.
|
|
103
103
|
|
|
104
|
-
2. **
|
|
104
|
+
2. **Original column capture** — Copies the raw input column into `original {col}` via `column(lf, add("original ", col), col)` so the pre-normalization text is preserved in the output.
|
|
105
|
+
|
|
106
|
+
3. **NLP normalization** — Applies `level_one()` (whitespace stripping + lowercasing) and `level_two()` (non-word character removal via `\W+`) to produce the two normalized columns required by `resolve()`.
|
|
107
|
+
|
|
108
|
+
4. **DuckDB connection management** — Opens all 10 shard connections inside a `contextlib.ExitStack`, ensuring every connection is properly closed when resolution completes or if an error occurs.
|
|
105
109
|
|
|
106
|
-
|
|
110
|
+
5. **Entity resolution** — Delegates to `fullmap.resolve()` which queries the sharded DuckDB database, ranks matches by category priority, preferred-name exactness, NLP level, and category frequency, then deduplicates to one CURIE per input string.
|
|
107
111
|
|
|
108
|
-
|
|
112
|
+
6. **QC audit (optional)** — When `qc=True`, runs `fullmap_audit()` on the resolved LazyFrame. Rows that fail all three audit stages are dropped from the result.
|
|
109
113
|
|
|
110
|
-
|
|
114
|
+
7. **Collection and conversion** — Collects the lazy result into an eager `pl.DataFrame` and converts to a list of row dictionaries via `to_dicts()`.
|
|
111
115
|
|
|
112
116
|
### Example Usage
|
|
113
117
|
|
|
@@ -126,7 +130,7 @@ result: list[dict[str, Any]] = resolve_many(
|
|
|
126
130
|
entities=["TP53", "BRCA1", "EGFR", "KRAS"],
|
|
127
131
|
datassert=datassert,
|
|
128
132
|
taxon="9606",
|
|
129
|
-
prioritize=[Categories.
|
|
133
|
+
prioritize=[Categories.GENE],
|
|
130
134
|
)
|
|
131
135
|
|
|
132
136
|
# result[0] → {"original gene": "TP53", "gene": "HGNC:11998", "gene name": "TP53", ...}
|
|
@@ -147,7 +151,7 @@ result: list[dict[str, Any]] = resolve_many(
|
|
|
147
151
|
col="disease",
|
|
148
152
|
entities=["diabetes mellitus", "breast cancer", "alzheimer disease"],
|
|
149
153
|
datassert=datassert,
|
|
150
|
-
avoid=[Categories.
|
|
154
|
+
avoid=[Categories.GENE, Categories.PROTEIN],
|
|
151
155
|
)
|
|
152
156
|
|
|
153
157
|
# result[0] → {"original disease": "diabetes mellitus", "disease": "MONDO:0005015", ...}
|
|
@@ -206,7 +210,7 @@ for row in result:
|
|
|
206
210
|
| **Connections** | Managed internally via `ExitStack` | Must be opened externally |
|
|
207
211
|
| **Output** | `list[dict[str, Any]]` | `pl.LazyFrame` |
|
|
208
212
|
| **Logging** | Uses default (`log=True`) | Configurable |
|
|
209
|
-
| **Context params** |
|
|
213
|
+
| **Context params** | `column_context` exposed; `section_hash`, `config_file`, `tag` not exposed | Fully configurable |
|
|
210
214
|
| **Use case** | Standalone batch lookups, scripting, notebooks | Internal pipeline integration |
|
|
211
215
|
|
|
212
216
|
`resolve_many()` is designed for ad-hoc and programmatic use — scripts, notebooks, and one-off lookups. For pipeline integration where you need full control over logging, context metadata, and lazy evaluation, use `resolve()` directly.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The `qc` module validates entity resolution mappings through a multi-stage pipeline: exact matching, fuzzy matching, and BERT semantic similarity.
|
|
4
4
|
|
|
5
|
-
QC runtime support is optional. Install `tablassert[qc]` for CPU inference or `tablassert[qc-cuda]` for CUDA inference on GPU 0.
|
|
5
|
+
QC runtime support is optional. Install `tablassert[qc]` for CPU inference or `tablassert[qc-cuda]` for CUDA inference on GPU 0. **Strict GPU behavior:** if `onnxruntime-gpu` is installed but `CUDAExecutionProvider` is not available (e.g., a broken CUDA/cuDNN environment), `fullmap_audit()` raises a `RuntimeError` rather than silently falling back to CPU — install `tablassert[qc]` for CPU inference or fix the CUDA environment.
|
|
6
6
|
|
|
7
7
|
## fullmap_audit()
|
|
8
8
|
|
|
@@ -84,7 +84,7 @@ original == preferred_name
|
|
|
84
84
|
|
|
85
85
|
**Performance:** O(1) string comparison
|
|
86
86
|
|
|
87
|
-
Before fuzzy matching, the function also applies rule-based pass-through checks
|
|
87
|
+
Before fuzzy matching, the function also applies rule-based pass-through checks: (1) the resolved CURIE matches an exempt prefix (`CHEBI`, `PR`, `UniProtKB`, `NCBIGene`, `UMLS`, `UNII`, `PUBCHEM`, `MONDO`); (2) the original text contains `:` (looks like a CURIE); (3) the preferred name matches an exception prefix (`^LOC` or `^si:`).
|
|
88
88
|
|
|
89
89
|
#### Stage 2: Fuzzy Matching
|
|
90
90
|
|
|
@@ -94,11 +94,11 @@ Two fuzzy matching algorithms:
|
|
|
94
94
|
1. **Ratio:** Overall string similarity
|
|
95
95
|
2. **Partial token sort ratio:** Combined token/subsequence matching
|
|
96
96
|
|
|
97
|
-
**
|
|
97
|
+
**Thresholds:** `fuzz.ratio` >= 20 OR `fuzz.partial_token_sort_ratio` >= 30
|
|
98
98
|
|
|
99
99
|
```python
|
|
100
100
|
fuzz.ratio(original, preferred) >= 20
|
|
101
|
-
or fuzz.partial_token_sort_ratio(original, preferred) >=
|
|
101
|
+
or fuzz.partial_token_sort_ratio(original, preferred) >= 30
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
**Example passes:**
|
|
@@ -116,8 +116,8 @@ or fuzz.partial_token_sort_ratio(original, preferred) >= 20
|
|
|
116
116
|
3. **Accept** if similarity >= 0.2 (20%)
|
|
117
117
|
|
|
118
118
|
```python
|
|
119
|
-
embeddings =
|
|
120
|
-
similarity = cosine_similarity(
|
|
119
|
+
embeddings = get_biobert(provider).encode(originals + preferreds)
|
|
120
|
+
similarity = cosine_similarity(embeddings[:n], embeddings[n:]).diagonal()
|
|
121
121
|
return similarity >= 0.2
|
|
122
122
|
```
|
|
123
123
|
|
|
@@ -19,10 +19,8 @@ def namespace_uuid(domain: Any, *values: list[Any]) -> str
|
|
|
19
19
|
Domain string used to create the namespace UUID.
|
|
20
20
|
|
|
21
21
|
Converted to string internally. Common domains:
|
|
22
|
-
- `"TABLASSERT"` - Default domain used for
|
|
23
|
-
- `"edges"`
|
|
24
|
-
- `"nodes"` - For custom node IDs
|
|
25
|
-
- `"tablassert"` - For application-specific IDs
|
|
22
|
+
- `"TABLASSERT"` - Default domain used for KGX edge IDs (the value used by `label_edge`)
|
|
23
|
+
- Other domain strings (e.g., `"edges"`, `"nodes"`) may be passed for custom namespaces, though only `"TABLASSERT"` is used internally.
|
|
26
24
|
|
|
27
25
|
**`*values: list[Any]`**
|
|
28
26
|
|
|
@@ -118,7 +116,7 @@ edge_id = namespace_uuid(
|
|
|
118
116
|
"MONDO:0005148", # Type 2 diabetes
|
|
119
117
|
"PMC11708054" # Publication
|
|
120
118
|
)
|
|
121
|
-
# Returns: "
|
|
119
|
+
# Returns: "2cfea591-0f8f-33af-a7df-03da531d3359"
|
|
122
120
|
```
|
|
123
121
|
|
|
124
122
|
**Benefits:**
|
|
@@ -145,7 +143,7 @@ from tablassert.utils import namespace_uuid
|
|
|
145
143
|
|
|
146
144
|
# Generate edge ID
|
|
147
145
|
edge_id = namespace_uuid("edges", "subject", "predicate", "object")
|
|
148
|
-
print(edge_id) # "
|
|
146
|
+
print(edge_id) # "12345678-1234-1234-1234-123456789abc"
|
|
149
147
|
```
|
|
150
148
|
|
|
151
149
|
**With qualifiers:**
|
|
@@ -183,12 +181,33 @@ Suitable for millions of ID generations per second.
|
|
|
183
181
|
**`basespace(domain)`** - Creates namespace UUID from domain
|
|
184
182
|
|
|
185
183
|
```python
|
|
184
|
+
@cache
|
|
186
185
|
def basespace(domain: str) -> UUID:
|
|
187
186
|
namespace = UUID("00000000-0000-0000-0000-000000000000")
|
|
188
187
|
return uuid3(namespace, domain)
|
|
189
188
|
```
|
|
190
189
|
|
|
191
|
-
Used internally by `namespace_uuid()`.
|
|
190
|
+
Used internally by `namespace_uuid()`. Results are memoized per domain.
|
|
191
|
+
|
|
192
|
+
## mkhash()
|
|
193
|
+
|
|
194
|
+
Generates an `xxhash` 64-bit digest (hex string, 16 characters) for arbitrary input.
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
def mkhash(x: Any) -> str
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Used for compact identifier hashing (e.g., config/file identifiers in the CLI). Returns the `xxh64` hex digest of the input converted to a string.
|
|
201
|
+
|
|
202
|
+
## samphash()
|
|
203
|
+
|
|
204
|
+
Hashes a sampled `polars.DataFrame` for deterministic temp-file naming.
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
def samphash(df: pl.DataFrame, n: int = 20) -> str
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Samples up to `n` rows (default `20`) from `df`, hashes the sampled bytes via `mkhash()`, and returns the digest string.
|
|
192
211
|
|
|
193
212
|
## Next Steps
|
|
194
213
|
|
|
@@ -4,6 +4,13 @@ The canonical release history lives in the repository root at [`CHANGELOG.md`](h
|
|
|
4
4
|
|
|
5
5
|
## Current Release Notes
|
|
6
6
|
|
|
7
|
+
## 7.4.14 - 2026-06-30
|
|
8
|
+
|
|
9
|
+
### Changes
|
|
10
|
+
|
|
11
|
+
- Extended `sig()` in `lib.py` to select a p-value column by fuzzy matching rather than requiring an exact `"p value"` name. All schema columns whose names contain the substring `"p value"` are now considered candidates; `fuzz.ratio` (rapidfuzz) scores each against the literal `"p value"` and the highest-scoring column is used to compute the `"significant"` output. An exact `"p value"` column scores 100 and is always preferred; columns like `"adjusted p value"` or `"log p value"` are used only when no exact match is present. If no column contains the substring the function continues to emit `"UNSURE"` for all rows.
|
|
12
|
+
- Added five regression tests in `test_lib.py` covering: exact-match preference, non-exact fallback, closest-match selection among multiple non-exact candidates, no-p-value column (UNSURE), and null value handling.
|
|
13
|
+
|
|
7
14
|
## 7.4.13 - 2026-06-30
|
|
8
15
|
|
|
9
16
|
### Changes
|
|
@@ -26,7 +26,7 @@ Prints the installed Tablassert version to stdout and exits. This is a flag on t
|
|
|
26
26
|
|
|
27
27
|
## build
|
|
28
28
|
|
|
29
|
-
Build
|
|
29
|
+
Build a knowledge graph from a YAML configuration file.
|
|
30
30
|
|
|
31
31
|
### Synopsis
|
|
32
32
|
|
|
@@ -70,7 +70,7 @@ See [Graph Configuration](configuration/graph.md) for details on the YAML schema
|
|
|
70
70
|
|
|
71
71
|
## validate
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Validate section syntax from a YAML configuration file.
|
|
74
74
|
|
|
75
75
|
### Synopsis
|
|
76
76
|
|
|
@@ -23,7 +23,7 @@ template:
|
|
|
23
23
|
local: ./DATALAKE/ALAM.XLSX
|
|
24
24
|
url: https://pmc.ncbi.nlm.nih.gov/articles/instance/11708054/bin/mbio.01679-24-s0006.xlsx
|
|
25
25
|
row_slice:
|
|
26
|
-
- 2 # Skip first
|
|
26
|
+
- 2 # Skip the first two rows (title + header)
|
|
27
27
|
- auto # Read to end
|
|
28
28
|
sheet: all correlations
|
|
29
29
|
|
|
@@ -39,9 +39,9 @@ template:
|
|
|
39
39
|
avoid:
|
|
40
40
|
- Gene
|
|
41
41
|
|
|
42
|
-
#
|
|
42
|
+
# Strip non-value text in place (rows are not dropped)
|
|
43
43
|
remove:
|
|
44
|
-
- "^NA " #
|
|
44
|
+
- "^NA " # Cells starting with "NA "
|
|
45
45
|
|
|
46
46
|
# Clean taxonomic names with regex
|
|
47
47
|
regex:
|
|
@@ -66,7 +66,7 @@ template:
|
|
|
66
66
|
# Provenance: Publication and curation info
|
|
67
67
|
provenance:
|
|
68
68
|
repo: PMC
|
|
69
|
-
publication:
|
|
69
|
+
publication: PMC11708054
|
|
70
70
|
contributors:
|
|
71
71
|
- kind: curation
|
|
72
72
|
name: Skye Lane Goetz
|
|
@@ -147,7 +147,7 @@ The subject field uses three regex transformations in sequence:
|
|
|
147
147
|
```
|
|
148
148
|
`"Lactobacillus sp"` → `"Lactobacillus sp. "`
|
|
149
149
|
|
|
150
|
-
> **Regex constraint:** Each `pattern` is handed to Polars `str.replace_all()` (Rust `regex` crate). **
|
|
150
|
+
> **Regex constraint:** Each `pattern` is handed to Polars `str.replace_all()` (Rust `regex` crate). **Backreferences (`\1`, `\2`, …) and lookarounds (`(?=...)`, `(?<=...)`, `(?!...)`, `(?<!...)`) are not allowed** and will fail validation. Plain groups `(...)` and non-capturing groups `(?:...)` *are* supported. Express transformations as a sequence of simple anchored / character-class substitutions where possible — the pipeline above is a deliberate three-step chain. If the transformation can't be expressed without those unsupported features, capture the leftover context in a `miscellaneous notes` annotation rather than fighting the regex engine.
|
|
151
151
|
|
|
152
152
|
### Taxonomic Filtering
|
|
153
153
|
|
|
@@ -226,6 +226,7 @@ template:
|
|
|
226
226
|
|
|
227
227
|
statement:
|
|
228
228
|
subject:
|
|
229
|
+
method: column
|
|
229
230
|
encoding: A
|
|
230
231
|
prioritize: [OrganismTaxon]
|
|
231
232
|
avoid: [Gene]
|
|
@@ -239,18 +240,20 @@ sections:
|
|
|
239
240
|
# Section 1: Positive correlations
|
|
240
241
|
- statement:
|
|
241
242
|
predicate: positively_correlated_with
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
source:
|
|
244
|
+
reindex:
|
|
245
|
+
- column: B # Correlation coefficient
|
|
246
|
+
comparison: gt
|
|
247
|
+
comparator: 0
|
|
246
248
|
|
|
247
249
|
# Section 2: Negative correlations
|
|
248
250
|
- statement:
|
|
249
251
|
predicate: negatively_correlated_with
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
source:
|
|
253
|
+
reindex:
|
|
254
|
+
- column: B
|
|
255
|
+
comparison: lt
|
|
256
|
+
comparator: 0
|
|
254
257
|
```
|
|
255
258
|
|
|
256
259
|
This produces two sets of edges from one table:
|
|
@@ -296,14 +299,9 @@ template:
|
|
|
296
299
|
- pattern: _
|
|
297
300
|
replacement: ' ' # "Lactobacillus_rhamnosus" → "Lactobacillus rhamnosus"
|
|
298
301
|
|
|
299
|
-
qualifiers:
|
|
300
|
-
- qualifier: p value
|
|
301
|
-
method: column
|
|
302
|
-
encoding: E
|
|
303
|
-
|
|
304
302
|
provenance:
|
|
305
303
|
repo: PMC
|
|
306
|
-
publication:
|
|
304
|
+
publication: PMC12345678
|
|
307
305
|
contributors:
|
|
308
306
|
- kind: curation
|
|
309
307
|
name: Skye Lane Goetz
|
|
@@ -324,7 +322,7 @@ template:
|
|
|
324
322
|
|
|
325
323
|
**Both nodes from columns:** Setting `method: column` on both subject and object means both undergo entity resolution via `resolve()`. Each gets its own `prioritize` list to guide disambiguation.
|
|
326
324
|
|
|
327
|
-
**`remove` vs `regex`:** `remove`
|
|
325
|
+
**`remove` vs `regex`:** Both transform cell text in place before resolution (neither drops rows). `remove` strips each listed regex pattern by replacing it with an empty string; `regex` applies an ordered `pattern`→`replacement` substitution list.
|
|
328
326
|
|
|
329
327
|
---
|
|
330
328
|
|
|
@@ -364,7 +362,7 @@ template:
|
|
|
364
362
|
|
|
365
363
|
provenance:
|
|
366
364
|
repo: PMC
|
|
367
|
-
publication:
|
|
365
|
+
publication: PMC87654321
|
|
368
366
|
contributors:
|
|
369
367
|
- kind: curation
|
|
370
368
|
name: Skye Lane Goetz
|
|
@@ -16,7 +16,6 @@ A graph configuration file specifies:
|
|
|
16
16
|
|
|
17
17
|
| Field | Type | Description |
|
|
18
18
|
|-------|------|-------------|
|
|
19
|
-
| `syntax` | String | Configuration version (must be `"GC2"`) |
|
|
20
19
|
| `name` | String | Knowledge graph name (used in output filename) |
|
|
21
20
|
| `version` | String | Knowledge graph version (used in output filename) |
|
|
22
21
|
| `tables` | List[Path] | Paths to table configuration YAML files |
|
|
@@ -26,6 +25,7 @@ A graph configuration file specifies:
|
|
|
26
25
|
|
|
27
26
|
| Field | Type | Description |
|
|
28
27
|
|-------|------|-------------|
|
|
28
|
+
| `syntax` | String | Configuration version. Defaults to `"GC2"` (also accepts `"TC3"`); overriding is not recommended. |
|
|
29
29
|
| `pubmed_db` | Path | Path to SQLite PubMed metadata database |
|
|
30
30
|
| `pmc_db` | Path | Path to SQLite PMC figure captions database |
|
|
31
31
|
| `log` | Boolean | Log unmatched entities and audit details during graph builds |
|
|
@@ -35,7 +35,7 @@ A graph configuration file specifies:
|
|
|
35
35
|
|
|
36
36
|
**`syntax: "GC2"`**
|
|
37
37
|
|
|
38
|
-
Configuration syntax version.
|
|
38
|
+
Configuration syntax version. Defaults to `"GC2"` (the type also accepts `"TC3"`); overriding the default is not recommended.
|
|
39
39
|
|
|
40
40
|
**`name: string`**
|
|
41
41
|
|
|
@@ -61,7 +61,7 @@ This field only controls whether QC runs. Install `tablassert[qc]` or `tablasser
|
|
|
61
61
|
|
|
62
62
|
**`tables: list[path]`**
|
|
63
63
|
|
|
64
|
-
List of table configuration file paths. Can be absolute or relative to graph
|
|
64
|
+
List of table configuration file paths. Can be absolute or relative to the current working directory (paths are resolved against the process CWD, not the graph-config file location).
|
|
65
65
|
|
|
66
66
|
Each table config defines:
|
|
67
67
|
- Data source (Excel/CSV/TSV)
|
|
@@ -101,8 +101,7 @@ When provided, this is used when provenance specifies PMC publications.
|
|
|
101
101
|
|
|
102
102
|
Paths can be:
|
|
103
103
|
- **Absolute:** `/home/user/data/datassert`
|
|
104
|
-
- **Relative to
|
|
105
|
-
- **Relative to current directory:** `../configs/table.yaml`
|
|
104
|
+
- **Relative to the current working directory:** `./tables/table1.yaml` (note: paths are resolved against the process CWD, not the graph-config file location — there is no config-relative resolver)
|
|
106
105
|
|
|
107
106
|
## Minimal Example
|
|
108
107
|
|
|
@@ -139,16 +138,17 @@ pmc_db: /databases/PMCSuppCaptions.db
|
|
|
139
138
|
When you run `tablassert build graph.yaml`:
|
|
140
139
|
|
|
141
140
|
1. **Load graph configuration** - Parse YAML, validate schema
|
|
142
|
-
2. **
|
|
143
|
-
|
|
141
|
+
2. **Load table configurations** - Parse each YAML in `tables`
|
|
142
|
+
3. **Extract sections** - Expand templates into per-section `Tcode` instances
|
|
143
|
+
4. **Collect instructions (per section):**
|
|
144
144
|
- Download source file (if URL specified)
|
|
145
|
-
- Apply transformations
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
145
|
+
- Apply transformations and resolve entities using `datassert`
|
|
146
|
+
- Validate with the QC audit when `qc: true`
|
|
147
|
+
- Enrich with provenance: query `pubmed_db` (MeSH) and `pmc_db` (captions) when configured
|
|
148
|
+
5. **Build subgraphs** - Compile each section's resolved data into a parquet file
|
|
149
|
+
6. **Compile graph** - Aggregate all subgraph parquets and export `{name}_{version}.nodes.ndjson` / `.edges.ndjson`
|
|
150
|
+
|
|
151
|
+
> Note: provenance enrichment (`with_mesh`/`with_captions`) and QC both run during the per-section Collect Instructions stage, *before* subgraphs are built — not as a separate post-aggregation step.
|
|
152
152
|
|
|
153
153
|
## Output Files
|
|
154
154
|
|
|
@@ -173,8 +173,8 @@ version: UNSTABLE
|
|
|
173
173
|
tables:
|
|
174
174
|
- /local_raid1/sgoetz/STORE/CONFIG/TABLASSERT/TABLE/V6/ALAMV6.yaml
|
|
175
175
|
datassert: /local_raid1/sgoetz/CODE/DATASSERT/datassert
|
|
176
|
-
pubmed_db: /local_raid1/sgoetz/DBSTORE/
|
|
177
|
-
pmc_db: /local_raid1/sgoetz/DBSTORE/
|
|
176
|
+
pubmed_db: /local_raid1/sgoetz/DBSTORE/PUBMED/PubMed.db
|
|
177
|
+
pmc_db: /local_raid1/sgoetz/DBSTORE/CAPTIONS/PMCSuppCaptions.db
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
This processes a single table configuration (ALAMV6.yaml) into a knowledge graph named `MULTIOMICS_KG_UNSTABLE`.
|