improved esri rest io for geopandas
Project description
restgdf
improved esri rest io for geopandas
What's new in 2.0
restgdf 2.0 is a major release built on pydantic 2.13.
See MIGRATION.md for the full breaking-changes table and
code-rewrite recipes.
- Typed responses.
FeatureLayer.metadata,Directory.metadata/.services/.report, and helpers likeget_metadata,safe_crawlnow return pydantic models instead of raw dicts. - Validated envelopes.
get_feature_count,get_object_ids, and token refresh surface malformed ArcGIS payloads as a typedRestgdfResponseError(withmodel_name,context,raw). - Schema-drift observability. Vendor variance in permissive payloads
(metadata, crawl) is logged through the opt-in
restgdf.schema_driftlogger instead of silentlyKeyError-ing. - Redacted credentials.
AGOLUserPass.passwordis apydantic.SecretStrso passwords are never inrepr()or logs. - Centralized settings.
Settings/get_settings()readsRESTGDF_*environment variables (chunk size, timeout, user agent, token URL, refresh threshold, etc.). - Migration helpers.
restgdf.compat.as_dictandas_json_dictconvert any returned model back to a plain dict during a transitional upgrade window. - Deprecated shim.
restgdf._types.*still imports the legacyTypedDictnames, but they now re-export the pydantic classes and emitDeprecationWarning. The shim will be removed in 3.x. - Dependency bump.
pydantic>=2.13.3,<3is a new required dependency.
gpd.read_file(url, driver="ESRIJSON") does not account for max record count limitations
so if you read a service with 100000 features but there's a limit of 1000 records per query, then your gdf will only have 1000 features
these functions use asyncio to read all features from a service, not limited by max record count
keyword arguments to FeatureLayer.getgdf are passed on to aiohttp.ClientSession.post; include query parameters like where and token in the data dict when needed
this enables enhanced control over queries and supports either direct data={"token": "..."} usage or a reusable ArcGISTokenSession
Usage
pip install restgdf
import asyncio
from aiohttp import ClientSession
from restgdf import FeatureLayer
beaches_url = r"https://maps1.vcgov.org/arcgis/rest/services/Beaches/MapServer/6"
zipcodes_url = "https://services.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services/USA_ZIP_Codes_2016/FeatureServer/0"
async def main():
async with ClientSession() as session:
beaches = await FeatureLayer.from_url(beaches_url, session=session)
beaches_gdf = await beaches.getgdf()
daytona = await beaches.where("LOWER(City) LIKE 'daytona%'")
daytona_gdf = await daytona.getgdf()
oh_zipcodes = await FeatureLayer.from_url(zipcodes_url, where="STATE = 'OH'", session=session)
oh_zipcodes_gdf = await oh_zipcodes.getgdf()
return beaches_gdf, daytona_gdf, oh_zipcodes_gdf
beaches_gdf, daytona_gdf, oh_zipcodes_gdf = asyncio.run(main())
print(beaches_gdf.shape)
# (243, 10)
print(daytona_gdf.shape)
# (83, 10)
print(oh_zipcodes_gdf.shape)
# (1026, 8)
Token authentication
import asyncio
from aiohttp import ClientSession
from restgdf import AGOLUserPass, ArcGISTokenSession, FeatureLayer
secured_url = "https://example.com/arcgis/rest/services/Secured/FeatureServer/0"
async def main():
async with ClientSession() as base_session:
token_session = ArcGISTokenSession(
session=base_session,
credentials=AGOLUserPass(
username="my-username",
password="my-password",
),
)
layer = await FeatureLayer.from_url(secured_url, session=token_session)
return await layer.getgdf()
secured_gdf = asyncio.run(main())
If you already have a token, you can pass it with token="..." or data={"token": "..."}.
Typed responses
Every response is a pydantic model. Attribute access replaces dict
indexing, and model_dump(by_alias=True) round-trips back to ArcGIS
camelCase:
import asyncio
from aiohttp import ClientSession
from restgdf import FeatureLayer
async def main():
async with ClientSession() as session:
fl = await FeatureLayer.from_url(beaches_url, session=session)
md = fl.metadata # restgdf.LayerMetadata
return md.name, md.max_record_count, md.model_dump(by_alias=True)
name, max_record_count, arcgis_dict = asyncio.run(main())
Need a plain dict during a transitional migration? Use
restgdf.compat.as_dict(md). See MIGRATION.md for
the full 1.x → 2.0 rewrite table.
Documentation
Full docs live at https://restgdf.readthedocs.io/ (hosted by Read the Docs).
Docs for humans and LLMs
Every page is published in three formats so you can feed it to a teammate or to a language model without any preprocessing:
| Format | URL |
|---|---|
| Rendered HTML | https://restgdf.readthedocs.io/en/latest/ |
| Plain Markdown (per page) | append .md to any page — e.g. https://restgdf.readthedocs.io/en/latest/quickstart.html.md |
| llms.txt index | https://restgdf.readthedocs.io/en/latest/llms.txt |
| llms-full.txt (all pages) | https://restgdf.readthedocs.io/en/latest/llms-full.txt |
| Ask DeepWiki | https://deepwiki.com/joshuasundance-swca/restgdf |
Point your coding agent or RAG pipeline at llms-full.txt for the entire
reference in a single file, or at llms.txt for a concise table of
contents.
Uses
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file restgdf-2.0.0.tar.gz.
File metadata
- Download URL: restgdf-2.0.0.tar.gz
- Upload date:
- Size: 70.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4cabed380c37ee5d780ab6a3a99cf36a5509504777d7a354e3db74f2729fd4f
|
|
| MD5 |
1901c56e742411144e5ca3b2956c1202
|
|
| BLAKE2b-256 |
07816ca3b4117e3add6b94008c3490bbede3012a1b1686342a01bfeb2b18ef22
|
Provenance
The following attestation bundles were made for restgdf-2.0.0.tar.gz:
Publisher:
publish_on_pypi.yml on joshuasundance-swca/restgdf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
restgdf-2.0.0.tar.gz -
Subject digest:
c4cabed380c37ee5d780ab6a3a99cf36a5509504777d7a354e3db74f2729fd4f - Sigstore transparency entry: 1345465636
- Sigstore integration time:
-
Permalink:
joshuasundance-swca/restgdf@2d3f7eefe5519e93a28c0ebbea35c7aaa671eaa2 -
Branch / Tag:
refs/tags/2.0.0 - Owner: https://github.com/joshuasundance-swca
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_on_pypi.yml@2d3f7eefe5519e93a28c0ebbea35c7aaa671eaa2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file restgdf-2.0.0-py3-none-any.whl.
File metadata
- Download URL: restgdf-2.0.0-py3-none-any.whl
- Upload date:
- Size: 46.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45d93209038d44a0eb090d4b1e6bda96b472ef3157965d462da2f5200df5e07b
|
|
| MD5 |
b2a536e2a408d27231c84d4af0dd754a
|
|
| BLAKE2b-256 |
1290e4e5aa6710d10381a0951cbf9c978cb505c5ef50adea8cc8f191bdd80550
|
Provenance
The following attestation bundles were made for restgdf-2.0.0-py3-none-any.whl:
Publisher:
publish_on_pypi.yml on joshuasundance-swca/restgdf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
restgdf-2.0.0-py3-none-any.whl -
Subject digest:
45d93209038d44a0eb090d4b1e6bda96b472ef3157965d462da2f5200df5e07b - Sigstore transparency entry: 1345465717
- Sigstore integration time:
-
Permalink:
joshuasundance-swca/restgdf@2d3f7eefe5519e93a28c0ebbea35c7aaa671eaa2 -
Branch / Tag:
refs/tags/2.0.0 - Owner: https://github.com/joshuasundance-swca
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_on_pypi.yml@2d3f7eefe5519e93a28c0ebbea35c7aaa671eaa2 -
Trigger Event:
push
-
Statement type: