Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## 0.1.1 (2026-06-11)

**Fixed.** Partial remote caches no longer error: after downloading a single
remote tier (e.g. `download("geo.admin1")`), `Resolver.auto()` raised
`MissingModuleDependencyError` demanding sibling tiers, and explicitly
requesting one tier via `module_ids` transitively queued every declared
sibling (a ~796 MB download). Declared dependencies on remote packs that are
not in the local cache are now skipped during loading and validation; bundled
and cached dependencies are still enforced.

**Docs.** Corrected the OECD DAC entry in NOTICE.md: OECD distributes its
content under CC BY 4.0 (attribution, commercial use permitted) since July
2024 — the previous wording incorrectly claimed a non-commercial restriction.
Also documented the DAC contribution to the org entity store and updated the
upstream URL.

## 0.1.0 (2026-06-11)

First public beta release.
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ rk.download("geo.admin1") # ~12 MB; verifies checksum, then marks is_available
```python
>>> import resolvekit as rk
>>> rk.__version__
'0.1.0'
'0.1.1'
>>> rk.resolve_id("United States")
'country/USA'
```
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/resolver.md
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ Resolver.lite().domains # ['geo']

```python
r.info.data_version # "2026.06"
r.info.resolvekit_version # "0.1.0"
r.info.resolvekit_version # "0.1.1"
r.info.domains # ("geo", "org")
r.info.routing_mode # "auto"
r.info.closed # False
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "resolvekit"
version = "0.1.0"
version = "0.1.1"
description = "Entity and place resolution system that maps messy place/entity strings and codes to canonical entities"
requires-python = ">=3.12"

Expand Down
25 changes: 19 additions & 6 deletions src/resolvekit/NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,25 @@ license requires attribution, that attribution is given below.

## OECD DAC (Development Assistance Committee)

- **Contributes:** DAC country codes and recipient classifications used in the
geo entity store.
- **Upstream:** https://www.oecd.org/dac/financing-sustainable-development/development-finance-standards/dacandcrscodelists.htm
- **License:** OECD terms of use — data is freely available for non-commercial
and research use with attribution.
https://www.oecd.org/termsandconditions/
- **Contributes:** DAC recipient, provider, channel, and agency codes with
their English/French names and an ISO3 crosswalk. These populate DAC codes
on countries and regions in the geo entity store and provider and
government-agency entities in the org entity store.
- **Upstream:** https://development-finance-codelists.oecd.org/ (DAC and CRS
code lists)
- **License:** OECD Terms and Conditions. Since 1 July 2024 most OECD data and
content is published under Creative Commons Attribution 4.0 International
(CC BY 4.0), which permits reuse — including commercial use — with
attribution; earlier content is available on terms similar to CC BY 4.0.
https://www.oecd.org/en/about/terms-conditions.html
https://creativecommons.org/licenses/by/4.0/
- **Modifications:** only the codelists (codes, names, and the ISO3 crosswalk)
were extracted and repackaged; no OECD statistical, financial, or aid-flow
data is redistributed.
- **Attribution required:** OECD DAC codelists are used under the OECD Terms
and Conditions (CC BY 4.0). Source: OECD Development Assistance Committee
(DAC). The OECD logo and branding are not covered by this license and are
not used.

## HDX Python Country / UN M49

Expand Down
55 changes: 53 additions & 2 deletions src/resolvekit/core/api/loading/module_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,41 @@ def _load_and_separate_datapacks(
return base_packs, overlay_packs


def _remote_dependency_uncached(
module_id: str,
available: dict[str, Path],
manifest_overrides: dict[str, dict[str, object]],
) -> bool:
"""Return True if ``module_id`` is a remote-distribution module whose data
is not in the local cache.

Such a dependency may be absent from a load set without error: remote
packs the user hasn't downloaded are not hard errors (partial caches are
first-class, and ``Resolver.auto()`` never triggers a network fetch).
Bundled dependencies and unknown module ids stay hard errors.
"""
from resolvekit.core.module_registry import load_module_metadata
from resolvekit.core.remote import is_cached

if module_id not in available:
return False
path = available[module_id]
if not (path / "metadata.json").exists():
return False
metadata = load_module_metadata(module_id, path, overrides=manifest_overrides)
return metadata.distribution == "remote" and not is_cached(metadata)


def _validate_module_dependencies(
base_packs: dict[str, LoadedDataPack],
overlay_packs: dict[str, LoadedDataPack],
pack_filter: set[str],
) -> None:
from resolvekit.core.module_registry import get_manifest_overrides

available_module_ids = set(base_packs) | set(overlay_packs)
registry: dict[str, Path] | None = None
manifest_overrides: dict[str, dict[str, object]] | None = None
for loaded in [*base_packs.values(), *overlay_packs.values()]:
if pack_filter and loaded.pack_id not in pack_filter:
continue
Expand All @@ -149,6 +178,22 @@ def _validate_module_dependencies(
for module_id in loaded.metadata.module_dependencies
if module_id not in available_module_ids
]
if missing:
# An absent dependency is only a hard error when its data could
# have been loaded — a declared dep on a remote pack the user
# hasn't downloaded is skipped, mirroring the auto-mode intent in
# _resolve_requested_module_paths.
if registry is None:
registry = list_available_modules()
manifest_overrides = get_manifest_overrides()
assert manifest_overrides is not None
missing = [
module_id
for module_id in missing
if not _remote_dependency_uncached(
module_id, registry, manifest_overrides
)
]
if missing:
raise MissingModuleDependencyError(loaded.module_id, missing)

Expand Down Expand Up @@ -250,8 +295,10 @@ def _resolve_requested_module_paths(
continue
# In auto mode, silently skip dependencies whose data isn't
# locally available (remote packs the user hasn't downloaded
# are not hard errors — see v1-scope §225). In explicit mode
# we always queue them so the queue-loop's own
# are not hard errors — see v1-scope §225). In explicit mode,
# likewise skip remote-uncached dependencies so requesting one
# module never transitively forces sibling downloads; unknown
# module ids are still queued so the queue-loop's own
# ``module_id not in available`` check raises
# ``DataModuleNotFoundError``.
if auto_mode and (
Expand All @@ -261,6 +308,10 @@ def _resolve_requested_module_paths(
)
):
continue
if not auto_mode and _remote_dependency_uncached(
dependency, available, manifest_overrides
):
continue
queue.append(dependency)
if metadata.is_overlay:
for dependency in metadata.base_module_ids or []:
Expand Down
Loading
Loading