Skip to content

utils

ANONYMOUS_ELEMENTS

Returns the first 150 values of the anonymous element generator.

ATOMIC_NUMBERS

CHEMICAL_FORMULA_REGEXP

CHEMICAL_SYMBOLS

EXTRA_SYMBOLS

OPTIMADE_SCHEMA_EXTENSION_KEYS

OPTIMADE_SCHEMA_EXTENSION_PREFIX

SemanticVersion (str)

A custom type for a semantic version, using the recommended semver regexp from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string.

Source code in optimade/models/utils.py
class SemanticVersion(str):
    """A custom type for a semantic version, using the recommended
    semver regexp from
    https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string.

    """

    regex = re.compile(
        r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
    )

    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def __modify_schema__(cls, field_schema):
        field_schema.update(
            pattern=cls.regex.pattern,
            example=["0.10.1", "1.0.0-rc.2", "1.2.3-rc.5+develop"],
        )

    @classmethod
    def validate(cls, v: str):
        if not cls.regex.match(v):
            raise ValueError(
                f"Unable to validate the version string {v!r} as a semantic version (expected <major>.<minor>.<patch>)."
                "See https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string for more information."
            )

        return v

    @property
    def _match(self):
        """The result of the regex match."""
        return self.regex.match(self)

    @property
    def major(self) -> int:
        """The major version number."""
        return int(self._match.group(1))

    @property
    def minor(self) -> int:
        """The minor version number."""
        return int(self._match.group(2))

    @property
    def patch(self) -> int:
        """The patch version number."""
        return int(self._match.group(3))

    @property
    def prerelease(self) -> str:
        """The pre-release tag."""
        return self._match.group(4)

    @property
    def build_metadata(self) -> str:
        """The build metadata."""
        return self._match.group(5)

    @property
    def base_version(self) -> str:
        """The base version string without patch and metadata info."""
        return f"{self.major}.{self.minor}.{self.patch}"

base_version: str property readonly

The base version string without patch and metadata info.

build_metadata: str property readonly

The build metadata.

major: int property readonly

The major version number.

minor: int property readonly

The minor version number.

patch: int property readonly

The patch version number.

prerelease: str property readonly

The pre-release tag.

regex

__get_validators__() classmethod special

Source code in optimade/models/utils.py
@classmethod
def __get_validators__(cls):
    yield cls.validate

__modify_schema__(field_schema) classmethod special

Source code in optimade/models/utils.py
@classmethod
def __modify_schema__(cls, field_schema):
    field_schema.update(
        pattern=cls.regex.pattern,
        example=["0.10.1", "1.0.0-rc.2", "1.2.3-rc.5+develop"],
    )

validate(v) classmethod

Source code in optimade/models/utils.py
@classmethod
def validate(cls, v: str):
    if not cls.regex.match(v):
        raise ValueError(
            f"Unable to validate the version string {v!r} as a semantic version (expected <major>.<minor>.<patch>)."
            "See https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string for more information."
        )

    return v

StrictFieldInfo (FieldInfo)

Wraps the standard pydantic FieldInfo in order to prefix any custom keys from StrictField.

Source code in optimade/models/utils.py
class StrictFieldInfo(FieldInfo):
    """Wraps the standard pydantic `FieldInfo` in order
    to prefix any custom keys from `StrictField`.

    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for key in OPTIMADE_SCHEMA_EXTENSION_KEYS:
            if key in self.extra:
                self.extra[f"{OPTIMADE_SCHEMA_EXTENSION_PREFIX}{key}"] = self.extra.pop(
                    key
                )

__init__(self, *args, **kwargs) special

Initialize self. See help(type(self)) for accurate signature.

Source code in optimade/models/utils.py
def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for key in OPTIMADE_SCHEMA_EXTENSION_KEYS:
        if key in self.extra:
            self.extra[f"{OPTIMADE_SCHEMA_EXTENSION_PREFIX}{key}"] = self.extra.pop(
                key
            )

SupportLevel (Enum)

OPTIMADE property/field support levels

Source code in optimade/models/utils.py
class SupportLevel(Enum):
    """OPTIMADE property/field support levels"""

    MUST = "must"
    SHOULD = "should"
    OPTIONAL = "optional"

MUST

OPTIONAL

SHOULD

OptimadeField(*args, *, support=None, queryable=None, unit=None, **kwargs)

A wrapper around pydantic.Field that adds OPTIMADE-specific field paramters queryable, support and unit, indicating the corresponding support level in the specification and the physical unit of the field.

Parameters:

Name Type Description Default
support Union[str, optimade.models.utils.SupportLevel]

The support level of the field itself, i.e. whether the field can be null or omitted by an implementation.

None
queryable Union[str, optimade.models.utils.SupportLevel]

The support level corresponding to the queryablility of this field.

None
unit Optional[str]

A string describing the unit of the field.

None

Returns:

Type Description
<cyfunction Field at 0x7fad4228e810>

The pydantic field with extra validation provided by StrictField.

Source code in optimade/models/utils.py
def OptimadeField(
    *args,
    support: Optional[Union[str, SupportLevel]] = None,
    queryable: Optional[Union[str, SupportLevel]] = None,
    unit: Optional[str] = None,
    **kwargs,
) -> Field:
    """A wrapper around `pydantic.Field` that adds OPTIMADE-specific
    field paramters `queryable`, `support` and `unit`, indicating
    the corresponding support level in the specification and the
    physical unit of the field.

    Arguments:
        support: The support level of the field itself, i.e. whether the field
            can be null or omitted by an implementation.
        queryable: The support level corresponding to the queryablility
            of this field.
        unit: A string describing the unit of the field.

    Returns:
        The pydantic field with extra validation provided by [`StrictField`][optimade.models.utils.StrictField].

    """

    # Collect non-null keyword arguments to add to the Field schema
    if unit is not None:
        kwargs["unit"] = unit
    if queryable is not None:
        if isinstance(queryable, str):
            queryable = SupportLevel(queryable.lower())
        kwargs["queryable"] = queryable
    if support is not None:
        if isinstance(support, str):
            support = SupportLevel(support.lower())
        kwargs["support"] = support

    return StrictField(*args, **kwargs)

StrictField(*args, *, description=None, **kwargs)

A wrapper around pydantic.Field that does the following:

  • Forbids any "extra" keys that would be passed to pydantic.Field, except those used elsewhere to modify the schema in-place, e.g. "uniqueItems", "pattern" and those added by OptimadeField, e.g. "unit", "queryable" and "sortable".
  • Emits a warning when no description is provided.

Parameters:

Name Type Description Default
*args Any

Positional arguments passed through to Field.

()
description Optional[str]

The description of the Field; if this is not specified then a UserWarning will be emitted.

None
**kwargs Any

Extra keyword arguments to be passed to Field.

{}

Exceptions:

Type Description
RuntimeError

If **kwargs contains a key not found in the function signature of Field, or in the extensions used by models in this package (see above).

Returns:

Type Description
StrictFieldInfo

The pydantic Field.

Source code in optimade/models/utils.py
def StrictField(
    *args: "Any",
    description: Optional[str] = None,
    **kwargs: "Any",
) -> StrictFieldInfo:
    """A wrapper around `pydantic.Field` that does the following:

    - Forbids any "extra" keys that would be passed to `pydantic.Field`,
      except those used elsewhere to modify the schema in-place,
      e.g. "uniqueItems", "pattern" and those added by OptimadeField, e.g.
      "unit", "queryable" and "sortable".
    - Emits a warning when no description is provided.

    Arguments:
        *args: Positional arguments passed through to `Field`.
        description: The description of the `Field`; if this is not
            specified then a `UserWarning` will be emitted.
        **kwargs: Extra keyword arguments to be passed to `Field`.

    Raises:
        RuntimeError: If `**kwargs` contains a key not found in the
            function signature of `Field`, or in the extensions used
            by models in this package (see above).

    Returns:
        The pydantic `Field`.

    """

    allowed_keys = [
        "pattern",
        "uniqueItems",
        "nullable",
    ] + OPTIMADE_SCHEMA_EXTENSION_KEYS
    _banned = [k for k in kwargs if k not in set(_PYDANTIC_FIELD_KWARGS + allowed_keys)]

    if _banned:
        raise RuntimeError(
            f"Not creating StrictField({args}, {kwargs}) with forbidden keywords {_banned}."
        )

    if description is not None:
        kwargs["description"] = description

    if description is None:
        warnings.warn(
            f"No description provided for StrictField specified by {args}, {kwargs}."
        )

    return StrictPydanticField(*args, **kwargs)

StrictPydanticField(*args, **kwargs)

Wrapper for Field that uses StrictFieldInfo instead of the pydantic FieldInfo.

Source code in optimade/models/utils.py
def StrictPydanticField(*args, **kwargs):
    """Wrapper for `Field` that uses `StrictFieldInfo` instead of
    the pydantic `FieldInfo`.
    """
    field_info = StrictFieldInfo(*args, **kwargs)
    field_info._validate()
    return field_info

anonymize_formula(formula)

Takes a string representation of a chemical formula of the form [A-Z][a-z]*[0-9]* (potentially with whitespace) and returns the OPTIMADE chemical_formula_anonymous representation, i.e., a reduced chemical formula comprising of element symbols drawn from A, B, C... ordered from largest proportion to smallest.

Returns:

Type Description
str

The anonymous chemical formula in the OPTIMADE representation.

Source code in optimade/models/utils.py
def anonymize_formula(formula: str) -> str:
    """Takes a string representation of a chemical formula of the form `[A-Z][a-z]*[0-9]*` (potentially with whitespace) and
    returns the OPTIMADE `chemical_formula_anonymous` representation, i.e., a reduced chemical formula comprising of element symbols
    drawn from A, B, C... ordered from largest proportion to smallest.

    Returns:
        The anonymous chemical formula in the OPTIMADE representation.

    """
    return _reduce_or_anonymize_formula(formula, alphabetize=False, anonymize=True)

anonymous_element_generator()

Generator that yields the next symbol in the A, B, Aa, ... Az naming scheme.

Source code in optimade/models/utils.py
def anonymous_element_generator():
    """Generator that yields the next symbol in the A, B, Aa, ... Az naming scheme."""
    from string import ascii_lowercase

    for size in itertools.count(1):
        for s in itertools.product(ascii_lowercase, repeat=size):
            s = list(s)
            s[0] = s[0].upper()
            yield "".join(s)

reduce_formula(formula)

Takes a string representation of a chemical formula of the form [A-Z][a-z]*[0-9]* (potentially with whitespace) and reduces it by the GCD of the proportion integers present in the formula, stripping any leftover "1" values.

Returns:

Type Description
str

The reduced chemical formula in the OPTIMADE representation.

Source code in optimade/models/utils.py
def reduce_formula(formula: str) -> str:
    """Takes a string representation of a chemical formula of the form `[A-Z][a-z]*[0-9]*` (potentially with whitespace) and
    reduces it by the GCD of the proportion integers present in the formula, stripping any leftover "1" values.

    Returns:
        The reduced chemical formula in the OPTIMADE representation.

    """
    return _reduce_or_anonymize_formula(formula, alphabetize=True, anonymize=False)