httk.serve.optimade.backend =========================== .. py:module:: httk.serve.optimade.backend Submodules ---------- .. toctree:: :maxdepth: 1 /reference/autoapi/httk/serve/optimade/backend/adapter/index /reference/autoapi/httk/serve/optimade/backend/execution/index /reference/autoapi/httk/serve/optimade/backend/handlers/index /reference/autoapi/httk/serve/optimade/backend/memory_store/index /reference/autoapi/httk/serve/optimade/backend/partial/index /reference/autoapi/httk/serve/optimade/backend/protocols/index /reference/autoapi/httk/serve/optimade/backend/providers/index /reference/autoapi/httk/serve/optimade/backend/translation/index Classes ------- .. autoapisummary:: httk.serve.optimade.backend.BackendAdapter httk.serve.optimade.backend.EntrySource httk.serve.optimade.backend.StoreResults httk.serve.optimade.backend.InMemoryStore httk.serve.optimade.backend.PartialDimension httk.serve.optimade.backend.PartialValue httk.serve.optimade.backend.QueryFunction httk.serve.optimade.backend.QueryResults Functions --------- .. autoapisummary:: httk.serve.optimade.backend.execute_query httk.serve.optimade.backend.adapter_from_providers httk.serve.optimade.backend.providers_from_registry httk.serve.optimade.backend.translate_filter httk.serve.optimade.backend.translate_filter_node Package Contents ---------------- .. py:class:: BackendAdapter Binds a store to the OPTIMADE entry endpoints it serves. ``sources`` maps entry endpoint names (e.g. ``'structures'``) to the sources queried for that endpoint; an endpoint with several sources (e.g. several calculation result types) is queried across all of them. ``schema`` is required: it declares the served entry types and properties. ``field_handlers`` maps each entry type to its filter-handler table. When omitted (left empty) it is derived from ``schema`` via :func:`~httk.data.optimade_query.simple_property_handlers`, using an identity property-key map (each property is filtered against a backend field of the same name); a backend whose field names differ, or that wants finer control, supplies its own tables instead. .. py:attribute:: store :type: httk.data.query.Store .. py:attribute:: sources :type: collections.abc.Mapping[str, collections.abc.Sequence[EntrySource]] .. py:attribute:: schema :type: httk.serve.optimade.schema.served.ServedSchema .. py:attribute:: field_handlers :type: collections.abc.Mapping[str, httk.data.optimade_query.HandlerTable] .. py:method:: query_function() -> httk.serve.optimade.model.results.QueryFunction .. py:class:: EntrySource One queryable source (table/type) behind an OPTIMADE entry endpoint. ``target`` is what gets passed to ``searcher.variable()``; ``fields`` maps OPTIMADE response-field names to extractors applied to matched row objects. ``relationships``, when set, is an extractor mapping a matched row to a dictionary keyed by related entry type, each value a list of ``{'id': str, 'description': str?, 'role': str?}`` dictionaries. ``sort_keys`` maps response-field names to the backend field names to sort on. ``property_metadata`` maps response-field names to extractors returning the per-property metadata dictionary for a matched row (or ``None`` when there is no metadata for that row). .. py:attribute:: target :type: Any .. py:attribute:: fields :type: collections.abc.Mapping[str, FieldExtractor] .. py:attribute:: sort_keys :type: collections.abc.Mapping[str, str] .. py:attribute:: relationships :type: FieldExtractor | None :value: None .. py:attribute:: property_metadata :type: collections.abc.Mapping[str, FieldExtractor] .. py:class:: StoreResults(pairs: list[tuple[httk.serve.optimade.backend.adapter.EntrySource, httk.data.query.Searcher]], response_fields: list[str], unknown_response_fields: list[str], limit: int | None, offset: int, total_count: int, recognized_prefixes: tuple[str, Ellipsis]) Results of a query over one or more searchers. Implements the :class:`~httk.serve.optimade.model.results.QueryResults` protocol. Iteration yields one :class:`~httk.serve.optimade.model.results.ResultRow` per entry, whose values map response-field names to values extracted from the matched row objects. .. py:attribute:: pairs .. py:attribute:: recognized_prefixes .. py:attribute:: cur :type: collections.abc.Iterator[tuple[httk.serve.optimade.backend.adapter.EntrySource, Any]] | None .. py:attribute:: limit .. py:attribute:: response_fields .. py:attribute:: unknown_response_fields .. py:attribute:: offset .. py:attribute:: more_data_available :value: True .. py:method:: count() -> int Return all current-filter matches, before pagination. The endpoint metadata needs the filtered total even after execution has applied page limits and offsets to its searchers. Retaining it here also keeps the value stable once this one-shot result iterator is consumed. .. py:function:: execute_query(adapter: httk.serve.optimade.backend.adapter.BackendAdapter, entries: list[str], response_fields: list[str], unknown_response_fields: list[str], response_limit: int | None, response_offset: int | None, filter_ast: httk.core.FilterAst | None = None, *, sort: collections.abc.Sequence[tuple[str, bool]] | None = None, debug: bool = False) -> StoreResults .. py:class:: InMemoryStore(tables: dict[str, list[Row]]) A store over dict rows: ``InMemoryStore({'structures': [ {...}, ... ]})``. .. py:attribute:: tables .. py:method:: searcher() -> MemorySearcher .. py:class:: PartialDimension One list axis of a :class:`PartialValue`. ``length`` is the number of items along the axis (``None`` when unknown or entry-dependent and not declared). ``sliceable`` indicates whether the server can honour a slice request for this axis. .. py:attribute:: name :type: str .. py:attribute:: length :type: int | None :value: None .. py:attribute:: sliceable :type: bool :value: False .. py:class:: PartialValue A property value provided lazily, one slice at a time. ``fetch`` takes a tuple of Python slices (one per dimension, with the usual *exclusive* stop) and returns the corresponding nested lists. .. py:attribute:: dimensions :type: tuple[PartialDimension, Ellipsis] .. py:attribute:: fetch :type: collections.abc.Callable[[tuple[slice, Ellipsis]], Any] .. py:class:: QueryFunction Bases: :py:obj:`Protocol` The callback seam through which the request engine runs queries on a backend. .. py:class:: QueryResults Bases: :py:obj:`Protocol` The results of a query against a backend, as consumed by the entry endpoints. Iteration yields one :class:`~httk.serve.optimade.model.results.ResultRow` per entry; its ``values`` map OPTIMADE response-field names to values, and the ``id`` and ``type`` keys are always present. .. py:attribute:: more_data_available :type: bool .. py:method:: count() -> int .. py:function:: adapter_from_providers(providers: collections.abc.Iterable[httk.core.EntryProvider], **options: Any) -> httk.serve.optimade.backend.adapter.BackendAdapter Build a :class:`~httk.serve.optimade.backend.adapter.BackendAdapter` serving the given entry providers. Every provider's :meth:`~httk.core.EntryProvider.entry_types` become served entry types (described by their :class:`~httk.core.EntryTypeDefinition`), its :meth:`~httk.core.EntryProvider.property_keys` name the served subset and drive both the filter handlers (via :func:`~httk.data.optimade_query.simple_property_handlers`) and the response-field extractors, and its :meth:`~httk.core.EntryProvider.records` are loaded into an :class:`~httk.serve.optimade.backend.memory_store.InMemoryStore`. Every served property MUST be described by the entry type's definition (a custom property must therefore live in an :meth:`~httk.core.EntryTypeDefinition.extended` definition); a :class:`ValueError` names any offender. All served properties beyond ``id``/``type`` are marked default-response. Extra keyword ``options`` (e.g. ``sortable``, ``recognized_prefixes``) are forwarded to :func:`~httk.serve.optimade.schema.served.build_served_schema`; every served property is sortable-capable, since the provider's property-key map is passed through as the source's :attr:`~httk.serve.optimade.backend.adapter.EntrySource.sort_keys`. Declared relationships (:meth:`~httk.core.EntryProvider.relationships`) are fully auto-wired for serving *and* filtering: for each entry type with declared relationships, a synthetic ``__rel_`` id-list field is materialized on EVERY row of that entry type (an empty list when the row has no related entries of that type, so inverse set semantics are well-defined), and a ``'.id'`` entry built with :func:`~httk.data.optimade_query.relationship_id_handler` is merged into the entry type's derived filter-handler table (never overwriting an entry already present, mirroring how :class:`~httk.serve.optimade.backend.adapter.BackendAdapter` respects explicitly supplied handler tables). ``.id HAS ...`` filters — and, through the related-property resolver of :func:`~httk.serve.optimade.backend.translation.translate_filter`, depth-1 relationship-property filters such as ``references.doi CONTAINS "10.1"`` — therefore work without any hand-wiring. .. py:function:: providers_from_registry() -> dict[str, collections.abc.Callable[Ellipsis, httk.core.EntryProvider]] Return the registered entry-provider factories keyed by their registered name. Resolves each factory registered via :func:`httk.core.register_entry_provider` (through ``httk.registry.*`` self-registration) into a callable. Providers need data, so applications instantiate them: ``providers_from_registry()["atomistic-structures"](data)``. .. py:function:: translate_filter(filter_ast: httk.core.FilterAst | None, entries: list[str], adapter: httk.serve.optimade.backend.adapter.BackendAdapter, sort: collections.abc.Sequence[tuple[str, bool]] | None = None) -> list[tuple[httk.serve.optimade.backend.adapter.EntrySource, httk.data.query.Searcher]] Build one searcher per entry source, with the filter applied to each. Relationship-property filters (dotted identifiers over served entry types) are resolved through the adapter's related-property resolver (built by ``_related_property_resolver``), so filtering ``references.doi`` behaves exactly like filtering ``/references`` directly. .. py:function:: translate_filter_node(node: httk.core.FilterAst, search_variable: httk.data.query.SearchVariable, entry: str, entry_info: collections.abc.Mapping[str, Any], handlers: httk.data.optimade_query.HandlerTable, recognized_prefixes: tuple[str, Ellipsis], served_entries: tuple[str, Ellipsis] = ()) -> httk.data.query.SearchExpression Translate one filter node against an OPTIMADE *entry-info* property mapping. An OPTIMADE-side adaptation of :func:`~httk.data.optimade_query.translate_filter_ast`: ``entry_info`` maps property names to their property dictionaries (only their ``'fulltype'`` keys are read) rather than straight to fulltypes, ``served_entries`` names the relationship targets, and failures surface as :class:`~httk.serve.optimade.model.errors.TranslatorError` instead of the upstream neutral :class:`~httk.data.optimade_query.FilterTranslationError`. No related-property resolver is threaded through, so relationship-property filters other than ``.id HAS ...`` raise a not-implemented (501) error. Use :func:`translate_filter` (which builds the resolver from its adapter) for full relationship-property filtering.