1
1
from collections import defaultdict
2
- from typing import Any , Callable , CallableMeta , Dict , GenericMeta , List , Set , Tuple , Type , Union # type: ignore
2
+ from typing import Any , Callable , Dict , List , Set , Tuple , Type , Union
3
3
import inspect
4
4
import logging
5
+ import sys
5
6
import traceback
6
7
import types
7
8
12
13
13
14
logger = logging .getLogger (__name__ )
14
15
16
+
17
+ # We rely heavily on the typing module and its type annotations for our grammar induction code.
18
+ # Unfortunately, the behavior of the typing module changed somewhat substantially between python
19
+ # 3.6 and 3.7, so we need to do some gymnastics to get some of our checks to work with both.
20
+ # That's what these three methods are about.
21
+
22
+ def is_callable (type_ : Type ) -> bool :
23
+ if sys .version_info < (3 , 7 ):
24
+ from typing import CallableMeta # type: ignore
25
+ return isinstance (type_ , CallableMeta ) # type: ignore
26
+ else :
27
+ return getattr (type_ , '_name' , None ) == 'Callable'
28
+
29
+
30
+ def is_generic (type_ : Type ) -> bool :
31
+ if sys .version_info < (3 , 7 ):
32
+ from typing import GenericMeta # type: ignore
33
+ return isinstance (type_ , GenericMeta ) # type: ignore
34
+ else :
35
+ # pylint: disable=protected-access
36
+ from typing import _GenericAlias # type: ignore
37
+ return isinstance (type_ , _GenericAlias ) # type: ignore
38
+
39
+
40
+ def get_generic_name (type_ : Type ) -> str :
41
+ if sys .version_info < (3 , 7 ):
42
+ origin = type_ .__origin__ .__name__
43
+ else :
44
+ # In python 3.7, type_.__origin__ switched to the built-in class, instead of the typing
45
+ # class.
46
+ origin = type_ ._name # pylint: disable=protected-access
47
+ args = type_ .__args__
48
+ return f'{ origin } [{ "," .join (arg .__name__ for arg in args )} ]'
49
+
50
+
15
51
class PredicateType :
16
52
"""
17
53
A base class for `types` in a domain language. This serves much the same purpose as
@@ -31,17 +67,15 @@ def get_type(type_: Type) -> 'PredicateType':
31
67
those specially, so that the ``name`` for the ``BasicType`` remains ``List[str]``, as you
32
68
would expect.
33
69
"""
34
- if isinstance (type_ , CallableMeta ):
70
+ if is_callable (type_ ):
35
71
callable_args = type_ .__args__
36
72
argument_types = [PredicateType .get_type (t ) for t in callable_args [:- 1 ]]
37
73
return_type = PredicateType .get_type (callable_args [- 1 ])
38
74
return FunctionType (argument_types , return_type )
39
- elif isinstance (type_ , GenericMeta ):
40
- # This is something like List[int]. type_.__name__ will only give 'List', though, so
41
- # we need to do some magic here.
42
- origin = type_ .__origin__
43
- args = type_ .__args__
44
- name = f'{ origin .__name__ } [{ "," .join (arg .__name__ for arg in args )} ]'
75
+ elif is_generic (type_ ):
76
+ # This is something like List[int]. type_.__name__ doesn't do the right thing (and
77
+ # crashes in python 3.7), so we need to do some magic here.
78
+ name = get_generic_name (type_ )
45
79
else :
46
80
name = type_ .__name__
47
81
return BasicType (name )
0 commit comments