Skip to content

Commit 41de8f5

Browse files
authored
Migrate fully to pydantic 2 (#268)
* Add Raises to validate docstring * Update requirements
1 parent 232b182 commit 41de8f5

File tree

5 files changed

+65
-46
lines changed

5 files changed

+65
-46
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ Confirmed to work with Zaptec products
2626
* Zaptec Home
2727
* Zaptec PRO
2828

29-
To use this component, a user with access to
30-
[Zaptec Portal](https://portal.zaptec.com/) is required.
29+
# Requirements
3130

31+
* Home Assistant 2025.7 or newer.
32+
* A user with access to [Zaptec Portal](https://portal.zaptec.com/).
3233

3334
# ⭐ Version 0.8.*
3435

custom_components/zaptec/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"issue_tracker": "https://github.com/custom-components/zaptec/issues",
1414
"requirements": [
1515
"azure-servicebus==7.14.2",
16-
"pydantic==2.11.7",
16+
"pydantic>=2.11.7,<2.12",
1717
"aiolimiter==1.2.1"
1818
],
1919
"version": "0.8.2"

custom_components/zaptec/validate.py

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,98 +4,121 @@
44

55
import logging
66
import re
7+
from typing import Any
78

8-
try:
9-
from pydantic.v1 import BaseModel, ConfigDict, ValidationError
10-
except ImportError:
11-
from pydantic import BaseModel, ConfigDict, ValidationError
9+
from pydantic import BaseModel, ConfigDict, TypeAdapter, ValidationError
1210

1311
_LOGGER = logging.getLogger(__name__)
1412

1513

16-
class TypeWrapper:
17-
"""Workaround class for v1 pydantic."""
18-
19-
2014
class Installation(BaseModel):
15+
"""Pydantic model for a Zaptec installation."""
16+
2117
model_config = ConfigDict(extra="allow")
2218
Id: str
19+
Active: bool
20+
AuthenticationType: int
21+
CurrentUserRoles: int
22+
InstallationType: int
23+
NetworkType: int
2324

2425

2526
class Installations(BaseModel):
27+
"""Pydantic model for a list of Zaptec installations."""
28+
2629
model_config = ConfigDict(extra="allow")
2730
Data: list[Installation]
31+
Pages: int
2832

2933

3034
class Charger(BaseModel):
35+
"""Pydantic model for a Zaptec charger."""
36+
3137
model_config = ConfigDict(extra="allow")
3238
Id: str
3339
Name: str
40+
Active: bool
41+
DeviceType: int
3442

3543

3644
class ChargerState(BaseModel):
45+
"""Pydantic model for a single state of a Zaptec charger."""
46+
3747
model_config = ConfigDict(extra="allow")
3848
StateId: int
3949
ValueAsString: str
4050

4151

42-
# pydantic v2
43-
# ChargerStates = TypeAdapter[list[ChargerState]]
44-
class ChargerStates(TypeWrapper, BaseModel):
45-
_data: list[ChargerState]
46-
47-
48-
class ChargerUpdate(TypeWrapper, BaseModel):
49-
_data: dict[str, str]
52+
ChargerStates = TypeAdapter[list[ChargerState]]
53+
ChargerUpdate = TypeAdapter[dict[str, str]]
5054

5155

5256
class Chargers(BaseModel):
57+
"""Pydantic model for a list of Zaptec chargers."""
58+
5359
model_config = ConfigDict(extra="allow")
5460
Data: list[Charger]
61+
Pages: int
5562

5663

5764
class Circuit(BaseModel):
65+
"""Pydantic model for a Zaptec circuit."""
66+
5867
model_config = ConfigDict(extra="allow")
5968
Id: str
6069
Name: str
6170
Chargers: list[Charger]
6271

6372

6473
class Hierarchy(BaseModel):
74+
"""Pydantic model for the hierarchy of Zaptec objects in an installation."""
75+
6576
model_config = ConfigDict(extra="allow")
6677
Id: str
6778
Name: str
79+
NetworkType: int
6880
Circuits: list[Circuit]
6981

7082

7183
class ChargerFirmware(BaseModel):
84+
"""Pydantic model for the firmware information of a Zaptec charger."""
85+
7286
model_config = ConfigDict(extra="allow")
7387
ChargerId: str
88+
DeviceType: int
89+
IsOnline: bool
7490
CurrentVersion: str
7591
AvailableVersion: str
7692
IsUpToDate: bool
7793

7894

7995
class ChargerLocalSettings(BaseModel):
96+
"""
97+
Pydantic model for the local settings of a Zaptec charger.
98+
99+
Note: This model is used in an undocumented API-call, and should be removed as soon as we have
100+
official API-calls that can cover the necessary functionality
101+
"""
102+
80103
model_config = ConfigDict(extra="allow")
81104
Id: str
82-
# Name: str
83-
# DeviceId: str
105+
Name: str | None = None
106+
DeviceId: str | None = None
84107

85108

86-
# pydantic v2
87-
# ChargerFirmwares = TypeAdapter[list[ChargerFirmware]]
88-
class ChargerFirmwares(TypeWrapper, BaseModel):
89-
_data: list[ChargerFirmware]
109+
ChargerFirmwares = TypeAdapter[list[ChargerFirmware]]
90110

91111

92112
class InstallationConnectionDetails(BaseModel):
113+
"""Pydantic model for the servicebus connection details of a Zaptec installation."""
114+
93115
model_config = ConfigDict(extra="allow")
94116
Host: str
95117
Password: str
96-
# Port: int
118+
Port: int
119+
UseSSL: bool
97120
Subscription: str
98-
# Type: int
121+
Type: int
99122
Username: str
100123
Topic: str
101124

@@ -121,29 +144,24 @@ class InstallationConnectionDetails(BaseModel):
121144
_URLS = [(k, re.compile(k), v) for k, v in URLS.items()]
122145

123146

124-
def validate(data, url):
125-
"""Validate the data."""
147+
def validate(data: Any, url: str) -> None:
148+
"""
149+
Validate the data.
150+
151+
Raises:
152+
ValidationError: If data doesn't match the pydantic model associated with the url.
153+
154+
"""
126155

127156
for pat, re_pat, model in _URLS:
128157
# Mathes either the exact string or its regexp
129158
if url == pat or re_pat.fullmatch(url):
130159
try:
131-
d = data
132-
133-
# pydantic v1
134-
if isinstance(model, TypeWrapper):
135-
d = {"_data": data}
136-
137160
if isinstance(model, BaseModel):
138-
# pydantic v1
139-
model.parse_obj(d)
140-
141-
# pydantic v2
142-
# model.model_validate(data, strict=True)
161+
model.model_validate(data, strict=True)
143162

144-
# pydantic v2
145-
# elif isinstance(model, TypeAdapter):
146-
# model.validate_python(data, strict=True)
163+
elif isinstance(model, TypeAdapter):
164+
model.validate_python(data, strict=True)
147165

148166
except ValidationError as err:
149167
_LOGGER.error("Failed to validate %s (pattern %s): %s", url, pat, err)

hacs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"name": "Zaptec EV charger",
3-
"homeassistant": "2025.2.4",
3+
"homeassistant": "2025.7.0",
44
"hacs": "2.0.5"
55
}

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
colorlog==6.9.0
2-
homeassistant==2025.7.3
2+
homeassistant==2025.8.3
33
pip>=25.0
4-
ruff==0.12.4
4+
ruff==0.12.10
55

66
# Copy from manifest.json to get this into the dev container
77
# without needing to start HA

0 commit comments

Comments
 (0)