tablassert 7.4.12__tar.gz → 7.4.13__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 (63) hide show
  1. {tablassert-7.4.12 → tablassert-7.4.13}/AGENTS.md +1 -1
  2. {tablassert-7.4.12 → tablassert-7.4.13}/CHANGELOG.md +6 -0
  3. {tablassert-7.4.12 → tablassert-7.4.13}/PKG-INFO +1 -1
  4. {tablassert-7.4.12 → tablassert-7.4.13}/docs/changelog.md +7 -0
  5. {tablassert-7.4.12 → tablassert-7.4.13}/pyproject.toml +2 -2
  6. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/cli.py +32 -39
  7. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/models.py +0 -42
  8. {tablassert-7.4.12 → tablassert-7.4.13}/tests/conftest.py +1 -14
  9. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_lib.py +14 -0
  10. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_models.py +0 -192
  11. {tablassert-7.4.12 → tablassert-7.4.13}/uv.lock +1 -1
  12. tablassert-7.4.12/.github/workflows/autotag.yml +0 -26
  13. {tablassert-7.4.12 → tablassert-7.4.13}/.github/workflows/docker.yml +0 -0
  14. {tablassert-7.4.12 → tablassert-7.4.13}/.github/workflows/docs.yml +0 -0
  15. {tablassert-7.4.12 → tablassert-7.4.13}/.github/workflows/pipy.yml +0 -0
  16. {tablassert-7.4.12 → tablassert-7.4.13}/.gitignore +0 -0
  17. {tablassert-7.4.12 → tablassert-7.4.13}/.pre-commit-config.yaml +0 -0
  18. {tablassert-7.4.12 → tablassert-7.4.13}/CITATION.cff +0 -0
  19. {tablassert-7.4.12 → tablassert-7.4.13}/CONTRIBUTING.md +0 -0
  20. {tablassert-7.4.12 → tablassert-7.4.13}/Dockerfile +0 -0
  21. {tablassert-7.4.12 → tablassert-7.4.13}/LICENSE +0 -0
  22. {tablassert-7.4.12 → tablassert-7.4.13}/README.md +0 -0
  23. {tablassert-7.4.12 → tablassert-7.4.13}/docs/api/fullmap.md +0 -0
  24. {tablassert-7.4.12 → tablassert-7.4.13}/docs/api/lib.md +0 -0
  25. {tablassert-7.4.12 → tablassert-7.4.13}/docs/api/qc.md +0 -0
  26. {tablassert-7.4.12 → tablassert-7.4.13}/docs/api/utils.md +0 -0
  27. {tablassert-7.4.12 → tablassert-7.4.13}/docs/cli.md +0 -0
  28. {tablassert-7.4.12 → tablassert-7.4.13}/docs/configuration/advanced-example.md +0 -0
  29. {tablassert-7.4.12 → tablassert-7.4.13}/docs/configuration/graph.md +0 -0
  30. {tablassert-7.4.12 → tablassert-7.4.13}/docs/configuration/table.md +0 -0
  31. {tablassert-7.4.12 → tablassert-7.4.13}/docs/datassert.md +0 -0
  32. {tablassert-7.4.12 → tablassert-7.4.13}/docs/docker.md +0 -0
  33. {tablassert-7.4.12 → tablassert-7.4.13}/docs/examples/tutorial-data.csv +0 -0
  34. {tablassert-7.4.12 → tablassert-7.4.13}/docs/examples/tutorial-graph.yaml +0 -0
  35. {tablassert-7.4.12 → tablassert-7.4.13}/docs/examples/tutorial-table.yaml +0 -0
  36. {tablassert-7.4.12 → tablassert-7.4.13}/docs/examples.md +0 -0
  37. {tablassert-7.4.12 → tablassert-7.4.13}/docs/index.md +0 -0
  38. {tablassert-7.4.12 → tablassert-7.4.13}/docs/installation.md +0 -0
  39. {tablassert-7.4.12 → tablassert-7.4.13}/docs/tutorial.md +0 -0
  40. {tablassert-7.4.12 → tablassert-7.4.13}/llms.txt +0 -0
  41. {tablassert-7.4.12 → tablassert-7.4.13}/mkdocs.yml +0 -0
  42. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/__init__.py +0 -0
  43. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/downloader.py +0 -0
  44. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/enums.py +0 -0
  45. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/fullmap.py +0 -0
  46. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/ingests.py +0 -0
  47. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/lib.py +0 -0
  48. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/log.py +0 -0
  49. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/nlp.py +0 -0
  50. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/progress.py +0 -0
  51. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/qc.py +0 -0
  52. {tablassert-7.4.12 → tablassert-7.4.13}/src/tablassert/utils.py +0 -0
  53. {tablassert-7.4.12 → tablassert-7.4.13}/tests/__init__.py +0 -0
  54. {tablassert-7.4.12 → tablassert-7.4.13}/tests/fixtures/invalid_section_missing_source.yaml +0 -0
  55. {tablassert-7.4.12 → tablassert-7.4.13}/tests/fixtures/minimal_section.yaml +0 -0
  56. {tablassert-7.4.12 → tablassert-7.4.13}/tests/fixtures/minimal_section_with_sections.yaml +0 -0
  57. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_downloader.py +0 -0
  58. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_enums.py +0 -0
  59. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_fullmap.py +0 -0
  60. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_ingests.py +0 -0
  61. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_nlp.py +0 -0
  62. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_qc.py +0 -0
  63. {tablassert-7.4.12 → tablassert-7.4.13}/tests/test_utils.py +0 -0
@@ -6,7 +6,7 @@
6
6
  - Install with `uv sync`. QC is not available unless you install an extra: `uv sync --extra qc` or `uv sync --extra qc-cuda`.
7
7
  - CLI entrypoint is `tablassert.cli:APP`. Real user commands are:
8
8
  - `uv run tablassert build <graph.yaml>`
9
- - `uv run tablassert validate <table.yaml> <datassert>`
9
+ - `uv run tablassert validate <table.yaml>`
10
10
 
11
11
  ## Verify Changes
12
12
 
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## 7.4.13 - 2026-06-30
6
+
7
+ ### Changes
8
+ - Removed the datassert prevalidation failure for unresolved `statement.subject` / `statement.object` literal encodings under `method: value`. Graph builds no longer abort during `Tcode.model_validate(...)` for cases like `"Incertae Sedis XI"`; unresolved literal values are now allowed through config validation so downstream runtime handling can decide whether they map or get filtered.
9
+ - Added a regression test at the `Tcode.model_validate(...)` layer covering an unresolved `method: value` subject encoding, matching the build-time validation path reported in the field.
10
+
5
11
  ## 7.4.12 - 2026-06-29
6
12
 
7
13
  ### Changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tablassert
3
- Version: 7.4.12
3
+ Version: 7.4.13
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
@@ -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.13 - 2026-06-30
8
+
9
+ ### Changes
10
+
11
+ - Removed the datassert prevalidation failure for unresolved `statement.subject` / `statement.object` literal encodings under `method: value`. Graph builds no longer abort during `Tcode.model_validate(...)` for cases like `"Incertae Sedis XI"`; unresolved literal values are now allowed through config validation so downstream runtime handling can decide whether they map or get filtered.
12
+ - Added a regression test at the `Tcode.model_validate(...)` layer covering an unresolved `method: value` subject encoding, matching the build-time validation path reported in the field.
13
+
7
14
  ## 7.4.12 - 2026-06-29
8
15
 
9
16
  ### Changes
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tablassert"
3
- version = "7.4.12"
3
+ version = "7.4.13"
4
4
  description = "Extract knowledge assertions from tabular data into NCATS Translator-compliant KGX NDJSON — declaratively, with entity resolution and quality control built in."
5
5
  authors = [
6
6
  { name = "Skye Lane Goetz", email = "sgoetz@isbscience.org" }
@@ -100,7 +100,7 @@ dev = [
100
100
 
101
101
  [tool.pytest.ini_options]
102
102
  testpaths = ["tests"]
103
- markers = ["network: requires internet", "gpu: requires CUDAExecutionProvider", "datassert: requires the datassert DuckDB shards"]
103
+ markers = ["network: requires internet", "gpu: requires CUDAExecutionProvider"]
104
104
 
105
105
  [tool.ruff]
106
106
  line-length = 120
@@ -57,30 +57,29 @@ def build_pipeline(graph_configuration_file: Path, progress: "PipelineProgress")
57
57
  sections: list[dict[str, Any]] = list(chain.from_iterable(temp))
58
58
  n: int = len(sections)
59
59
 
60
+ # * Build TCode (3/6)
61
+ progress.stage(f"Building TCode | Sections: {n}")
62
+ advance = progress.section_loop(n, "TCode")
63
+ tcode: list[Tcode] = []
64
+ for idx, s in enumerate(sections, start=1):
65
+ try:
66
+ tcode.append(
67
+ Tcode.model_validate(
68
+ {**s, "number": idx, "store": (STORE / f"{mkhash(s)}.parquet"), "log": g.log, "qc": g.qc}
69
+ )
70
+ )
71
+ except pydantic.ValidationError as e:
72
+ raise RuntimeError(
73
+ f"02 | FAILED VALIDATION | CONFIG: {graph_configuration_file} | IDX: {idx} | HASH: {mkhash(s)} | PYDANTIC: {flatten_pydantic_error(e)}"
74
+ ) from e
75
+ advance(format_section_oneline(tcode[-1]))
76
+
60
77
  with ExitStack() as stack:
61
78
  conns: list[object] = [
62
79
  stack.enter_context(duckdb.connect(g.datassert / "data" / f"{x}.duckdb", read_only=True))
63
80
  for x in range(SHARDS)
64
81
  ]
65
82
 
66
- # * Build TCode (3/6)
67
- progress.stage(f"Building TCode | Sections: {n}")
68
- advance = progress.section_loop(n, "TCode")
69
- tcode: list[Tcode] = []
70
- for idx, s in enumerate(sections, start=1):
71
- try:
72
- tcode.append(
73
- Tcode.model_validate(
74
- {**s, "number": idx, "store": (STORE / f"{mkhash(s)}.parquet"), "log": g.log, "qc": g.qc},
75
- context={"conns": conns},
76
- )
77
- )
78
- except pydantic.ValidationError as e:
79
- raise RuntimeError(
80
- f"02 | FAILED VALIDATION | CONFIG: {graph_configuration_file} | IDX: {idx} | HASH: {mkhash(s)} | PYDANTIC: {flatten_pydantic_error(e)}"
81
- ) from e
82
- advance(format_section_oneline(tcode[-1]))
83
-
84
83
  # * Collect Instructions (4/6)
85
84
  progress.stage(f"Collecting Instructions | Sections: {n}")
86
85
  advance = progress.section_loop(n, "Collect")
@@ -106,9 +105,8 @@ def build_pipeline(graph_configuration_file: Path, progress: "PipelineProgress")
106
105
  logger.info(f"BUILD DONE | SECTIONS: {n} | NAME: {g.name} | VERSION: {g.version}")
107
106
 
108
107
 
109
- def validate_pipeline(table_configuration_file: Path, datassert: Path, progress: "PipelineProgress") -> None:
108
+ def validate_pipeline(table_configuration_file: Path, progress: "PipelineProgress") -> None:
110
109
  # ? Validate Section Syntax From A Configuration File
111
- from tablassert.fullmap import SHARDS
112
110
  from tablassert.ingests import from_yaml, to_sections
113
111
  from tablassert.lib import Tcode
114
112
  from tablassert.progress import flatten_pydantic_error
@@ -126,32 +124,27 @@ def validate_pipeline(table_configuration_file: Path, datassert: Path, progress:
126
124
  # * Validate Section Syntax (3/3)
127
125
  progress.stage(f"Validating Section Syntax | Sections: {n}")
128
126
  advance = progress.section_loop(n, "Validate")
129
- with ExitStack() as stack:
130
- conns: list[object] = [
131
- stack.enter_context(duckdb.connect(datassert / "data" / f"{x}.duckdb", read_only=True))
132
- for x in range(SHARDS)
133
- ]
134
- for idx, s in enumerate(sections, start=1):
135
- h: str = mkhash(s)
136
- try:
137
- Tcode.model_validate({**s, "number": idx, "store": (STORE / f"{h}.parquet")}, context={"conns": conns})
138
- except pydantic.ValidationError as e:
139
- raise RuntimeError(
140
- f"02 | FAILED VALIDATION | CONFIG: {table_configuration_file} | IDX: {idx} | HASH: {h} | PYDANTIC: {flatten_pydantic_error(e)}"
141
- ) from e
142
- advance(f"#{idx} | HASH: {h}")
127
+ for idx, s in enumerate(sections, start=1):
128
+ h: str = mkhash(s)
129
+ try:
130
+ Tcode.model_validate({**s, "number": idx, "store": (STORE / f"{h}.parquet")})
131
+ except pydantic.ValidationError as e:
132
+ raise RuntimeError(
133
+ f"02 | FAILED VALIDATION | CONFIG: {table_configuration_file} | IDX: {idx} | HASH: {h} | PYDANTIC: {flatten_pydantic_error(e)}"
134
+ ) from e
135
+ advance(f"#{idx} | HASH: {h}")
143
136
 
144
137
  logger.info(f"VALIDATE DONE | SECTIONS: {n} | CONFIG: {table_configuration_file.name}")
145
138
 
146
139
 
147
- def run(stages: int, fn: Any, *args: Path) -> None:
140
+ def run(stages: int, fn: Any, arg: Path) -> None:
148
141
  from tablassert.log import LOG_FORMAT, logger
149
142
  from tablassert.progress import PipelineProgress
150
143
 
151
144
  with PipelineProgress(total_stages=stages) as progress:
152
145
  sink_id: int = logger.add(progress.log_sink, level="INFO", format=LOG_FORMAT)
153
146
  try:
154
- fn(*args, progress)
147
+ fn(arg, progress)
155
148
  finally:
156
149
  logger.remove(sink_id)
157
150
 
@@ -163,6 +156,6 @@ def build(graph_configuration_file: Path) -> None:
163
156
 
164
157
 
165
158
  @APP.command
166
- def validate(table_configuration_file: Path, datassert: Path) -> None:
167
- """Validate section syntax from a YAML configuration file against a datassert directory."""
168
- run(3, validate_pipeline, table_configuration_file, datassert)
159
+ def validate(table_configuration_file: Path) -> None:
160
+ """Validate section syntax from a YAML configuration file."""
161
+ run(3, validate_pipeline, table_configuration_file)
@@ -25,9 +25,6 @@ from tablassert.enums import (
25
25
  Tokens,
26
26
  )
27
27
 
28
- from tablassert.fullmap import resolve
29
- from tablassert.nlp import level_one, level_two
30
-
31
28
  if TYPE_CHECKING:
32
29
  import httpx
33
30
  import polars as pl
@@ -318,35 +315,6 @@ class Annotation(Encoding):
318
315
  return annotation.replace("_", " ").strip()
319
316
 
320
317
 
321
- def resolves_value_encodings(statement: Statement, conns: list[object]) -> None:
322
- # ? Resolve Every Value-Method Literal Against The Shared Datassert Shards
323
- nodes: list[tuple[str, NodeEncoding]] = [("subject", statement.subject), ("object", statement.object)]
324
- if statement.qualifiers:
325
- nodes += [(q.qualifier, q) for q in statement.qualifiers]
326
-
327
- for label, node in nodes:
328
- if not eq(node.method, EncodingMethods.VALUE):
329
- continue
330
-
331
- term: str = str(node.encoding)
332
- lf: pl.LazyFrame = pl.DataFrame({"term": [term]}).lazy()
333
- lf = level_one(lf, "term")
334
- lf = level_two(lf, "term")
335
- resolved: pl.DataFrame = resolve(
336
- lf,
337
- "term",
338
- conns,
339
- taxon=str(node.taxon) if node.taxon else None,
340
- prioritize=node.prioritize,
341
- avoid=node.avoid,
342
- log=False,
343
- column_context=False,
344
- ).collect()
345
- if resolved.height == 0:
346
- msg: str = f"21 | value encoding {term!r} in {label!r} did not resolve against datassert"
347
- raise ValueError(msg)
348
-
349
-
350
318
  class Section(TablaBase):
351
319
  # ? Pydantic "Section" Model And Coercion
352
320
  syntax: Syntaxes = Field(Syntaxes.TC3, description="Section configuration syntax version.")
@@ -358,16 +326,6 @@ class Section(TablaBase):
358
326
  None, description="Optional extra encoded columns added to each row."
359
327
  )
360
328
 
361
- @field_validator("statement", mode="after")
362
- @classmethod
363
- def value_encodings_resolve(cls, statement: Statement, info: Any) -> Statement:
364
- # ? Ensure Value-Method Encodings Resolve Against The Shared Datassert Shards
365
- conns: Optional[list[object]] = info.context.get("conns") if info.context else None
366
- if conns is None:
367
- return statement # * skip without shared connections (contextless path)
368
- resolves_value_encodings(statement, conns)
369
- return statement
370
-
371
329
 
372
330
  class Graph(TablaBase):
373
331
  # ? Pydantic "Graph" Configuration
@@ -1,8 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
3
  from pathlib import Path
5
- from typing import Any, Optional
4
+ from typing import Any
6
5
 
7
6
  import httpx
8
7
  import pytest
@@ -27,15 +26,3 @@ def mockhttpxhead(monkeypatch: pytest.MonkeyPatch) -> None:
27
26
  @pytest.fixture
28
27
  def fixtures_path() -> Path:
29
28
  return Path(__file__).parent / "fixtures"
30
-
31
-
32
- @pytest.fixture
33
- def datassert_dir() -> Path:
34
- # ? Shared Datassert Shard Directory (Skipped When Unavailable)
35
- env: Optional[str] = os.environ.get("DATASSERT")
36
- if not env:
37
- pytest.skip("DATASSERT env var not set; skipping datassert-dependent test")
38
- directory: Path = Path(env)
39
- if not (directory / "data" / "0.duckdb").is_file():
40
- pytest.skip(f"datassert shard data/0.duckdb not found under {directory}")
41
- return directory
@@ -138,6 +138,20 @@ def test_tcode_collect_threads_download_context(fixtures_path: Path) -> None:
138
138
  assert first_op[1] == ("https://example.com/test.tsv", Path("test.tsv"), "minimal_section.yaml", "sectionhash")
139
139
 
140
140
 
141
+ # ? Tcode Allows Unresolved Value Encodings During Validation
142
+ def test_tcode_model_allows_unresolved_value_encoding(fixtures_path: Path) -> None:
143
+ data: Any = from_yaml(fixtures_path / "minimal_section.yaml")
144
+ store: Path = Path("/tmp/sectionhash.parquet")
145
+ data["statement"]["subject"] = {"method": "value", "encoding": "Incertae Sedis XI"}
146
+
147
+ tcode_model: Tcode = Tcode.model_validate( # pyright: ignore
148
+ {**data, "number": 55, "config": fixtures_path / "minimal_section.yaml", "store": store}
149
+ )
150
+
151
+ assert tcode_model.statement.subject.method == "value"
152
+ assert tcode_model.statement.subject.encoding == "Incertae Sedis XI"
153
+
154
+
141
155
  # ? Tcode collect Enables QC Logging By Default
142
156
  def test_tcode_collect_skips_qc_by_default(fixtures_path: Path) -> None:
143
157
  data: Any = from_yaml(fixtures_path / "minimal_section.yaml")
@@ -3,11 +3,9 @@ from __future__ import annotations
3
3
  from pathlib import Path
4
4
  from typing import Any
5
5
 
6
- import polars as pl
7
6
  import pytest
8
7
  from pydantic import ValidationError
9
8
 
10
- import tablassert.models as models
11
9
  from tablassert.enums import Categories
12
10
  from tablassert.ingests import from_yaml
13
11
  from tablassert.models import (
@@ -282,193 +280,3 @@ def test_section_with_annotations() -> None:
282
280
  ],
283
281
  )
284
282
  assert len(section.annotations) == 2 # pyright: ignore
285
-
286
-
287
- # ? Value Encoding Resolves Against Datassert (Context-Aware Pass)
288
- def test_value_encoding_resolves_pass(monkeypatch: pytest.MonkeyPatch) -> None:
289
- def fake_resolve(_lf: Any, _col: str, _conns: list[object], **_kwargs: Any) -> Any:
290
- return pl.DataFrame({"resolved": ["YES"]}).lazy()
291
-
292
- monkeypatch.setattr(models, "resolve", fake_resolve)
293
- section: Section = Section.model_validate(
294
- {
295
- "source": {"local": "./t.tsv", "url": "https://example.com/t.tsv", "kind": "text"},
296
- "statement": {
297
- "subject": {"method": "value", "encoding": "BRCA1"},
298
- "object": {"method": "value", "encoding": "TP53"},
299
- },
300
- "provenance": {
301
- "repo": "PMC",
302
- "publication": "PMC000",
303
- "contributors": [{"kind": "curation", "name": "T", "date": "2025"}],
304
- },
305
- },
306
- context={"conns": [object()]},
307
- )
308
- assert section.statement.subject.encoding == "BRCA1"
309
-
310
-
311
- # ? Value Encoding Fails To Resolve Raises Code 21
312
- def test_value_encoding_resolves_fail(monkeypatch: pytest.MonkeyPatch) -> None:
313
- def fake_resolve_empty(_lf: Any, _col: str, _conns: list[object], **_kwargs: Any) -> Any:
314
- return pl.DataFrame({"resolved": []}).lazy()
315
-
316
- monkeypatch.setattr(models, "resolve", fake_resolve_empty)
317
- with pytest.raises(ValidationError) as exc_info:
318
- Section.model_validate(
319
- {
320
- "source": {"local": "./t.tsv", "url": "https://example.com/t.tsv", "kind": "text"},
321
- "statement": {
322
- "subject": {"method": "value", "encoding": "BRCA1"},
323
- "object": {"method": "value", "encoding": "TP53"},
324
- },
325
- "provenance": {
326
- "repo": "PMC",
327
- "publication": "PMC000",
328
- "contributors": [{"kind": "curation", "name": "T", "date": "2025"}],
329
- },
330
- },
331
- context={"conns": [object()]},
332
- )
333
- assert "21 |" in str(exc_info.value)
334
-
335
-
336
- # ? Value Encoding Validator Skips Without Context
337
- def test_value_encoding_skips_without_context(monkeypatch: pytest.MonkeyPatch) -> None:
338
- def fake_resolve_empty(_lf: Any, _col: str, _conns: list[object], **_kwargs: Any) -> Any:
339
- return pl.DataFrame({"resolved": []}).lazy()
340
-
341
- monkeypatch.setattr(models, "resolve", fake_resolve_empty)
342
- section: Section = Section( # pyright: ignore
343
- source={"local": "./t.tsv", "url": "https://example.com/t.tsv", "kind": "text"},
344
- statement={
345
- "subject": {"method": "value", "encoding": "BRCA1"},
346
- "object": {"method": "value", "encoding": "TP53"},
347
- },
348
- provenance={
349
- "repo": "PMC",
350
- "publication": "PMC000",
351
- "contributors": [{"kind": "curation", "name": "T", "date": "2025"}],
352
- },
353
- )
354
- assert section.statement.subject.encoding == "BRCA1"
355
-
356
-
357
- # ? Column Method Encodings Are Not Checked
358
- def test_column_encoding_not_checked(monkeypatch: pytest.MonkeyPatch) -> None:
359
- def boom_resolve(_lf: Any, _col: str, _conns: list[object], **_kwargs: Any) -> Any:
360
- raise AssertionError("resolve must not be called for column-method encodings")
361
-
362
- monkeypatch.setattr(models, "resolve", boom_resolve)
363
- section: Section = Section.model_validate(
364
- {
365
- "source": {"local": "./t.tsv", "url": "https://example.com/t.tsv", "kind": "text"},
366
- "statement": {
367
- "subject": {"method": "column", "encoding": "A"},
368
- "object": {"method": "column", "encoding": "B"},
369
- },
370
- "provenance": {
371
- "repo": "PMC",
372
- "publication": "PMC000",
373
- "contributors": [{"kind": "curation", "name": "T", "date": "2025"}],
374
- },
375
- },
376
- context={"conns": [object()]},
377
- )
378
- assert section.statement.subject.encoding == "A"
379
-
380
-
381
- # ? Qualifier Value Encoding Is Checked Against Datassert
382
- def test_qualifier_value_encoding_checked(monkeypatch: pytest.MonkeyPatch) -> None:
383
- def fake_resolve(lf: Any, col: str, _conns: list[object], **_kwargs: Any) -> Any:
384
- term: str = str(lf.collect().get_column(col).to_list()[0])
385
- if term in ("brca1", "tp53"):
386
- return pl.DataFrame({"resolved": ["YES"]}).lazy()
387
- return pl.DataFrame({"resolved": []}).lazy()
388
-
389
- monkeypatch.setattr(models, "resolve", fake_resolve)
390
- with pytest.raises(ValidationError) as exc_info:
391
- Section.model_validate(
392
- {
393
- "source": {"local": "./t.tsv", "url": "https://example.com/t.tsv", "kind": "text"},
394
- "statement": {
395
- "subject": {"method": "value", "encoding": "BRCA1"},
396
- "object": {"method": "value", "encoding": "TP53"},
397
- "qualifiers": [
398
- {"qualifier": "disease_context_qualifier", "method": "value", "encoding": "ZZZNOTAREALGENE123"}
399
- ],
400
- },
401
- "provenance": {
402
- "repo": "PMC",
403
- "publication": "PMC000",
404
- "contributors": [{"kind": "curation", "name": "T", "date": "2025"}],
405
- },
406
- },
407
- context={"conns": [object()]},
408
- )
409
- assert "21 |" in str(exc_info.value)
410
-
411
-
412
- # ? Real Value Encoding Resolves Against The Datassert Shards
413
- @pytest.mark.datassert
414
- def test_real_value_encoding_resolves(datassert_dir: Path) -> None:
415
- from contextlib import ExitStack
416
-
417
- import duckdb
418
-
419
- from tablassert.fullmap import SHARDS
420
-
421
- with ExitStack() as stack:
422
- conns: list[object] = [
423
- stack.enter_context(duckdb.connect(datassert_dir / "data" / f"{x}.duckdb", read_only=True))
424
- for x in range(SHARDS)
425
- ]
426
- section: Section = Section.model_validate(
427
- {
428
- "source": {"local": "./t.tsv", "url": "https://example.com/t.tsv", "kind": "text"},
429
- "statement": {
430
- "subject": {"method": "value", "encoding": "BRCA1"},
431
- "object": {"method": "value", "encoding": "TP53"},
432
- },
433
- "provenance": {
434
- "repo": "PMC",
435
- "publication": "PMC000",
436
- "contributors": [{"kind": "curation", "name": "T", "date": "2025"}],
437
- },
438
- },
439
- context={"conns": conns},
440
- )
441
- assert section.statement.subject.encoding == "BRCA1"
442
-
443
-
444
- # ? Real Value Encoding Failure Raises Code 21
445
- @pytest.mark.datassert
446
- def test_real_value_encoding_fails(datassert_dir: Path) -> None:
447
- from contextlib import ExitStack
448
-
449
- import duckdb
450
-
451
- from tablassert.fullmap import SHARDS
452
-
453
- with ExitStack() as stack:
454
- conns: list[object] = [
455
- stack.enter_context(duckdb.connect(datassert_dir / "data" / f"{x}.duckdb", read_only=True))
456
- for x in range(SHARDS)
457
- ]
458
- with pytest.raises(ValidationError) as exc_info:
459
- Section.model_validate(
460
- {
461
- "source": {"local": "./t.tsv", "url": "https://example.com/t.tsv", "kind": "text"},
462
- "statement": {
463
- "subject": {"method": "value", "encoding": "ZZZNOTAREALGENE123"},
464
- "object": {"method": "value", "encoding": "TP53"},
465
- },
466
- "provenance": {
467
- "repo": "PMC",
468
- "publication": "PMC000",
469
- "contributors": [{"kind": "curation", "name": "T", "date": "2025"}],
470
- },
471
- },
472
- context={"conns": conns},
473
- )
474
- assert "21 |" in str(exc_info.value)
@@ -2360,7 +2360,7 @@ wheels = [
2360
2360
 
2361
2361
  [[package]]
2362
2362
  name = "tablassert"
2363
- version = "7.4.11"
2363
+ version = "7.4.13"
2364
2364
  source = { editable = "." }
2365
2365
  dependencies = [
2366
2366
  { name = "cyclopts" },
@@ -1,26 +0,0 @@
1
- name: Auto Tag Versions
2
- on:
3
- workflow_dispatch:
4
- workflow_run:
5
- workflows:
6
- - "Deploy to PyPI"
7
- types:
8
- - completed
9
- branches:
10
- - main
11
- permissions:
12
- contents: write
13
- jobs:
14
- autotag:
15
- runs-on: ubuntu-latest
16
- steps:
17
- - uses: actions/checkout@v4
18
- with:
19
- fetch-depth: 0
20
- - name: Autotag using pyproject.toml
21
- uses: anothrNick/github-tag-action@v1
22
- env:
23
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24
- INITIAL_VERSION: 7.1.0
25
- TAG_PREFIX: v
26
- DEFAULT_BUMP: minor
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