python-fotoware-client
A thin, read-only Python client for the FotoWare API (FotoWeb). It does what the API does and shows what that costs; it knows nothing about any particular archive's fields.
Not affiliated with or endorsed by FotoWare AS. "FotoWare" and "FotoWeb" are their trademarks.
What it does
- One call is one request.
search_assetsreturns one page;next_pageanditer_searchfollowpaging.next. Nothing is batched or asked again behind the caller's back. The only exception are the rendition downloads, which poll until FotoWare has prepared the file. - Refuses a query FotoWare would answer wrongly. Over FotoWare's size limit
a search comes back as a 500 or, worse, as an empty list that looks exactly
like "no hits".
search_assetsestimates the query first and raisesQueryTooLargeErrorover the budget, without sending it.estimate_query_sizeis public, so callers can batch to stay under it. - Retries what is transient. urllib3's
Retryon the session retries 429 (honouringRetry-After) and 502/503/504, twice by default. A 500 is not retried: it was always caused by the query. - Counts the cost.
cost_snapshot()reports requests, retries, errors, search pages and empty search pages. - OAuth client credentials with automatic token refresh; context manager.
- Takes hrefs as FotoWare gives them. Answers carry paths on the tenant; every call that takes an href accepts a path or a full URL.
FotoWare's limits
Measured on 2026-10-23 against FotoWeb 8.1.1223.0; details and edges in
fotoware_client/limits.py.
| Limit | Value |
|---|---|
| Assets per search answer | 25, with pageSize ignored. FotoWare guarantees no page size, so the client follows paging.next and counts nothing |
| Cost of an answer | ~0.4 s with hits whether 1 or 25 assets; 130–220 ms empty |
| Search size | about 2,000 by estimate_query_size; budget 1,500 |
So the cheapest search asks for as many terms as fit the budget and fills whole pages.
Two search settings of an installation (Site Configuration › Searching) are out of the client's sight:
- Maximum number of hits caps a result set. A search with more hits ends early, without saying so.
- Search string modification decides how plain words without an operator
are combined (AND, OR or as a phrase). Write
AND/ORexplicitly, and the setting does not matter.
Settings of an installation
What a FotoWare installation may set differently, the client takes as
ServerSettings; the defaults are FotoWeb's:
from fotoware_client import FotoWareClient, ServerSettings
settings = ServerSettings(
original_rendition_name="Originaldatei", # display names are configurable
download_timeout=300, # seconds per download or rendition
rendition_poll_interval=0.5, # first wait while a rendition is made
query_size_budget=1200, # if the installation's limit is lower
)
client = FotoWareClient.from_env(settings=settings)
Also: oauth_token_path, api_descriptor_path, rendition_poll_interval_max
and term_overhead. See fotoware_client/settings.py.
Credentials
Pass them to the constructor, or let FotoWareClient.from_env() find them:
- the environment:
FOTOWARE_TENANT_URL,FOTOWARE_CLIENT_ID,FOTOWARE_CLIENT_SECRET; - else the credentials file
~/.config/fotoware/credentials($XDG_CONFIG_HOME/fotoware/credentials), oneNAME=valueper line, refused unless only its owner may read it (chmod 600).
Never on a command line, where a secret lands in the process list and the shell history.
Usage
from fotoware_client import FotoWareClient
with FotoWareClient.from_env() as client:
archive = next(
a for a in client.list_archives() if a.href.startswith("/fotoweb/archives/5000-")
)
query = "(631:4000000000001 OR 631:4000000000002) AND (dt:image OR dt:graphic)"
for page in client.iter_search(archive.href, query):
for asset in page.assets:
print(asset.filename)
print(client.cost_snapshot())
Other calls: get_asset, get_field_labels, get_rendition_url, download_original,
download_original_to_file, download_rendition_to_file, download_bytes.
Errors
All derive from FotoWareError:
| Error | When |
|---|---|
QueryTooLargeError |
the query is over the size budget; nothing sent |
RateLimitError |
a 429 outlasted the retries |
RetryExhaustedError |
a 502/503/504, connection error or timeout outlasted the retries |
NotFoundError |
a 404 |
APIError |
any other error status, a 500 among them |
AuthenticationError |
the token could not be fetched |
ConfigurationError |
the client was set up wrongly |
Install
pip install python-fotoware-client
Development
make venv
make lint type test
Pre-commit hooks: pip install pre-commit && pre-commit install.
License
MIT, see LICENSE.
Metadata
Release files for python-fotoware-client 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| python_fotoware_client-0.2.2.tar.gz | 35.9 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| python_fotoware_client-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 63.1 kB
Release files / python_fotoware_client-0.2.2.tar.gz
| Download URL | python_fotoware_client-0.2.2.tar.gz |
|---|---|
| Size | 35.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b3b724f4b0ce017c9a1ebd3a0bdcbdda19be864e5776295cf86e37ca05fd197a
|
|
BLAKE2b-256 checksum How to use checksums |
bb5537aa8d4a62a48deb231d6deabe47383472fac496df98763e552acc82fee2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / python_fotoware_client-0.2.2-py3-none-any.whl
| Download URL | python_fotoware_client-0.2.2-py3-none-any.whl |
|---|---|
| Size | 27.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ca70442f17814d227a4c050234ca4f016b8003f861afb32bde271f438d95f647
|
|
BLAKE2b-256 checksum How to use checksums |
a166008b78b2ef950873107939e982c1480e630fb826dc06a65cac86fc1b3780
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for python-fotoware-client 0.2.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for python_fotoware_client-0.2.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.