]>
Commit | Line | Data |
---|---|---|
53e6db90 DC |
1 | from inspect import Parameter |
2 | ||
3 | from jedi.cache import memoize_method | |
4 | from jedi import debug | |
5 | from jedi import parser_utils | |
6 | ||
7 | ||
8 | class _SignatureMixin: | |
9 | def to_string(self): | |
10 | def param_strings(): | |
11 | is_positional = False | |
12 | is_kw_only = False | |
13 | for n in self.get_param_names(resolve_stars=True): | |
14 | kind = n.get_kind() | |
15 | is_positional |= kind == Parameter.POSITIONAL_ONLY | |
16 | if is_positional and kind != Parameter.POSITIONAL_ONLY: | |
17 | yield '/' | |
18 | is_positional = False | |
19 | ||
20 | if kind == Parameter.VAR_POSITIONAL: | |
21 | is_kw_only = True | |
22 | elif kind == Parameter.KEYWORD_ONLY and not is_kw_only: | |
23 | yield '*' | |
24 | is_kw_only = True | |
25 | ||
26 | yield n.to_string() | |
27 | ||
28 | if is_positional: | |
29 | yield '/' | |
30 | ||
31 | s = self.name.string_name + '(' + ', '.join(param_strings()) + ')' | |
32 | annotation = self.annotation_string | |
33 | if annotation: | |
34 | s += ' -> ' + annotation | |
35 | return s | |
36 | ||
37 | ||
38 | class AbstractSignature(_SignatureMixin): | |
39 | def __init__(self, value, is_bound=False): | |
40 | self.value = value | |
41 | self.is_bound = is_bound | |
42 | ||
43 | @property | |
44 | def name(self): | |
45 | return self.value.name | |
46 | ||
47 | @property | |
48 | def annotation_string(self): | |
49 | return '' | |
50 | ||
51 | def get_param_names(self, resolve_stars=False): | |
52 | param_names = self._function_value.get_param_names() | |
53 | if self.is_bound: | |
54 | return param_names[1:] | |
55 | return param_names | |
56 | ||
57 | def bind(self, value): | |
58 | raise NotImplementedError | |
59 | ||
60 | def matches_signature(self, arguments): | |
61 | return True | |
62 | ||
63 | def __repr__(self): | |
64 | if self.value is self._function_value: | |
65 | return '<%s: %s>' % (self.__class__.__name__, self.value) | |
66 | return '<%s: %s, %s>' % (self.__class__.__name__, self.value, self._function_value) | |
67 | ||
68 | ||
69 | class TreeSignature(AbstractSignature): | |
70 | def __init__(self, value, function_value=None, is_bound=False): | |
71 | super().__init__(value, is_bound) | |
72 | self._function_value = function_value or value | |
73 | ||
74 | def bind(self, value): | |
75 | return TreeSignature(value, self._function_value, is_bound=True) | |
76 | ||
77 | @property | |
78 | def _annotation(self): | |
79 | # Classes don't need annotations, even if __init__ has one. They always | |
80 | # return themselves. | |
81 | if self.value.is_class(): | |
82 | return None | |
83 | return self._function_value.tree_node.annotation | |
84 | ||
85 | @property | |
86 | def annotation_string(self): | |
87 | a = self._annotation | |
88 | if a is None: | |
89 | return '' | |
90 | return a.get_code(include_prefix=False) | |
91 | ||
92 | @memoize_method | |
93 | def get_param_names(self, resolve_stars=False): | |
94 | params = self._function_value.get_param_names() | |
95 | if resolve_stars: | |
96 | from jedi.inference.star_args import process_params | |
97 | params = process_params(params) | |
98 | if self.is_bound: | |
99 | return params[1:] | |
100 | return params | |
101 | ||
102 | def matches_signature(self, arguments): | |
103 | from jedi.inference.param import get_executed_param_names_and_issues | |
104 | executed_param_names, issues = \ | |
105 | get_executed_param_names_and_issues(self._function_value, arguments) | |
106 | if issues: | |
107 | return False | |
108 | ||
109 | matches = all(executed_param_name.matches_signature() | |
110 | for executed_param_name in executed_param_names) | |
111 | if debug.enable_notice: | |
112 | tree_node = self._function_value.tree_node | |
113 | signature = parser_utils.get_signature(tree_node) | |
114 | if matches: | |
115 | debug.dbg("Overloading match: %s@%s (%s)", | |
116 | signature, tree_node.start_pos[0], arguments, color='BLUE') | |
117 | else: | |
118 | debug.dbg("Overloading no match: %s@%s (%s)", | |
119 | signature, tree_node.start_pos[0], arguments, color='BLUE') | |
120 | return matches | |
121 | ||
122 | ||
123 | class BuiltinSignature(AbstractSignature): | |
124 | def __init__(self, value, return_string, function_value=None, is_bound=False): | |
125 | super().__init__(value, is_bound) | |
126 | self._return_string = return_string | |
127 | self.__function_value = function_value | |
128 | ||
129 | @property | |
130 | def annotation_string(self): | |
131 | return self._return_string | |
132 | ||
133 | @property | |
134 | def _function_value(self): | |
135 | if self.__function_value is None: | |
136 | return self.value | |
137 | return self.__function_value | |
138 | ||
139 | def bind(self, value): | |
140 | return BuiltinSignature( | |
141 | value, self._return_string, | |
142 | function_value=self.value, | |
143 | is_bound=True | |
144 | ) | |
145 | ||
146 | ||
147 | class SignatureWrapper(_SignatureMixin): | |
148 | def __init__(self, wrapped_signature): | |
149 | self._wrapped_signature = wrapped_signature | |
150 | ||
151 | def __getattr__(self, name): | |
152 | return getattr(self._wrapped_signature, name) |