Skip to content

honua-sdk › Source facade

The canonical entry point for portable code is the Source facade — client.source(SourceDescriptor(...)).query(Query(...)) returns a Result[QueryFeature] regardless of whether the underlying source is a GeoServices FeatureServer, an OGC Features collection, a STAC catalog, or an OData entity set. Prefer this path when you want behaviour that is consistent across protocols; reach for the protocol-specific clients (feature_server(...), ogc_features(), stac(), odata()) when you need protocol-native operations not covered by the canonical surface.

See Protocol examples for side-by-side recipes that show the same query running against each supported protocol via the facade.

from honua_sdk import Query, SourceDescriptor, SourceLocator

descriptor = SourceDescriptor(id="svc", protocol="geoservices-feature-service",
                              locator=SourceLocator(service_id="svc", layer_id=0))
result = client.source(descriptor).query(Query(where="1=1"))

arcpy.da-style cursors

For geoprocessing authoring the facade exposes the arcpy.da cursor idioms over the streaming query and batched apply_edits:

source = client.source(descriptor)

# SearchCursor: lazily iterate (attrs, geometry) rows; "SHAPE@" selects geometry.
for name, shape in source.search_cursor(["NAME", "SHAPE@"], where="POP > 1000"):
    ...

# UpdateCursor: iterate rows, edit, write back in batches.
with source.update_cursor(where="STATUS = 'stale'") as cursor:
    for row in cursor:
        cursor.update_row(row, attributes={"STATUS": "reviewed"})

# InsertCursor: batched feature inserts.
with source.insert_cursor() as cursor:
    cursor.insert_row({"NAME": "New"}, {"x": -100.0, "y": 40.0})

Source.schema() returns a typed LayerSchema (arcpy.Describe analogue) and Source.to_geodataframe(...) returns a GeoPandas GeoDataFrame in one call (the Spatially-Enabled-DataFrame equivalent; requires the geopandas extra).

See also: Models for the Query / Result shapes, and Core client model for how the facade composes over the underlying clients.

honua_sdk.source.Source

Source-bound facade over the shared query API and protocol escape hatches.

Binds a :class:SourceDescriptor to a :class:HonuaClient so callers can issue protocol-neutral :class:Query requests (query, stream) without rebuilding the source identifier on each call. Routes requests through the canonical query dispatcher and exposes capability introspection via :meth:supports; falls back to the underlying protocol clients (feature_server, ogc_features, stac, odata) when callers need protocol-specific escape hatches. Construct via :meth:HonuaClient.source rather than directly.

Attributes:

Name Type Description
descriptor

The normalized :class:SourceDescriptor describing this source's protocol, addressing fields, and advertised capabilities.

query(query=None, *, where=None, out_fields=None, return_geometry=None, bbox=None, spatial_filter=None, limit=None, page_size=None, max_pages=None, cql_filter=None, where_as_cql=None, extra_params=None, fields=None, filter=None, timeout=None, extra_headers=None, idempotency_key=None)

Run a canonical source query and collect normalized features.

Accepts either a :class:Query (or mapping) plus explicit keyword overrides matching :class:Query fields. Two legacy keyword aliases remain accepted for source compatibility but emit :class:DeprecationWarning; migrate to the canonical :class:Query field names:

  • fields= is deprecated — use out_fields=.
  • filter= is deprecated — use where= (see :class:Query for filter-routing semantics across SQL- and CQL-style protocols).

Pass cql_filter= explicitly when targeting OGC Features / STAC with a CQL2-text expression — that bypasses the where field and routes the expression directly to the protocol's filter field. Passing only where= against an OGC/STAC source raises :class:ValueError; opt into the old silent forwarding behavior with where_as_cql=True if you have verified the string is already valid CQL2-text.

Per-call timeout / extra_headers / idempotency_key are forwarded to the bound client's query method (and from there to FeatureServer, OGC Features, and STAC pagination wrappers).

query_all(query=None, *, where=None, out_fields=None, return_geometry=None, bbox=None, spatial_filter=None, limit=None, page_size=None, max_pages=None, cql_filter=None, where_as_cql=None, extra_params=None, fields=None, filter=None)

Return all normalized features for a canonical source query.

stream(query=None, *, where=None, out_fields=None, return_geometry=None, bbox=None, spatial_filter=None, limit=None, page_size=None, max_pages=None, cql_filter=None, where_as_cql=None, extra_params=None, fields=None, filter=None, timeout=None, extra_headers=None, idempotency_key=None)

Stream normalized features for a canonical source query.

Per-call timeout / extra_headers / idempotency_key are forwarded to the bound client's iter_query method.

iter_features(query=None, *, where=None, out_fields=None, return_geometry=None, bbox=None, spatial_filter=None, limit=None, page_size=None, max_pages=None, cql_filter=None, where_as_cql=None, extra_params=None, fields=None, filter=None)

Alias for stream() using a Python iterator name.

apply_edits(*, adds=None, updates=None, deletes=None, rollback_on_failure=True, idempotency_key=None, timeout=None, extra_headers=None)

Apply edits for source protocols that expose a normalized edit helper.

Parameters:

Name Type Description Default
adds Sequence[Mapping[str, Any]] | None

Sequence of feature mappings to insert.

None
updates Sequence[Mapping[str, Any]] | None

Sequence of feature mappings to update by OBJECTID.

None
deletes Sequence[int] | str | None

Either a sequence of object ids or a comma-string of ids to delete.

None
rollback_on_failure bool

Whether the server should roll the entire batch back if any individual edit fails.

True
idempotency_key str | None

Stripe-style Idempotency-Key header value.

None
timeout float | Timeout | None

Per-request timeout forwarded to the transport layer.

None
extra_headers Mapping[str, str] | None

Additional HTTP headers merged onto the request.

None

protocol(kind=None)

Return the native protocol client for source-specific operations.

schema(layer_id=None)

Return a typed :class:LayerSchema for this source's layer.

The arcpy.Describe / ListFields analogue: fetches the FeatureServer layer metadata and parses it into typed fields, geometry type, spatial-reference WKID, and extent. layer_id defaults to the source descriptor's layer.

search_cursor(fields=None, *, where=None, geometry_filter=None, **query_kwargs)

Open a lazy :class:~honua_sdk.cursors.SearchCursor over this source.

The arcpy.da.SearchCursor analogue — iterate (geometry, attrs) rows lazily without materializing the whole result.

iter_rows(fields=None, *, where=None, geometry_filter=None, **query_kwargs)

Lazily iterate cursor rows (alias for search_cursor(...) iteration).

update_cursor(fields=None, *, where=None, geometry_filter=None, batch_size=200, rollback_on_failure=True, **query_kwargs)

Open an :class:~honua_sdk.cursors.UpdateCursor (iterate + batched write-back).

insert_cursor(*, batch_size=200, rollback_on_failure=True)

Open an :class:~honua_sdk.cursors.InsertCursor (batched feature inserts).

to_geodataframe(query=None, **query_kwargs)

Run a query and return its features as a GeoPandas GeoDataFrame.

First-class SEDF-equivalent: one call from source to geopandas. Requires the optional geopandas extra.

honua_sdk.source.AsyncSource

Async source-bound facade over the shared query API and protocol escape hatches.

Asynchronous counterpart to :class:Source. Binds a :class:SourceDescriptor to an :class:AsyncHonuaClient so callers can await protocol-neutral :class:Query requests (query, stream) without rebuilding the source identifier on each call. Capability introspection (:meth:supports) and protocol escape hatches mirror the sync facade. Construct via :meth:AsyncHonuaClient.source rather than directly.

Attributes:

Name Type Description
descriptor

The normalized :class:SourceDescriptor describing this source's protocol, addressing fields, and advertised capabilities.

query(query=None, *, where=None, out_fields=None, return_geometry=None, bbox=None, spatial_filter=None, limit=None, page_size=None, max_pages=None, cql_filter=None, where_as_cql=None, extra_params=None, fields=None, filter=None, timeout=None, extra_headers=None, idempotency_key=None) async

Run a canonical source query and collect normalized features.

Accepts either a :class:Query (or mapping) plus explicit keyword overrides matching :class:Query fields. Two legacy keyword aliases remain accepted for source compatibility but emit :class:DeprecationWarning; migrate to the canonical :class:Query field names:

  • fields= is deprecated — use out_fields=.
  • filter= is deprecated — use where= (see :class:Query for filter-routing semantics across SQL- and CQL-style protocols).

Pass cql_filter= explicitly when targeting OGC Features / STAC with a CQL2-text expression — that bypasses the where field and routes the expression directly to the protocol's filter field. Passing only where= against an OGC/STAC source raises :class:ValueError; opt into the old silent forwarding behavior with where_as_cql=True if you have verified the string is already valid CQL2-text.

Per-call timeout / extra_headers / idempotency_key are forwarded to the bound client's query method.

query_all(query=None, *, where=None, out_fields=None, return_geometry=None, bbox=None, spatial_filter=None, limit=None, page_size=None, max_pages=None, cql_filter=None, where_as_cql=None, extra_params=None, fields=None, filter=None) async

Return all normalized features for a canonical source query.

stream(query=None, *, where=None, out_fields=None, return_geometry=None, bbox=None, spatial_filter=None, limit=None, page_size=None, max_pages=None, cql_filter=None, where_as_cql=None, extra_params=None, fields=None, filter=None, timeout=None, extra_headers=None, idempotency_key=None) async

Stream normalized features for a canonical source query.

Per-call timeout / extra_headers / idempotency_key are forwarded to the bound client's iter_query method.

iter_features(query=None, *, where=None, out_fields=None, return_geometry=None, bbox=None, spatial_filter=None, limit=None, page_size=None, max_pages=None, cql_filter=None, where_as_cql=None, extra_params=None, fields=None, filter=None) async

Alias for stream() using a Python iterator name.

apply_edits(*, adds=None, updates=None, deletes=None, rollback_on_failure=True, idempotency_key=None, timeout=None, extra_headers=None) async

Apply edits for source protocols that expose a normalized edit helper.

Parameters:

Name Type Description Default
adds Sequence[Mapping[str, Any]] | None

Sequence of feature mappings to insert.

None
updates Sequence[Mapping[str, Any]] | None

Sequence of feature mappings to update by OBJECTID.

None
deletes Sequence[int] | str | None

Either a sequence of object ids or a comma-string of ids to delete.

None
rollback_on_failure bool

Whether the server should roll the entire batch back if any individual edit fails.

True
idempotency_key str | None

Stripe-style Idempotency-Key header value.

None
timeout float | Timeout | None

Per-request timeout forwarded to the transport layer.

None
extra_headers Mapping[str, str] | None

Additional HTTP headers merged onto the request.

None

protocol(kind=None)

Return the native protocol client for source-specific operations.

schema(layer_id=None) async

Return a typed :class:LayerSchema for this source's layer.

Asynchronous counterpart to :meth:Source.schema. The arcpy.Describe / ListFields analogue: fetches the FeatureServer layer metadata and parses it into typed fields, geometry type, spatial-reference WKID, and extent.

search_cursor(fields=None, *, where=None, geometry_filter=None, **query_kwargs)

Open a lazy :class:~honua_sdk.cursors.AsyncSearchCursor over this source.

iter_rows(fields=None, *, where=None, geometry_filter=None, **query_kwargs)

Lazily iterate cursor rows (alias for search_cursor(...) iteration).

update_cursor(fields=None, *, where=None, geometry_filter=None, batch_size=200, rollback_on_failure=True, **query_kwargs)

Open an :class:~honua_sdk.cursors.AsyncUpdateCursor (iterate + batched write-back).

insert_cursor(*, batch_size=200, rollback_on_failure=True)

Open an :class:~honua_sdk.cursors.AsyncInsertCursor (batched feature inserts).

to_geodataframe(query=None, **query_kwargs) async

Run a query and return its features as a GeoPandas GeoDataFrame.

First-class SEDF-equivalent: one await from source to geopandas. Requires the optional geopandas extra.

honua_sdk.cursors.SearchCursor

Lazy row iterator over a source query (arcpy.da.SearchCursor analogue).

Wraps :meth:Source.stream, yielding :class:Row objects one at a time so a tool never materializes the whole result. Pass fields to iterate positional value tuples (with "SHAPE@" selecting geometry) instead of rows. Supports the context-manager and iterator protocols.

rows()

Iterate :class:Row objects regardless of the fields selection.

honua_sdk.cursors.UpdateCursor

Bases: _BaseWriteCursor

Iterate rows and write edits back (arcpy.da.UpdateCursor analogue).

Iterating yields :class:Row objects (lazily, via a search cursor). Call :meth:update_row with new attributes/geometry to queue an update keyed by the row's object id; queued updates flush in batches through Source.apply_edits(updates=...) on :meth:flush / context-manager exit.

update_row(row, *, attributes=None, geometry=None)

Queue an update for row, merging attributes over its current ones.

flush()

Write any pending updates; returns the batch result or None.

honua_sdk.cursors.InsertCursor

Bases: _BaseWriteCursor

Batched feature inserts (arcpy.da.InsertCursor analogue).

Accumulate rows with :meth:insert_row; they are flushed to the source via Source.apply_edits(adds=...) once batch_size is reached, on :meth:flush, or when the context manager exits.

insert_row(attributes, geometry=None)

Queue a feature for insertion, flushing when the batch fills.

flush()

Write any pending inserts; returns the batch result or None.

honua_sdk.cursors.Row dataclass

A single cursor row: a feature's geometry plus its attribute mapping.

Mirrors an arcpy.da cursor row. :meth:values projects the row onto a requested field tuple (with the "SHAPE@" token selecting geometry), giving the positional-tuple ergonomic GP tools expect.

attributes property

The feature's attribute mapping (GeoJSON properties).

geometry property

The row geometry as a Shapely geometry (None when absent).

values(fields)

Project the row onto fields as a positional tuple.

The "SHAPE@" token yields the Shapely geometry; every other name is looked up in the attribute mapping (None when missing).