Last active
December 29, 2017 15:21
-
-
Save miraculixx/01410a6a874a1cd2954b927ac2488435 to your computer and use it in GitHub Desktop.
type checking for python functions. this is way better than PEP 484 type hints and it works for Python 2.x and Python 3.x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typecheck import typecheck | |
@typecheck((int, int), dict(c=(int, type(None))), int) | |
def foo(a, b, c=None): | |
print("hello", a, b) | |
return 5 | |
typecheck.active = False | |
@typecheck((int, int), dict(c=(int, type(None))), str) | |
def foox(a, b, c=None): | |
print("hello", a, b) | |
return 5 | |
# foo has typecheck enabled | |
foo(1, 2, c=5) | |
# foox does not have type check enabled | |
foox('1', '2', '3') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def typecheck(argstypes=[], kwargstypes={}, | |
returntype=(str,dict,int,float,list,tuple,set,object,type(typecheck),type(None))): | |
""" | |
Assert types of arguments to functions and methods | |
Usage: | |
On any function use the @typecheck decorater | |
@typecheck((int, int)) | |
def foo(a, b): | |
... | |
The decorator accepts three arguments: | |
argstypes: tuple of types | |
kwargstypes: dict of kwarg:tuple of types | |
returntype: tuple of return types | |
The default for each is to accept any type. | |
For methods, use the object type as the first argument to match self: | |
class Bar: | |
@typecheck((object, int, int)) | |
def foo(self, a, b): | |
... | |
If you can't use the decorator for some reason, typecheck also works inside functions: | |
def internal(a, b, c): | |
typecheck((int, int, int)).ins(a, b, c) | |
result = 5 | |
return typecheck(returntype=int).out(result) | |
If you need to use *args and **kwargs: | |
def internal2(*args, **kwargs): | |
(a, b, c), kwargs = typecheck((int, int, int)).ins(*args, **kwargs) | |
... | |
Notes: | |
typecheck works at run time and thus has some overhead. To deactivate typechecking in | |
production, set typecheck.active = False in your application's main entry point. | |
""" | |
def check_in(*args, **kwargs): | |
for i, arg in enumerate(args): | |
msg = "Expected arg {} to be of type {} got {}".format(i, argstypes[i], type(arg)) | |
assert isinstance(arg, argstypes[i]), msg | |
for kwarg in kwargs.iteritems(): | |
kw, val = kwarg | |
msg = "Expected kwarg {} to be of type {} got {}".format(kw, kwargstypes[kw], type(val)) | |
assert isinstance(val, kwargstypes[kw]), msg | |
return args, kwargs | |
def check_out(result): | |
msg = "Expected result to be of type {} got {}".format(returntype, type(result)) | |
assert isinstance(result, returntype), msg | |
return result | |
def wrap(func): | |
if not getattr(typecheck, 'active', True): | |
return func | |
def check(*args, **kwargs): | |
check_in(*args, **kwargs) | |
result = func(*args, **kwargs) | |
check_out(result) | |
return result | |
return check | |
wrap.ins = check_in | |
wrap.out = check_out | |
return wrap |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment