1"""
2This module is about generics, like the `int` in `List[int]`. It's not about
3the Generic class.
4"""
5from abc import abstractmethod
6
7from jedi import debug
8from jedi.cache import memoize_method
9from jedi.inference.utils import to_tuple
10from jedi.inference.base_value import ValueSet, NO_VALUES
11from jedi.inference.value.iterable import SequenceLiteralValue
12from jedi.inference.helpers import is_string
13
14
15def _resolve_forward_references(context, value_set):
16 for value in value_set:
17 if is_string(value):
18 from jedi.inference.gradual.annotation import _get_forward_reference_node
19 node = _get_forward_reference_node(context, value.get_safe_value())
20 if node is not None:
21 for c in context.infer_node(node):
22 yield c
23 else:
24 yield value
25
26
27class _AbstractGenericManager:
28 @abstractmethod
29 def __getitem__(self, index):
30 raise NotImplementedError
31
32 @abstractmethod
33 def to_tuple(self):
34 raise NotImplementedError
35
36 def get_index_and_execute(self, index):
37 try:
38 return self[index].execute_annotation(None)
39 except IndexError:
40 debug.warning('No param #%s found for annotation %s', index, self)
41 return NO_VALUES
42
43 def get_type_hint(self):
44 return '[%s]' % ', '.join(t.get_type_hint(add_class_info=False) for t in self.to_tuple())
45
46
47class LazyGenericManager(_AbstractGenericManager):
48 def __init__(self, context_of_index, index_value):
49 self._context_of_index = context_of_index
50 self._index_value = index_value
51
52 @memoize_method
53 def __getitem__(self, index):
54 return self._tuple()[index]()
55
56 def __len__(self):
57 return len(self._tuple())
58
59 @memoize_method
60 @to_tuple
61 def _tuple(self):
62 def lambda_scoping_in_for_loop_sucks(lazy_value):
63 return lambda: ValueSet(_resolve_forward_references(
64 self._context_of_index,
65 lazy_value.infer()
66 ))
67
68 if isinstance(self._index_value, SequenceLiteralValue):
69 for lazy_value in self._index_value.py__iter__(contextualized_node=None):
70 yield lambda_scoping_in_for_loop_sucks(lazy_value)
71 else:
72 yield lambda: ValueSet(_resolve_forward_references(
73 self._context_of_index,
74 ValueSet([self._index_value])
75 ))
76
77 @to_tuple
78 def to_tuple(self):
79 for callable_ in self._tuple():
80 yield callable_()
81
82 def is_homogenous_tuple(self):
83 if isinstance(self._index_value, SequenceLiteralValue):
84 entries = self._index_value.get_tree_entries()
85 if len(entries) == 2 and entries[1] == '...':
86 return True
87 return False
88
89 def __repr__(self):
90 return '<LazyG>[%s]' % (', '.join(repr(x) for x in self.to_tuple()))
91
92
93class TupleGenericManager(_AbstractGenericManager):
94 def __init__(self, tup):
95 self._tuple = tup
96
97 def __getitem__(self, index):
98 return self._tuple[index]
99
100 def __len__(self):
101 return len(self._tuple)
102
103 def to_tuple(self):
104 return self._tuple
105
106 def is_homogenous_tuple(self):
107 return False
108
109 def __repr__(self):
110 return '<TupG>[%s]' % (', '.join(repr(x) for x in self.to_tuple()))