Skip to content

Commit 66eada6

Browse files
rbell517Richard Bell
andauthored
feat: Upgrade to Pydantic 2.11 (#129)
Co-authored-by: Richard Bell <[email protected]>
1 parent c5cb4c2 commit 66eada6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+674
-644
lines changed

conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,4 @@ def enterprise_config(pytestconfig):
8888
@pytest.fixture(scope="session", autouse=True)
8989
def pydantic_forbid_extra_fields():
9090
"""Fixture to disable allowing extra fields in our Pydantic models."""
91-
JsonModel.Config.extra = Extra.forbid
91+
JsonModel.model_config.update(extra='forbid')

mypy.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ disallow_untyped_calls=True
1010
disallow_untyped_defs=True
1111
disallow_incomplete_defs=True
1212
disallow_untyped_decorators=True
13+
disable_error_code=empty-body
1314

1415
strict_equality=True
1516

nisystemlink/clients/core/_api_exception.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def error(self) -> Optional[core.ApiError]: # noqa: D401
4545
if self._error is None:
4646
return None
4747
else:
48-
return self._error.copy()
48+
return self._error.model_copy()
4949

5050
@property
5151
def http_status_code(self) -> Optional[int]: # noqa: D401

nisystemlink/clients/core/_http_configuration_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ class HttpConfigurationManager:
3030
_SALT_GRAINS_WORKSPACE_KEY = "systemlink_workspace"
3131
"""Key of Workspace ID stored in the salt grains config file."""
3232

33-
_configs = None
34-
_virtual_configs = None
33+
_configs: Optional[Dict[str, core.HttpConfiguration]] = None
34+
_virtual_configs: Optional[Dict[str, core.HttpConfiguration]] = None
3535

3636
@classmethod
3737
def get_configuration(

nisystemlink/clients/core/_uplink/_base_client.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
# mypy: disable-error-code = misc
22

3-
from json import loads
43
from typing import Any, Callable, Dict, get_origin, Optional, Type, Union
54

65
import requests
76
from nisystemlink.clients import core
8-
from pydantic import parse_obj_as
7+
from pydantic import TypeAdapter
98
from requests import JSONDecodeError, Response
109
from uplink import commands, Consumer, converters, response_handler, utils
1110

@@ -28,7 +27,7 @@ def _handle_http_status(response: Response) -> Optional[Response]:
2827
try:
2928
content = response.json()
3029
if content and "error" in content:
31-
err_obj = core.ApiError.parse_obj(content["error"])
30+
err_obj = core.ApiError.model_validate(content["error"])
3231
else:
3332
err_obj = None
3433

@@ -41,12 +40,20 @@ def _handle_http_status(response: Response) -> Optional[Response]:
4140
raise core.ApiException(msg, http_status_code=response.status_code)
4241

4342

43+
_type_adapters: Dict[Type, TypeAdapter] = dict()
44+
45+
4446
class _JsonModelConverter(converters.Factory):
47+
"""A converter that converts between JSON and Pydantic models."""
48+
49+
def __init__(self) -> None:
50+
super().__init__()
51+
4552
def create_request_body_converter(
4653
self, _class: Type, _: commands.RequestDefinition
4754
) -> Optional[Callable[[JsonModel], Dict]]:
4855
def encoder(model: JsonModel) -> Dict:
49-
return loads(model.json(by_alias=True, exclude_unset=True))
56+
return model.model_dump(mode="json", by_alias=True, exclude_unset=True)
5057

5158
if utils.is_subclass(_class, JsonModel):
5259
return encoder
@@ -56,15 +63,24 @@ def encoder(model: JsonModel) -> Dict:
5663
def create_response_body_converter(
5764
self, _class: Type, _: commands.RequestDefinition
5865
) -> Optional[Callable[[Response], Any]]:
59-
def decoder(response: Response) -> Any:
60-
try:
61-
data = response.json()
62-
except AttributeError:
63-
data = response
64-
65-
return parse_obj_as(_class, data)
66-
67-
if get_origin(_class) is Union or utils.is_subclass(_class, JsonModel):
66+
def decoder(response: Union[Response, Any]) -> Any:
67+
if response is None:
68+
return None
69+
70+
adapter = _type_adapters[_class]
71+
if isinstance(response, Response):
72+
if response.status_code == 204:
73+
return None
74+
return adapter.validate_json(response.text, by_alias=True, strict=True)
75+
else:
76+
# In cases where a return_key is specified, the response will already be parsed into a dict
77+
return adapter.validate_python(response, by_alias=True, strict=True)
78+
79+
origin = get_origin(_class)
80+
modelable_origin = origin is Union or origin is dict or origin is list
81+
if modelable_origin or utils.is_subclass(_class, JsonModel):
82+
if _type_adapters.get(_class) is None:
83+
_type_adapters[_class] = TypeAdapter(_class)
6884
return decoder
6985
else:
7086
return None
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from pydantic import BaseModel, Extra
1+
from pydantic import BaseModel, ConfigDict
22

33

44
def _camelcase(s: str) -> str:
@@ -10,7 +10,9 @@ def _camelcase(s: str) -> str:
1010
class JsonModel(BaseModel):
1111
"""Base class for models that are serialized to and from JSON."""
1212

13-
class Config:
14-
alias_generator = _camelcase
15-
allow_population_by_field_name = True
16-
extra = Extra.ignore.value
13+
model_config = ConfigDict(
14+
alias_generator=_camelcase,
15+
validate_by_name=True,
16+
validate_by_alias=True,
17+
extra="ignore",
18+
)

nisystemlink/clients/dataframe/models/_column_filter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ class ColumnFilter(JsonModel):
3333
* When ``value`` is ``NaN`` for a floating-point column, the operation must be ``NOT_EQUALS``.
3434
"""
3535

36-
value: Optional[str]
36+
value: Optional[str] = None
3737
"""The comparison value to use for filtering. An error will be returned if
3838
the value cannot be converted to the column's data type."""

nisystemlink/clients/file/models/_file_metadata.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,62 +17,62 @@ class FileMetadata(JsonModel):
1717
- updateMetadata: Link to update the file's metadata using a POST request
1818
"""
1919

20-
created: Optional[datetime]
20+
created: Optional[datetime] = None
2121
"""
2222
The date and time the file was created in the file service.
2323
2424
example :2018-05-15T18:54:27.519Z
2525
"""
2626

27-
id: Optional[str]
27+
id: Optional[str] = None
2828
"""
2929
The file's ID within the service group.
3030
3131
example: "5afb2ce3741fe11d88838cc9"
3232
"""
3333

34-
path: Optional[str]
34+
path: Optional[str] = None
3535
"""
3636
The path to the file on the server. This field is returned only if
3737
the user has associated privileges to view file paths.
3838
3939
example: C:\temp\4afb2ce3741fe11d88838cc9.txt
4040
"""
4141

42-
properties: Optional[Dict[str, str]]
42+
properties: Optional[Dict[str, str]] = None
4343
"""
4444
The file's properties
4545
Example - {"Name": "myfile.txt", "MyProperty": "Value"}
4646
"""
4747

48-
meta_data_revision: Optional[int]
48+
meta_data_revision: Optional[int] = None
4949
"""
5050
The file's properties revision number. When a file is uploaded, the revision number starts at 1.
5151
Every time metadata is updated, the revision number is incremented by 1.
5252
"""
5353

54-
service_group: Optional[str]
54+
service_group: Optional[str] = None
5555
"""
5656
The service group that owns the file
5757
"""
5858

59-
size: Optional[int]
59+
size: Optional[int] = None
6060
"""
6161
The 32-bit file size in bytes. If the value is larger than a 32-bit integer,
6262
this value is -1 and the size64 parameter contains the correct value.
6363
"""
6464

65-
size64: Optional[int]
65+
size64: Optional[int] = None
6666
"""
6767
The 64-bit file size in bytes
6868
"""
6969

70-
workspace: Optional[str]
70+
workspace: Optional[str] = None
7171
"""
7272
The workspace the file belongs to
7373
"""
7474

75-
last_updated_timestamp: Optional[datetime]
75+
last_updated_timestamp: Optional[datetime] = None
7676
"""
7777
The date and time the file was last updated in the file service.
7878

nisystemlink/clients/file/models/_link.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class Link(JsonModel):
6-
href: str = Field(..., example="/nifile/v1/service-groups")
6+
href: str = Field(..., examples=["/nifile/v1/service-groups"])
77
"""
88
URI of the link
99
"""

nisystemlink/clients/file/models/_operations.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55

66

77
class Operations(JsonModel):
8-
delete_files: Optional[Operation]
9-
download_data: Optional[Operation]
10-
list_files: Optional[Operation]
11-
query_files: Optional[Operation]
12-
update_metadata: Optional[Operation]
13-
upload_files: Optional[Operation]
8+
delete_files: Optional[Operation] = None
9+
download_data: Optional[Operation] = None
10+
list_files: Optional[Operation] = None
11+
query_files: Optional[Operation] = None
12+
update_metadata: Optional[Operation] = None
13+
upload_files: Optional[Operation] = None
1414

1515

1616
class V1Operations(JsonModel):
17-
operations: Optional[Operations]
17+
operations: Optional[Operations] = None
1818
"""
1919
Available operations in the v1 version of the API:
2020
- deleteFiles: The ability to delete uploaded files

0 commit comments

Comments
 (0)