Skip to main content

Simple OData client with query builder

Project description

Python OData Client

A powerful, intuitive, and production-ready OData client for Python with pandas integration.

Features

  • Fluent query building interface
  • Comprehensive OData query support ($filter, $select, $expand, $orderby, $top, $skip)
  • Batch fetching for large datasets
  • Automatic pagination handling with @odata.nextLink
  • Pandas DataFrame integration
  • Type hints for better IDE support
  • Extensible filter expression builder
  • Request authentication support
  • Logging integration with loguru
  • Query cloning for reuse
  • Timeout configuration

Installation

pip install odata-bc

Quick Start

from odata import OData, Q
from datetime import date

# Initialize client
client = OData("https://api.example.com", credentials=("user", "pass"))

# Create a query
sales = client("sales")
    .filter((Q("Amount") > 1000) & (Q("Date") >= date(2024, 1, 1)))
    .select("Id", "Amount", ("CustomerName", "client"))
    .orderby(("Amount", "desc"))
    .top(10)

# Execute query and get results as DataFrame
df = sales.fetch()

Detailed Usage

Client Initialization

Initialize the OData client with your service base URL and optional credentials:

from odata import OData

# Basic initialization
client = OData("https://api.example.com")

# With authentication
client = OData("https://api.example.com", credentials=("username", "password"))

Building Queries

The library provides a fluent interface for building OData queries:

query = client("sales")  # Initialize query for 'sales' endpoint

Filtering

Use the Q class to build filter expressions:

from odata import Q
from datetime import date

# Simple comparisons
query.filter(Q("Amount") > 1000)
query.filter(Q("Status") == "Active")
query.filter(Q("Date") >= date(2024, 1, 1))

# Combining conditions with & (and) and | (or)
query.filter(
    (Q("Type") == "Sale") & 
    (Q("Amount") > 1000) | 
    (Q("Status") == "Priority")
)

Supported operators:

  • == (eq)
  • != (ne)
  • > (gt)
  • >= (ge)
  • < (lt)
  • <= (le)
  • & (and)
  • | (or)

Batch Fetching

For scenarios where you need to fetch data for a large number of specific values:

# Fetch data for multiple order numbers efficiently
order_numbers = ['SO001', 'SO002', ..., 'SO10000']

results = query.select("OrderNo", "Amount", "Status") \
              .filter(Q("Type") == "Sale") \
              .batch_fetch("OrderNo", order_numbers, batch_size=25)

The batch_fetch method:

  • Automatically splits values into batches (default 25 per batch)
  • Combines with existing filters and query parameters
  • Handles pagination within each batch
  • Returns combined results as DataFrame or list

Select Fields

Select specific fields to return:

# Simple select
query.select("Id", "Name", "Amount")

# With field aliasing
query.select(
    ("Id", "identifier"),
    ("CustomerName", "client"),
    "Amount"
)

Ordering Results

Order results by one or more fields:

# Ascending order (default)
query.orderby("Date", "Amount")

# Descending order
query.orderby(("Date", "desc"), ("Amount", "desc"))

Pagination

The client handles pagination automatically using OData's @odata.nextLink. You can still control initial result set size:

# Limit total results
query.top(10)

# Skip initial records
query.skip(20)

# Iterate through all records with automatic pagination
for record in query:
    process_record(record)

Expanding Related Entities

Include related entities in the results:

query.expand("Customer", "Products")

Executing Queries

Fetch as DataFrame

By default, fetch() returns results as a pandas DataFrame:

# Default behavior
df = query.fetch()

# With custom timeout (in seconds)
df = query.fetch(timeout=60)

Fetch as List

Get results as a list of dictionaries:

records = query.fetch(as_dataframe=False)

Iterating Results

Iterate through individual records with automatic pagination:

# Iterate through all records
for record in query:
    process_record(record)

# With result limit
query.top(50)
for record in query:
    process_record(record)

Query Reuse

Clone queries to reuse and modify them:

base_query = client("sales").filter(Q("Status") == "Active")

# Clone and modify for different uses
high_value = base_query.clone().filter(Q("Amount") > 1000)
low_value = base_query.clone().filter(Q("Amount") < 1000)

Logging

The library uses loguru for logging:

from loguru import logger

# Configure logging
logger.add("odata.log", level="DEBUG", rotation="1 day")

Error Handling

The library raises standard HTTP exceptions from the requests library:

from requests.exceptions import RequestException

try:
    results = query.fetch()
except RequestException as e:
    print(f"Query failed: {e}")

Type Support

The library includes comprehensive type hints for better IDE support and static type checking:

from typing import Tuple, Union
from datetime import date

def get_sales(client: OData, start_date: date) -> pd.DataFrame:
    return client("sales").filter(Q("Date") >= start_date).fetch()

Performance Considerations

  • Use select() to limit returned fields when possible
  • Use batch_fetch() for querying large sets of specific values
  • Consider timeouts for slow connections or large queries
  • Use expand() judiciously as it can increase response size
  • Pagination is handled automatically for large result sets

License

This project is licensed under the MIT License - see the LICENSE file 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

odata_bc-0.1.4.post1.tar.gz (19.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

odata_bc-0.1.4.post1-py3-none-any.whl (7.1 kB view details)

Uploaded Python 3

File details

Details for the file odata_bc-0.1.4.post1.tar.gz.

File metadata

  • Download URL: odata_bc-0.1.4.post1.tar.gz
  • Upload date:
  • Size: 19.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for odata_bc-0.1.4.post1.tar.gz
Algorithm Hash digest
SHA256 e46a9bedc05523cacabcb960dfdd465302e75fb098605e39ed190eaeeb0422c5
MD5 7f4e1c9cb13cd1041f78149299b4c51a
BLAKE2b-256 1f702d6eb61098bd2a30498aa6480b9a01037ceb7052ecb6a596e41effd5168f

See more details on using hashes here.

File details

Details for the file odata_bc-0.1.4.post1-py3-none-any.whl.

File metadata

  • Download URL: odata_bc-0.1.4.post1-py3-none-any.whl
  • Upload date:
  • Size: 7.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for odata_bc-0.1.4.post1-py3-none-any.whl
Algorithm Hash digest
SHA256 76163ca1a7c00adfea857fb5126be8a42ecc464ffd3f920a5ebbd8b0c5322580
MD5 d34f73b113f0071d8930c02cf5a6b660
BLAKE2b-256 40615e275d2e026cd8adb50b975197512b1e37a7d22d34f60f7250881b48ef20

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page