From ea6130f3645eede2c10d8080655f1bea43f34642 Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 00:06:35 +0900 Subject: [PATCH 01/12] Attempting to implement typing List support --- typen/_enforcer.py | 13 +++++++++++++ typen/_typing.py | 27 +++++++++++++++++++++++++++ typen/tests/test_typing.py | 9 +++++++++ 3 files changed, 49 insertions(+) create mode 100644 typen/_typing.py create mode 100644 typen/tests/test_typing.py diff --git a/typen/_enforcer.py b/typen/_enforcer.py index 118d4d0..52bee83 100644 --- a/typen/_enforcer.py +++ b/typen/_enforcer.py @@ -2,6 +2,7 @@ from traits.api import HasTraits, TraitError +from typen._typing import typing_to_trait from typen.exceptions import ( ParameterTypeError, ReturnTypeError, @@ -225,6 +226,18 @@ def verify_result(self, value): raise exception from None +def to_traitable(param_type): + """ + Function to attempt to turn the input parameter type to a suitable Traits + type. + """ + param_type = typing_to_trait(param_type) + # More conversion attempts can be made if more than just typing types + # are supported + + return param_type + + class Arg: def __init__(self, name, type): self.name = name diff --git a/typen/_typing.py b/typen/_typing.py new file mode 100644 index 0000000..c877645 --- /dev/null +++ b/typen/_typing.py @@ -0,0 +1,27 @@ +import sys +import typing + +import traits.api as traits_api + +from typen.exceptions import TypenError + + +if sys.version_info[1] == 8: + typing_generic = typing.GenericMeta +else: + typing_generic = typing.Generic + + +def typing_to_trait(arg_type): + """ + Attempt to convert a ``typing`` type into an appropriate ``traits`` type + """ + if arg_type.__class__ is not typing.GenericMeta: + return arg_type + origin = arg_type.__origin__ + + if origin is typing.List: + contained = arg_type.__args__[0] + return traits_api.List(typing_to_trait(contained)) + + raise TypenError("Could not convert typing type to trait: {}".format(arg_type)) diff --git a/typen/tests/test_typing.py b/typen/tests/test_typing.py new file mode 100644 index 0000000..e7795e0 --- /dev/null +++ b/typen/tests/test_typing.py @@ -0,0 +1,9 @@ +import unittest + + +class ToTrait(unittest.TestCase): + pass + + +class EnforceTypingTypes(unittest.TestCase): + pass From e97780ca4226d4eff6680488bf5d63e157026c84 Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 00:51:41 +0900 Subject: [PATCH 02/12] Can't get nested trait type working yet --- typen/_enforcer.py | 10 +++++++++- typen/_typing.py | 29 +++++++++++++++++++++-------- typen/tests/test_typing.py | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/typen/_enforcer.py b/typen/_enforcer.py index 994772f..9ec74b5 100644 --- a/typen/_enforcer.py +++ b/typen/_enforcer.py @@ -90,10 +90,18 @@ def __init__( raise UnspecifiedReturnTypeError(msg.format(func.__name__)) self.returns = UNSPECIFIED + # Convert any non-trait type hints to traits + spec = { + k: to_traitable(v) for k, v in spec.items() + } + self.returns = to_traitable(self.returns) + self.packed_args_spec = to_traitable(self.packed_args_spec) + self.packed_kwargs_spec = to_traitable(self.packed_kwargs_spec) + # Restore order of args self.args = [Arg(k, spec[k]) for k in params.keys()] - # Validate defaults + # Store defaults for validation self.default_kwargs = { k: v.default for k, v in params.items() if v.default is not inspect.Parameter.empty diff --git a/typen/_typing.py b/typen/_typing.py index c877645..cd04302 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -7,21 +7,34 @@ if sys.version_info[1] == 8: - typing_generic = typing.GenericMeta -else: typing_generic = typing.Generic +else: + typing_generic = typing.GenericMeta def typing_to_trait(arg_type): """ Attempt to convert a ``typing`` type into an appropriate ``traits`` type + + Raises + ------ + TypenError + If the input type is a ``typing`` type but it could not be converted + to a traits type. This may be because the type is not currently + supported. """ - if arg_type.__class__ is not typing.GenericMeta: + if arg_type.__class__ is not typing_generic: return arg_type - origin = arg_type.__origin__ - if origin is typing.List: - contained = arg_type.__args__[0] - return traits_api.List(typing_to_trait(contained)) + origin = arg_type.__origin__ or arg_type - raise TypenError("Could not convert typing type to trait: {}".format(arg_type)) + if origin is typing.List: + if arg_type.__args__ is not None: + contained = arg_type.__args__[0] + temp=typing_to_trait(contained) + print(temp) + return traits_api.List(temp) + else: + return traits_api.List() + + raise TypenError("Could not convert {} to trait".format(arg_type)) diff --git a/typen/tests/test_typing.py b/typen/tests/test_typing.py index e7795e0..03dafc5 100644 --- a/typen/tests/test_typing.py +++ b/typen/tests/test_typing.py @@ -1,9 +1,39 @@ +from typing import List import unittest +from typen._enforcer import Enforcer +from typen.exceptions import ParameterTypeError -class ToTrait(unittest.TestCase): + +class TypingToTrait(unittest.TestCase): pass class EnforceTypingTypes(unittest.TestCase): - pass + def test_enforce_typing_list(self): + def test_function(a: List): + pass + e = Enforcer(test_function) + + e.verify_args([[1, 2]], {}) + e.verify_args([[1.1, 0.1]], {}) + e.verify_args([["a", "b"]], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([1], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([(1, 2)], {}) + + def test_enforce_typing_list_spec(self): + def test_function(a: List[int]): + pass + e = Enforcer(test_function) + + e.verify_args([[1, 2]], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([[1.1, 0.1]], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([["a", "b"]], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([1], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([(1, 2)], {}) From 24b8267515f6f563b0eb85afe38c232f6c0a7c09 Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 01:24:06 +0900 Subject: [PATCH 03/12] Added tuple --- typen/_typing.py | 10 +++++++--- typen/tests/test_typing.py | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/typen/_typing.py b/typen/_typing.py index cd04302..cf7297a 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -31,10 +31,14 @@ def typing_to_trait(arg_type): if origin is typing.List: if arg_type.__args__ is not None: contained = arg_type.__args__[0] - temp=typing_to_trait(contained) - print(temp) - return traits_api.List(temp) + return traits_api.List(typing_to_trait(contained)) else: return traits_api.List() + elif origin is typing.Tuple: + if arg_type.__args__ is not None: + contained = [typing_to_trait(arg) for arg in arg_type.__args__] + return traits_api.Tuple(*contained) + else: + return traits_api.Tuple() raise TypenError("Could not convert {} to trait".format(arg_type)) diff --git a/typen/tests/test_typing.py b/typen/tests/test_typing.py index 03dafc5..5c5cdff 100644 --- a/typen/tests/test_typing.py +++ b/typen/tests/test_typing.py @@ -1,4 +1,4 @@ -from typing import List +from traits.api import List, Tuple import unittest from typen._enforcer import Enforcer @@ -24,7 +24,7 @@ def test_function(a: List): e.verify_args([(1, 2)], {}) def test_enforce_typing_list_spec(self): - def test_function(a: List[int]): + def test_function(a: List(int)): pass e = Enforcer(test_function) @@ -37,3 +37,37 @@ def test_function(a: List[int]): e.verify_args([1], {}) with self.assertRaises(ParameterTypeError): e.verify_args([(1, 2)], {}) + + def test_enforce_typing_tuple(self): + def test_function(a: Tuple): + pass + e = Enforcer(test_function) + + e.verify_args([(1, 2)], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([[1.1, 0.1]], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([["a", "b"]], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([1], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([(1, 2)], {}) + + def test_enforce_typing_tuple_spec(self): + def test_function(a: Tuple(int, int)): + pass + e = Enforcer(test_function) + + e.verify_args([(1, 2)], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([(1.1, 0.1)], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([(1, "b")], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([("a", "b")], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args((1,), {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([(1, 2, 3)], {}) + with self.assertRaises(ParameterTypeError): + e.verify_args([[1, 2]], {}) From 63d117a1b188bc053f2e36ff6c6374c557ae44ca Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 11:48:00 +0900 Subject: [PATCH 04/12] Working List and Tuple typing support --- typen/_typing.py | 24 +++++++++++++++--------- typen/tests/test_typing.py | 25 ++++++++++++++++--------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/typen/_typing.py b/typen/_typing.py index cf7297a..af41c4c 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -1,4 +1,3 @@ -import sys import typing import traits.api as traits_api @@ -6,12 +5,6 @@ from typen.exceptions import TypenError -if sys.version_info[1] == 8: - typing_generic = typing.Generic -else: - typing_generic = typing.GenericMeta - - def typing_to_trait(arg_type): """ Attempt to convert a ``typing`` type into an appropriate ``traits`` type @@ -23,7 +16,8 @@ def typing_to_trait(arg_type): to a traits type. This may be because the type is not currently supported. """ - if arg_type.__class__ is not typing_generic: + + if not hasattr(arg_type, "__origin__"): return arg_type origin = arg_type.__origin__ or arg_type @@ -31,7 +25,7 @@ def typing_to_trait(arg_type): if origin is typing.List: if arg_type.__args__ is not None: contained = arg_type.__args__[0] - return traits_api.List(typing_to_trait(contained)) + return ValidatedList(typing_to_trait(contained)) else: return traits_api.List() elif origin is typing.Tuple: @@ -42,3 +36,15 @@ def typing_to_trait(arg_type): return traits_api.Tuple() raise TypenError("Could not convert {} to trait".format(arg_type)) + + +class ValidatedList(traits_api.List): + """ + Defines a list that does validation on the internal type + """ + + def validate(self, object, name, value): + value = super(ValidatedList, self).validate(object, name, value) + + for item in value: + self.item_trait.validate(object, name, item) diff --git a/typen/tests/test_typing.py b/typen/tests/test_typing.py index 5c5cdff..c8e867a 100644 --- a/typen/tests/test_typing.py +++ b/typen/tests/test_typing.py @@ -1,7 +1,8 @@ -from traits.api import List, Tuple +from typing import List, Tuple import unittest from typen._enforcer import Enforcer +from typen._typing import typing_to_trait from typen.exceptions import ParameterTypeError @@ -24,7 +25,7 @@ def test_function(a: List): e.verify_args([(1, 2)], {}) def test_enforce_typing_list_spec(self): - def test_function(a: List(int)): + def test_function(a: List[int]): pass e = Enforcer(test_function) @@ -44,30 +45,36 @@ def test_function(a: Tuple): e = Enforcer(test_function) e.verify_args([(1, 2)], {}) - with self.assertRaises(ParameterTypeError): - e.verify_args([[1.1, 0.1]], {}) - with self.assertRaises(ParameterTypeError): - e.verify_args([["a", "b"]], {}) + + e.verify_args([[1.1, 0.1]], {}) + + # Lists can be cast to tuple + e.verify_args([["a", "b"]], {}) + with self.assertRaises(ParameterTypeError): e.verify_args([1], {}) - with self.assertRaises(ParameterTypeError): - e.verify_args([(1, 2)], {}) def test_enforce_typing_tuple_spec(self): - def test_function(a: Tuple(int, int)): + def test_function(a: Tuple[int, int]): pass e = Enforcer(test_function) e.verify_args([(1, 2)], {}) + with self.assertRaises(ParameterTypeError): e.verify_args([(1.1, 0.1)], {}) + with self.assertRaises(ParameterTypeError): e.verify_args([(1, "b")], {}) + with self.assertRaises(ParameterTypeError): e.verify_args([("a", "b")], {}) + with self.assertRaises(ParameterTypeError): e.verify_args((1,), {}) + with self.assertRaises(ParameterTypeError): e.verify_args([(1, 2, 3)], {}) + with self.assertRaises(ParameterTypeError): e.verify_args([[1, 2]], {}) From 888d24655fe4a5a36be9be307f0dd41ca11e48f6 Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 22:50:44 +0900 Subject: [PATCH 05/12] List and Tuple support --- typen/_typing.py | 13 +------ typen/tests/test_typing.py | 73 ++++++++++++++++++++++++++++++++++---- typen/traits.py | 13 +++++++ 3 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 typen/traits.py diff --git a/typen/_typing.py b/typen/_typing.py index af41c4c..1b99050 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -3,6 +3,7 @@ import traits.api as traits_api from typen.exceptions import TypenError +from typen.traits import ValidatedList def typing_to_trait(arg_type): @@ -36,15 +37,3 @@ def typing_to_trait(arg_type): return traits_api.Tuple() raise TypenError("Could not convert {} to trait".format(arg_type)) - - -class ValidatedList(traits_api.List): - """ - Defines a list that does validation on the internal type - """ - - def validate(self, object, name, value): - value = super(ValidatedList, self).validate(object, name, value) - - for item in value: - self.item_trait.validate(object, name, item) diff --git a/typen/tests/test_typing.py b/typen/tests/test_typing.py index c8e867a..18068e5 100644 --- a/typen/tests/test_typing.py +++ b/typen/tests/test_typing.py @@ -1,18 +1,76 @@ -from typing import List, Tuple +import typing import unittest +import traits.api as traits_api + from typen._enforcer import Enforcer from typen._typing import typing_to_trait from typen.exceptions import ParameterTypeError +from typen.traits import ValidatedList class TypingToTrait(unittest.TestCase): - pass + def test_typing_to_trait_list(self): + typ = typing.List + + traits_typ = typing_to_trait(typ) + + self.assertIsInstance(traits_typ, traits_api.List) + self.assertNotIsInstance(traits_typ, ValidatedList) + + traits_typ.validate(None, None, [1]) + traits_typ.validate(None, None, ["a"]) + with self.assertRaises(traits_api.TraitError): + traits_typ.validate(None, None, "a") + + def test_typing_to_trait_list_of_int(self): + typ = typing.List[int] + + traits_typ = typing_to_trait(typ) + + self.assertIsInstance(traits_typ, traits_api.List) + self.assertIsInstance(traits_typ, ValidatedList) + + traits_typ.validate(None, None, [1]) + + with self.assertRaises(traits_api.TraitError): + traits_typ.validate(None, None, ["a"]) + + def test_typing_to_trait_nested_list(self): + typ = typing.List[typing.List[str]] + + traits_typ = typing_to_trait(typ) + + self.assertIsInstance(traits_typ, traits_api.List) + self.assertIsInstance(traits_typ, ValidatedList) + + traits_typ.validate(None, None, [["a", "b"], ["c", "d"]]) + + with self.assertRaises(traits_api.TraitError): + traits_typ.validate(None, None, ["a"]) + + with self.assertRaises(traits_api.TraitError): + traits_typ.validate(None, None, [[1, "b"], ["c", "d"]]) + + def test_typing_to_trait_int(self): + typ = int + + traits_typ = typing_to_trait(typ) + self.assertIs(traits_typ, int) + + def test_typing_to_trait_tuple(self): + typ = typing.Tuple[int, str, int] + + traits_typ = typing_to_trait(typ) + + self.assertIsInstance(traits_typ, traits_api.Tuple) + + self.fail("Complete test") class EnforceTypingTypes(unittest.TestCase): def test_enforce_typing_list(self): - def test_function(a: List): + def test_function(a: typing.List): pass e = Enforcer(test_function) @@ -25,7 +83,7 @@ def test_function(a: List): e.verify_args([(1, 2)], {}) def test_enforce_typing_list_spec(self): - def test_function(a: List[int]): + def test_function(a: typing.List[int]): pass e = Enforcer(test_function) @@ -40,7 +98,7 @@ def test_function(a: List[int]): e.verify_args([(1, 2)], {}) def test_enforce_typing_tuple(self): - def test_function(a: Tuple): + def test_function(a: typing.Tuple): pass e = Enforcer(test_function) @@ -55,7 +113,7 @@ def test_function(a: Tuple): e.verify_args([1], {}) def test_enforce_typing_tuple_spec(self): - def test_function(a: Tuple[int, int]): + def test_function(a: typing.Tuple[int, int]): pass e = Enforcer(test_function) @@ -78,3 +136,6 @@ def test_function(a: Tuple[int, int]): with self.assertRaises(ParameterTypeError): e.verify_args([[1, 2]], {}) + + +#TODO: return types, args, kwargs diff --git a/typen/traits.py b/typen/traits.py new file mode 100644 index 0000000..2253776 --- /dev/null +++ b/typen/traits.py @@ -0,0 +1,13 @@ +from traits.api import List + + +class ValidatedList(List): + """ + Defines a list that does validation on the internal type + """ + + def validate(self, object, name, value): + value = super(ValidatedList, self).validate(object, name, value) + + for item in value: + self.item_trait.validate(object, name, item) From 60330413fb84047f7755a9b89342dc901597aedd Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 23:08:17 +0900 Subject: [PATCH 06/12] Incomplete test --- typen/tests/test_typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typen/tests/test_typing.py b/typen/tests/test_typing.py index 18068e5..4105eeb 100644 --- a/typen/tests/test_typing.py +++ b/typen/tests/test_typing.py @@ -65,7 +65,7 @@ def test_typing_to_trait_tuple(self): self.assertIsInstance(traits_typ, traits_api.Tuple) - self.fail("Complete test") + #self.fail("Complete test") class EnforceTypingTypes(unittest.TestCase): From f25a5f723467c323396e0bf3cf96920e6aebb68a Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 23:12:43 +0900 Subject: [PATCH 07/12] temp --- typen/_typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typen/_typing.py b/typen/_typing.py index 1b99050..8aa45c1 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -36,4 +36,4 @@ def typing_to_trait(arg_type): else: return traits_api.Tuple() - raise TypenError("Could not convert {} to trait".format(arg_type)) + raise TypenError("Could not convert {} {} to trait".format(arg_type, arg_type.__origin__)) From 1ce99540ee2f06fad514af827c96ae4f65d69942 Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 23:14:34 +0900 Subject: [PATCH 08/12] Attempt at 3.7+ support --- typen/_typing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/typen/_typing.py b/typen/_typing.py index 8aa45c1..5a1bc27 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -23,17 +23,17 @@ def typing_to_trait(arg_type): origin = arg_type.__origin__ or arg_type - if origin is typing.List: + if origin in [typing.List, list]: if arg_type.__args__ is not None: contained = arg_type.__args__[0] return ValidatedList(typing_to_trait(contained)) else: return traits_api.List() - elif origin is typing.Tuple: + elif origin in [typing.Tuple, tuple]: if arg_type.__args__ is not None: contained = [typing_to_trait(arg) for arg in arg_type.__args__] return traits_api.Tuple(*contained) else: return traits_api.Tuple() - raise TypenError("Could not convert {} {} to trait".format(arg_type, arg_type.__origin__)) + raise TypenError("Could not convert {} to trait".format(arg_type)) From 2981a4804868b01684468c633f964c057fa8d633 Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 23:18:48 +0900 Subject: [PATCH 09/12] temp --- typen/_typing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/typen/_typing.py b/typen/_typing.py index 5a1bc27..b4d2304 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -26,6 +26,7 @@ def typing_to_trait(arg_type): if origin in [typing.List, list]: if arg_type.__args__ is not None: contained = arg_type.__args__[0] + print(contained) return ValidatedList(typing_to_trait(contained)) else: return traits_api.List() From eefeaf977da82166a06538c16bf3f00c814399da Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 23:21:35 +0900 Subject: [PATCH 10/12] Attempt at 3.7+ support --- typen/_typing.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/typen/_typing.py b/typen/_typing.py index b4d2304..1d15e74 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -24,14 +24,13 @@ def typing_to_trait(arg_type): origin = arg_type.__origin__ or arg_type if origin in [typing.List, list]: - if arg_type.__args__ is not None: + if arg_type.__args__ is not None and arg_type.__args__ is not typing.Any: contained = arg_type.__args__[0] - print(contained) return ValidatedList(typing_to_trait(contained)) else: return traits_api.List() elif origin in [typing.Tuple, tuple]: - if arg_type.__args__ is not None: + if arg_type.__args__ is not None and arg_type.__args__ is not typing.Any: contained = [typing_to_trait(arg) for arg in arg_type.__args__] return traits_api.Tuple(*contained) else: From cfae368a75e6dce5ee1ee30d5c6347abab76efa7 Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 23:24:04 +0900 Subject: [PATCH 11/12] temp --- typen/_typing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/typen/_typing.py b/typen/_typing.py index 1d15e74..a2a70f6 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -24,6 +24,7 @@ def typing_to_trait(arg_type): origin = arg_type.__origin__ or arg_type if origin in [typing.List, list]: + print(arg_type.__args__) if arg_type.__args__ is not None and arg_type.__args__ is not typing.Any: contained = arg_type.__args__[0] return ValidatedList(typing_to_trait(contained)) From 05298815e80363bc90e8f88e1c8b89da62be0e1d Mon Sep 17 00:00:00 2001 From: Kevin Duff Date: Thu, 28 Nov 2019 23:26:55 +0900 Subject: [PATCH 12/12] Attempt at 3.7+ support --- typen/_typing.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/typen/_typing.py b/typen/_typing.py index a2a70f6..2841cf4 100644 --- a/typen/_typing.py +++ b/typen/_typing.py @@ -24,14 +24,13 @@ def typing_to_trait(arg_type): origin = arg_type.__origin__ or arg_type if origin in [typing.List, list]: - print(arg_type.__args__) - if arg_type.__args__ is not None and arg_type.__args__ is not typing.Any: + if arg_type.__args__ is not None and arg_type.__args__[0] is not typing.Any: contained = arg_type.__args__[0] return ValidatedList(typing_to_trait(contained)) else: return traits_api.List() elif origin in [typing.Tuple, tuple]: - if arg_type.__args__ is not None and arg_type.__args__ is not typing.Any: + if arg_type.__args__ is not None: contained = [typing_to_trait(arg) for arg in arg_type.__args__] return traits_api.Tuple(*contained) else: