Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jedi/plugins/stdlib.py: 33%

452 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

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 

14from inspect import Parameter 

15 

16from jedi import debug 

17from jedi.inference.utils import safe_property 

18from jedi.inference.helpers import get_str_or_none 

19from jedi.inference.arguments import iterate_argument_clinic, ParamIssue, \ 

20 repack_with_argument_clinic, AbstractArguments, TreeArgumentsWrapper 

21from jedi.inference import analysis 

22from jedi.inference import compiled 

23from jedi.inference.value.instance import \ 

24 AnonymousMethodExecutionContext, MethodExecutionContext 

25from jedi.inference.base_value import ContextualizedNode, \ 

26 NO_VALUES, ValueSet, ValueWrapper, LazyValueWrapper 

27from jedi.inference.value import ClassValue, ModuleValue 

28from jedi.inference.value.klass import ClassMixin 

29from jedi.inference.value.function import FunctionMixin 

30from jedi.inference.value import iterable 

31from jedi.inference.lazy_value import LazyTreeValue, LazyKnownValue, \ 

32 LazyKnownValues 

33from jedi.inference.names import ValueName, BaseTreeParamName 

34from jedi.inference.filters import AttributeOverwrite, publish_method, \ 

35 ParserTreeFilter, DictFilter 

36from 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 

43from operator import itemgetter as _itemgetter 

44from collections import OrderedDict 

45 

46class {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 

104def 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 

139def _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 

148def 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) 

184def 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], /') 

191def 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], /') 

197def 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], /') 

211def 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 

219class 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) 

244def 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 

255class 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) 

271def 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) 

290def 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 

331class StaticMethodObject(ValueWrapper): 

332 def py__get__(self, instance, class_value): 

333 return ValueSet([self._wrapped_value]) 

334 

335 

336@argument_clinic('sequence, /') 

337def builtins_staticmethod(functions): 

338 return ValueSet(StaticMethodObject(f) for f in functions) 

339 

340 

341class 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 

353class 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 

366class 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) 

378def 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 

386class 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) 

406def 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 

414def 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 

472class 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 

528class 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 

535class 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 

546class 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 

565def functools_partial(value, arguments, callback): 

566 return ValueSet( 

567 PartialObject(instance, arguments) 

568 for instance in value.py__call__(arguments) 

569 ) 

570 

571 

572def 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, /') 

580def _return_first_param(firsts): 

581 return firsts 

582 

583 

584@argument_clinic('seq') 

585def _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 

593def _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 

602class 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 

628class 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 

637class 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 

653class 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, /') 

678def _functools_wraps(funcs): 

679 return ValueSet(WrapsCallable(func) for func in funcs) 

680 

681 

682class 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 

691class 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) 

705def _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 

712def _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) 

729def _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 

826def 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 

840class 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 

872def 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