Skip to main content

DSIS Python Client

Python SDK for the DSIS (DecisionSpace Integration Server) API. Handles dual-token authentication (Azure AD + DSIS) and provides a fluent query builder for OData access.

Installation

pip install dsis-client

For protobuf bulk data decoding (grids, horizons, seismic):

pip install dsis-schemas[protobuf]

Quick Start

import os
from dsis_client import DSISClient, DSISConfig, Environment, QueryBuilder

config = DSISConfig(
    environment=Environment.DEV,
    tenant_id=os.getenv("DSIS_TENANT_ID"),
    client_id=os.getenv("DSIS_CLIENT_ID"),
    client_secret=os.getenv("DSIS_CLIENT_SECRET"),
    access_app_id=os.getenv("DSIS_ACCESS_APP_ID"),
    dsis_username=os.getenv("DSIS_USERNAME"),
    dsis_password=os.getenv("DSIS_PASSWORD"),
    subscription_key_dsauth=os.getenv("DSIS_SUBSCRIPTION_KEY_DSAUTH"),
    subscription_key_dsdata=os.getenv("DSIS_SUBSCRIPTION_KEY_DSDATA"),
    dsis_site="qa",
    auth_timeout=(5, 30),  # Optional: bound Azure AD + DSIS token requests
)

client = DSISClient(config)

query = (
    QueryBuilder(
        model_name="OpenWorksCommonModel",
        district_id="OpenWorksCommonModel_OW_SV4TSTA-OW_SV4TSTA",
        project="SNORRE",
    )
    .schema("Well")
    .select("name", "depth", "status")
    .filter("depth gt 1000")
    .expand("wellbores")
)

for well in client.execute_query(query):
    print(well)

QueryBuilder

QueryBuilder is the primary way to query data. It uses method chaining and IS the query object (no .build() needed).

query = (
    QueryBuilder(
        model_name="OW5000",
        district_id="OpenWorks_OW_SV4TSTA_SingleSource-OW_SV4TSTA",
        project="SNORRE",
    )
    .schema("Fault")
    .select("fault_id,fault_type,fault_name")
    .filter("fault_type eq 'NORMAL'")
    .expand("interpretations")
)

for item in client.execute_query(query):
    print(item)

Type-safe casting with model classes

Pass a model class to .schema() and use cast=True to get typed results:

from dsis_model_sdk.models.common import Basin

query = (
    QueryBuilder(model_name="OpenWorksCommonModel", district_id=dist, project=prj)
    .schema(Basin)
    .select("basin_name,basin_id,native_uid")
)

for basin in client.execute_query(query, cast=True):
    print(basin.basin_name)  # IDE autocomplete works

Pagination

execute_query() automatically follows odata.nextLink across all pages. Control with max_pages:

# All pages (default)
all_items = list(client.execute_query(query))

# First page only (max 1000 items)
first_page = list(client.execute_query(query, max_pages=1))

Bulk Data (Protobuf)

Fetch binary data (horizons, log curves, seismic) with get_bulk_data() or stream large datasets with get_bulk_data_stream():

from dsis_model_sdk.models.common import HorizonData3D
from dsis_model_sdk.protobuf import decode_horizon_data

binary_data = client.get_bulk_data(
    schema=HorizonData3D,
    native_uid="46075",
    district_id=district_id,
    project=project,
)
decoded = decode_horizon_data(binary_data)

For large datasets, stream in chunks:

for chunk in client.get_bulk_data_stream(
    schema=SeismicDataSet3D,
    native_uid=seismic,
    query=query,
    chunk_size=10 * 1024 * 1024,  # 10 MB
    stream_retries=2,
):
    process(chunk)

Set stream_retries to retry transient failures while reading streamed chunks. Retries reopen the stream and assume the endpoint returns the same bytes across reconnects. The timeout value on streamed downloads applies to connection setup and waiting for the next bytes, not to the full transfer duration.

For authentication, set auth_timeout on DSISConfig to bound Azure AD token acquisition and DSIS token refresh requests:

config = DSISConfig(
    ...,
    auth_timeout=(5, 30),  # (connect_timeout, read_timeout)
)

Error Handling

from dsis_client import DSISAuthenticationError, DSISAPIError, DSISConfigurationError

try:
    client = DSISClient(config)
    for item in client.execute_query(query):
        print(item)
except DSISConfigurationError as e:
    print(f"Bad config: {e}")
except DSISAuthenticationError as e:
    print(f"Auth failed: {e}")
except DSISAPIError as e:
    print(f"Request failed: {e}")

Logging

import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("dsis_client").setLevel(logging.DEBUG)

Documentation

Contributing

See CONTRIBUTING.md.

License

MIT

Metadata

Release files for dsis-client 1.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dsis-client 1.8.0
File Size Uploaded
dsis_client-1.8.0.tar.gz 21.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dsis-client 1.8.0
File Interpreter ABI Platform
dsis_client-1.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 54.6 kB

Release files / dsis_client-1.8.0.tar.gz

Download URL dsis_client-1.8.0.tar.gz
Size 21.2 kB
Tags Source
SHA-256 checksum
How to use checksums
59e4efb9d8514bbbf310b9d17bb7b8669611231dae30ebc102cb37d7590a306a
BLAKE2b-256 checksum
How to use checksums
469729890bde7f84a273a2056f76592420f233ed168bb5065a28885b6058814d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.

Transparency log

Release files / dsis_client-1.8.0-py3-none-any.whl

Download URL dsis_client-1.8.0-py3-none-any.whl
Size 33.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a3e2e4e227aaaafecc2d6ae1aa8e40cbd4fa166294e2a7291c3c9e6d081c2947
BLAKE2b-256 checksum
How to use checksums
1f1def790c95282064eae909a86dc0c042f4e97cfd03b436e53654339520867d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.8.0 This release

2 release files

1.7.0

2 release files

1.6.1

2 release files

1.6.0

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page