sdmxlib 0.41.3__tar.gz → 0.43.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.
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/PKG-INFO +1 -1
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/pyproject.toml +1 -1
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/code_query.py +47 -6
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/README.md +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/_duckdb.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/client.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/federated.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/filters.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/policy.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/providers.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/query.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/registry.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/api/session.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/builders/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/builders/contentconstraint.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/catalog.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/data_store.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_csv/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_csv/reader.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_csv/writer.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json/_data_common.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json/data_v1.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json/data_v2.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json/metadata.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json/reader.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json/structure_values.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json/writer.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json_1_0/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_json_1_0/writer.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml/_common.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml21/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml21/namespaces.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml21/reader.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml21/writer.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml30/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml30/metadata.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml30/namespaces.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml30/reader.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml30/writer.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml31/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml31/namespaces.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml31/reader.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/formats/sdmx_ml31/writer.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/local/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/local/data_store.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/local/registry.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/annotations.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/base.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/binding.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/category.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/codelist.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/collections.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/concept.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/constraint.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/convert.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/dataflow.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/dataset.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/datastructure.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/expr.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/hierarchy.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/hierarchy_query.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/in_memory_registry.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/istring.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/mapping.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/message.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/metadataflow.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/metadataset.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/metadatastructure.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/organisation.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/provision.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/ref.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/registry.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/representation.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/urn.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/model/validation.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/polars.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/py.typed +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/rest.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/sql.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/storage/__init__.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/storage/_kinds.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/storage/lazy.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/storage/readers.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/storage/schema.py +0 -0
- {sdmxlib-0.41.3 → sdmxlib-0.43.0}/src/sdmxlib/storage/writers.py +0 -0
|
@@ -956,14 +956,20 @@ def _emit_string_match(
|
|
|
956
956
|
join_params: list[object],
|
|
957
957
|
annotation_join_aliases: dict[str, str],
|
|
958
958
|
) -> tuple[str, list[object]]:
|
|
959
|
-
pattern = _ilike_pattern(pred.op, pred.value)
|
|
960
959
|
field = pred.field
|
|
960
|
+
# Natural-language label fields (name / annotation title / annotation
|
|
961
|
+
# text) are matched accent- AND punctuation-INSENSITIVELY via
|
|
962
|
+
# :func:`_label_match_sql`, so "Montreal" finds "Montréal" and
|
|
963
|
+
# "Trois Rivieres" finds "Trois-Rivières". The raw value is passed and
|
|
964
|
+
# normalised in SQL. ID fields (code_id / parent_id) keep the plain ILIKE
|
|
965
|
+
# — codes and DGUIDs are ASCII identifiers, so folding them is a no-op
|
|
966
|
+
# that only defeats indexes.
|
|
961
967
|
if isinstance(field, _IdField):
|
|
962
|
-
return f"{row_alias}.code_id ILIKE ?", [
|
|
968
|
+
return f"{row_alias}.code_id ILIKE ?", [_ilike_pattern(pred.op, pred.value)]
|
|
963
969
|
if isinstance(field, _ParentIdField):
|
|
964
|
-
return f"{row_alias}.parent_id ILIKE ?", [
|
|
970
|
+
return f"{row_alias}.parent_id ILIKE ?", [_ilike_pattern(pred.op, pred.value)]
|
|
965
971
|
if isinstance(field, _NameField):
|
|
966
|
-
return f"{row_alias}.name[?]
|
|
972
|
+
return _label_match_sql(f"{row_alias}.name[?]", pred.op), [field.lang, pred.value]
|
|
967
973
|
if isinstance(field, _AnnotationField):
|
|
968
974
|
alias = _ensure_annotation_join(
|
|
969
975
|
field.type,
|
|
@@ -972,7 +978,7 @@ def _emit_string_match(
|
|
|
972
978
|
join_params=join_params,
|
|
973
979
|
annotation_join_aliases=annotation_join_aliases,
|
|
974
980
|
)
|
|
975
|
-
return f"{alias}.title
|
|
981
|
+
return _label_match_sql(f"{alias}.title", pred.op), [pred.value]
|
|
976
982
|
if isinstance(field, _AnnotationTextField):
|
|
977
983
|
text_alias = _ensure_annotation_text_join(
|
|
978
984
|
field.type,
|
|
@@ -982,7 +988,7 @@ def _emit_string_match(
|
|
|
982
988
|
join_params=join_params,
|
|
983
989
|
annotation_join_aliases=annotation_join_aliases,
|
|
984
990
|
)
|
|
985
|
-
return f"{text_alias}.text
|
|
991
|
+
return _label_match_sql(f"{text_alias}.text", pred.op), [pred.value]
|
|
986
992
|
msg = f"Unsupported field for string match: {type(field).__name__}"
|
|
987
993
|
raise NotImplementedError(msg)
|
|
988
994
|
|
|
@@ -1160,6 +1166,41 @@ def _ilike_pattern(op: str, value: str) -> str:
|
|
|
1160
1166
|
raise NotImplementedError(msg)
|
|
1161
1167
|
|
|
1162
1168
|
|
|
1169
|
+
# Accent- AND punctuation-insensitive label matching. ``strip_accents`` folds
|
|
1170
|
+
# diacritics; the regexp collapses runs of Unicode punctuation + separators
|
|
1171
|
+
# (``\p{P}\p{Z}`` + whitespace) to a single space, so "Trois Rivieres" matches
|
|
1172
|
+
# "Trois-Rivières", "St Johns" ~ "St. John's", etc. ``\p{P}\p{Z}`` keeps
|
|
1173
|
+
# letters of any script (Latin, Inuktitut syllabics, …) — unlike a naive
|
|
1174
|
+
# ``[^a-zA-Z0-9]``, which would destroy non-Latin names. The regexp also
|
|
1175
|
+
# strips ILIKE wildcards (``%`` / ``_`` are punctuation), so the bound value
|
|
1176
|
+
# needs no LIKE-escaping.
|
|
1177
|
+
_LABEL_NORM_REGEX = r"[\p{P}\p{Z}\s]+"
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
def _label_norm(expr: str) -> str:
|
|
1181
|
+
"""Wrap ``expr`` in the accent + punctuation fold used for label search."""
|
|
1182
|
+
return f"trim(regexp_replace(strip_accents({expr}), '{_LABEL_NORM_REGEX}', ' ', 'g'))"
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
def _label_match_sql(col_expr: str, op: str) -> str:
|
|
1186
|
+
"""Build an accent/punctuation-insensitive ILIKE of ``col_expr`` vs a bound ``?``.
|
|
1187
|
+
|
|
1188
|
+
Both sides are folded by :func:`_label_norm`, then the op decides where
|
|
1189
|
+
the ``%`` wildcards go. The value placeholder is normalised in SQL (not
|
|
1190
|
+
pre-wrapped), so callers pass the raw value, not an ILIKE pattern.
|
|
1191
|
+
"""
|
|
1192
|
+
col = _label_norm(col_expr)
|
|
1193
|
+
val = _label_norm("?")
|
|
1194
|
+
if op == "contains":
|
|
1195
|
+
return f"{col} ILIKE '%' || {val} || '%'"
|
|
1196
|
+
if op == "starts_with":
|
|
1197
|
+
return f"{col} ILIKE {val} || '%'"
|
|
1198
|
+
if op == "ends_with":
|
|
1199
|
+
return f"{col} ILIKE '%' || {val}"
|
|
1200
|
+
msg = f"Unsupported string op: {op}"
|
|
1201
|
+
raise NotImplementedError(msg)
|
|
1202
|
+
|
|
1203
|
+
|
|
1163
1204
|
# ── Row → Code construction ─────────────────────────────────────────────
|
|
1164
1205
|
|
|
1165
1206
|
|
|
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
|
|
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
|
|
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
|
|
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
|