Skip to content
This repository was archived by the owner on Jan 21, 2023. It is now read-only.

Commit 4f93e1c

Browse files
committed
refactor: move argument catching to abstract base
1 parent 3d92b68 commit 4f93e1c

File tree

3 files changed

+44
-29
lines changed

3 files changed

+44
-29
lines changed

src/structurizr/abstract_base.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,25 @@
2525
class AbstractBase(ABC):
2626
"""Define common business logic through an abstract base class."""
2727

28+
def __init__(self, **kwargs):
29+
"""
30+
Initialize an abstract base class.
31+
32+
The AbstractBase class is designed to be the singular root of the entire class
33+
hierarchy, similar to `object`, and acts as a guard against unknown keyword
34+
arguments. Any keyword arguments not consumed in the hierarchy above cause a
35+
`TypeError`.
36+
37+
"""
38+
if kwargs:
39+
is_plural = len(kwargs) > 1
40+
message = "\n ".join(f"{key}={value}" for key, value in kwargs.items())
41+
raise TypeError(
42+
f"{type(self).__name__}.__init__() got {'' if is_plural else 'an '}"
43+
f"unexpected keyword argument{'s' if is_plural else ''}:\n {message}"
44+
)
45+
super().__init__()
46+
2847
def __hash__(self) -> int:
2948
"""Return an integer that represents a unique hash value for this instance."""
3049
return id(self)

src/structurizr/model/model_item.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,7 @@ def __init__(
8484
**kwargs,
8585
):
8686
"""Initialise a ModelItem instance."""
87-
if len(kwargs) > 0:
88-
type_name = type(self).__name__
89-
args = [f"'{key}'" for key in kwargs.keys()]
90-
if len(args) == 1:
91-
raise TypeError(
92-
f"{type_name}.__init__() got an unexpected "
93-
f"keyword argument {args[0]}"
94-
)
95-
else:
96-
raise TypeError(
97-
f"{type_name}.__init__() got unexpected "
98-
f"keyword arguments {', '.join(args)}"
99-
)
100-
101-
super().__init__()
87+
super().__init__(**kwargs)
10288
self.id = id
10389
self.tags = OrderedSet(tags)
10490
self.properties = dict(properties)

tests/unit/model/test_model_item.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,34 @@ def test_model_item_init(attributes):
4545
assert getattr(model_item, attr) == expected
4646

4747

48-
def test_handling_of_bogus_init_params():
48+
@pytest.mark.parametrize(
49+
"kwargs",
50+
[
51+
pytest.param(
52+
{"foo": 7},
53+
marks=pytest.mark.raises(
54+
exception=TypeError,
55+
message="ConcreteModelItem.__init__() got an unexpected keyword "
56+
"argument:\n foo=7",
57+
),
58+
),
59+
pytest.param(
60+
{"foo": 7, "bar": 17},
61+
marks=pytest.mark.raises(
62+
exception=TypeError,
63+
message="ConcreteModelItem.__init__() got unexpected keyword "
64+
"arguments:\n foo=7\n bar=17",
65+
),
66+
),
67+
],
68+
)
69+
def test_handle_unknown_argument(kwargs: dict):
4970
"""
50-
Test for sensible error message if wrong param passed.
71+
Test for a sensible error message when unknown keyword arguments are passed.
5172
5273
See https://github.com/Midnighter/structurizr-python/issues/50.
5374
"""
54-
with pytest.raises(
55-
TypeError,
56-
match=r"ConcreteModelItem.__init__\(\) got an unexpected "
57-
r"keyword argument 'foo'",
58-
):
59-
ConcreteModelItem(foo=7)
60-
with pytest.raises(
61-
TypeError,
62-
match=r"ConcreteModelItem.__init__\(\) got unexpected keyword "
63-
r"arguments 'foo', 'bar'",
64-
):
65-
ConcreteModelItem(foo=7, bar=17)
75+
ConcreteModelItem(**kwargs)
6676

6777

6878
def test_default_element_tags_order(empty_model: Model):

0 commit comments

Comments
 (0)