Pydantic models

The base pip install restgdf install exposes every ArcGIS response and config object as a pydantic BaseModel. These classes are the single source of truth for payload shape and are re-exported from restgdf directly. Use restgdf.compat.as_dict() if you need a plain dict during a migration.

Model relationships

The models nest in a natural hierarchy that mirrors the ArcGIS REST API response structure:

FeatureLayer.metadata → LayerMetadata
│                        ├── .fields → list[FieldSpec]
│                        ├── .extent → dict (raw spatial extent)
│                        └── .advanced_query_capabilities → AdvancedQueryCapabilities
│
FeatureLayer.get_gdf() internally parses → FeaturesResponse
│                                          ├── .features → list[Feature]
│                                          └── .exceeded_transfer_limit → bool
│
Directory.crawl() → list[CrawlServiceEntry]
│                    ├── .metadata → LayerMetadata | None
│                    └── .name, .url, .type
│
Directory.report → CrawlReport
                   ├── .services → list[CrawlServiceEntry]
                   └── .errors → list[CrawlError]

Use model.model_dump(by_alias=True) to round-trip any model back to ArcGIS camelCase JSON. Use restgdf.compat.as_dict() for a plain dict during migration.

Response envelopes

pydantic model restgdf.LayerMetadata[source]

Bases: PermissiveModel

Polymorphic ArcGIS REST metadata envelope.

The same endpoint family (GET <url>?f=json) returns per-layer metadata (name, fields, maxRecordCount, …), service roots (services, folders), sub-layer descriptors (id), and restgdf-enriched payloads (url, feature_count). All variants parse into this single permissive model; missing fields default to None rather than raise.

Field aliases accept either camelCase (native ArcGIS) or snake_case (Python-native) input via AliasChoices, and model_dump(by_alias=True) round-trips back to camelCase so downstream serialization stays ArcGIS-compatible.

Fields:
  • advanced_query_capabilities (dict[str, Any] | None)

  • advanced_query_capabilities_typed (restgdf._models.responses.AdvancedQueryCapabilities | None)

  • feature_count (int | None)

  • fields (list[restgdf._models.responses.FieldSpec] | None)

  • folders (list[str] | None)

  • id (int | None)

  • layers (list[restgdf._models.responses.LayerMetadata] | None)

  • max_record_count (int | None)

  • name (str | None)

  • services (list[dict[str, Any]] | None)

  • supports_pagination (bool | None)

  • type (str | None)

  • url (str | None)

pydantic model restgdf.ServiceInfo[source]

Bases: PermissiveModel

Root GET <services_root>?f=json envelope.

A narrower permissive view over the subset of keys a services-root crawl consumes (services and folders). Unlike LayerMetadata, this model does not enrich nested services entries into typed objects — the crawl report keeps them as raw dicts so per-service merge keys (name, type) survive unchanged.

Fields:
  • folders (list[str] | None)

  • layers (list[restgdf._models.responses.LayerMetadata] | None)

  • services (list[dict[str, Any]] | None)

  • url (str | None)

pydantic model restgdf.FieldSpec[source]

Bases: PermissiveModel

A field descriptor entry in a layer’s fields list.

Real ArcGIS servers emit an open-ended set of keys here (sqlType, defaultValue, modelName, …). Permissive tier preserves them via extra="allow" while declaring the handful of keys restgdf actually consumes.

Fields:
  • alias (str | None)

  • domain (dict | None)

  • editable (bool | None)

  • length (int | None)

  • name (str | None)

  • nullable (bool | None)

  • type (str | None)

pydantic model restgdf.Feature[source]

Bases: PermissiveModel

A single feature in FeaturesResponse.features.

attributes is declared as a dict but not typed further — ArcGIS layer schemas are dynamic. geometry is optional because non- spatial tables and returnGeometry=false queries omit it.

Fields:
  • attributes (dict[str, Any] | None)

  • geometry (dict[str, Any] | None)

pydantic model restgdf.FeaturesResponse[source]

Bases: PermissiveModel

Envelope for ?f=json feature queries.

Permissive tier: only the envelope keys restgdf consumes are declared. features is kept as a list[dict] rather than list[Feature] on purpose — validating every feature of a large batch with pydantic would be expensive and returns no value to the downstream GeoPandas reader, which consumes raw ArcGIS JSON. Callers that need typed features can validate them explicitly via Feature.

Fields:
  • exceeded_transfer_limit (bool | None)

  • features (list[dict[str, Any]])

  • fields (list[restgdf._models.responses.FieldSpec] | None)

  • object_id_field_name (str | None)

pydantic model restgdf.CountResponse[source]

Bases: StrictModel

Envelope for ?returnCountOnly=true query results.

Strict tier: ArcGIS always returns count for this query shape, so a missing/ill-typed key signals a protocol-level incident (for example an HTML error page bodied as JSON). _parse_response() surfaces those as RestgdfResponseError.

Fields:
  • count (int)

pydantic model restgdf.ObjectIdsResponse[source]

Bases: StrictModel

Envelope for ?returnIdsOnly=true query results.

Strict tier. The response is operation-critical: chunked pagination in restgdf.utils.getgdf requires both the OID field name and the full id list. A zero-row match produces {"objectIdFieldName": "OBJECTID", "objectIds": null} in the wild; the object_ids validator below coerces that None to an empty list so consumers can unconditionally iterate.

Fields:
  • object_id_field_name (str)

  • object_ids (list[int])

Validators:
  • _coerce_null_to_empty » object_ids

pydantic model restgdf.TokenResponse[source]

Bases: StrictModel

Envelope for ArcGIS /generateToken responses.

Strict tier: token refresh is operation-critical; a missing token or expires key means a token cannot be used and any downstream request will fail authentication. ArcGIS also returns error envelopes through this same endpoint ({"error": {...}}); those fail validation here and surface as RestgdfResponseError, leaving the original payload on exc.raw for operator triage.

Fields:
  • expires (int)

  • ssl (bool | None)

  • token (str)

pydantic model restgdf.ErrorInfo[source]

Bases: PermissiveModel

Inner error payload: {"code": int, "message": str, ...}.

ArcGIS error payloads routinely carry diagnostic extras (messageCode, errorCode, details) that restgdf does not need but should not strip away.

Fields:
  • code (int | None)

  • details (list[str] | None)

  • message (str | None)

pydantic model restgdf.ErrorResponse[source]

Bases: StrictModel

Top-level JSON error envelope: {"error": {...}}.

Strict tier: callers branching on isinstance(obj, ErrorResponse) need the error key to actually be present. Missing-key drift on this envelope indicates a protocol-level bug, not vendor variance.

Fields:
  • error (restgdf._models.responses.ErrorInfo)

Crawl models

pydantic model restgdf.CrawlReport[source]

Bases: PermissiveModel

Aggregated result of a directory crawl.

Unlike the legacy fetch_all_data return shape (which short-circuits to {"error": exc} on the first failure), CrawlReport always returns partial successes alongside captured errors.

Fields:
  • errors (list[restgdf._models.crawl.CrawlError])

  • metadata (restgdf._models.responses.LayerMetadata | None)

  • services (list[restgdf._models.crawl.CrawlServiceEntry])

pydantic model restgdf.CrawlServiceEntry[source]

Bases: PermissiveModel

A service entry in CrawlReport.services.

metadata is the LayerMetadata returned by service_metadata for this service. It is None when the service_metadata call failed; in that case a corresponding CrawlError is recorded in CrawlReport.errors.

Fields:
  • metadata (restgdf._models.responses.LayerMetadata | None)

  • name (str | None)

  • type (str | None)

  • url (str | None)

pydantic model restgdf.CrawlError[source]

Bases: PermissiveModel

A single failure captured during safe_crawl().

stage identifies where the failure occurred. Standard stages emitted by safe_crawl are:

  • "base_metadata" — the root get_metadata call failed.

  • "folder_metadata" — a per-folder get_metadata call failed.

  • "service_metadata" — a per-service service_metadata call failed.

exception preserves the original BaseException so callers can re-raise; it is excluded from the default model_dump() output for JSON safety.

Fields:
  • exception (BaseException | None)

  • message (str | None)

  • stage (str | None)

  • url (str | None)

Credentials and session config

pydantic model restgdf.AGOLUserPass[source]

Bases: StrictModel

ArcGIS Online / Enterprise credentials used to mint tokens.

password is stored as pydantic.SecretStr. Call creds.password.get_secret_value() only at the HTTP-POST boundary; never store or log the unwrapped value.

Fields:
  • expiration (int)

  • password (pydantic.types.SecretStr)

  • referer (str | None)

  • username (str)

pydantic model restgdf.TokenSessionConfig[source]

Bases: StrictModel

Validated configuration for ArcGISTokenSession.

token_url is intentionally a plain str with a custom validator rather than pydantic.AnyHttpUrl. ArcGIS Enterprise deployments commonly run plain HTTP on internal networks, and AnyHttpUrl normalizes/rejects real-world URLs (for example it appends trailing slashes and may reject edge cases). Accepting any http:// or https:// string matches the behavior ArcGIS clients need.

Refresh semantics (BL-04 / R-36, R-37):
  • refresh_leeway_seconds (default 120) — how far in advance of the token’s expiry the session eagerly refreshes.

  • clock_skew_seconds (default 30, capped at 30 when derived from the legacy alias) — extra padding for client / server clock drift.

refresh_threshold_seconds is retained as a deprecation-warning alias. Reads return refresh_leeway_seconds + clock_skew_seconds; writes via the constructor kwarg split the supplied total into clock_skew_seconds = min(30, total) and refresh_leeway_seconds = total - clock_skew_seconds.

Fields:
  • clock_skew_seconds (int)

  • credentials (restgdf._models.credentials.AGOLUserPass)

  • header_name (str)

  • referer (str | None)

  • refresh_leeway_seconds (int)

  • token (pydantic.types.SecretStr | None)

  • token_url (str)

  • transport (Literal['header', 'body', 'query'])

  • verify_ssl (bool)

Validators:
  • _check_token_url_scheme » token_url

  • _translate_legacy_refresh_threshold » all fields

Runtime settings

pydantic model restgdf.Settings[source]

Bases: BaseModel

Validated runtime configuration for restgdf.

The model is frozen: treat a Settings instance as immutable. To change runtime configuration, mutate the environment (or pass an explicit mapping), then call reset_settings_cache() and re-fetch via get_settings().

Fields:
  • chunk_size (int)

  • default_headers_json (str | None)

  • log_level (str)

  • max_concurrent_requests (int)

  • refresh_threshold_seconds (int)

  • timeout_seconds (float)

  • token_url (str)

  • user_agent (str)

Validators:
  • _check_token_url_scheme » token_url

  • _normalize_log_level » log_level