From 824850c1bcea36858e20270b3612e1fab750ab6b Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:20:14 +0000 Subject: [PATCH 01/12] docs: Enable relative cross-references in mkdocstrings Add the `relative_crossrefs: true` option to the mkdocstrings Python handler options in mkdocs.yml. This enables relative cross- reference resolution in docstrings, which is the current convention being rolled out across all Frequenz Python projects. Signed-off-by: Leandro Lucarella --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 163d1fa..e0c3bcc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -112,6 +112,7 @@ plugins: show_source: true show_symbol_type_toc: true signature_crossrefs: true + relative_crossrefs: true inventories: - https://docs.python.org/3/objects.inv - https://typing-extensions.readthedocs.io/en/stable/objects.inv From 234cae571260099b4077efeb561628bb5fc1195b Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:20:19 +0000 Subject: [PATCH 02/12] ci: Enable pydoclint style mismatch and class attribute checks Add missing pydoclint options to the [tool.flake8] configuration: - check-class-attributes = true: enforce documentation of class attributes - check-style-mismatch = true: detect when docstrings use a different style than what is configured - require-inline-class-var-docs = true: require inline documentation for class variables These are part of the convention being actively rolled out across all Frequenz Python projects. Signed-off-by: Leandro Lucarella --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 421ed2f..94c6e99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,6 +127,9 @@ check-yield-types = false arg-type-hints-in-docstring = false arg-type-hints-in-signature = true allow-init-docstring = true +check-class-attributes = true +check-style-mismatch = true +require-inline-class-var-docs = true [tool.pylint.similarities] ignore-comments = ['yes'] From adcc035b0126f42a587e643df596b6c3213e5f1e Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:28:27 +0000 Subject: [PATCH 03/12] docs: Fix typos and grammar errors in docstrings - Fix subject-verb agreement in __init__.py module docstring: 'provide' -> 'provides' - Fix article agreement in ApparentPower class docstring: 'A apparent power' -> 'An apparent power' - Fix typo 'the a current' -> 'a current' in ApparentPower, Power and ReactivePower __truediv__ overload docstrings Signed-off-by: Leandro Lucarella --- src/frequenz/quantities/__init__.py | 2 +- src/frequenz/quantities/_apparent_power.py | 4 ++-- src/frequenz/quantities/_power.py | 2 +- src/frequenz/quantities/_reactive_power.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/frequenz/quantities/__init__.py b/src/frequenz/quantities/__init__.py index 1afd324..85c8e0f 100644 --- a/src/frequenz/quantities/__init__.py +++ b/src/frequenz/quantities/__init__.py @@ -3,7 +3,7 @@ """Types for holding quantities with units. -This library provide types for holding quantities with units. The main goal is to avoid +This library provides types for holding quantities with units. The main goal is to avoid mistakes while working with different types of quantities, for example avoiding adding a length to a time. diff --git a/src/frequenz/quantities/_apparent_power.py b/src/frequenz/quantities/_apparent_power.py index e5df26a..2da9bf1 100644 --- a/src/frequenz/quantities/_apparent_power.py +++ b/src/frequenz/quantities/_apparent_power.py @@ -25,7 +25,7 @@ class ApparentPower( 6: "MVA", }, ): - """A apparent power quantity. + """An apparent power quantity. Objects of this type are wrappers around `float` values and are immutable. @@ -193,7 +193,7 @@ def __truediv__(self, current: Current, /) -> Voltage: current: The current to divide by. Returns: - A voltage from dividing this power by the a current. + A voltage from dividing this power by a current. """ @overload diff --git a/src/frequenz/quantities/_power.py b/src/frequenz/quantities/_power.py index 2feb2da..94b2fb1 100644 --- a/src/frequenz/quantities/_power.py +++ b/src/frequenz/quantities/_power.py @@ -202,7 +202,7 @@ def __truediv__(self, current: Current, /) -> Voltage: current: The current to divide by. Returns: - A voltage from dividing this power by the a current. + A voltage from dividing this power by a current. """ @overload diff --git a/src/frequenz/quantities/_reactive_power.py b/src/frequenz/quantities/_reactive_power.py index a38acd8..5c56d88 100644 --- a/src/frequenz/quantities/_reactive_power.py +++ b/src/frequenz/quantities/_reactive_power.py @@ -193,7 +193,7 @@ def __truediv__(self, current: Current, /) -> Voltage: current: The current to divide by. Returns: - A voltage from dividing this power by the a current. + A voltage from dividing this power by a current. """ @overload From c859a1088b968dce4c687bc529c47265bc6571e1 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:28:42 +0000 Subject: [PATCH 04/12] docs: Fix property docstrings to use noun-phrase style Properties must use a one-line noun phrase starting with 'The' rather than imperative style with a Returns: section. - base_value: 'Return the value...' + Returns section -> 'The value of this quantity in the base unit.' - base_unit: 'Return the base unit...' + Returns section -> 'The base unit of this quantity, or None if this quantity has no unit.' Signed-off-by: Leandro Lucarella --- src/frequenz/quantities/_quantity.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/frequenz/quantities/_quantity.py b/src/frequenz/quantities/_quantity.py index db89c4a..566c30f 100644 --- a/src/frequenz/quantities/_quantity.py +++ b/src/frequenz/quantities/_quantity.py @@ -130,11 +130,7 @@ def from_string(cls, string: str) -> Self: @property def base_value(self) -> float: - """Return the value of this quantity in the base unit. - - Returns: - The value of this quantity in the base unit. - """ + """The value of this quantity in the base unit.""" return self._base_value def __round__(self, ndigits: int | None = None) -> Self: @@ -169,13 +165,7 @@ def __mod__(self, other: Self) -> Self: @property def base_unit(self) -> str | None: - """Return the base unit of this quantity. - - None if this quantity has no unit. - - Returns: - The base unit of this quantity. - """ + """The base unit of this quantity, or `None` if this quantity has no unit.""" if not self._exponent_unit_map: return None return self._exponent_unit_map[0] From ed1ff7aeb5ecc74bcef80fdd38a7c98fdd0405e8 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:29:35 +0000 Subject: [PATCH 05/12] docs: Fix copy-paste errors in operator docstrings Several operator docstrings were copied from Power and never updated to refer to the correct quantity type: - ApparentPower.__mul__: was 'power or energy' (wrong, no Energy return), now 'Scale this apparent power by a scalar or percentage' - ApparentPower.__truediv__: 'this power' -> 'this apparent power' throughout all overloads and implementation - Energy.__mul__: was 'percentage' only, now 'scalar or percentage' to match the float | Percentage signature - Energy.__truediv__: implementation was 'power or duration' (omitted the Self and float cases), now 'scaled energy, ratio, power, or duration' - ReactivePower.__mul__: was 'power or energy' (wrong), now 'Scale this reactive power by a scalar or percentage' - ReactivePower.__truediv__: 'this power' -> 'this reactive power' throughout all overloads and implementation Signed-off-by: Leandro Lucarella --- src/frequenz/quantities/_apparent_power.py | 44 +++++++++++----------- src/frequenz/quantities/_energy.py | 8 ++-- src/frequenz/quantities/_reactive_power.py | 44 +++++++++++----------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/frequenz/quantities/_apparent_power.py b/src/frequenz/quantities/_apparent_power.py index 2da9bf1..d2fa730 100644 --- a/src/frequenz/quantities/_apparent_power.py +++ b/src/frequenz/quantities/_apparent_power.py @@ -118,34 +118,34 @@ def as_mega_volt_amperes(self) -> float: @overload def __mul__(self, scalar: float, /) -> Self: - """Scale this power by a scalar. + """Scale this apparent power by a scalar. Args: - scalar: The scalar by which to scale this power. + scalar: The scalar by which to scale this apparent power. Returns: - The scaled power. + The scaled apparent power. """ @overload def __mul__(self, percent: Percentage, /) -> Self: - """Scale this power by a percentage. + """Scale this apparent power by a percentage. Args: - percent: The percentage by which to scale this power. + percent: The percentage by which to scale this apparent power. Returns: - The scaled power. + The scaled apparent power. """ def __mul__(self, other: float | Percentage, /) -> Self: - """Return a power or energy from multiplying this power by the given value. + """Scale this apparent power by a scalar or percentage. Args: - other: The scalar, percentage or duration to multiply by. + other: The scalar or percentage by which to scale this apparent power. Returns: - A power or energy. + The scaled apparent power. """ from ._percentage import Percentage # pylint: disable=import-outside-toplevel @@ -165,58 +165,58 @@ def __mul__(self, other: float | Percentage, /) -> Self: # https://github.com/python/mypy/issues/4985#issuecomment-389692396 @overload # type: ignore[override] def __truediv__(self, other: float, /) -> Self: - """Divide this power by a scalar. + """Divide this apparent power by a scalar. Args: - other: The scalar to divide this power by. + other: The scalar to divide this apparent power by. Returns: - The divided power. + The divided apparent power. """ @overload def __truediv__(self, other: Self, /) -> float: - """Return the ratio of this power to another. + """Return the ratio of this apparent power to another. Args: - other: The other power. + other: The other apparent power. Returns: - The ratio of this power to another. + The ratio of this apparent power to another. """ @overload def __truediv__(self, current: Current, /) -> Voltage: - """Return a voltage from dividing this power by the given current. + """Return a voltage from dividing this apparent power by the given current. Args: current: The current to divide by. Returns: - A voltage from dividing this power by a current. + A voltage from dividing this apparent power by a current. """ @overload def __truediv__(self, voltage: Voltage, /) -> Current: - """Return a current from dividing this power by the given voltage. + """Return a current from dividing this apparent power by the given voltage. Args: voltage: The voltage to divide by. Returns: - A current from dividing this power by a voltage. + A current from dividing this apparent power by a voltage. """ def __truediv__( self, other: float | Self | Current | Voltage, / ) -> Self | float | Voltage | Current: - """Return a current or voltage from dividing this power by the given value. + """Return a scaled apparent power, ratio, voltage, or current. Args: - other: The scalar, power, current or voltage to divide by. + other: The scalar, apparent power, current or voltage to divide by. Returns: - A current or voltage from dividing this power by the given value. + A scaled apparent power, a ratio, a voltage, or a current. """ from ._current import Current # pylint: disable=import-outside-toplevel from ._voltage import Voltage # pylint: disable=import-outside-toplevel diff --git a/src/frequenz/quantities/_energy.py b/src/frequenz/quantities/_energy.py index 57d03f3..6c416e7 100644 --- a/src/frequenz/quantities/_energy.py +++ b/src/frequenz/quantities/_energy.py @@ -96,10 +96,10 @@ def as_megawatt_hours(self) -> float: return self._base_value / 1e6 def __mul__(self, other: float | Percentage) -> Self: - """Scale this energy by a percentage. + """Scale this energy by a scalar or percentage. Args: - other: The percentage by which to scale this energy. + other: The scalar or percentage by which to scale this energy. Returns: The scaled energy. @@ -162,13 +162,13 @@ def __truediv__(self, power: Power, /) -> timedelta: def __truediv__( self, other: float | Self | timedelta | Power, / ) -> Self | float | Power | timedelta: - """Return a power or duration from dividing this energy by the given value. + """Return a scaled energy, ratio, power, or duration. Args: other: The scalar, energy, power or duration to divide by. Returns: - A power or duration from dividing this energy by the given value. + A scaled energy, a ratio, a power, or a duration. """ from ._power import Power # pylint: disable=import-outside-toplevel diff --git a/src/frequenz/quantities/_reactive_power.py b/src/frequenz/quantities/_reactive_power.py index 5c56d88..24898ca 100644 --- a/src/frequenz/quantities/_reactive_power.py +++ b/src/frequenz/quantities/_reactive_power.py @@ -118,34 +118,34 @@ def as_mega_volt_amperes_reactive(self) -> float: @overload def __mul__(self, scalar: float, /) -> Self: - """Scale this power by a scalar. + """Scale this reactive power by a scalar. Args: - scalar: The scalar by which to scale this power. + scalar: The scalar by which to scale this reactive power. Returns: - The scaled power. + The scaled reactive power. """ @overload def __mul__(self, percent: Percentage, /) -> Self: - """Scale this power by a percentage. + """Scale this reactive power by a percentage. Args: - percent: The percentage by which to scale this power. + percent: The percentage by which to scale this reactive power. Returns: - The scaled power. + The scaled reactive power. """ def __mul__(self, other: float | Percentage, /) -> Self: - """Return a power or energy from multiplying this power by the given value. + """Scale this reactive power by a scalar or percentage. Args: - other: The scalar, percentage or duration to multiply by. + other: The scalar or percentage by which to scale this reactive power. Returns: - A power or energy. + The scaled reactive power. """ from ._percentage import Percentage # pylint: disable=import-outside-toplevel @@ -165,58 +165,58 @@ def __mul__(self, other: float | Percentage, /) -> Self: # https://github.com/python/mypy/issues/4985#issuecomment-389692396 @overload # type: ignore[override] def __truediv__(self, other: float, /) -> Self: - """Divide this power by a scalar. + """Divide this reactive power by a scalar. Args: - other: The scalar to divide this power by. + other: The scalar to divide this reactive power by. Returns: - The divided power. + The divided reactive power. """ @overload def __truediv__(self, other: Self, /) -> float: - """Return the ratio of this power to another. + """Return the ratio of this reactive power to another. Args: - other: The other power. + other: The other reactive power. Returns: - The ratio of this power to another. + The ratio of this reactive power to another. """ @overload def __truediv__(self, current: Current, /) -> Voltage: - """Return a voltage from dividing this power by the given current. + """Return a voltage from dividing this reactive power by the given current. Args: current: The current to divide by. Returns: - A voltage from dividing this power by a current. + A voltage from dividing this reactive power by a current. """ @overload def __truediv__(self, voltage: Voltage, /) -> Current: - """Return a current from dividing this power by the given voltage. + """Return a current from dividing this reactive power by the given voltage. Args: voltage: The voltage to divide by. Returns: - A current from dividing this power by a voltage. + A current from dividing this reactive power by a voltage. """ def __truediv__( self, other: float | Self | Current | Voltage, / ) -> Self | float | Voltage | Current: - """Return a current or voltage from dividing this power by the given value. + """Return a scaled reactive power, ratio, voltage, or current. Args: - other: The scalar, power, current or voltage to divide by. + other: The scalar, reactive power, current or voltage to divide by. Returns: - A current or voltage from dividing this power by the given value. + A scaled reactive power, a ratio, a voltage, or a current. """ from ._current import Current # pylint: disable=import-outside-toplevel from ._voltage import Voltage # pylint: disable=import-outside-toplevel From b48389d191240e32c33ebfa535f9770539df44b0 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:29:55 +0000 Subject: [PATCH 06/12] docs: Fix minor docstring issues in _quantity.py - Remove trailing blank line inside from_string() Raises: section - Fix __truediv__ overload 1: arg description incorrectly mentioned 'or percentage' in a float-only overload - Capitalize arg descriptions in NoDefaultConstructible.__call__: 'ignored positional arguments' -> 'Ignored positional arguments' Signed-off-by: Leandro Lucarella --- src/frequenz/quantities/_quantity.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/frequenz/quantities/_quantity.py b/src/frequenz/quantities/_quantity.py index 566c30f..3982a21 100644 --- a/src/frequenz/quantities/_quantity.py +++ b/src/frequenz/quantities/_quantity.py @@ -104,7 +104,6 @@ def from_string(cls, string: str) -> Self: Raises: ValueError: If the string does not match the expected format. - """ split_string = string.split(" ") @@ -386,7 +385,7 @@ def __truediv__(self, other: float, /) -> Self: """Divide this quantity by a scalar. Args: - other: The scalar or percentage to divide this quantity by. + other: The scalar to divide this quantity by. Returns: The divided quantity. @@ -517,8 +516,8 @@ def __call__(cls, *_args: Any, **_kwargs: Any) -> NoReturn: """Raise a TypeError when the default constructor is called. Args: - *_args: ignored positional arguments. - **_kwargs: ignored keyword arguments. + *_args: Ignored positional arguments. + **_kwargs: Ignored keyword arguments. Raises: TypeError: Always. From 426477cd50711f61042b617befbfbdbd5707891d Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:30:20 +0000 Subject: [PATCH 07/12] docs: Replace absolute cross-references with relative ones in __init__.py Use name-based auto-resolve form [`Foo`][] and relative cross- references like [.Power.from_watts] and [.experimental.marshmallow] instead of absolute fully-qualified paths like [frequenz.quantities.Power]. This is consistent with the convention of using relative cross-references (relative_crossrefs: true) wherever possible. Also add backtick formatting to cross-reference display text for the class list and the Quantity mention in the prose. Signed-off-by: Leandro Lucarella --- src/frequenz/quantities/__init__.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/frequenz/quantities/__init__.py b/src/frequenz/quantities/__init__.py index 85c8e0f..a03a17d 100644 --- a/src/frequenz/quantities/__init__.py +++ b/src/frequenz/quantities/__init__.py @@ -13,7 +13,7 @@ Quantities store the value in a base unit, and then provide methods to get that quantity as a particular unit. They can only be constructed using special constructors with the form `Quantity.from_`, for example -[`Power.from_watts(10.0)`][frequenz.quantities.Power.from_watts]. +[`Power.from_watts(10.0)`][.Power.from_watts]. Internally quantities store values as `float`s, so regular [float issues and limitations apply](https://docs.python.org/3/tutorial/floatingpoint.html), although some of them are @@ -24,19 +24,17 @@ This library provides the following types: -- [ApparentPower][frequenz.quantities.ApparentPower]: A quantity representing apparent - power. -- [Current][frequenz.quantities.Current]: A quantity representing an electric current. -- [Energy][frequenz.quantities.Energy]: A quantity representing energy. -- [Frequency][frequenz.quantities.Frequency]: A quantity representing frequency. -- [Percentage][frequenz.quantities.Percentage]: A quantity representing a percentage. -- [Power][frequenz.quantities.Power]: A quantity representing power. -- [ReactivePower][frequenz.quantities.ReactivePower]: A quantity representing reactive - power. -- [Temperature][frequenz.quantities.Temperature]: A quantity representing temperature. -- [Voltage][frequenz.quantities.Voltage]: A quantity representing electric voltage. - -There is also the unitless [Quantity][frequenz.quantities.Quantity] class. All +- [`ApparentPower`][]: A quantity representing apparent power. +- [`Current`][]: A quantity representing an electric current. +- [`Energy`][]: A quantity representing energy. +- [`Frequency`][]: A quantity representing frequency. +- [`Percentage`][]: A quantity representing a percentage. +- [`Power`][]: A quantity representing power. +- [`ReactivePower`][]: A quantity representing reactive power. +- [`Temperature`][]: A quantity representing temperature. +- [`Voltage`][]: A quantity representing electric voltage. + +There is also the unitless [`Quantity`][] class. All quantities are subclasses of this class and it can be used as a base to create new quantities. Using the `Quantity` class directly is discouraged, as it doesn't provide any unit conversion methods. @@ -80,7 +78,7 @@ ``` This library also provides an [**experimental** module with marshmallow fields and -a base schema][frequenz.quantities.experimental.marshmallow] to serialize and +a base schema][.experimental.marshmallow] to serialize and deserialize quantities using the marshmallow library. To use it, you need to make sure to install this package with the `marshmallow` optional dependencies (e.g. `pip install frequenz-quantities[marshmallow]`). From 005cd2e53bfee3bae2229c0062fa71797f9d308b Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:31:08 +0000 Subject: [PATCH 08/12] docs: Add marshmallow inventory for cross-reference resolution The experimental marshmallow module references marshmallow.ValidationError in docstrings. Add the marshmallow readthedocs inventory so mkdocstrings can resolve the cross-reference correctly. Signed-off-by: Leandro Lucarella --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index e0c3bcc..de77690 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -115,6 +115,7 @@ plugins: relative_crossrefs: true inventories: - https://docs.python.org/3/objects.inv + - https://marshmallow.readthedocs.io/en/stable/objects.inv - https://typing-extensions.readthedocs.io/en/stable/objects.inv # Note this plugin must be loaded after mkdocstrings to be able to use macros # inside docstrings. From ed6f1b8ffa663ab685d1abd6cc94e415286387fd Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:34:33 +0000 Subject: [PATCH 09/12] docs: Fix multiple docstring violations in experimental/marshmallow.py - Module docstring: absolute cross-ref -> [`QuantitySchema`][] - serialize_as_string_default: fix summary ('The context variable...'), backtick True/False - _QuantityField class: add 'A' prefix, add cross-refs for Quantity, field_type, QuantitySchema.TYPE_MAPPING, QUANTITY_FIELD_CLASSES; use relative references (.field_type, ..QuantitySchema.TYPE_MAPPING) - field_type attribute: add Quantity cross-reference - _serialize: add Args and Returns sections - _deserialize: add Args, Returns, and Raises sections with marshmallow.ValidationError cross-reference - Field subclasses (9): add 'A' prefix and quantity cross-refs - QUANTITY_FIELD_CLASSES: fix summary ('The mapping from...'), add cross-ref to QuantitySchema.TYPE_MAPPING - QuantitySchema: 'Example usage:' -> 'Example:' - TYPE_MAPPING: add missing inline docstring Signed-off-by: Leandro Lucarella --- .../quantities/experimental/marshmallow.py | 98 ++++++++++++------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/src/frequenz/quantities/experimental/marshmallow.py b/src/frequenz/quantities/experimental/marshmallow.py index 9bb28e7..abf2cef 100644 --- a/src/frequenz/quantities/experimental/marshmallow.py +++ b/src/frequenz/quantities/experimental/marshmallow.py @@ -4,7 +4,7 @@ """Custom marshmallow fields and schema. This module provides custom marshmallow fields for quantities and -a [QuantitySchema][frequenz.quantities.experimental.marshmallow.QuantitySchema] class to +a [`QuantitySchema`][] class to be used as base schema for dataclasses containing quantities. Danger: @@ -34,42 +34,43 @@ serialize_as_string_default: ContextVar[bool] = ContextVar( "serialize_as_string_default", default=False ) -"""Context variable to control the default serialization format for quantities. +"""The context variable controlling the default serialization format for quantities. -If True, quantities are serialized as strings with units. -If False, quantities are serialized as floats. - -This can be overridden on a per-field basis using the `serialize_as_string` -metadata attribute. +If `True`, quantities are serialized as strings with units; if `False`, as floats. +This can be overridden on a per-field basis using the `serialize_as_string` metadata +attribute. """ class _QuantityField(Field[Quantity]): - """Custom field for Quantity objects supporting per-field serialization configuration. + """A custom field for [`Quantity`][] objects supporting per-field serialization. - This class handles serialization and deserialization of ALL Quantity + This class handles serialization and deserialization of ALL [`Quantity`][] subclasses. - The specific Quantity subclass is determined by the field_type attribute. + The specific [`Quantity`][] subclass is determined by the [`.field_type`][.field_type] + attribute. * Deserialization auto-detects the type of deserialization (float or string) based on the input type. * Serialization uses either the schema's default or the per-field configuration found in the metadata. - We need distinct QuantityField subclasses for each Quantity subclass, so - they can be used in the TYPE_MAPPING in the `QuantitySchema`. - Which means this class is not intended to be used directly. + We need distinct `_QuantityField` subclasses for each [`Quantity`][] subclass, so + they can be used in the [`TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] in + [`QuantitySchema`][]. + This class is not intended to be used directly. - Instead, we use the specific QuantityField subclasses for each Quantity. - Each field subclass simply sets the field_type attribute to the corresponding - Quantity subclass. + Instead, we use the specific `_QuantityField` subclasses for each [`Quantity`][]. + Each field subclass simply sets the [`.field_type`][.field_type] + attribute to the corresponding [`Quantity`][] subclass. - Those subclasses are generated and stored in the QUANTITY_FIELD_CLASSES - mapping and are used for the TYPE_MAPPING in the `QuantitySchema`. + Those subclasses are stored in [`QUANTITY_FIELD_CLASSES`][] + and are used for the [`TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] in + [`QuantitySchema`][]. """ field_type: Type[Quantity] | None = None - """The specific Quantity subclass.""" + """The specific [`Quantity`][] subclass.""" def __init__(self, *args: Any, **kwargs: Any) -> None: """Initialize the field.""" @@ -79,7 +80,18 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: def _serialize( self, value: Quantity | None, attr: str | None, obj: Any, **kwargs: Any ) -> Any: - """Serialize the Quantity object based on per-field configuration.""" + """Serialize a [`Quantity`][] value based on per-field configuration. + + Args: + value: The quantity to serialize, or `None`. + attr: The attribute name being serialized. + obj: The object the value was taken from. + **kwargs: Additional keyword arguments passed to the parent field. + + Returns: + The string representation with unit if serializing as string, or + the raw base float value otherwise. `None` if `value` is `None`. + """ if self.field_type is None or not issubclass(self.field_type, Quantity): raise TypeError( "field_type must be set to a Quantity subclass in the subclass." @@ -110,7 +122,21 @@ def _serialize( def _deserialize( self, value: Any, attr: str | None, data: Any, **kwargs: Any ) -> Quantity: - """Deserialize the Quantity object from float or string.""" + """Deserialize a float, int, or string into a [`Quantity`][] instance. + + Args: + value: The raw value to deserialize (float, int, or string). + attr: The attribute name being deserialized. + data: The raw input data (the full object). + **kwargs: Additional keyword arguments passed to the parent field. + + Returns: + The deserialized quantity instance. + + Raises: + [`ValidationError`][marshmallow.ValidationError]: If the input type is + invalid or parsing fails. + """ if self.field_type is None or not issubclass(self.field_type, Quantity): raise TypeError( "field_type must be set to a Quantity subclass in the subclass." @@ -148,55 +174,55 @@ def _deserialize( class ApparentPowerField(_QuantityField): - """Custom field for ApparentPower objects.""" + """A custom field for [`ApparentPower`][] objects.""" field_type = ApparentPower class CurrentField(_QuantityField): - """Custom field for Current objects.""" + """A custom field for [`Current`][] objects.""" field_type = Current class EnergyField(_QuantityField): - """Custom field for Energy objects.""" + """A custom field for [`Energy`][] objects.""" field_type = Energy class FrequencyField(_QuantityField): - """Custom field for Frequency objects.""" + """A custom field for [`Frequency`][] objects.""" field_type = Frequency class PercentageField(_QuantityField): - """Custom field for Percentage objects.""" + """A custom field for [`Percentage`][] objects.""" field_type = Percentage class PowerField(_QuantityField): - """Custom field for Power objects.""" + """A custom field for [`Power`][] objects.""" field_type = Power class ReactivePowerField(_QuantityField): - """Custom field for ReactivePower objects.""" + """A custom field for [`ReactivePower`][] objects.""" field_type = ReactivePower class TemperatureField(_QuantityField): - """Custom field for Temperature objects.""" + """A custom field for [`Temperature`][] objects.""" field_type = Temperature class VoltageField(_QuantityField): - """Custom field for Voltage objects.""" + """A custom field for [`Voltage`][] objects.""" field_type = Voltage @@ -212,20 +238,17 @@ class VoltageField(_QuantityField): Temperature: TemperatureField, Voltage: VoltageField, } -"""Mapping of Quantity subclasses to their corresponding QuantityField subclasses. - -This mapping is used in the `QuantitySchema` to determine the correct field -class for each Quantity subclass. +"""The mapping from [`Quantity`][] subclasses to their corresponding field subclasses. -The keys are Quantity subclasses (e.g., Percentage, Energy) and the values are -the corresponding QuantityField subclasses. +This mapping is used in [`QuantitySchema.TYPE_MAPPING`][.QuantitySchema.TYPE_MAPPING] to +determine the correct field class for each [`Quantity`][] subclass. """ class QuantitySchema(Schema): """A schema for quantities. - Example usage: + Example: ```python from dataclasses import dataclass, field @@ -292,3 +315,4 @@ class Config: """ TYPE_MAPPING: dict[type, type[Field[Any]]] = QUANTITY_FIELD_CLASSES + """The field class to use for each [`Quantity`][] subclass.""" From 389db4145f332f3799e2af62659f881fefce70f4 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:38:04 +0000 Subject: [PATCH 10/12] docs: Fix cross-reference targets to use explicit relative/absolute paths mkdocstrings resolves targets not starting with '.' as absolute paths, and name-based lookup (empty []) is unreliable in module/attribute docstring contexts. Fix all ambiguous references: - __init__.py: use [.ClassName] (relative to module) for all type cross-refs in the module docstring instead of [`Foo`][] - marshmallow.py module docstring: [.QuantitySchema] instead of [] - _QuantityField: use frequenz.quantities.Quantity absolute path for Quantity (external module); use [..QuantitySchema] (two dots = module level from class context) for QuantitySchema; use [..X] for all module-level symbols referenced from a class docstring - QUANTITY_FIELD_CLASSES: use [..QuantitySchema.TYPE_MAPPING] (constant docstring context: one dot = constant itself, two dots = module) - Field subclasses: use frequenz.quantities.X absolute paths for all quantity type cross-references (they live in a different module) Signed-off-by: Leandro Lucarella --- src/frequenz/quantities/__init__.py | 22 +++---- .../quantities/experimental/marshmallow.py | 58 ++++++++++--------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/frequenz/quantities/__init__.py b/src/frequenz/quantities/__init__.py index a03a17d..2a9ad4f 100644 --- a/src/frequenz/quantities/__init__.py +++ b/src/frequenz/quantities/__init__.py @@ -24,17 +24,17 @@ This library provides the following types: -- [`ApparentPower`][]: A quantity representing apparent power. -- [`Current`][]: A quantity representing an electric current. -- [`Energy`][]: A quantity representing energy. -- [`Frequency`][]: A quantity representing frequency. -- [`Percentage`][]: A quantity representing a percentage. -- [`Power`][]: A quantity representing power. -- [`ReactivePower`][]: A quantity representing reactive power. -- [`Temperature`][]: A quantity representing temperature. -- [`Voltage`][]: A quantity representing electric voltage. - -There is also the unitless [`Quantity`][] class. All +- [`ApparentPower`][.ApparentPower]: A quantity representing apparent power. +- [`Current`][.Current]: A quantity representing an electric current. +- [`Energy`][.Energy]: A quantity representing energy. +- [`Frequency`][.Frequency]: A quantity representing frequency. +- [`Percentage`][.Percentage]: A quantity representing a percentage. +- [`Power`][.Power]: A quantity representing power. +- [`ReactivePower`][.ReactivePower]: A quantity representing reactive power. +- [`Temperature`][.Temperature]: A quantity representing temperature. +- [`Voltage`][.Voltage]: A quantity representing electric voltage. + +There is also the unitless [`Quantity`][.Quantity] class. All quantities are subclasses of this class and it can be used as a base to create new quantities. Using the `Quantity` class directly is discouraged, as it doesn't provide any unit conversion methods. diff --git a/src/frequenz/quantities/experimental/marshmallow.py b/src/frequenz/quantities/experimental/marshmallow.py index abf2cef..0d67a56 100644 --- a/src/frequenz/quantities/experimental/marshmallow.py +++ b/src/frequenz/quantities/experimental/marshmallow.py @@ -4,7 +4,7 @@ """Custom marshmallow fields and schema. This module provides custom marshmallow fields for quantities and -a [`QuantitySchema`][] class to +a [`QuantitySchema`][.QuantitySchema] class to be used as base schema for dataclasses containing quantities. Danger: @@ -43,34 +43,36 @@ class _QuantityField(Field[Quantity]): - """A custom field for [`Quantity`][] objects supporting per-field serialization. + """A custom field for [`Quantity`][frequenz.quantities.Quantity] objects supporting per-field serialization. - This class handles serialization and deserialization of ALL [`Quantity`][] - subclasses. - The specific [`Quantity`][] subclass is determined by the [`.field_type`][.field_type] - attribute. + This class handles serialization and deserialization of ALL + [`Quantity`][frequenz.quantities.Quantity] subclasses. + The specific [`Quantity`][frequenz.quantities.Quantity] subclass is determined by the + [`.field_type`][.field_type] attribute. * Deserialization auto-detects the type of deserialization (float or string) based on the input type. * Serialization uses either the schema's default or the per-field configuration found in the metadata. - We need distinct `_QuantityField` subclasses for each [`Quantity`][] subclass, so + We need distinct `_QuantityField` subclasses for each + [`Quantity`][frequenz.quantities.Quantity] subclass, so they can be used in the [`TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] in - [`QuantitySchema`][]. + [`QuantitySchema`][..QuantitySchema]. This class is not intended to be used directly. - Instead, we use the specific `_QuantityField` subclasses for each [`Quantity`][]. + Instead, we use the specific `_QuantityField` subclasses for each + [`Quantity`][frequenz.quantities.Quantity]. Each field subclass simply sets the [`.field_type`][.field_type] - attribute to the corresponding [`Quantity`][] subclass. + attribute to the corresponding [`Quantity`][frequenz.quantities.Quantity] subclass. - Those subclasses are stored in [`QUANTITY_FIELD_CLASSES`][] + Those subclasses are stored in [`QUANTITY_FIELD_CLASSES`][..QUANTITY_FIELD_CLASSES] and are used for the [`TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] in - [`QuantitySchema`][]. + [`QuantitySchema`][..QuantitySchema]. """ field_type: Type[Quantity] | None = None - """The specific [`Quantity`][] subclass.""" + """The specific [`Quantity`][frequenz.quantities.Quantity] subclass.""" def __init__(self, *args: Any, **kwargs: Any) -> None: """Initialize the field.""" @@ -80,7 +82,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: def _serialize( self, value: Quantity | None, attr: str | None, obj: Any, **kwargs: Any ) -> Any: - """Serialize a [`Quantity`][] value based on per-field configuration. + """Serialize a [`Quantity`][frequenz.quantities.Quantity] value based on per-field configuration. Args: value: The quantity to serialize, or `None`. @@ -122,7 +124,7 @@ def _serialize( def _deserialize( self, value: Any, attr: str | None, data: Any, **kwargs: Any ) -> Quantity: - """Deserialize a float, int, or string into a [`Quantity`][] instance. + """Deserialize a float, int, or string into a [`Quantity`][frequenz.quantities.Quantity] instance. Args: value: The raw value to deserialize (float, int, or string). @@ -174,55 +176,55 @@ def _deserialize( class ApparentPowerField(_QuantityField): - """A custom field for [`ApparentPower`][] objects.""" + """A custom field for [`ApparentPower`][frequenz.quantities.ApparentPower] objects.""" field_type = ApparentPower class CurrentField(_QuantityField): - """A custom field for [`Current`][] objects.""" + """A custom field for [`Current`][frequenz.quantities.Current] objects.""" field_type = Current class EnergyField(_QuantityField): - """A custom field for [`Energy`][] objects.""" + """A custom field for [`Energy`][frequenz.quantities.Energy] objects.""" field_type = Energy class FrequencyField(_QuantityField): - """A custom field for [`Frequency`][] objects.""" + """A custom field for [`Frequency`][frequenz.quantities.Frequency] objects.""" field_type = Frequency class PercentageField(_QuantityField): - """A custom field for [`Percentage`][] objects.""" + """A custom field for [`Percentage`][frequenz.quantities.Percentage] objects.""" field_type = Percentage class PowerField(_QuantityField): - """A custom field for [`Power`][] objects.""" + """A custom field for [`Power`][frequenz.quantities.Power] objects.""" field_type = Power class ReactivePowerField(_QuantityField): - """A custom field for [`ReactivePower`][] objects.""" + """A custom field for [`ReactivePower`][frequenz.quantities.ReactivePower] objects.""" field_type = ReactivePower class TemperatureField(_QuantityField): - """A custom field for [`Temperature`][] objects.""" + """A custom field for [`Temperature`][frequenz.quantities.Temperature] objects.""" field_type = Temperature class VoltageField(_QuantityField): - """A custom field for [`Voltage`][] objects.""" + """A custom field for [`Voltage`][frequenz.quantities.Voltage] objects.""" field_type = Voltage @@ -238,10 +240,10 @@ class VoltageField(_QuantityField): Temperature: TemperatureField, Voltage: VoltageField, } -"""The mapping from [`Quantity`][] subclasses to their corresponding field subclasses. +"""The mapping from [`Quantity`][frequenz.quantities.Quantity] subclasses to their corresponding field subclasses. -This mapping is used in [`QuantitySchema.TYPE_MAPPING`][.QuantitySchema.TYPE_MAPPING] to -determine the correct field class for each [`Quantity`][] subclass. +This mapping is used in [`QuantitySchema.TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] to +determine the correct field class for each [`Quantity`][frequenz.quantities.Quantity] subclass. """ @@ -315,4 +317,4 @@ class Config: """ TYPE_MAPPING: dict[type, type[Field[Any]]] = QUANTITY_FIELD_CLASSES - """The field class to use for each [`Quantity`][] subclass.""" + """The field class to use for each [`Quantity`][frequenz.quantities.Quantity] subclass.""" From e96eb87d81345b424a7e521ca0cf9aa7c9e2fd60 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 10:43:19 +0000 Subject: [PATCH 11/12] docs: Fix flake8 violations in experimental/marshmallow.py - Wrap overlong lines (E501) in class summary, _serialize and _deserialize summaries, and QUANTITY_FIELD_CLASSES docstring - _serialize: add missing Raises section for TypeError (DOC501/DOC503) - _deserialize: document both TypeError and ValidationError in Raises; use bare exception name 'ValidationError' for pydoclint compatibility (DOC503 cannot match cross-reference markup in exception names), with a link to marshmallow.ValidationError in the description - QuantitySchema: remove blank line between Example: header and code fence (D412) - _deserialize summary: rewrite as single line ending with period to fix D205 and D400 Signed-off-by: Leandro Lucarella --- .../quantities/experimental/marshmallow.py | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/frequenz/quantities/experimental/marshmallow.py b/src/frequenz/quantities/experimental/marshmallow.py index 0d67a56..8391478 100644 --- a/src/frequenz/quantities/experimental/marshmallow.py +++ b/src/frequenz/quantities/experimental/marshmallow.py @@ -43,7 +43,9 @@ class _QuantityField(Field[Quantity]): - """A custom field for [`Quantity`][frequenz.quantities.Quantity] objects supporting per-field serialization. + """A custom field for [`Quantity`][frequenz.quantities.Quantity] objects. + + Supports per-field serialization configuration. This class handles serialization and deserialization of ALL [`Quantity`][frequenz.quantities.Quantity] subclasses. @@ -82,7 +84,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: def _serialize( self, value: Quantity | None, attr: str | None, obj: Any, **kwargs: Any ) -> Any: - """Serialize a [`Quantity`][frequenz.quantities.Quantity] value based on per-field configuration. + """Serialize a [`Quantity`][frequenz.quantities.Quantity] based on per-field configuration. Args: value: The quantity to serialize, or `None`. @@ -93,6 +95,12 @@ def _serialize( Returns: The string representation with unit if serializing as string, or the raw base float value otherwise. `None` if `value` is `None`. + + Raises: + TypeError: If [`.field_type`][.field_type] is not set to a + [`Quantity`][frequenz.quantities.Quantity] subclass, or if + `value` is not a [`Quantity`][frequenz.quantities.Quantity] + instance. """ if self.field_type is None or not issubclass(self.field_type, Quantity): raise TypeError( @@ -124,7 +132,7 @@ def _serialize( def _deserialize( self, value: Any, attr: str | None, data: Any, **kwargs: Any ) -> Quantity: - """Deserialize a float, int, or string into a [`Quantity`][frequenz.quantities.Quantity] instance. + """Deserialize a [`Quantity`][frequenz.quantities.Quantity] from a float, int, or string. Args: value: The raw value to deserialize (float, int, or string). @@ -136,8 +144,10 @@ def _deserialize( The deserialized quantity instance. Raises: - [`ValidationError`][marshmallow.ValidationError]: If the input type is - invalid or parsing fails. + TypeError: If [`.field_type`][.field_type] is not set to a + [`Quantity`][frequenz.quantities.Quantity] subclass. + ValidationError: If the input type is invalid or parsing fails + (see [`marshmallow.ValidationError`][marshmallow.ValidationError]). """ if self.field_type is None or not issubclass(self.field_type, Quantity): raise TypeError( @@ -240,10 +250,12 @@ class VoltageField(_QuantityField): Temperature: TemperatureField, Voltage: VoltageField, } -"""The mapping from [`Quantity`][frequenz.quantities.Quantity] subclasses to their corresponding field subclasses. +"""The mapping from [`Quantity`][frequenz.quantities.Quantity] subclasses to +their corresponding field subclasses. This mapping is used in [`QuantitySchema.TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] to -determine the correct field class for each [`Quantity`][frequenz.quantities.Quantity] subclass. +determine the correct field class for each [`Quantity`][frequenz.quantities.Quantity] +subclass. """ @@ -251,7 +263,6 @@ class QuantitySchema(Schema): """A schema for quantities. Example: - ```python from dataclasses import dataclass, field from marshmallow_dataclass import class_schema From 48dbe31c5054c0d18a0c00d17165999d3348394f Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 30 Jun 2026 11:15:32 +0000 Subject: [PATCH 12/12] docs: Replace absolute cross-refs with relative ones in marshmallow.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All cross-references to frequenz.quantities.* symbols were written as absolute paths. Replace them with dot-notation relative references: - Depth-1 objects (classes, module-level constants): use ....X (3 levels up from class/constant → frequenz.quantities.X) - Depth-2 objects (methods, class attributes): use .....X (4 levels up) - In _serialize/_deserialize method docstrings: [.field_type] was wrong (resolved to the method's own field_type, which doesn't exist); fixed to [..field_type] (1 level up → _QuantityField.field_type) Signed-off-by: Leandro Lucarella --- .../quantities/experimental/marshmallow.py | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/frequenz/quantities/experimental/marshmallow.py b/src/frequenz/quantities/experimental/marshmallow.py index 8391478..9e4bf21 100644 --- a/src/frequenz/quantities/experimental/marshmallow.py +++ b/src/frequenz/quantities/experimental/marshmallow.py @@ -43,13 +43,13 @@ class _QuantityField(Field[Quantity]): - """A custom field for [`Quantity`][frequenz.quantities.Quantity] objects. + """A custom field for [`Quantity`][....Quantity] objects. Supports per-field serialization configuration. This class handles serialization and deserialization of ALL - [`Quantity`][frequenz.quantities.Quantity] subclasses. - The specific [`Quantity`][frequenz.quantities.Quantity] subclass is determined by the + [`Quantity`][....Quantity] subclasses. + The specific [`Quantity`][....Quantity] subclass is determined by the [`.field_type`][.field_type] attribute. * Deserialization auto-detects the type of deserialization (float or string) @@ -58,15 +58,15 @@ class _QuantityField(Field[Quantity]): configuration found in the metadata. We need distinct `_QuantityField` subclasses for each - [`Quantity`][frequenz.quantities.Quantity] subclass, so + [`Quantity`][....Quantity] subclass, so they can be used in the [`TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] in [`QuantitySchema`][..QuantitySchema]. This class is not intended to be used directly. Instead, we use the specific `_QuantityField` subclasses for each - [`Quantity`][frequenz.quantities.Quantity]. + [`Quantity`][....Quantity]. Each field subclass simply sets the [`.field_type`][.field_type] - attribute to the corresponding [`Quantity`][frequenz.quantities.Quantity] subclass. + attribute to the corresponding [`Quantity`][....Quantity] subclass. Those subclasses are stored in [`QUANTITY_FIELD_CLASSES`][..QUANTITY_FIELD_CLASSES] and are used for the [`TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] in @@ -74,7 +74,7 @@ class _QuantityField(Field[Quantity]): """ field_type: Type[Quantity] | None = None - """The specific [`Quantity`][frequenz.quantities.Quantity] subclass.""" + """The specific [`Quantity`][.....Quantity] subclass.""" def __init__(self, *args: Any, **kwargs: Any) -> None: """Initialize the field.""" @@ -84,7 +84,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: def _serialize( self, value: Quantity | None, attr: str | None, obj: Any, **kwargs: Any ) -> Any: - """Serialize a [`Quantity`][frequenz.quantities.Quantity] based on per-field configuration. + """Serialize a [`Quantity`][.....Quantity] based on per-field configuration. Args: value: The quantity to serialize, or `None`. @@ -97,9 +97,9 @@ def _serialize( the raw base float value otherwise. `None` if `value` is `None`. Raises: - TypeError: If [`.field_type`][.field_type] is not set to a - [`Quantity`][frequenz.quantities.Quantity] subclass, or if - `value` is not a [`Quantity`][frequenz.quantities.Quantity] + TypeError: If [`..field_type`][..field_type] is not set to a + [`Quantity`][.....Quantity] subclass, or if + `value` is not a [`Quantity`][.....Quantity] instance. """ if self.field_type is None or not issubclass(self.field_type, Quantity): @@ -132,7 +132,7 @@ def _serialize( def _deserialize( self, value: Any, attr: str | None, data: Any, **kwargs: Any ) -> Quantity: - """Deserialize a [`Quantity`][frequenz.quantities.Quantity] from a float, int, or string. + """Deserialize a [`Quantity`][.....Quantity] from a float, int, or string. Args: value: The raw value to deserialize (float, int, or string). @@ -144,8 +144,8 @@ def _deserialize( The deserialized quantity instance. Raises: - TypeError: If [`.field_type`][.field_type] is not set to a - [`Quantity`][frequenz.quantities.Quantity] subclass. + TypeError: If [`..field_type`][..field_type] is not set to a + [`Quantity`][.....Quantity] subclass. ValidationError: If the input type is invalid or parsing fails (see [`marshmallow.ValidationError`][marshmallow.ValidationError]). """ @@ -186,55 +186,55 @@ def _deserialize( class ApparentPowerField(_QuantityField): - """A custom field for [`ApparentPower`][frequenz.quantities.ApparentPower] objects.""" + """A custom field for [`ApparentPower`][....ApparentPower] objects.""" field_type = ApparentPower class CurrentField(_QuantityField): - """A custom field for [`Current`][frequenz.quantities.Current] objects.""" + """A custom field for [`Current`][....Current] objects.""" field_type = Current class EnergyField(_QuantityField): - """A custom field for [`Energy`][frequenz.quantities.Energy] objects.""" + """A custom field for [`Energy`][....Energy] objects.""" field_type = Energy class FrequencyField(_QuantityField): - """A custom field for [`Frequency`][frequenz.quantities.Frequency] objects.""" + """A custom field for [`Frequency`][....Frequency] objects.""" field_type = Frequency class PercentageField(_QuantityField): - """A custom field for [`Percentage`][frequenz.quantities.Percentage] objects.""" + """A custom field for [`Percentage`][....Percentage] objects.""" field_type = Percentage class PowerField(_QuantityField): - """A custom field for [`Power`][frequenz.quantities.Power] objects.""" + """A custom field for [`Power`][....Power] objects.""" field_type = Power class ReactivePowerField(_QuantityField): - """A custom field for [`ReactivePower`][frequenz.quantities.ReactivePower] objects.""" + """A custom field for [`ReactivePower`][....ReactivePower] objects.""" field_type = ReactivePower class TemperatureField(_QuantityField): - """A custom field for [`Temperature`][frequenz.quantities.Temperature] objects.""" + """A custom field for [`Temperature`][....Temperature] objects.""" field_type = Temperature class VoltageField(_QuantityField): - """A custom field for [`Voltage`][frequenz.quantities.Voltage] objects.""" + """A custom field for [`Voltage`][....Voltage] objects.""" field_type = Voltage @@ -250,11 +250,10 @@ class VoltageField(_QuantityField): Temperature: TemperatureField, Voltage: VoltageField, } -"""The mapping from [`Quantity`][frequenz.quantities.Quantity] subclasses to -their corresponding field subclasses. +"""The mapping from [`Quantity`][....Quantity] subclasses to their corresponding field subclasses. This mapping is used in [`QuantitySchema.TYPE_MAPPING`][..QuantitySchema.TYPE_MAPPING] to -determine the correct field class for each [`Quantity`][frequenz.quantities.Quantity] +determine the correct field class for each [`Quantity`][....Quantity] subclass. """ @@ -328,4 +327,4 @@ class Config: """ TYPE_MAPPING: dict[type, type[Field[Any]]] = QUANTITY_FIELD_CLASSES - """The field class to use for each [`Quantity`][frequenz.quantities.Quantity] subclass.""" + """The field class to use for each [`Quantity`][.....Quantity] subclass."""