Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Pydantic 2 #440

Merged
merged 15 commits into from
Sep 28, 2023
16 changes: 9 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@ classifiers = [
requires-python = ">=3.8"
dependencies = [
"PyYAML",
"maggma>=0.38.1",
"monty>=2021.5.9",
"maggma>=0.57.0",
"monty>=2023.9.25",
"networkx",
"pydantic<2",
"pydantic>=2.0.1",
"pydantic-settings>=2.0.3",
"pydash",
]

[project.optional-dependencies]
docs = [
"autodoc_pydantic==1.9.0",
"autodoc_pydantic==2.0.1",
"furo==2023.9.10",
"ipython==8.15.0",
"myst_parser==2.0.0",
Expand All @@ -52,12 +53,13 @@ fireworks = ["FireWorks"]
strict = [
"FireWorks==2.0.3",
"PyYAML==6.0.1",
"maggma==0.56.0",
"maggma==0.57.0",
"matplotlib==3.7.2",
"monty==2023.9.25",
"moto==4.2.4",
"networkx==3.1",
"pydantic==1.10.9",
"pydantic==2.4.1",
"pydantic-settings==2.0.3",
"pydash==7.0.6",
"pydot==1.4.2",
"typing-extensions==4.8.0",
Expand Down Expand Up @@ -142,4 +144,4 @@ isort.known-first-party = ["jobflow"]

[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"]
"**/tests/*" = ["D"]
"**/tests/*" = ["D", "B018"]
4 changes: 2 additions & 2 deletions src/jobflow/core/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from monty.json import MontyDecoder, MontyEncoder, MSONable, jsanitize
from pydantic import BaseModel
from pydantic.utils import lenient_issubclass
from pydantic.v1.utils import lenient_issubclass

from jobflow.utils.enum import ValueEnum

Expand Down Expand Up @@ -503,7 +503,7 @@ def validate_schema_access(
raise AttributeError(f"{schema.__name__} does not have attribute '{item}'.")

subschema = None
item_type = schema.__fields__[item].outer_type_
item_type = schema.model_fields[item].annotation
if lenient_issubclass(item_type, BaseModel):
subschema = item_type

Expand Down
12 changes: 5 additions & 7 deletions src/jobflow/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from pathlib import Path

from maggma.stores import MemoryStore
from pydantic import BaseSettings, Field, root_validator
from pydantic import Field, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

from jobflow import JobStore

Expand Down Expand Up @@ -118,13 +119,10 @@ class JobflowSettings(BaseSettings):
"%Y-%m-%d-%H-%M-%S-%f",
description="Date stamp format used to create directories",
)
model_config = SettingsConfigDict(env_prefix="jobflow_")

class Config:
"""Pydantic config settings."""

env_prefix = "jobflow_"

@root_validator(pre=True)
@model_validator(mode="before")
@classmethod
def load_default_settings(cls, values):
"""
Load settings from file or environment variables.
Expand Down
16 changes: 8 additions & 8 deletions tests/core/test_reference.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Optional, Union
from typing import Dict, List, Union

import pytest

Expand Down Expand Up @@ -161,7 +161,7 @@ class InnerSchema(BaseModel):
class MediumSchema(BaseModel):
s: str
nested: InnerSchema
nested_opt: Optional[InnerSchema]
nested_opt: InnerSchema = None
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I had to change this in the test suite. For some reason, leaving it as Optional[InnerSchema] caused ref.nested.nested_opt.m.uuid not to be raised. Must be a change in how Pydantic 2 handles optional-annotated fields.

nested_u: Union[InnerSchema, dict]
nested_l: List[InnerSchema]
nested_d: Dict[str, InnerSchema]
Expand All @@ -184,25 +184,25 @@ class MySchema(BaseModel):
assert new_ref.output_schema is None

with pytest.raises(AttributeError):
assert ref.a.uuid == "123"
ref.a.uuid

with pytest.raises(AttributeError):
assert ref["a"].uuid == "123"
ref["a"].uuid

with pytest.raises(AttributeError):
assert ref[1].uuid == "123"
ref[1].uuid

# check valid nested schemas
assert ref.nested.s.uuid == "123"
with pytest.raises(AttributeError):
assert ref.nested.m.uuid == "123"
ref.nested.m.uuid
assert ref.nested.nested.n.uuid == "123"
with pytest.raises(AttributeError):
assert ref.nested.nested.m.uuid == "123"
ref.nested.nested.m.uuid

assert ref.nested.nested_opt.n.uuid == "123"
with pytest.raises(AttributeError):
assert ref.nested.nested_opt.m.uuid == "123"
ref.nested.nested_opt.m.uuid

# Union, List and Dict are currently not recognized by their inner type
# but check that there is no problem with them
Expand Down
Loading