pyodata
pyodata is an enterprise-ready Python OData client that provides a comfortable and Python-agnostic way to communicate with OData services. It abstracts away OData protocol implementation details, primarily supporting OData V2, with future plans for V4 support. The library is actively maintained, with frequent minor releases, and its current version is 1.11.2.
Common errors
-
pyodata.exceptions.PyODataParserError: Unsupported Schema namespace - http://schemas.microsoft.com/ado/2007/05/edm
cause The OData service's metadata document uses an XML schema namespace that `pyodata`'s default parser configuration does not recognize or support, often indicating a service that deviates from standard OData metadata specifications.fixConfigure the `pyodata.Client` with custom XML namespaces if the service uses non-standard ones, or apply a tolerant parser policy (e.g., `PolicyWarning` or `PolicyIgnore`) via the `config` parameter to allow parsing despite minor schema issues. -
HTTP status code 403 Forbidden on POST/PATCH requests (e.g., when creating or updating an entity).
cause This is typically caused by missing or invalid CSRF (Cross-Site Request Forgery) tokens, which are a security measure on OData services, especially for modifying operations.fixBefore sending a POST or PATCH request, perform a HEAD request to the service URL (e.g., `session.head(SERVICE_URL, headers={'x-csrf-token': 'fetch'})`). Extract the `x-csrf-token` and `set-cookie` headers from the response and include them in the subsequent modifying request's headers or ensure the session object correctly manages them. -
Incomplete data retrieved for large collections; only a partial list of entities is returned.
cause The OData service is implementing server-side pagination, returning only a subset of entities with a link to the next page, typically indicated by a `__next` field in the response.fixAfter executing a `get_entities()` request, check the response for a `__next` attribute. If present, it contains the URI for the next page of results. You'll need to implement logic to follow these `__next` links to retrieve all pages of data.
Warnings
- breaking Python 3.7 and 3.8 are no longer supported. The library now requires Python >= 3.9.
- gotcha When creating or updating entities (POST/PATCH requests), OData services often require CSRF tokens. You must correctly initialize your `requests.Session` to handle these, typically by fetching a token with a HEAD request first.
- gotcha The metadata parser can encounter errors with non-fully valid metadata documents. This can lead to issues if the service is not under your control. By default, missing properties might be filled with type-specific default values.
- deprecated Directly setting custom XML namespaces via the client initialization is deprecated.
- gotcha OData services may require non-standard URL query parameters (e.g., 'sap-client') or specific path encoding. The default behavior might not always match specific service implementations.
Install
-
pip install -U pyodata
Imports
- Client
import pyodata # ... client = pyodata.Client(...)
- GetEntitySetFilter
from pyodata.v2.service import GetEntitySetFilter as esf
- HttpError
from pyodata.exceptions import HttpError
Quickstart
import requests
import pyodata
import os
# Replace with your OData service URL
SERVICE_URL = os.environ.get('PYODATA_SERVICE_URL', 'http://services.odata.org/V2/Northwind/Northwind.svc/')
session = requests.Session()
# For services requiring authentication
# username = os.environ.get('PYODATA_USERNAME', '')
# password = os.environ.get('PYODATA_PASSWORD', '')
# if username and password:
# session.auth = (username, password)
# Create instance of OData client
client = pyodata.Client(SERVICE_URL, session)
# Example: Query all products
products_request = client.entity_sets.Products.get_entities()
products = products_request.execute()
print(f"Found {len(products)} products:")
for product in products[:3]: # Print first 3 products
print(f"- {product.ProductName} (ID: {product.ProductID})")