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