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

Better error messages for unknown initialization keyword arguments #60

Merged
merged 4 commits into from
Nov 29, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ History

Next Release
------------
* Fix: Better error on bad ModelItem constructor argument (#50)

0.2.1 (2020-11-27)
------------------
Expand Down
19 changes: 19 additions & 0 deletions src/structurizr/abstract_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@
class AbstractBase(ABC):
"""Define common business logic through an abstract base class."""

def __init__(self, **kwargs):
"""
Initialize an abstract base class.

The AbstractBase class is designed to be the singular root of the entire class
hierarchy, similar to `object`, and acts as a guard against unknown keyword
arguments. Any keyword arguments not consumed in the hierarchy above cause a
`TypeError`.

"""
if kwargs:
is_plural = len(kwargs) > 1
message = "\n ".join(f"{key}={value}" for key, value in kwargs.items())
raise TypeError(
f"{type(self).__name__}.__init__() got {'' if is_plural else 'an '}"
f"unexpected keyword argument{'s' if is_plural else ''}:\n {message}"
)
super().__init__()

def __hash__(self) -> int:
"""Return an integer that represents a unique hash value for this instance."""
return id(self)
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/model/test_model_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,36 @@ def test_model_item_init(attributes):
assert getattr(model_item, attr) == expected


@pytest.mark.parametrize(
"kwargs",
[
pytest.param(
{"foo": 7},
marks=pytest.mark.raises(
exception=TypeError,
message="ConcreteModelItem.__init__() got an unexpected keyword "
"argument:\n foo=7",
),
),
pytest.param(
{"foo": 7, "bar": 17},
marks=pytest.mark.raises(
exception=TypeError,
message="ConcreteModelItem.__init__() got unexpected keyword "
"arguments:\n foo=7\n bar=17",
),
),
],
)
def test_handle_unknown_argument(kwargs: dict):
"""
Test for a sensible error message when unknown keyword arguments are passed.

See https://github.com/Midnighter/structurizr-python/issues/50.
"""
ConcreteModelItem(**kwargs)


def test_default_element_tags_order(empty_model: Model):
"""
Test that the default tags get added in the right order.
Expand Down