GISPulse v2.0.0
[2.0.0]
The first major release. Numerically it's a jump from 1.6.2, but in
practice the API surface is the same as 1.7.0 / 1.8.0 / 1.9.0 —
features that accumulated on main without ever being published to
PyPI. We promote the whole stack in one tag and reset the public version
to match the product story.
Three threads converge here:
- Foundations (was tagged internally
v1.8.0) —gispulse.*
mono-package,ExtensionHubreplacingPluginHub,GISPulseApp
façade, full MCP server, data-pack regime, CLI / HTTP / template
routers. - Worldwide aggregator (was tagged internally
v1.9.0) — lazy
DuckDB-backed fetcher network covering 4 protocol families
(GeoParquetS3,OGCFeatures,STAC,HttpFile) and a curated
worldwide_catalog.ymllisting France / EU / world data sources. - Data-pack rails — the first third-party data-packs can now ship
on PyPI: a discovery channel via thegispulse.data_packsentry-point,
an Ed25519 signature gate on EXTERNAL manifests, and a shared licence
payload format that also covers the future SaaS tenant licence.
The full migration path is in MIGRATION-2.0.md. The
short version: no application code change is strictly required — the
_compat.py meta-path shim absorbs the import-path move and the
PluginHub rename keeps a working alias until 2.1.
Added
- Data-pack regime — PyPI discovery channel (T5). A third channel
alongside the bundled OSS manifests andGISPULSE_DATA_PACKS_DIR: a
Python entry-point groupgispulse.data_packslets a third-party
package register its manifests at install time. One bad pack never
locks out the others (every failure path is isolated and logged).
(#269) - Data-pack regime — Ed25519 signature gate (G1a).
DataPackManifest
gains an optionalsignaturefield. An EXTERNAL manifest carrying a
signature is verified against the public key in
GISPULSE_DATA_PACK_PUBLIC_KEYbefore being registered; tampered or
foreign-signed manifests are dropped with explicit log events
(data_pack_signature_invalid,
data_pack_signature_no_public_key). INTERNAL (bundled) manifests
are exempt — the OSS tree is the source of truth. Unsigned EXTERNAL
packs are admitted by default (rollout-friendly); set
GISPULSE_DATA_PACK_REQUIRE_SIGNATURE=trueto refuse them. (#271) - Unified Ed25519 licence payload format (L0). New
gispulse.core.licence_formatdefines the single payload schema
shared by the per-machine licence key (Mode A), the future SaaS
tenant licence (Mode B) and the data-pack manifest signature.
Versioned viaschema_version, forward-compat (unknown fields land
inLicencePayload.extra, never crash an older verifier),
canonicalised JSON (sort-keys, compact, UTF-8) so bytes-to-sign are
stable across runs and Python versions. (#266) - High-level OGC client for data packs (T1). New
gispulse.core.fetchers.ogc_client.fetch_features(...)— a one-liner
any data-pack can use without building anAccessSpec. Thin layer
over the consolidated transport: argument normalisation, WFS vs OGC
API Features dispatch, typed network-error surface
(OGCEndpointUnreachable,OGCClientError) so callers don't depend
on httpx classes. (#267) - Declarative ZoningElement normaliser (T2). New
gispulse.core.zoning_normalizermaps heterogeneous source records
into a common 8-field schema (geometry, zone_code, zone_label, hilucs_class, plan_id, plan_date, regulation_ref, source_country)
inspired by INSPIRE PlannedLandUse.ZoningMappingis a flat
declarative{target -> source_key}table plus an optional
best-effort HILUCS lookup. CRS is mandatory and must be explicit
(EPSG:XXXX). HILUCS misses leave the columnNone, never crash
the batch. (#268) regulatory-zoningdata-pack content type (T3). New value in
DATA_PACK_CONTENTSso a manifest of that type is recognised by the
discovery and signature gate. NewRegulatoryZoningEntrydataclassfrom_dict()validator: required-field set, no unknown fields,
ISO-3166-1 alpha-2 country, known protocol, explicitEPSG:CRS,
bbox 4-numbers.DataPackManifest.entriesstays a list of opaque
dicts — entries are validated on demand so the pack format can
evolve without changing the manifest loader. (#270)
Changed
PluginHubrenamed toExtensionHub. The class lives in the
same module (gispulse.core.plugin_hub); aPluginHub = ExtensionHub
alias preserves existing imports. The alias is scheduled for removal
in 2.1.0. The data-pack regime (_discover_data_packs) is wired
into both bundled discovery and the new PyPI channel.gispulse.core.plugin_contractspublic surface frozen via
__all__. The 8 symbols actually exported by the 1.6.2 wheel are
gelled with an explicit__all__and an anti-regression test. The
types that moved toplugin_model.pyduring the consolidation
(Tier,PluginManifest,DataPackManifest, …) were never in
plugin_contractsin 1.6.2 — no compat shim is needed._compat.pydeprecation horizon corrected. The docstring and
DeprecationWarningmessage had carried over a stale "removed in
1.9.0" line; both now correctly point at 2.1.0, in step with
the release plan.
Fixed
security-auditjob — silence two disputed upstream advisories.
pip-auditwas failing onjoblibPYSEC-2024-277 (disputed by
upstream, only triggered when loading untrusted cache content) and
pyjwtPYSEC-2025-183 (disputed by upstream, the key length is
chosen by the application, not the library). Both are added to the
--ignore-vulnallowlist with a re-evaluation note. No code change.
Migration
See MIGRATION-2.0.md. TL;DR:
- imports under top-level
core.*,capabilities.*,rules.*,
orchestration.*,persistence.*,catalog.*continue to work via
the_compat.pymeta-path shim with a one-timeDeprecationWarning; PluginHubcontinues to work via thePluginHub = ExtensionHub
alias;- both will be removed in 2.1.0 — migrate to
gispulse.*/
ExtensionHubat your leisure.