{"id":9230,"library":"pyodata","title":"pyodata","description":"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.","status":"active","version":"1.11.2","language":"en","source_language":"en","source_url":"https://github.com/SAP/python-pyodata","tags":["OData","SAP","client","REST","data-access","enterprise"],"install":[{"cmd":"pip install -U pyodata","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"PyOData requires an external HTTP library with an API compatible with `requests.Session` for all HTTP communication.","package":"requests","optional":false}],"imports":[{"note":"The primary entry point for interacting with an OData service.","symbol":"Client","correct":"import pyodata\n# ...\nclient = pyodata.Client(...)"},{"note":"Used for advanced filtering of entity sets in a more Pythonic/ORM-like style.","symbol":"GetEntitySetFilter","correct":"from pyodata.v2.service import GetEntitySetFilter as esf"},{"note":"Base exception for HTTP errors (status codes >= 400) returned by the OData service.","symbol":"HttpError","correct":"from pyodata.exceptions import HttpError"}],"quickstart":{"code":"import requests\nimport pyodata\nimport os\n\n# Replace with your OData service URL\nSERVICE_URL = os.environ.get('PYODATA_SERVICE_URL', 'http://services.odata.org/V2/Northwind/Northwind.svc/')\n\nsession = requests.Session()\n\n# For services requiring authentication\n# username = os.environ.get('PYODATA_USERNAME', '')\n# password = os.environ.get('PYODATA_PASSWORD', '')\n# if username and password:\n#     session.auth = (username, password)\n\n# Create instance of OData client\nclient = pyodata.Client(SERVICE_URL, session)\n\n# Example: Query all products\nproducts_request = client.entity_sets.Products.get_entities()\nproducts = products_request.execute()\n\nprint(f\"Found {len(products)} products:\")\nfor product in products[:3]: # Print first 3 products\n    print(f\"- {product.ProductName} (ID: {product.ProductID})\")\n","lang":"python","description":"Initializes an OData client using `requests.Session` and queries the 'Products' entity set from the Northwind OData V2 sample service. This demonstrates basic client setup and data retrieval."},"warnings":[{"fix":"Upgrade your Python environment to 3.9 or newer.","message":"Python 3.7 and 3.8 are no longer supported. The library now requires Python >= 3.9.","severity":"breaking","affected_versions":">=1.11.0"},{"fix":"Before making a POST/PATCH request, execute a HEAD request to the service URL to obtain the 'x-csrf-token' and 'set-cookie' headers, then include them in subsequent requests. Example: `session.head(SERVICE_URL, headers={'x-csrf-token': 'fetch'})`.","message":"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.","severity":"gotcha","affected_versions":"All"},{"fix":"Configure the metadata parser to recover from problems using `pyodata.Client`'s `config` parameter. You can specify parser policies (e.g., `PolicyWarning`, `PolicyIgnore`) and set `retain_null=False` to prevent substitution by default values.","message":"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.","severity":"gotcha","affected_versions":"All"},{"fix":"Use the `config` object (e.g., `pyodata.client.config`) to manage XML namespaces and other parser settings instead.","message":"Directly setting custom XML namespaces via the client initialization is deprecated.","severity":"deprecated","affected_versions":"<=1.x"},{"fix":"Use the `.custom(name, value)` method on entity requests to add custom query parameters. To disable URL path encoding, set `encode_path=False` during client initialization or on the request.","message":"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.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Configure 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.","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.","error":"pyodata.exceptions.PyODataParserError: Unsupported Schema namespace - http://schemas.microsoft.com/ado/2007/05/edm"},{"fix":"Before 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.","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.","error":"HTTP status code 403 Forbidden on POST/PATCH requests (e.g., when creating or updating an entity)."},{"fix":"After 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.","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.","error":"Incomplete data retrieved for large collections; only a partial list of entities is returned."}]}