Skip to content

Commit c359496

Browse files
authored
feat!: compatibility with pydantic v2 (#148)
Pydantic v1 is EOL, but some users of this library still use it. Pydantic v2 contains the pydantic v1 in the pydantic.v1 namespace, and pydantic v1.10.17+ also contains this same namespace. So, step one to migrating to Pydantic v2 is to use the pydantic.v1 namespace throughout. Then, in future, the models can be updated to true Pydantic v2 when all consumers are ready for it. I'm marking this as a breaking change since the pydantic library update is not backwards compatible. Signed-off-by: Daniel Neilson <53624638+ddneilson@users.noreply.github.com>
1 parent 7d49e04 commit c359496

27 files changed

+53
-53
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ classifiers = [
3030
]
3131
dependencies = [
3232
"pyyaml == 6.0.*",
33-
"pydantic ~= 1.10",
33+
"pydantic >= 1.10.17",
3434
]
3535

3636
[project.urls]
@@ -99,7 +99,7 @@ mypy_path = "src"
9999

100100
# See: https://docs.pydantic.dev/mypy_plugin/
101101
# - Helps mypy understand pydantic typing.
102-
plugins = "pydantic.mypy"
102+
plugins = "pydantic.v1.mypy"
103103

104104
[tool.ruff]
105105
line-length = 100

src/openjd/model/_convert_pydantic_error.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22

33
from typing import TypedDict, Union, Type
4-
from pydantic import BaseModel
4+
from pydantic.v1 import BaseModel
55
from inspect import getmodule
66

77
# Calling pydantic's ValidationError.errors() returns a list[ErrorDict], but

src/openjd/model/_create_job.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pathlib import Path
55
from typing import Optional, cast
66

7-
from pydantic import ValidationError
7+
from pydantic.v1 import ValidationError
88

99
from ._errors import CompatibilityError, DecodeValidationError
1010
from ._symbol_table import SymbolTable

src/openjd/model/_format_strings/_dyn_constrained_str.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
import re
44
from typing import TYPE_CHECKING, Any, Callable, Optional, Pattern, Union
55

6-
from pydantic.errors import AnyStrMaxLengthError, AnyStrMinLengthError, StrRegexError
7-
from pydantic.utils import update_not_none
8-
from pydantic.validators import strict_str_validator
6+
from pydantic.v1.errors import AnyStrMaxLengthError, AnyStrMinLengthError, StrRegexError
7+
from pydantic.v1.utils import update_not_none
8+
from pydantic.v1.validators import strict_str_validator
99

1010
if TYPE_CHECKING:
11-
from pydantic.typing import CallableGenerator
11+
from pydantic.v1.typing import CallableGenerator
1212

1313

1414
class DynamicConstrainedStr(str):

src/openjd/model/_format_strings/_format_string.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from ._expression import InterpolationExpression
1111

1212
if TYPE_CHECKING:
13-
from pydantic.typing import CallableGenerator
13+
from pydantic.v1.typing import CallableGenerator
1414

1515

1616
@dataclass

src/openjd/model/_internal/_create_job.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from typing import Any, Union
44

5-
from pydantic import ValidationError
6-
from pydantic.error_wrappers import ErrorWrapper
5+
from pydantic.v1 import ValidationError
6+
from pydantic.v1.error_wrappers import ErrorWrapper
77

88
from .._symbol_table import SymbolTable
99
from .._format_strings import FormatString, FormatStringError

src/openjd/model/_internal/_variable_reference_validation.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
from typing import Any, Optional, Type
55
from inspect import isclass
66

7-
from pydantic.error_wrappers import ErrorWrapper
8-
import pydantic.fields
9-
from pydantic.typing import is_literal_type
7+
from pydantic.v1.error_wrappers import ErrorWrapper
8+
import pydantic.v1.fields
9+
from pydantic.v1.typing import is_literal_type
1010

1111
from .._types import OpenJDModel, ResolutionScope
1212
from .._format_strings import FormatString, FormatStringError
@@ -104,7 +104,7 @@
104104
# 4. Since this validation is a pre-validator, we basically have to re-implement a fragment of Pydantic's model parser for this
105105
# depth first traversal. Thus, you'll need to know the following about Pydantic v1.x's data model and parser to understand this
106106
# implementation:
107-
# a) All models are derived from pydantic.BaseModel
107+
# a) All models are derived from pydantic.v1.BaseModel
108108
# b) pydantic.BaseModel.__fields__: dict[str, pydantic.ModelField] is injected into all BaseModels by pydantic's BaseModel metaclass.
109109
# This member is what gives pydantic information about each of the fields defined in the model class. The key of the dict is the
110110
# name of the field in the model.
@@ -228,7 +228,7 @@ def _validate_model_template_variable_references(
228228
value_symbols = _collect_variable_definitions(cls, values, current_scope, symbol_prefix)
229229

230230
# Recursively validate the contents of FormatStrings within the model.
231-
# Note: cls.__fields__: dict[str, pydantic.fields.ModelField]
231+
# Note: cls.__fields__: dict[str, pydantic.v1.fields.ModelField]
232232
for field_name, field_model in cls.__fields__.items():
233233
field_value = values.get(field_name, None)
234234
if field_value is None:
@@ -248,7 +248,7 @@ def _validate_model_template_variable_references(
248248
# Add in all of the symbols passed down from the parent.
249249
validation_symbols.update_self(symbols)
250250

251-
if field_model.shape == pydantic.fields.SHAPE_SINGLETON:
251+
if field_model.shape == pydantic.v1.fields.SHAPE_SINGLETON:
252252
_validate_singleton(
253253
errors,
254254
field_model,
@@ -258,7 +258,7 @@ def _validate_model_template_variable_references(
258258
validation_symbols,
259259
(*loc, field_name),
260260
)
261-
elif field_model.shape == pydantic.fields.SHAPE_LIST:
261+
elif field_model.shape == pydantic.v1.fields.SHAPE_LIST:
262262
if not isinstance(field_value, list):
263263
continue
264264
assert field_model.sub_fields is not None # For the type checker
@@ -273,7 +273,7 @@ def _validate_model_template_variable_references(
273273
validation_symbols,
274274
(*loc, field_name, i),
275275
)
276-
elif field_model.shape == pydantic.fields.SHAPE_DICT:
276+
elif field_model.shape == pydantic.v1.fields.SHAPE_DICT:
277277
if not isinstance(field_value, dict):
278278
continue
279279
assert field_model.sub_fields is not None # For the type checker
@@ -300,7 +300,7 @@ def _validate_model_template_variable_references(
300300

301301
def _validate_singleton(
302302
errors: list[ErrorWrapper],
303-
field_model: pydantic.fields.ModelField,
303+
field_model: pydantic.v1.fields.ModelField,
304304
field_value: Any,
305305
current_scope: ResolutionScope,
306306
symbol_prefix: str,
@@ -356,7 +356,7 @@ def _validate_singleton(
356356

357357
def _validate_general_union(
358358
errors: list[ErrorWrapper],
359-
field_model: pydantic.fields.ModelField,
359+
field_model: pydantic.v1.fields.ModelField,
360360
field_value: Any,
361361
current_scope: ResolutionScope,
362362
symbol_prefix: str,
@@ -375,11 +375,11 @@ def _validate_general_union(
375375
# and attempt to process the value as that type.
376376
assert field_model.sub_fields is not None # For the type checker
377377
for sub_field in field_model.sub_fields:
378-
if sub_field.shape == pydantic.fields.SHAPE_SINGLETON:
378+
if sub_field.shape == pydantic.v1.fields.SHAPE_SINGLETON:
379379
_validate_singleton(
380380
errors, sub_field, field_value, current_scope, symbol_prefix, symbols, loc
381381
)
382-
elif sub_field.shape == pydantic.fields.SHAPE_LIST:
382+
elif sub_field.shape == pydantic.v1.fields.SHAPE_LIST:
383383
if not isinstance(field_value, list):
384384
# The given value must be a list in this case.
385385
continue
@@ -414,8 +414,8 @@ def _check_format_string(
414414

415415

416416
def _get_model_for_singleton_value(
417-
field_model: pydantic.fields.ModelField, value: Any
418-
) -> Optional[pydantic.fields.ModelField]:
417+
field_model: pydantic.v1.fields.ModelField, value: Any
418+
) -> Optional[pydantic.v1.fields.ModelField]:
419419
"""Given a ModelField and the value that we're given for that field, determine
420420
the actual ModelField for the value in the event that the ModelField may be for
421421
a discriminated union."""
@@ -509,7 +509,7 @@ def _collect_variable_definitions( # noqa: C901 (suppress: too complex)
509509
symbol_name = f"{symbol_prefix}{symbol}"
510510
_add_symbol(symbols["__self__"], current_scope, symbol_name)
511511

512-
# Note: cls.__fields__: dict[str, pydantic.fields.ModelField]
512+
# Note: cls.__fields__: dict[str, pydantic.v1.fields.ModelField]
513513
for field_name, field_model in cls.__fields__.items():
514514
field_value = values.get(field_name, None)
515515
if field_value is None:
@@ -519,11 +519,11 @@ def _collect_variable_definitions( # noqa: C901 (suppress: too complex)
519519
# Literals cannot define variables, so skip this field.
520520
continue
521521

522-
if field_model.shape == pydantic.fields.SHAPE_SINGLETON:
522+
if field_model.shape == pydantic.v1.fields.SHAPE_SINGLETON:
523523
result = _collect_singleton(field_model, field_value, current_scope, symbol_prefix)
524524
if result:
525525
symbols[field_name] = result
526-
elif field_model.shape == pydantic.fields.SHAPE_LIST:
526+
elif field_model.shape == pydantic.v1.fields.SHAPE_LIST:
527527
# If the shape expects a list, but the value isn't one then we have a validation error.
528528
# The error will get flagged by subsequent passes of the model validation.
529529
if not isinstance(field_value, list):
@@ -535,7 +535,7 @@ def _collect_variable_definitions( # noqa: C901 (suppress: too complex)
535535
result = _collect_singleton(item_model, item, current_scope, symbol_prefix)
536536
if result:
537537
symbols[field_name].update_self(result)
538-
elif field_model.shape == pydantic.fields.SHAPE_DICT:
538+
elif field_model.shape == pydantic.v1.fields.SHAPE_DICT:
539539
# dict[] fields can't define symbols.
540540
continue
541541
else:
@@ -566,7 +566,7 @@ def _add_symbol(into: ScopedSymtabs, scope: ResolutionScope, symbol_name: str) -
566566

567567

568568
def _collect_singleton(
569-
model: pydantic.fields.ModelField,
569+
model: pydantic.v1.fields.ModelField,
570570
value: Any,
571571
current_scope: ResolutionScope,
572572
symbol_prefix: str,

src/openjd/model/_parse.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
from typing import Any, ClassVar, Optional, Type, TypeVar, Union, cast
88

99
import yaml
10-
from pydantic import BaseModel
11-
from pydantic import ValidationError as PydanticValidationError
12-
from pydantic.error_wrappers import ErrorWrapper
10+
from pydantic.v1 import BaseModel
11+
from pydantic.v1 import ValidationError as PydanticValidationError
12+
from pydantic.v1.error_wrappers import ErrorWrapper
1313

1414
from ._errors import DecodeValidationError
1515
from ._types import EnvironmentTemplate, JobTemplate, OpenJDModel, TemplateSpecificationVersion

src/openjd/model/_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from enum import Enum
99
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Optional, Type, Union
1010

11-
from pydantic import BaseModel, Extra
11+
from pydantic.v1 import BaseModel, Extra
1212

1313
from ._symbol_table import SymbolTable
1414

src/openjd/model/v2023_09/_model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from typing import TYPE_CHECKING, Any, ClassVar, Literal, Optional, Type, Union, cast
1010
from typing_extensions import Annotated
1111

12-
from pydantic import (
12+
from pydantic.v1 import (
1313
Field,
1414
PositiveInt,
1515
PositiveFloat,
@@ -22,7 +22,7 @@
2222
root_validator,
2323
validator,
2424
)
25-
from pydantic.error_wrappers import ErrorWrapper
25+
from pydantic.v1.error_wrappers import ErrorWrapper
2626

2727
from .._format_strings import FormatString
2828
from .._errors import ExpressionError, TokenError

0 commit comments

Comments
 (0)