Skip to content

Commit

Permalink
Be more consistent about validator temrinology
Browse files Browse the repository at this point in the history
Use field validator or model validator explicitly instead of talking
about Pydantic validators. Remove the linter exclusion for the old
root_validator and validator functions, which are no longer used.
  • Loading branch information
rra committed Sep 18, 2023
1 parent 6ed0396 commit 870caa2
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 30 deletions.
8 changes: 4 additions & 4 deletions docs/user-guide/pydantic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Normalizing datetime fields
Pydantic supports several input formats for `~datetime.datetime` fields, but the resulting `~datetime.datetime` object may be timezone-naive.
Best practice for Python code is to only use timezone-aware `~datetime.datetime` objects in the UTC time zone.

Pydantic provides a utility function, `~safir.pydantic.normalize_datetime`, that can be used as a validator for a `~datetime.datetime` model field.
Pydantic provides a utility function, `~safir.pydantic.normalize_datetime`, that can be used as a field validator for a `~datetime.datetime` model field.
It ensures that any input is converted to UTC and is always timezone-aware.

Here's an example of how to use it:
Expand All @@ -36,14 +36,14 @@ Here's an example of how to use it:
normalize_datetime
)
Multiple attributes can be listed as the initial arguments of `~pydantic.validator` if there are multiple fields that need to be checked.
Multiple attributes can be listed as the initial arguments of `~pydantic.field_validator` if there are multiple fields that need to be checked.

This validator accepts all of the input formats that Pydantic accepts.
This field validator accepts all of the input formats that Pydantic accepts.
This includes some ambiguous formats, such as an ISO 8601 date without time zone information.
All such dates are given a consistent interpretation as UTC, but the results may be surprising if the caller expected local time.
In some cases, it may be desirable to restrict input to one unambiguous format.

This can be done by using `~safir.pydantic.normalize_isodatetime` as the validator instead.
This can be done by using `~safir.pydantic.normalize_isodatetime` as the field validator instead.
This function only accepts ``YYYY-MM-DDTHH:MM[:SS]Z`` as the input format.
The ``Z`` time zone prefix indicating UTC is mandatory.
It is called the same way as `~safir.pydantic.normalize_datetime`.
Expand Down
6 changes: 0 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,6 @@ builtins-ignorelist = [
fixture-parentheses = false
mark-parentheses = false

[tool.ruff.pep8-naming]
classmethod-decorators = [
"pydantic.root_validator",
"pydantic.validator",
]

[tool.ruff.pydocstyle]
convention = "numpy"

Expand Down
40 changes: 20 additions & 20 deletions src/safir/pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@


def normalize_datetime(v: int | datetime | None) -> datetime | None:
"""Pydantic validator for datetime fields.
"""Pydantic field validator for datetime fields.
Supports `~datetime.datetime` fields given in either any format supported
by Pydantic natively, or in seconds since epoch (which Pydantic doesn't
support). This validator ensures that datetimes are always stored in the
model as timezone-aware UTC datetimes.
support). This field validator ensures that datetimes are always stored
in the model as timezone-aware UTC datetimes.
Parameters
----------
Expand All @@ -41,12 +41,12 @@ def normalize_datetime(v: int | datetime | None) -> datetime | None:
Examples
--------
Here is a partial model that uses this function as a validator.
Here is a partial model that uses this function as a field validator.
.. code-block:: python
class Info(BaseModel):
last_used: Optional[datetime] = Field(
last_used: datetime | None = Field(
None,
title="Last used",
description="When last used in seconds since epoch",
Expand All @@ -68,12 +68,12 @@ class Info(BaseModel):


def normalize_isodatetime(v: str | None) -> datetime | None:
"""Pydantic validator for datetime fields in ISO format.
"""Pydantic field validator for datetime fields in ISO format.
This validator requires the ISO 8601 date and time format with ``Z`` as
the time zone (``YYYY-MM-DDTHH:MM:SSZ``). This format is compatible with
Kubernetes and the ISO UWS standard and is the same format produced by
`safir.datetime.isodatetime`. It should be used when the ambiguous
This field validator requires the ISO 8601 date and time format with ``Z``
as the time zone (``YYYY-MM-DDTHH:MM:SSZ``). This format is compatible
with Kubernetes and the ISO UWS standard and is the same format produced
by `safir.datetime.isodatetime`. It should be used when the ambiguous
formats supported by Pydantic by default (such as dates and times without
time zone information) shouldn't be allowed.
Expand All @@ -90,12 +90,12 @@ def normalize_isodatetime(v: str | None) -> datetime | None:
Examples
--------
Here is a partial model that uses this function as a validator.
Here is a partial model that uses this function as a field validator.
.. code-block:: python
class Info(BaseModel):
last_used: Optional[datetime] = Field(
last_used: datetime | None = Field(
None,
title="Last used",
description="Date and time last used",
Expand Down Expand Up @@ -216,13 +216,13 @@ def model_dump_json(self, **kwargs: Any) -> str:
def validate_exactly_one_of(
*settings: str,
) -> Callable[[BaseModel], BaseModel]:
"""Generate a validator imposing a one and only one constraint.
"""Generate a model validator imposing a one and only one constraint.
Sometimes, models have a set of attributes of which one and only one may
be set. Ideally this is represented properly in the type system, but
occasionally it's more convenient to use a validator. This is a validator
generator that can produce a validator function that ensures one and only
one of an arbitrary set of attributes must be set.
occasionally it's more convenient to use a model validator. This is a
model validator generator that can produce a model validator function that
ensures one and only one of an arbitrary set of attributes must be set.
Parameters
----------
Expand All @@ -237,7 +237,7 @@ def validate_exactly_one_of(
Examples
--------
Use this inside a Pydantic class as a validator as follows:
Use this inside a Pydantic class as a model validator as follows:
.. code-block:: python
Expand All @@ -250,9 +250,9 @@ class Foo(BaseModel):
validate_exactly_one_of("foo", "bar", "baz")
)
The attribute listed as the first argument to the ``validator`` call must
be the last attribute in the model definition so that any other attributes
have already been seen.
The attribute listed as the first argument to the ``model_validator`` call
must be the last attribute in the model definition so that any other
attributes have already been seen.
"""
if len(settings) < 2:
msg = "validate_exactly_one_of takes at least two field names"
Expand Down

0 comments on commit 870caa2

Please sign in to comment.