httk.store.query.optimade_filters

Translate OPTIMADE filter syntax trees into backend search expressions.

This module turns the OPTIMADE filter language — parsed by httk.core.optimade.parse_optimade_filter() into a httk.core.optimade.FilterAst nested-tuple syntax tree — into SearchExpression objects over the backend-agnostic store/searcher protocols of httk.store.query. It is pure and store-independent: any Store whose search variables expose the queried fields can execute the translated expressions.

The translation is driven by three inputs:

  • property_fulltypes — a minimal mapping from recognized property names to their OPTIMADE fulltype strings ("string", "integer", "float", "boolean", "timestamp", "dict", "unknown", or "list of ..."), used to type-check and convert filter constants;

  • handlers — a HandlerTable mapping property names to the callables that build the actual search expressions (see simple_property_handlers() for the generic property-key-driven builder, and relationship_id_handler() for <type>.id relationship entries);

  • recognized_prefixes — property-name prefixes the serving side claims: an unknown property carrying such a prefix is an error ("unrecognized-property"), while any other unknown property silently matches nothing, as the OPTIMADE specification prescribes.

Failures raise FilterTranslationError, which carries a neutral category (no HTTP semantics); consumers map categories onto their transport’s error codes.

Relationship filtering (dotted identifiers such as references.doi) is supported for relationship types named in relationship_targets: <type>.id HAS ... translates directly through the handler table, and any other depth-1 dotted filter is resolved by a two-phase semi-join through a supplied RelatedPropertyResolver (see translate_filter_ast()). Each dotted filter node is resolved independently: in references.doi CONTAINS "x" AND references.year >= 2000, some related reference must match the doi condition and some (possibly different) related reference must match the year condition.

Attributes

FilterTranslationCategory

Why a filter could not be translated (see FilterTranslationError).

HandlerTable

Per-property translation callables, keyed by property name.

RelatedPropertyResolver

Resolve a depth-1 relationship filter to the matching related-entry ids.

constant_types

Parsed filter token kinds that represent literal constants.

invert_op

Comparison operators after swapping a constant from left to right.

Exceptions

FilterTranslationError

Report that a filter cannot be translated into a search expression.

Functions

format_value(fulltype, val[, allow_null])

Convert a filter constant node to a Python value of the property's fulltype.

true_handler(search_variable)

Build a constant-true expression over search_variable.

false_handler(search_variable)

Build a constant-false expression over search_variable.

unknown_unknown_handler(entry, search_variable, ...)

Translate unknown-value tests for an unrecognized property.

known_unknown_handler(entry, search_variable, unknown_type)

Translate known-value tests for a property with known nullability.

field_unknown_handler(entry, search_variable, unknown_type)

Test nullability against the mapped backend field.

unknown_comparison_handler(entry, ops, values, ...)

Build a false expression for comparison on an unknown property.

unknown_stringmatching_handler(entry, values, ...)

Build a false expression for string matching on an unknown property.

unknown_has_handler(entry, op, value, search_variable, ...)

Build a false expression for set filtering on an unknown property.

unknown_length_handler(entry, op, value, search_variable)

Build a false expression for length filtering on an unknown property.

string_handler(entry, op, value, search_variable)

Translate a scalar comparison onto a backend field.

stringmatching_handler(entry, value, ...)

Translate CONTAINS/STARTS/ENDS onto the field's literal matchers.

constant_comparison_handler(val1, op, val2, ...)

Fold val1 <op> val2 (both constants) to a constant expression.

constant_stringmatching_handler(val1, val2, ...)

Fold val1 <CONTAINS|STARTS|ENDS> val2 (both constants) to a constant expression.

number_handler(entry, op, value, search_variable)

Translate a numeric comparison onto a backend field.

timestamp_handler(entry, op, value, search_variable)

Normalize an RFC 3339 timestamp and translate its comparison.

set_handler(entry, ops, values, has_type, search_variable)

Translate one HAS family node over the list-valued field entry.

constant_set_handler(val1, ops, val2, has_type, ...)

Fold a HAS-family operation over two constant sets.

translate_filter_ast(node, search_variable, ...[, ...])

Translate one filter syntax-tree node into a search expression.

simple_property_handlers(entry_type, property_keys, ...)

Build a filter handler table for an entry type from a property-key map.

relationship_id_handler(rel_key)

A '<type>.id' handler-table entry matching related ids over a list-valued field.

filter_searcher(store, target, filter_string, *, ...)

Build a Searcher over store applying an OPTIMADE filter.

Module Contents

type httk.store.query.optimade_filters.FilterTranslationCategory = Literal['unrecognized-property', 'not-implemented', 'type-mismatch', 'internal'][source]

Why a filter could not be translated (see FilterTranslationError).

type httk.store.query.optimade_filters.HandlerTable = Mapping[str, Mapping[str, Callable[..., Any]]][source]

Per-property translation callables, keyed by property name.

The inner mapping’s keys name the filter-operation families: 'comparison' (=, !=, <, <=, >, >=), 'stringmatching' (CONTAINS/STARTS/ENDS), 'HAS' (the set operations), 'length' (LENGTH), and 'unknown' (IS KNOWN/IS UNKNOWN). A 'HAS' handler is called as handler(property, ops, values, search_variable, has_type) and returns a plain SearchExpression. The caller applies NOT as ~; handlers do not receive negation state or report post-filter placement. Dotted '<type>.id' entries provide relationship-id filtering (see relationship_id_handler()).

type httk.store.query.optimade_filters.RelatedPropertyResolver = Callable[[str, FilterAst], tuple[str, ...]][source]

Resolve a depth-1 relationship filter to the matching related-entry ids.

Called as resolver(related_type, sub_ast) where sub_ast is the filter node with the <related_type>. prefix stripped from its identifier (and without any surrounding NOT); returns the ids of the related entries matching the sub-filter, evaluated against the related type’s own properties.

exception httk.store.query.optimade_filters.FilterTranslationError(message, category, detail=None)[source]

Bases: Exception

Report that a filter cannot be translated into a search expression.

The exception message describes the failure; category classifies it neutrally (this module knows nothing about transports, so consumers map each category onto their own error codes):

  • "unrecognized-property" — the filter names an unknown property carrying a recognized prefix (a caller error);

  • "type-mismatch" — a filter constant does not match the property’s declared type (a caller error);

  • "not-implemented" — the filter uses a construct this translation (or the supplied handler table) does not support;

  • "internal" — an inconsistency in the translation itself.

detail optionally carries extra machine-readable context.

Parameters:
  • message (str) – The human-readable translation failure.

  • category (FilterTranslationCategory) – The neutral failure category.

  • detail (str | None) – Optional machine-readable failure context.

category: FilterTranslationCategory[source]
detail = None[source]
httk.store.query.optimade_filters.constant_types = ('String', 'Number', 'Boolean')[source]

Parsed filter token kinds that represent literal constants.

httk.store.query.optimade_filters.invert_op[source]

Comparison operators after swapping a constant from left to right.

httk.store.query.optimade_filters.format_value(fulltype, val, allow_null=False)[source]

Convert a filter constant node to a Python value of the property’s fulltype.

Parameters:
  • fulltype (str) – The OPTIMADE fulltype expected by the property.

  • val (tuple[Any, ...]) – The parsed filter constant node.

  • allow_null (bool) – Whether a parsed null constant is accepted.

Returns:

The converted Python filter value.

Raises:

FilterTranslationError – With category "type-mismatch" when the constant does not fit the declared type, or "not-implemented" for dictionary-typed properties.

Return type:

Any

httk.store.query.optimade_filters.true_handler(search_variable)[source]

Build a constant-true expression over search_variable.

Parameters:

search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

An expression that matches every row.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.false_handler(search_variable)[source]

Build a constant-false expression over search_variable.

Parameters:

search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

An expression that matches no row.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.unknown_unknown_handler(entry, search_variable, unknown_type)[source]

Translate unknown-value tests for an unrecognized property.

Parameters:
  • entry (str) – The property name, retained for handler compatibility.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

  • unknown_type (str) – The IS_KNOWN or IS_UNKNOWN operator.

Returns:

The corresponding constant expression.

Raises:

FilterTranslationError – If unknown_type is not supported.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.known_unknown_handler(entry, search_variable, unknown_type)[source]

Translate known-value tests for a property with known nullability.

Parameters:
  • entry (str) – The property name, retained for handler compatibility.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

  • unknown_type (str) – The IS_KNOWN or IS_UNKNOWN operator.

Returns:

The corresponding constant expression.

Raises:

FilterTranslationError – If unknown_type is not supported.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.field_unknown_handler(entry, search_variable, unknown_type)[source]

Test nullability against the mapped backend field.

Parameters:
  • entry (str) – The backend field name to inspect.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

  • unknown_type (str) – The IS_KNOWN or IS_UNKNOWN operator.

Returns:

The nullability expression for the field.

Raises:

FilterTranslationError – If unknown_type is not supported.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.unknown_comparison_handler(entry, ops, values, search_variable)[source]

Build a false expression for comparison on an unknown property.

Parameters:
  • entry (str) – The unknown property name.

  • ops (Any) – The parsed comparison operators.

  • values (Any) – The parsed comparison values.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

An expression that matches no row.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.unknown_stringmatching_handler(entry, values, stringmatching_type, search_variable)[source]

Build a false expression for string matching on an unknown property.

Parameters:
  • entry (str) – The unknown property name.

  • values (Any) – The parsed match value.

  • stringmatching_type (str) – The parsed string-matching operator.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

An expression that matches no row.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.unknown_has_handler(entry, op, value, search_variable, has_type)[source]

Build a false expression for set filtering on an unknown property.

Parameters:
  • entry (str) – The unknown property name.

  • op (Any) – The parsed set operators.

  • value (Any) – The parsed set values.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

  • has_type (str) – The parsed HAS-family operator.

Returns:

An expression that matches no row.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.unknown_length_handler(entry, op, value, search_variable)[source]

Build a false expression for length filtering on an unknown property.

Parameters:
  • entry (str) – The unknown property name.

  • op (str) – The parsed length comparison operator.

  • value (Any) – The parsed length value.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

An expression that matches no row.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.string_handler(entry, op, value, search_variable)[source]

Translate a scalar comparison onto a backend field.

Parameters:
  • entry (str) – The backend field name.

  • op (str) – The comparison operator.

  • value (Any) – The converted filter value.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

The field comparison expression.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.stringmatching_handler(entry, value, stringmatching_type, search_variable)[source]

Translate CONTAINS/STARTS/ENDS onto the field’s literal matchers.

The filter constant is passed through unescaped: the search-field protocol’s contains/startswith/endswith take literal text, so % and _ match themselves (as OPTIMADE requires). Any escaping a backend’s pattern language needs is that backend’s own business.

Parameters:
  • entry (str) – The backend field name.

  • value (str) – The literal filter text.

  • stringmatching_type (str) – The CONTAINS, STARTS, or ENDS operator.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

The literal string-matching expression.

Raises:

FilterTranslationError – If stringmatching_type is not supported.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.constant_comparison_handler(val1, op, val2, search_variable)[source]

Fold val1 <op> val2 (both constants) to a constant expression.

val1 is the value being compared and val2 the filter constant, the same left-to-right convention as constant_set_handler(); translate_filter_ast() has already inverted op for constant-on-the-left filters, so this ordering is the filter’s own.

Parameters:
  • val1 (Any) – The value being compared.

  • op (str) – The comparison operator.

  • val2 (Any) – The filter constant.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

A constant expression representing the comparison result.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.constant_stringmatching_handler(val1, val2, stringmatching_type, search_variable)[source]

Fold val1 <CONTAINS|STARTS|ENDS> val2 (both constants) to a constant expression.

val1 is the value being matched and val2 the filter text, the same left-to-right convention as constant_set_handler().

Parameters:
  • val1 (Any) – The value being matched.

  • val2 (Any) – The filter text.

  • stringmatching_type (str) – The CONTAINS, STARTS, or ENDS operator.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

A constant expression representing the match result.

Raises:

FilterTranslationError – If stringmatching_type is not supported.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.number_handler(entry, op, value, search_variable)[source]

Translate a numeric comparison onto a backend field.

Parameters:
  • entry (str) – The backend field name.

  • op (str) – The comparison operator.

  • value (Any) – The converted numeric filter value.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

The field comparison expression.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.timestamp_handler(entry, op, value, search_variable)[source]

Normalize an RFC 3339 timestamp and translate its comparison.

Parameters:
  • entry (str) – The backend field name.

  • op (str) – The comparison operator.

  • value (Any) – The RFC 3339 timestamp filter value.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

The normalized timestamp comparison expression.

Raises:

FilterTranslationError – If value is not an offset-aware RFC 3339 timestamp.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.set_handler(entry, ops, values, has_type, search_variable)[source]

Translate one HAS family node over the list-valued field entry.

HAS ALL becomes a conjunction of one-value has_any calls (each constraining an independently joined child row); HAS ANY and HAS ONLY map straight onto has_any/has_only. Negation is not the handler’s business: a surrounding NOT inverts the returned expression, and the backend’s ~ knows how to negate a set predicate.

Parameters:
  • entry (str) – The backend list-valued field name.

  • ops (Any) – The parsed set comparison operators.

  • values (Any) – The converted set values.

  • has_type (str) – The HAS-family operator.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

The list-membership expression.

Raises:

FilterTranslationError – If has_type is not supported.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.constant_set_handler(val1, ops, val2, has_type, search_variable)[source]

Fold a HAS-family operation over two constant sets.

Parameters:
  • val1 (Any) – The list value being tested.

  • ops (Any) – The parsed set comparison operators.

  • val2 (Any) – The filter values.

  • has_type (str) – The HAS-family operator.

  • search_variable (httk.store.query.SearchVariable) – The backend search variable receiving the expression.

Returns:

A constant expression representing the set result.

Raises:

FilterTranslationError – If has_type is not supported.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.translate_filter_ast(node, search_variable, property_fulltypes, handlers, recognized_prefixes, *, relationship_targets=(), related_property_resolver=None)[source]

Translate one filter syntax-tree node into a search expression.

node is a FilterAst node (as produced by httk.core.optimade.parse_optimade_filter()); search_variable is the backend search variable the expression is built against; property_fulltypes, handlers, and recognized_prefixes drive the translation as described in the module docstring.

Returns the translated expression, ready to hand to add(). NOT translates to the backend’s ~; a backend whose set predicates need a second (post-filter) evaluation position derives that from the expression itself, so the caller never has to.

Relationship filtering: an identifier dotted with a name in relationship_targets (e.g. ('Identifier', 'references', 'doi')) filters on the properties of related entries. <type>.id HAS ... is served directly by the '<type>.id' handler-table entry. Every other depth-1 dotted filter — comparisons (including <type>.id = ...), string matching, IS KNOWN/IS UNKNOWN, and the HAS family over related list properties — is resolved by a two-phase semi-join: the <type>. prefix is stripped from the node, the resulting sub-filter is passed to related_property_resolver (without any surrounding NOT — inversion applies to the resulting id-set membership), and the returned ids are substituted back as <type>.id HAS ANY <ids> (an empty id set translates to a constant-false expression). Each dotted node is resolved independently: references.doi CONTAINS "x" AND references.year >= 2000 matches entries where some related reference matches the doi condition and some — possibly different — related reference matches the year condition. Without a resolver, dotted filters other than <type>.id HAS ... are not implemented; nested (deeper than depth-1) paths and dotted LENGTH filters are never supported.

Parameters:
Returns:

The translated backend search expression.

Raises:

FilterTranslationError – If the filter cannot be translated; see FilterTranslationError for the failure categories.

Return type:

httk.store.query.SearchExpression

httk.store.query.optimade_filters.simple_property_handlers(entry_type, property_keys, property_fulltypes)[source]

Build a filter handler table for an entry type from a property-key map.

Provides default handlers for standard id (matched against the ID_FIELD field) and type (a constant equal to entry_type). Entries in property_keys replace those defaults when their names overlap. For every property named in property_keys (which maps property names to backend field names), handlers are generated from the property’s fulltype in property_fulltypes (default "string"): string properties get comparison and stringmatching handlers; integer and float properties get a numeric comparison handler; list of ... properties get a HAS (set membership) handler. Every generated property also gets a known unknown handler.

Parameters:
Returns:

A handler table keyed by served property name.

Return type:

dict[str, collections.abc.Mapping[str, collections.abc.Callable[…, Any]]]

httk.store.query.optimade_filters.relationship_id_handler(rel_key)[source]

A '<type>.id' handler-table entry matching related ids over a list-valued field.

rel_key names a list-valued backend field holding the related entry ids; the returned {'HAS': ...} mapping serves <type>.id HAS ... filters (and the semi-join rewrites of other dotted filters) with the standard set-operation semantics of set_handler().

Parameters:

rel_key (str) – The backend field name for related entry identifiers.

Returns:

A handler mapping containing the HAS operation.

Return type:

collections.abc.Mapping[str, collections.abc.Callable[…, Any]]

httk.store.query.optimade_filters.filter_searcher(store, target, filter_string, *, entry_type, property_fulltypes, property_keys=None, handlers=None, recognized_prefixes=(), relationship_targets=(), related_property_resolver=None)[source]

Build a Searcher over store applying an OPTIMADE filter.

filter_string is an OPTIMADE filter string (parsed with httk.core.optimade.parse_optimade_filter()) or an already-parsed FilterAst. The searcher binds one search variable to target (the store-specific query target, declared as the searcher output named entry_type) and applies the translated filter. When handlers is not supplied, a default table is built with simple_property_handlers() from property_keys (or, when property_keys is also None, from an identity map over property_fulltypes). The remaining keyword arguments are passed through to translate_filter_ast().

Parameters:
  • store (httk.store.query.Store) – The backend store on which to build the searcher.

  • target (Any) – The backend query target to bind.

  • filter_string (str | httk.core.optimade.FilterAst) – An OPTIMADE filter string or parsed filter AST.

  • entry_type (str) – The output name and served entry type.

  • property_fulltypes (collections.abc.Mapping[str, str]) – Fulltypes keyed by recognized property name.

  • property_keys (collections.abc.Mapping[str, str] | None) – Optional mapping from property names to backend field names.

  • handlers (HandlerTable | None) – Optional prebuilt property handler table.

  • recognized_prefixes (tuple[str, ...]) – Prefixes whose unknown properties are errors.

  • relationship_targets (tuple[str, ...]) – Related entry types that support dotted filters.

  • related_property_resolver (RelatedPropertyResolver | None) – Optional resolver for related-property filters.

Returns:

A searcher with the translated filter already applied.

Raises:
Return type:

httk.store.query.Searcher