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 all 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
22 changes: 22 additions & 0 deletions src/structurizr/abstract_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@
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:
phrase = (
"unexpected keyword arguments"
if len(kwargs) > 1
else "an unexpected keyword argument"
)
message = "\n ".join(f"{key}={value}" for key, value in kwargs.items())
raise TypeError(
f"{type(self).__name__}.__init__() got {phrase}:\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