I am a member of a team building SAP S/4HANA Cloud applications. I am mainly working on the back-end part (ABAP) but these days I am more involved in automation of our development processes where I often create tools in Python and Bash.
I would like to briefly introduce the Python library providing OData client our team has built while we were working on test automation of OData services providing data for our Fiori applications.
The library has name pyodata and its has three homes:
Why Python?
In the beginning of our Fiori journey, we made the decision to go for BTD and ATTD and since we were experienced Python programmers we took
Robot Framework as the test tool.
Our goals
Due to our lack of deep knowledge of OData protocol, our test base started growing by ad-hoc OData URLs builders and results processors. We were aware of the existing Python libraries but no one was willing to tailor them to our needs and some of them looked un-maintained.
In the next step, we created Robot keywords executing basic OData request and were happy until we ran into the need to prepare test data. It was a natural decision to start building the test-data preparation tools in Python too. At the moment we already had a metadata analyzer verifying validity of $metadata document (e.g. checking ValueList annotations points to the existing EntityTypes and EntityProperties).
So, we took the metadata analyzer and used its output to create a OData request builder seamlessly integrated into Python. We want to save us a lot of typing by avoiding the need to use brackets for function calls and providing string literals - instead we rather leverage Python dynamic features to enable writing code as if you had native Python types and functions.
Features
Currently the library supports only
However, we plan to add support for V4 soon and potentially V3 in future.
Even though we started with Python 2.7 we no longer support this version of Python and focus on
We did not want to make the library dependent on any HTTP framework, thus you must provide an object implementing
Python Requests Session object's interface. That allows to focus on OData protocol and ignore service vendor implementation details.
However, we have been building the library against SAP Gateway, so the implementation favors this vendor (for example, the library gracefully handle errors reported by SAP Gateway).
Examples
For demonstration purposes, I took the backend OData service at
https://fioriappslibrary.hana.ondemand.com/sap/fix/externalViewer/services/SingleApp.xsodata/ which provides data for
SAP Fiori Apps Reference Library
List of all OnPremis Releases
import requests
import pyodata
SERVICE_URL = 'https://fioriappslibrary.hana.ondemand.com/sap/fix/externalViewer/services/SingleApp.xsodata/'
client = pyodata.Client(SERVICE_URL, requests)
query = client.entity_sets.Releases.get_entities()
query = query.filter(query.releaseType == 'SOP')
for rel in query.execute():
print(f'{rel.releaseName} ({rel.releaseId})')
List of all apps in the release SAP S/4HANA 1809 and its FPSes
import requests
import pyodata
from pyodata.v2.service import GetEntitySetFilter as esf
SERVICE_URL = 'https://fioriappslibrary.hana.ondemand.com/sap/fix/externalViewer/services/SingleApp.xsodata/'
client = pyodata.Client(SERVICE_URL, requests)
rel_query = client.entity_sets.Releases.get_entities().filter("startswith(releaseName, 'S/4HANA 1809')")
sop_releases = rel_query.execute()
apps_query = client.entity_sets.AppsOnSearch.get_entities()
apps_cond = esf.or_(*[apps_query.releaseId == sop.releaseId for sop in sop_releases])
for app in apps_query.filter(apps_cond).execute():
print(f'{app.AppNameAll} ({app.appId})')
Bottom line
PyOData is being developed with Developer Experience in our minds and we have some ideas how to make the library even more comfortable (
our Wish List). However, only the developers using the library know which parts are not optimal, so I encourage you to report us your ideas.
I hope I will enjoy the python way of consuming OData services as our team do!