Skip to content

Commit

Permalink
feat: raise UndefinedKey exception on user decision (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixTheC authored Dec 4, 2023
1 parent c830ec7 commit bd6f82c
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ profile = "black"
[tool.ruff]
exclude = ["strongtyping/tests"]
line-length = 100
target-version = "py310"
target-version = "py312"

[tool.poetry]
name = "strongtyping"
Expand Down
11 changes: 11 additions & 0 deletions strongtyping/strong_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from strongtyping.config import SEVERITY_LEVEL
from strongtyping.strong_typing_utils import (
TypeMisMatch,
UndefinedKey,
check_type,
checking_typing_typedict_values,
default_return_queue,
Expand Down Expand Up @@ -235,6 +236,7 @@ def match_class_typing(cls=None, **kwargs):
excep_raise = kwargs.pop("excep_raise", TypeMisMatch)
cache_size = kwargs.pop("cache_size", 1)
severity = kwargs.pop("severity", "env")
throw_on_undefined = kwargs.pop("throw_on_undefined", False)

def __has_annotations__(obj):
return hasattr(obj, "__annotations__")
Expand Down Expand Up @@ -267,6 +269,7 @@ def __add_decorator(_cls):
cache_size=cache_size,
excep_raise=excep_raise,
subclass=is_static,
throw_on_undefined=throw_on_undefined,
),
)
except TypeError:
Expand All @@ -275,6 +278,14 @@ def __add_decorator(_cls):
def wrapper(some_cls):
def inner(*args, **cls_kwargs):
__add_decorator(some_cls)
if throw_on_undefined:
allowed_keys = some_cls.__annotations__.keys()
data = args[0] if args else cls_kwargs
if not all(arg in allowed_keys for arg in data):
raise UndefinedKey(
f"You can use the `TypedDict[{some_cls.__name__}]` "
f"only with the following attributes: `{', '.join(allowed_keys)}`"
)
return some_cls(*args, **cls_kwargs)

inner._matches_class = True
Expand Down
6 changes: 6 additions & 0 deletions strongtyping/strong_typing_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ def __init__(self, message):
print(message)


class UndefinedKey(Exception):
def __init__(self, message):
super().__init__()
print(message)


typing_base_class = typing._GenericAlias # type: ignore


Expand Down
19 changes: 18 additions & 1 deletion strongtyping/tests/test_typedict.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pytest

from strongtyping.strong_typing import match_class_typing, match_typing
from strongtyping.strong_typing_utils import TypeMisMatch, ValidationError
from strongtyping.strong_typing_utils import TypeMisMatch, UndefinedKey, ValidationError


def test_typedict():
Expand Down Expand Up @@ -305,5 +305,22 @@ def foo(**kwargs: Unpack[Movie]) -> str:
foo(**movie)


def test_undefined_keys_raise_error():
@match_class_typing(throw_on_undefined=True)
class User(TypedDict):
id: str
username: str
description: str | None

with pytest.raises(UndefinedKey):
User({"id": "0123", "username": "test", "description": None, "age": 10})

with pytest.raises(UndefinedKey):
User(id="Alfonso Cuarón", username="2004", description=None, age=10)

assert User({"id": "0123", "username": "test", "description": None})
assert User(id="0123", username="test")


if __name__ == "__main__":
pytest.main(["-vv", "-s", __file__])

0 comments on commit bd6f82c

Please sign in to comment.