Skip to content

Commit 2be3806

Browse files
OLILHRhf-kklein
andauthored
Remove attrs dependency and use pydantic instead (#168)
Co-authored-by: konstantin <konstantin.klein@hochfrequenz.de>
1 parent 9969327 commit 2be3806

6 files changed

Lines changed: 22 additions & 36 deletions

File tree

requirements.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
attrs
21
bo4e>=0.5.0
32
pydantic>=2.0.0
43
typeguard

requirements.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
#
77
annotated-types==0.5.0
88
# via pydantic
9-
attrs==23.2.0
10-
# via -r requirements.in
119
bidict==0.22.1
1210
# via
1311
# -r requirements.in

setup.cfg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ zip_safe = False
3232
include_package_data = True
3333
python_requires = >=3.10
3434
install_requires =
35-
attrs
3635
bo4e
3736
pydantic>=2.0.0
3837
typeguard>=4.0.1

src/bomf/loader/entityloader.py

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,63 +9,56 @@
99
from pathlib import Path
1010
from typing import Awaitable, Callable, Generic, Optional, TypeVar
1111

12-
import attrs
1312
from generics import get_filled_type
14-
from pydantic import BaseModel, TypeAdapter, ValidationError # pylint:disable=no-name-in-module
13+
from pydantic import BaseModel, TypeAdapter, ConfigDict, ValidationError # pylint:disable=no-name-in-module
1514

1615
_TargetEntity = TypeVar("_TargetEntity")
1716

1817

19-
@attrs.define(auto_attribs=True, kw_only=True)
20-
class EntityLoadingResult: # pylint:disable=too-few-public-methods
18+
class EntityLoadingResult(BaseModel): # pylint:disable=too-few-public-methods
2119
"""
2220
Information gathered while loading a _TargetEntity into the target system.
2321
"""
2422

25-
id_in_target_system: Optional[str] = attrs.field(
26-
validator=attrs.validators.optional(attrs.validators.instance_of(str)), default=None
27-
)
23+
model_config = ConfigDict(arbitrary_types_allowed=True)
24+
25+
id_in_target_system: Optional[str] = None
2826
"""
2927
the optional ID of the entity in the target system (e.g. if a new (GU)ID is generated upon loading)
3028
"""
31-
polling_task: Optional[Awaitable] = attrs.field(default=None)
29+
polling_task: Optional[Awaitable] = None
3230
"""
3331
If this task is awaited it means, that the target system is done with processing the request.
3432
A possible use case is that the target system responds with something like an event ID which can be used to poll
3533
an endpoint until it returns the expected result.
3634
"""
3735

3836

39-
@attrs.define(auto_attribs=True, kw_only=True)
40-
class LoadingSummary(ABC, Generic[_TargetEntity]): # pylint:disable=too-few-public-methods
37+
class LoadingSummary(BaseModel, ABC, Generic[_TargetEntity]): # pylint:disable=too-few-public-methods
4138
"""
4239
Each instance of _TargetEntity that is loaded to the target system results in a LoadingSummary.
4340
It is a summary that reports to calling code.
4441
"""
4542

46-
was_loaded_successfully: bool = attrs.field(validator=attrs.validators.instance_of(bool))
43+
model_config = ConfigDict(arbitrary_types_allowed=True)
44+
45+
was_loaded_successfully: bool
4746
"""
4847
true iff the instance has been loaded successfully
4948
"""
50-
loaded_at: Optional[datetime] = attrs.field(
51-
validator=attrs.validators.optional(attrs.validators.instance_of(datetime)), default=None
52-
)
49+
loaded_at: Optional[datetime] = None
5350
"""
5451
point in time at which the loading (without verification) has completed; if not None
5552
"""
56-
verified_at: Optional[datetime] = attrs.field(
57-
validator=attrs.validators.optional(attrs.validators.instance_of(datetime)), default=None
58-
)
53+
verified_at: Optional[datetime] = None
5954
"""
6055
point in time at which the loading of this entity has been verified (or None if not)
6156
"""
62-
id_in_target_system: Optional[str] = attrs.field(
63-
validator=attrs.validators.optional(attrs.validators.instance_of(str)), default=None
64-
)
57+
id_in_target_system: Optional[str] = None
6558
"""
6659
the optional ID of the entity in the target system (e.g. if a new (GU)ID is generated upon loading)
6760
"""
68-
loading_error: Optional[Exception] = attrs.field(default=None)
61+
loading_error: Optional[Exception] = None
6962

7063

7164
class EntityLoader(ABC, Generic[_TargetEntity]): # pylint:disable=too-few-public-methods

src/bomf/model/__init__.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from abc import ABC
88
from typing import TypeVar, Union
99

10-
import attrs
1110
from bo4e.bo.geschaeftsobjekt import Geschaeftsobjekt
1211
from bo4e.com.com import COM
1312
from pydantic import BaseModel, Field # pylint: disable=no-name-in-module
@@ -26,8 +25,7 @@
2625

2726

2827
# pylint:disable=too-few-public-methods
29-
@attrs.define(kw_only=True, auto_attribs=True)
30-
class BusinessObjectRelation:
28+
class BusinessObjectRelation(BaseModel):
3129
"""
3230
A business object relation describes the relation between two business object.
3331
E.g. a relation could have the type "has_melo" where relation_part_a is a bo4e.bo.Vertrag
@@ -37,7 +35,7 @@ class BusinessObjectRelation:
3735
necessary relation information.
3836
"""
3937

40-
relation_type: enum.Enum = attrs.field()
38+
relation_type: enum.Enum
4139
"""
4240
The relation type describes how two business objects relate to each other.
4341
This is not (only) about cardinality. It's about being able to model different relations between objects.
@@ -48,12 +46,12 @@ class BusinessObjectRelation:
4846
All these relation types are 1:1 relations between business partners and adresses, yet they all carry different
4947
meaning which we'd like to distinguish in our data.
5048
"""
51-
relation_part_a: Bo4eTyp = attrs.field()
49+
relation_part_a: Bo4eTyp
5250
"""
5351
one Business Object or COM
5452
"""
5553

56-
relation_part_b: Bo4eTyp = attrs.field()
54+
relation_part_b: Bo4eTyp
5755
"""
5856
another Business Object or COM
5957
"""

unittests/test_mapper.py

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

3-
import attrs
3+
from pydantic import BaseModel
44
import pytest # type:ignore[import]
55
from bo4e.bo.marktlokation import Marktlokation
66
from bo4e.bo.messlokation import Messlokation
@@ -15,10 +15,9 @@ class _NotImplementedBo4eDataSetMixin:
1515
"""
1616

1717

18-
@attrs.define(kw_only=True, auto_attribs=True)
19-
class _MaLoAndMeLo(_NotImplementedBo4eDataSetMixin):
20-
malo: Marktlokation = attrs.field()
21-
melo: Messlokation = attrs.field()
18+
class _MaLoAndMeLo(BaseModel, _NotImplementedBo4eDataSetMixin):
19+
malo: Marktlokation
20+
melo: Messlokation
2221

2322
def get_business_object(self, bo_type: Type[Bo4eTyp], specification: Optional[str] = None) -> Bo4eTyp:
2423
# pyling:disable=fixme

0 commit comments

Comments
 (0)