1"""
2Implementations of standard library functions, because it's not possible to
3understand them with Jedi.
4
5To add a new implementation, create a function and add it to the
6``_implemented`` dict at the bottom of this module.
7
8Note that this module exists only to implement very specific functionality in
9the standard library. The usual way to understand the standard library is the
10compiled module that returns the types for C-builtins.
11"""
12import parso
13import os
14
15from jedi import debug
16from jedi.inference.utils import safe_property
17from jedi.inference.helpers import get_str_or_none
18from jedi.inference.arguments import iterate_argument_clinic, ParamIssue, \
19 repack_with_argument_clinic, AbstractArguments, TreeArgumentsWrapper
20from jedi.inference import analysis
21from jedi.inference import compiled
22from jedi.inference.value.instance import \
23 AnonymousMethodExecutionContext, MethodExecutionContext
24from jedi.inference.base_value import ContextualizedNode, \
25 NO_VALUES, ValueSet, ValueWrapper, LazyValueWrapper
26from jedi.inference.value import ClassValue, ModuleValue
27from jedi.inference.value.decorator import Decoratee
28from jedi.inference.value.klass import (
29 DataclassWrapper,
30 DataclassDecorator,
31 DataclassTransformer,
32)
33from jedi.inference.value.function import FunctionMixin
34from jedi.inference.value import iterable
35from jedi.inference.lazy_value import LazyTreeValue, LazyKnownValue, \
36 LazyKnownValues
37from jedi.inference.names import ValueName
38from jedi.inference.filters import AttributeOverwrite, publish_method, \
39 ParserTreeFilter, DictFilter
40from jedi.inference.signature import SignatureWrapper
41
42
43# Copied from Python 3.6's stdlib.
44_NAMEDTUPLE_CLASS_TEMPLATE = """\
45_property = property
46_tuple = tuple
47from operator import itemgetter as _itemgetter
48from collections import OrderedDict
49
50class {typename}(tuple):
51 __slots__ = ()
52
53 _fields = {field_names!r}
54
55 def __new__(_cls, {arg_list}):
56 'Create new instance of {typename}({arg_list})'
57 return _tuple.__new__(_cls, ({arg_list}))
58
59 @classmethod
60 def _make(cls, iterable, new=tuple.__new__, len=len):
61 'Make a new {typename} object from a sequence or iterable'
62 result = new(cls, iterable)
63 if len(result) != {num_fields:d}:
64 raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result))
65 return result
66
67 def _replace(_self, **kwds):
68 'Return a new {typename} object replacing specified fields with new values'
69 result = _self._make(map(kwds.pop, {field_names!r}, _self))
70 if kwds:
71 raise ValueError('Got unexpected field names: %r' % list(kwds))
72 return result
73
74 def __repr__(self):
75 'Return a nicely formatted representation string'
76 return self.__class__.__name__ + '({repr_fmt})' % self
77
78 def _asdict(self):
79 'Return a new OrderedDict which maps field names to their values.'
80 return OrderedDict(zip(self._fields, self))
81
82 def __getnewargs__(self):
83 'Return self as a plain tuple. Used by copy and pickle.'
84 return tuple(self)
85
86 # These methods were added by Jedi.
87 # __new__ doesn't really work with Jedi. So adding this to nametuples seems
88 # like the easiest way.
89 def __init__(self, {arg_list}):
90 'A helper function for namedtuple.'
91 self.__iterable = ({arg_list})
92
93 def __iter__(self):
94 for i in self.__iterable:
95 yield i
96
97 def __getitem__(self, y):
98 return self.__iterable[y]
99
100{field_defs}
101"""
102
103_NAMEDTUPLE_FIELD_TEMPLATE = '''\
104 {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}')
105'''
106
107
108def execute(callback):
109 def wrapper(value, arguments):
110 def call():
111 return callback(value, arguments=arguments)
112
113 try:
114 obj_name = value.name.string_name
115 except AttributeError:
116 pass
117 else:
118 p = value.parent_context
119 if p is not None and p.is_builtins_module():
120 module_name = 'builtins'
121 elif p is not None and p.is_module():
122 module_name = p.py__name__()
123 else:
124 return call()
125
126 if value.is_bound_method() or value.is_instance():
127 # value can be an instance for example if it is a partial
128 # object.
129 return call()
130
131 # for now we just support builtin functions.
132 try:
133 func = _implemented[module_name][obj_name]
134 except KeyError:
135 pass
136 else:
137 return func(value, arguments=arguments, callback=call)
138 return call()
139
140 return wrapper
141
142
143def _follow_param(inference_state, arguments, index):
144 try:
145 key, lazy_value = list(arguments.unpack())[index]
146 except IndexError:
147 return NO_VALUES
148 else:
149 return lazy_value.infer()
150
151
152def argument_clinic(clinic_string, want_value=False, want_context=False,
153 want_arguments=False, want_inference_state=False,
154 want_callback=False):
155 """
156 Works like Argument Clinic (PEP 436), to validate function params.
157 """
158
159 def f(func):
160 def wrapper(value, arguments, callback):
161 try:
162 args = tuple(iterate_argument_clinic(
163 value.inference_state, arguments, clinic_string))
164 except ParamIssue:
165 return NO_VALUES
166
167 debug.dbg('builtin start %s' % value, color='MAGENTA')
168 kwargs = {}
169 if want_context:
170 kwargs['context'] = arguments.context
171 if want_value:
172 kwargs['value'] = value
173 if want_inference_state:
174 kwargs['inference_state'] = value.inference_state
175 if want_arguments:
176 kwargs['arguments'] = arguments
177 if want_callback:
178 kwargs['callback'] = callback
179 result = func(*args, **kwargs)
180 debug.dbg('builtin end: %s', result, color='MAGENTA')
181 return result
182
183 return wrapper
184 return f
185
186
187@argument_clinic('iterator[, default], /', want_inference_state=True)
188def builtins_next(iterators, defaults, inference_state):
189 # TODO theoretically we have to check here if something is an iterator.
190 # That is probably done by checking if it's not a class.
191 return defaults | iterators.py__getattribute__('__next__').execute_with_values()
192
193
194@argument_clinic('iterator[, default], /')
195def builtins_iter(iterators_or_callables, defaults):
196 # TODO implement this if it's a callable.
197 return iterators_or_callables.py__getattribute__('__iter__').execute_with_values()
198
199
200@argument_clinic('object, name[, default], /')
201def builtins_getattr(objects, names, defaults=None):
202 # follow the first param
203 for value in objects:
204 for name in names:
205 string = get_str_or_none(name)
206 if string is None:
207 debug.warning('getattr called without str')
208 continue
209 else:
210 return value.py__getattribute__(string)
211 return NO_VALUES
212
213
214@argument_clinic('object[, bases, dict], /')
215def builtins_type(objects, bases, dicts):
216 if bases or dicts:
217 # It's a type creation... maybe someday...
218 return NO_VALUES
219 else:
220 return objects.py__class__()
221
222
223class SuperInstance(LazyValueWrapper):
224 """To be used like the object ``super`` returns."""
225 def __init__(self, inference_state, instance):
226 self.inference_state = inference_state
227 self._instance = instance # Corresponds to super().__self__
228
229 def _get_bases(self):
230 return self._instance.py__class__().py__bases__()
231
232 def _get_wrapped_value(self):
233 objs = self._get_bases()[0].infer().execute_with_values()
234 if not objs:
235 # This is just a fallback and will only be used, if it's not
236 # possible to find a class
237 return self._instance
238 return next(iter(objs))
239
240 def get_filters(self, origin_scope=None):
241 for b in self._get_bases():
242 for value in b.infer().execute_with_values():
243 for f in value.get_filters():
244 yield f
245
246
247@argument_clinic('[type[, value]], /', want_context=True)
248def builtins_super(types, objects, context):
249 instance = None
250 if isinstance(context, AnonymousMethodExecutionContext):
251 instance = context.instance
252 elif isinstance(context, MethodExecutionContext):
253 instance = context.instance
254 if instance is None:
255 return NO_VALUES
256 return ValueSet({SuperInstance(instance.inference_state, instance)})
257
258
259class ReversedObject(AttributeOverwrite):
260 def __init__(self, reversed_obj, iter_list):
261 super().__init__(reversed_obj)
262 self._iter_list = iter_list
263
264 def py__iter__(self, contextualized_node=None):
265 return self._iter_list
266
267 @publish_method('__next__')
268 def _next(self, arguments):
269 return ValueSet.from_sets(
270 lazy_value.infer() for lazy_value in self._iter_list
271 )
272
273
274@argument_clinic('sequence, /', want_value=True, want_arguments=True)
275def builtins_reversed(sequences, value, arguments):
276 # While we could do without this variable (just by using sequences), we
277 # want static analysis to work well. Therefore we need to generated the
278 # values again.
279 key, lazy_value = next(arguments.unpack())
280 cn = None
281 if isinstance(lazy_value, LazyTreeValue):
282 cn = ContextualizedNode(lazy_value.context, lazy_value.data)
283 ordered = list(sequences.iterate(cn))
284
285 # Repack iterator values and then run it the normal way. This is
286 # necessary, because `reversed` is a function and autocompletion
287 # would fail in certain cases like `reversed(x).__iter__` if we
288 # just returned the result directly.
289 seq, = value.inference_state.typing_module.py__getattribute__('Iterator').execute_with_values()
290 return ValueSet([ReversedObject(seq, list(reversed(ordered)))])
291
292
293@argument_clinic('value, type, /', want_arguments=True, want_inference_state=True)
294def builtins_isinstance(objects, types, arguments, inference_state):
295 bool_results = set()
296 for o in objects:
297 cls = o.py__class__()
298 try:
299 cls.py__bases__
300 except AttributeError:
301 # This is temporary. Everything should have a class attribute in
302 # Python?! Maybe we'll leave it here, because some numpy objects or
303 # whatever might not.
304 bool_results = set([True, False])
305 break
306
307 mro = list(cls.py__mro__())
308
309 for cls_or_tup in types:
310 if cls_or_tup.is_class():
311 bool_results.add(cls_or_tup in mro)
312 elif cls_or_tup.name.string_name == 'tuple' \
313 and cls_or_tup.get_root_context().is_builtins_module():
314 # Check for tuples.
315 classes = ValueSet.from_sets(
316 lazy_value.infer()
317 for lazy_value in cls_or_tup.iterate()
318 )
319 bool_results.add(any(cls in mro for cls in classes))
320 else:
321 _, lazy_value = list(arguments.unpack())[1]
322 if isinstance(lazy_value, LazyTreeValue):
323 node = lazy_value.data
324 message = 'TypeError: isinstance() arg 2 must be a ' \
325 'class, type, or tuple of classes and types, ' \
326 'not %s.' % cls_or_tup
327 analysis.add(lazy_value.context, 'type-error-isinstance', node, message)
328
329 return ValueSet(
330 compiled.builtin_from_name(inference_state, str(b))
331 for b in bool_results
332 )
333
334
335class StaticMethodObject(ValueWrapper):
336 def py__get__(self, instance, class_value):
337 return ValueSet([self._wrapped_value])
338
339
340@argument_clinic('sequence, /')
341def builtins_staticmethod(functions):
342 return ValueSet(StaticMethodObject(f) for f in functions)
343
344
345class ClassMethodObject(ValueWrapper):
346 def __init__(self, class_method_obj, function):
347 super().__init__(class_method_obj)
348 self._function = function
349
350 def py__get__(self, instance, class_value):
351 return ValueSet([
352 ClassMethodGet(__get__, class_value, self._function)
353 for __get__ in self._wrapped_value.py__getattribute__('__get__')
354 ])
355
356
357class ClassMethodGet(ValueWrapper):
358 def __init__(self, get_method, klass, function):
359 super().__init__(get_method)
360 self._class = klass
361 self._function = function
362
363 def get_signatures(self):
364 return [sig.bind(self._function) for sig in self._function.get_signatures()]
365
366 def py__call__(self, arguments):
367 return self._function.execute(ClassMethodArguments(self._class, arguments))
368
369
370class ClassMethodArguments(TreeArgumentsWrapper):
371 def __init__(self, klass, arguments):
372 super().__init__(arguments)
373 self._class = klass
374
375 def unpack(self, func=None):
376 yield None, LazyKnownValue(self._class)
377 for values in self._wrapped_arguments.unpack(func):
378 yield values
379
380
381@argument_clinic('sequence, /', want_value=True, want_arguments=True)
382def builtins_classmethod(functions, value, arguments):
383 return ValueSet(
384 ClassMethodObject(class_method_object, function)
385 for class_method_object in value.py__call__(arguments=arguments)
386 for function in functions
387 )
388
389
390class PropertyObject(AttributeOverwrite, ValueWrapper):
391 api_type = 'property'
392
393 def __init__(self, property_obj, function):
394 super().__init__(property_obj)
395 self._function = function
396
397 def py__get__(self, instance, class_value):
398 if instance is None:
399 return ValueSet([self])
400 return self._function.execute_with_values(instance)
401
402 @publish_method('deleter')
403 @publish_method('getter')
404 @publish_method('setter')
405 def _return_self(self, arguments):
406 return ValueSet({self})
407
408
409@argument_clinic('func, /', want_callback=True)
410def builtins_property(functions, callback):
411 return ValueSet(
412 PropertyObject(property_value, function)
413 for property_value in callback()
414 for function in functions
415 )
416
417
418def collections_namedtuple(value, arguments, callback):
419 """
420 Implementation of the namedtuple function.
421
422 This has to be done by processing the namedtuple class template and
423 inferring the result.
424
425 """
426 inference_state = value.inference_state
427
428 # Process arguments
429 name = 'jedi_unknown_namedtuple'
430 for c in _follow_param(inference_state, arguments, 0):
431 x = get_str_or_none(c)
432 if x is not None:
433 name = x
434 break
435
436 # TODO here we only use one of the types, we should use all.
437 param_values = _follow_param(inference_state, arguments, 1)
438 if not param_values:
439 return NO_VALUES
440 _fields = list(param_values)[0]
441 string = get_str_or_none(_fields)
442 if string is not None:
443 fields = string.replace(',', ' ').split()
444 elif isinstance(_fields, iterable.Sequence):
445 fields = [
446 get_str_or_none(v)
447 for lazy_value in _fields.py__iter__()
448 for v in lazy_value.infer()
449 ]
450 fields = [f for f in fields if f is not None]
451 else:
452 return NO_VALUES
453
454 # Build source code
455 code = _NAMEDTUPLE_CLASS_TEMPLATE.format(
456 typename=name,
457 field_names=tuple(fields),
458 num_fields=len(fields),
459 arg_list=repr(tuple(fields)).replace("'", "")[1:-1],
460 repr_fmt='',
461 field_defs='\n'.join(_NAMEDTUPLE_FIELD_TEMPLATE.format(index=index, name=name)
462 for index, name in enumerate(fields))
463 )
464
465 # Parse source code
466 module = inference_state.grammar.parse(code)
467 generated_class = next(module.iter_classdefs())
468 parent_context = ModuleValue(
469 inference_state, module,
470 code_lines=parso.split_lines(code, keepends=True),
471 ).as_context()
472
473 return ValueSet([ClassValue(inference_state, parent_context, generated_class)])
474
475
476class PartialObject(ValueWrapper):
477 def __init__(self, actual_value, arguments, instance=None):
478 super().__init__(actual_value)
479 self._arguments = arguments
480 self._instance = instance
481
482 def _get_functions(self, unpacked_arguments):
483 key, lazy_value = next(unpacked_arguments, (None, None))
484 if key is not None or lazy_value is None:
485 debug.warning("Partial should have a proper function %s", self._arguments)
486 return None
487 return lazy_value.infer()
488
489 def get_signatures(self):
490 unpacked_arguments = self._arguments.unpack()
491 funcs = self._get_functions(unpacked_arguments)
492 if funcs is None:
493 return []
494
495 arg_count = 0
496 if self._instance is not None:
497 arg_count = 1
498 keys = set()
499 for key, _ in unpacked_arguments:
500 if key is None:
501 arg_count += 1
502 else:
503 keys.add(key)
504 return [PartialSignature(s, arg_count, keys) for s in funcs.get_signatures()]
505
506 def py__call__(self, arguments):
507 funcs = self._get_functions(self._arguments.unpack())
508 if funcs is None:
509 return NO_VALUES
510
511 return funcs.execute(
512 MergedPartialArguments(self._arguments, arguments, self._instance)
513 )
514
515 def py__doc__(self):
516 """
517 In CPython partial does not replace the docstring. However we are still
518 imitating it here, because we want this docstring to be worth something
519 for the user.
520 """
521 callables = self._get_functions(self._arguments.unpack())
522 if callables is None:
523 return ''
524 for callable_ in callables:
525 return callable_.py__doc__()
526 return ''
527
528 def py__get__(self, instance, class_value):
529 return ValueSet([self])
530
531
532class PartialMethodObject(PartialObject):
533 def py__get__(self, instance, class_value):
534 if instance is None:
535 return ValueSet([self])
536 return ValueSet([PartialObject(self._wrapped_value, self._arguments, instance)])
537
538
539class PartialSignature(SignatureWrapper):
540 def __init__(self, wrapped_signature, skipped_arg_count, skipped_arg_set):
541 super().__init__(wrapped_signature)
542 self._skipped_arg_count = skipped_arg_count
543 self._skipped_arg_set = skipped_arg_set
544
545 def get_param_names(self, resolve_stars=False):
546 names = self._wrapped_signature.get_param_names()[self._skipped_arg_count:]
547 return [n for n in names if n.string_name not in self._skipped_arg_set]
548
549
550class MergedPartialArguments(AbstractArguments):
551 def __init__(self, partial_arguments, call_arguments, instance=None):
552 self._partial_arguments = partial_arguments
553 self._call_arguments = call_arguments
554 self._instance = instance
555
556 def unpack(self, funcdef=None):
557 unpacked = self._partial_arguments.unpack(funcdef)
558 # Ignore this one, it's the function. It was checked before that it's
559 # there.
560 next(unpacked, None)
561 if self._instance is not None:
562 yield None, LazyKnownValue(self._instance)
563 for key_lazy_value in unpacked:
564 yield key_lazy_value
565 for key_lazy_value in self._call_arguments.unpack(funcdef):
566 yield key_lazy_value
567
568
569def functools_partial(value, arguments, callback):
570 return ValueSet(
571 PartialObject(instance, arguments)
572 for instance in value.py__call__(arguments)
573 )
574
575
576def functools_partialmethod(value, arguments, callback):
577 return ValueSet(
578 PartialMethodObject(instance, arguments)
579 for instance in value.py__call__(arguments)
580 )
581
582
583@argument_clinic('first, /')
584def _return_first_param(firsts):
585 return firsts
586
587
588@argument_clinic('seq')
589def _random_choice(sequences):
590 return ValueSet.from_sets(
591 lazy_value.infer()
592 for sequence in sequences
593 for lazy_value in sequence.py__iter__()
594 )
595
596
597def _dataclass(value, arguments, callback):
598 """
599 Decorator entry points for dataclass.
600
601 1. dataclass decorator declaration with parameters
602 2. dataclass semantics on a class from a dataclass(-like) decorator
603 """
604 for c in _follow_param(value.inference_state, arguments, 0):
605 if c.is_class():
606 # Declare dataclass semantics on a class from a dataclass decorator
607 should_generate_init = (
608 # Customized decorator, init may be disabled
609 value.init_param_mode
610 if isinstance(value, DataclassDecorator)
611 # Bare dataclass decorator, always with init mode
612 else True
613 )
614 return ValueSet([DataclassWrapper(c, should_generate_init)])
615 else:
616 # @dataclass(init=False)
617 # dataclass decorator customization
618 return ValueSet(
619 [
620 DataclassDecorator(
621 value,
622 arguments=arguments,
623 default_init=True,
624 )
625 ]
626 )
627
628 return NO_VALUES
629
630
631def _dataclass_transform(value, arguments, callback):
632 """
633 Decorator entry points for dataclass_transform.
634
635 1. dataclass-like decorator instantiation from a dataclass_transform decorator
636 2. dataclass_transform decorator declaration with parameters
637 3. dataclass-like decorator declaration with parameters
638 4. dataclass-like semantics on a class from a dataclass-like decorator
639 """
640 for c in _follow_param(value.inference_state, arguments, 0):
641 if c.is_class():
642 is_dataclass_transform = (
643 value.name.string_name == "dataclass_transform"
644 # The decorator function from dataclass_transform acting as the
645 # dataclass decorator.
646 and not isinstance(value, Decoratee)
647 # The decorator function from dataclass_transform acting as the
648 # dataclass decorator with customized parameters
649 and not isinstance(value, DataclassDecorator)
650 )
651
652 if is_dataclass_transform:
653 # Declare base class
654 return ValueSet([DataclassTransformer(c)])
655 else:
656 # Declare dataclass-like semantics on a class from a
657 # dataclass-like decorator
658 should_generate_init = value.init_param_mode
659 return ValueSet([DataclassWrapper(c, should_generate_init)])
660 elif c.is_function():
661 # dataclass-like decorator instantiation:
662 # @dataclass_transform
663 # def create_model()
664 return ValueSet(
665 [
666 DataclassDecorator(
667 value,
668 arguments=arguments,
669 default_init=True,
670 )
671 ]
672 )
673 elif (
674 # @dataclass_transform
675 # def create_model(): pass
676 # @create_model(init=...)
677 isinstance(value, Decoratee)
678 ):
679 # dataclass (or like) decorator customization
680 return ValueSet(
681 [
682 DataclassDecorator(
683 value,
684 arguments=arguments,
685 default_init=value._wrapped_value.init_param_mode,
686 )
687 ]
688 )
689 else:
690 # dataclass_transform decorator with parameters; nothing impactful
691 return ValueSet([value])
692 return NO_VALUES
693
694
695class ItemGetterCallable(ValueWrapper):
696 def __init__(self, instance, args_value_set):
697 super().__init__(instance)
698 self._args_value_set = args_value_set
699
700 @repack_with_argument_clinic('item, /')
701 def py__call__(self, item_value_set):
702 value_set = NO_VALUES
703 for args_value in self._args_value_set:
704 lazy_values = list(args_value.py__iter__())
705 if len(lazy_values) == 1:
706 # TODO we need to add the contextualized value.
707 value_set |= item_value_set.get_item(lazy_values[0].infer(), None)
708 else:
709 value_set |= ValueSet([iterable.FakeList(
710 self._wrapped_value.inference_state,
711 [
712 LazyKnownValues(item_value_set.get_item(lazy_value.infer(), None))
713 for lazy_value in lazy_values
714 ],
715 )])
716 return value_set
717
718
719@argument_clinic('func, /')
720def _functools_wraps(funcs):
721 return ValueSet(WrapsCallable(func) for func in funcs)
722
723
724class WrapsCallable(ValueWrapper):
725 # XXX this is not the correct wrapped value, it should be a weird
726 # partials object, but it doesn't matter, because it's always used as a
727 # decorator anyway.
728 @repack_with_argument_clinic('func, /')
729 def py__call__(self, funcs):
730 return ValueSet({Wrapped(func, self._wrapped_value) for func in funcs})
731
732
733class Wrapped(ValueWrapper, FunctionMixin):
734 def __init__(self, func, original_function):
735 super().__init__(func)
736 self._original_function = original_function
737
738 @property
739 def name(self):
740 return self._original_function.name
741
742 def get_signature_functions(self):
743 return [self]
744
745
746@argument_clinic('*args, /', want_value=True, want_arguments=True)
747def _operator_itemgetter(args_value_set, value, arguments):
748 return ValueSet([
749 ItemGetterCallable(instance, args_value_set)
750 for instance in value.py__call__(arguments)
751 ])
752
753
754def _create_string_input_function(func):
755 @argument_clinic('string, /', want_value=True, want_arguments=True)
756 def wrapper(strings, value, arguments):
757 def iterate():
758 for value in strings:
759 s = get_str_or_none(value)
760 if s is not None:
761 s = func(s)
762 yield compiled.create_simple_object(value.inference_state, s)
763 values = ValueSet(iterate())
764 if values:
765 return values
766 return value.py__call__(arguments)
767 return wrapper
768
769
770@argument_clinic('*args, /', want_callback=True)
771def _os_path_join(args_set, callback):
772 if len(args_set) == 1:
773 string = ''
774 sequence, = args_set
775 is_first = True
776 for lazy_value in sequence.py__iter__():
777 string_values = lazy_value.infer()
778 if len(string_values) != 1:
779 break
780 s = get_str_or_none(next(iter(string_values)))
781 if s is None:
782 break
783 if not is_first:
784 string += os.path.sep
785 string += s
786 is_first = False
787 else:
788 return ValueSet([compiled.create_simple_object(sequence.inference_state, string)])
789 return callback()
790
791
792_implemented = {
793 'builtins': {
794 'getattr': builtins_getattr,
795 'type': builtins_type,
796 'super': builtins_super,
797 'reversed': builtins_reversed,
798 'isinstance': builtins_isinstance,
799 'next': builtins_next,
800 'iter': builtins_iter,
801 'staticmethod': builtins_staticmethod,
802 'classmethod': builtins_classmethod,
803 'property': builtins_property,
804 },
805 'copy': {
806 'copy': _return_first_param,
807 'deepcopy': _return_first_param,
808 },
809 'json': {
810 'load': lambda value, arguments, callback: NO_VALUES,
811 'loads': lambda value, arguments, callback: NO_VALUES,
812 },
813 'collections': {
814 'namedtuple': collections_namedtuple,
815 },
816 'functools': {
817 'partial': functools_partial,
818 'partialmethod': functools_partialmethod,
819 'wraps': _functools_wraps,
820 },
821 '_weakref': {
822 'proxy': _return_first_param,
823 },
824 'random': {
825 'choice': _random_choice,
826 },
827 'operator': {
828 'itemgetter': _operator_itemgetter,
829 },
830 'abc': {
831 # Not sure if this is necessary, but it's used a lot in typeshed and
832 # it's for now easier to just pass the function.
833 'abstractmethod': _return_first_param,
834 },
835 'typing': {
836 # The _alias function just leads to some annoying type inference.
837 # Therefore, just make it return nothing, which leads to the stubs
838 # being used instead. This only matters for 3.7+.
839 '_alias': lambda value, arguments, callback: NO_VALUES,
840 # runtime_checkable doesn't really change anything and is just
841 # adding logs for infering stuff, so we can safely ignore it.
842 'runtime_checkable': lambda value, arguments, callback: NO_VALUES,
843 # Python 3.11+
844 'dataclass_transform': _dataclass_transform,
845 },
846 'typing_extensions': {
847 # Python <3.11
848 'dataclass_transform': _dataclass_transform,
849 },
850 'dataclasses': {
851 # For now this works at least better than Jedi trying to understand it.
852 'dataclass': _dataclass
853 },
854 'os.path': {
855 'dirname': _create_string_input_function(os.path.dirname),
856 'abspath': _create_string_input_function(os.path.abspath),
857 'relpath': _create_string_input_function(os.path.relpath),
858 'join': _os_path_join,
859 }
860}
861
862
863def get_metaclass_filters(func):
864 def wrapper(cls, metaclasses, is_instance):
865 for metaclass in metaclasses:
866 if metaclass.py__name__() == 'EnumMeta' \
867 and metaclass.get_root_context().py__name__() == 'enum':
868 filter_ = ParserTreeFilter(parent_context=cls.as_context())
869 return [DictFilter({
870 name.string_name: EnumInstance(cls, name).name
871 for name in filter_.values()
872 })]
873 return func(cls, metaclasses, is_instance)
874 return wrapper
875
876
877class EnumInstance(LazyValueWrapper):
878 def __init__(self, cls, name):
879 self.inference_state = cls.inference_state
880 self._cls = cls # Corresponds to super().__self__
881 self._name = name
882 self.tree_node = self._name.tree_name
883
884 @safe_property
885 def name(self):
886 return ValueName(self, self._name.tree_name)
887
888 def _get_wrapped_value(self):
889 n = self._name.string_name
890 if n.startswith('__') and n.endswith('__') or self._name.api_type == 'function':
891 inferred = self._name.infer()
892 if inferred:
893 return next(iter(inferred))
894 o, = self.inference_state.builtins_module.py__getattribute__('object')
895 return o
896
897 value, = self._cls.execute_with_values()
898 return value
899
900 def get_filters(self, origin_scope=None):
901 yield DictFilter(dict(
902 name=compiled.create_simple_object(self.inference_state, self._name.string_name).name,
903 value=self._name,
904 ))
905 for f in self._get_wrapped_value().get_filters():
906 yield f
907
908
909def tree_name_to_values(func):
910 def wrapper(inference_state, context, tree_name):
911 if tree_name.value == 'sep' and context.is_module() and context.py__name__() == 'os.path':
912 return ValueSet({
913 compiled.create_simple_object(inference_state, os.path.sep),
914 })
915 return func(inference_state, context, tree_name)
916 return wrapper