tablassert 7.4.0__tar.gz → 7.4.2__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 (65) hide show
  1. {tablassert-7.4.0 → tablassert-7.4.2}/CHANGELOG.md +11 -0
  2. {tablassert-7.4.0 → tablassert-7.4.2}/PKG-INFO +1 -1
  3. tablassert-7.4.2/docs/changelog.md +20 -0
  4. {tablassert-7.4.0 → tablassert-7.4.2}/docs/configuration/table.md +8 -8
  5. {tablassert-7.4.0 → tablassert-7.4.2}/pyproject.toml +1 -1
  6. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/models.py +110 -5
  7. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/progress.py +1 -1
  8. tablassert-7.4.2/tests/conftest.py +28 -0
  9. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_models.py +2 -2
  10. {tablassert-7.4.0 → tablassert-7.4.2}/uv.lock +1 -1
  11. tablassert-7.4.0/docs/changelog.md +0 -32
  12. tablassert-7.4.0/tests/conftest.py +0 -10
  13. {tablassert-7.4.0 → tablassert-7.4.2}/.github/workflows/autotag.yml +0 -0
  14. {tablassert-7.4.0 → tablassert-7.4.2}/.github/workflows/docker.yml +0 -0
  15. {tablassert-7.4.0 → tablassert-7.4.2}/.github/workflows/docs.yml +0 -0
  16. {tablassert-7.4.0 → tablassert-7.4.2}/.github/workflows/pipy.yml +0 -0
  17. {tablassert-7.4.0 → tablassert-7.4.2}/.gitignore +0 -0
  18. {tablassert-7.4.0 → tablassert-7.4.2}/.pre-commit-config.yaml +0 -0
  19. {tablassert-7.4.0 → tablassert-7.4.2}/AGENTS.md +0 -0
  20. {tablassert-7.4.0 → tablassert-7.4.2}/CITATION.cff +0 -0
  21. {tablassert-7.4.0 → tablassert-7.4.2}/CONTRIBUTING.md +0 -0
  22. {tablassert-7.4.0 → tablassert-7.4.2}/Dockerfile +0 -0
  23. {tablassert-7.4.0 → tablassert-7.4.2}/LICENSE +0 -0
  24. {tablassert-7.4.0 → tablassert-7.4.2}/README.md +0 -0
  25. {tablassert-7.4.0 → tablassert-7.4.2}/docs/api/fullmap.md +0 -0
  26. {tablassert-7.4.0 → tablassert-7.4.2}/docs/api/lib.md +0 -0
  27. {tablassert-7.4.0 → tablassert-7.4.2}/docs/api/qc.md +0 -0
  28. {tablassert-7.4.0 → tablassert-7.4.2}/docs/api/utils.md +0 -0
  29. {tablassert-7.4.0 → tablassert-7.4.2}/docs/cli.md +0 -0
  30. {tablassert-7.4.0 → tablassert-7.4.2}/docs/configuration/advanced-example.md +0 -0
  31. {tablassert-7.4.0 → tablassert-7.4.2}/docs/configuration/graph.md +0 -0
  32. {tablassert-7.4.0 → tablassert-7.4.2}/docs/datassert.md +0 -0
  33. {tablassert-7.4.0 → tablassert-7.4.2}/docs/docker.md +0 -0
  34. {tablassert-7.4.0 → tablassert-7.4.2}/docs/examples/tutorial-data.csv +0 -0
  35. {tablassert-7.4.0 → tablassert-7.4.2}/docs/examples/tutorial-graph.yaml +0 -0
  36. {tablassert-7.4.0 → tablassert-7.4.2}/docs/examples/tutorial-table.yaml +0 -0
  37. {tablassert-7.4.0 → tablassert-7.4.2}/docs/examples.md +0 -0
  38. {tablassert-7.4.0 → tablassert-7.4.2}/docs/index.md +0 -0
  39. {tablassert-7.4.0 → tablassert-7.4.2}/docs/installation.md +0 -0
  40. {tablassert-7.4.0 → tablassert-7.4.2}/docs/tutorial.md +0 -0
  41. {tablassert-7.4.0 → tablassert-7.4.2}/llms.txt +0 -0
  42. {tablassert-7.4.0 → tablassert-7.4.2}/mkdocs.yml +0 -0
  43. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/__init__.py +0 -0
  44. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/cli.py +0 -0
  45. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/downloader.py +0 -0
  46. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/enums.py +0 -0
  47. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/fullmap.py +0 -0
  48. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/ingests.py +0 -0
  49. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/lib.py +0 -0
  50. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/log.py +0 -0
  51. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/nlp.py +0 -0
  52. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/qc.py +0 -0
  53. {tablassert-7.4.0 → tablassert-7.4.2}/src/tablassert/utils.py +0 -0
  54. {tablassert-7.4.0 → tablassert-7.4.2}/tests/__init__.py +0 -0
  55. {tablassert-7.4.0 → tablassert-7.4.2}/tests/fixtures/invalid_section_missing_source.yaml +0 -0
  56. {tablassert-7.4.0 → tablassert-7.4.2}/tests/fixtures/minimal_section.yaml +0 -0
  57. {tablassert-7.4.0 → tablassert-7.4.2}/tests/fixtures/minimal_section_with_sections.yaml +0 -0
  58. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_downloader.py +0 -0
  59. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_enums.py +0 -0
  60. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_fullmap.py +0 -0
  61. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_ingests.py +0 -0
  62. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_lib.py +0 -0
  63. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_nlp.py +0 -0
  64. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_qc.py +0 -0
  65. {tablassert-7.4.0 → tablassert-7.4.2}/tests/test_utils.py +0 -0
@@ -2,6 +2,17 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## 7.4.2 - 2026-05-07
6
+
7
+ ### Changes
8
+ - Added Pydantic field and model validators to `models.py` that enforce configuration correctness at parse time: `url` fields are verified reachable via `httpx.head()`, `rows` and `row_slice` are mutually exclusive, `Reindex.comparator` type must match its `comparison` operator (`eq`/`ne` require `str`, numeric operators require `int`/`float`), `encoding` values under `method: column` must be Excel-style letters (`A`–`ZZZ`), `Regex` pattern/replacement strings are validated against the Polars regex engine, `remove` entries are validated as Polars-compatible regex, and `annotation` names have underscores replaced with spaces.
9
+ - Changed `rows` and `row_slice` element type from `NonNegativeInt` to `PositiveInt` in `BaseSource`.
10
+
11
+ ## 7.4.1 - 2026-05-05
12
+
13
+ ### Bug Fixes
14
+ - Fixed `AttributeError: 'str' object has no attribute 'value'` raised by `format_section_oneline()` in `progress.py` during the BUILDING TCODE stage. The `Section` model sets `use_enum_values=True`, so `Tcode.status` is already a plain string — removed the stale `.value` access.
15
+
5
16
  ## 7.4.0 - 2026-05-05
6
17
 
7
18
  ### Changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tablassert
3
- Version: 7.4.0
3
+ Version: 7.4.2
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
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ The canonical release history lives in the repository root at [`CHANGELOG.md`](https://github.com/SkyeAv/Tablassert/blob/main/CHANGELOG.md).
4
+
5
+ ## Current Release Notes
6
+
7
+ ## 7.4.2 - 2026-05-07
8
+
9
+ ### Changes
10
+
11
+ - Added Pydantic field and model validators to `models.py` that catch misconfigurations at parse time: unreachable `url` fields, mutually exclusive `rows`/`row_slice`, mismatched `Reindex` comparator types, non–Excel-style column letters under `method: column`, Polars-incompatible `regex`/`remove` patterns, and `annotation` name normalization (underscores → spaces).
12
+ - Changed `rows` and `row_slice` element type from `NonNegativeInt` to `PositiveInt`.
13
+
14
+ ## 7.4.1 - 2026-05-05
15
+
16
+ ### Bug Fixes
17
+
18
+ - Fixed crash in the BUILDING TCODE progress display caused by `format_section_oneline()` calling `.value` on `Tcode.status`, which is a plain string under `use_enum_values=True`.
19
+
20
+ For older releases and the full project history, open the root `CHANGELOG.md` in the repository.
@@ -139,10 +139,10 @@ Defines the data file location and format.
139
139
  |-------|------|----------|-------------|
140
140
  | `kind` | String | No | Source kind. Model default is `"excel"`, but specify it explicitly in configs. |
141
141
  | `local` | Path | Yes | Local file path for caching |
142
- | `url` | URL | Yes | Download URL (HTTP/HTTPS) |
142
+ | `url` | URL | Yes | Download URL (HTTP/HTTPS). Validated as reachable at parse time. |
143
143
  | `sheet` | String | No | Sheet name. Defaults to `"Sheet1"`. |
144
- | `row_slice` | List[Int\|"auto"] | No | Two-value zero-based crop bounds: `[start, stop]`. Each value may be an integer or `"auto"`. |
145
- | `rows` | List[Int] | No | Zero-based row indices to keep after any `row_slice` crop. |
144
+ | `row_slice` | List[Int\|"auto"] | No | Two-value zero-based crop bounds: `[start, stop]`. Each value may be an integer or `"auto"`. Mutually exclusive with `rows`. |
145
+ | `rows` | List[Int] | No | Zero-based row indices to keep after any `row_slice` crop. Mutually exclusive with `row_slice`. |
146
146
  | `reindex` | List[Reindex] | No | Conditional row filtering |
147
147
 
148
148
  **Example:**
@@ -163,10 +163,10 @@ source:
163
163
  |-------|------|----------|-------------|
164
164
  | `kind` | String | No | Source kind. Model default is `"text"`, but specify it explicitly in configs. |
165
165
  | `local` | Path | Yes | Local file path for caching |
166
- | `url` | URL | Yes | Download URL |
166
+ | `url` | URL | Yes | Download URL. Validated as reachable at parse time. |
167
167
  | `delimiter` | String | No | Field delimiter. Defaults to `","`. |
168
- | `row_slice` | List[Int\|"auto"] | No | Two-value zero-based crop bounds: `[start, stop]`. Each value may be an integer or `"auto"`. |
169
- | `rows` | List[Int] | No | Zero-based row indices to keep after any `row_slice` crop. |
168
+ | `row_slice` | List[Int\|"auto"] | No | Two-value zero-based crop bounds: `[start, stop]`. Each value may be an integer or `"auto"`. Mutually exclusive with `rows`. |
169
+ | `rows` | List[Int] | No | Zero-based row indices to keep after any `row_slice` crop. Mutually exclusive with `row_slice`. |
170
170
  | `reindex` | List[Reindex] | No | Conditional filtering |
171
171
 
172
172
  **Example:**
@@ -189,7 +189,7 @@ Filter rows based on column values.
189
189
  |-------|------|-------------|
190
190
  | `column` | String | Source column letters to evaluate (`A`-`ZZZ`) |
191
191
  | `comparison` | String | Operator. Defaults to `"ne"`; allowed values are `"eq"`, `"ne"`, `"lt"`, `"le"`, `"gt"`, `"ge"`. |
192
- | `comparator` | String\|Int\|Float | Value to compare against |
192
+ | `comparator` | String\|Int\|Float | Value to compare against. Must be a string for `"eq"`/`"ne"`, or a number for `"lt"`/`"le"`/`"gt"`/`"ge"`. |
193
193
 
194
194
  **Example:**
195
195
  ```yaml
@@ -454,7 +454,7 @@ Optional edge attributes (statistical metadata, notes, etc.).
454
454
 
455
455
  | Field | Type | Description |
456
456
  |-------|------|-------------|
457
- | `annotation` | String | Attribute name (e.g., `"p value"`, `"sample size"`) |
457
+ | `annotation` | String | Attribute name (e.g., `"p value"`, `"sample size"`). Underscores are automatically replaced with spaces at parse time. |
458
458
  | (inherits Encoding) | | All Encoding fields available (method, encoding, regex, etc.) |
459
459
 
460
460
  **Example:**
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tablassert"
3
- version = "7.4.0"
3
+ version = "7.4.2"
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" }
@@ -1,9 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import re
4
+ from operator import eq
3
5
  from pathlib import Path
4
- from typing import Literal, Optional, Union
6
+ from typing import TYPE_CHECKING, Any, Literal, Optional, Self, Union
5
7
 
6
- from pydantic import BaseModel, ConfigDict, Field, HttpUrl, NonNegativeInt, PositiveInt
8
+ import lazy_loader as Lazy
9
+ from pydantic import BaseModel, ConfigDict, Field, HttpUrl, PositiveInt, field_validator, model_validator
7
10
 
8
11
  from tablassert.enums import (
9
12
  Categories,
@@ -21,6 +24,13 @@ from tablassert.enums import (
21
24
  Tokens,
22
25
  )
23
26
 
27
+ if TYPE_CHECKING:
28
+ import httpx
29
+ import polars as pl
30
+ else:
31
+ httpx = Lazy.load("httpx")
32
+ pl = Lazy.load("polars")
33
+
24
34
 
25
35
  class TablaBase(BaseModel):
26
36
  model_config: ConfigDict = ConfigDict( # pyright: ignore
@@ -45,18 +55,58 @@ class Reindex(TablaBase):
45
55
  ..., description="Right-side value compared against the selected column.", examples=["N/A", 0, 1.5]
46
56
  )
47
57
 
58
+ @model_validator(mode="after")
59
+ def comparison_datatypes(self: Self) -> Self:
60
+ x: Comparisons = self.comparison
61
+ y: Union[str, int, float] = self.comparator
62
+
63
+ if eq(x, Comparisons.NE) or eq(x, Comparisons.EQ):
64
+ if not isinstance(y, str):
65
+ msg: str = f"14 | eq or ne comparisons must have a str comparator, got {type(y)}"
66
+ raise ValueError(msg)
67
+ else:
68
+ if not (isinstance(y, int) or isinstance(y, float)):
69
+ msg = f"15 | all comparisons other than eq or ne must have a float or an int comparator, got {type(y)}"
70
+ raise ValueError(msg)
71
+
72
+ return self
73
+
48
74
 
49
75
  class BaseSource(TablaBase):
50
76
  local: Path = Field(..., description="Local path to read from or download into.")
51
77
  url: HttpUrl = Field(..., description="Remote source URL fetched before parsing.")
52
- rows: Optional[list[NonNegativeInt]] = Field(
78
+
79
+ @field_validator("url", mode="after")
80
+ @classmethod
81
+ def is_real_url(cls, url: HttpUrl, timeout: float = 3.0) -> HttpUrl:
82
+ s: str = str(url)
83
+
84
+ try:
85
+ r: Any = httpx.head(s, timeout=timeout, follow_redirects=True)
86
+ r.raise_for_status()
87
+ except Exception as e:
88
+ msg: str = f"12 | not a real url {s} | {e}"
89
+ raise ValueError(msg)
90
+
91
+ return url
92
+
93
+ rows: Optional[list[PositiveInt]] = Field(
53
94
  None, description="Zero-based row indices kept after any row_slice crop.", examples=[[0, 2, 5]]
54
95
  )
55
- row_slice: Optional[list[Union[NonNegativeInt, Literal[Tokens.AUTO]]]] = Field(
96
+ row_slice: Optional[list[Union[PositiveInt, Literal[Tokens.AUTO]]]] = Field(
56
97
  None,
57
98
  description="Two-value row bounds [start, stop]; each value can be an index or 'auto'.",
58
99
  examples=[[1, 50], [Tokens.AUTO, 100], [5, Tokens.AUTO]],
59
100
  )
101
+
102
+ @model_validator(mode="after")
103
+ def no_rows_and_slice(self: Self) -> Self:
104
+ if self.rows and self.row_slice:
105
+ msg: str = "13 | cannot specify rows and row_slice in the same section"
106
+ raise ValueError(msg)
107
+
108
+ return self
109
+
60
110
  reindex: Optional[list[Reindex]] = Field(
61
111
  None,
62
112
  description="Sequential row filters applied using source column values.",
@@ -80,10 +130,33 @@ class Regex(TablaBase):
80
130
  pattern: Union[int, float, str] = Field(
81
131
  ..., description="Regex pattern passed to string replacement.", examples=["\\s+", "\\.$"]
82
132
  )
133
+
134
+ @field_validator("pattern", mode="after")
135
+ @classmethod
136
+ def polars_compatible_pattern(cls, pattern: Union[int, float, str]) -> Union[int, float, str]:
137
+ try:
138
+ pl.Series([""]).str.contains(str(pattern))
139
+ except Exception as e:
140
+ msg: str = f"17 | pattern must be a polars compatible regex, got {pattern} | {e}"
141
+ raise ValueError(msg)
142
+
143
+ return pattern
144
+
83
145
  replacement: Union[int, float, str] = Field(
84
146
  ..., description="Replacement value used when the pattern matches.", examples=[" ", "", 0]
85
147
  )
86
148
 
149
+ @field_validator("replacement", mode="after")
150
+ @classmethod
151
+ def polars_compatible_replacement(cls, replacement: Union[int, float, str]) -> Union[int, float, str]:
152
+ try:
153
+ pl.Series([""]).str.contains(str(replacement))
154
+ except Exception as e:
155
+ msg: str = f"18 | replacement must be a polars compatible regex, got {replacement} | {e}"
156
+ raise ValueError(msg)
157
+
158
+ return replacement
159
+
87
160
 
88
161
  class Math(TablaBase):
89
162
  function: Functions = Field(..., description="Math function applied during numeric transformation.")
@@ -103,6 +176,17 @@ class Encoding(TablaBase):
103
176
  encoding: Union[str, int, float] = Field(
104
177
  ..., description="Literal value or source column letters, depending on method.", examples=["A", "BRCA1", 1.0]
105
178
  )
179
+
180
+ @model_validator(mode="after")
181
+ def excel_style_columns(self: Self) -> Self:
182
+ if eq(self.method, EncodingMethods.COLUMN):
183
+ x: Union[str, int, float] = self.encoding
184
+ if not re.search(r"^[A-Z]{1,3}$", str(x)):
185
+ msg: str = f"16 | encoding must be an excel style alphanumeric column name like A to ZZ, got {x}"
186
+ raise ValueError(msg)
187
+
188
+ return self
189
+
106
190
  regex: Optional[list[Regex]] = Field(
107
191
  None,
108
192
  description="Ordered regex replacements applied to encoded text.",
@@ -113,11 +197,27 @@ class Encoding(TablaBase):
113
197
  description="Null fill strategy applied after value extraction.",
114
198
  examples=[FillMethods.FORWARD, FillMethods.ZERO],
115
199
  )
116
- remove: Optional[list[str]] = Field(
200
+ remove: Optional[list[Union[int, float, str]]] = Field(
117
201
  None,
118
202
  description="Regex patterns removed from text (replace with empty string).",
119
203
  examples=[["\\[\\d+\\]", "\\s+"]],
120
204
  )
205
+
206
+ @field_validator("remove", mode="after")
207
+ @classmethod
208
+ def polars_compatible_replacement(
209
+ cls, remove: Optional[list[Union[int, float, str]]]
210
+ ) -> Optional[list[Union[int, float, str]]]:
211
+ if remove:
212
+ for r in remove:
213
+ try:
214
+ pl.Series([""]).str.contains(str(r))
215
+ except Exception as e:
216
+ msg: str = f"19 | remove must be contain polars compatible regular expressions, got {r} | {e}"
217
+ raise ValueError(msg)
218
+
219
+ return remove
220
+
121
221
  prefix: Optional[str] = Field(None, description="String prepended to the encoded value.")
122
222
  suffix: Optional[str] = Field(None, description="String appended to the encoded value.")
123
223
  explode_by: Optional[str] = Field(
@@ -186,6 +286,11 @@ class Annotation(Encoding):
186
286
  ..., description="Output column name that receives this encoded annotation.", examples=["p_value", "cohort"]
187
287
  )
188
288
 
289
+ @field_validator("annotation", mode="after")
290
+ @classmethod
291
+ def clean_annotation(cls, annotation: str) -> str:
292
+ return annotation.replace("_", " ").strip()
293
+
189
294
 
190
295
  class Section(TablaBase):
191
296
  # ? Pydantic "Section" Model And Coercion
@@ -36,7 +36,7 @@ def format_section_oneline(x: "Tcode") -> str:
36
36
  source_detail = f"TEXT({(x.source.delimiter or ',')!r})" # pyright: ignore
37
37
  return (
38
38
  f"#{x.number} | HASH: {x.store.stem} | SOURCE: {source_detail} "
39
- f"| CONFIG: {x.config.name} | STATUS: {x.status.value}"
39
+ f"| CONFIG: {x.config.name} | STATUS: {x.status}"
40
40
  )
41
41
 
42
42
 
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ import httpx
7
+ import pytest
8
+
9
+
10
+ class FakeHeadResponse:
11
+ status_code: int = 200
12
+
13
+ def raise_for_status(self) -> None:
14
+ return None
15
+
16
+
17
+ def fakehead(url: str, *args: Any, **kwargs: Any) -> FakeHeadResponse:
18
+ return FakeHeadResponse()
19
+
20
+
21
+ @pytest.fixture(autouse=True)
22
+ def mockhttpxhead(monkeypatch: pytest.MonkeyPatch) -> None:
23
+ monkeypatch.setattr(httpx, "head", fakehead)
24
+
25
+
26
+ @pytest.fixture
27
+ def fixtures_path() -> Path:
28
+ return Path(__file__).parent / "fixtures"
@@ -230,8 +230,8 @@ def test_section_with_row_slice() -> None:
230
230
 
231
231
  # ? Section With Rows
232
232
  def test_section_with_rows() -> None:
233
- source: Text = Text(local=Path("./test.tsv"), url="https://example.com/test.tsv", kind="text", rows=[0, 2, 5]) # pyright: ignore
234
- assert source.rows == [0, 2, 5]
233
+ source: Text = Text(local=Path("./test.tsv"), url="https://example.com/test.tsv", kind="text", rows=[1, 2, 5]) # pyright: ignore
234
+ assert source.rows == [1, 2, 5]
235
235
 
236
236
 
237
237
  # ? Section With Reindex
@@ -2351,7 +2351,7 @@ wheels = [
2351
2351
 
2352
2352
  [[package]]
2353
2353
  name = "tablassert"
2354
- version = "7.4.0"
2354
+ version = "7.4.2"
2355
2355
  source = { editable = "." }
2356
2356
  dependencies = [
2357
2357
  { name = "cyclopts" },
@@ -1,32 +0,0 @@
1
- # Changelog
2
-
3
- The canonical release history lives in the repository root at [`CHANGELOG.md`](https://github.com/SkyeAv/Tablassert/blob/main/CHANGELOG.md).
4
-
5
- ## Current Release Notes
6
-
7
- ## 7.4.0 - 2026-05-05
8
-
9
- ### Changes
10
-
11
- - Renamed CLI commands: `build-knowledge-graph` → `build`, `verify-table-configuration-syntax` → `validate`. Version now shown via `--version` flag.
12
- - Added `log` parameter to graph configuration for controlling unmatched entity and audit logging during builds.
13
- - Added `qc` parameter to `resolve_many()` for optional QC auditing. ONNX Runtime provider is auto-detected via `get_qc_provider()`.
14
- - Added `has_qc_runtime()` helper to `qc.py` and `empty_matches()` helper to `fullmap.py`.
15
- - Rewrote `downloader.py` with `DownloadReceipt`, exception classes, and file validation.
16
- - Refactored `cli.py` to use the shared `logger` instance instead of `loguru.logger` directly.
17
- - Unified failure log messages to a single `FAILED` prefix; unmatched entity logging now filters to NLP level 1 terms only.
18
- - Updated progress bar and section display labels to uppercase with pipe separators.
19
-
20
- ### Bug Fixes
21
-
22
- - Fixed tutorial table configuration using header names instead of Excel column letters for encodings.
23
-
24
- ### Documentation
25
-
26
- - Updated all documentation for renamed CLI commands.
27
- - Fixed tutorial and example YAML configurations to use Excel column letter references.
28
- - Updated `resolve_many()` API reference with new `qc` parameter and auto-detected QC provider.
29
- - Documented new `log` graph configuration parameter with example.
30
- - Fixed CITATION.cff version and CONTRIBUTING.md package list.
31
-
32
- For older releases and the full project history, open the root `CHANGELOG.md` in the repository.
@@ -1,10 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from pathlib import Path
4
-
5
- import pytest
6
-
7
-
8
- @pytest.fixture
9
- def fixtures_path() -> Path:
10
- return Path(__file__).parent / "fixtures"
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
File without changes
File without changes