Quickstart¶
Requires Python ≥ 3.9.
Choose the install that matches the workflow you want:
Install command |
Capabilities |
|---|---|
|
Typed metadata/models, count/object-id helpers, raw row dictionaries, directory crawl, and token/session helpers |
|
Everything in the base install, plus GeoDataFrame/pandas-backed helpers like |
Light-core workflow (pip install restgdf)¶
pip install restgdf
import asyncio
from aiohttp import ClientSession
from restgdf import FeatureLayer
beaches_url = "https://maps1.vcgov.org/arcgis/rest/services/Beaches/MapServer/6"
async def main():
async with ClientSession() as session:
beaches = await FeatureLayer.from_url(beaches_url, session=session)
cities = await beaches.get_unique_values("CITY")
first_rows = []
async for row in beaches.row_dict_generator(data={"outFields": "CITY,STATE"}):
first_rows.append(row)
if len(first_rows) == 2:
break
return beaches.count, beaches.metadata.max_record_count, cities[:3], first_rows
count, max_record_count, cities, first_rows = asyncio.run(main())
Read a FeatureServer into a GeoDataFrame (restgdf[geo])¶
pip install "restgdf[geo]"
restgdf reads all features past the maxRecordCount limit, using
asyncio + aiohttp to chunk objectIds
in parallel.
import asyncio
from aiohttp import ClientSession
from restgdf import FeatureLayer
beaches_url = "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.get_gdf()
daytona = await beaches.where("LOWER(City) LIKE 'daytona%'")
daytona_gdf = await daytona.get_gdf()
oh = await FeatureLayer.from_url(
zipcodes_url, where="STATE = 'OH'", session=session
)
oh_gdf = await oh.get_gdf()
return beaches_gdf, daytona_gdf, oh_gdf
beaches_gdf, daytona_gdf, oh_gdf = asyncio.run(main())
# (243, 10) (83, 10) (1026, 8)
Keyword arguments to get_gdf() are forwarded to
aiohttp.ClientSession.post; include query parameters like where and
token in the data dict when you need per-request overrides.
Typed responses¶
Every response in the base install is a pydantic model. Attribute access replaces dict indexing,
and model_dump(by_alias=True) round-trips back to ArcGIS camelCase:
fl = await FeatureLayer.from_url(beaches_url, session=session)
md = fl.metadata # restgdf.LayerMetadata
md.name # was md["name"]
md.max_record_count # was md["maxRecordCount"]
md.model_dump(by_alias=True) # ArcGIS camelCase dict
Need a plain dict during a transitional migration? Use
restgdf.compat.as_dict() — see the restgdf migration guide for the full
rewrite table.
Crawl a directory¶
from restgdf import Directory
async def crawl():
async with ClientSession() as session:
d = await Directory.from_url(
"https://services.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services",
session=session,
)
report = d.report # restgdf.CrawlReport
for svc in report.services: # list[CrawlServiceEntry]
print(svc.name, svc.type)
What next?¶
Authentication — tokens and
ArcGISTokenSession.Pydantic models — every pydantic response model.
API reference — the full API reference.
restgdf migration guide — moving from 1.x.