Output adapters¶
The restgdf.adapters subpackage composes streaming primitives into
tabular output shapes. Each adapter works against the async iterators
exposed by FeatureLayer and avoids importing heavy
dependencies (pandas, geopandas) at module load time — they are guarded
behind runtime checks and raise OptionalDependencyError
with an install hint when missing.
restgdf.adapters.dict¶
Pure-Python row conversion. Part of the base pip install restgdf install.
Core-install safe row-shaped dict adapters.
Thin, stable aliases for the row-flattening helpers in
restgdf.utils.getgdf. No heavy dependencies — this module is safe to
import and use on a minimal restgdf install.
- restgdf.adapters.dict.as_dict(obj)[source]¶
Return a plain Python dict view of a restgdf pydantic model.
If
objis apydantic.BaseModelinstance, returnsobj.model_dump(mode="python", by_alias=False)— a dict keyed by the model’s Python (snake_case) field names, with nested models also recursively dumped.If
objis anything else (already-a-dict,None, primitive, list), it is returned unchanged. This lets migration code wrap heterogeneous values uniformly:for entry in report.services: row = as_dict(entry) # dict whether entry is model or already dict save(row["name"], row.get("url"))
This helper is intentionally conservative: it does not recurse into containers of models and does not coerce
by_alias=True. Callers that need the ArcGIS-native camelCase round-trip should callmodel_dump()explicitly.
- restgdf.adapters.dict.as_json_dict(obj)[source]¶
Return a JSON-safe dict view of a restgdf pydantic model.
Like
as_dict(), but usesmodel_dump(mode="json")so every nested value is a JSON-serializable primitive (SecretStr→"**********"placeholder,datetime→ ISO string, etc.). Handy for structured logging of a model without carrying unserializable objects into the log record.Non-model values are returned unchanged.
- restgdf.adapters.dict.feature_to_row(feature)[source]¶
Flatten a single ArcGIS feature envelope into a row-shaped dict.
Merges
feature["attributes"]with a"geometry"key holding the raw ArcGIS geometry dict verbatim. Safe on a base install — no pandas/geopandas dependency.- Parameters:
feature – A raw ArcGIS feature dict as returned by a
/queryresponse (the elements ofresponse["features"]).- Returns:
{**feature["attributes"], "geometry": feature.get("geometry")}.- Return type:
dict[str,Any]
Examples
>>> feature_to_row({"attributes": {"OBJECTID": 1}, "geometry": {"x": 0, "y": 0}}) {'OBJECTID': 1, 'geometry': {'x': 0, 'y': 0}}
See also
restgdf.FeatureLayer.stream_rows()High-level async iterator that yields row-shaped dicts directly from a live layer.
restgdf.utils.getgdf._feature_to_row_dict()Underlying flattening primitive.
- restgdf.adapters.dict.features_to_rows(features)[source]¶
Materialize an iterable of ArcGIS features as a list of row-shaped dicts.
- Parameters:
features – Any iterable of raw ArcGIS feature dicts (e.g. a page’s
"features"list).- Returns:
One
feature_to_row()output per input feature.- Return type:
list[dict[str,Any]]
Examples
>>> features_to_rows([{"attributes": {"OBJECTID": 1}, "geometry": None}]) [{'OBJECTID': 1, 'geometry': None}]
See also
restgdf.FeatureLayer.stream_feature_batches()Async iterator yielding one
list[feature_dict]per page; feed each batch through this helper to materialize row tables.
restgdf.adapters.stream¶
Async iterator helpers that compose pagination into per-row or per-batch shapes. Part of the base install.
Core-install safe streaming adapters over ArcGIS pagination.
Thin async-iterator wrappers over the existing pagination helpers in
restgdf.utils.getgdf. Row-level and feature-batch-level iteration are
safe on a base install; iter_gdf_chunks requires the optional geo stack
and gates at call time via restgdf.utils.getgdf.chunk_generator()’s
internal call to restgdf.utils._optional.require_geo_stack().
The public streaming surface (stream_features, stream_feature_batches,
ordering guarantees, backpressure options) is planned to expand in phase-4a
under MASTER-PLAN BL-24. The names exposed here are the minimum viable set
that today’s callers can depend on; their shape is compatible with the
planned BL-24 expansion.
- async restgdf.adapters.stream.iter_feature_batches(url, session, **kwargs)[source]¶
Yield ArcGIS feature batches (lists of raw feature dicts) from
url.Thin wrapper around
restgdf.utils.getgdf._feature_batch_generator(). Core-install safe — no pandas / geopandas dependency.- Parameters:
url – Fully qualified ArcGIS FeatureServer/MapServer layer URL.
session – An
aiohttp.ClientSessionorrestgdf.ArcGISTokenSession.**kwargs – Forwarded to the underlying batch generator (
data,where,outFields,token, etc.).
- Yields:
list[dict[str,Any]]– One list of raw ArcGIS feature dicts per page.
Examples
>>> import asyncio, aiohttp >>> from restgdf.adapters.stream import iter_feature_batches >>> async def demo(url): ... async with aiohttp.ClientSession() as s: ... async for batch in iter_feature_batches(url, s): ... print(len(batch))
See also
restgdf.FeatureLayer.stream_feature_batches()Preferred high-level entrypoint with
order,max_concurrent_pages, andon_truncationknobs.
- async restgdf.adapters.stream.iter_gdf_chunks(url, session, **kwargs)[source]¶
Yield
GeoDataFramechunks fromurl.Requires the optional geo extra:
pip install "restgdf[geo]". Thin wrapper aroundrestgdf.utils.getgdf.chunk_generator(), which itself validates the optional geo stack viarestgdf.utils._optional.require_geo_stack().- Parameters:
url – Fully qualified ArcGIS FeatureServer/MapServer layer URL.
session – An
aiohttp.ClientSessionorrestgdf.ArcGISTokenSession.**kwargs – Forwarded to
restgdf.utils.getgdf.chunk_generator().
- Yields:
geopandas.GeoDataFrame– One chunk per ArcGIS query page.- Raises:
restgdf.errors.OptionalDependencyError – When
pandas,geopandas, orpyogriois missing.
See also
restgdf.FeatureLayer.stream_gdf_chunks()Preferred high-level entrypoint. Each yielded chunk carries
gdf.attrs["spatial_reference"]populated from layer metadata (R-65).
- async restgdf.adapters.stream.iter_rows(url, session, **kwargs)[source]¶
Yield row-shaped dicts from
url.Thin wrapper around
restgdf.utils.getgdf.row_dict_generator(). Core-install safe — no pandas / geopandas dependency.- Parameters:
url – Fully qualified ArcGIS FeatureServer/MapServer layer URL.
session – An
aiohttp.ClientSessionorrestgdf.ArcGISTokenSession.**kwargs – Forwarded to
restgdf.utils.getgdf.row_dict_generator().
- Yields:
dict[str,Any]–{**feature["attributes"], "geometry": feature.get("geometry")}per feature.
Examples
>>> async for row in iter_rows(url, session): ... print(row["OBJECTID"], row["geometry"])
See also
restgdf.FeatureLayer.stream_rows()Preferred high-level entrypoint with streaming ordering and truncation-handling knobs.
restgdf.adapters.pandas¶
DataFrame materialization. Requires pandas (installed via restgdf[geo]
or standalone).
Pandas-gated tabular adapters.
Materialize row-shaped dict iterables into a pandas.DataFrame. The
module itself is safe to import on a base restgdf install — pandas is loaded
lazily via restgdf.utils._optional.require_pandas() inside each
adapter function, so importing this module on a pandas-free install does not
raise. Calling an adapter function on such an install raises
restgdf.errors.OptionalDependencyError with the canonical
restgdf[geo] guidance.
- async restgdf.adapters.pandas.arows_to_dataframe(rows)[source]¶
Async counterpart of
rows_to_dataframe().Consumes the async iterable to completion, then delegates to
rows_to_dataframe().- Parameters:
rows – Async iterable of row-shaped dicts — typically
restgdf.FeatureLayer.stream_rows()orrestgdf.adapters.stream.iter_rows().- Return type:
- Raises:
restgdf.errors.OptionalDependencyError – When
pandasis not installed. Install viapip install "restgdf[geo]"(geo extra bundles pandas) orpip install pandas.
Examples
>>> import asyncio >>> from restgdf.adapters.pandas import arows_to_dataframe >>> async def demo(): ... async def rows(): ... yield {"OBJECTID": 1} ... return await arows_to_dataframe(rows()) >>> asyncio.run(demo()) OBJECTID 0 1
See also
restgdf.FeatureLayer.get_df()Convenience accessor equivalent to
await arows_to_dataframe(layer.stream_rows()).
- restgdf.adapters.pandas.resolve_domains(df, fields)[source]¶
Replace coded-value domain codes with their human-readable names.
Post-processes an already-materialized
pandas.DataFrameusing ArcGIS layer field metadata:Coded-value domains — values present in the domain’s
codedValuestable are substituted for theirname. Codes absent from the table pass through unchanged.Range domains — values are left as-is. Out-of-range values are not flagged or coerced (callers who need strict validation should check
[min, max]themselves using the layer’s field metadata).
The input DataFrame is not mutated; a shallow copy is returned when any substitution is performed, and the original object is returned unchanged when
fieldsis empty /Noneor carries no applicable domains.- Parameters:
df – DataFrame produced by
rows_to_dataframe()/arows_to_dataframe().fields – Sequence of field descriptors (either
restgdf._models.responses.FieldSpecinstances or raw dicts) as found onrestgdf.FeatureLayer.metadata.fields.
- Returns:
A DataFrame with applicable coded-value columns resolved.
- Return type:
Examples
>>> import pandas as pd >>> from restgdf.adapters.pandas import resolve_domains >>> df = pd.DataFrame({"STATUS": [1, 2, 99]}) >>> fields = [{ ... "name": "STATUS", ... "domain": { ... "type": "codedValue", ... "codedValues": [ ... {"name": "Active", "code": 1}, ... {"name": "Inactive", "code": 2}, ... ], ... }, ... }] >>> resolve_domains(df, fields)["STATUS"].tolist() ['Active', 'Inactive', 99]
- restgdf.adapters.pandas.rows_to_dataframe(rows)[source]¶
Materialize an iterable of row-shaped dicts as a
pandas.DataFrame.- Parameters:
rows – Any iterable of row-shaped dicts — typically produced by
restgdf.adapters.dict.features_to_rows()or collected fromrestgdf.FeatureLayer.stream_rows().- Return type:
- Raises:
restgdf.errors.OptionalDependencyError – When
pandasis not installed. Install the optional extra viapip install "restgdf[geo]"(which ships pandas alongside the geo stack) or installpandasdirectly.
Examples
>>> from restgdf.adapters.pandas import rows_to_dataframe >>> rows_to_dataframe([{"OBJECTID": 1, "NAME": "A"}]) OBJECTID NAME 0 1 A
See also
restgdf.FeatureLayer.get_df()Async pandas-first tabular accessor that wraps this adapter over a live layer.
restgdf.adapters.geopandas¶
GeoDataFrame materialization. Requires restgdf[geo] (geopandas + pyogrio).
Geopandas-gated geo-tabular adapters.
Materialize row-shaped dict iterables into a geopandas.GeoDataFrame.
The module itself is safe to import on a base restgdf install — the geo
stack (pandas + geopandas + pyogrio) is loaded lazily via
restgdf.utils._optional.require_geo_stack() inside each adapter
function. Calling an adapter on a base install raises
restgdf.errors.OptionalDependencyError.
Scope note¶
Phase-2d keeps geometry handling minimal: the adapters pass the materialized
row table directly to geopandas.GeoDataFrame with geometry=geometry_field.
Callers are expected to supply shapely-compatible geometry values, already-built
GeoSeries elements, or to leave the field empty for tabular-only flows.
Full ArcGIS geometry-dict normalization (points, polylines, polygons,
mixed-Z/M, spatial-reference promotion) ships with MASTER-PLAN BL-27 / BL-28
in phase-2b and BL-35 in phase-4b.
- async restgdf.adapters.geopandas.arows_to_geodataframe(rows, *, geometry_field='geometry', crs=None)[source]¶
Async counterpart of
rows_to_geodataframe().Consumes the async iterable to completion, then delegates. Requires the optional geo extra:
pip install "restgdf[geo]".- Parameters:
rows – Async iterable of row-shaped dicts — typically
restgdf.FeatureLayer.stream_rows()orrestgdf.adapters.stream.iter_rows().geometry_field – Column name for the geometry column. Defaults to
"geometry".crs – Optional CRS forwarded to
GeoDataFrame(crs=...).
- Return type:
- Raises:
restgdf.errors.OptionalDependencyError – When any of
pandas,geopandas, orpyogriois missing.
See also
restgdf.FeatureLayer.get_gdf()Equivalent to
await arows_to_geodataframe(layer.stream_rows())with geometry normalization and CRS propagation handled for you.
- restgdf.adapters.geopandas.rows_to_geodataframe(rows, *, geometry_field='geometry', crs=None)[source]¶
Materialize row-shaped dicts as a
geopandas.GeoDataFrame.Requires the optional geo extra:
pip install "restgdf[geo]"(brings inpandas,geopandas, andpyogrio).- Parameters:
rows – Iterable of row-shaped dicts, typically produced by
restgdf.adapters.stream.iter_rows()orrestgdf.adapters.dict.features_to_rows(). Each row’sgeometry_fieldentry must be shapely-compatible (or aGeoSerieselement).geometry_field – Column name holding the geometry values. Defaults to
"geometry".crs – Optional CRS passed through to
GeoDataFrame(crs=...).
- Return type:
- Raises:
restgdf.errors.OptionalDependencyError – When any of
pandas,geopandas, orpyogriois missing. Install viapip install "restgdf[geo]".
Examples
>>> from shapely.geometry import Point >>> rows_to_geodataframe( ... [{"OBJECTID": 1, "geometry": Point(0, 0)}], ... crs="EPSG:4326", ... )
See also
restgdf.FeatureLayer.get_gdf()High-level accessor that returns the full layer as a single
GeoDataFrame.restgdf.FeatureLayer.stream_gdf_chunks()Async iterator yielding one
GeoDataFrameper page, each withgdf.attrs["spatial_reference"]populated from layer metadata.