Type safe checker and signature decorator
Project description
ty-sig
Type safe checker and signature decorator
from tysig.tysig import TySig
is_type examples
check type of variable including typing types e.g. Union, Optional, List, Dict, Tuple, Literal, Any, AnyStr, TypeVar, etc.
from typing import Union, Optional, Dict, List, Tuple, Any, AnyStr
help(TySig)
Help on class TySig in module tysig.tysig:
class TySig(builtins.object)
| Static methods defined here:
|
| getattr_name(invar) -> Union[str, NoneType]
| gets name of type of invar
| i.e. gets __name__, or _name, or __origin__ of input object
|
| :param invar: object we are checking name of
| :return: name if exists otherwise None
|
| is_type(var: object, check_type) -> bool
| recursively checks if var is of type check_type
|
| :param var: variable to check type
| :param check_type: type to check against
| :return: True if var is of type check_type, else False
|
| is_typing_type(vtype)
| check if type vtype is a typing type of either:
| _GenericAlias, _VariadicGenericAlias, or _SpecialForm
|
| :param vtype: we are checking the type of this type
| :return: True if is a typing type, else False
|
| signature(classobj: bool = False, **in_vars_types)
| signature decorator applied to functions to hard check the types
| of the arguments including typing types. Also applies default values,
| and raises exceptions on failing type checks. Uses is_type function.
|
| Return types are also checked post execution of function.
|
| :param classobj: set to True if within a class (self object)
| :param in_vars_types: arguments with their types and/or default values
| e.g. @signature(a=int, b=Union[float, str],
| c=List[Dict[str, Tuple[str, int]]]
| :return: applies signature checks and applies default values
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
def print_check(var, ntype, check):
print("\n", "-" * 30)
print(f"CHECK: {var} is {ntype} ? --> ", check)
print("-" * 30)
help(TySig.is_type)
Help on function is_type in module tysig.tysig:
is_type(var: object, check_type) -> bool
recursively checks if var is of type check_type
:param var: variable to check type
:param check_type: type to check against
:return: True if var is of type check_type, else False
AType = Tuple[Union[float, str], Union[int, str], Union[float, str]]
BType = Tuple[Union[float, str], Union[List[int], str],
Union[float, str]]
a: AType = (2.3, 1, "oik") # type: ignore
check = TySig.is_type(a, AType)
print_check(a, AType, check)
# False example
check = TySig.is_type(a, BType)
print_check(a, BType, check)
# False example
a2: AType = (2.3, 1.6, "oik")
check = TySig.is_type(a2, AType)
print_check(a2, AType, check)
------------------------------
CHECK: (2.3, 1, 'oik') is typing.Tuple[typing.Union[float, str], typing.Union[int, str], typing.Union[float, str]] ? --> True
------------------------------
------------------------------
CHECK: (2.3, 1, 'oik') is typing.Tuple[typing.Union[float, str], typing.Union[typing.List[int], str], typing.Union[float, str]] ? --> False
------------------------------
------------------------------
CHECK: (2.3, 1.6, 'oik') is typing.Tuple[typing.Union[float, str], typing.Union[int, str], typing.Union[float, str]] ? --> False
------------------------------
BType = Dict[
int,
Tuple[
float,
str,
List[
Union[
Dict[str, int],
List[float]
]
]
]
]
b: BType = {
4: (3.7, "je;p", [[4.5, 90.0], {"h": 3}, {"pp": 1}, []]),
5: (3.7, "je;p", [[4.5, 90.2], {"h": 3}, {"pp": 1}, [], {"1": 2}])
}
check = TySig.is_type(b, BType)
print_check(b, BType, check)
# False example
b2: BType = {
4: (3.7, "je;p", [[4.5, 90.0], {"h": 3.1}, {"pp": 1}, []]),
5: (3.7, "je;p", [[4.5, 90.2], {"h": 3}, {"pp": 1}, [], {"1": 2}])
}
check = TySig.is_type(b2, BType)
print_check(b2, BType, check)
------------------------------
CHECK: {4: (3.7, 'je;p', [[4.5, 90.0], {'h': 3}, {'pp': 1}, []]), 5: (3.7, 'je;p', [[4.5, 90.2], {'h': 3}, {'pp': 1}, [], {'1': 2}])} is typing.Dict[int, typing.Tuple[float, str, typing.List[typing.Union[typing.Dict[str, int], typing.List[float]]]]] ? --> True
------------------------------
------------------------------
CHECK: {4: (3.7, 'je;p', [[4.5, 90.0], {'h': 3.1}, {'pp': 1}, []]), 5: (3.7, 'je;p', [[4.5, 90.2], {'h': 3}, {'pp': 1}, [], {'1': 2}])} is typing.Dict[int, typing.Tuple[float, str, typing.List[typing.Union[typing.Dict[str, int], typing.List[float]]]]] ? --> False
------------------------------
CType = Dict[str,
Dict[int,
Dict[float,
List[
Tuple[
Dict[int, float],
Union[int, float],
str
]
]]]]
c: CType = {
"h": {1: {3.3: [({1: 1.}, 5, "hello"), ({3: 1.}, 50, "bbbello")]}},
"ss": {1: {
3.5: [({1: 1.}, 5., "hello"), ({3: 1.6}, 50.6, "bbbello")]}},
}
check = TySig.is_type(c, CType)
print_check(c, CType, check)
# False example
c2: CType = {
"h": {1: {3.3: [({1: 1.}, 5, "hello"), ({3: 1.}, 50, 2.6)]}},
"ss": {1: {
3.5: [({1: 1.}, 5., "hello"), ({3: 1.6}, 50.6, "bbbello")]}},
}
check = TySig.is_type(c2, CType)
print_check(c2, CType, check)
------------------------------
CHECK: {'h': {1: {3.3: [({1: 1.0}, 5, 'hello'), ({3: 1.0}, 50, 'bbbello')]}}, 'ss': {1: {3.5: [({1: 1.0}, 5.0, 'hello'), ({3: 1.6}, 50.6, 'bbbello')]}}} is typing.Dict[str, typing.Dict[int, typing.Dict[float, typing.List[typing.Tuple[typing.Dict[int, float], typing.Union[int, float], str]]]]] ? --> True
------------------------------
------------------------------
CHECK: {'h': {1: {3.3: [({1: 1.0}, 5, 'hello'), ({3: 1.0}, 50, 2.6)]}}, 'ss': {1: {3.5: [({1: 1.0}, 5.0, 'hello'), ({3: 1.6}, 50.6, 'bbbello')]}}} is typing.Dict[str, typing.Dict[int, typing.Dict[float, typing.List[typing.Tuple[typing.Dict[int, float], typing.Union[int, float], str]]]]] ? --> False
------------------------------
DType = Tuple[Optional[float], Optional[int], Optional[str]]
d: DType = (2.3, 1, "oik")
check = TySig.is_type(d, DType)
print_check(d, DType, check)
d2: DType = (None, 1, "oik")
check = TySig.is_type(d2, DType)
print_check(d2, DType, check)
d3: DType = (2.3, None, "oik")
check = TySig.is_type(d3, DType)
print_check(d3, DType, check)
d4: DType = (2.3, 1, None)
check = TySig.is_type(d4, DType)
print_check(d4, DType, check)
# False example
d5: DType = (2, 1, None)
check = TySig.is_type(d5, DType)
print_check(d5, DType, check)
------------------------------
CHECK: (2.3, 1, 'oik') is typing.Tuple[typing.Union[float, NoneType], typing.Union[int, NoneType], typing.Union[str, NoneType]] ? --> True
------------------------------
------------------------------
CHECK: (None, 1, 'oik') is typing.Tuple[typing.Union[float, NoneType], typing.Union[int, NoneType], typing.Union[str, NoneType]] ? --> True
------------------------------
------------------------------
CHECK: (2.3, None, 'oik') is typing.Tuple[typing.Union[float, NoneType], typing.Union[int, NoneType], typing.Union[str, NoneType]] ? --> True
------------------------------
------------------------------
CHECK: (2.3, 1, None) is typing.Tuple[typing.Union[float, NoneType], typing.Union[int, NoneType], typing.Union[str, NoneType]] ? --> True
------------------------------
------------------------------
CHECK: (2, 1, None) is typing.Tuple[typing.Union[float, NoneType], typing.Union[int, NoneType], typing.Union[str, NoneType]] ? --> False
------------------------------
print(TySig.is_type("hello", str), "Expecting True")
print(TySig.is_type(44, int), "Expecting True")
print(TySig.is_type(3434.3434, float), "Expecting True")
print(TySig.is_type([], list), "Expecting True")
print(TySig.is_type({1: 2}, dict), "Expecting True")
print(TySig.is_type((1, 2), tuple), "Expecting True")
print(TySig.is_type("hello", int), "Expecting False")
print(TySig.is_type("jhnj", int), "Expecting False")
print(TySig.is_type(3434, float), "Expecting False")
print(TySig.is_type([], tuple), "Expecting False")
print(TySig.is_type({1: 2}, list), "Expecting False")
print(TySig.is_type((1, 2), dict), "Expecting False")
True Expecting True
True Expecting True
True Expecting True
True Expecting True
True Expecting True
True Expecting True
False Expecting False
False Expecting False
False Expecting False
False Expecting False
False Expecting False
False Expecting False
Signature examples
Apply signature decorator on top of any function, which will be type-safe - raising exceptions where granular level types are not correct.
help(TySig.signature)
Help on function signature in module tysig.tysig:
signature(classobj: bool = False, **in_vars_types)
signature decorator applied to functions to hard check the types
of the arguments including typing types. Also applies default values,
and raises exceptions on failing type checks. Uses is_type function.
Return types are also checked post execution of function.
:param classobj: set to True if within a class (self object)
:param in_vars_types: arguments with their types and/or default values
e.g. @signature(a=int, b=Union[float, str],
c=List[Dict[str, Tuple[str, int]]]
:return: applies signature checks and applies default values
Working and Non-Working examples below
@TySig.signature(a=(8, int), b=float, c=str, d=Tuple[str, List[int]])
def fn(*args, **kwargs):
print(args)
print(kwargs)
return args, kwargs
# working example where the data within the data structures conform to the signature
res = fn("hello", ("dd", [1, 2]), b=2.2)
print(res == ((), {'a': 8, 'c': 'hello', 'd': ('dd', [1, 2]), 'b': 2.2}))
()
{'a': 8, 'c': 'hello', 'd': ('dd', [1, 2]), 'b': 2.2}
True
# non-working example where the data within the data structures do not conform to the signature
try:
_ = fn("hello", ("dd", [1., 2]), b=2.2) # list within tuple is only allowed to hold int's
except TypeError as exp:
print(exp)
'd' type should be 'typing.Tuple[str, typing.List[int]]' instead found '<class 'tuple'>'. If you're using GenericAlias, VariadicGenericAlias, or SpecialForm types then please check the sub argument types are correct
@TySig.signature(
idx=(0, int),
name=Optional[str],
dob=Union[Tuple[int, int, int], str],
history=Dict[str, Tuple[List[Dict[int, List[Union[str, float]]]],
float, Optional[int]]],
ranking=float
)
def fn2(*args, **kwargs):
print(args)
print(kwargs)
return args, kwargs
# working example where the data within the data structures conform to the signature
res = fn2(
None, (2000, 1, 1), 2.3, history={
"gs": (
[
{
1: ["dzf", "JKkj", 1., "jh", 98.8, "kj", 2.3, 989.],
2: [2.3, 989.],
3: ["dzf", "JKkj"],
4: []
},
{
16: ["dzf", "JKkj", 1., "jh", 98.8, "kj", 2.3,
989.],
26: [2.3, 989.],
36: ["dzf", "JKkj"],
46: []
}
], 98.98, None
)
}
)
()
{'idx': 0, 'name': None, 'dob': (2000, 1, 1), 'ranking': 2.3, 'history': {'gs': ([{1: ['dzf', 'JKkj', 1.0, 'jh', 98.8, 'kj', 2.3, 989.0], 2: [2.3, 989.0], 3: ['dzf', 'JKkj'], 4: []}, {16: ['dzf', 'JKkj', 1.0, 'jh', 98.8, 'kj', 2.3, 989.0], 26: [2.3, 989.0], 36: ['dzf', 'JKkj'], 46: []}], 98.98, None)}}
# non-working example where the data within the data structures do not conform to the signature
try:
_ = fn2(
None, (2000, 1, 1), 2.3, history={
"gs": [ # this part of 'history' a list but should be tuple as per signature
[
{
1: ["dzf", "JKkj", 1., "jh", 98.8, "kj", 2.3,
989.],
2: [2.3, 989.],
3: ["dzf", "JKkj"],
4: []
},
{
16: ["dzf", "JKkj", 1., "jh", 98.8, "kj", 2.3,
989.],
26: [2.3, 989.],
36: ["dzf", "JKkj"],
46: []
}
], 98.98, None
]
}
)
except TypeError as exp:
print(exp)
'history' type should be 'typing.Dict[str, typing.Tuple[typing.List[typing.Dict[int, typing.List[typing.Union[str, float]]]], float, typing.Union[int, NoneType]]]' instead found '<class 'dict'>'. If you're using GenericAlias, VariadicGenericAlias, or SpecialForm types then please check the sub argument types are correct
# non-working example where the data within the data structures do not conform to the signature
try:
_ = fn2(
None, (2000, 1, "1"), 2.3, history={ # dob tuple, last element is str but should be int
"gs": (
[
{
1: ["dzf", "JKkj", 1., "jh", 98.8, "kj", 2.3,
989.],
2: [2.3, 989.],
3: ["dzf", "JKkj"],
4: []
},
{
16: ["dzf", "JKkj", 1., "jh", 98.8, "kj", 2.3,
989.],
26: [2.3, 989.],
36: ["dzf", "JKkj"],
46: []
}
], 98.98, None
)
}
)
except TypeError as exp:
print(exp)
'dob' type should be 'typing.Union[typing.Tuple[int, int, int], str]' instead found '<class 'tuple'>'. If you're using GenericAlias, VariadicGenericAlias, or SpecialForm types then please check the sub argument types are correct
from datetime import datetime
@TySig.signature(
name_id=Union[Optional[str], int],
favnum=(7, int),
dob=Union[datetime, Tuple[int, int, int]]
)
def fn3(*args, **kwargs):
print(args)
print(kwargs)
return args, kwargs
# working examples where the data within the data structures conform to the signature
_ = fn3(datetime(2000, 2, 20), name_id=None)
_ = fn3(8, (2000, 5, 20), name_id=None)
()
{'favnum': 7, 'dob': datetime.datetime(2000, 2, 20, 0, 0), 'name_id': None}
()
{'favnum': 8, 'dob': (2000, 5, 20), 'name_id': None}
@TySig.signature(
idx=(0, int),
name=Optional[str],
dob=Union[Tuple[int, int, int], str],
history=(
{"1": ([{1: []}], 0., None)},
Dict[str, Tuple[List[Dict[int, List[Union[str, float]]]],
float, Optional[int]]]
),
ranking=float
)
def fn4(*args, **kwargs):
print(args)
print(kwargs)
return args, kwargs
# working example where the data within the data structures conform to the signature
_ = fn4(None, (2000, 1, 1), 2.3)
()
{'idx': 0, 'name': None, 'dob': (2000, 1, 1), 'history': {'1': ([{1: []}], 0.0, None)}, 'ranking': 2.3}
@TySig.signature(
var1=Tuple[str, Any, Any],
var2=Tuple[AnyStr, Any, str],
var3=Tuple[Any, AnyStr, Any]
)
def fn5(*args, **kwargs):
print(args)
print(kwargs)
return args, kwargs
# working example where the data within the data structures conform to the signature
_ = fn5((b"2", 3, "d"), ("2.3", b"5.6", "sd"), var1=("j", 6, "k"))
()
{'var2': (b'2', 3, 'd'), 'var3': ('2.3', b'5.6', 'sd'), 'var1': ('j', 6, 'k')}
# non-working example where the data within the data structures do not conform to the signature
try:
_ = fn5((2, 3, "5"), (2.3, "5.6", "sd"), var1=("j", 6, "k"))
except TypeError as exp:
print(exp)
'var2' type should be 'typing.Tuple[~AnyStr, typing.Any, str]' instead found '<class 'tuple'>'. If you're using GenericAlias, VariadicGenericAlias, or SpecialForm types then please check the sub argument types are correct
# non-working example where the data within the data structures do not conform to the signature
try:
_ = fn5((b"2", 3, "5"), ("2.3", b"5.6"), var1=("j", 6, "k"))
except TypeError as exp:
print(exp)
'var3' type should be 'typing.Tuple[typing.Any, ~AnyStr, typing.Any]' instead found '<class 'tuple'>'. If you're using GenericAlias, VariadicGenericAlias, or SpecialForm types then please check the sub argument types are correct
# Signtaure Return Type check
@TySig.signature(num=int)
def fn15(*args, **kwargs) -> Union[
Tuple[str, float, List[AnyStr]],
Optional[Dict[int, List[Dict[float, Any]]]]
]:
print(args, kwargs)
num = kwargs.get("num")
if num == 0:
return "hello", 5., [b"h", "k", "lll", b"jhjh"]
elif num == 1:
return "hello", 5., [b"h", 5, "lll", b"jhjh"]
elif num == 2:
return ["hello", 5., [b"h", "5", "lll", b"jhjh"]]
elif num == 3:
return [b"hello", 5., [b"h", "5", "lll", b"jhjh"]]
elif num == 4:
return {
1: [
{
2.: "Jhjdshf"
}
]
}
elif num == 5:
return {
1.: [
{
2.: "Jhjdshf"
}
]
}
elif num == 6:
return {
1: [
{
2: "Jhjdshf"
}
]
}
else:
return None
ret = fn15(0)
print(ret)
() {'num': 0}
('hello', 5.0, [b'h', 'k', 'lll', b'jhjh'])
try:
_ = fn15(1)
except TypeError as exp:
print(exp)
() {'num': 1}
Return object type does not match signature return type typing.Union[typing.Tuple[str, float, typing.List[~AnyStr]], typing.Dict[int, typing.List[typing.Dict[float, typing.Any]]], NoneType]
try:
_ = fn15(2)
except TypeError as exp:
print(exp)
() {'num': 2}
Return object type does not match signature return type typing.Union[typing.Tuple[str, float, typing.List[~AnyStr]], typing.Dict[int, typing.List[typing.Dict[float, typing.Any]]], NoneType]
try:
_ = fn15(3)
except TypeError as exp:
print(exp)
() {'num': 3}
Return object type does not match signature return type typing.Union[typing.Tuple[str, float, typing.List[~AnyStr]], typing.Dict[int, typing.List[typing.Dict[float, typing.Any]]], NoneType]
ret = fn15(4)
print(ret)
() {'num': 4}
{1: [{2.0: 'Jhjdshf'}]}
try:
_ = fn15(5)
except TypeError as exp:
print(exp)
() {'num': 5}
Return object type does not match signature return type typing.Union[typing.Tuple[str, float, typing.List[~AnyStr]], typing.Dict[int, typing.List[typing.Dict[float, typing.Any]]], NoneType]
try:
_ = fn15(6)
except TypeError as exp:
print(exp)
() {'num': 6}
Return object type does not match signature return type typing.Union[typing.Tuple[str, float, typing.List[~AnyStr]], typing.Dict[int, typing.List[typing.Dict[float, typing.Any]]], NoneType]
ret = fn15(-1)
print(ret)
() {'num': -1}
None
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
ty-sig-0.1.5.tar.gz
(12.7 kB
view details)
Built Distribution
File details
Details for the file ty-sig-0.1.5.tar.gz
.
File metadata
- Download URL: ty-sig-0.1.5.tar.gz
- Upload date:
- Size: 12.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.4 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.1 CPython/3.9.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1d9410d38292545d639ea7514343c9a6eb182ceee73cfe518329ad0367ab21d6 |
|
MD5 | dd4550c8af5077b378da141bab3137e5 |
|
BLAKE2b-256 | 4dc03b53d96dc95837b7433a7b87b2698bc422533f7cbb49b6e7c8c089307ca1 |
File details
Details for the file ty_sig-0.1.5-py3-none-any.whl
.
File metadata
- Download URL: ty_sig-0.1.5-py3-none-any.whl
- Upload date:
- Size: 9.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.4 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.1 CPython/3.9.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 026cbef1df2136318e86809f2f771076f0ff20124896dbc7f353b037b6355ce7 |
|
MD5 | e3d222cb03ab2c2c48b2c71f7d0f2b3a |
|
BLAKE2b-256 | 61d6f0d126519d8b1677d8dfe5b2faae6f09670df6d8efabe5d18d47adb9521d |