Skip to content

Commit 33595a6

Browse files
TKaltofenTomKaltofen
authored andcommitted
chore(deps): bump mloda to 0.10.0 (#11)
* chore(deps): bump mloda to 0.10.0
1 parent bacd6c8 commit 33595a6

6 files changed

Lines changed: 47 additions & 30 deletions

File tree

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,16 @@ from mloda_plugin_govdata.feature_groups.govdata import StuttgartPopulationReade
2525
slug = "einwohner-nach-altersgruppen-und-stadtbezirken"
2626
result = mloda.run_all(
2727
[
28-
Feature("Einwohner", options={StuttgartPopulationReader.__name__: slug}),
29-
Feature("Stadtbezirk", options={StuttgartPopulationReader.__name__: slug}),
28+
Feature("Einwohner", options={StuttgartPopulationReader: slug}),
29+
Feature("Stadtbezirk", options={StuttgartPopulationReader: slug}),
3030
],
3131
compute_frameworks=["PyArrowTable"],
3232
)
3333
table = result[0] # pyarrow.Table with the requested columns
34+
result.plan # resolved execution steps: which FeatureGroup ran on which framework
3435
```
3536

36-
The option value is a GovData dataset slug or a direct distribution URL. The license is read from the CKAN distribution metadata. Set `BaseGovDataReader.cache_dir` to control where downloads are cached. For any other GovData CSV dataset, `GovDataReader` works out of the box and reads every column as a string; subclass it and set `schema` for typed columns.
37+
The options key is the reader class or its class-name string; both select the same reader. The option value is a GovData dataset slug or a direct distribution URL. The license is read from the CKAN distribution metadata. Set `BaseGovDataReader.cache_dir` to control where downloads are cached. For any other GovData CSV dataset, `GovDataReader` works out of the box and reads every column as a string; subclass it and set `schema` for typed columns.
3738

3839
Don't know the slug yet? Search GovData with the paginated CKAN `package_search` API:
3940

@@ -62,7 +63,7 @@ from mloda_plugin_govdata.feature_groups.govdata import BundeswahlleiterinReader
6263

6364
kerg = "https://www.bundeswahlleiterin.de/bundestagswahlen/2025/ergebnisse/opendata/btw25/csv/kerg.csv"
6465
result = mloda.run_all(
65-
[Feature("Gebiet", options={BundeswahlleiterinReader.__name__: kerg})],
66+
[Feature("Gebiet", options={BundeswahlleiterinReader: kerg})],
6667
compute_frameworks=["PyArrowTable"],
6768
)
6869
```
@@ -75,8 +76,8 @@ from mloda_plugin_govdata.feature_groups.govdata import UbaAirReader, uba_measur
7576
url = uba_measures_url(station=143, component=3, scope=2, date_from="2025-01-01", date_to="2025-01-01")
7677
result = mloda.run_all(
7778
[
78-
Feature("date_start", options={UbaAirReader.__name__: url}),
79-
Feature("value", options={UbaAirReader.__name__: url}),
79+
Feature("date_start", options={UbaAirReader: url}),
80+
Feature("value", options={UbaAirReader: url}),
8081
],
8182
compute_frameworks=["PyArrowTable"],
8283
)

demos/govdata_demo.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@ def _(Feature, StuttgartPopulationReader, mloda):
9494
_slug = "einwohner-nach-altersgruppen-und-stadtbezirken"
9595
_result = mloda.run_all(
9696
[
97-
Feature("Stichtag", options={StuttgartPopulationReader.__name__: _slug}),
98-
Feature("Stadtbezirk", options={StuttgartPopulationReader.__name__: _slug}),
99-
Feature("Alter in 10 Gruppen", options={StuttgartPopulationReader.__name__: _slug}),
100-
Feature("Einwohner", options={StuttgartPopulationReader.__name__: _slug}),
97+
Feature("Stichtag", options={StuttgartPopulationReader: _slug}),
98+
Feature("Stadtbezirk", options={StuttgartPopulationReader: _slug}),
99+
Feature("Alter in 10 Gruppen", options={StuttgartPopulationReader: _slug}),
100+
Feature("Einwohner", options={StuttgartPopulationReader: _slug}),
101101
],
102102
compute_frameworks=["PyArrowTable"],
103103
)
@@ -116,7 +116,7 @@ def _(mo):
116116
def _(BundeswahlleiterinReader, Feature, mloda):
117117
_kerg = "https://www.bundeswahlleiterin.de/bundestagswahlen/2025/ergebnisse/opendata/btw25/csv/kerg.csv"
118118
_result = mloda.run_all(
119-
[Feature("Gebiet", options={BundeswahlleiterinReader.__name__: _kerg})],
119+
[Feature("Gebiet", options={BundeswahlleiterinReader: _kerg})],
120120
compute_frameworks=["PyArrowTable"],
121121
)
122122
elections = _result[0].to_pandas()
@@ -135,8 +135,8 @@ def _(Feature, UbaAirReader, mloda, uba_measures_url):
135135
_url = uba_measures_url(station=143, component=3, scope=2, date_from="2025-01-01", date_to="2025-01-01")
136136
_result = mloda.run_all(
137137
[
138-
Feature("date_start", options={UbaAirReader.__name__: _url}),
139-
Feature("value", options={UbaAirReader.__name__: _url}),
138+
Feature("date_start", options={UbaAirReader: _url}),
139+
Feature("value", options={UbaAirReader: _url}),
140140
],
141141
compute_frameworks=["PyArrowTable"],
142142
)

mloda_plugin_govdata/feature_groups/govdata/reader.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
from mloda.provider import FeatureSet
2020

2121
# Imported for its registration side effect so "PyArrowTable" resolves; the reader returns a pyarrow Table.
22-
from mloda_plugins.compute_framework.base_implementations.pyarrow.table import PyArrowTable # noqa: F401
22+
# Public path since mloda 0.10.0 (lazy export); resolving it imports and registers the framework class.
23+
from mloda.user import PyArrowTable # noqa: F401
2324
from mloda_plugins.feature_group.input_data.read_file import ReadFile
2425

2526
from .core.cache import DownloadCache
@@ -64,9 +65,9 @@ def match_subclass_data_access(cls, data_access: Any, feature_names: list[str],
6465

6566
@classmethod
6667
def load_data(cls, data_access: Any, features: FeatureSet) -> Any:
67-
# Touch features first: the framework probes load_data(None, None) and
68-
# only tolerates AttributeError to detect scoped-access support.
69-
requested = sorted(features.get_all_names()) # deterministic column order
68+
# Overriding load_data wholesale classifies this as a final reader (mloda >=0.10.0
69+
# is_final_reader, structural, no runtime probe).
70+
requested = list(features.get_all_names()) # sorted tuple since mloda 0.10.0; deterministic column order
7071
locator = cls._coerce_locator(data_access)
7172
table = cls._read_table(locator)
7273
available = set(table.column_names)

mloda_plugin_govdata/feature_groups/govdata/tests/test_reader.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
import json
44
from pathlib import Path
5-
from typing import cast
5+
from typing import Any, cast
66

77
import httpx
88
import pyarrow as pa
99
import pytest
1010
import respx
1111

1212
from mloda.provider import FeatureSet
13-
from mloda.user import Feature, mloda
13+
from mloda.user import Feature, Options, mloda
14+
from mloda_plugins.feature_group.input_data.read_file import ReadFile
1415

1516
from mloda_plugin_govdata.feature_groups.govdata.bundeswahlleiterin import BundeswahlleiterinReader
1617
from mloda_plugin_govdata.feature_groups.govdata.feature import GovDataFeature
@@ -33,19 +34,26 @@ def _mock_population_endpoints(fixtures_dir: Path) -> None:
3334

3435

3536
class _FakeFeatureSet:
36-
"""Just enough FeatureSet surface for load_data."""
37+
"""Just enough FeatureSet surface for load_data; mirrors the sorted-tuple contract."""
3738

3839
def __init__(self, names: set[str]) -> None:
39-
self._names = names
40+
self._names = tuple(sorted(names))
4041

41-
def get_all_names(self) -> set[str]:
42+
def get_all_names(self) -> tuple[str, ...]:
4243
return self._names
4344

4445

4546
def test_feature_group_uses_base_govdata_reader() -> None:
4647
assert isinstance(GovDataFeature.input_data(), BaseGovDataReader)
4748

4849

50+
def test_class_options_key_normalizes_to_reader_name() -> None:
51+
# The reader class works as an options key; it normalizes to the class-name string (mloda >=0.10.0).
52+
# The cast bridges a 0.10.0 typing gap: the runtime accepts class keys, the hints only admit str.
53+
options = Options(cast(dict[str, Any], {GovDataReader: SLUG}))
54+
assert options.get(GovDataReader.__name__) == SLUG
55+
56+
4957
@respx.mock
5058
def test_load_data_level2(fixtures_dir: Path, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
5159
monkeypatch.setattr(StuttgartPopulationReader, "cache_dir", str(tmp_path))
@@ -67,6 +75,11 @@ def test_load_data_level2(fixtures_dir: Path, tmp_path: Path, monkeypatch: pytes
6775
assert set(table.schema.names) == {"Einwohner", "Stadtbezirk"}
6876
assert table.num_rows == 1000
6977
assert table.schema.field("Einwohner").type == pa.int64()
78+
# RunResult.plan (mloda >=0.10.0): the resolved execution steps name our group and framework.
79+
compute_steps = [step for step in result.plan if step.step_kind == "compute"]
80+
assert [step.feature_group_name for step in compute_steps] == ["GovDataFeature"]
81+
assert compute_steps[0].compute_framework_name == "PyArrowTable"
82+
assert set(compute_steps[0].requested_feature_names) == {"Einwohner", "Stadtbezirk"}
7083

7184

7285
@respx.mock
@@ -184,10 +197,12 @@ def test_peek_rejects_unusable_data_access() -> None:
184197
"reader",
185198
[BaseGovDataReader, GovDataReader, StuttgartPopulationReader, BundeswahlleiterinReader, UbaAirReader],
186199
)
187-
def test_load_data_probe_still_raises_attribute_error(reader: type[BaseGovDataReader]) -> None:
188-
# The framework probes load_data(None, None) and only tolerates AttributeError.
189-
with pytest.raises(AttributeError):
190-
reader.load_data(None, cast(FeatureSet, None))
200+
def test_readers_classify_as_final_readers(reader: type[BaseGovDataReader]) -> None:
201+
# mloda >=0.10.0 classifies readers structurally: overriding load_data wholesale
202+
# relative to the ReadFile anchor makes each reader final; the ReadFile base is not.
203+
assert reader.final_reader_anchor() is ReadFile
204+
assert reader.is_final_reader() is True
205+
assert ReadFile.is_final_reader() is False
191206

192207

193208
@respx.mock

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ description = "mloda plugin providing connectors and harmonization for German go
1111
license = "Apache-2.0"
1212
authors = [{ name = "Tom Kaltofen", email = "tomkaltofen@mloda.ai" }]
1313
dependencies = [
14-
"mloda>=0.9.0",
14+
"mloda>=0.10.0,<0.11.0",
1515
"mloda-testing>=0.3.1",
1616
"httpx>=0.27",
1717
"pandas>=2.0",

uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)