statcatlib 0.8.0__py3-none-any.whl
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.
- statcatlib/__init__.py +187 -0
- statcatlib/bundle.py +565 -0
- statcatlib/cli/__init__.py +546 -0
- statcatlib/expr.py +167 -0
- statcatlib/model/__init__.py +56 -0
- statcatlib/model/agents.py +32 -0
- statcatlib/model/catalog.py +71 -0
- statcatlib/model/classification.py +19 -0
- statcatlib/model/dataset.py +198 -0
- statcatlib/model/distribution.py +50 -0
- statcatlib/model/licence.py +18 -0
- statcatlib/model/quality.py +31 -0
- statcatlib/model/skos.py +141 -0
- statcatlib/model/spatial.py +19 -0
- statcatlib/model/temporal.py +33 -0
- statcatlib/model/types.py +5 -0
- statcatlib/py.typed +0 -0
- statcatlib/query.py +924 -0
- statcatlib/sources/__init__.py +13 -0
- statcatlib/sources/ckan.py +490 -0
- statcatlib/sources/sdmx.py +321 -0
- statcatlib/store/__init__.py +38 -0
- statcatlib/store/lance.py +1494 -0
- statcatlib/store/row.py +30 -0
- statcatlib/store/schema.py +403 -0
- statcatlib/store/scopes.py +1419 -0
- statcatlib/store/sentinel.py +99 -0
- statcatlib/store/store.py +6836 -0
- statcatlib/store/xhtml.py +206 -0
- statcatlib/urn.py +108 -0
- statcatlib-0.8.0.dist-info/METADATA +429 -0
- statcatlib-0.8.0.dist-info/RECORD +35 -0
- statcatlib-0.8.0.dist-info/WHEEL +4 -0
- statcatlib-0.8.0.dist-info/entry_points.txt +3 -0
- statcatlib-0.8.0.dist-info/licenses/LICENSE +180 -0
statcatlib/model/skos.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""SKOS domain types for statcatlib.
|
|
2
|
+
|
|
3
|
+
ConceptScheme and Concept are first-class artefacts, on a par with Dataset
|
|
4
|
+
and Catalog. They model DCAT's use of SKOS for themes, types, subjects, and
|
|
5
|
+
other controlled vocabulary references.
|
|
6
|
+
|
|
7
|
+
Identity model
|
|
8
|
+
--------------
|
|
9
|
+
- ``ConceptScheme`` is globally identified by URI.
|
|
10
|
+
- ``Concept`` is identified by ``notation`` within its scheme (the "code").
|
|
11
|
+
It does not carry a ``uri`` field — the URI is implicit from the scheme and
|
|
12
|
+
reconstructed at serialization or recovered from the storage PK at load time.
|
|
13
|
+
This mirrors how sdmxlib models Code (local ``id``) vs. Codelist (global URN).
|
|
14
|
+
|
|
15
|
+
Ref types
|
|
16
|
+
---------
|
|
17
|
+
Cross-boundary citations use typed ref objects rather than bare strings:
|
|
18
|
+
|
|
19
|
+
- ``ConceptSchemeRef`` — carried on ``Catalog.theme_taxonomy``
|
|
20
|
+
- ``ConceptRef`` — carried on ``Dataset.themes``, ``.subject``, ``.dataset_type``
|
|
21
|
+
|
|
22
|
+
Non-identity fields on refs (``label``, ``notation``, ``scheme_uri``) are
|
|
23
|
+
``eq=False, hash=False``: two refs with the same URI compare equal regardless
|
|
24
|
+
of what display metadata they carry. This ensures refs parsed from different
|
|
25
|
+
sources (DCAT-AP XML, JSON-LD, store read-back) match cleanly.
|
|
26
|
+
|
|
27
|
+
XKOS extensibility
|
|
28
|
+
------------------
|
|
29
|
+
The ``broader``/``narrower``/``related`` relation names in storage use a
|
|
30
|
+
VARCHAR column rather than an enum, so future XKOS types (``xkos:generalizes``,
|
|
31
|
+
``xkos:isPartOf``, etc.) can be added without schema changes.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
import attrs
|
|
37
|
+
from sdmxlib import InternationalString
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"Concept",
|
|
41
|
+
"ConceptRef",
|
|
42
|
+
"ConceptScheme",
|
|
43
|
+
"ConceptSchemeRef",
|
|
44
|
+
"is_concept_in_scheme",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@attrs.frozen
|
|
49
|
+
class ConceptSchemeRef:
|
|
50
|
+
"""Typed reference to a ConceptScheme.
|
|
51
|
+
|
|
52
|
+
Carried on ``Catalog.theme_taxonomy`` (DCAT's ``dcat:themeTaxonomy``).
|
|
53
|
+
URI is identity; label is denormalized display convenience only.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
uri: str
|
|
57
|
+
label: InternationalString = attrs.field(factory=InternationalString, eq=False, hash=False)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@attrs.frozen
|
|
61
|
+
class ConceptRef:
|
|
62
|
+
"""Typed reference to a Concept.
|
|
63
|
+
|
|
64
|
+
Carried on ``Dataset.themes``, ``.subject``, and ``.dataset_type``
|
|
65
|
+
(DCAT's ``dcat:theme``, ``dcterms:subject``, ``dcterms:type``).
|
|
66
|
+
|
|
67
|
+
URI is identity. ``scheme_uri``, ``notation``, and ``label`` are hints
|
|
68
|
+
that speed up display and within-scheme lookups but do not affect equality.
|
|
69
|
+
|
|
70
|
+
``label`` is populated at read time via a LEFT JOIN with the concept table;
|
|
71
|
+
it is an empty dict when the concept is not materialized in the store
|
|
72
|
+
(permissive refs — datasets may cite concepts from external vocabularies
|
|
73
|
+
that are never locally ingested).
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
uri: str
|
|
77
|
+
scheme_uri: str | None = attrs.field(default=None, eq=False, hash=False)
|
|
78
|
+
notation: str | None = attrs.field(default=None, eq=False, hash=False)
|
|
79
|
+
label: InternationalString = attrs.field(factory=InternationalString, eq=False, hash=False)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@attrs.frozen
|
|
83
|
+
class Concept:
|
|
84
|
+
"""A SKOS Concept.
|
|
85
|
+
|
|
86
|
+
Identity is ``notation`` within its parent scheme — the "code" (e.g. "PUMF",
|
|
87
|
+
"HEAL", "ON"). ``broader``, ``narrower``, and ``related`` are tuples of
|
|
88
|
+
notations in the same scheme, not URIs. Cross-scheme relations use
|
|
89
|
+
``ConceptRef`` or (in future) an XKOS Correspondence artefact.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
notation: str
|
|
93
|
+
label: InternationalString = attrs.field(factory=InternationalString)
|
|
94
|
+
alt_label: InternationalString = attrs.field(factory=InternationalString)
|
|
95
|
+
definition: InternationalString | None = None
|
|
96
|
+
broader: tuple[str, ...] = () # notations within same scheme
|
|
97
|
+
narrower: tuple[str, ...] = ()
|
|
98
|
+
related: tuple[str, ...] = ()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@attrs.frozen
|
|
102
|
+
class ConceptScheme:
|
|
103
|
+
"""A SKOS ConceptScheme — a controlled vocabulary.
|
|
104
|
+
|
|
105
|
+
Globally identified by URI. Owns its Concepts: a Concept has no identity
|
|
106
|
+
outside its scheme (``skos:inScheme`` is a required property).
|
|
107
|
+
|
|
108
|
+
``concepts`` maps notation → Concept for Pythonic within-scheme access::
|
|
109
|
+
|
|
110
|
+
scheme.concepts["PUMF"] # direct lookup by notation
|
|
111
|
+
|
|
112
|
+
``top_concepts`` lists notations of the top-level hierarchy entries
|
|
113
|
+
(``skos:hasTopConcept``).
|
|
114
|
+
|
|
115
|
+
Construction with embedded concepts enables cascade persistence::
|
|
116
|
+
|
|
117
|
+
store.put_concept_scheme(ConceptScheme(uri=..., label=..., concepts={...}))
|
|
118
|
+
|
|
119
|
+
``put_concept_scheme()`` writes the scheme row and cascades to write each
|
|
120
|
+
Concept row. This is the correct container convenience: the ownership
|
|
121
|
+
relation is genuine.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
uri: str
|
|
125
|
+
label: InternationalString
|
|
126
|
+
definition: InternationalString | None = None
|
|
127
|
+
concepts: dict[str, Concept] = attrs.field(factory=dict) # notation → Concept
|
|
128
|
+
top_concepts: tuple[str, ...] = () # notations
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def is_concept_in_scheme(scheme: ConceptScheme, notation: str) -> bool:
|
|
132
|
+
"""Return True if *notation* is a known concept in *scheme*.
|
|
133
|
+
|
|
134
|
+
Pure-Python — no DuckDB or any other storage involved.
|
|
135
|
+
Useful for validation pipelines that operate on in-memory domain objects.
|
|
136
|
+
|
|
137
|
+
Example::
|
|
138
|
+
|
|
139
|
+
valid = is_concept_in_scheme(product_type_scheme, dataset.dataset_type.notation)
|
|
140
|
+
"""
|
|
141
|
+
return notation in scheme.concepts
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Spatial types for the statcatlib domain model."""
|
|
2
|
+
|
|
3
|
+
from attrs import define
|
|
4
|
+
from sdmxlib import InternationalString
|
|
5
|
+
|
|
6
|
+
__all__ = ["SpatialCoverage"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@define
|
|
10
|
+
class SpatialCoverage:
|
|
11
|
+
"""A geographic area covered by the dataset.
|
|
12
|
+
|
|
13
|
+
Maps to dct:spatial → dct:Location in DCAT-AP.
|
|
14
|
+
Can be a named region (with URI) or a bounding box.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
label: InternationalString | None = None
|
|
18
|
+
uri: str | None = None
|
|
19
|
+
bbox: tuple[float, float, float, float] | None = None
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Temporal types for the statcatlib domain model."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from attrs import define
|
|
6
|
+
from sdmxlib import InternationalString
|
|
7
|
+
|
|
8
|
+
__all__ = ["Frequency", "TemporalCoverage"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@define
|
|
12
|
+
class TemporalCoverage:
|
|
13
|
+
"""A time interval that the dataset covers.
|
|
14
|
+
|
|
15
|
+
Maps to dct:temporal → dct:PeriodOfTime in DCAT-AP.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
start: datetime | None = None
|
|
19
|
+
end: datetime | None = None
|
|
20
|
+
label: InternationalString | None = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@define
|
|
24
|
+
class Frequency:
|
|
25
|
+
"""Update frequency of a dataset.
|
|
26
|
+
|
|
27
|
+
Maps to dct:accrualPeriodicity in DCAT-AP. The id should use
|
|
28
|
+
the Dublin Core frequency vocabulary or SDMX CL_FREQ values
|
|
29
|
+
where possible (e.g. "ANNUAL", "QUARTERLY", "MONTHLY").
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
id: str
|
|
33
|
+
label: InternationalString | None = None
|
statcatlib/py.typed
ADDED
|
File without changes
|