Installation

# Using pip
pip install geoserver-sdk

# Using poetry
poetry add geoserver-sdk
System Requirements Python 3.8+ required. Supports both synchronous and asynchronous execution environments.

Quick Start

Initialize the client and retrieve available workspaces:

from geoserver_sdk import GeoServerClient

# Initialize client
client = GeoServerClient(
    server="https://geo.example.com/geoserver",
    username="admin",
    password="geoserver"
)

# List all workspaces
workspaces = client.workspaces.list()
for ws in workspaces:
    print(f"{ws.name}: {ws.enabled}")

GeoServerClient

The main entry point for all operations. Configurable with retry policies, timeout settings, and custom HTTP headers.

Method Parameters Description Returns
__init__() server str, username str, password str, verify_ssl bool=True Initialize authenticated session None
health_check() None Verify server connectivity and authentication bool
create_workspace() name str, disable bool=False Register new workspace namespace Workspace
delete_workspace() name str, recursive bool=False Remove workspace and optionally its contents bool

Layer Management

Programmatic control over GeoServer layers, including publishing, styling, and bounding box configuration.

from geoserver_sdk import LayerStyle, CoverageStore

# Create a shapefile store
store = client.stores.create_shapefile(
    workspace="my_project",
    name="urban_zones",
    filepath="/data/zones.shp"
)

# Publish the layer
layer = store.publish_layer(
    name="zones",
    srs="EPSG:4326",
    style="polygon_fill"
)

# Update layer bounds dynamically
layer.calculate_bounds(recalculate=True)
print(f"Native BCRS: {layer.native_bcrs}")

Spatial Queries & WFS

Query features directly without downloading entire datasets. Supports CQL filters and geometry operations.

from geoserver_sdk import CQLFilter

# Build complex spatial query
query = client.queries.build(
    workspace="environment",
    layer="soil_moisture",
    properties=["id", "moisture_pct", "geometry"],
    filter=CQLFilter.and_(
        CQLFilter.gt("moisture_pct", 45.0),
        CQLFilter.within("geom", "POLYGON((...))")
    ),
    limit=500,
    srs_out="EPSG:3857"
)

# Execute and parse GeoJSON response
result = query.execute()
print(f"Found {result.total_features} records")
for feat in result.iter_features():
    print(feat.properties["id"])

SLD/SE Styling

Upload and manage layer styles programmatically. Supports both SLD XML and embedded style definitions.

Warning Overwriting default styles will affect all layers referencing them. Use unique style names for production workflows.
import xml.etree.ElementTree as ET

# Upload SLD from fileclient.styles.upload(
    workspace="my_project",
    name="custom_urban",
    filepath="./styles/urban.sld",
    overwrite=True
)

# Apply to layer
client.layers.set_style(
    workspace="my_project",
    layer="urban_zones",
    style="custom_urban"
)

Async Client (Python 3.10+)

For high-throughput pipelines, use AsyncGeoServerClient with httpx and asyncio.

from geoserver_sdk.async_client import AsyncGeoServerClient
import asyncio

async def batch_publish(layers_config):
    async with AsyncGeoServerClient("...", "admin", "pass") as client:
        tasks = [
            client.stores.publish(cfg)
            for cfg in layers_config
        ]
        return await asyncio.gather(*tasks)

# Run concurrent publishing
asyncio.run(batch_publish(["layer1", "layer2", "layer3"]))