odatadol.read#
Reading an entity set: its URL, its count, its records page by page, and wide reads.
The functions take the service root and the entity set name first, then keyword-only
options, and share three seams: credentials=, fetch= and, for anything returning
records, parse_float=.
Server quirks met in practice, each with a default that copes:
$countis asked for withAccept: */*: some servers refuse a baretext/plain.A name that is not an OData identifier (
Unit Price) is double-quoted in$select/$orderby(quote_name()).:travels bare in the query string: a percent-encoded:inside a$filtertimestamp is a syntax error on some servers.JSON is parsed with
strict=False: raw control characters (a bare CR line break) inside strings are kept verbatim instead of failing the page.A front end may refuse URLs past ~2k characters, so
entity_columns()splits a wide$selectinto column groups undermax_urland joins them on a key.
Module Attributes
small enough that one slow page is not a timeout, large enough that tens of thousands of records are a few dozen requests. |
|
The longest URL |
Functions
|
The URL of an entity set, optionally with a path suffix and query options. |
|
A property name as |
|
How many records the entity set holds now (or match |
|
Records of an entity set, lazily, page by page, with OData annotations removed. |
|
Every record with every |
Exceptions
|
Reads of one entity set disagreed about which records exist, or their versions. |
- odatadol.read.DEFAULT_PAGE_SIZE = 1000#
small enough that one slow page is not a timeout, large enough that tens of thousands of records are a few dozen requests.
- Type:
Records per request
- odatadol.read.MAX_URL_CHARS = 2000#
The longest URL
entity_columns()sends. IIS’s default query-string ceiling is 2,048 characters, and past it IIS answers its own 404 as if the entity did not exist.
- exception odatadol.read.UnstableRead(message, *, status=None, code='')[source]#
Bases:
ODataErrorReads of one entity set disagreed about which records exist, or their versions.
- odatadol.read.entity_columns(service, entity, *, select, key, version=None, filter=None, max_url=2000, page_size=1000, credentials=None, fetch=None, parse_float=None)[source]#
Every record with every
selectfield, however many fields that is, as one moment.Splits
selectinto groups whose URL fitsmax_url, reads each group inkeyorder, and joins them onkey. Records come back in key order, each with exactly theselectfields, inselectorder.**A join of reads is only one moment if every read saw the same records in the same state.** So
version(a property the server rewrites on every edit, such as a modification timestamp) is read in every group and must agree per key; without it, an edit landing between two groups yields a record that never existed: the old name beside the new price. And there are always at least two reads: a single group is followed by a narrowkey/versionread, because$skippaging over a delete before the cursor and an insert after it skips a live record while the count still balances.- Raises:
UnstableRead – If reads disagree about which keys exist, their order, or their versions. The entity set changed during the read; retrying is safe.
ODataError – If
keyis empty or repeats: the join would silently merge different records into one.ValueError – If one field cannot fit under
max_urlat all.
- Return type:
- odatadol.read.entity_count(service, entity, *, filter=None, credentials=None, fetch=None)[source]#
How many records the entity set holds now (or match
filter). One request.- Return type:
- odatadol.read.entity_records(service, entity, *, select=None, filter=None, orderby=None, top=None, page_size=1000, credentials=None, fetch=None, parse_float=None)[source]#
Records of an entity set, lazily, page by page, with OData annotations removed.
Follows
@odata.nextLinkwhen the server sends one, and otherwise pages with$top/$skipuntil an empty page (a short page may be a server capping its pages without a nextLink, so it is not taken as the end).orderbyshould name a unique key: paging without a stable order can skip or repeat a record that moves between pages.- Parameters:
select (
Iterable[str] |None) – Properties to fetch (quoted as needed).Nonefetches all of them.filter (
str|None) – A$filterexpression, sent as written.orderby (
str|None) – A$orderbyexpression, sent as written (quote spaced names yourself withquote_name()).top (
int|None) – The most records to yield in all;Nonefor every one.page_size (
int) – Records asked for per request.parse_float (
Callable[[str],Any] |None) – Called on every JSON number with a fraction;decimal.Decimalkeeps every digit. Defaults tofloat.
- Return type:
- odatadol.read.entity_url(service, entity, *, suffix='', query=None)[source]#
The URL of an entity set, optionally with a path suffix and query options.
None-valued options are dropped, and:is not percent-encoded.>>> entity_url('https://example.com/odata/', 'Products', suffix='/$count', ... query={'$filter': 'ModifiedAt gt 2026-01-01T00:00:00Z', '$top': None}) 'https://example.com/odata/Products/$count?$filter=ModifiedAt%20gt%202026-01-01T00:00:00Z'
- Return type:
- odatadol.read.quote_name(name)[source]#
A property name as
$select/$orderbyaccept it.>>> quote_name('Status'), quote_name('Unit Price'), quote_name('Category/Name') ('Status', '"Unit Price"', 'Category/Name')
A bare
Unit Priceis a syntax error at the space; servers that allow such names (FileMaker’s OData, for one) take them double-quoted. A standard OData name is never quoted.- Raises:
ValueError – For a name holding a
", which no quoting can carry.- Return type: