RussBaz / enforce

Python 3.5+ runtime type checking for integration testing and data validation
542 stars 21 forks source link

__init__ signature is not preserved for Generic classes #67

Open smarie opened 6 years ago

smarie commented 6 years ago
from inspect import signature

from enforce import runtime_validation
from typing import Generic, TypeVar

T = TypeVar('T')

class A(Generic[T]):
    def __init__(self, foo: T):
        self.foo = foo

A(foo=1)
s = signature(A.__init__)
print(s.parameters)

A[int](foo=1)
s = signature(A[int].__init__)
print(s.parameters)

@runtime_validation
class A(Generic[T]):
    def __init__(self, foo: T):
        self.foo = foo

A(foo=1)
s = signature(A.__init__)
print(s.parameters)

A[int](foo=1)
s = signature(A[int].__init__)
print(s.parameters)

yields

OrderedDict([('self', <Parameter "self">), ('foo', <Parameter "foo:~T">)])
OrderedDict([('self', <Parameter "self">), ('foo', <Parameter "foo:~T">)])
OrderedDict([('wrapped', <Parameter "wrapped">), ('settings', <Parameter "settings=None">)])
OrderedDict([('wrapped', <Parameter "wrapped">), ('settings', <Parameter "settings=None">)])

This prevents type constructor introspection, for example with the parsyfiles parsing library.

smarie commented 6 years ago

I had a look in the code: in the case of generics, it seems that you are proxying the whole class with GenericProxy(ObjectProxy), which seems overkill: applying runtime_validation on the class as usual and simply replacing the __getitem__ class method so that it applies it on generated classes should be sufficient. Or did I miss some important functionality that is specific to Generic classes ?