NREL / infrasys

Data store for components and time series in support of Python-based modeling packages
https://nrel.github.io/infrasys/
BSD 3-Clause "New" or "Revised" License
5 stars 2 forks source link

feat: Added `PydanticPintQuantity` as an option to enforce unit validation for fields #56

Open pesap opened 1 week ago

pesap commented 1 week ago

This was the original idea we intended before introducing BaseQuantity. It is more simple, but in the same spirt that we add an annotation as to enforce the unit as follow:

from typing import Annotated
from pint import Quantity
from infrasys.component import Component
from infrasys.pint_quantities import PydanticPintQuantity

class ACBus(Component):
    voltage: Annotated[Quantity, PydanticPintQuantity("volts")]

I do not plan to retire the BaseQuantity from infrasys, but this could be a simplier solution for people that do not want to create a class that enforces unit validation.

Someone already released this as a package here: https://github.com/tylerh111/pydantic-pint. We do not need the full implementation or dependency since we already had something similar.

codecov-commenter commented 1 week ago

Codecov Report

Attention: Patch coverage is 97.11538% with 3 lines in your changes missing coverage. Please review.

Project coverage is 95.36%. Comparing base (f3703dd) to head (9e99ddb). Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/infrasys/pint_quantities.py 92.85% 3 Missing :warning:
Additional details and impacted files ```diff @@ Coverage Diff @@ ## main #56 +/- ## ========================================== + Coverage 95.04% 95.36% +0.31% ========================================== Files 33 35 +2 Lines 2807 2870 +63 ========================================== + Hits 2668 2737 +69 + Misses 139 133 -6 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.


🚨 Try these New Features:

KapilDuwadi commented 6 days ago

@pesap I like the general idea. Is there a way to make it easier to ensure value must be positive, nonnegative, nonpositive etc. ?

Currently we are defining positive resistance class like below. I was wondering how would we migrate this to your new implementation.

class PositiveResistance(Resistance):
    """Quantity representing power system resistance."""

    def __init__(self, value, units, **kwargs):
        assert value >= 0, f"Resistance ({value}, {units}) must be positive."
pesap commented 6 days ago

@pesap I like the general idea. Is there a way to make it easier to ensure value must be positive, nonnegative, nonpositive etc. ?

Currently we are defining positive resistance class like below. I was wondering how would we migrate this to your new implementation.

class PositiveResistance(Resistance):
    """Quantity representing power system resistance."""

    def __init__(self, value, units, **kwargs):
        assert value >= 0, f"Resistance ({value}, {units}) must be positive."

Yes, @KapilDuwadi . You can compose constraints. Using your example it would look like this,

from typing import Annotated
from pint import Quantity
from pydantic import Field
from infrasys.component import Component
from infrasys.pint_quantities import PydanticPintQuantity

class ACBus(Component):
    resistance: Annotated[Quantity, PydanticPintQuantity("ohms"), Field(gt=0)]
KapilDuwadi commented 5 days ago

@pesap I like the general idea. Is there a way to make it easier to ensure value must be positive, nonnegative, nonpositive etc. ? Currently we are defining positive resistance class like below. I was wondering how would we migrate this to your new implementation.

class PositiveResistance(Resistance):
    """Quantity representing power system resistance."""

    def __init__(self, value, units, **kwargs):
        assert value >= 0, f"Resistance ({value}, {units}) must be positive."

Yes, @KapilDuwadi . You can compose constraints. Using your example it would look like this,

from typing import Annotated
from pint import Quantity
from pydantic import Field
from infrasys.component import Component
from infrasys.pint_quantities import PydanticPintQuantity

class ACBus(Component):
    resistance: Annotated[Quantity, PydanticPintQuantity("ohms"), Field(gt=0)]

Cool makes sense.