A lightweight library for interacting with ESRI ArcGIS REST APIs.
Project description
archibald
An async Python client for interacting with ESRI ArcGIS REST APIs, designed around a
dataframe-first approach for seamless analysis and data editing with pandas and geopandas.
Why archibald?
Esri's official arcgis Python library is comprehensive,
but it comes with tradeoffs that make it difficult to use in modern data engineering contexts.
archibald is/has:
- Async first. Every call blocks in
arcgis, which makes concurrent operations across multiple layers awkward, expensive, and time-consuming. archibald isasync-native throughout. - Light. The
arcgispackage pulls in hundreds of megabytes of dependencies — map rendering, notebook widgets, spatial analysis services, and more. archibald's dependency surface ishttpx,pandas, andgeopandas. Ideal for AWS Lambdas and other contexts where bloat comes at a premium. - Clear error handling. Esri's API frequently returns HTTP 200 responses with embedded error bodies that the official library doesn't always surface. archibald treats these as first-class exceptions with a typed hierarchy.
- Robust DataFrame integration. The official library's
SpatialDataFrametype has historically been finicky. archibald deals entirely inpd.DataFrameandgpd.GeoDataFrameobjects. - Editing that meets you at the DataFrame. Pass a GeoDataFrame and archibald handles
the rest: geometry serialization, field type coercion, and validation before anything
hits the wire. Write operations range from fine-grained
apply_edits()to a full DataFramesync(), all returning structured results with per-operation failure details.
archibald is deliberately narrow in scope: FeatureServer and MapServer interactions, done well.
It is not a replacement for the full arcgis SDK if you need portal management, hosted
notebooks, or Esri's spatial analysis services.
Installation
pip install archibald
Or with uv:
uv add archibald
Quick Start
import archibald as arc
auth = arc.UserTokenAuth(
username="your_username",
password="your_password",
)
async with arc.ArchieClient(
base_url="https://services.arcgis.com/sharing/rest/services",
auth=auth,
) as client:
layer = arc.FeatureLayer(
client=client,
service_path="MyService/FeatureServer",
layer_id=0,
)
# Query features and convert to a pandas DataFrame
result = await layer.query(where="1=1")
df = result.to_frame()
# Or work with spatial data as a GeoDataFrame
gdf = result.to_geodataframe()
# Bulk insert from a DataFrame
edits = await layer.append(df.head(5).copy())
Authentication
NoAuth — for public feature layers:
auth = arc.NoAuth()
UserTokenAuth — for token-based authentication:
auth = arc.UserTokenAuth(
username="your_username",
password="your_password",
base_url="https://www.arcgis.com", # optional; defaults to ArcGIS Online
)
Custom auth — implement the ArcGISAuth abstract base class to plug in your own token
strategy (API keys, OAuth2, keyring-backed credentials, etc.):
class MyCustomAuth(arc.ArcGISAuth):
async def get_token(self) -> str:
# your token logic
async def force_refresh(self) -> None:
# refresh logic
Services
archibald wraps Esri's REST endpoints with typed service and layer classes:
| Class | Description |
|---|---|
FeatureLayer |
Query, add, update, delete, upsert, and sync features; attach, update, and delete attachments |
MapLayer |
Query-only access to map service layers |
FeatureService |
Service-level metadata and capabilities |
MapService |
Map service metadata and operations |
All layers expose:
query()— retrieve features with optional filtering and field selectionfields()— introspect layer schemacrs()— coordinate reference system metadataquery_attachments()— list attachment metadata for one or more features
FeatureLayer additionally supports a layered write API:
apply_edits()— fine-grained control over add/update/delete in a single callappend()— bulk insert from a DataFrameupsert()— insert or update based on key fieldssync()— reconcile a DataFrame with the service: adds missing records, updates changed ones, deletes removed onesadd_attachments()— attach files to one or more featuresupdate_attachments()— replace existing attachment filesdelete_attachments()— remove attachments from features
Data Models
QueryResult — returned by query():
result = await layer.query(where="population > 10000")
df = result.to_frame() # pandas DataFrame
gdf = result.to_geodataframe() # GeoDataFrame (when geometry is present)
# Access raw features and field metadata
features = result.features
fields = result.fields
ApplyEditsResult — returned by apply_edits(), append(), upsert(), and sync():
edits = await layer.apply_edits(adds=[...], updates=[...], deletes=[...])
if edits.has_failures:
print("Failed adds:", edits.failed_adds)
print("Failed updates:", edits.failed_updates)
print("Failed deletes:", edits.failed_deletes)
FieldsResult — layer schema information:
fields = await layer.fields()
field_names = fields.names
numeric_fields = fields.filter(
types=["esriFieldTypeSmallInteger", "esriFieldTypeInteger"]
)
df = fields.to_frame()
AttachmentsQueryResult — returned by query_attachments():
result = await layer.query_attachments(definition_expression="status = 'open'")
df = result.to_frame() # camelCase column names
df = result.to_frame(use_field_names=True) # ESRI attachment-table field names
AttachmentsResult — returned by add_attachments(), update_attachments(), and
delete_attachments():
result = await layer.add_attachments(
object_ids=42,
files=Path("photo.jpg"),
)
if result.has_failures:
print("Failed attachments:", result.failed)
df = result.to_frame()
All three attachment write methods accept the same three calling modes:
- Single — one object ID and one file
- Fan-out — one object ID and multiple files (all attached to the same feature)
- Multi — parallel iterables of object IDs and files (one file per feature, run concurrently)
Error Handling
archibald raises typed exceptions for both Esri service errors and client-side errors, including the common case of HTTP 200 responses that contain embedded error payloads.
try:
result = await layer.query(where="invalid syntax")
except arc.ArcGISError as e:
print(f"Error {e.code}: {e.message}")
The ArcGISError hierarchy:
| Exception | When it's raised |
|---|---|
TokenExpiredError |
Token has expired (archibald auto-refreshes and retries) |
TokenMissingError |
Token required but not present |
AuthorizationError |
Insufficient permissions for the operation |
NotFoundError |
Resource not found |
ServiceError |
Other Esri service errors |
ArchieClientError and its subclasses cover archibald-originated errors (invalid parameters,
unsupported capabilities, etc.).
Roadmap
- Geocoding operations — suggest and batch geocode endpoints
Contributing
See CONTRIBUTING.md for guidance on setting up a development environment, running tests, and submitting pull requests.
Changelog
See CHANGELOG.md for release notes and version history.
License
MIT — see LICENSE for details.
Project details
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 archibald-1.1.1.tar.gz.
File metadata
- Download URL: archibald-1.1.1.tar.gz
- Upload date:
- Size: 186.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3abc4e3292abaf8ce72ef35b636545df5427027c48ac71f49ce29e46eb9bf935
|
|
| MD5 |
48d2cde408e4fe68f22689599a6cdffa
|
|
| BLAKE2b-256 |
4030cb63c02d052b81cb87f2586f6c82632542924cb0832f218f4d97d636a908
|
File details
Details for the file archibald-1.1.1-py3-none-any.whl.
File metadata
- Download URL: archibald-1.1.1-py3-none-any.whl
- Upload date:
- Size: 55.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa9f310f6d997c800e43ac445b319a11da36910231ad1ae446b3556d1ee15214
|
|
| MD5 |
a51ae81f7b77ee9668feefff5cb02d97
|
|
| BLAKE2b-256 |
06831fad0a5e805244dac099742b4ee574967a0ffdaeb0f6a73ca1ade8dbe4ed
|