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.5.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.5-py3-none-any.whl (7.0 kB view details)

Uploaded Python 3

File details

Details for the file odata_bc-0.1.5.tar.gz.

File metadata

  • Download URL: odata_bc-0.1.5.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.5.tar.gz
Algorithm Hash digest
SHA256 ceee59e96769c807e7ce97a1d94099ee0661c81b81acde8af28af9b152dd0fb4
MD5 484757fa0802a77b3984d0cc479c8226
BLAKE2b-256 bc0b7b335b9207b476bd7e6b47d70fdff694c142d76f4b45fb9bc3f37caa3c36

See more details on using hashes here.

File details

Details for the file odata_bc-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: odata_bc-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 7.0 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 4b76d81e54554b3374d6d9ad2ec7e22591848ce4d7b5a630503e06261b4293e9
MD5 aea960791c2ed767e3a9e28b990ad1a8
BLAKE2b-256 b6515f9e8599c904d73a4702c6c5a7a36d600894318482fe98e9d58ba6ce550c

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