AI/LLM-friendly Python client for SAP OData V2 and V4 APIs - single generic function for all operations
Project description
SAP OData Python
Simple Python client for OData V2 and V4 services.
Installation
pip install sap-odata-python
Quick Start
from sap_odata import ODataClient
# Public OData service
client = ODataClient("https://services.odata.org")
# GET data
data = client.get("V4/Northwind/Northwind.svc", "Products", top=5)
for product in data["value"]:
print(product["ProductName"])
# With filters
data = client.get(
"V4/Northwind/Northwind.svc",
"Products",
filter="UnitPrice gt 20",
select="ProductID,ProductName,UnitPrice",
top=10
)
SAP OData V4 (RAP Services)
client = ODataClient(
host="https://sap-system.company.com",
username="user",
password="pass",
client="100"
)
# Simple query
data = client.get(
service="zmy_product_api",
entity="Products",
version="v4",
namespace="zsb_product_api",
filter="ProductID eq '12345'"
)
# Complex nested $expand
data = client.get(
service="zmy_order_api",
entity="Orders",
version="v4",
namespace="zsb_order_api",
filter="OrderID eq '12345'",
expand="Customer($expand=Contacts),LineItems($expand=Product,Discounts($expand=Details)),Payments($expand=BankAccount)"
)
# Access nested data
for order in data["value"]:
print(f"Order: {order['OrderID']}")
for line in order.get("LineItems", []):
print(f" Line Item: {line['ProductName']}")
SAP OData V2 (Gateway Services)
# Simple query
data = client.get(
service="ZMY_SALESORDER_SRV",
entity="SalesOrderSet",
version="v2",
top=10,
filter="Status eq 'OPEN'"
)
# Entity with key in path
data = client.get(
service="ZMY_CUSTOMER_SRV",
entity="CustomerSet(CustomerID='CUST001',Region='US')",
version="v2"
)
# Complex nested $expand (V2 style with /)
data = client.get(
service="ZMY_ORDER_SRV",
entity="OrderSet(OrderID='12345')",
version="v2",
expand="OrderToCustomer/CustomerToContacts,OrderToItems/ItemToProduct,OrderToItems/ItemToDiscounts,OrderToPayments/PaymentToBankAccount"
)
# V2 nested results are in "results" arrays
for order in data["value"]:
print(f"Order: {order['OrderID']}")
for item in order.get("OrderToItems", {}).get("results", []):
print(f" Item: {item['ProductName']}")
Write Operations
# POST - Create
new_order = client.post(
service="ZMY_SALESORDER_SRV",
entity="SalesOrderSet",
data={"CustomerID": "CUST001", "Amount": 1000},
version="v2"
)
# PATCH - Update
client.patch(
service="ZMY_SALESORDER_SRV",
entity="SalesOrderSet('12345')",
data={"Status": "APPROVED"},
version="v2"
)
# DELETE
client.delete(
service="ZMY_SALESORDER_SRV",
entity="SalesOrderSet('12345')",
version="v2"
)
Get Service Metadata
# V4 metadata
xml = client.metadata(service="zmy_product_api", namespace="zsb_product_api")
# V2 metadata
xml = client.metadata(service="ZMY_SALESORDER_SRV", version="v2")
print(xml) # Returns XML string with entity definitions
API Reference
ODataClient
client = ODataClient(
host="https://sap-system.com", # Base URL
username="user", # Optional: for auth
password="pass", # Optional: for auth
client="100", # Optional: SAP client
verify_ssl=True, # Optional: SSL verification
timeout=60 # Optional: request timeout
)
Methods
| Method | Description |
|---|---|
get(service, entity, version="v4", namespace="", **params) |
Read data |
post(service, entity, data, version="v4", namespace="") |
Create record |
patch(service, entity, data, version="v4", namespace="") |
Update record |
delete(service, entity, version="v4", namespace="") |
Delete record |
metadata(service, version="v4", namespace="") |
Get XML metadata |
Query Parameters
| Param | Example | Description |
|---|---|---|
top |
top=10 |
Limit results |
skip |
skip=20 |
Skip records (pagination) |
filter |
filter="Price gt 100" |
Filter expression |
select |
select="ID,Name" |
Select fields |
expand |
expand="Orders" |
Expand navigation properties |
orderby |
orderby="Name asc" |
Sort results |
Response Format
All responses are normalized to:
{"value": [{"field": "value"}, ...]}
- V4: Native format, returned as-is
- V2: Converted from
{"d": {"results": [...]}}to{"value": [...]}
Context Manager
with ODataClient("https://sap-system.com", "user", "pass", client="100") as client:
data = client.get("ZMY_SALESORDER_SRV", "SalesOrderSet", version="v2")
# Session automatically closed
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
sap_odata_python-1.0.3.tar.gz
(13.5 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sap_odata_python-1.0.3.tar.gz.
File metadata
- Download URL: sap_odata_python-1.0.3.tar.gz
- Upload date:
- Size: 13.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86d7d867dc19f7863719e5bb4ff184ac53d286e9c2f1354dde93c86bf32196d9
|
|
| MD5 |
200d9fdff5db4f5444887161ef6ebab4
|
|
| BLAKE2b-256 |
cadf06592d44d0e5c4d80af1870ae56bbe5efe0c2df89d44855530b354423981
|
File details
Details for the file sap_odata_python-1.0.3-py3-none-any.whl.
File metadata
- Download URL: sap_odata_python-1.0.3-py3-none-any.whl
- Upload date:
- Size: 11.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc4d95d05bc3f80a1072b3ec554987fbde5886b85a155d2ba47122d50a18f4ff
|
|
| MD5 |
8a31cce48fb8273f5bc26b65667170d0
|
|
| BLAKE2b-256 |
aba438298441b21d8d4535f1007e3e12c4d4fd7896d4b27a74e7d587b16d24fc
|