Migrate from attrs dataclasses to Pydantic

Open
#906 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Feature
Clarity
Needs clarification
Activity status
Active
Tech stack
python
Domain
backend

Research direction

The issue proposes migrating dataclasses from attrs to Pydantic but leaves the implementation scope open for discussion and does not name files or tests. Start by locating the existing attrs-based dataclasses and reviewing how they are used; compare their validation needs with Pydantic v2 and the suggested Pydantic Pint integration. Done would require an agreed migration scope and validation that the affected models and tests still work.

Written by the indexing model from the issue text.

Description

enhancement for 1.0 infrastructure

Migrate dataclasses from attrs to Pydantic

One of the core reasons we use attrs under the hood was early versions of Pydantic simply couldn't compete with attrs in providing useful data validation routines. However, with v2 it seems Pydantic does all that and more, on top of potentially being more performant and providing built-in JSON schema support.

Additionally, there is a new Pydantic plug in (Pydantic Pint) that provides support for units out of the box to handle some of our input data a little more efficiently before it gets to OpenMDAO.

Proposed solution

Pydantic has a lot of cool functionality that could aid/replace some of the functionality we currently have, but at present this is more for a longer discussion than implementation details.

Quick look at Pydantic with Pint
from pydantic import BaseModel
from pydantic_pint import PydanticPintQuantity
from pint import Quantity
from typing import Annotated

class Box(BaseModel):
    # NOTE: strict controls if units are required in the input
    length: Annotated[Quantity, PydanticPintQuantity("m", strict=False)]
    width: Annotated[Quantity, PydanticPintQuantity("m", strict=False)]

>>> box1 = Box(length="4m", width="2m")
>>> box2 = Box(length=4, width=2)
>>> box1 == box2
True

>>> box1
Box(length=Quantity(4, "meter"), width=Quantity(2, "meter"))

Alternatives considered

Stick with attrs! I started the train with WOMBAT and FLORIS v3, so many of us at NWTC know it quite well. It's now incorporated into numerous NWTC software, so there's a lot of intertia behind sticking with attrs. That all said, libraries evolve and some don't evolve as much, so there is good reason to at least get curious--it's how we got attrs into so many models!.

Additional context

Pydantic docs: https://pydantic.dev/docs/validation/latest/get-started/why/
Pydantic Pint docs: https://pydantic-pint.readthedocs.io/en/stable/

Update

A direct comparison of units will be a bit time consuming, though a quick glance on some of the major pieces seems to suggest their definitions are the same. The docs pages for both OpenMDAO and Pint unts are below:
OpenMDAO units: https://openmdao.org/newdocs/versions/latest/features/units.html
Pint units: https://pint.readthedocs.io/en/stable/default-units.html

Dominant language
Python
Stars
30
Forks
44
Avg merge
3d 12h
Merged PRs (30d)
28

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from NatLabRockies/H2Integrate

All issues in NatLabRockies/H2Integrate

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.