Module pedantic.tests.tests_pedantic
Expand source code
import os.path
import sys
import types
import typing
import unittest
from dataclasses import dataclass
from datetime import datetime, date
from functools import wraps
from io import BytesIO, StringIO
from typing import List, Tuple, Callable, Any, Optional, Union, Dict, Set, FrozenSet, NewType, TypeVar, Sequence, \
AbstractSet, Iterator, NamedTuple, Collection, Type, Generator, Generic, BinaryIO, TextIO, Iterable, Container, \
NoReturn, ClassVar, Literal
from enum import Enum, IntEnum
from pedantic import pedantic_class
from pedantic.exceptions import PedanticTypeCheckException, PedanticException, PedanticCallWithArgsException, \
PedanticTypeVarMismatchException
from pedantic.decorators.fn_deco_pedantic import pedantic
TEST_FILE = 'test.txt'
class Parent:
pass
class Child(Parent):
def method(self, a: int):
pass
class TestDecoratorRequireKwargsAndTypeCheck(unittest.TestCase):
def tearDown(self) -> None:
if os.path.isfile(TEST_FILE):
os.remove(TEST_FILE)
def test_no_kwargs(self):
@pedantic
def calc(n: int, m: int, i: int) -> int:
return n + m + i
with self.assertRaises(expected_exception=PedanticCallWithArgsException):
calc(42, 40, 38)
with self.assertRaises(expected_exception=PedanticCallWithArgsException):
calc(42, m=40, i=38)
calc(n=42, m=40, i=38)
def test_nested_type_hints_1(self):
@pedantic
def calc(n: int) -> List[List[float]]:
return [0.0 * n]
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42)
def test_nested_type_hints_1_corrected(self):
@pedantic
def calc(n: int) -> List[List[float]]:
return [[0.0 * n]]
calc(n=42)
def test_nested_type_hints_2(self):
"""Problem here: int != float"""
@pedantic
def calc(n: int) -> List[Tuple[float, str]]:
return [(n, str(n))]
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42)
def test_nested_type_hints_2_corrected(self):
@pedantic
def calc(n: int) -> List[Tuple[int, str]]:
return [(n, str(n))]
@pedantic
def calc_2(n: float) -> List[Tuple[float, str]]:
return [(n, str(n))]
calc(n=42)
calc_2(n=42.0)
def test_nested_type_hints_3(self):
"""Problem here: inner function actually returns Tuple[int, str]"""
@pedantic
def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
@pedantic
def f(x: int, y: float) -> Tuple[float, str]:
return n * x, str(y)
return f
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42)(x=3, y=3.14)
def test_nested_type_hints_3_corrected(self):
@pedantic
def calc(n: int) -> Callable[[int, float], Tuple[int, str]]:
@pedantic
def f(x: int, y: float) -> Tuple[int, str]:
return n * x, str(y)
return f
calc(n=42)(x=3, y=3.14)
def test_nested_type_hints_4(self):
"""Problem here: return type is actually float"""
@pedantic
def calc(n: List[List[float]]) -> int:
return n[0][0]
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=[[42.0]])
def test_nested_type_hints_corrected(self):
@pedantic
def calc(n: List[List[float]]) -> int:
return int(n[0][0])
calc(n=[[42.0]])
def test_nested_type_hints_5(self):
"""Problem here: Tuple[float, str] != Tuple[float, float]"""
@pedantic
def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
@pedantic
def f(x: int, y: float) -> Tuple[float, float]:
return n * float(x), y
return f
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42)
def test_nested_type_hints_5_corrected(self):
@pedantic
def calc(n: int) -> Callable[[int, float], Tuple[float, float]]:
@pedantic
def f(x: int, y: float) -> Tuple[float, float]:
return n * float(x), y
return f
calc(n=42)
def test_missing_type_hint_1(self):
"""Problem here: type hint for n missed"""
@pedantic
def calc(n) -> float:
return 42.0 * n
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42)
def test_missing_type_hint_1_corrected(self):
@pedantic
def calc(n: int) -> float:
return 42.0 * n
calc(n=42)
def test_missing_type_hint_2(self):
"""Problem here: Return type annotation missed"""
@pedantic
def calc(n: int):
return 'Hi' + str(n)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42)
def test_missing_type_hint_2_corrected(self):
@pedantic
def calc(n: int) -> str:
return 'Hi' + str(n)
calc(n=42)
def test_missing_type_hint_3(self):
"""Problem here: type hint for i missed"""
@pedantic
def calc(n: int, m: int, i) -> int:
return n + m + i
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42, m=40, i=38)
def test_missing_type_hint_3_corrected(self):
@pedantic
def calc(n: int, m: int, i: int) -> int:
return n + m + i
calc(n=42, m=40, i=38)
def test_all_ok_2(self):
@pedantic
def calc(n: int, m: int, i: int) -> str:
return str(n + m + i)
calc(n=42, m=40, i=38)
def test_all_ok_3(self):
@pedantic
def calc(n: int, m: int, i: int) -> None:
str(n + m + i)
calc(n=42, m=40, i=38)
def test_all_ok_4(self):
@pedantic
def calc(n: int) -> List[List[int]]:
return [[n]]
calc(n=42)
def test_all_ok_5(self):
@pedantic
def calc(n: int) -> List[Tuple[float, str]]:
return [(float(n), str(n))]
calc(n=42)
def test_all_ok_6(self):
@pedantic
def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
@pedantic
def f(x: int, y: float) -> Tuple[float, str]:
return n * float(x), str(y)
return f
calc(n=42)(x=72, y=3.14)
def test_all_ok_7(self):
@pedantic
def calc(n: List[List[float]]) -> Any:
return n[0][0]
calc(n=[[42.0]])
def test_all_ok_8(self):
@pedantic
def calc(n: int) -> Callable[[int, float], Tuple[float, str]]:
@pedantic
def f(x: int, y: float) -> Tuple[float, str]:
return n * float(x), str(y)
return f
calc(n=42)(x=3, y=3.14)
def test_wrong_type_hint_1(self):
"""Problem here: str != int"""
@pedantic
def calc(n: int, m: int, i: int) -> str:
return n + m + i
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42, m=40, i=38)
def test_wrong_type_hint_1_corrected(self):
@pedantic
def calc(n: int, m: int, i: int) -> str:
return str(n + m + i)
calc(n=42, m=40, i=38)
def test_wrong_type_hint_2(self):
"""Problem here: str != int"""
@pedantic
def calc(n: int, m: int, i: str) -> int:
return n + m + i
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42, m=40, i=38)
def test_wrong_type_hint_2_corrected(self):
@pedantic
def calc(n: int, m: int, i: str) -> int:
return n + m + int(i)
calc(n=42, m=40, i='38')
def test_wrong_type_hint_3(self):
"""Problem here: None != int"""
@pedantic
def calc(n: int, m: int, i: int) -> None:
return n + m + i
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42, m=40, i=38)
def test_wrong_type_hint_corrected(self):
@pedantic
def calc(n: int, m: int, i: int) -> None:
print(n + m + i)
calc(n=42, m=40, i=38)
def test_wrong_type_hint_4(self):
"""Problem here: None != int"""
@pedantic
def calc(n: int, m: int, i: int) -> int:
print(n + m + i)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42, m=40, i=38)
def test_wrong_type_hint_4_corrected(self):
@pedantic
def calc(n: int, m: int, i: int) -> int:
return n + m + i
calc(n=42, m=40, i=38)
def test_none_1(self):
"""Problem here: None is not accepted"""
@pedantic
def calc(n: int, m: int, i: int) -> int:
return n + m + i
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42, m=40, i=None)
def test_none_2(self):
@pedantic
def calc(n: int, m: int, i: Optional[int]) -> int:
return n + m + i if i is not None else n + m
calc(n=42, m=40, i=None)
def test_none_3(self):
@pedantic
def calc(n: int, m: int, i: Union[int, None]) -> int:
return n + m + i if i is not None else n + m
calc(n=42, m=40, i=None)
def test_none_4(self):
"""Problem here: function may return None"""
@pedantic
def calc(n: int, m: int, i: Union[int, None]) -> int:
return n + m + i if i is not None else None
calc(n=42, m=40, i=42)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(n=42, m=40, i=None)
def test_none_5(self):
@pedantic
def calc(n: int, m: int, i: Union[int, None]) -> Optional[int]:
return n + m + i if i is not None else None
calc(n=42, m=40, i=None)
def test_inheritance_1(self):
class MyClassA:
pass
class MyClassB(MyClassA):
pass
@pedantic
def calc(a: MyClassA) -> str:
return str(a)
calc(a=MyClassA())
calc(a=MyClassB())
def test_inheritance_2(self):
"""Problem here: A is not a subtype of B"""
class MyClassA:
pass
class MyClassB(MyClassA):
pass
@pedantic
def calc(a: MyClassB) -> str:
return str(a)
calc(a=MyClassB())
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(a=MyClassA())
def test_instance_method_1(self):
class MyClassA:
@pedantic
def calc(self, i: int) -> str:
return str(i)
a = MyClassA()
a.calc(i=42)
def test_instance_method_2(self):
"""Problem here: 'i' has no type annotation"""
class MyClassA:
@pedantic
def calc(self, i) -> str:
return str(i)
a = MyClassA()
with self.assertRaises(expected_exception=PedanticTypeCheckException):
a.calc(i=42)
def test_instance_method_2_corrected(self):
class MyClassA:
@pedantic
def calc(self, i: int) -> str:
return str(i)
a = MyClassA()
a.calc(i=42)
def test_instance_method_int_is_not_float(self):
class MyClassA:
@pedantic
def calc(self, i: float) -> str:
return str(i)
a = MyClassA()
with self.assertRaises(expected_exception=PedanticTypeCheckException):
a.calc(i=42)
def test_instance_method_3_corrected(self):
class MyClassA:
@pedantic
def calc(self, i: float) -> str:
return str(i)
a = MyClassA()
a.calc(i=42.0)
def test_instance_method_no_kwargs(self):
class MyClassA:
@pedantic
def calc(self, i: int) -> str:
return str(i)
a = MyClassA()
with self.assertRaises(expected_exception=PedanticCallWithArgsException):
a.calc(42)
def test_instance_method_5(self):
"""Problem here: instance methods is not called with kwargs"""
class MyClassA:
@pedantic
def calc(self, i: int) -> str:
return str(i)
a = MyClassA()
a.calc(i=42)
def test_lambda_1(self):
@pedantic
def calc(i: float) -> Callable[[float], str]:
return lambda x: str(x * i)
calc(i=42.0)(10.0)
def test_lambda_3(self):
@pedantic
def calc(i: float) -> Callable[[float], str]:
def res(x: float) -> str:
return str(x * i)
return res
calc(i=42.0)(10.0)
def test_lambda_int_is_not_float(self):
@pedantic
def calc(i: float) -> Callable[[float], str]:
def res(x: int) -> str:
return str(x * i)
return res
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(i=42.0)(x=10)
def test_lambda_4_almost_corrected(self):
"""Problem here: float != str"""
@pedantic
def calc(i: float) -> Callable[[float], str]:
@pedantic
def res(x: int) -> str:
return str(x * i)
return res
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(i=42.0)(x=10)
def test_lambda_4_almost_corrected_2(self):
@pedantic
def calc(i: float) -> Callable[[int], str]:
@pedantic
def res(x: int) -> str:
return str(x * i)
return res
calc(i=42.0)(x=10)
def test_lambda_5(self):
"""Problem here: float != int"""
@pedantic
def calc(i: float) -> Callable[[float], str]:
@pedantic
def res(x: float) -> str:
return str(x * i)
return res
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(i=42.0)(x=10)
def test_lambda_corrected(self):
@pedantic
def calc(i: float) -> Callable[[float], str]:
@pedantic
def res(x: float) -> str:
return str(x * i)
return res
calc(i=42.0)(x=10.0)
def test_tuple_without_type_args(self):
@pedantic
def calc(i: Tuple) -> str:
return str(i)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(i=(42.0, 43, 'hi'))
def test_tuple_without_args_corrected(self):
@pedantic
def calc(i: Tuple[Any, ...]) -> str:
return str(i)
calc(i=(42.0, 43, 'hi'))
def test_callable_without_type_args(self):
@pedantic
def calc(i: Callable) -> str:
return str(i(' you'))
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(i=lambda x: (42.0, 43, 'hi', x))
def test_callable_without_args_correct_with_lambdas(self):
@pedantic
def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str:
return str(i(x=' you'))
calc(i=lambda x: (42.0, 43, 'hi', x))
def test_callable_without_args_corrected(self):
@pedantic
def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str:
return str(i(x=' you'))
@pedantic
def arg(x: Any) -> Tuple[Any, ...]:
return 42.0, 43, 'hi', x
calc(i=arg)
def test_list_without_args(self):
@pedantic
def calc(i: List) -> Any:
return [i]
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(i=[42.0, 43, 'hi'])
def test_list_without_args_corrected(self):
@pedantic
def calc(i: List[Any]) -> List[List[Any]]:
return [i]
calc(i=[42.0, 43, 'hi'])
def test_ellipsis_in_callable_1(self):
@pedantic
def calc(i: Callable[..., int]) -> int:
return i()
@pedantic
def call() -> int:
return 42
calc(i=call)
def test_ellipsis_in_callable_2(self):
@pedantic
def calc(i: Callable[..., int]) -> int:
return i(x=3.14, y=5)
@pedantic
def call(x: float, y: int) -> int:
return 42
calc(i=call)
def test_ellipsis_in_callable_3(self):
"""Problem here: call to "call" misses one argument"""
@pedantic
def calc(i: Callable[..., int]) -> int:
return i(x=3.14)
@pedantic
def call(x: float, y: int) -> int:
return 42
with self.assertRaises(expected_exception=PedanticException):
calc(i=call)
def test_optional_args_1(self):
@pedantic
def calc(a: int, b: int = 42) -> int:
return a + b
calc(a=2)
def test_optional_args_2(self):
@pedantic
def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float:
return a + b + c
calc()
calc(a=1)
calc(b=1)
calc(c=1.0)
calc(a=1, b=1)
calc(a=1, c=1.0)
calc(b=1, c=1.0)
calc(a=1, b=1, c=1.0)
def test_optional_args_3(self):
"""Problem here: optional argument c: 5 is not a float"""
@pedantic
def calc(a: int = 3, b: int = 42, c: float = 5) -> float:
return a + b + c
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc()
def test_optional_args_3_corrected(self):
@pedantic
def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float:
return a + b + c
calc()
def test_optional_args_4(self):
class MyClass:
@pedantic
def foo(self, a: int, b: Optional[int] = 1) -> int:
return a + b
my_class = MyClass()
my_class.foo(a=10)
def test_optional_args_5(self):
@pedantic
def calc(d: Optional[Dict[int, int]] = None) -> Optional[int]:
if d is None:
return None
return sum(d.keys())
calc(d=None)
calc()
calc(d={42: 3})
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(d={42: 3.14})
def test_optional_args_6(self):
""""Problem here: str != int"""
@pedantic
def calc(d: int = 42) -> int:
return int(d)
calc(d=99999)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(d='999999')
def test_enum_1(self):
"""Problem here: Type hint for 'a' should be MyEnum instead of MyEnum.GAMMA"""
class MyEnum(Enum):
ALPHA = 'startEvent'
BETA = 'task'
GAMMA = 'sequenceFlow'
class MyClass:
@pedantic
def operation(self, a: MyEnum.GAMMA) -> None:
print(a)
m = MyClass()
with self.assertRaises(expected_exception=PedanticTypeCheckException):
m.operation(a=MyEnum.GAMMA)
def test_enum_1_corrected(self):
class MyEnum(Enum):
ALPHA = 'startEvent'
BETA = 'task'
GAMMA = 'sequenceFlow'
@pedantic
def operation(a: MyEnum) -> None:
print(a)
operation(a=MyEnum.GAMMA)
def test_sloppy_types_dict(self):
@pedantic
def operation(d: dict) -> int:
return len(d.keys())
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d={1: 1, 2: 2})
def test_sloppy_types_dict_almost_corrected_no_type_args(self):
@pedantic
def operation(d: Dict) -> int:
return len(d.keys())
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d={1: 1, 2: 2})
def test_sloppy_types_dict_corrected(self):
@pedantic
def operation(d: Dict[int, int]) -> int:
return len(d.keys())
operation(d={1: 1, 2: 2})
def test_sloppy_types_list(self):
@pedantic
def operation(d: list) -> int:
return len(d)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d=[1, 2, 3, 4])
def test_sloppy_types_list_almost_corrected_no_type_args(self):
@pedantic
def operation(d: List) -> int:
return len(d)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d=[1, 2, 3, 4])
def test_sloppy_types_list_corrected(self):
@pedantic
def operation(d: List[int]) -> int:
return len(d)
operation(d=[1, 2, 3, 4])
def test_sloppy_types_tuple(self):
@pedantic
def operation(d: tuple) -> int:
return len(d)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d=(1, 2, 3))
def test_sloppy_types_tuple_almost_corrected_no_type_args(self):
@pedantic
def operation(d: Tuple) -> int:
return len(d)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d=(1, 2, 3))
def test_sloppy_types_tuple_corrected(self):
@pedantic
def operation(d: Tuple[int, int, int]) -> int:
return len(d)
operation(d=(1, 2, 3))
def test_sloppy_types_set(self):
@pedantic
def operation(d: set) -> int:
return len(d)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d={1, 2, 3})
def test_sloppy_types_set_almost_corrected_to_type_args(self):
@pedantic
def operation(d: Set) -> int:
return len(d)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d={1, 2, 3})
def test_sloppy_types_set_corrected(self):
@pedantic
def operation(d: Set[int]) -> int:
return len(d)
operation(d={1, 2, 3})
def test_sloppy_types_frozenset(self):
@pedantic
def operation(d: frozenset) -> int:
return len(d)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d=frozenset({1, 2, 3}))
def test_sloppy_types_frozenset_almost_corrected_no_type_args(self):
@pedantic
def operation(d: FrozenSet) -> int:
return len(d)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
operation(d=frozenset({1, 2, 3}))
def test_sloppy_types_frozenset_corrected(self):
@pedantic
def operation(d: FrozenSet[int]) -> int:
return len(d)
operation(d=frozenset({1, 2, 3}))
def test_type_list_but_got_tuple(self):
@pedantic
def calc(ls: List[Any]) -> int:
return len(ls)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
calc(ls=(1, 2, 3))
def test_type_list_corrected(self):
@pedantic
def calc(ls: Tuple[Any, ...]) -> int:
return len(ls)
calc(ls=(1, 2, 3))
def test_any(self):
@pedantic
def calc(ls: List[Any]) -> Dict[int, Any]:
return {i: ls[i] for i in range(0, len(ls))}
calc(ls=[1, 2, 3])
calc(ls=[1.11, 2.0, 3.0])
calc(ls=['1', '2', '3'])
calc(ls=[10.5, '2', (3, 4, 5)])
def test_aliases(self):
Vector = List[float]
@pedantic
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
scale(scalar=2.0, vector=[1.0, -4.2, 5.4])
def test_new_type(self):
UserId = NewType('UserId', int)
@pedantic
def get_user_name(user_id: UserId) -> str:
return str(user_id)
some_id = UserId(524313)
get_user_name(user_id=some_id)
# the following would be desirable but impossible to check at runtime:
# with self.assertRaises(expected_exception=AssertionError):
# get_user_name(user_id=-1)
def test_list_of_new_type(self):
UserId = NewType('UserId', int)
@pedantic
def get_user_name(user_ids: List[UserId]) -> str:
return str(user_ids)
get_user_name(user_ids=[UserId(524313), UserId(42)])
with self.assertRaises(expected_exception=PedanticTypeCheckException):
get_user_name(user_ids=[UserId(524313), UserId(42), 430.0])
def test_callable_no_args(self):
@pedantic
def f(g: Callable[[], str]) -> str:
return g()
@pedantic
def greetings() -> str:
return 'hello world'
f(g=greetings)
def test_type_var(self):
T = TypeVar('T')
@pedantic
def first(ls: List[T]) -> T:
return ls[0]
first(ls=[1, 2, 3])
def test_type_var_wrong(self):
T = TypeVar('T')
@pedantic
def first(ls: List[T]) -> T:
return str(ls[0])
with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
first(ls=[1, 2, 3])
def test_type_var_wrong_sequence(self):
T = TypeVar('T')
@pedantic
def first(ls: Sequence[T]) -> T:
return str(ls[0])
with self.assertRaises(expected_exception=PedanticTypeVarMismatchException):
first(ls=[1, 2, 3])
def test_double_pedantic(self):
@pedantic
@pedantic
def f(x: int, y: float) -> Tuple[float, str]:
return float(x), str(y)
f(x=5, y=3.14)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
f(x=5.0, y=3.14)
with self.assertRaises(expected_exception=PedanticCallWithArgsException):
f(5, 3.14)
def test_args_kwargs(self):
@pedantic
def some_method(a: int = 0, b: float = 0.0) -> float:
return a * b
@pedantic
def wrapper_method(*args: Union[int, float], **kwargs: Union[int, float]) -> float:
return some_method(*args, **kwargs)
some_method()
with self.assertRaises(expected_exception=PedanticCallWithArgsException):
some_method(3, 3.0)
some_method(a=3, b=3.0)
wrapper_method()
with self.assertRaises(expected_exception=PedanticCallWithArgsException):
wrapper_method(3, 3.0)
wrapper_method(a=3, b=3.0)
def test_args_kwargs_no_type_hint(self):
@pedantic
def method_no_type_hint(*args, **kwargs) -> None:
print(args)
print(kwargs)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
method_no_type_hint(a=3, b=3.0)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
method_no_type_hint()
def test_args_kwargs_wrong_type_hint(self):
"""See: https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values"""
@pedantic
def wrapper_method(*args: str, **kwargs: str) -> None:
print(args)
print(kwargs)
wrapper_method()
wrapper_method('hi', 'you', ':)')
wrapper_method(a='hi', b='you', c=':)')
with self.assertRaises(expected_exception=PedanticTypeCheckException):
wrapper_method('hi', 'you', ':)', 7)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
wrapper_method(3, 3.0)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
wrapper_method(a=3, b=3.0)
def test_additional_kwargs(self):
@pedantic
def some_method(a: int, b: float = 0.0, **kwargs: int) -> float:
return sum([a, b])
some_method(a=5)
some_method(a=5, b=0.1)
some_method(a=5, b=0.1, c=4)
some_method(a=5, b=0.1, c=4, d=5, e=6)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
some_method(a=5, b=0.1, c=4, d=5.0, e=6)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
some_method(a=5.0, b=0.1, c=4, d=5, e=6)
with self.assertRaises(expected_exception=PedanticTypeCheckException):
some_method(a=5, b=0, c=4, d=5, e=6)
def test_args_kwargs_different_types(self):
@pedantic
def foo(*args: str, **kwds: int) -> None:
print(args)
print(kwds)
foo('a', 'b', 'c')
foo(x=1, y=2)
foo('', z=0)
def test_pedantic_on_class(self):
with self.assertRaises(expected_exception=PedanticTypeCheckException):
@pedantic
class MyClass:
pass
MyClass()
def test_is_subtype_tuple(self):
with self.assertRaises(expected_exception=PedanticTypeCheckException):
@pedantic
def foo() -> Callable[[Tuple[float, str]], Tuple[int]]:
def bar(a: Tuple[float]) -> Tuple[int]:
return len(a[1]) + int(a[0]),
return bar
foo()
def test_is_subtype_tuple_corrected(self):
@pedantic
def foo() -> Callable[[Tuple[float, str]], Tuple[int]]:
def bar(a: Tuple[float, str]) -> Tuple[int]:
return len(a[1]) + int(a[0]),
return bar
foo()
def test_forward_ref(self):
class Conversation:
pass
@pedantic
def get_conversations() -> List['Conversation']:
return [Conversation(), Conversation()]
get_conversations()
def test_alternative_list_type_hint(self):
@pedantic
def _is_digit_in_int(digit: [int], num: int) -> bool:
num_str = str(num)
for i in num_str:
if int(i) == digit:
return True
return False
with self.assertRaises(expected_exception=PedanticTypeCheckException):
_is_digit_in_int(digit=4, num=42)
def test_callable_with_union_return(self):
class MyClass:
pass
@pedantic
def admin_required(func: Callable[..., Union[str, MyClass]]) -> Callable[..., Union[str, MyClass]]:
@wraps(func)
def decorated_function(*args, **kwargs):
return func(*args, **kwargs)
return decorated_function
@admin_required
@pedantic
def get_server_info() -> str:
return 'info'
get_server_info()
def test_pedantic(self):
@pedantic
def foo(a: int, b: str) -> str:
return 'abc'
self.assertEqual('abc', foo(a=4, b='abc'))
def test_pedantic_always(self):
@pedantic
def foo(a: int, b: str) -> str:
return 'abc'
self.assertEqual('abc', foo(a=4, b='abc'))
def test_pedantic_arguments_fail(self):
@pedantic
def foo(a: int, b: str) -> str:
return 'abc'
with self.assertRaises(expected_exception=PedanticTypeCheckException):
foo(a=4, b=5)
def test_pedantic_return_type_fail(self):
@pedantic
def foo(a: int, b: str) -> str:
return 6
with self.assertRaises(expected_exception=PedanticTypeCheckException):
foo(a=4, b='abc')
def test_return_type_none(self):
@pedantic
def foo() -> None:
return 'a'
with self.assertRaises(expected_exception=PedanticTypeCheckException):
foo()
def test_marco(self):
@pedantic_class
class A:
def __init__(self, val: int) -> None:
self.val = val
def __eq__(self, other: 'A') -> bool: # other: A and all subclasses
return self.val == other.val
@pedantic_class
class B(A):
def __init__(self, val: int) -> None:
super().__init__(val=val)
@pedantic_class
class C(A):
def __init__(self, val: int) -> None:
super().__init__(val=val)
a = A(val=42)
b = B(val=42)
c = C(val=42)
assert a == b # works
assert a == c # works
assert b == c # error
def test_date_datetime(self):
@pedantic
def foo(a: datetime, b: date) -> None:
pass
foo(a=datetime(1995, 2, 5), b=date(1987, 8, 7))
foo(a=datetime(1995, 2, 5), b=datetime(1987, 8, 7))
with self.assertRaises(expected_exception=PedanticTypeCheckException):
foo(a=date(1995, 2, 5), b=date(1987, 8, 7))
def test_any_type(self):
@pedantic
def foo(a: Any) -> None:
pass
foo(a='aa')
def test_callable_exact_arg_count(self):
@pedantic
def foo(a: Callable[[int, str], int]) -> None:
pass
def some_callable(x: int, y: str) -> int:
pass
foo(a=some_callable)
def test_callable_bad_type(self):
@pedantic
def foo(a: Callable[..., int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=5)
def test_callable_too_few_arguments(self):
@pedantic
def foo(a: Callable[[int, str], int]) -> None:
pass
def some_callable(x: int) -> int:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=some_callable)
def test_callable_mandatory_kwonlyargs(self):
@pedantic
def foo(a: Callable[[int, str], int]) -> None:
pass
def some_callable(x: int, y: str, *, z: float, bar: str) -> int:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=some_callable)
def test_callable_class(self):
"""
Test that passing a class as a callable does not count the "self" argument "a"gainst the
ones declared in the Callable specification.
"""
@pedantic
def foo(a: Callable[[int, str], Any]) -> None:
pass
class SomeClass:
def __init__(self, x: int, y: str):
pass
foo(a=SomeClass)
def test_callable_plain(self):
@pedantic
def foo(a: Callable[..., Any]) -> None:
pass
def callback(a):
pass
foo(a=callback)
def test_callable_bound_method(self):
@pedantic
def foo(callback: Callable[[int], Any]) -> None:
pass
foo(callback=Child().method)
def test_callable_defaults(self):
"""
Test that a callable having "too many" arguments don't raise an error if the extra
arguments have default values.
"""
@pedantic
def foo(callback: Callable[[int, str], Any]) -> None:
pass
def some_callable(x: int, y: str, z: float = 1.2) -> int:
pass
foo(callback=some_callable)
def test_callable_builtin(self):
@pedantic
def foo(callback: types.BuiltinFunctionType) -> None:
pass
foo(callback=[].append)
def test_dict_bad_type(self):
@pedantic
def foo(a: Dict[str, int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=5)
def test_dict_bad_key_type(self):
@pedantic
def foo(a: Dict[str, int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a={1: 2})
def test_dict_bad_value_type(self):
@pedantic
def foo(a: Dict[str, int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a={'x': 'a'})
def test_list_bad_type(self):
@pedantic
def foo(a: List[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=5)
def test_list_bad_element(self):
@pedantic
def foo(a: List[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=[1, 2, 'bb'])
def test_sequence_bad_type(self):
@pedantic
def foo(a: Sequence[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=5)
def test_sequence_bad_element(self):
@pedantic
def foo(a: Sequence[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=[1, 2, 'bb'])
def test_abstractset_custom_type(self):
T = TypeVar('T')
@pedantic_class
class DummySet(AbstractSet[T]):
def __contains__(self, x: object) -> bool:
return x == 1
def __len__(self) -> T:
return 1
def __iter__(self) -> Iterator[T]:
yield 1
@pedantic
def foo(a: AbstractSet[int]) -> None:
pass
foo(a=DummySet[int]())
def test_abstractset_bad_type(self):
@pedantic
def foo(a: AbstractSet[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=5)
def test_set_bad_type(self):
@pedantic
def foo(a: Set[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=5)
def test_abstractset_bad_element(self):
@pedantic
def foo(a: AbstractSet[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a={1, 2, 'bb'})
def test_set_bad_element(self):
@pedantic
def foo(a: Set[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a={1, 2, 'bb'})
def test_tuple_bad_type(self):
@pedantic
def foo(a: Tuple[int]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=5)
def test_tuple_too_many_elements(self):
@pedantic
def foo(a: Tuple[int, str]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=(1, 'aa', 2))
def test_tuple_too_few_elements(self):
@pedantic
def foo(a: Tuple[int, str]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=(1,))
def test_tuple_bad_element(self):
@pedantic
def foo(a: Tuple[int, str]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=(1, 2))
def test_tuple_ellipsis_bad_element(self):
@pedantic
def foo(a: Tuple[int, ...]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=(1, 2, 'blah'))
def test_namedtuple(self):
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
@pedantic
def foo(bar: Employee) -> None:
print(bar)
foo(bar=Employee('bob', 1))
def test_namedtuple_key_mismatch(self):
Employee1 = NamedTuple('Employee', [('name', str), ('id', int)])
Employee2 = NamedTuple('Employee', [('firstname', str), ('id', int)])
@pedantic
def foo(bar: Employee1) -> None:
print(bar)
with self.assertRaises(PedanticTypeCheckException):
foo(bar=Employee2('bob', 1))
def test_namedtuple_type_mismatch(self):
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
@pedantic
def foo(bar: Employee) -> None:
print(bar)
with self.assertRaises(PedanticTypeCheckException):
foo(bar=('bob', 1))
def test_namedtuple_huge_type_mismatch(self):
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
@pedantic
def foo(bar: int) -> None:
print(bar)
with self.assertRaises(PedanticTypeCheckException):
foo(bar=foo(bar=Employee('bob', 1)))
def test_namedtuple_wrong_field_type(self):
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
@pedantic
def foo(bar: Employee) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(bar=Employee(2, 1))
def test_union(self):
@pedantic
def foo(a: Union[str, int]) -> None:
pass
for value in [6, 'xa']:
foo(a=value)
def test_union_new_syntax(self):
@pedantic
def foo(a: str | int) -> None:
pass
for value in [6, 'xa']:
foo(a=value)
with self.assertRaises(PedanticTypeCheckException):
foo(a=1.7)
def test_union_typing_type(self):
@pedantic
def foo(a: Union[str, Collection]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=1)
def test_union_fail(self):
@pedantic
def foo(a: Union[str, int]) -> None:
pass
for value in [5.6, b'xa']:
with self.assertRaises(PedanticTypeCheckException):
foo(a=value)
def test_type_var_constraints(self):
T = TypeVar('T', int, str)
@pedantic
def foo(a: T, b: T) -> None:
pass
for values in [
{'a': 6, 'b': 7},
{'a': 'aa', 'b': "bb"},
]:
foo(**values)
def test_type_var_constraints_fail_typing_type(self):
T = TypeVar('T', int, Collection)
@pedantic
def foo(a: T, b: T) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a='aa', b='bb')
def test_typevar_constraints_fail(self):
T = TypeVar('T', int, str)
@pedantic
def foo(a: T, b: T) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=2.5, b='aa')
def test_typevar_bound(self):
T = TypeVar('T', bound=Parent)
@pedantic
def foo(a: T, b: T) -> None:
pass
foo(a=Child(), b=Child())
def test_type_var_bound_fail(self):
T = TypeVar('T', bound=Child)
@pedantic
def foo(a: T, b: T) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=Parent(), b=Parent())
def test_type_var_invariant_fail(self):
T = TypeVar('T', int, str)
@pedantic
def foo(a: T, b: T) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=2, b=3.6)
def test_type_var_covariant(self):
T = TypeVar('T', covariant=True)
@pedantic
def foo(a: T, b: T) -> None:
pass
foo(a=Parent(), b=Child())
def test_type_var_covariant_fail(self):
T = TypeVar('T', covariant=True)
@pedantic
def foo(a: T, b: T) -> None:
pass
with self.assertRaises(PedanticTypeVarMismatchException):
foo(a=Child(), b=Parent())
def test_type_var_contravariant(self):
T = TypeVar('T', contravariant=True)
@pedantic
def foo(a: T, b: T) -> None:
pass
foo(a=Child(), b=Parent())
def test_type_var_contravariant_fail(self):
T = TypeVar('T', contravariant=True)
@pedantic
def foo(a: T, b: T) -> None:
pass
with self.assertRaises(PedanticTypeVarMismatchException):
foo(a=Parent(), b=Child())
def test_class_bad_subclass(self):
@pedantic
def foo(a: Type[Child]) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=Parent)
def test_class_any(self):
@pedantic
def foo(a: Type[Any]) -> None:
pass
foo(a=str)
def test_wrapped_function(self):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@pedantic
@decorator
def foo(a: 'Child') -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=Parent())
def test_mismatching_default_type(self):
@pedantic
def foo(a: str = 1) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo()
def test_implicit_default_none(self):
"""
Test that if the default value is ``None``, a ``None`` argument can be passed.
"""
@pedantic
def foo(a: Optional[str] = None) -> None:
pass
foo()
def test_generator_simple(self):
"""Test that argument type checking works in a generator function too."""
@pedantic
def generate(a: int) -> Generator[int, int, None]:
yield a
yield a + 1
gen = generate(a=1)
next(gen)
def test_wrapped_generator_no_return_type_annotation(self):
"""Test that return type checking works in a generator function too."""
@pedantic
def generate(a: int) -> Generator[int, int, None]:
yield a
yield a + 1
gen = generate(a=1)
next(gen)
def test_varargs(self):
@pedantic
def foo(*args: int) -> None:
pass
foo(1, 2)
def test_varargs_fail(self):
@pedantic
def foo(*args: int) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(1, 'a')
def test_kwargs(self):
@pedantic
def foo(**kwargs: int) -> None:
pass
foo(a=1, b=2)
def test_kwargs_fail(self):
@pedantic
def foo(**kwargs: int) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=1, b='a')
def test_generic(self):
T_Foo = TypeVar('T_Foo')
class FooGeneric(Generic[T_Foo]):
pass
@pedantic
def foo(a: FooGeneric[str]) -> None:
print(a)
foo(a=FooGeneric[str]())
def test_newtype(self):
myint = NewType("myint", int)
@pedantic
def foo(a: myint) -> int:
return 42
assert foo(a=1) == 42
with self.assertRaises(PedanticTypeCheckException):
foo(a="a")
def test_collection(self):
@pedantic
def foo(a: Collection) -> None:
pass
with self.assertRaises(PedanticTypeCheckException):
foo(a=True)
def test_binary_io(self):
@pedantic
def foo(a: BinaryIO) -> None:
print(a)
foo(a=BytesIO())
def test_text_io(self):
@pedantic
def foo(a: TextIO) -> None:
print(a)
foo(a=StringIO())
def test_binary_io_fail(self):
@pedantic
def foo(a: TextIO) -> None:
print(a)
with self.assertRaises(PedanticTypeCheckException):
foo(a=BytesIO())
def test_text_io_fail(self):
@pedantic
def foo(a: BinaryIO) -> None:
print(a)
with self.assertRaises(PedanticTypeCheckException):
foo(a=StringIO())
def test_binary_io_real_file(self):
@pedantic
def foo(a: BinaryIO) -> None:
print(a)
with open(file=TEST_FILE, mode='wb') as f:
foo(a=f)
def test_text_io_real_file(self):
@pedantic
def foo(a: TextIO) -> None:
print(a)
with open(file=TEST_FILE, mode='w') as f:
foo(a=f)
def test_pedantic_return_type_var_fail(self):
T = TypeVar('T', int, float)
@pedantic
def foo(a: T, b: T) -> T:
return 'a'
with self.assertRaises(PedanticTypeCheckException):
foo(a=4, b=2)
def test_callable(self):
@pedantic
def foo_1(a: Callable[..., int]) -> None:
print(a)
@pedantic
def foo_2(a: Callable) -> None:
print(a)
def some_callable() -> int:
return 4
foo_1(a=some_callable)
with self.assertRaises(PedanticTypeCheckException):
foo_2(a=some_callable)
def test_list(self):
@pedantic
def foo_1(a: List[int]) -> None:
print(a)
@pedantic
def foo_2(a: List) -> None:
print(a)
@pedantic
def foo_3(a: list) -> None:
print(a)
@pedantic
def foo_4(a: list[int]) -> None:
print(a)
foo_1(a=[1, 2])
with self.assertRaises(PedanticTypeCheckException):
foo_2(a=[1, 2])
with self.assertRaises(PedanticTypeCheckException):
foo_3(a=[1, 2])
foo_4(a=[1, 2])
def test_dict(self):
@pedantic
def foo_1(a: Dict[str, int]) -> None:
print(a)
@pedantic
def foo_2(a: Dict) -> None:
print(a)
@pedantic
def foo_3(a: dict) -> None:
print(a)
@pedantic
def foo_4(a: dict[str, int]) -> None:
print(a)
foo_1(a={'x': 2})
with self.assertRaises(PedanticTypeCheckException):
foo_2(a={'x': 2})
with self.assertRaises(PedanticTypeCheckException):
foo_3(a={'x': 2})
foo_4(a={'x': 2})
def test_sequence(self):
@pedantic
def foo(a: Sequence[str]) -> None:
print(a)
for value in [('a', 'b'), ['a', 'b'], 'abc']:
foo(a=value)
def test_sequence_no_type_args(self):
@pedantic
def foo(a: Sequence) -> None:
print(a)
for value in [('a', 'b'), ['a', 'b'], 'abc']:
with self.assertRaises(PedanticTypeCheckException):
foo(a=value)
def test_iterable(self):
@pedantic
def foo(a: Iterable[str]) -> None:
print(a)
for value in [('a', 'b'), ['a', 'b'], 'abc']:
foo(a=value)
def test_iterable_no_type_args(self):
@pedantic
def foo(a: Iterable) -> None:
print(a)
for value in [('a', 'b'), ['a', 'b'], 'abc']:
with self.assertRaises(PedanticTypeCheckException):
foo(a=value)
def test_container(self):
@pedantic
def foo(a: Container[str]) -> None:
print(a)
for value in [('a', 'b'), ['a', 'b'], 'abc']:
foo(a=value)
def test_container_no_type_args(self):
@pedantic
def foo(a: Container) -> None:
print(a)
for value in [('a', 'b'), ['a', 'b'], 'abc']:
with self.assertRaises(PedanticTypeCheckException):
foo(a=value)
def test_set(self):
@pedantic
def foo_1(a: AbstractSet[int]) -> None:
print(a)
@pedantic
def foo_2(a: Set[int]) -> None:
print(a)
for value in [set(), {6}]:
foo_1(a=value)
foo_2(a=value)
def test_set_no_type_args(self):
@pedantic
def foo_1(a: AbstractSet) -> None:
print(a)
@pedantic
def foo_2(a: Set) -> None:
print(a)
@pedantic
def foo_3(a: set) -> None:
print(a)
for value in [set(), {6}]:
with self.assertRaises(PedanticTypeCheckException):
foo_1(a=value)
with self.assertRaises(PedanticTypeCheckException):
foo_2(a=value)
with self.assertRaises(PedanticTypeCheckException):
foo_3(a=value)
def test_tuple(self):
@pedantic
def foo_1(a: Tuple[int, int]) -> None:
print(a)
@pedantic
def foo_2(a: Tuple[int, ...]) -> None:
print(a)
foo_1(a=(1, 2))
foo_2(a=(1, 2))
def test_tuple_no_type_args(self):
@pedantic
def foo_1(a: Tuple) -> None:
print(a)
@pedantic
def foo_2(a: tuple) -> None:
print(a)
with self.assertRaises(PedanticTypeCheckException):
foo_1(a=(1, 2))
with self.assertRaises(PedanticTypeCheckException):
foo_2(a=(1, 2))
def test_empty_tuple(self):
@pedantic
def foo(a: Tuple[()]) -> None:
print(a)
with self.assertRaises(PedanticTypeCheckException):
foo(a=())
def test_class(self):
@pedantic
def foo_1(a: Type[Parent]) -> None:
print(a)
@pedantic
def foo_2(a: Type[TypeVar('UnboundType')]) -> None:
print(a)
@pedantic
def foo_3(a: Type[TypeVar('BoundType', bound=Parent)]) -> None:
print(a)
foo_1(a=Child)
foo_2(a=Child)
foo_3(a=Child)
def test_class_no_type_vars(self):
@pedantic
def foo_1(a: Type) -> None:
print(a)
@pedantic
def foo_2(a: type) -> None:
print(a)
with self.assertRaises(PedanticTypeCheckException):
foo_1(a=Child)
with self.assertRaises(PedanticTypeCheckException):
foo_2(a=Child)
def test_class_not_a_class(self):
@pedantic
def foo(a: Type[Parent]) -> None:
print(a)
with self.assertRaises(PedanticTypeCheckException):
foo(a=1)
def test_complex(self):
@pedantic
def foo(a: complex) -> None:
print(a)
foo(a=complex(1, 5))
with self.assertRaises(PedanticTypeCheckException):
foo(a=1.0)
def test_float(self):
@pedantic
def foo(a: float) -> None:
print(a)
foo(a=1.5)
with self.assertRaises(PedanticTypeCheckException):
foo(a=1)
def test_coroutine_correct_return_type(self):
@pedantic
async def foo() -> str:
return 'foo'
coro = foo()
with self.assertRaises(StopIteration):
coro.send(None)
def test_coroutine_wrong_return_type(self):
@pedantic
async def foo() -> str:
return 1
coro = foo()
with self.assertRaises(PedanticTypeCheckException):
coro.send(None)
def test_bytearray_bytes(self):
@pedantic
def foo(x: bytearray) -> None:
pass
foo(x=bytearray([1]))
def test_class_decorator(self):
@pedantic_class
class Foo:
@staticmethod
def staticmethod() -> int:
return 'foo'
@classmethod
def classmethod(cls) -> int:
return 'foo'
def method(self) -> int:
return 'foo'
with self.assertRaises(PedanticTypeCheckException):
Foo.staticmethod()
with self.assertRaises(PedanticTypeCheckException):
Foo.classmethod()
with self.assertRaises(PedanticTypeCheckException):
Foo().method()
def test_generator(self):
@pedantic
def genfunc() -> Generator[int, str, List[str]]:
val1 = yield 2
val2 = yield 3
val3 = yield 4
return [val1, val2, val3]
gen = genfunc()
with self.assertRaises(StopIteration):
value = next(gen)
while True:
value = gen.send(str(value))
assert isinstance(value, int)
def test_generator_no_type_args(self):
@pedantic
def genfunc() -> Generator:
val1 = yield 2
val2 = yield 3
val3 = yield 4
return [val1, val2, val3]
with self.assertRaises(PedanticTypeCheckException):
genfunc()
def test_iterator(self):
@pedantic
def genfunc() -> Iterator[int]:
val1 = yield 2
val2 = yield 3
val3 = yield 4
return [val1, val2, val3]
gen = genfunc()
with self.assertRaises(PedanticTypeCheckException):
value = next(gen)
while True:
value = gen.send(str(value))
assert isinstance(value, int)
def test_iterator_no_type_args(self):
@pedantic
def genfunc() -> Iterator:
val1 = yield 2
val2 = yield 3
val3 = yield 4
return [val1, val2, val3]
with self.assertRaises(PedanticTypeCheckException):
genfunc()
def test_iterable_advanced(self):
@pedantic
def genfunc() -> Iterable[int]:
val1 = yield 2
val2 = yield 3
val3 = yield 4
return [val1, val2, val3]
gen = genfunc()
with self.assertRaises(PedanticTypeCheckException):
value = next(gen)
while True:
value = gen.send(str(value))
assert isinstance(value, int)
def test_iterable_advanced_no_type_args(self):
@pedantic
def genfunc() -> Iterable:
val1 = yield 2
val2 = yield 3
val3 = yield 4
return [val1, val2, val3]
with self.assertRaises(PedanticTypeCheckException):
genfunc()
def test_generator_bad_yield(self):
@pedantic
def genfunc_1() -> Generator[int, str, None]:
yield 'foo'
@pedantic
def genfunc_2() -> Iterable[int]:
yield 'foo'
@pedantic
def genfunc_3() -> Iterator[int]:
yield 'foo'
gen = genfunc_1()
with self.assertRaises(PedanticTypeCheckException):
next(gen)
gen = genfunc_2()
with self.assertRaises(PedanticTypeCheckException):
next(gen)
gen = genfunc_3()
with self.assertRaises(PedanticTypeCheckException):
next(gen)
def test_generator_bad_send(self):
@pedantic
def genfunc() -> Generator[int, str, None]:
yield 1
yield 2
gen = genfunc()
next(gen)
with self.assertRaises(PedanticTypeCheckException):
gen.send(2)
def test_generator_bad_return(self):
@pedantic
def genfunc() -> Generator[int, str, str]:
yield 1
return 6
gen = genfunc()
next(gen)
with self.assertRaises(PedanticTypeCheckException):
gen.send('foo')
def test_return_generator(self):
@pedantic
def genfunc() -> Generator[int, None, None]:
yield 1
@pedantic
def foo() -> Generator[int, None, None]:
return genfunc()
foo()
def test_local_class(self):
@pedantic_class
class LocalClass:
class Inner:
pass
def create_inner(self) -> 'Inner':
return self.Inner()
retval = LocalClass().create_inner()
assert isinstance(retval, LocalClass.Inner)
def test_local_class_async(self):
@pedantic_class
class LocalClass:
class Inner:
pass
async def create_inner(self) -> 'Inner':
return self.Inner()
coro = LocalClass().create_inner()
with self.assertRaises(StopIteration):
coro.send(None)
def test_callable_nonmember(self):
class CallableClass:
def __call__(self):
pass
@pedantic_class
class LocalClass:
some_callable = CallableClass()
def test_inherited_class_method(self):
@pedantic_class
class Parent:
@classmethod
def foo(cls, x: str) -> str:
return cls.__name__
@pedantic_class
class Child(Parent):
pass
self.assertEqual('Parent', Child.foo(x='bar'))
with self.assertRaises(PedanticTypeCheckException):
Child.foo(x=1)
def test_type_var_forward_ref_bound(self):
TBound = TypeVar('TBound', bound='Parent')
@pedantic
def func(x: TBound) -> None:
pass
func(x=Parent())
with self.assertRaises(PedanticTypeCheckException):
func(x='foo')
def test_noreturn(self):
@pedantic
def foo() -> NoReturn:
pass
@pedantic
def bar() -> NoReturn:
raise ZeroDivisionError('bar')
with self.assertRaises(expected_exception=ZeroDivisionError):
bar()
with self.assertRaises(PedanticTypeCheckException):
foo()
def test_literal(self):
@pedantic
def foo(a: Literal[1, True, 'x', b'y', 404]) -> None:
print(a)
foo(a=404)
foo(a=True)
foo(a='x')
with self.assertRaises(PedanticTypeCheckException):
foo(a=4)
def test_literal_union(self):
@pedantic
def foo(a: Union[str, Literal[1, 6, 8]]) -> None:
print(a)
foo(a=6)
with self.assertRaises(PedanticTypeCheckException):
foo(a=4)
def test_literal_illegal_value(self):
@pedantic
def foo(a: Literal[1, 1.1]) -> None:
print(a)
with self.assertRaises(PedanticTypeCheckException):
foo(a=4)
def test_enum(self):
with self.assertRaises(PedanticTypeCheckException):
@pedantic_class
class MyEnum(Enum):
A = 'a'
def test_enum_aggregate(self):
T = TypeVar('T', bound=IntEnum)
@pedantic_class
class EnumAggregate(Generic[T]):
enum: ClassVar[Type[T]]
def __init__(self, value: Union[int, str, List[T]]) -> None:
assert len(self.enum) < 10
if value == '':
raise ValueError(f'Parameter "value" cannot be empty!')
if isinstance(value, list):
self._value = ''.join([str(x.value) for x in value])
else:
self._value = str(value)
self._value = ''.join(sorted(self._value)) # sort characters in string
self.to_list() # check if is valid
def __contains__(self, item: T) -> bool:
return item in self.to_list()
def __eq__(self, other: Union['EnumAggregate', str]) -> bool:
if isinstance(other, str):
return self._value == other
return self._value == other._value
def __str__(self) -> str:
return self._value
def to_list(self) -> List[T]:
return [self.enum(int(character)) for character in self._value]
@property
def value(self) -> str:
return self._value
@classmethod
def all(cls) -> str:
return ''.join([str(x.value) for x in cls.enum])
class Gender(IntEnum):
MALE = 1
FEMALE = 2
DIVERS = 3
@pedantic_class
class Genders(EnumAggregate[Gender]):
enum = Gender
Genders(value=12)
with self.assertRaises(PedanticTypeCheckException):
Genders(value=Child())
def test_primitive_list_dict_tuple(self):
@pedantic
def f(x: list[dict[int, tuple[float, str]]]) -> list[Any]:
return x
f(x=[{3: (3.24, 'hi')}])
for value in [
[{3, (3, 'hi')}],
[{3: (3, 'hi')}],
[{3: (3.24, 3)}],
[{3: (3.24, 'hi')}, {0}],
]:
with self.assertRaises(PedanticTypeCheckException):
f(x=value)
def test_dataclass_protocol(self):
class IsDataclass(typing.Protocol):
__dataclass_fields__: ClassVar[Dict]
@dataclass
class Foo:
v: int
@pedantic
def foo(x: IsDataclass) -> IsDataclass:
return x
foo(x=Foo(v=42))
def test_dataclass_protocol_in_type(self):
class IsDataclass(typing.Protocol):
__dataclass_fields__: ClassVar[Dict]
@dataclass
class Foo:
v: int
@pedantic
def foo(x: type[IsDataclass]) -> IsDataclass:
return x
assert foo(x=Foo) == Foo
def test_dataclass_protocol_in_type_with_union(self):
class IsDataclass(typing.Protocol):
__dataclass_fields__: ClassVar[Dict]
@dataclass
class Foo:
v: int
@pedantic
def foo(x: type[None | bool | IsDataclass]) -> IsDataclass:
return x
assert foo(x=Foo) == Foo
Classes
class Child
-
Expand source code
class Child(Parent): def method(self, a: int): pass
Ancestors
Methods
def method(self, a:Â int)
-
Expand source code
def method(self, a: int): pass
class Parent
-
Expand source code
class Parent: pass
Subclasses
class TestDecoratorRequireKwargsAndTypeCheck (methodName='runTest')
-
A class whose instances are single test cases.
By default, the test code itself should be placed in a method named 'runTest'.
If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase subclass, specify in the constructor arguments the name of the test method that the instance is to execute.
Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment ('fixture') can be implemented by overriding the 'setUp' and 'tearDown' methods respectively.
If it is necessary to override the init method, the base class init method must always be called. It is important that subclasses should not change the signature of their init method, since instances of the classes are instantiated automatically by parts of the framework in order to be run.
When subclassing TestCase, you can set these attributes: * failureException: determines which exception will be raised when the instance's assertion methods fail; test methods raising this exception will be deemed to have 'failed' rather than 'errored'. * longMessage: determines whether long messages (including repr of objects used in assert methods) will be printed on failure in addition to any explicit message passed. * maxDiff: sets the maximum length of a diff in failure messages by assert methods using difflib. It is looked up as an instance attribute so can be configured by individual tests if required.
Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name.
Expand source code
class TestDecoratorRequireKwargsAndTypeCheck(unittest.TestCase): def tearDown(self) -> None: if os.path.isfile(TEST_FILE): os.remove(TEST_FILE) def test_no_kwargs(self): @pedantic def calc(n: int, m: int, i: int) -> int: return n + m + i with self.assertRaises(expected_exception=PedanticCallWithArgsException): calc(42, 40, 38) with self.assertRaises(expected_exception=PedanticCallWithArgsException): calc(42, m=40, i=38) calc(n=42, m=40, i=38) def test_nested_type_hints_1(self): @pedantic def calc(n: int) -> List[List[float]]: return [0.0 * n] with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42) def test_nested_type_hints_1_corrected(self): @pedantic def calc(n: int) -> List[List[float]]: return [[0.0 * n]] calc(n=42) def test_nested_type_hints_2(self): """Problem here: int != float""" @pedantic def calc(n: int) -> List[Tuple[float, str]]: return [(n, str(n))] with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42) def test_nested_type_hints_2_corrected(self): @pedantic def calc(n: int) -> List[Tuple[int, str]]: return [(n, str(n))] @pedantic def calc_2(n: float) -> List[Tuple[float, str]]: return [(n, str(n))] calc(n=42) calc_2(n=42.0) def test_nested_type_hints_3(self): """Problem here: inner function actually returns Tuple[int, str]""" @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, str]]: @pedantic def f(x: int, y: float) -> Tuple[float, str]: return n * x, str(y) return f with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42)(x=3, y=3.14) def test_nested_type_hints_3_corrected(self): @pedantic def calc(n: int) -> Callable[[int, float], Tuple[int, str]]: @pedantic def f(x: int, y: float) -> Tuple[int, str]: return n * x, str(y) return f calc(n=42)(x=3, y=3.14) def test_nested_type_hints_4(self): """Problem here: return type is actually float""" @pedantic def calc(n: List[List[float]]) -> int: return n[0][0] with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=[[42.0]]) def test_nested_type_hints_corrected(self): @pedantic def calc(n: List[List[float]]) -> int: return int(n[0][0]) calc(n=[[42.0]]) def test_nested_type_hints_5(self): """Problem here: Tuple[float, str] != Tuple[float, float]""" @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, str]]: @pedantic def f(x: int, y: float) -> Tuple[float, float]: return n * float(x), y return f with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42) def test_nested_type_hints_5_corrected(self): @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, float]]: @pedantic def f(x: int, y: float) -> Tuple[float, float]: return n * float(x), y return f calc(n=42) def test_missing_type_hint_1(self): """Problem here: type hint for n missed""" @pedantic def calc(n) -> float: return 42.0 * n with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42) def test_missing_type_hint_1_corrected(self): @pedantic def calc(n: int) -> float: return 42.0 * n calc(n=42) def test_missing_type_hint_2(self): """Problem here: Return type annotation missed""" @pedantic def calc(n: int): return 'Hi' + str(n) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42) def test_missing_type_hint_2_corrected(self): @pedantic def calc(n: int) -> str: return 'Hi' + str(n) calc(n=42) def test_missing_type_hint_3(self): """Problem here: type hint for i missed""" @pedantic def calc(n: int, m: int, i) -> int: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38) def test_missing_type_hint_3_corrected(self): @pedantic def calc(n: int, m: int, i: int) -> int: return n + m + i calc(n=42, m=40, i=38) def test_all_ok_2(self): @pedantic def calc(n: int, m: int, i: int) -> str: return str(n + m + i) calc(n=42, m=40, i=38) def test_all_ok_3(self): @pedantic def calc(n: int, m: int, i: int) -> None: str(n + m + i) calc(n=42, m=40, i=38) def test_all_ok_4(self): @pedantic def calc(n: int) -> List[List[int]]: return [[n]] calc(n=42) def test_all_ok_5(self): @pedantic def calc(n: int) -> List[Tuple[float, str]]: return [(float(n), str(n))] calc(n=42) def test_all_ok_6(self): @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, str]]: @pedantic def f(x: int, y: float) -> Tuple[float, str]: return n * float(x), str(y) return f calc(n=42)(x=72, y=3.14) def test_all_ok_7(self): @pedantic def calc(n: List[List[float]]) -> Any: return n[0][0] calc(n=[[42.0]]) def test_all_ok_8(self): @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, str]]: @pedantic def f(x: int, y: float) -> Tuple[float, str]: return n * float(x), str(y) return f calc(n=42)(x=3, y=3.14) def test_wrong_type_hint_1(self): """Problem here: str != int""" @pedantic def calc(n: int, m: int, i: int) -> str: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38) def test_wrong_type_hint_1_corrected(self): @pedantic def calc(n: int, m: int, i: int) -> str: return str(n + m + i) calc(n=42, m=40, i=38) def test_wrong_type_hint_2(self): """Problem here: str != int""" @pedantic def calc(n: int, m: int, i: str) -> int: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38) def test_wrong_type_hint_2_corrected(self): @pedantic def calc(n: int, m: int, i: str) -> int: return n + m + int(i) calc(n=42, m=40, i='38') def test_wrong_type_hint_3(self): """Problem here: None != int""" @pedantic def calc(n: int, m: int, i: int) -> None: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38) def test_wrong_type_hint_corrected(self): @pedantic def calc(n: int, m: int, i: int) -> None: print(n + m + i) calc(n=42, m=40, i=38) def test_wrong_type_hint_4(self): """Problem here: None != int""" @pedantic def calc(n: int, m: int, i: int) -> int: print(n + m + i) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38) def test_wrong_type_hint_4_corrected(self): @pedantic def calc(n: int, m: int, i: int) -> int: return n + m + i calc(n=42, m=40, i=38) def test_none_1(self): """Problem here: None is not accepted""" @pedantic def calc(n: int, m: int, i: int) -> int: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=None) def test_none_2(self): @pedantic def calc(n: int, m: int, i: Optional[int]) -> int: return n + m + i if i is not None else n + m calc(n=42, m=40, i=None) def test_none_3(self): @pedantic def calc(n: int, m: int, i: Union[int, None]) -> int: return n + m + i if i is not None else n + m calc(n=42, m=40, i=None) def test_none_4(self): """Problem here: function may return None""" @pedantic def calc(n: int, m: int, i: Union[int, None]) -> int: return n + m + i if i is not None else None calc(n=42, m=40, i=42) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=None) def test_none_5(self): @pedantic def calc(n: int, m: int, i: Union[int, None]) -> Optional[int]: return n + m + i if i is not None else None calc(n=42, m=40, i=None) def test_inheritance_1(self): class MyClassA: pass class MyClassB(MyClassA): pass @pedantic def calc(a: MyClassA) -> str: return str(a) calc(a=MyClassA()) calc(a=MyClassB()) def test_inheritance_2(self): """Problem here: A is not a subtype of B""" class MyClassA: pass class MyClassB(MyClassA): pass @pedantic def calc(a: MyClassB) -> str: return str(a) calc(a=MyClassB()) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(a=MyClassA()) def test_instance_method_1(self): class MyClassA: @pedantic def calc(self, i: int) -> str: return str(i) a = MyClassA() a.calc(i=42) def test_instance_method_2(self): """Problem here: 'i' has no type annotation""" class MyClassA: @pedantic def calc(self, i) -> str: return str(i) a = MyClassA() with self.assertRaises(expected_exception=PedanticTypeCheckException): a.calc(i=42) def test_instance_method_2_corrected(self): class MyClassA: @pedantic def calc(self, i: int) -> str: return str(i) a = MyClassA() a.calc(i=42) def test_instance_method_int_is_not_float(self): class MyClassA: @pedantic def calc(self, i: float) -> str: return str(i) a = MyClassA() with self.assertRaises(expected_exception=PedanticTypeCheckException): a.calc(i=42) def test_instance_method_3_corrected(self): class MyClassA: @pedantic def calc(self, i: float) -> str: return str(i) a = MyClassA() a.calc(i=42.0) def test_instance_method_no_kwargs(self): class MyClassA: @pedantic def calc(self, i: int) -> str: return str(i) a = MyClassA() with self.assertRaises(expected_exception=PedanticCallWithArgsException): a.calc(42) def test_instance_method_5(self): """Problem here: instance methods is not called with kwargs""" class MyClassA: @pedantic def calc(self, i: int) -> str: return str(i) a = MyClassA() a.calc(i=42) def test_lambda_1(self): @pedantic def calc(i: float) -> Callable[[float], str]: return lambda x: str(x * i) calc(i=42.0)(10.0) def test_lambda_3(self): @pedantic def calc(i: float) -> Callable[[float], str]: def res(x: float) -> str: return str(x * i) return res calc(i=42.0)(10.0) def test_lambda_int_is_not_float(self): @pedantic def calc(i: float) -> Callable[[float], str]: def res(x: int) -> str: return str(x * i) return res with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=42.0)(x=10) def test_lambda_4_almost_corrected(self): """Problem here: float != str""" @pedantic def calc(i: float) -> Callable[[float], str]: @pedantic def res(x: int) -> str: return str(x * i) return res with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=42.0)(x=10) def test_lambda_4_almost_corrected_2(self): @pedantic def calc(i: float) -> Callable[[int], str]: @pedantic def res(x: int) -> str: return str(x * i) return res calc(i=42.0)(x=10) def test_lambda_5(self): """Problem here: float != int""" @pedantic def calc(i: float) -> Callable[[float], str]: @pedantic def res(x: float) -> str: return str(x * i) return res with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=42.0)(x=10) def test_lambda_corrected(self): @pedantic def calc(i: float) -> Callable[[float], str]: @pedantic def res(x: float) -> str: return str(x * i) return res calc(i=42.0)(x=10.0) def test_tuple_without_type_args(self): @pedantic def calc(i: Tuple) -> str: return str(i) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=(42.0, 43, 'hi')) def test_tuple_without_args_corrected(self): @pedantic def calc(i: Tuple[Any, ...]) -> str: return str(i) calc(i=(42.0, 43, 'hi')) def test_callable_without_type_args(self): @pedantic def calc(i: Callable) -> str: return str(i(' you')) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=lambda x: (42.0, 43, 'hi', x)) def test_callable_without_args_correct_with_lambdas(self): @pedantic def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str: return str(i(x=' you')) calc(i=lambda x: (42.0, 43, 'hi', x)) def test_callable_without_args_corrected(self): @pedantic def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str: return str(i(x=' you')) @pedantic def arg(x: Any) -> Tuple[Any, ...]: return 42.0, 43, 'hi', x calc(i=arg) def test_list_without_args(self): @pedantic def calc(i: List) -> Any: return [i] with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=[42.0, 43, 'hi']) def test_list_without_args_corrected(self): @pedantic def calc(i: List[Any]) -> List[List[Any]]: return [i] calc(i=[42.0, 43, 'hi']) def test_ellipsis_in_callable_1(self): @pedantic def calc(i: Callable[..., int]) -> int: return i() @pedantic def call() -> int: return 42 calc(i=call) def test_ellipsis_in_callable_2(self): @pedantic def calc(i: Callable[..., int]) -> int: return i(x=3.14, y=5) @pedantic def call(x: float, y: int) -> int: return 42 calc(i=call) def test_ellipsis_in_callable_3(self): """Problem here: call to "call" misses one argument""" @pedantic def calc(i: Callable[..., int]) -> int: return i(x=3.14) @pedantic def call(x: float, y: int) -> int: return 42 with self.assertRaises(expected_exception=PedanticException): calc(i=call) def test_optional_args_1(self): @pedantic def calc(a: int, b: int = 42) -> int: return a + b calc(a=2) def test_optional_args_2(self): @pedantic def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float: return a + b + c calc() calc(a=1) calc(b=1) calc(c=1.0) calc(a=1, b=1) calc(a=1, c=1.0) calc(b=1, c=1.0) calc(a=1, b=1, c=1.0) def test_optional_args_3(self): """Problem here: optional argument c: 5 is not a float""" @pedantic def calc(a: int = 3, b: int = 42, c: float = 5) -> float: return a + b + c with self.assertRaises(expected_exception=PedanticTypeCheckException): calc() def test_optional_args_3_corrected(self): @pedantic def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float: return a + b + c calc() def test_optional_args_4(self): class MyClass: @pedantic def foo(self, a: int, b: Optional[int] = 1) -> int: return a + b my_class = MyClass() my_class.foo(a=10) def test_optional_args_5(self): @pedantic def calc(d: Optional[Dict[int, int]] = None) -> Optional[int]: if d is None: return None return sum(d.keys()) calc(d=None) calc() calc(d={42: 3}) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(d={42: 3.14}) def test_optional_args_6(self): """"Problem here: str != int""" @pedantic def calc(d: int = 42) -> int: return int(d) calc(d=99999) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(d='999999') def test_enum_1(self): """Problem here: Type hint for 'a' should be MyEnum instead of MyEnum.GAMMA""" class MyEnum(Enum): ALPHA = 'startEvent' BETA = 'task' GAMMA = 'sequenceFlow' class MyClass: @pedantic def operation(self, a: MyEnum.GAMMA) -> None: print(a) m = MyClass() with self.assertRaises(expected_exception=PedanticTypeCheckException): m.operation(a=MyEnum.GAMMA) def test_enum_1_corrected(self): class MyEnum(Enum): ALPHA = 'startEvent' BETA = 'task' GAMMA = 'sequenceFlow' @pedantic def operation(a: MyEnum) -> None: print(a) operation(a=MyEnum.GAMMA) def test_sloppy_types_dict(self): @pedantic def operation(d: dict) -> int: return len(d.keys()) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d={1: 1, 2: 2}) def test_sloppy_types_dict_almost_corrected_no_type_args(self): @pedantic def operation(d: Dict) -> int: return len(d.keys()) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d={1: 1, 2: 2}) def test_sloppy_types_dict_corrected(self): @pedantic def operation(d: Dict[int, int]) -> int: return len(d.keys()) operation(d={1: 1, 2: 2}) def test_sloppy_types_list(self): @pedantic def operation(d: list) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=[1, 2, 3, 4]) def test_sloppy_types_list_almost_corrected_no_type_args(self): @pedantic def operation(d: List) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=[1, 2, 3, 4]) def test_sloppy_types_list_corrected(self): @pedantic def operation(d: List[int]) -> int: return len(d) operation(d=[1, 2, 3, 4]) def test_sloppy_types_tuple(self): @pedantic def operation(d: tuple) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=(1, 2, 3)) def test_sloppy_types_tuple_almost_corrected_no_type_args(self): @pedantic def operation(d: Tuple) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=(1, 2, 3)) def test_sloppy_types_tuple_corrected(self): @pedantic def operation(d: Tuple[int, int, int]) -> int: return len(d) operation(d=(1, 2, 3)) def test_sloppy_types_set(self): @pedantic def operation(d: set) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d={1, 2, 3}) def test_sloppy_types_set_almost_corrected_to_type_args(self): @pedantic def operation(d: Set) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d={1, 2, 3}) def test_sloppy_types_set_corrected(self): @pedantic def operation(d: Set[int]) -> int: return len(d) operation(d={1, 2, 3}) def test_sloppy_types_frozenset(self): @pedantic def operation(d: frozenset) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=frozenset({1, 2, 3})) def test_sloppy_types_frozenset_almost_corrected_no_type_args(self): @pedantic def operation(d: FrozenSet) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=frozenset({1, 2, 3})) def test_sloppy_types_frozenset_corrected(self): @pedantic def operation(d: FrozenSet[int]) -> int: return len(d) operation(d=frozenset({1, 2, 3})) def test_type_list_but_got_tuple(self): @pedantic def calc(ls: List[Any]) -> int: return len(ls) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(ls=(1, 2, 3)) def test_type_list_corrected(self): @pedantic def calc(ls: Tuple[Any, ...]) -> int: return len(ls) calc(ls=(1, 2, 3)) def test_any(self): @pedantic def calc(ls: List[Any]) -> Dict[int, Any]: return {i: ls[i] for i in range(0, len(ls))} calc(ls=[1, 2, 3]) calc(ls=[1.11, 2.0, 3.0]) calc(ls=['1', '2', '3']) calc(ls=[10.5, '2', (3, 4, 5)]) def test_aliases(self): Vector = List[float] @pedantic def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector] scale(scalar=2.0, vector=[1.0, -4.2, 5.4]) def test_new_type(self): UserId = NewType('UserId', int) @pedantic def get_user_name(user_id: UserId) -> str: return str(user_id) some_id = UserId(524313) get_user_name(user_id=some_id) # the following would be desirable but impossible to check at runtime: # with self.assertRaises(expected_exception=AssertionError): # get_user_name(user_id=-1) def test_list_of_new_type(self): UserId = NewType('UserId', int) @pedantic def get_user_name(user_ids: List[UserId]) -> str: return str(user_ids) get_user_name(user_ids=[UserId(524313), UserId(42)]) with self.assertRaises(expected_exception=PedanticTypeCheckException): get_user_name(user_ids=[UserId(524313), UserId(42), 430.0]) def test_callable_no_args(self): @pedantic def f(g: Callable[[], str]) -> str: return g() @pedantic def greetings() -> str: return 'hello world' f(g=greetings) def test_type_var(self): T = TypeVar('T') @pedantic def first(ls: List[T]) -> T: return ls[0] first(ls=[1, 2, 3]) def test_type_var_wrong(self): T = TypeVar('T') @pedantic def first(ls: List[T]) -> T: return str(ls[0]) with self.assertRaises(expected_exception=PedanticTypeVarMismatchException): first(ls=[1, 2, 3]) def test_type_var_wrong_sequence(self): T = TypeVar('T') @pedantic def first(ls: Sequence[T]) -> T: return str(ls[0]) with self.assertRaises(expected_exception=PedanticTypeVarMismatchException): first(ls=[1, 2, 3]) def test_double_pedantic(self): @pedantic @pedantic def f(x: int, y: float) -> Tuple[float, str]: return float(x), str(y) f(x=5, y=3.14) with self.assertRaises(expected_exception=PedanticTypeCheckException): f(x=5.0, y=3.14) with self.assertRaises(expected_exception=PedanticCallWithArgsException): f(5, 3.14) def test_args_kwargs(self): @pedantic def some_method(a: int = 0, b: float = 0.0) -> float: return a * b @pedantic def wrapper_method(*args: Union[int, float], **kwargs: Union[int, float]) -> float: return some_method(*args, **kwargs) some_method() with self.assertRaises(expected_exception=PedanticCallWithArgsException): some_method(3, 3.0) some_method(a=3, b=3.0) wrapper_method() with self.assertRaises(expected_exception=PedanticCallWithArgsException): wrapper_method(3, 3.0) wrapper_method(a=3, b=3.0) def test_args_kwargs_no_type_hint(self): @pedantic def method_no_type_hint(*args, **kwargs) -> None: print(args) print(kwargs) with self.assertRaises(expected_exception=PedanticTypeCheckException): method_no_type_hint(a=3, b=3.0) with self.assertRaises(expected_exception=PedanticTypeCheckException): method_no_type_hint() def test_args_kwargs_wrong_type_hint(self): """See: https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values""" @pedantic def wrapper_method(*args: str, **kwargs: str) -> None: print(args) print(kwargs) wrapper_method() wrapper_method('hi', 'you', ':)') wrapper_method(a='hi', b='you', c=':)') with self.assertRaises(expected_exception=PedanticTypeCheckException): wrapper_method('hi', 'you', ':)', 7) with self.assertRaises(expected_exception=PedanticTypeCheckException): wrapper_method(3, 3.0) with self.assertRaises(expected_exception=PedanticTypeCheckException): wrapper_method(a=3, b=3.0) def test_additional_kwargs(self): @pedantic def some_method(a: int, b: float = 0.0, **kwargs: int) -> float: return sum([a, b]) some_method(a=5) some_method(a=5, b=0.1) some_method(a=5, b=0.1, c=4) some_method(a=5, b=0.1, c=4, d=5, e=6) with self.assertRaises(expected_exception=PedanticTypeCheckException): some_method(a=5, b=0.1, c=4, d=5.0, e=6) with self.assertRaises(expected_exception=PedanticTypeCheckException): some_method(a=5.0, b=0.1, c=4, d=5, e=6) with self.assertRaises(expected_exception=PedanticTypeCheckException): some_method(a=5, b=0, c=4, d=5, e=6) def test_args_kwargs_different_types(self): @pedantic def foo(*args: str, **kwds: int) -> None: print(args) print(kwds) foo('a', 'b', 'c') foo(x=1, y=2) foo('', z=0) def test_pedantic_on_class(self): with self.assertRaises(expected_exception=PedanticTypeCheckException): @pedantic class MyClass: pass MyClass() def test_is_subtype_tuple(self): with self.assertRaises(expected_exception=PedanticTypeCheckException): @pedantic def foo() -> Callable[[Tuple[float, str]], Tuple[int]]: def bar(a: Tuple[float]) -> Tuple[int]: return len(a[1]) + int(a[0]), return bar foo() def test_is_subtype_tuple_corrected(self): @pedantic def foo() -> Callable[[Tuple[float, str]], Tuple[int]]: def bar(a: Tuple[float, str]) -> Tuple[int]: return len(a[1]) + int(a[0]), return bar foo() def test_forward_ref(self): class Conversation: pass @pedantic def get_conversations() -> List['Conversation']: return [Conversation(), Conversation()] get_conversations() def test_alternative_list_type_hint(self): @pedantic def _is_digit_in_int(digit: [int], num: int) -> bool: num_str = str(num) for i in num_str: if int(i) == digit: return True return False with self.assertRaises(expected_exception=PedanticTypeCheckException): _is_digit_in_int(digit=4, num=42) def test_callable_with_union_return(self): class MyClass: pass @pedantic def admin_required(func: Callable[..., Union[str, MyClass]]) -> Callable[..., Union[str, MyClass]]: @wraps(func) def decorated_function(*args, **kwargs): return func(*args, **kwargs) return decorated_function @admin_required @pedantic def get_server_info() -> str: return 'info' get_server_info() def test_pedantic(self): @pedantic def foo(a: int, b: str) -> str: return 'abc' self.assertEqual('abc', foo(a=4, b='abc')) def test_pedantic_always(self): @pedantic def foo(a: int, b: str) -> str: return 'abc' self.assertEqual('abc', foo(a=4, b='abc')) def test_pedantic_arguments_fail(self): @pedantic def foo(a: int, b: str) -> str: return 'abc' with self.assertRaises(expected_exception=PedanticTypeCheckException): foo(a=4, b=5) def test_pedantic_return_type_fail(self): @pedantic def foo(a: int, b: str) -> str: return 6 with self.assertRaises(expected_exception=PedanticTypeCheckException): foo(a=4, b='abc') def test_return_type_none(self): @pedantic def foo() -> None: return 'a' with self.assertRaises(expected_exception=PedanticTypeCheckException): foo() def test_marco(self): @pedantic_class class A: def __init__(self, val: int) -> None: self.val = val def __eq__(self, other: 'A') -> bool: # other: A and all subclasses return self.val == other.val @pedantic_class class B(A): def __init__(self, val: int) -> None: super().__init__(val=val) @pedantic_class class C(A): def __init__(self, val: int) -> None: super().__init__(val=val) a = A(val=42) b = B(val=42) c = C(val=42) assert a == b # works assert a == c # works assert b == c # error def test_date_datetime(self): @pedantic def foo(a: datetime, b: date) -> None: pass foo(a=datetime(1995, 2, 5), b=date(1987, 8, 7)) foo(a=datetime(1995, 2, 5), b=datetime(1987, 8, 7)) with self.assertRaises(expected_exception=PedanticTypeCheckException): foo(a=date(1995, 2, 5), b=date(1987, 8, 7)) def test_any_type(self): @pedantic def foo(a: Any) -> None: pass foo(a='aa') def test_callable_exact_arg_count(self): @pedantic def foo(a: Callable[[int, str], int]) -> None: pass def some_callable(x: int, y: str) -> int: pass foo(a=some_callable) def test_callable_bad_type(self): @pedantic def foo(a: Callable[..., int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5) def test_callable_too_few_arguments(self): @pedantic def foo(a: Callable[[int, str], int]) -> None: pass def some_callable(x: int) -> int: pass with self.assertRaises(PedanticTypeCheckException): foo(a=some_callable) def test_callable_mandatory_kwonlyargs(self): @pedantic def foo(a: Callable[[int, str], int]) -> None: pass def some_callable(x: int, y: str, *, z: float, bar: str) -> int: pass with self.assertRaises(PedanticTypeCheckException): foo(a=some_callable) def test_callable_class(self): """ Test that passing a class as a callable does not count the "self" argument "a"gainst the ones declared in the Callable specification. """ @pedantic def foo(a: Callable[[int, str], Any]) -> None: pass class SomeClass: def __init__(self, x: int, y: str): pass foo(a=SomeClass) def test_callable_plain(self): @pedantic def foo(a: Callable[..., Any]) -> None: pass def callback(a): pass foo(a=callback) def test_callable_bound_method(self): @pedantic def foo(callback: Callable[[int], Any]) -> None: pass foo(callback=Child().method) def test_callable_defaults(self): """ Test that a callable having "too many" arguments don't raise an error if the extra arguments have default values. """ @pedantic def foo(callback: Callable[[int, str], Any]) -> None: pass def some_callable(x: int, y: str, z: float = 1.2) -> int: pass foo(callback=some_callable) def test_callable_builtin(self): @pedantic def foo(callback: types.BuiltinFunctionType) -> None: pass foo(callback=[].append) def test_dict_bad_type(self): @pedantic def foo(a: Dict[str, int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5) def test_dict_bad_key_type(self): @pedantic def foo(a: Dict[str, int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a={1: 2}) def test_dict_bad_value_type(self): @pedantic def foo(a: Dict[str, int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a={'x': 'a'}) def test_list_bad_type(self): @pedantic def foo(a: List[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5) def test_list_bad_element(self): @pedantic def foo(a: List[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=[1, 2, 'bb']) def test_sequence_bad_type(self): @pedantic def foo(a: Sequence[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5) def test_sequence_bad_element(self): @pedantic def foo(a: Sequence[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=[1, 2, 'bb']) def test_abstractset_custom_type(self): T = TypeVar('T') @pedantic_class class DummySet(AbstractSet[T]): def __contains__(self, x: object) -> bool: return x == 1 def __len__(self) -> T: return 1 def __iter__(self) -> Iterator[T]: yield 1 @pedantic def foo(a: AbstractSet[int]) -> None: pass foo(a=DummySet[int]()) def test_abstractset_bad_type(self): @pedantic def foo(a: AbstractSet[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5) def test_set_bad_type(self): @pedantic def foo(a: Set[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5) def test_abstractset_bad_element(self): @pedantic def foo(a: AbstractSet[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a={1, 2, 'bb'}) def test_set_bad_element(self): @pedantic def foo(a: Set[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a={1, 2, 'bb'}) def test_tuple_bad_type(self): @pedantic def foo(a: Tuple[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5) def test_tuple_too_many_elements(self): @pedantic def foo(a: Tuple[int, str]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=(1, 'aa', 2)) def test_tuple_too_few_elements(self): @pedantic def foo(a: Tuple[int, str]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=(1,)) def test_tuple_bad_element(self): @pedantic def foo(a: Tuple[int, str]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=(1, 2)) def test_tuple_ellipsis_bad_element(self): @pedantic def foo(a: Tuple[int, ...]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=(1, 2, 'blah')) def test_namedtuple(self): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic def foo(bar: Employee) -> None: print(bar) foo(bar=Employee('bob', 1)) def test_namedtuple_key_mismatch(self): Employee1 = NamedTuple('Employee', [('name', str), ('id', int)]) Employee2 = NamedTuple('Employee', [('firstname', str), ('id', int)]) @pedantic def foo(bar: Employee1) -> None: print(bar) with self.assertRaises(PedanticTypeCheckException): foo(bar=Employee2('bob', 1)) def test_namedtuple_type_mismatch(self): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic def foo(bar: Employee) -> None: print(bar) with self.assertRaises(PedanticTypeCheckException): foo(bar=('bob', 1)) def test_namedtuple_huge_type_mismatch(self): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic def foo(bar: int) -> None: print(bar) with self.assertRaises(PedanticTypeCheckException): foo(bar=foo(bar=Employee('bob', 1))) def test_namedtuple_wrong_field_type(self): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic def foo(bar: Employee) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(bar=Employee(2, 1)) def test_union(self): @pedantic def foo(a: Union[str, int]) -> None: pass for value in [6, 'xa']: foo(a=value) def test_union_new_syntax(self): @pedantic def foo(a: str | int) -> None: pass for value in [6, 'xa']: foo(a=value) with self.assertRaises(PedanticTypeCheckException): foo(a=1.7) def test_union_typing_type(self): @pedantic def foo(a: Union[str, Collection]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=1) def test_union_fail(self): @pedantic def foo(a: Union[str, int]) -> None: pass for value in [5.6, b'xa']: with self.assertRaises(PedanticTypeCheckException): foo(a=value) def test_type_var_constraints(self): T = TypeVar('T', int, str) @pedantic def foo(a: T, b: T) -> None: pass for values in [ {'a': 6, 'b': 7}, {'a': 'aa', 'b': "bb"}, ]: foo(**values) def test_type_var_constraints_fail_typing_type(self): T = TypeVar('T', int, Collection) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a='aa', b='bb') def test_typevar_constraints_fail(self): T = TypeVar('T', int, str) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=2.5, b='aa') def test_typevar_bound(self): T = TypeVar('T', bound=Parent) @pedantic def foo(a: T, b: T) -> None: pass foo(a=Child(), b=Child()) def test_type_var_bound_fail(self): T = TypeVar('T', bound=Child) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=Parent(), b=Parent()) def test_type_var_invariant_fail(self): T = TypeVar('T', int, str) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=2, b=3.6) def test_type_var_covariant(self): T = TypeVar('T', covariant=True) @pedantic def foo(a: T, b: T) -> None: pass foo(a=Parent(), b=Child()) def test_type_var_covariant_fail(self): T = TypeVar('T', covariant=True) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeVarMismatchException): foo(a=Child(), b=Parent()) def test_type_var_contravariant(self): T = TypeVar('T', contravariant=True) @pedantic def foo(a: T, b: T) -> None: pass foo(a=Child(), b=Parent()) def test_type_var_contravariant_fail(self): T = TypeVar('T', contravariant=True) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeVarMismatchException): foo(a=Parent(), b=Child()) def test_class_bad_subclass(self): @pedantic def foo(a: Type[Child]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=Parent) def test_class_any(self): @pedantic def foo(a: Type[Any]) -> None: pass foo(a=str) def test_wrapped_function(self): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @pedantic @decorator def foo(a: 'Child') -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=Parent()) def test_mismatching_default_type(self): @pedantic def foo(a: str = 1) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo() def test_implicit_default_none(self): """ Test that if the default value is ``None``, a ``None`` argument can be passed. """ @pedantic def foo(a: Optional[str] = None) -> None: pass foo() def test_generator_simple(self): """Test that argument type checking works in a generator function too.""" @pedantic def generate(a: int) -> Generator[int, int, None]: yield a yield a + 1 gen = generate(a=1) next(gen) def test_wrapped_generator_no_return_type_annotation(self): """Test that return type checking works in a generator function too.""" @pedantic def generate(a: int) -> Generator[int, int, None]: yield a yield a + 1 gen = generate(a=1) next(gen) def test_varargs(self): @pedantic def foo(*args: int) -> None: pass foo(1, 2) def test_varargs_fail(self): @pedantic def foo(*args: int) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(1, 'a') def test_kwargs(self): @pedantic def foo(**kwargs: int) -> None: pass foo(a=1, b=2) def test_kwargs_fail(self): @pedantic def foo(**kwargs: int) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=1, b='a') def test_generic(self): T_Foo = TypeVar('T_Foo') class FooGeneric(Generic[T_Foo]): pass @pedantic def foo(a: FooGeneric[str]) -> None: print(a) foo(a=FooGeneric[str]()) def test_newtype(self): myint = NewType("myint", int) @pedantic def foo(a: myint) -> int: return 42 assert foo(a=1) == 42 with self.assertRaises(PedanticTypeCheckException): foo(a="a") def test_collection(self): @pedantic def foo(a: Collection) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=True) def test_binary_io(self): @pedantic def foo(a: BinaryIO) -> None: print(a) foo(a=BytesIO()) def test_text_io(self): @pedantic def foo(a: TextIO) -> None: print(a) foo(a=StringIO()) def test_binary_io_fail(self): @pedantic def foo(a: TextIO) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=BytesIO()) def test_text_io_fail(self): @pedantic def foo(a: BinaryIO) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=StringIO()) def test_binary_io_real_file(self): @pedantic def foo(a: BinaryIO) -> None: print(a) with open(file=TEST_FILE, mode='wb') as f: foo(a=f) def test_text_io_real_file(self): @pedantic def foo(a: TextIO) -> None: print(a) with open(file=TEST_FILE, mode='w') as f: foo(a=f) def test_pedantic_return_type_var_fail(self): T = TypeVar('T', int, float) @pedantic def foo(a: T, b: T) -> T: return 'a' with self.assertRaises(PedanticTypeCheckException): foo(a=4, b=2) def test_callable(self): @pedantic def foo_1(a: Callable[..., int]) -> None: print(a) @pedantic def foo_2(a: Callable) -> None: print(a) def some_callable() -> int: return 4 foo_1(a=some_callable) with self.assertRaises(PedanticTypeCheckException): foo_2(a=some_callable) def test_list(self): @pedantic def foo_1(a: List[int]) -> None: print(a) @pedantic def foo_2(a: List) -> None: print(a) @pedantic def foo_3(a: list) -> None: print(a) @pedantic def foo_4(a: list[int]) -> None: print(a) foo_1(a=[1, 2]) with self.assertRaises(PedanticTypeCheckException): foo_2(a=[1, 2]) with self.assertRaises(PedanticTypeCheckException): foo_3(a=[1, 2]) foo_4(a=[1, 2]) def test_dict(self): @pedantic def foo_1(a: Dict[str, int]) -> None: print(a) @pedantic def foo_2(a: Dict) -> None: print(a) @pedantic def foo_3(a: dict) -> None: print(a) @pedantic def foo_4(a: dict[str, int]) -> None: print(a) foo_1(a={'x': 2}) with self.assertRaises(PedanticTypeCheckException): foo_2(a={'x': 2}) with self.assertRaises(PedanticTypeCheckException): foo_3(a={'x': 2}) foo_4(a={'x': 2}) def test_sequence(self): @pedantic def foo(a: Sequence[str]) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value) def test_sequence_no_type_args(self): @pedantic def foo(a: Sequence) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: with self.assertRaises(PedanticTypeCheckException): foo(a=value) def test_iterable(self): @pedantic def foo(a: Iterable[str]) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value) def test_iterable_no_type_args(self): @pedantic def foo(a: Iterable) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: with self.assertRaises(PedanticTypeCheckException): foo(a=value) def test_container(self): @pedantic def foo(a: Container[str]) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value) def test_container_no_type_args(self): @pedantic def foo(a: Container) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: with self.assertRaises(PedanticTypeCheckException): foo(a=value) def test_set(self): @pedantic def foo_1(a: AbstractSet[int]) -> None: print(a) @pedantic def foo_2(a: Set[int]) -> None: print(a) for value in [set(), {6}]: foo_1(a=value) foo_2(a=value) def test_set_no_type_args(self): @pedantic def foo_1(a: AbstractSet) -> None: print(a) @pedantic def foo_2(a: Set) -> None: print(a) @pedantic def foo_3(a: set) -> None: print(a) for value in [set(), {6}]: with self.assertRaises(PedanticTypeCheckException): foo_1(a=value) with self.assertRaises(PedanticTypeCheckException): foo_2(a=value) with self.assertRaises(PedanticTypeCheckException): foo_3(a=value) def test_tuple(self): @pedantic def foo_1(a: Tuple[int, int]) -> None: print(a) @pedantic def foo_2(a: Tuple[int, ...]) -> None: print(a) foo_1(a=(1, 2)) foo_2(a=(1, 2)) def test_tuple_no_type_args(self): @pedantic def foo_1(a: Tuple) -> None: print(a) @pedantic def foo_2(a: tuple) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo_1(a=(1, 2)) with self.assertRaises(PedanticTypeCheckException): foo_2(a=(1, 2)) def test_empty_tuple(self): @pedantic def foo(a: Tuple[()]) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=()) def test_class(self): @pedantic def foo_1(a: Type[Parent]) -> None: print(a) @pedantic def foo_2(a: Type[TypeVar('UnboundType')]) -> None: print(a) @pedantic def foo_3(a: Type[TypeVar('BoundType', bound=Parent)]) -> None: print(a) foo_1(a=Child) foo_2(a=Child) foo_3(a=Child) def test_class_no_type_vars(self): @pedantic def foo_1(a: Type) -> None: print(a) @pedantic def foo_2(a: type) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo_1(a=Child) with self.assertRaises(PedanticTypeCheckException): foo_2(a=Child) def test_class_not_a_class(self): @pedantic def foo(a: Type[Parent]) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=1) def test_complex(self): @pedantic def foo(a: complex) -> None: print(a) foo(a=complex(1, 5)) with self.assertRaises(PedanticTypeCheckException): foo(a=1.0) def test_float(self): @pedantic def foo(a: float) -> None: print(a) foo(a=1.5) with self.assertRaises(PedanticTypeCheckException): foo(a=1) def test_coroutine_correct_return_type(self): @pedantic async def foo() -> str: return 'foo' coro = foo() with self.assertRaises(StopIteration): coro.send(None) def test_coroutine_wrong_return_type(self): @pedantic async def foo() -> str: return 1 coro = foo() with self.assertRaises(PedanticTypeCheckException): coro.send(None) def test_bytearray_bytes(self): @pedantic def foo(x: bytearray) -> None: pass foo(x=bytearray([1])) def test_class_decorator(self): @pedantic_class class Foo: @staticmethod def staticmethod() -> int: return 'foo' @classmethod def classmethod(cls) -> int: return 'foo' def method(self) -> int: return 'foo' with self.assertRaises(PedanticTypeCheckException): Foo.staticmethod() with self.assertRaises(PedanticTypeCheckException): Foo.classmethod() with self.assertRaises(PedanticTypeCheckException): Foo().method() def test_generator(self): @pedantic def genfunc() -> Generator[int, str, List[str]]: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] gen = genfunc() with self.assertRaises(StopIteration): value = next(gen) while True: value = gen.send(str(value)) assert isinstance(value, int) def test_generator_no_type_args(self): @pedantic def genfunc() -> Generator: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] with self.assertRaises(PedanticTypeCheckException): genfunc() def test_iterator(self): @pedantic def genfunc() -> Iterator[int]: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] gen = genfunc() with self.assertRaises(PedanticTypeCheckException): value = next(gen) while True: value = gen.send(str(value)) assert isinstance(value, int) def test_iterator_no_type_args(self): @pedantic def genfunc() -> Iterator: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] with self.assertRaises(PedanticTypeCheckException): genfunc() def test_iterable_advanced(self): @pedantic def genfunc() -> Iterable[int]: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] gen = genfunc() with self.assertRaises(PedanticTypeCheckException): value = next(gen) while True: value = gen.send(str(value)) assert isinstance(value, int) def test_iterable_advanced_no_type_args(self): @pedantic def genfunc() -> Iterable: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] with self.assertRaises(PedanticTypeCheckException): genfunc() def test_generator_bad_yield(self): @pedantic def genfunc_1() -> Generator[int, str, None]: yield 'foo' @pedantic def genfunc_2() -> Iterable[int]: yield 'foo' @pedantic def genfunc_3() -> Iterator[int]: yield 'foo' gen = genfunc_1() with self.assertRaises(PedanticTypeCheckException): next(gen) gen = genfunc_2() with self.assertRaises(PedanticTypeCheckException): next(gen) gen = genfunc_3() with self.assertRaises(PedanticTypeCheckException): next(gen) def test_generator_bad_send(self): @pedantic def genfunc() -> Generator[int, str, None]: yield 1 yield 2 gen = genfunc() next(gen) with self.assertRaises(PedanticTypeCheckException): gen.send(2) def test_generator_bad_return(self): @pedantic def genfunc() -> Generator[int, str, str]: yield 1 return 6 gen = genfunc() next(gen) with self.assertRaises(PedanticTypeCheckException): gen.send('foo') def test_return_generator(self): @pedantic def genfunc() -> Generator[int, None, None]: yield 1 @pedantic def foo() -> Generator[int, None, None]: return genfunc() foo() def test_local_class(self): @pedantic_class class LocalClass: class Inner: pass def create_inner(self) -> 'Inner': return self.Inner() retval = LocalClass().create_inner() assert isinstance(retval, LocalClass.Inner) def test_local_class_async(self): @pedantic_class class LocalClass: class Inner: pass async def create_inner(self) -> 'Inner': return self.Inner() coro = LocalClass().create_inner() with self.assertRaises(StopIteration): coro.send(None) def test_callable_nonmember(self): class CallableClass: def __call__(self): pass @pedantic_class class LocalClass: some_callable = CallableClass() def test_inherited_class_method(self): @pedantic_class class Parent: @classmethod def foo(cls, x: str) -> str: return cls.__name__ @pedantic_class class Child(Parent): pass self.assertEqual('Parent', Child.foo(x='bar')) with self.assertRaises(PedanticTypeCheckException): Child.foo(x=1) def test_type_var_forward_ref_bound(self): TBound = TypeVar('TBound', bound='Parent') @pedantic def func(x: TBound) -> None: pass func(x=Parent()) with self.assertRaises(PedanticTypeCheckException): func(x='foo') def test_noreturn(self): @pedantic def foo() -> NoReturn: pass @pedantic def bar() -> NoReturn: raise ZeroDivisionError('bar') with self.assertRaises(expected_exception=ZeroDivisionError): bar() with self.assertRaises(PedanticTypeCheckException): foo() def test_literal(self): @pedantic def foo(a: Literal[1, True, 'x', b'y', 404]) -> None: print(a) foo(a=404) foo(a=True) foo(a='x') with self.assertRaises(PedanticTypeCheckException): foo(a=4) def test_literal_union(self): @pedantic def foo(a: Union[str, Literal[1, 6, 8]]) -> None: print(a) foo(a=6) with self.assertRaises(PedanticTypeCheckException): foo(a=4) def test_literal_illegal_value(self): @pedantic def foo(a: Literal[1, 1.1]) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=4) def test_enum(self): with self.assertRaises(PedanticTypeCheckException): @pedantic_class class MyEnum(Enum): A = 'a' def test_enum_aggregate(self): T = TypeVar('T', bound=IntEnum) @pedantic_class class EnumAggregate(Generic[T]): enum: ClassVar[Type[T]] def __init__(self, value: Union[int, str, List[T]]) -> None: assert len(self.enum) < 10 if value == '': raise ValueError(f'Parameter "value" cannot be empty!') if isinstance(value, list): self._value = ''.join([str(x.value) for x in value]) else: self._value = str(value) self._value = ''.join(sorted(self._value)) # sort characters in string self.to_list() # check if is valid def __contains__(self, item: T) -> bool: return item in self.to_list() def __eq__(self, other: Union['EnumAggregate', str]) -> bool: if isinstance(other, str): return self._value == other return self._value == other._value def __str__(self) -> str: return self._value def to_list(self) -> List[T]: return [self.enum(int(character)) for character in self._value] @property def value(self) -> str: return self._value @classmethod def all(cls) -> str: return ''.join([str(x.value) for x in cls.enum]) class Gender(IntEnum): MALE = 1 FEMALE = 2 DIVERS = 3 @pedantic_class class Genders(EnumAggregate[Gender]): enum = Gender Genders(value=12) with self.assertRaises(PedanticTypeCheckException): Genders(value=Child()) def test_primitive_list_dict_tuple(self): @pedantic def f(x: list[dict[int, tuple[float, str]]]) -> list[Any]: return x f(x=[{3: (3.24, 'hi')}]) for value in [ [{3, (3, 'hi')}], [{3: (3, 'hi')}], [{3: (3.24, 3)}], [{3: (3.24, 'hi')}, {0}], ]: with self.assertRaises(PedanticTypeCheckException): f(x=value) def test_dataclass_protocol(self): class IsDataclass(typing.Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass class Foo: v: int @pedantic def foo(x: IsDataclass) -> IsDataclass: return x foo(x=Foo(v=42)) def test_dataclass_protocol_in_type(self): class IsDataclass(typing.Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass class Foo: v: int @pedantic def foo(x: type[IsDataclass]) -> IsDataclass: return x assert foo(x=Foo) == Foo def test_dataclass_protocol_in_type_with_union(self): class IsDataclass(typing.Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass class Foo: v: int @pedantic def foo(x: type[None | bool | IsDataclass]) -> IsDataclass: return x assert foo(x=Foo) == Foo
Ancestors
- unittest.case.TestCase
Methods
def tearDown(self) ‑> None
-
Hook method for deconstructing the test fixture after testing it.
Expand source code
def tearDown(self) -> None: if os.path.isfile(TEST_FILE): os.remove(TEST_FILE)
def test_abstractset_bad_element(self)
-
Expand source code
def test_abstractset_bad_element(self): @pedantic def foo(a: AbstractSet[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a={1, 2, 'bb'})
def test_abstractset_bad_type(self)
-
Expand source code
def test_abstractset_bad_type(self): @pedantic def foo(a: AbstractSet[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5)
def test_abstractset_custom_type(self)
-
Expand source code
def test_abstractset_custom_type(self): T = TypeVar('T') @pedantic_class class DummySet(AbstractSet[T]): def __contains__(self, x: object) -> bool: return x == 1 def __len__(self) -> T: return 1 def __iter__(self) -> Iterator[T]: yield 1 @pedantic def foo(a: AbstractSet[int]) -> None: pass foo(a=DummySet[int]())
def test_additional_kwargs(self)
-
Expand source code
def test_additional_kwargs(self): @pedantic def some_method(a: int, b: float = 0.0, **kwargs: int) -> float: return sum([a, b]) some_method(a=5) some_method(a=5, b=0.1) some_method(a=5, b=0.1, c=4) some_method(a=5, b=0.1, c=4, d=5, e=6) with self.assertRaises(expected_exception=PedanticTypeCheckException): some_method(a=5, b=0.1, c=4, d=5.0, e=6) with self.assertRaises(expected_exception=PedanticTypeCheckException): some_method(a=5.0, b=0.1, c=4, d=5, e=6) with self.assertRaises(expected_exception=PedanticTypeCheckException): some_method(a=5, b=0, c=4, d=5, e=6)
def test_aliases(self)
-
Expand source code
def test_aliases(self): Vector = List[float] @pedantic def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector] scale(scalar=2.0, vector=[1.0, -4.2, 5.4])
def test_all_ok_2(self)
-
Expand source code
def test_all_ok_2(self): @pedantic def calc(n: int, m: int, i: int) -> str: return str(n + m + i) calc(n=42, m=40, i=38)
def test_all_ok_3(self)
-
Expand source code
def test_all_ok_3(self): @pedantic def calc(n: int, m: int, i: int) -> None: str(n + m + i) calc(n=42, m=40, i=38)
def test_all_ok_4(self)
-
Expand source code
def test_all_ok_4(self): @pedantic def calc(n: int) -> List[List[int]]: return [[n]] calc(n=42)
def test_all_ok_5(self)
-
Expand source code
def test_all_ok_5(self): @pedantic def calc(n: int) -> List[Tuple[float, str]]: return [(float(n), str(n))] calc(n=42)
def test_all_ok_6(self)
-
Expand source code
def test_all_ok_6(self): @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, str]]: @pedantic def f(x: int, y: float) -> Tuple[float, str]: return n * float(x), str(y) return f calc(n=42)(x=72, y=3.14)
def test_all_ok_7(self)
-
Expand source code
def test_all_ok_7(self): @pedantic def calc(n: List[List[float]]) -> Any: return n[0][0] calc(n=[[42.0]])
def test_all_ok_8(self)
-
Expand source code
def test_all_ok_8(self): @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, str]]: @pedantic def f(x: int, y: float) -> Tuple[float, str]: return n * float(x), str(y) return f calc(n=42)(x=3, y=3.14)
def test_alternative_list_type_hint(self)
-
Expand source code
def test_alternative_list_type_hint(self): @pedantic def _is_digit_in_int(digit: [int], num: int) -> bool: num_str = str(num) for i in num_str: if int(i) == digit: return True return False with self.assertRaises(expected_exception=PedanticTypeCheckException): _is_digit_in_int(digit=4, num=42)
def test_any(self)
-
Expand source code
def test_any(self): @pedantic def calc(ls: List[Any]) -> Dict[int, Any]: return {i: ls[i] for i in range(0, len(ls))} calc(ls=[1, 2, 3]) calc(ls=[1.11, 2.0, 3.0]) calc(ls=['1', '2', '3']) calc(ls=[10.5, '2', (3, 4, 5)])
def test_any_type(self)
-
Expand source code
def test_any_type(self): @pedantic def foo(a: Any) -> None: pass foo(a='aa')
def test_args_kwargs(self)
-
Expand source code
def test_args_kwargs(self): @pedantic def some_method(a: int = 0, b: float = 0.0) -> float: return a * b @pedantic def wrapper_method(*args: Union[int, float], **kwargs: Union[int, float]) -> float: return some_method(*args, **kwargs) some_method() with self.assertRaises(expected_exception=PedanticCallWithArgsException): some_method(3, 3.0) some_method(a=3, b=3.0) wrapper_method() with self.assertRaises(expected_exception=PedanticCallWithArgsException): wrapper_method(3, 3.0) wrapper_method(a=3, b=3.0)
def test_args_kwargs_different_types(self)
-
Expand source code
def test_args_kwargs_different_types(self): @pedantic def foo(*args: str, **kwds: int) -> None: print(args) print(kwds) foo('a', 'b', 'c') foo(x=1, y=2) foo('', z=0)
def test_args_kwargs_no_type_hint(self)
-
Expand source code
def test_args_kwargs_no_type_hint(self): @pedantic def method_no_type_hint(*args, **kwargs) -> None: print(args) print(kwargs) with self.assertRaises(expected_exception=PedanticTypeCheckException): method_no_type_hint(a=3, b=3.0) with self.assertRaises(expected_exception=PedanticTypeCheckException): method_no_type_hint()
def test_args_kwargs_wrong_type_hint(self)
-
Expand source code
def test_args_kwargs_wrong_type_hint(self): """See: https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values""" @pedantic def wrapper_method(*args: str, **kwargs: str) -> None: print(args) print(kwargs) wrapper_method() wrapper_method('hi', 'you', ':)') wrapper_method(a='hi', b='you', c=':)') with self.assertRaises(expected_exception=PedanticTypeCheckException): wrapper_method('hi', 'you', ':)', 7) with self.assertRaises(expected_exception=PedanticTypeCheckException): wrapper_method(3, 3.0) with self.assertRaises(expected_exception=PedanticTypeCheckException): wrapper_method(a=3, b=3.0)
def test_binary_io(self)
-
Expand source code
def test_binary_io(self): @pedantic def foo(a: BinaryIO) -> None: print(a) foo(a=BytesIO())
def test_binary_io_fail(self)
-
Expand source code
def test_binary_io_fail(self): @pedantic def foo(a: TextIO) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=BytesIO())
def test_binary_io_real_file(self)
-
Expand source code
def test_binary_io_real_file(self): @pedantic def foo(a: BinaryIO) -> None: print(a) with open(file=TEST_FILE, mode='wb') as f: foo(a=f)
def test_bytearray_bytes(self)
-
Expand source code
def test_bytearray_bytes(self): @pedantic def foo(x: bytearray) -> None: pass foo(x=bytearray([1]))
def test_callable(self)
-
Expand source code
def test_callable(self): @pedantic def foo_1(a: Callable[..., int]) -> None: print(a) @pedantic def foo_2(a: Callable) -> None: print(a) def some_callable() -> int: return 4 foo_1(a=some_callable) with self.assertRaises(PedanticTypeCheckException): foo_2(a=some_callable)
def test_callable_bad_type(self)
-
Expand source code
def test_callable_bad_type(self): @pedantic def foo(a: Callable[..., int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5)
def test_callable_bound_method(self)
-
Expand source code
def test_callable_bound_method(self): @pedantic def foo(callback: Callable[[int], Any]) -> None: pass foo(callback=Child().method)
def test_callable_builtin(self)
-
Expand source code
def test_callable_builtin(self): @pedantic def foo(callback: types.BuiltinFunctionType) -> None: pass foo(callback=[].append)
def test_callable_class(self)
-
Test that passing a class as a callable does not count the "self" argument "a"gainst the ones declared in the Callable specification.
Expand source code
def test_callable_class(self): """ Test that passing a class as a callable does not count the "self" argument "a"gainst the ones declared in the Callable specification. """ @pedantic def foo(a: Callable[[int, str], Any]) -> None: pass class SomeClass: def __init__(self, x: int, y: str): pass foo(a=SomeClass)
def test_callable_defaults(self)
-
Test that a callable having "too many" arguments don't raise an error if the extra arguments have default values.
Expand source code
def test_callable_defaults(self): """ Test that a callable having "too many" arguments don't raise an error if the extra arguments have default values. """ @pedantic def foo(callback: Callable[[int, str], Any]) -> None: pass def some_callable(x: int, y: str, z: float = 1.2) -> int: pass foo(callback=some_callable)
def test_callable_exact_arg_count(self)
-
Expand source code
def test_callable_exact_arg_count(self): @pedantic def foo(a: Callable[[int, str], int]) -> None: pass def some_callable(x: int, y: str) -> int: pass foo(a=some_callable)
def test_callable_mandatory_kwonlyargs(self)
-
Expand source code
def test_callable_mandatory_kwonlyargs(self): @pedantic def foo(a: Callable[[int, str], int]) -> None: pass def some_callable(x: int, y: str, *, z: float, bar: str) -> int: pass with self.assertRaises(PedanticTypeCheckException): foo(a=some_callable)
def test_callable_no_args(self)
-
Expand source code
def test_callable_no_args(self): @pedantic def f(g: Callable[[], str]) -> str: return g() @pedantic def greetings() -> str: return 'hello world' f(g=greetings)
def test_callable_nonmember(self)
-
Expand source code
def test_callable_nonmember(self): class CallableClass: def __call__(self): pass @pedantic_class class LocalClass: some_callable = CallableClass()
def test_callable_plain(self)
-
Expand source code
def test_callable_plain(self): @pedantic def foo(a: Callable[..., Any]) -> None: pass def callback(a): pass foo(a=callback)
def test_callable_too_few_arguments(self)
-
Expand source code
def test_callable_too_few_arguments(self): @pedantic def foo(a: Callable[[int, str], int]) -> None: pass def some_callable(x: int) -> int: pass with self.assertRaises(PedanticTypeCheckException): foo(a=some_callable)
def test_callable_with_union_return(self)
-
Expand source code
def test_callable_with_union_return(self): class MyClass: pass @pedantic def admin_required(func: Callable[..., Union[str, MyClass]]) -> Callable[..., Union[str, MyClass]]: @wraps(func) def decorated_function(*args, **kwargs): return func(*args, **kwargs) return decorated_function @admin_required @pedantic def get_server_info() -> str: return 'info' get_server_info()
def test_callable_without_args_correct_with_lambdas(self)
-
Expand source code
def test_callable_without_args_correct_with_lambdas(self): @pedantic def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str: return str(i(x=' you')) calc(i=lambda x: (42.0, 43, 'hi', x))
def test_callable_without_args_corrected(self)
-
Expand source code
def test_callable_without_args_corrected(self): @pedantic def calc(i: Callable[[Any], Tuple[Any, ...]]) -> str: return str(i(x=' you')) @pedantic def arg(x: Any) -> Tuple[Any, ...]: return 42.0, 43, 'hi', x calc(i=arg)
def test_callable_without_type_args(self)
-
Expand source code
def test_callable_without_type_args(self): @pedantic def calc(i: Callable) -> str: return str(i(' you')) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=lambda x: (42.0, 43, 'hi', x))
def test_class(self)
-
Expand source code
def test_class(self): @pedantic def foo_1(a: Type[Parent]) -> None: print(a) @pedantic def foo_2(a: Type[TypeVar('UnboundType')]) -> None: print(a) @pedantic def foo_3(a: Type[TypeVar('BoundType', bound=Parent)]) -> None: print(a) foo_1(a=Child) foo_2(a=Child) foo_3(a=Child)
def test_class_any(self)
-
Expand source code
def test_class_any(self): @pedantic def foo(a: Type[Any]) -> None: pass foo(a=str)
def test_class_bad_subclass(self)
-
Expand source code
def test_class_bad_subclass(self): @pedantic def foo(a: Type[Child]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=Parent)
def test_class_decorator(self)
-
Expand source code
def test_class_decorator(self): @pedantic_class class Foo: @staticmethod def staticmethod() -> int: return 'foo' @classmethod def classmethod(cls) -> int: return 'foo' def method(self) -> int: return 'foo' with self.assertRaises(PedanticTypeCheckException): Foo.staticmethod() with self.assertRaises(PedanticTypeCheckException): Foo.classmethod() with self.assertRaises(PedanticTypeCheckException): Foo().method()
def test_class_no_type_vars(self)
-
Expand source code
def test_class_no_type_vars(self): @pedantic def foo_1(a: Type) -> None: print(a) @pedantic def foo_2(a: type) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo_1(a=Child) with self.assertRaises(PedanticTypeCheckException): foo_2(a=Child)
def test_class_not_a_class(self)
-
Expand source code
def test_class_not_a_class(self): @pedantic def foo(a: Type[Parent]) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=1)
def test_collection(self)
-
Expand source code
def test_collection(self): @pedantic def foo(a: Collection) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=True)
def test_complex(self)
-
Expand source code
def test_complex(self): @pedantic def foo(a: complex) -> None: print(a) foo(a=complex(1, 5)) with self.assertRaises(PedanticTypeCheckException): foo(a=1.0)
def test_container(self)
-
Expand source code
def test_container(self): @pedantic def foo(a: Container[str]) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value)
def test_container_no_type_args(self)
-
Expand source code
def test_container_no_type_args(self): @pedantic def foo(a: Container) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: with self.assertRaises(PedanticTypeCheckException): foo(a=value)
def test_coroutine_correct_return_type(self)
-
Expand source code
def test_coroutine_correct_return_type(self): @pedantic async def foo() -> str: return 'foo' coro = foo() with self.assertRaises(StopIteration): coro.send(None)
def test_coroutine_wrong_return_type(self)
-
Expand source code
def test_coroutine_wrong_return_type(self): @pedantic async def foo() -> str: return 1 coro = foo() with self.assertRaises(PedanticTypeCheckException): coro.send(None)
def test_dataclass_protocol(self)
-
Expand source code
def test_dataclass_protocol(self): class IsDataclass(typing.Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass class Foo: v: int @pedantic def foo(x: IsDataclass) -> IsDataclass: return x foo(x=Foo(v=42))
def test_dataclass_protocol_in_type(self)
-
Expand source code
def test_dataclass_protocol_in_type(self): class IsDataclass(typing.Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass class Foo: v: int @pedantic def foo(x: type[IsDataclass]) -> IsDataclass: return x assert foo(x=Foo) == Foo
def test_dataclass_protocol_in_type_with_union(self)
-
Expand source code
def test_dataclass_protocol_in_type_with_union(self): class IsDataclass(typing.Protocol): __dataclass_fields__: ClassVar[Dict] @dataclass class Foo: v: int @pedantic def foo(x: type[None | bool | IsDataclass]) -> IsDataclass: return x assert foo(x=Foo) == Foo
def test_date_datetime(self)
-
Expand source code
def test_date_datetime(self): @pedantic def foo(a: datetime, b: date) -> None: pass foo(a=datetime(1995, 2, 5), b=date(1987, 8, 7)) foo(a=datetime(1995, 2, 5), b=datetime(1987, 8, 7)) with self.assertRaises(expected_exception=PedanticTypeCheckException): foo(a=date(1995, 2, 5), b=date(1987, 8, 7))
def test_dict(self)
-
Expand source code
def test_dict(self): @pedantic def foo_1(a: Dict[str, int]) -> None: print(a) @pedantic def foo_2(a: Dict) -> None: print(a) @pedantic def foo_3(a: dict) -> None: print(a) @pedantic def foo_4(a: dict[str, int]) -> None: print(a) foo_1(a={'x': 2}) with self.assertRaises(PedanticTypeCheckException): foo_2(a={'x': 2}) with self.assertRaises(PedanticTypeCheckException): foo_3(a={'x': 2}) foo_4(a={'x': 2})
def test_dict_bad_key_type(self)
-
Expand source code
def test_dict_bad_key_type(self): @pedantic def foo(a: Dict[str, int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a={1: 2})
def test_dict_bad_type(self)
-
Expand source code
def test_dict_bad_type(self): @pedantic def foo(a: Dict[str, int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5)
def test_dict_bad_value_type(self)
-
Expand source code
def test_dict_bad_value_type(self): @pedantic def foo(a: Dict[str, int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a={'x': 'a'})
def test_double_pedantic(self)
-
Expand source code
def test_double_pedantic(self): @pedantic @pedantic def f(x: int, y: float) -> Tuple[float, str]: return float(x), str(y) f(x=5, y=3.14) with self.assertRaises(expected_exception=PedanticTypeCheckException): f(x=5.0, y=3.14) with self.assertRaises(expected_exception=PedanticCallWithArgsException): f(5, 3.14)
def test_ellipsis_in_callable_1(self)
-
Expand source code
def test_ellipsis_in_callable_1(self): @pedantic def calc(i: Callable[..., int]) -> int: return i() @pedantic def call() -> int: return 42 calc(i=call)
def test_ellipsis_in_callable_2(self)
-
Expand source code
def test_ellipsis_in_callable_2(self): @pedantic def calc(i: Callable[..., int]) -> int: return i(x=3.14, y=5) @pedantic def call(x: float, y: int) -> int: return 42 calc(i=call)
def test_ellipsis_in_callable_3(self)
-
Problem here: call to "call" misses one argument
Expand source code
def test_ellipsis_in_callable_3(self): """Problem here: call to "call" misses one argument""" @pedantic def calc(i: Callable[..., int]) -> int: return i(x=3.14) @pedantic def call(x: float, y: int) -> int: return 42 with self.assertRaises(expected_exception=PedanticException): calc(i=call)
def test_empty_tuple(self)
-
Expand source code
def test_empty_tuple(self): @pedantic def foo(a: Tuple[()]) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=())
def test_enum(self)
-
Expand source code
def test_enum(self): with self.assertRaises(PedanticTypeCheckException): @pedantic_class class MyEnum(Enum): A = 'a'
def test_enum_1(self)
-
Problem here: Type hint for 'a' should be MyEnum instead of MyEnum.GAMMA
Expand source code
def test_enum_1(self): """Problem here: Type hint for 'a' should be MyEnum instead of MyEnum.GAMMA""" class MyEnum(Enum): ALPHA = 'startEvent' BETA = 'task' GAMMA = 'sequenceFlow' class MyClass: @pedantic def operation(self, a: MyEnum.GAMMA) -> None: print(a) m = MyClass() with self.assertRaises(expected_exception=PedanticTypeCheckException): m.operation(a=MyEnum.GAMMA)
def test_enum_1_corrected(self)
-
Expand source code
def test_enum_1_corrected(self): class MyEnum(Enum): ALPHA = 'startEvent' BETA = 'task' GAMMA = 'sequenceFlow' @pedantic def operation(a: MyEnum) -> None: print(a) operation(a=MyEnum.GAMMA)
def test_enum_aggregate(self)
-
Expand source code
def test_enum_aggregate(self): T = TypeVar('T', bound=IntEnum) @pedantic_class class EnumAggregate(Generic[T]): enum: ClassVar[Type[T]] def __init__(self, value: Union[int, str, List[T]]) -> None: assert len(self.enum) < 10 if value == '': raise ValueError(f'Parameter "value" cannot be empty!') if isinstance(value, list): self._value = ''.join([str(x.value) for x in value]) else: self._value = str(value) self._value = ''.join(sorted(self._value)) # sort characters in string self.to_list() # check if is valid def __contains__(self, item: T) -> bool: return item in self.to_list() def __eq__(self, other: Union['EnumAggregate', str]) -> bool: if isinstance(other, str): return self._value == other return self._value == other._value def __str__(self) -> str: return self._value def to_list(self) -> List[T]: return [self.enum(int(character)) for character in self._value] @property def value(self) -> str: return self._value @classmethod def all(cls) -> str: return ''.join([str(x.value) for x in cls.enum]) class Gender(IntEnum): MALE = 1 FEMALE = 2 DIVERS = 3 @pedantic_class class Genders(EnumAggregate[Gender]): enum = Gender Genders(value=12) with self.assertRaises(PedanticTypeCheckException): Genders(value=Child())
def test_float(self)
-
Expand source code
def test_float(self): @pedantic def foo(a: float) -> None: print(a) foo(a=1.5) with self.assertRaises(PedanticTypeCheckException): foo(a=1)
def test_forward_ref(self)
-
Expand source code
def test_forward_ref(self): class Conversation: pass @pedantic def get_conversations() -> List['Conversation']: return [Conversation(), Conversation()] get_conversations()
def test_generator(self)
-
Expand source code
def test_generator(self): @pedantic def genfunc() -> Generator[int, str, List[str]]: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] gen = genfunc() with self.assertRaises(StopIteration): value = next(gen) while True: value = gen.send(str(value)) assert isinstance(value, int)
def test_generator_bad_return(self)
-
Expand source code
def test_generator_bad_return(self): @pedantic def genfunc() -> Generator[int, str, str]: yield 1 return 6 gen = genfunc() next(gen) with self.assertRaises(PedanticTypeCheckException): gen.send('foo')
def test_generator_bad_send(self)
-
Expand source code
def test_generator_bad_send(self): @pedantic def genfunc() -> Generator[int, str, None]: yield 1 yield 2 gen = genfunc() next(gen) with self.assertRaises(PedanticTypeCheckException): gen.send(2)
def test_generator_bad_yield(self)
-
Expand source code
def test_generator_bad_yield(self): @pedantic def genfunc_1() -> Generator[int, str, None]: yield 'foo' @pedantic def genfunc_2() -> Iterable[int]: yield 'foo' @pedantic def genfunc_3() -> Iterator[int]: yield 'foo' gen = genfunc_1() with self.assertRaises(PedanticTypeCheckException): next(gen) gen = genfunc_2() with self.assertRaises(PedanticTypeCheckException): next(gen) gen = genfunc_3() with self.assertRaises(PedanticTypeCheckException): next(gen)
def test_generator_no_type_args(self)
-
Expand source code
def test_generator_no_type_args(self): @pedantic def genfunc() -> Generator: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] with self.assertRaises(PedanticTypeCheckException): genfunc()
def test_generator_simple(self)
-
Test that argument type checking works in a generator function too.
Expand source code
def test_generator_simple(self): """Test that argument type checking works in a generator function too.""" @pedantic def generate(a: int) -> Generator[int, int, None]: yield a yield a + 1 gen = generate(a=1) next(gen)
def test_generic(self)
-
Expand source code
def test_generic(self): T_Foo = TypeVar('T_Foo') class FooGeneric(Generic[T_Foo]): pass @pedantic def foo(a: FooGeneric[str]) -> None: print(a) foo(a=FooGeneric[str]())
def test_implicit_default_none(self)
-
Test that if the default value is
None
, aNone
argument can be passed.Expand source code
def test_implicit_default_none(self): """ Test that if the default value is ``None``, a ``None`` argument can be passed. """ @pedantic def foo(a: Optional[str] = None) -> None: pass foo()
def test_inheritance_1(self)
-
Expand source code
def test_inheritance_1(self): class MyClassA: pass class MyClassB(MyClassA): pass @pedantic def calc(a: MyClassA) -> str: return str(a) calc(a=MyClassA()) calc(a=MyClassB())
def test_inheritance_2(self)
-
Problem here: A is not a subtype of B
Expand source code
def test_inheritance_2(self): """Problem here: A is not a subtype of B""" class MyClassA: pass class MyClassB(MyClassA): pass @pedantic def calc(a: MyClassB) -> str: return str(a) calc(a=MyClassB()) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(a=MyClassA())
def test_inherited_class_method(self)
-
Expand source code
def test_inherited_class_method(self): @pedantic_class class Parent: @classmethod def foo(cls, x: str) -> str: return cls.__name__ @pedantic_class class Child(Parent): pass self.assertEqual('Parent', Child.foo(x='bar')) with self.assertRaises(PedanticTypeCheckException): Child.foo(x=1)
def test_instance_method_1(self)
-
Expand source code
def test_instance_method_1(self): class MyClassA: @pedantic def calc(self, i: int) -> str: return str(i) a = MyClassA() a.calc(i=42)
def test_instance_method_2(self)
-
Problem here: 'i' has no type annotation
Expand source code
def test_instance_method_2(self): """Problem here: 'i' has no type annotation""" class MyClassA: @pedantic def calc(self, i) -> str: return str(i) a = MyClassA() with self.assertRaises(expected_exception=PedanticTypeCheckException): a.calc(i=42)
def test_instance_method_2_corrected(self)
-
Expand source code
def test_instance_method_2_corrected(self): class MyClassA: @pedantic def calc(self, i: int) -> str: return str(i) a = MyClassA() a.calc(i=42)
def test_instance_method_3_corrected(self)
-
Expand source code
def test_instance_method_3_corrected(self): class MyClassA: @pedantic def calc(self, i: float) -> str: return str(i) a = MyClassA() a.calc(i=42.0)
def test_instance_method_5(self)
-
Problem here: instance methods is not called with kwargs
Expand source code
def test_instance_method_5(self): """Problem here: instance methods is not called with kwargs""" class MyClassA: @pedantic def calc(self, i: int) -> str: return str(i) a = MyClassA() a.calc(i=42)
def test_instance_method_int_is_not_float(self)
-
Expand source code
def test_instance_method_int_is_not_float(self): class MyClassA: @pedantic def calc(self, i: float) -> str: return str(i) a = MyClassA() with self.assertRaises(expected_exception=PedanticTypeCheckException): a.calc(i=42)
def test_instance_method_no_kwargs(self)
-
Expand source code
def test_instance_method_no_kwargs(self): class MyClassA: @pedantic def calc(self, i: int) -> str: return str(i) a = MyClassA() with self.assertRaises(expected_exception=PedanticCallWithArgsException): a.calc(42)
def test_is_subtype_tuple(self)
-
Expand source code
def test_is_subtype_tuple(self): with self.assertRaises(expected_exception=PedanticTypeCheckException): @pedantic def foo() -> Callable[[Tuple[float, str]], Tuple[int]]: def bar(a: Tuple[float]) -> Tuple[int]: return len(a[1]) + int(a[0]), return bar foo()
def test_is_subtype_tuple_corrected(self)
-
Expand source code
def test_is_subtype_tuple_corrected(self): @pedantic def foo() -> Callable[[Tuple[float, str]], Tuple[int]]: def bar(a: Tuple[float, str]) -> Tuple[int]: return len(a[1]) + int(a[0]), return bar foo()
def test_iterable(self)
-
Expand source code
def test_iterable(self): @pedantic def foo(a: Iterable[str]) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value)
def test_iterable_advanced(self)
-
Expand source code
def test_iterable_advanced(self): @pedantic def genfunc() -> Iterable[int]: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] gen = genfunc() with self.assertRaises(PedanticTypeCheckException): value = next(gen) while True: value = gen.send(str(value)) assert isinstance(value, int)
def test_iterable_advanced_no_type_args(self)
-
Expand source code
def test_iterable_advanced_no_type_args(self): @pedantic def genfunc() -> Iterable: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] with self.assertRaises(PedanticTypeCheckException): genfunc()
def test_iterable_no_type_args(self)
-
Expand source code
def test_iterable_no_type_args(self): @pedantic def foo(a: Iterable) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: with self.assertRaises(PedanticTypeCheckException): foo(a=value)
def test_iterator(self)
-
Expand source code
def test_iterator(self): @pedantic def genfunc() -> Iterator[int]: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] gen = genfunc() with self.assertRaises(PedanticTypeCheckException): value = next(gen) while True: value = gen.send(str(value)) assert isinstance(value, int)
def test_iterator_no_type_args(self)
-
Expand source code
def test_iterator_no_type_args(self): @pedantic def genfunc() -> Iterator: val1 = yield 2 val2 = yield 3 val3 = yield 4 return [val1, val2, val3] with self.assertRaises(PedanticTypeCheckException): genfunc()
def test_kwargs(self)
-
Expand source code
def test_kwargs(self): @pedantic def foo(**kwargs: int) -> None: pass foo(a=1, b=2)
def test_kwargs_fail(self)
-
Expand source code
def test_kwargs_fail(self): @pedantic def foo(**kwargs: int) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=1, b='a')
def test_lambda_1(self)
-
Expand source code
def test_lambda_1(self): @pedantic def calc(i: float) -> Callable[[float], str]: return lambda x: str(x * i) calc(i=42.0)(10.0)
def test_lambda_3(self)
-
Expand source code
def test_lambda_3(self): @pedantic def calc(i: float) -> Callable[[float], str]: def res(x: float) -> str: return str(x * i) return res calc(i=42.0)(10.0)
def test_lambda_4_almost_corrected(self)
-
Problem here: float != str
Expand source code
def test_lambda_4_almost_corrected(self): """Problem here: float != str""" @pedantic def calc(i: float) -> Callable[[float], str]: @pedantic def res(x: int) -> str: return str(x * i) return res with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=42.0)(x=10)
def test_lambda_4_almost_corrected_2(self)
-
Expand source code
def test_lambda_4_almost_corrected_2(self): @pedantic def calc(i: float) -> Callable[[int], str]: @pedantic def res(x: int) -> str: return str(x * i) return res calc(i=42.0)(x=10)
def test_lambda_5(self)
-
Problem here: float != int
Expand source code
def test_lambda_5(self): """Problem here: float != int""" @pedantic def calc(i: float) -> Callable[[float], str]: @pedantic def res(x: float) -> str: return str(x * i) return res with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=42.0)(x=10)
def test_lambda_corrected(self)
-
Expand source code
def test_lambda_corrected(self): @pedantic def calc(i: float) -> Callable[[float], str]: @pedantic def res(x: float) -> str: return str(x * i) return res calc(i=42.0)(x=10.0)
def test_lambda_int_is_not_float(self)
-
Expand source code
def test_lambda_int_is_not_float(self): @pedantic def calc(i: float) -> Callable[[float], str]: def res(x: int) -> str: return str(x * i) return res with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=42.0)(x=10)
def test_list(self)
-
Expand source code
def test_list(self): @pedantic def foo_1(a: List[int]) -> None: print(a) @pedantic def foo_2(a: List) -> None: print(a) @pedantic def foo_3(a: list) -> None: print(a) @pedantic def foo_4(a: list[int]) -> None: print(a) foo_1(a=[1, 2]) with self.assertRaises(PedanticTypeCheckException): foo_2(a=[1, 2]) with self.assertRaises(PedanticTypeCheckException): foo_3(a=[1, 2]) foo_4(a=[1, 2])
def test_list_bad_element(self)
-
Expand source code
def test_list_bad_element(self): @pedantic def foo(a: List[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=[1, 2, 'bb'])
def test_list_bad_type(self)
-
Expand source code
def test_list_bad_type(self): @pedantic def foo(a: List[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5)
def test_list_of_new_type(self)
-
Expand source code
def test_list_of_new_type(self): UserId = NewType('UserId', int) @pedantic def get_user_name(user_ids: List[UserId]) -> str: return str(user_ids) get_user_name(user_ids=[UserId(524313), UserId(42)]) with self.assertRaises(expected_exception=PedanticTypeCheckException): get_user_name(user_ids=[UserId(524313), UserId(42), 430.0])
def test_list_without_args(self)
-
Expand source code
def test_list_without_args(self): @pedantic def calc(i: List) -> Any: return [i] with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=[42.0, 43, 'hi'])
def test_list_without_args_corrected(self)
-
Expand source code
def test_list_without_args_corrected(self): @pedantic def calc(i: List[Any]) -> List[List[Any]]: return [i] calc(i=[42.0, 43, 'hi'])
def test_literal(self)
-
Expand source code
def test_literal(self): @pedantic def foo(a: Literal[1, True, 'x', b'y', 404]) -> None: print(a) foo(a=404) foo(a=True) foo(a='x') with self.assertRaises(PedanticTypeCheckException): foo(a=4)
def test_literal_illegal_value(self)
-
Expand source code
def test_literal_illegal_value(self): @pedantic def foo(a: Literal[1, 1.1]) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=4)
def test_literal_union(self)
-
Expand source code
def test_literal_union(self): @pedantic def foo(a: Union[str, Literal[1, 6, 8]]) -> None: print(a) foo(a=6) with self.assertRaises(PedanticTypeCheckException): foo(a=4)
def test_local_class(self)
-
Expand source code
def test_local_class(self): @pedantic_class class LocalClass: class Inner: pass def create_inner(self) -> 'Inner': return self.Inner() retval = LocalClass().create_inner() assert isinstance(retval, LocalClass.Inner)
def test_local_class_async(self)
-
Expand source code
def test_local_class_async(self): @pedantic_class class LocalClass: class Inner: pass async def create_inner(self) -> 'Inner': return self.Inner() coro = LocalClass().create_inner() with self.assertRaises(StopIteration): coro.send(None)
def test_marco(self)
-
Expand source code
def test_marco(self): @pedantic_class class A: def __init__(self, val: int) -> None: self.val = val def __eq__(self, other: 'A') -> bool: # other: A and all subclasses return self.val == other.val @pedantic_class class B(A): def __init__(self, val: int) -> None: super().__init__(val=val) @pedantic_class class C(A): def __init__(self, val: int) -> None: super().__init__(val=val) a = A(val=42) b = B(val=42) c = C(val=42) assert a == b # works assert a == c # works assert b == c # error
def test_mismatching_default_type(self)
-
Expand source code
def test_mismatching_default_type(self): @pedantic def foo(a: str = 1) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo()
def test_missing_type_hint_1(self)
-
Problem here: type hint for n missed
Expand source code
def test_missing_type_hint_1(self): """Problem here: type hint for n missed""" @pedantic def calc(n) -> float: return 42.0 * n with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42)
def test_missing_type_hint_1_corrected(self)
-
Expand source code
def test_missing_type_hint_1_corrected(self): @pedantic def calc(n: int) -> float: return 42.0 * n calc(n=42)
def test_missing_type_hint_2(self)
-
Problem here: Return type annotation missed
Expand source code
def test_missing_type_hint_2(self): """Problem here: Return type annotation missed""" @pedantic def calc(n: int): return 'Hi' + str(n) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42)
def test_missing_type_hint_2_corrected(self)
-
Expand source code
def test_missing_type_hint_2_corrected(self): @pedantic def calc(n: int) -> str: return 'Hi' + str(n) calc(n=42)
def test_missing_type_hint_3(self)
-
Problem here: type hint for i missed
Expand source code
def test_missing_type_hint_3(self): """Problem here: type hint for i missed""" @pedantic def calc(n: int, m: int, i) -> int: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38)
def test_missing_type_hint_3_corrected(self)
-
Expand source code
def test_missing_type_hint_3_corrected(self): @pedantic def calc(n: int, m: int, i: int) -> int: return n + m + i calc(n=42, m=40, i=38)
def test_namedtuple(self)
-
Expand source code
def test_namedtuple(self): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic def foo(bar: Employee) -> None: print(bar) foo(bar=Employee('bob', 1))
def test_namedtuple_huge_type_mismatch(self)
-
Expand source code
def test_namedtuple_huge_type_mismatch(self): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic def foo(bar: int) -> None: print(bar) with self.assertRaises(PedanticTypeCheckException): foo(bar=foo(bar=Employee('bob', 1)))
def test_namedtuple_key_mismatch(self)
-
Expand source code
def test_namedtuple_key_mismatch(self): Employee1 = NamedTuple('Employee', [('name', str), ('id', int)]) Employee2 = NamedTuple('Employee', [('firstname', str), ('id', int)]) @pedantic def foo(bar: Employee1) -> None: print(bar) with self.assertRaises(PedanticTypeCheckException): foo(bar=Employee2('bob', 1))
def test_namedtuple_type_mismatch(self)
-
Expand source code
def test_namedtuple_type_mismatch(self): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic def foo(bar: Employee) -> None: print(bar) with self.assertRaises(PedanticTypeCheckException): foo(bar=('bob', 1))
def test_namedtuple_wrong_field_type(self)
-
Expand source code
def test_namedtuple_wrong_field_type(self): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) @pedantic def foo(bar: Employee) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(bar=Employee(2, 1))
def test_nested_type_hints_1(self)
-
Expand source code
def test_nested_type_hints_1(self): @pedantic def calc(n: int) -> List[List[float]]: return [0.0 * n] with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42)
def test_nested_type_hints_1_corrected(self)
-
Expand source code
def test_nested_type_hints_1_corrected(self): @pedantic def calc(n: int) -> List[List[float]]: return [[0.0 * n]] calc(n=42)
def test_nested_type_hints_2(self)
-
Problem here: int != float
Expand source code
def test_nested_type_hints_2(self): """Problem here: int != float""" @pedantic def calc(n: int) -> List[Tuple[float, str]]: return [(n, str(n))] with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42)
def test_nested_type_hints_2_corrected(self)
-
Expand source code
def test_nested_type_hints_2_corrected(self): @pedantic def calc(n: int) -> List[Tuple[int, str]]: return [(n, str(n))] @pedantic def calc_2(n: float) -> List[Tuple[float, str]]: return [(n, str(n))] calc(n=42) calc_2(n=42.0)
def test_nested_type_hints_3(self)
-
Problem here: inner function actually returns Tuple[int, str]
Expand source code
def test_nested_type_hints_3(self): """Problem here: inner function actually returns Tuple[int, str]""" @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, str]]: @pedantic def f(x: int, y: float) -> Tuple[float, str]: return n * x, str(y) return f with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42)(x=3, y=3.14)
def test_nested_type_hints_3_corrected(self)
-
Expand source code
def test_nested_type_hints_3_corrected(self): @pedantic def calc(n: int) -> Callable[[int, float], Tuple[int, str]]: @pedantic def f(x: int, y: float) -> Tuple[int, str]: return n * x, str(y) return f calc(n=42)(x=3, y=3.14)
def test_nested_type_hints_4(self)
-
Problem here: return type is actually float
Expand source code
def test_nested_type_hints_4(self): """Problem here: return type is actually float""" @pedantic def calc(n: List[List[float]]) -> int: return n[0][0] with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=[[42.0]])
def test_nested_type_hints_5(self)
-
Problem here: Tuple[float, str] != Tuple[float, float]
Expand source code
def test_nested_type_hints_5(self): """Problem here: Tuple[float, str] != Tuple[float, float]""" @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, str]]: @pedantic def f(x: int, y: float) -> Tuple[float, float]: return n * float(x), y return f with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42)
def test_nested_type_hints_5_corrected(self)
-
Expand source code
def test_nested_type_hints_5_corrected(self): @pedantic def calc(n: int) -> Callable[[int, float], Tuple[float, float]]: @pedantic def f(x: int, y: float) -> Tuple[float, float]: return n * float(x), y return f calc(n=42)
def test_nested_type_hints_corrected(self)
-
Expand source code
def test_nested_type_hints_corrected(self): @pedantic def calc(n: List[List[float]]) -> int: return int(n[0][0]) calc(n=[[42.0]])
def test_new_type(self)
-
Expand source code
def test_new_type(self): UserId = NewType('UserId', int) @pedantic def get_user_name(user_id: UserId) -> str: return str(user_id) some_id = UserId(524313) get_user_name(user_id=some_id) # the following would be desirable but impossible to check at runtime: # with self.assertRaises(expected_exception=AssertionError): # get_user_name(user_id=-1)
def test_newtype(self)
-
Expand source code
def test_newtype(self): myint = NewType("myint", int) @pedantic def foo(a: myint) -> int: return 42 assert foo(a=1) == 42 with self.assertRaises(PedanticTypeCheckException): foo(a="a")
def test_no_kwargs(self)
-
Expand source code
def test_no_kwargs(self): @pedantic def calc(n: int, m: int, i: int) -> int: return n + m + i with self.assertRaises(expected_exception=PedanticCallWithArgsException): calc(42, 40, 38) with self.assertRaises(expected_exception=PedanticCallWithArgsException): calc(42, m=40, i=38) calc(n=42, m=40, i=38)
def test_none_1(self)
-
Problem here: None is not accepted
Expand source code
def test_none_1(self): """Problem here: None is not accepted""" @pedantic def calc(n: int, m: int, i: int) -> int: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=None)
def test_none_2(self)
-
Expand source code
def test_none_2(self): @pedantic def calc(n: int, m: int, i: Optional[int]) -> int: return n + m + i if i is not None else n + m calc(n=42, m=40, i=None)
def test_none_3(self)
-
Expand source code
def test_none_3(self): @pedantic def calc(n: int, m: int, i: Union[int, None]) -> int: return n + m + i if i is not None else n + m calc(n=42, m=40, i=None)
def test_none_4(self)
-
Problem here: function may return None
Expand source code
def test_none_4(self): """Problem here: function may return None""" @pedantic def calc(n: int, m: int, i: Union[int, None]) -> int: return n + m + i if i is not None else None calc(n=42, m=40, i=42) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=None)
def test_none_5(self)
-
Expand source code
def test_none_5(self): @pedantic def calc(n: int, m: int, i: Union[int, None]) -> Optional[int]: return n + m + i if i is not None else None calc(n=42, m=40, i=None)
def test_noreturn(self)
-
Expand source code
def test_noreturn(self): @pedantic def foo() -> NoReturn: pass @pedantic def bar() -> NoReturn: raise ZeroDivisionError('bar') with self.assertRaises(expected_exception=ZeroDivisionError): bar() with self.assertRaises(PedanticTypeCheckException): foo()
def test_optional_args_1(self)
-
Expand source code
def test_optional_args_1(self): @pedantic def calc(a: int, b: int = 42) -> int: return a + b calc(a=2)
def test_optional_args_2(self)
-
Expand source code
def test_optional_args_2(self): @pedantic def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float: return a + b + c calc() calc(a=1) calc(b=1) calc(c=1.0) calc(a=1, b=1) calc(a=1, c=1.0) calc(b=1, c=1.0) calc(a=1, b=1, c=1.0)
def test_optional_args_3(self)
-
Problem here: optional argument c: 5 is not a float
Expand source code
def test_optional_args_3(self): """Problem here: optional argument c: 5 is not a float""" @pedantic def calc(a: int = 3, b: int = 42, c: float = 5) -> float: return a + b + c with self.assertRaises(expected_exception=PedanticTypeCheckException): calc()
def test_optional_args_3_corrected(self)
-
Expand source code
def test_optional_args_3_corrected(self): @pedantic def calc(a: int = 3, b: int = 42, c: float = 5.0) -> float: return a + b + c calc()
def test_optional_args_4(self)
-
Expand source code
def test_optional_args_4(self): class MyClass: @pedantic def foo(self, a: int, b: Optional[int] = 1) -> int: return a + b my_class = MyClass() my_class.foo(a=10)
def test_optional_args_5(self)
-
Expand source code
def test_optional_args_5(self): @pedantic def calc(d: Optional[Dict[int, int]] = None) -> Optional[int]: if d is None: return None return sum(d.keys()) calc(d=None) calc() calc(d={42: 3}) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(d={42: 3.14})
def test_optional_args_6(self)
-
"Problem here: str != int
Expand source code
def test_optional_args_6(self): """"Problem here: str != int""" @pedantic def calc(d: int = 42) -> int: return int(d) calc(d=99999) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(d='999999')
def test_pedantic(self)
-
Expand source code
def test_pedantic(self): @pedantic def foo(a: int, b: str) -> str: return 'abc' self.assertEqual('abc', foo(a=4, b='abc'))
def test_pedantic_always(self)
-
Expand source code
def test_pedantic_always(self): @pedantic def foo(a: int, b: str) -> str: return 'abc' self.assertEqual('abc', foo(a=4, b='abc'))
def test_pedantic_arguments_fail(self)
-
Expand source code
def test_pedantic_arguments_fail(self): @pedantic def foo(a: int, b: str) -> str: return 'abc' with self.assertRaises(expected_exception=PedanticTypeCheckException): foo(a=4, b=5)
def test_pedantic_on_class(self)
-
Expand source code
def test_pedantic_on_class(self): with self.assertRaises(expected_exception=PedanticTypeCheckException): @pedantic class MyClass: pass MyClass()
def test_pedantic_return_type_fail(self)
-
Expand source code
def test_pedantic_return_type_fail(self): @pedantic def foo(a: int, b: str) -> str: return 6 with self.assertRaises(expected_exception=PedanticTypeCheckException): foo(a=4, b='abc')
def test_pedantic_return_type_var_fail(self)
-
Expand source code
def test_pedantic_return_type_var_fail(self): T = TypeVar('T', int, float) @pedantic def foo(a: T, b: T) -> T: return 'a' with self.assertRaises(PedanticTypeCheckException): foo(a=4, b=2)
def test_primitive_list_dict_tuple(self)
-
Expand source code
def test_primitive_list_dict_tuple(self): @pedantic def f(x: list[dict[int, tuple[float, str]]]) -> list[Any]: return x f(x=[{3: (3.24, 'hi')}]) for value in [ [{3, (3, 'hi')}], [{3: (3, 'hi')}], [{3: (3.24, 3)}], [{3: (3.24, 'hi')}, {0}], ]: with self.assertRaises(PedanticTypeCheckException): f(x=value)
def test_return_generator(self)
-
Expand source code
def test_return_generator(self): @pedantic def genfunc() -> Generator[int, None, None]: yield 1 @pedantic def foo() -> Generator[int, None, None]: return genfunc() foo()
def test_return_type_none(self)
-
Expand source code
def test_return_type_none(self): @pedantic def foo() -> None: return 'a' with self.assertRaises(expected_exception=PedanticTypeCheckException): foo()
def test_sequence(self)
-
Expand source code
def test_sequence(self): @pedantic def foo(a: Sequence[str]) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: foo(a=value)
def test_sequence_bad_element(self)
-
Expand source code
def test_sequence_bad_element(self): @pedantic def foo(a: Sequence[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=[1, 2, 'bb'])
def test_sequence_bad_type(self)
-
Expand source code
def test_sequence_bad_type(self): @pedantic def foo(a: Sequence[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5)
def test_sequence_no_type_args(self)
-
Expand source code
def test_sequence_no_type_args(self): @pedantic def foo(a: Sequence) -> None: print(a) for value in [('a', 'b'), ['a', 'b'], 'abc']: with self.assertRaises(PedanticTypeCheckException): foo(a=value)
def test_set(self)
-
Expand source code
def test_set(self): @pedantic def foo_1(a: AbstractSet[int]) -> None: print(a) @pedantic def foo_2(a: Set[int]) -> None: print(a) for value in [set(), {6}]: foo_1(a=value) foo_2(a=value)
def test_set_bad_element(self)
-
Expand source code
def test_set_bad_element(self): @pedantic def foo(a: Set[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a={1, 2, 'bb'})
def test_set_bad_type(self)
-
Expand source code
def test_set_bad_type(self): @pedantic def foo(a: Set[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5)
def test_set_no_type_args(self)
-
Expand source code
def test_set_no_type_args(self): @pedantic def foo_1(a: AbstractSet) -> None: print(a) @pedantic def foo_2(a: Set) -> None: print(a) @pedantic def foo_3(a: set) -> None: print(a) for value in [set(), {6}]: with self.assertRaises(PedanticTypeCheckException): foo_1(a=value) with self.assertRaises(PedanticTypeCheckException): foo_2(a=value) with self.assertRaises(PedanticTypeCheckException): foo_3(a=value)
def test_sloppy_types_dict(self)
-
Expand source code
def test_sloppy_types_dict(self): @pedantic def operation(d: dict) -> int: return len(d.keys()) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d={1: 1, 2: 2})
def test_sloppy_types_dict_almost_corrected_no_type_args(self)
-
Expand source code
def test_sloppy_types_dict_almost_corrected_no_type_args(self): @pedantic def operation(d: Dict) -> int: return len(d.keys()) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d={1: 1, 2: 2})
def test_sloppy_types_dict_corrected(self)
-
Expand source code
def test_sloppy_types_dict_corrected(self): @pedantic def operation(d: Dict[int, int]) -> int: return len(d.keys()) operation(d={1: 1, 2: 2})
def test_sloppy_types_frozenset(self)
-
Expand source code
def test_sloppy_types_frozenset(self): @pedantic def operation(d: frozenset) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=frozenset({1, 2, 3}))
def test_sloppy_types_frozenset_almost_corrected_no_type_args(self)
-
Expand source code
def test_sloppy_types_frozenset_almost_corrected_no_type_args(self): @pedantic def operation(d: FrozenSet) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=frozenset({1, 2, 3}))
def test_sloppy_types_frozenset_corrected(self)
-
Expand source code
def test_sloppy_types_frozenset_corrected(self): @pedantic def operation(d: FrozenSet[int]) -> int: return len(d) operation(d=frozenset({1, 2, 3}))
def test_sloppy_types_list(self)
-
Expand source code
def test_sloppy_types_list(self): @pedantic def operation(d: list) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=[1, 2, 3, 4])
def test_sloppy_types_list_almost_corrected_no_type_args(self)
-
Expand source code
def test_sloppy_types_list_almost_corrected_no_type_args(self): @pedantic def operation(d: List) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=[1, 2, 3, 4])
def test_sloppy_types_list_corrected(self)
-
Expand source code
def test_sloppy_types_list_corrected(self): @pedantic def operation(d: List[int]) -> int: return len(d) operation(d=[1, 2, 3, 4])
def test_sloppy_types_set(self)
-
Expand source code
def test_sloppy_types_set(self): @pedantic def operation(d: set) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d={1, 2, 3})
def test_sloppy_types_set_almost_corrected_to_type_args(self)
-
Expand source code
def test_sloppy_types_set_almost_corrected_to_type_args(self): @pedantic def operation(d: Set) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d={1, 2, 3})
def test_sloppy_types_set_corrected(self)
-
Expand source code
def test_sloppy_types_set_corrected(self): @pedantic def operation(d: Set[int]) -> int: return len(d) operation(d={1, 2, 3})
def test_sloppy_types_tuple(self)
-
Expand source code
def test_sloppy_types_tuple(self): @pedantic def operation(d: tuple) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=(1, 2, 3))
def test_sloppy_types_tuple_almost_corrected_no_type_args(self)
-
Expand source code
def test_sloppy_types_tuple_almost_corrected_no_type_args(self): @pedantic def operation(d: Tuple) -> int: return len(d) with self.assertRaises(expected_exception=PedanticTypeCheckException): operation(d=(1, 2, 3))
def test_sloppy_types_tuple_corrected(self)
-
Expand source code
def test_sloppy_types_tuple_corrected(self): @pedantic def operation(d: Tuple[int, int, int]) -> int: return len(d) operation(d=(1, 2, 3))
def test_text_io(self)
-
Expand source code
def test_text_io(self): @pedantic def foo(a: TextIO) -> None: print(a) foo(a=StringIO())
def test_text_io_fail(self)
-
Expand source code
def test_text_io_fail(self): @pedantic def foo(a: BinaryIO) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo(a=StringIO())
def test_text_io_real_file(self)
-
Expand source code
def test_text_io_real_file(self): @pedantic def foo(a: TextIO) -> None: print(a) with open(file=TEST_FILE, mode='w') as f: foo(a=f)
def test_tuple(self)
-
Expand source code
def test_tuple(self): @pedantic def foo_1(a: Tuple[int, int]) -> None: print(a) @pedantic def foo_2(a: Tuple[int, ...]) -> None: print(a) foo_1(a=(1, 2)) foo_2(a=(1, 2))
def test_tuple_bad_element(self)
-
Expand source code
def test_tuple_bad_element(self): @pedantic def foo(a: Tuple[int, str]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=(1, 2))
def test_tuple_bad_type(self)
-
Expand source code
def test_tuple_bad_type(self): @pedantic def foo(a: Tuple[int]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=5)
def test_tuple_ellipsis_bad_element(self)
-
Expand source code
def test_tuple_ellipsis_bad_element(self): @pedantic def foo(a: Tuple[int, ...]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=(1, 2, 'blah'))
def test_tuple_no_type_args(self)
-
Expand source code
def test_tuple_no_type_args(self): @pedantic def foo_1(a: Tuple) -> None: print(a) @pedantic def foo_2(a: tuple) -> None: print(a) with self.assertRaises(PedanticTypeCheckException): foo_1(a=(1, 2)) with self.assertRaises(PedanticTypeCheckException): foo_2(a=(1, 2))
def test_tuple_too_few_elements(self)
-
Expand source code
def test_tuple_too_few_elements(self): @pedantic def foo(a: Tuple[int, str]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=(1,))
def test_tuple_too_many_elements(self)
-
Expand source code
def test_tuple_too_many_elements(self): @pedantic def foo(a: Tuple[int, str]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=(1, 'aa', 2))
def test_tuple_without_args_corrected(self)
-
Expand source code
def test_tuple_without_args_corrected(self): @pedantic def calc(i: Tuple[Any, ...]) -> str: return str(i) calc(i=(42.0, 43, 'hi'))
def test_tuple_without_type_args(self)
-
Expand source code
def test_tuple_without_type_args(self): @pedantic def calc(i: Tuple) -> str: return str(i) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(i=(42.0, 43, 'hi'))
def test_type_list_but_got_tuple(self)
-
Expand source code
def test_type_list_but_got_tuple(self): @pedantic def calc(ls: List[Any]) -> int: return len(ls) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(ls=(1, 2, 3))
def test_type_list_corrected(self)
-
Expand source code
def test_type_list_corrected(self): @pedantic def calc(ls: Tuple[Any, ...]) -> int: return len(ls) calc(ls=(1, 2, 3))
def test_type_var(self)
-
Expand source code
def test_type_var(self): T = TypeVar('T') @pedantic def first(ls: List[T]) -> T: return ls[0] first(ls=[1, 2, 3])
def test_type_var_bound_fail(self)
-
Expand source code
def test_type_var_bound_fail(self): T = TypeVar('T', bound=Child) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=Parent(), b=Parent())
def test_type_var_constraints(self)
-
Expand source code
def test_type_var_constraints(self): T = TypeVar('T', int, str) @pedantic def foo(a: T, b: T) -> None: pass for values in [ {'a': 6, 'b': 7}, {'a': 'aa', 'b': "bb"}, ]: foo(**values)
def test_type_var_constraints_fail_typing_type(self)
-
Expand source code
def test_type_var_constraints_fail_typing_type(self): T = TypeVar('T', int, Collection) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a='aa', b='bb')
def test_type_var_contravariant(self)
-
Expand source code
def test_type_var_contravariant(self): T = TypeVar('T', contravariant=True) @pedantic def foo(a: T, b: T) -> None: pass foo(a=Child(), b=Parent())
def test_type_var_contravariant_fail(self)
-
Expand source code
def test_type_var_contravariant_fail(self): T = TypeVar('T', contravariant=True) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeVarMismatchException): foo(a=Parent(), b=Child())
def test_type_var_covariant(self)
-
Expand source code
def test_type_var_covariant(self): T = TypeVar('T', covariant=True) @pedantic def foo(a: T, b: T) -> None: pass foo(a=Parent(), b=Child())
def test_type_var_covariant_fail(self)
-
Expand source code
def test_type_var_covariant_fail(self): T = TypeVar('T', covariant=True) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeVarMismatchException): foo(a=Child(), b=Parent())
def test_type_var_forward_ref_bound(self)
-
Expand source code
def test_type_var_forward_ref_bound(self): TBound = TypeVar('TBound', bound='Parent') @pedantic def func(x: TBound) -> None: pass func(x=Parent()) with self.assertRaises(PedanticTypeCheckException): func(x='foo')
def test_type_var_invariant_fail(self)
-
Expand source code
def test_type_var_invariant_fail(self): T = TypeVar('T', int, str) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=2, b=3.6)
def test_type_var_wrong(self)
-
Expand source code
def test_type_var_wrong(self): T = TypeVar('T') @pedantic def first(ls: List[T]) -> T: return str(ls[0]) with self.assertRaises(expected_exception=PedanticTypeVarMismatchException): first(ls=[1, 2, 3])
def test_type_var_wrong_sequence(self)
-
Expand source code
def test_type_var_wrong_sequence(self): T = TypeVar('T') @pedantic def first(ls: Sequence[T]) -> T: return str(ls[0]) with self.assertRaises(expected_exception=PedanticTypeVarMismatchException): first(ls=[1, 2, 3])
def test_typevar_bound(self)
-
Expand source code
def test_typevar_bound(self): T = TypeVar('T', bound=Parent) @pedantic def foo(a: T, b: T) -> None: pass foo(a=Child(), b=Child())
def test_typevar_constraints_fail(self)
-
Expand source code
def test_typevar_constraints_fail(self): T = TypeVar('T', int, str) @pedantic def foo(a: T, b: T) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=2.5, b='aa')
def test_union(self)
-
Expand source code
def test_union(self): @pedantic def foo(a: Union[str, int]) -> None: pass for value in [6, 'xa']: foo(a=value)
def test_union_fail(self)
-
Expand source code
def test_union_fail(self): @pedantic def foo(a: Union[str, int]) -> None: pass for value in [5.6, b'xa']: with self.assertRaises(PedanticTypeCheckException): foo(a=value)
def test_union_new_syntax(self)
-
Expand source code
def test_union_new_syntax(self): @pedantic def foo(a: str | int) -> None: pass for value in [6, 'xa']: foo(a=value) with self.assertRaises(PedanticTypeCheckException): foo(a=1.7)
def test_union_typing_type(self)
-
Expand source code
def test_union_typing_type(self): @pedantic def foo(a: Union[str, Collection]) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=1)
def test_varargs(self)
-
Expand source code
def test_varargs(self): @pedantic def foo(*args: int) -> None: pass foo(1, 2)
def test_varargs_fail(self)
-
Expand source code
def test_varargs_fail(self): @pedantic def foo(*args: int) -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(1, 'a')
def test_wrapped_function(self)
-
Expand source code
def test_wrapped_function(self): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @pedantic @decorator def foo(a: 'Child') -> None: pass with self.assertRaises(PedanticTypeCheckException): foo(a=Parent())
def test_wrapped_generator_no_return_type_annotation(self)
-
Test that return type checking works in a generator function too.
Expand source code
def test_wrapped_generator_no_return_type_annotation(self): """Test that return type checking works in a generator function too.""" @pedantic def generate(a: int) -> Generator[int, int, None]: yield a yield a + 1 gen = generate(a=1) next(gen)
def test_wrong_type_hint_1(self)
-
Problem here: str != int
Expand source code
def test_wrong_type_hint_1(self): """Problem here: str != int""" @pedantic def calc(n: int, m: int, i: int) -> str: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38)
def test_wrong_type_hint_1_corrected(self)
-
Expand source code
def test_wrong_type_hint_1_corrected(self): @pedantic def calc(n: int, m: int, i: int) -> str: return str(n + m + i) calc(n=42, m=40, i=38)
def test_wrong_type_hint_2(self)
-
Problem here: str != int
Expand source code
def test_wrong_type_hint_2(self): """Problem here: str != int""" @pedantic def calc(n: int, m: int, i: str) -> int: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38)
def test_wrong_type_hint_2_corrected(self)
-
Expand source code
def test_wrong_type_hint_2_corrected(self): @pedantic def calc(n: int, m: int, i: str) -> int: return n + m + int(i) calc(n=42, m=40, i='38')
def test_wrong_type_hint_3(self)
-
Problem here: None != int
Expand source code
def test_wrong_type_hint_3(self): """Problem here: None != int""" @pedantic def calc(n: int, m: int, i: int) -> None: return n + m + i with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38)
def test_wrong_type_hint_4(self)
-
Problem here: None != int
Expand source code
def test_wrong_type_hint_4(self): """Problem here: None != int""" @pedantic def calc(n: int, m: int, i: int) -> int: print(n + m + i) with self.assertRaises(expected_exception=PedanticTypeCheckException): calc(n=42, m=40, i=38)
def test_wrong_type_hint_4_corrected(self)
-
Expand source code
def test_wrong_type_hint_4_corrected(self): @pedantic def calc(n: int, m: int, i: int) -> int: return n + m + i calc(n=42, m=40, i=38)
def test_wrong_type_hint_corrected(self)
-
Expand source code
def test_wrong_type_hint_corrected(self): @pedantic def calc(n: int, m: int, i: int) -> None: print(n + m + i) calc(n=42, m=40, i=38)