Skip to content

Commit f33cb8a

Browse files
authored
Merge pull request #200 from BrianPugh/pydantic-v2
Migrate to Pydantic v2
2 parents 1673a02 + 76606e9 commit f33cb8a

9 files changed

Lines changed: 174 additions & 78 deletions

File tree

belay/cli/select.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def validate_led_pin_number(response):
151151

152152
asyncio.run(blink_until_prompt(device))
153153

154-
spec_json = spec.json(exclude_none=True)
154+
spec_json = spec.model_dump_json(exclude_none=True)
155155
questionary.print("\n")
156156
questionary.print("Either set the BELAY_DEVICE environment variable:", style=style)
157157
questionary.print(f" export BELAY_DEVICE='{spec_json}'")

belay/packagemanager/models.py

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,15 @@
11
"""Pydantic models for validation Belay configuration.
22
"""
33

4-
from functools import partial
54
from pathlib import Path
65
from typing import Dict, List, Optional
76

8-
try:
9-
from pydantic.v1 import BaseModel as PydanticBaseModel
10-
from pydantic.v1 import validator
11-
except ImportError:
12-
from pydantic import BaseModel as PydanticBaseModel
13-
from pydantic import validator
14-
15-
validator_reuse = partial(validator, allow_reuse=True)
16-
prevalidator_reuse = partial(validator_reuse, pre=True)
7+
from pydantic import BaseModel as PydanticBaseModel
8+
from pydantic import ConfigDict, field_validator
179

1810

1911
class BaseModel(PydanticBaseModel):
20-
class Config:
21-
allow_mutation = False
12+
model_config = ConfigDict(frozen=True)
2213

2314

2415
class DependencySourceConfig(BaseModel):
@@ -106,11 +97,19 @@ class GroupConfig(BaseModel):
10697
##############
10798
# VALIDATORS #
10899
##############
109-
_v_dependencies_preprocessor = prevalidator_reuse("dependencies")(_dependencies_preprocessor)
110-
_v_dependencies_names = validator_reuse("dependencies")(_dependencies_name_validator)
111-
112-
@validator("dependencies")
113-
def max_1_rename_to_init(packages: dict):
100+
@field_validator("dependencies", mode="before")
101+
@classmethod
102+
def _v_dependencies_preprocessor(cls, v):
103+
return _dependencies_preprocessor(v)
104+
105+
@field_validator("dependencies")
106+
@classmethod
107+
def _v_dependencies_names(cls, v):
108+
return _dependencies_name_validator(v)
109+
110+
@field_validator("dependencies")
111+
@classmethod
112+
def max_1_rename_to_init(cls, packages: dict):
114113
rename_to_init_count = {}
115114
for package_name, dependency in walk_dependencies(packages):
116115
rename_to_init_count.setdefault(package_name, 0)
@@ -141,10 +140,18 @@ class BelayConfig(BaseModel):
141140
##############
142141
# VALIDATORS #
143142
##############
144-
_v_dependencies_preprocessor = prevalidator_reuse("dependencies")(_dependencies_preprocessor)
145-
_v_dependencies_names = validator_reuse("dependencies")(_dependencies_name_validator)
146-
147-
@validator("group")
143+
@field_validator("dependencies", mode="before")
144+
@classmethod
145+
def _v_dependencies_preprocessor(cls, v):
146+
return _dependencies_preprocessor(v)
147+
148+
@field_validator("dependencies")
149+
@classmethod
150+
def _v_dependencies_names(cls, v):
151+
return _dependencies_name_validator(v)
152+
153+
@field_validator("group")
154+
@classmethod
148155
def main_not_in_group(cls, v):
149156
if "main" in v:
150157
raise ValueError(

belay/project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,6 @@ def load_pyproject() -> BelayConfig:
8383
def load_groups() -> List[Group]:
8484
config = load_pyproject()
8585
groups = [Group("main", dependencies=config.dependencies)]
86-
groups.extend(Group(name, **definition.dict()) for name, definition in config.group.items())
86+
groups.extend(Group(name, **definition.model_dump()) for name, definition in config.group.items())
8787
groups.sort(key=lambda x: x.name)
8888
return groups

belay/pyboard.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,13 @@
6666
from threading import Lock, Thread
6767
from typing import Union
6868

69+
from pydantic import ValidationError
70+
6971
from .exceptions import BelayException, ConnectionFailedError, DeviceNotFoundError
7072
from .usb_specifier import UsbSpecifier
7173
from .utils import env_parse_bool
7274
from .webrepl import WebreplToSerial
7375

74-
try:
75-
from pydantic.v1.error_wrappers import ValidationError
76-
except ImportError:
77-
from pydantic import ValidationError
78-
79-
8076
try:
8177
stdout = sys.stdout.buffer
8278
except AttributeError:
@@ -349,15 +345,15 @@ def __init__(
349345

350346
if device is None:
351347
usb_specifier_str = os.environ.get("BELAY_DEVICE", "{}")
352-
device = UsbSpecifier.parse_raw(usb_specifier_str)
348+
device = UsbSpecifier.model_validate_json(usb_specifier_str)
353349

354350
for attempt_count in itertools.count(start=attempt_start_val):
355351
try:
356352
if isinstance(device, UsbSpecifier):
357353
device = device.to_port()
358354
else:
359355
with contextlib.suppress(ValidationError):
360-
device = UsbSpecifier.parse_raw(device).to_port()
356+
device = UsbSpecifier.model_validate_json(device).to_port()
361357
break
362358
except DeviceNotFoundError:
363359
pass

belay/usb_specifier.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
from typing import Dict, List, Optional
22

3-
try:
4-
from pydantic.v1 import BaseModel, Field
5-
except ImportError:
6-
from pydantic import BaseModel, Field
7-
3+
from pydantic import BaseModel, Field
84
from serial.tools.list_ports import comports
95

106
from .exceptions import DeviceNotFoundError, InsufficientSpecifierError
@@ -43,13 +39,13 @@ class UsbSpecifier(BaseModel):
4339
device: Optional[str] = Field(None, exclude=True)
4440

4541
def __repr__(self):
46-
return f'{self.__class__.__name__}({", ".join(f"{k}={v!r}" for k, v in self.dict().items() if v is not None)})'
42+
return f'{self.__class__.__name__}({", ".join(f"{k}={v!r}" for k, v in self.model_dump().items() if v is not None)})'
4743

4844
def to_port(self) -> str:
4945
if self.device:
5046
return self.device
5147

52-
spec = self.dict(exclude_none=True)
48+
spec = self.model_dump(exclude_none=True)
5349
possible_matches = []
5450

5551
for port_info in list_devices():
@@ -66,7 +62,7 @@ def to_port(self) -> str:
6662
def populated(self):
6763
# some ports, like wlan and bluetooth on macos,
6864
# don't populate any meaningful fields.
69-
return bool(self.dict(exclude_none=True))
65+
return bool(self.model_dump(exclude_none=True))
7066

7167

7268
def list_devices() -> List[UsbSpecifier]:

0 commit comments

Comments
 (0)