]>
Commit | Line | Data |
---|---|---|
53e6db90 DC |
1 | """ |
2 | Contains all classes and functions to deal with lists, dicts, generators and | |
3 | iterators in general. | |
4 | """ | |
5 | from jedi.inference import compiled | |
6 | from jedi.inference import analysis | |
7 | from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues, \ | |
8 | LazyTreeValue | |
9 | from jedi.inference.helpers import get_int_or_none, is_string, \ | |
10 | reraise_getitem_errors, SimpleGetItemNotFound | |
11 | from jedi.inference.utils import safe_property, to_list | |
12 | from jedi.inference.cache import inference_state_method_cache | |
13 | from jedi.inference.filters import LazyAttributeOverwrite, publish_method | |
14 | from jedi.inference.base_value import ValueSet, Value, NO_VALUES, \ | |
15 | ContextualizedNode, iterate_values, sentinel, \ | |
16 | LazyValueWrapper | |
17 | from jedi.parser_utils import get_sync_comp_fors | |
18 | from jedi.inference.context import CompForContext | |
19 | from jedi.inference.value.dynamic_arrays import check_array_additions | |
20 | ||
21 | ||
22 | class IterableMixin: | |
23 | def py__next__(self, contextualized_node=None): | |
24 | return self.py__iter__(contextualized_node) | |
25 | ||
26 | def py__stop_iteration_returns(self): | |
27 | return ValueSet([compiled.builtin_from_name(self.inference_state, 'None')]) | |
28 | ||
29 | # At the moment, safe values are simple values like "foo", 1 and not | |
30 | # lists/dicts. Therefore as a small speed optimization we can just do the | |
31 | # default instead of resolving the lazy wrapped values, that are just | |
32 | # doing this in the end as well. | |
33 | # This mostly speeds up patterns like `sys.version_info >= (3, 0)` in | |
34 | # typeshed. | |
35 | get_safe_value = Value.get_safe_value | |
36 | ||
37 | ||
38 | class GeneratorBase(LazyAttributeOverwrite, IterableMixin): | |
39 | array_type = None | |
40 | ||
41 | def _get_wrapped_value(self): | |
42 | instance, = self._get_cls().execute_annotation() | |
43 | return instance | |
44 | ||
45 | def _get_cls(self): | |
46 | generator, = self.inference_state.typing_module.py__getattribute__('Generator') | |
47 | return generator | |
48 | ||
49 | def py__bool__(self): | |
50 | return True | |
51 | ||
52 | @publish_method('__iter__') | |
53 | def _iter(self, arguments): | |
54 | return ValueSet([self]) | |
55 | ||
56 | @publish_method('send') | |
57 | @publish_method('__next__') | |
58 | def _next(self, arguments): | |
59 | return ValueSet.from_sets(lazy_value.infer() for lazy_value in self.py__iter__()) | |
60 | ||
61 | def py__stop_iteration_returns(self): | |
62 | return ValueSet([compiled.builtin_from_name(self.inference_state, 'None')]) | |
63 | ||
64 | @property | |
65 | def name(self): | |
66 | return compiled.CompiledValueName(self, 'Generator') | |
67 | ||
68 | def get_annotated_class_object(self): | |
69 | from jedi.inference.gradual.generics import TupleGenericManager | |
70 | gen_values = self.merge_types_of_iterate().py__class__() | |
71 | gm = TupleGenericManager((gen_values, NO_VALUES, NO_VALUES)) | |
72 | return self._get_cls().with_generics(gm) | |
73 | ||
74 | ||
75 | class Generator(GeneratorBase): | |
76 | """Handling of `yield` functions.""" | |
77 | def __init__(self, inference_state, func_execution_context): | |
78 | super().__init__(inference_state) | |
79 | self._func_execution_context = func_execution_context | |
80 | ||
81 | def py__iter__(self, contextualized_node=None): | |
82 | iterators = self._func_execution_context.infer_annotations() | |
83 | if iterators: | |
84 | return iterators.iterate(contextualized_node) | |
85 | return self._func_execution_context.get_yield_lazy_values() | |
86 | ||
87 | def py__stop_iteration_returns(self): | |
88 | return self._func_execution_context.get_return_values() | |
89 | ||
90 | def __repr__(self): | |
91 | return "<%s of %s>" % (type(self).__name__, self._func_execution_context) | |
92 | ||
93 | ||
94 | def comprehension_from_atom(inference_state, value, atom): | |
95 | bracket = atom.children[0] | |
96 | test_list_comp = atom.children[1] | |
97 | ||
98 | if bracket == '{': | |
99 | if atom.children[1].children[1] == ':': | |
100 | sync_comp_for = test_list_comp.children[3] | |
101 | if sync_comp_for.type == 'comp_for': | |
102 | sync_comp_for = sync_comp_for.children[1] | |
103 | ||
104 | return DictComprehension( | |
105 | inference_state, | |
106 | value, | |
107 | sync_comp_for_node=sync_comp_for, | |
108 | key_node=test_list_comp.children[0], | |
109 | value_node=test_list_comp.children[2], | |
110 | ) | |
111 | else: | |
112 | cls = SetComprehension | |
113 | elif bracket == '(': | |
114 | cls = GeneratorComprehension | |
115 | elif bracket == '[': | |
116 | cls = ListComprehension | |
117 | ||
118 | sync_comp_for = test_list_comp.children[1] | |
119 | if sync_comp_for.type == 'comp_for': | |
120 | sync_comp_for = sync_comp_for.children[1] | |
121 | ||
122 | return cls( | |
123 | inference_state, | |
124 | defining_context=value, | |
125 | sync_comp_for_node=sync_comp_for, | |
126 | entry_node=test_list_comp.children[0], | |
127 | ) | |
128 | ||
129 | ||
130 | class ComprehensionMixin: | |
131 | @inference_state_method_cache() | |
132 | def _get_comp_for_context(self, parent_context, comp_for): | |
133 | return CompForContext(parent_context, comp_for) | |
134 | ||
135 | def _nested(self, comp_fors, parent_context=None): | |
136 | comp_for = comp_fors[0] | |
137 | ||
138 | is_async = comp_for.parent.type == 'comp_for' | |
139 | ||
140 | input_node = comp_for.children[3] | |
141 | parent_context = parent_context or self._defining_context | |
142 | input_types = parent_context.infer_node(input_node) | |
143 | ||
144 | cn = ContextualizedNode(parent_context, input_node) | |
145 | iterated = input_types.iterate(cn, is_async=is_async) | |
146 | exprlist = comp_for.children[1] | |
147 | for i, lazy_value in enumerate(iterated): | |
148 | types = lazy_value.infer() | |
149 | dct = unpack_tuple_to_dict(parent_context, types, exprlist) | |
150 | context = self._get_comp_for_context( | |
151 | parent_context, | |
152 | comp_for, | |
153 | ) | |
154 | with context.predefine_names(comp_for, dct): | |
155 | try: | |
156 | yield from self._nested(comp_fors[1:], context) | |
157 | except IndexError: | |
158 | iterated = context.infer_node(self._entry_node) | |
159 | if self.array_type == 'dict': | |
160 | yield iterated, context.infer_node(self._value_node) | |
161 | else: | |
162 | yield iterated | |
163 | ||
164 | @inference_state_method_cache(default=[]) | |
165 | @to_list | |
166 | def _iterate(self): | |
167 | comp_fors = tuple(get_sync_comp_fors(self._sync_comp_for_node)) | |
168 | yield from self._nested(comp_fors) | |
169 | ||
170 | def py__iter__(self, contextualized_node=None): | |
171 | for set_ in self._iterate(): | |
172 | yield LazyKnownValues(set_) | |
173 | ||
174 | def __repr__(self): | |
175 | return "<%s of %s>" % (type(self).__name__, self._sync_comp_for_node) | |
176 | ||
177 | ||
178 | class _DictMixin: | |
179 | def _get_generics(self): | |
180 | return tuple(c_set.py__class__() for c_set in self.get_mapping_item_values()) | |
181 | ||
182 | ||
183 | class Sequence(LazyAttributeOverwrite, IterableMixin): | |
184 | api_type = 'instance' | |
185 | ||
186 | @property | |
187 | def name(self): | |
188 | return compiled.CompiledValueName(self, self.array_type) | |
189 | ||
190 | def _get_generics(self): | |
191 | return (self.merge_types_of_iterate().py__class__(),) | |
192 | ||
193 | @inference_state_method_cache(default=()) | |
194 | def _cached_generics(self): | |
195 | return self._get_generics() | |
196 | ||
197 | def _get_wrapped_value(self): | |
198 | from jedi.inference.gradual.base import GenericClass | |
199 | from jedi.inference.gradual.generics import TupleGenericManager | |
200 | klass = compiled.builtin_from_name(self.inference_state, self.array_type) | |
201 | c, = GenericClass( | |
202 | klass, | |
203 | TupleGenericManager(self._cached_generics()) | |
204 | ).execute_annotation() | |
205 | return c | |
206 | ||
207 | def py__bool__(self): | |
208 | return None # We don't know the length, because of appends. | |
209 | ||
210 | @safe_property | |
211 | def parent(self): | |
212 | return self.inference_state.builtins_module | |
213 | ||
214 | def py__getitem__(self, index_value_set, contextualized_node): | |
215 | if self.array_type == 'dict': | |
216 | return self._dict_values() | |
217 | return iterate_values(ValueSet([self])) | |
218 | ||
219 | ||
220 | class _BaseComprehension(ComprehensionMixin): | |
221 | def __init__(self, inference_state, defining_context, sync_comp_for_node, entry_node): | |
222 | assert sync_comp_for_node.type == 'sync_comp_for' | |
223 | super().__init__(inference_state) | |
224 | self._defining_context = defining_context | |
225 | self._sync_comp_for_node = sync_comp_for_node | |
226 | self._entry_node = entry_node | |
227 | ||
228 | ||
229 | class ListComprehension(_BaseComprehension, Sequence): | |
230 | array_type = 'list' | |
231 | ||
232 | def py__simple_getitem__(self, index): | |
233 | if isinstance(index, slice): | |
234 | return ValueSet([self]) | |
235 | ||
236 | all_types = list(self.py__iter__()) | |
237 | with reraise_getitem_errors(IndexError, TypeError): | |
238 | lazy_value = all_types[index] | |
239 | return lazy_value.infer() | |
240 | ||
241 | ||
242 | class SetComprehension(_BaseComprehension, Sequence): | |
243 | array_type = 'set' | |
244 | ||
245 | ||
246 | class GeneratorComprehension(_BaseComprehension, GeneratorBase): | |
247 | pass | |
248 | ||
249 | ||
250 | class _DictKeyMixin: | |
251 | # TODO merge with _DictMixin? | |
252 | def get_mapping_item_values(self): | |
253 | return self._dict_keys(), self._dict_values() | |
254 | ||
255 | def get_key_values(self): | |
256 | # TODO merge with _dict_keys? | |
257 | return self._dict_keys() | |
258 | ||
259 | ||
260 | class DictComprehension(ComprehensionMixin, Sequence, _DictKeyMixin): | |
261 | array_type = 'dict' | |
262 | ||
263 | def __init__(self, inference_state, defining_context, sync_comp_for_node, key_node, value_node): | |
264 | assert sync_comp_for_node.type == 'sync_comp_for' | |
265 | super().__init__(inference_state) | |
266 | self._defining_context = defining_context | |
267 | self._sync_comp_for_node = sync_comp_for_node | |
268 | self._entry_node = key_node | |
269 | self._value_node = value_node | |
270 | ||
271 | def py__iter__(self, contextualized_node=None): | |
272 | for keys, values in self._iterate(): | |
273 | yield LazyKnownValues(keys) | |
274 | ||
275 | def py__simple_getitem__(self, index): | |
276 | for keys, values in self._iterate(): | |
277 | for k in keys: | |
278 | # Be careful in the future if refactoring, index could be a | |
279 | # slice object. | |
280 | if k.get_safe_value(default=object()) == index: | |
281 | return values | |
282 | raise SimpleGetItemNotFound() | |
283 | ||
284 | def _dict_keys(self): | |
285 | return ValueSet.from_sets(keys for keys, values in self._iterate()) | |
286 | ||
287 | def _dict_values(self): | |
288 | return ValueSet.from_sets(values for keys, values in self._iterate()) | |
289 | ||
290 | @publish_method('values') | |
291 | def _imitate_values(self, arguments): | |
292 | lazy_value = LazyKnownValues(self._dict_values()) | |
293 | return ValueSet([FakeList(self.inference_state, [lazy_value])]) | |
294 | ||
295 | @publish_method('items') | |
296 | def _imitate_items(self, arguments): | |
297 | lazy_values = [ | |
298 | LazyKnownValue( | |
299 | FakeTuple( | |
300 | self.inference_state, | |
301 | [LazyKnownValues(key), | |
302 | LazyKnownValues(value)] | |
303 | ) | |
304 | ) | |
305 | for key, value in self._iterate() | |
306 | ] | |
307 | ||
308 | return ValueSet([FakeList(self.inference_state, lazy_values)]) | |
309 | ||
310 | def exact_key_items(self): | |
311 | # NOTE: A smarter thing can probably done here to achieve better | |
312 | # completions, but at least like this jedi doesn't crash | |
313 | return [] | |
314 | ||
315 | ||
316 | class SequenceLiteralValue(Sequence): | |
317 | _TUPLE_LIKE = 'testlist_star_expr', 'testlist', 'subscriptlist' | |
318 | mapping = {'(': 'tuple', | |
319 | '[': 'list', | |
320 | '{': 'set'} | |
321 | ||
322 | def __init__(self, inference_state, defining_context, atom): | |
323 | super().__init__(inference_state) | |
324 | self.atom = atom | |
325 | self._defining_context = defining_context | |
326 | ||
327 | if self.atom.type in self._TUPLE_LIKE: | |
328 | self.array_type = 'tuple' | |
329 | else: | |
330 | self.array_type = SequenceLiteralValue.mapping[atom.children[0]] | |
331 | """The builtin name of the array (list, set, tuple or dict).""" | |
332 | ||
333 | def _get_generics(self): | |
334 | if self.array_type == 'tuple': | |
335 | return tuple(x.infer().py__class__() for x in self.py__iter__()) | |
336 | return super()._get_generics() | |
337 | ||
338 | def py__simple_getitem__(self, index): | |
339 | """Here the index is an int/str. Raises IndexError/KeyError.""" | |
340 | if isinstance(index, slice): | |
341 | return ValueSet([self]) | |
342 | else: | |
343 | with reraise_getitem_errors(TypeError, KeyError, IndexError): | |
344 | node = self.get_tree_entries()[index] | |
345 | if node == ':' or node.type == 'subscript': | |
346 | return NO_VALUES | |
347 | return self._defining_context.infer_node(node) | |
348 | ||
349 | def py__iter__(self, contextualized_node=None): | |
350 | """ | |
351 | While values returns the possible values for any array field, this | |
352 | function returns the value for a certain index. | |
353 | """ | |
354 | for node in self.get_tree_entries(): | |
355 | if node == ':' or node.type == 'subscript': | |
356 | # TODO this should probably use at least part of the code | |
357 | # of infer_subscript_list. | |
358 | yield LazyKnownValue(Slice(self._defining_context, None, None, None)) | |
359 | else: | |
360 | yield LazyTreeValue(self._defining_context, node) | |
361 | yield from check_array_additions(self._defining_context, self) | |
362 | ||
363 | def py__len__(self): | |
364 | # This function is not really used often. It's more of a try. | |
365 | return len(self.get_tree_entries()) | |
366 | ||
367 | def get_tree_entries(self): | |
368 | c = self.atom.children | |
369 | ||
370 | if self.atom.type in self._TUPLE_LIKE: | |
371 | return c[::2] | |
372 | ||
373 | array_node = c[1] | |
374 | if array_node in (']', '}', ')'): | |
375 | return [] # Direct closing bracket, doesn't contain items. | |
376 | ||
377 | if array_node.type == 'testlist_comp': | |
378 | # filter out (for now) pep 448 single-star unpacking | |
379 | return [value for value in array_node.children[::2] | |
380 | if value.type != "star_expr"] | |
381 | elif array_node.type == 'dictorsetmaker': | |
382 | kv = [] | |
383 | iterator = iter(array_node.children) | |
384 | for key in iterator: | |
385 | if key == "**": | |
386 | # dict with pep 448 double-star unpacking | |
387 | # for now ignoring the values imported by ** | |
388 | next(iterator) | |
389 | next(iterator, None) # Possible comma. | |
390 | else: | |
391 | op = next(iterator, None) | |
392 | if op is None or op == ',': | |
393 | if key.type == "star_expr": | |
394 | # pep 448 single-star unpacking | |
395 | # for now ignoring values imported by * | |
396 | pass | |
397 | else: | |
398 | kv.append(key) # A set. | |
399 | else: | |
400 | assert op == ':' # A dict. | |
401 | kv.append((key, next(iterator))) | |
402 | next(iterator, None) # Possible comma. | |
403 | return kv | |
404 | else: | |
405 | if array_node.type == "star_expr": | |
406 | # pep 448 single-star unpacking | |
407 | # for now ignoring values imported by * | |
408 | return [] | |
409 | else: | |
410 | return [array_node] | |
411 | ||
412 | def __repr__(self): | |
413 | return "<%s of %s>" % (self.__class__.__name__, self.atom) | |
414 | ||
415 | ||
416 | class DictLiteralValue(_DictMixin, SequenceLiteralValue, _DictKeyMixin): | |
417 | array_type = 'dict' | |
418 | ||
419 | def __init__(self, inference_state, defining_context, atom): | |
420 | # Intentionally don't call the super class. This is definitely a sign | |
421 | # that the architecture is bad and we should refactor. | |
422 | Sequence.__init__(self, inference_state) | |
423 | self._defining_context = defining_context | |
424 | self.atom = atom | |
425 | ||
426 | def py__simple_getitem__(self, index): | |
427 | """Here the index is an int/str. Raises IndexError/KeyError.""" | |
428 | compiled_value_index = compiled.create_simple_object(self.inference_state, index) | |
429 | for key, value in self.get_tree_entries(): | |
430 | for k in self._defining_context.infer_node(key): | |
431 | for key_v in k.execute_operation(compiled_value_index, '=='): | |
432 | if key_v.get_safe_value(): | |
433 | return self._defining_context.infer_node(value) | |
434 | raise SimpleGetItemNotFound('No key found in dictionary %s.' % self) | |
435 | ||
436 | def py__iter__(self, contextualized_node=None): | |
437 | """ | |
438 | While values returns the possible values for any array field, this | |
439 | function returns the value for a certain index. | |
440 | """ | |
441 | # Get keys. | |
442 | types = NO_VALUES | |
443 | for k, _ in self.get_tree_entries(): | |
444 | types |= self._defining_context.infer_node(k) | |
445 | # We don't know which dict index comes first, therefore always | |
446 | # yield all the types. | |
447 | for _ in types: | |
448 | yield LazyKnownValues(types) | |
449 | ||
450 | @publish_method('values') | |
451 | def _imitate_values(self, arguments): | |
452 | lazy_value = LazyKnownValues(self._dict_values()) | |
453 | return ValueSet([FakeList(self.inference_state, [lazy_value])]) | |
454 | ||
455 | @publish_method('items') | |
456 | def _imitate_items(self, arguments): | |
457 | lazy_values = [ | |
458 | LazyKnownValue(FakeTuple( | |
459 | self.inference_state, | |
460 | (LazyTreeValue(self._defining_context, key_node), | |
461 | LazyTreeValue(self._defining_context, value_node)) | |
462 | )) for key_node, value_node in self.get_tree_entries() | |
463 | ] | |
464 | ||
465 | return ValueSet([FakeList(self.inference_state, lazy_values)]) | |
466 | ||
467 | def exact_key_items(self): | |
468 | """ | |
469 | Returns a generator of tuples like dict.items(), where the key is | |
470 | resolved (as a string) and the values are still lazy values. | |
471 | """ | |
472 | for key_node, value in self.get_tree_entries(): | |
473 | for key in self._defining_context.infer_node(key_node): | |
474 | if is_string(key): | |
475 | yield key.get_safe_value(), LazyTreeValue(self._defining_context, value) | |
476 | ||
477 | def _dict_values(self): | |
478 | return ValueSet.from_sets( | |
479 | self._defining_context.infer_node(v) | |
480 | for k, v in self.get_tree_entries() | |
481 | ) | |
482 | ||
483 | def _dict_keys(self): | |
484 | return ValueSet.from_sets( | |
485 | self._defining_context.infer_node(k) | |
486 | for k, v in self.get_tree_entries() | |
487 | ) | |
488 | ||
489 | ||
490 | class _FakeSequence(Sequence): | |
491 | def __init__(self, inference_state, lazy_value_list): | |
492 | """ | |
493 | type should be one of "tuple", "list" | |
494 | """ | |
495 | super().__init__(inference_state) | |
496 | self._lazy_value_list = lazy_value_list | |
497 | ||
498 | def py__simple_getitem__(self, index): | |
499 | if isinstance(index, slice): | |
500 | return ValueSet([self]) | |
501 | ||
502 | with reraise_getitem_errors(IndexError, TypeError): | |
503 | lazy_value = self._lazy_value_list[index] | |
504 | return lazy_value.infer() | |
505 | ||
506 | def py__iter__(self, contextualized_node=None): | |
507 | return self._lazy_value_list | |
508 | ||
509 | def py__bool__(self): | |
510 | return bool(len(self._lazy_value_list)) | |
511 | ||
512 | def __repr__(self): | |
513 | return "<%s of %s>" % (type(self).__name__, self._lazy_value_list) | |
514 | ||
515 | ||
516 | class FakeTuple(_FakeSequence): | |
517 | array_type = 'tuple' | |
518 | ||
519 | ||
520 | class FakeList(_FakeSequence): | |
521 | array_type = 'tuple' | |
522 | ||
523 | ||
524 | class FakeDict(_DictMixin, Sequence, _DictKeyMixin): | |
525 | array_type = 'dict' | |
526 | ||
527 | def __init__(self, inference_state, dct): | |
528 | super().__init__(inference_state) | |
529 | self._dct = dct | |
530 | ||
531 | def py__iter__(self, contextualized_node=None): | |
532 | for key in self._dct: | |
533 | yield LazyKnownValue(compiled.create_simple_object(self.inference_state, key)) | |
534 | ||
535 | def py__simple_getitem__(self, index): | |
536 | with reraise_getitem_errors(KeyError, TypeError): | |
537 | lazy_value = self._dct[index] | |
538 | return lazy_value.infer() | |
539 | ||
540 | @publish_method('values') | |
541 | def _values(self, arguments): | |
542 | return ValueSet([FakeTuple( | |
543 | self.inference_state, | |
544 | [LazyKnownValues(self._dict_values())] | |
545 | )]) | |
546 | ||
547 | def _dict_values(self): | |
548 | return ValueSet.from_sets(lazy_value.infer() for lazy_value in self._dct.values()) | |
549 | ||
550 | def _dict_keys(self): | |
551 | return ValueSet.from_sets(lazy_value.infer() for lazy_value in self.py__iter__()) | |
552 | ||
553 | def exact_key_items(self): | |
554 | return self._dct.items() | |
555 | ||
556 | def __repr__(self): | |
557 | return '<%s: %s>' % (self.__class__.__name__, self._dct) | |
558 | ||
559 | ||
560 | class MergedArray(Sequence): | |
561 | def __init__(self, inference_state, arrays): | |
562 | super().__init__(inference_state) | |
563 | self.array_type = arrays[-1].array_type | |
564 | self._arrays = arrays | |
565 | ||
566 | def py__iter__(self, contextualized_node=None): | |
567 | for array in self._arrays: | |
568 | yield from array.py__iter__() | |
569 | ||
570 | def py__simple_getitem__(self, index): | |
571 | return ValueSet.from_sets(lazy_value.infer() for lazy_value in self.py__iter__()) | |
572 | ||
573 | ||
574 | def unpack_tuple_to_dict(context, types, exprlist): | |
575 | """ | |
576 | Unpacking tuple assignments in for statements and expr_stmts. | |
577 | """ | |
578 | if exprlist.type == 'name': | |
579 | return {exprlist.value: types} | |
580 | elif exprlist.type == 'atom' and exprlist.children[0] in ('(', '['): | |
581 | return unpack_tuple_to_dict(context, types, exprlist.children[1]) | |
582 | elif exprlist.type in ('testlist', 'testlist_comp', 'exprlist', | |
583 | 'testlist_star_expr'): | |
584 | dct = {} | |
585 | parts = iter(exprlist.children[::2]) | |
586 | n = 0 | |
587 | for lazy_value in types.iterate(ContextualizedNode(context, exprlist)): | |
588 | n += 1 | |
589 | try: | |
590 | part = next(parts) | |
591 | except StopIteration: | |
592 | analysis.add(context, 'value-error-too-many-values', part, | |
593 | message="ValueError: too many values to unpack (expected %s)" % n) | |
594 | else: | |
595 | dct.update(unpack_tuple_to_dict(context, lazy_value.infer(), part)) | |
596 | has_parts = next(parts, None) | |
597 | if types and has_parts is not None: | |
598 | analysis.add(context, 'value-error-too-few-values', has_parts, | |
599 | message="ValueError: need more than %s values to unpack" % n) | |
600 | return dct | |
601 | elif exprlist.type == 'power' or exprlist.type == 'atom_expr': | |
602 | # Something like ``arr[x], var = ...``. | |
603 | # This is something that is not yet supported, would also be difficult | |
604 | # to write into a dict. | |
605 | return {} | |
606 | elif exprlist.type == 'star_expr': # `a, *b, c = x` type unpackings | |
607 | # Currently we're not supporting them. | |
608 | return {} | |
609 | raise NotImplementedError | |
610 | ||
611 | ||
612 | class Slice(LazyValueWrapper): | |
613 | def __init__(self, python_context, start, stop, step): | |
614 | self.inference_state = python_context.inference_state | |
615 | self._context = python_context | |
616 | # All of them are either a Precedence or None. | |
617 | self._start = start | |
618 | self._stop = stop | |
619 | self._step = step | |
620 | ||
621 | def _get_wrapped_value(self): | |
622 | value = compiled.builtin_from_name(self._context.inference_state, 'slice') | |
623 | slice_value, = value.execute_with_values() | |
624 | return slice_value | |
625 | ||
626 | def get_safe_value(self, default=sentinel): | |
627 | """ | |
628 | Imitate CompiledValue.obj behavior and return a ``builtin.slice()`` | |
629 | object. | |
630 | """ | |
631 | def get(element): | |
632 | if element is None: | |
633 | return None | |
634 | ||
635 | result = self._context.infer_node(element) | |
636 | if len(result) != 1: | |
637 | # For simplicity, we want slices to be clear defined with just | |
638 | # one type. Otherwise we will return an empty slice object. | |
639 | raise IndexError | |
640 | ||
641 | value, = result | |
642 | return get_int_or_none(value) | |
643 | ||
644 | try: | |
645 | return slice(get(self._start), get(self._stop), get(self._step)) | |
646 | except IndexError: | |
647 | return slice(None, None, None) |