National Gallery API Wrapper
A small Python wrapper around the National Gallery (London) Elasticsearch search endpoint. The library aims to provide:
- A more pythonic interface with the National Gallery API
- Plain-text rendering of records e.g. for use in LLM prompts (entity disambiguation, authority linking, etc.)
For a practical example of how this library can be used, some example notebooks are included.
National Gallery data is offered for reuse under specific licences.
Setup
This package is available for install via PyPi:
# sync only
pip install national-gallery-api
# sync and async
pip install "national-gallery-api[async]"
Quick start
The following entities are available: people, organisations, works, events, exhibitions, places, locations, concepts, publications, archives, media, and packages.
Search records
from national_gallery_api import NationalGallery
with NationalGallery() as ng:
results = ng.people.search("rembrandt", actual="Individual", size=5)
for person in results:
print(person.title, person.pid, person.dates)
Look up records by PID or NG number
Passing a list returns a list in the same order, fetched in batched requests. A NotFoundError names every identifier that matched nothing.
with NationalGallery() as ng:
vincent = ng.people.get("0QCE-0001-0000-0000")
print(vincent.title) # Vincent van Gogh
print(vincent.external_ids) # ULAN, Wikidata, RKD, VIAF, ...
people = ng.people.get(["0QCE-0001-0000-0000", "0P3C-0001-0000-0000"])
sunflowers = ng.works.get_by_ng_number("NG3863")
works = ng.works.get_by_ng_number(["NG3863", "ng 35", "NG6"])
# PIDs of any type, each parsed to its own model
vincent, sunflowers = ng.get(["0QCE-0001-0000-0000", "0GE6-0001-0000-0000"])
Iterate over all results
iter_all lazily walks an entire result set, handling paging internally:
with NationalGallery() as ng:
for person in ng.people.iter_all(actual="Individual", page_size=100):
...
Navigating Objects
Data objects are constructed at runtime to reflect the schemaless nature of the CIIM model served by the API. Child models are dynamically named to be semantically informative:
with NationalGallery() as ng:
vincent = ng.people.get("0QCE-0001-0000-0000")
print(vincent.birth.date[0].value) # 1853
print(vincent.description[0].value) # Van Gogh is today one of the most popular ...
# a string key on a list selects entries by their `type`; `.value` is the first match, `.values` all of them
print(vincent.name["primary name"].value) # Vincent van Gogh
print(vincent.identifier["PID (external)"].values) # ['http://vocab.getty.edu/ulan/500115588', ...]
# JSONPath, filters included, returns every match
print(vincent.jpath("$.description[?(@.type == 'web text')].value").value)
Simplified records
Each type has curated properties for its common fields, and to_dict() gathers them as plain, JSON-serialisable data. References are given by title. The full CIIM record stays reachable through the entity and .raw.
with NationalGallery() as ng:
sunflowers = ng.works.get_by_ng_number("NG3863")
print(sunflowers.attribution, sunflowers.medium) # Vincent van Gogh (1853–1890) oil on canvas
print(sunflowers.to_dict())
# {'title': 'Sunflowers', 'uid': '0GE6-0001-0000-0000', 'base': 'object', 'pid': '0GE6-0001-0000-0000', ...,
# 'object_number': 'NG3863', 'makers': ['Vincent van Gogh'], 'date': '1888', 'medium': 'oil on canvas', ...}
The model's __repr__ is designed to make exploring complex, deeply nested records clearer:
Person(
date=[Date(from_='1853', to='1890', value='1853 - 1890')],
summary=Summary(title='Vincent van Gogh'),
identifier=[
Identifier(type='PID', value='0QCE-0001-0000-0000'),
# ... 375 more lines of content
created=1633515854787,
formatted='<div><p>Van Gogh is today one of the most popular of the <a href="/paintings/glossary/post-impressionism">Post-Impressio'…(+1539 chars),
source='TMS',
type='web text',
value='Van Gogh is today one of the most popular of the Post-Impressionist painters, although he was not widely appreciated dur'…(+1175 chars),
status='Active'
)
]
)
Caching
Caching is disabled by default. To minimise server load when making frequent repeat requests (e.g. during batch jobs), cache should be enabled:
with NationalGallery(cache=True, ttl=3600, database_path="hishel_cache.db") as ng:
...
Async
AsyncNationalGallery mirrors the sync client.
import asyncio
from national_gallery_api import AsyncNationalGallery
async def main():
async with AsyncNationalGallery() as ng:
results = await ng.works.search("portrait", size=5)
for work in results:
...
async for work in ng.works.iter_all("portrait", page_size=50):
...
asyncio.run(main())
Rendering for LLM context
from national_gallery_api import NationalGallery, to_context, render_candidates
with NationalGallery() as ng:
vincent = ng.people.get("0QCE-0001-0000-0000")
print(to_context(vincent)) # for single entities
candidates = ng.people.search("rembrandt", actual="Individual", size=5)
print(render_candidates(candidates)) # for single entities or record sets
Example to_context output:
Person: Vincent van Gogh
PID: 0QCE-0001-0000-0000
Dates: 1853 - 1890
Roles: artist
Description: Van Gogh is today one of the most popular of the Post-Impressionist painters, although he was not widely appreciated during his lifetime.
Free-text search across all types
Calling search on the client object with a string performs a free-text search across all fields:
with NationalGallery() as ng:
results = ng.search("van gogh", size=10)
for entity in results:
...
# mixed collections of entity types can still be passed
print(render_candidates(results))
Raw Elasticsearch queries
Calling search on the client object with an Elasticsearch body allows for custom queries, returning an unparsed response dict. This should be used for any queries or fields not handled by the typed API:
with NationalGallery() as ng:
payload = ng.search({"query": {"match_all": {}}, "size": 0})
print(payload["hits"]["total"])
Query bodies can also be built with the build_search helper:
from national_gallery_api import build_search, EntityType
body = build_search("van gogh", base=EntityType.AGENT, actual="Individual", size=10)
Metadata
Release files for national-gallery-api 0.3.0
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 | |
|---|---|---|---|---|
| national_gallery_api-0.3.0.tar.gz | 22.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| national_gallery_api-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.8 kB
Release files / national_gallery_api-0.3.0.tar.gz
| Download URL | national_gallery_api-0.3.0.tar.gz |
|---|---|
| Size | 22.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
60bb58ac15b6077a7c5388e575821842d310b924d102263ff3e5c2766a81dbf3
|
|
BLAKE2b-256 checksum How to use checksums |
b100ab135afa5b4f13bd8b575cc28f035c692f587da91972fea28099ed47c9f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / national_gallery_api-0.3.0-py3-none-any.whl
| Download URL | national_gallery_api-0.3.0-py3-none-any.whl |
|---|---|
| Size | 25.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
44e9483255611df1c3ae07a9a21a62a4bf846a4f1c15b0efc5a06e0678293c59
|
|
BLAKE2b-256 checksum How to use checksums |
8db8fd79528f13721e1db5dbe76c553c0a247385064dd8b3f4b258fbfabd8257
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for national-gallery-api 0.3.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.