Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/jedi-0.20.0-py3.11.egg/jedi/inference/value/klass.py: 27%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

354 statements  

1""" 

2Like described in the :mod:`parso.python.tree` module, 

3there's a need for an ast like module to represent the states of parsed 

4modules. 

5 

6But now there are also structures in Python that need a little bit more than 

7that. An ``Instance`` for example is only a ``Class`` before it is 

8instantiated. This class represents these cases. 

9 

10So, why is there also a ``Class`` class here? Well, there are decorators and 

11they change classes in Python 3. 

12 

13Representation modules also define "magic methods". Those methods look like 

14``py__foo__`` and are typically mappable to the Python equivalents ``__call__`` 

15and others. Here's a list: 

16 

17====================================== ======================================== 

18**Method** **Description** 

19-------------------------------------- ---------------------------------------- 

20py__call__(arguments: Array) On callable objects, returns types. 

21py__bool__() Returns True/False/None; None means that 

22 there's no certainty. 

23py__bases__() Returns a list of base classes. 

24py__iter__() Returns a generator of a set of types. 

25py__class__() Returns the class of an instance. 

26py__simple_getitem__(index: int/str) Returns a a set of types of the index. 

27 Can raise an IndexError/KeyError. 

28py__getitem__(indexes: ValueSet) Returns a a set of types of the index. 

29py__file__() Only on modules. Returns None if does 

30 not exist. 

31py__package__() -> List[str] Only on modules. For the import system. 

32py__path__() Only on modules. For the import system. 

33py__get__(call_object) Only on instances. Simulates 

34 descriptors. 

35py__doc__() Returns the docstring for a value. 

36====================================== ======================================== 

37 

38""" 

39from __future__ import annotations 

40 

41from typing import List, Optional, Tuple, TYPE_CHECKING, Any 

42 

43from jedi import debug 

44from jedi.parser_utils import get_cached_parent_scope, expr_is_dotted, \ 

45 function_is_property 

46from jedi.inference.cache import inference_state_method_cache, CachedMetaClass, \ 

47 inference_state_method_generator_cache 

48from jedi.inference import compiled 

49from jedi.inference.lazy_value import LazyKnownValues, LazyTreeValue 

50from jedi.inference.filters import ParserTreeFilter 

51from jedi.inference.names import TreeNameDefinition, ValueName 

52from jedi.inference.arguments import unpack_arglist, ValuesArguments 

53from jedi.inference.base_value import ValueSet, iterator_to_value_set, \ 

54 NO_VALUES, ValueWrapper 

55from jedi.inference.context import ClassContext 

56from jedi.inference.value.function import FunctionAndClassBase, FunctionMixin 

57from jedi.inference.value.decorator import Decoratee 

58from jedi.inference.gradual.generics import LazyGenericManager, TupleGenericManager 

59from jedi.plugins import plugin_manager 

60from inspect import Parameter 

61from jedi.inference.names import BaseTreeParamName 

62from jedi.inference.signature import AbstractSignature 

63 

64if TYPE_CHECKING: 

65 from jedi.inference import InferenceState 

66 

67 

68class ClassName(TreeNameDefinition): 

69 def __init__(self, class_value, tree_name, name_context, apply_decorators): 

70 super().__init__(name_context, tree_name) 

71 self._apply_decorators = apply_decorators 

72 self._class_value = class_value 

73 

74 @iterator_to_value_set 

75 def infer(self): 

76 # We're using a different value to infer, so we cannot call super(). 

77 from jedi.inference.syntax_tree import tree_name_to_values 

78 inferred = tree_name_to_values( 

79 self.parent_context.inference_state, self.parent_context, self.tree_name) 

80 

81 for result_value in inferred: 

82 if self._apply_decorators: 

83 yield from result_value.py__get__(instance=None, class_value=self._class_value) 

84 else: 

85 yield result_value 

86 

87 @property 

88 def api_type(self): 

89 type_ = super().api_type 

90 if type_ == 'function': 

91 definition = self.tree_name.get_definition() 

92 if definition is None: 

93 return type_ 

94 if function_is_property(definition): 

95 # This essentially checks if there is an @property before 

96 # the function. @property could be something different, but 

97 # any programmer that redefines property as something that 

98 # is not really a property anymore, should be shot. (i.e. 

99 # this is a heuristic). 

100 return 'property' 

101 return type_ 

102 

103 

104class ClassFilter(ParserTreeFilter): 

105 def __init__(self, class_value, node_context=None, until_position=None, 

106 origin_scope=None, is_instance=False): 

107 super().__init__( 

108 class_value.as_context(), node_context, 

109 until_position=until_position, 

110 origin_scope=origin_scope, 

111 ) 

112 self._class_value = class_value 

113 self._is_instance = is_instance 

114 

115 def _convert_names(self, names): 

116 return [ 

117 ClassName( 

118 class_value=self._class_value, 

119 tree_name=name, 

120 name_context=self._node_context, 

121 apply_decorators=not self._is_instance, 

122 ) for name in names 

123 ] 

124 

125 def _equals_origin_scope(self): 

126 node = self._origin_scope 

127 while node is not None: 

128 if node == self._parser_scope or node == self.parent_context: 

129 return True 

130 node = get_cached_parent_scope(self._parso_cache_node, node) 

131 return False 

132 

133 def _access_possible(self, name): 

134 # Filter for name mangling of private variables like __foo 

135 return not name.value.startswith('__') or name.value.endswith('__') \ 

136 or self._equals_origin_scope() 

137 

138 def _filter(self, names): 

139 names = super()._filter(names) 

140 return [name for name in names if self._access_possible(name)] 

141 

142 

143def init_param_value(arg_nodes) -> Optional[bool]: 

144 """ 

145 Returns: 

146 

147 - ``True`` if ``@dataclass(init=True)`` 

148 - ``False`` if ``@dataclass(init=False)`` 

149 - ``None`` if not specified ``@dataclass()`` 

150 """ 

151 for arg_node in arg_nodes: 

152 if ( 

153 arg_node.type == "argument" 

154 and arg_node.children[0].value == "init" 

155 ): 

156 if arg_node.children[2].value == "False": 

157 return False 

158 elif arg_node.children[2].value == "True": 

159 return True 

160 

161 return None 

162 

163 

164def get_dataclass_param_names(cls) -> List[DataclassParamName]: 

165 """ 

166 ``cls`` is a :class:`ClassMixin`. The type is only documented as mypy would 

167 complain that some fields are missing. 

168 

169 .. code:: python 

170 

171 @dataclass 

172 class A: 

173 a: int 

174 b: str = "toto" 

175 

176 For the previous example, the param names would be ``a`` and ``b``. 

177 """ 

178 param_names = [] 

179 filter_ = cls.as_context().get_global_filter() 

180 for name in sorted(filter_.values(), key=lambda name: name.start_pos): 

181 d = name.tree_name.get_definition() 

182 annassign = d.children[1] 

183 if d.type == 'expr_stmt' and annassign.type == 'annassign': 

184 node = annassign.children[1] 

185 if node.type == "atom_expr" and node.children[0].value == "ClassVar": 

186 continue 

187 

188 if len(annassign.children) < 4: 

189 default = None 

190 else: 

191 default = annassign.children[3] 

192 

193 param_names.append(DataclassParamName( 

194 parent_context=cls.parent_context, 

195 tree_name=name.tree_name, 

196 annotation_node=annassign.children[1], 

197 default_node=default, 

198 )) 

199 return param_names 

200 

201 

202class ClassMixin: 

203 tree_node: Any 

204 parent_context: Any 

205 inference_state: InferenceState 

206 py__bases__: Any 

207 get_metaclasses: Any 

208 get_metaclass_filters: Any 

209 get_metaclass_signatures: Any 

210 list_type_vars: Any 

211 

212 def is_class(self): 

213 return True 

214 

215 def is_class_mixin(self): 

216 return True 

217 

218 def py__call__(self, arguments): 

219 from jedi.inference.value import TreeInstance 

220 

221 from jedi.inference.gradual.typing import TypedDict 

222 if self.is_typeddict(): 

223 return ValueSet([TypedDict(self)]) 

224 return ValueSet([TreeInstance(self.inference_state, self.parent_context, self, arguments)]) 

225 

226 def py__class__(self): 

227 return compiled.builtin_from_name(self.inference_state, 'type') 

228 

229 @property 

230 def name(self): 

231 return ValueName(self, self.tree_node.name) 

232 

233 def py__name__(self): 

234 return self.name.string_name 

235 

236 @inference_state_method_generator_cache() 

237 def py__mro__(self): 

238 mro = [self] 

239 yield self 

240 # TODO Do a proper mro resolution. Currently we are just listing 

241 # classes. However, it's a complicated algorithm. 

242 for lazy_cls in self.py__bases__(): 

243 # TODO there's multiple different mro paths possible if this yields 

244 # multiple possibilities. Could be changed to be more correct. 

245 for cls in lazy_cls.infer(): 

246 # TODO detect for TypeError: duplicate base class str, 

247 # e.g. `class X(str, str): pass` 

248 try: 

249 mro_method = cls.py__mro__ 

250 except AttributeError: 

251 # TODO add a TypeError like: 

252 """ 

253 >>> class Y(lambda: test): pass 

254 Traceback (most recent call last): 

255 File "<stdin>", line 1, in <module> 

256 TypeError: function() argument 1 must be code, not str 

257 >>> class Y(1): pass 

258 Traceback (most recent call last): 

259 File "<stdin>", line 1, in <module> 

260 TypeError: int() takes at most 2 arguments (3 given) 

261 """ 

262 debug.warning('Super class of %s is not a class: %s', self, cls) 

263 else: 

264 for cls_new in mro_method(): 

265 if cls_new not in mro: 

266 mro.append(cls_new) 

267 yield cls_new 

268 

269 def get_filters(self, origin_scope=None, is_instance=False, 

270 include_metaclasses=True, include_type_when_class=True): 

271 if include_metaclasses: 

272 metaclasses = self.get_metaclasses() 

273 if metaclasses: 

274 yield from self.get_metaclass_filters(metaclasses, is_instance) 

275 

276 for cls in self.py__mro__(): 

277 if cls.is_compiled(): 

278 yield from cls.get_filters(is_instance=is_instance) 

279 else: 

280 yield ClassFilter( 

281 self, node_context=cls.as_context(), 

282 origin_scope=origin_scope, 

283 is_instance=is_instance 

284 ) 

285 if not is_instance and include_type_when_class: 

286 from jedi.inference.compiled import builtin_from_name 

287 type_ = builtin_from_name(self.inference_state, 'type') 

288 if type_ != self: 

289 # We are not using execute_with_values here, because the 

290 # plugin function for type would get executed instead of an 

291 # instance creation. 

292 args = ValuesArguments([]) 

293 for instance in type_.py__call__(args): 

294 instance_filters = instance.get_filters() 

295 # Filter out self filters 

296 next(instance_filters, None) 

297 next(instance_filters, None) 

298 x = next(instance_filters, None) 

299 assert x is not None 

300 yield x 

301 

302 def _has_dataclass_transform_metaclasses(self) -> Tuple[bool, Optional[bool]]: 

303 for meta in self.get_metaclasses(): # type: ignore[attr-defined] 

304 if ( 

305 isinstance(meta, Decoratee) 

306 # Internal leakage :| 

307 and isinstance(meta._wrapped_value, DataclassTransformer) 

308 ): 

309 return True, meta._wrapped_value.init_mode_from_new() 

310 

311 return False, None 

312 

313 def _get_dataclass_transform_signatures(self) -> List[DataclassSignature]: 

314 """ 

315 Returns: A non-empty list if the class has dataclass semantics else an 

316 empty list. 

317 

318 The dataclass-like semantics will be assumed for any class that directly 

319 or indirectly derives from the decorated class or uses the decorated 

320 class as a metaclass. 

321 """ 

322 param_names = [] 

323 is_dataclass_transform = False 

324 default_init_mode: Optional[bool] = None 

325 for cls in reversed(list(self.py__mro__())): 

326 if not is_dataclass_transform: 

327 

328 # If dataclass_transform is applied to a class, dataclass-like semantics 

329 # will be assumed for any class that directly or indirectly derives from 

330 # the decorated class or uses the decorated class as a metaclass. 

331 if ( 

332 isinstance(cls, DataclassTransformer) 

333 and cls.init_mode_from_init_subclass 

334 ): 

335 is_dataclass_transform = True 

336 default_init_mode = cls.init_mode_from_init_subclass 

337 

338 elif ( 

339 # Some object like CompiledValues would not be compatible 

340 isinstance(cls, ClassMixin) 

341 ): 

342 is_dataclass_transform, default_init_mode = ( 

343 cls._has_dataclass_transform_metaclasses() 

344 ) 

345 

346 # Attributes on the decorated class and its base classes are not 

347 # considered to be fields. 

348 if is_dataclass_transform: 

349 continue 

350 

351 # All inherited classes behave like dataclass semantics 

352 if ( 

353 is_dataclass_transform 

354 and isinstance(cls, ClassValue) 

355 and ( 

356 cls.init_param_mode() 

357 or (cls.init_param_mode() is None and default_init_mode) 

358 ) 

359 ): 

360 param_names.extend( 

361 get_dataclass_param_names(cls) 

362 ) 

363 

364 if is_dataclass_transform: 

365 return [DataclassSignature(cls, param_names)] 

366 else: 

367 return [] 

368 

369 def get_signatures(self): 

370 # Since calling staticmethod without a function is illegal, the Jedi 

371 # plugin doesn't return anything. Therefore call directly and get what 

372 # we want: An instance of staticmethod. 

373 metaclasses = self.get_metaclasses() 

374 if metaclasses: 

375 sigs = self.get_metaclass_signatures(metaclasses) 

376 if sigs: 

377 return sigs 

378 args = ValuesArguments([]) 

379 instance = self.py__call__(args) 

380 init_funcs = init_or_new_func(instance) 

381 

382 dataclass_sigs = self._get_dataclass_transform_signatures() 

383 if dataclass_sigs: 

384 return dataclass_sigs 

385 else: 

386 return [sig.bind(self) for sig in init_funcs.get_signatures()] 

387 

388 def _as_context(self): 

389 return ClassContext(self) 

390 

391 def get_type_hint(self, add_class_info=True): 

392 if add_class_info: 

393 return 'Type[%s]' % self.py__name__() 

394 return self.py__name__() 

395 

396 @inference_state_method_cache(default=False) 

397 def is_typeddict(self): 

398 # TODO Do a proper mro resolution. Currently we are just listing 

399 # classes. However, it's a complicated algorithm. 

400 from jedi.inference.gradual.typing import TypedDictClass 

401 for lazy_cls in self.py__bases__(): 

402 if not isinstance(lazy_cls, LazyTreeValue): 

403 return False 

404 tree_node = lazy_cls.data 

405 # Only resolve simple classes, stuff like Iterable[str] are more 

406 # intensive to resolve and if generics are involved, we know it's 

407 # not a TypedDict. 

408 if not expr_is_dotted(tree_node): 

409 return False 

410 

411 for cls in lazy_cls.infer(): 

412 if isinstance(cls, TypedDictClass): 

413 return True 

414 try: 

415 method = cls.is_typeddict 

416 except AttributeError: 

417 # We're only dealing with simple classes, so just returning 

418 # here should be fine. This only happens with e.g. compiled 

419 # classes. 

420 return False 

421 else: 

422 if method(): 

423 return True 

424 return False 

425 

426 def py__getitem__(self, index_value_set, contextualized_node): 

427 from jedi.inference.gradual.base import GenericClass 

428 if not index_value_set: 

429 debug.warning('Class indexes inferred to nothing. Returning class instead') 

430 return ValueSet([self]) 

431 return ValueSet( 

432 GenericClass( 

433 self, 

434 LazyGenericManager( 

435 context_of_index=contextualized_node.context, 

436 index_value=index_value, 

437 ) 

438 ) 

439 for index_value in index_value_set 

440 ) 

441 

442 def with_generics(self, generics_tuple): 

443 from jedi.inference.gradual.base import GenericClass 

444 return GenericClass( 

445 self, 

446 TupleGenericManager(generics_tuple) 

447 ) 

448 

449 def define_generics(self, type_var_dict): 

450 from jedi.inference.gradual.base import GenericClass 

451 

452 def remap_type_vars(): 

453 """ 

454 The TypeVars in the resulting classes have sometimes different names 

455 and we need to check for that, e.g. a signature can be: 

456 

457 def iter(iterable: Iterable[_T]) -> Iterator[_T]: ... 

458 

459 However, the iterator is defined as Iterator[_T_co], which means it has 

460 a different type var name. 

461 """ 

462 for type_var in self.list_type_vars(): 

463 yield type_var_dict.get(type_var.py__name__(), NO_VALUES) 

464 

465 if type_var_dict: 

466 return ValueSet([GenericClass( 

467 self, 

468 TupleGenericManager(tuple(remap_type_vars())) 

469 )]) 

470 return ValueSet({self}) 

471 

472 

473def init_or_new_func(value): 

474 init_funcs = value.py__getattribute__('__init__') 

475 if len(init_funcs) == 1: 

476 init = next(iter(init_funcs)) 

477 try: 

478 class_context = init.class_context 

479 except AttributeError: 

480 pass 

481 else: 

482 # In the case where we are on object.__init__, we try to use 

483 # __new__. 

484 if class_context.get_root_context().is_builtins_module() \ 

485 and init.class_context.name.string_name == "object": 

486 return value.py__getattribute__('__new__') 

487 return init_funcs 

488 

489 

490class DataclassParamName(BaseTreeParamName): 

491 """ 

492 Represent a field declaration on a class with dataclass semantics. 

493 """ 

494 

495 def __init__(self, parent_context, tree_name, annotation_node, default_node): 

496 super().__init__(parent_context, tree_name) 

497 self.annotation_node = annotation_node 

498 self.default_node = default_node 

499 

500 def get_kind(self): 

501 return Parameter.POSITIONAL_OR_KEYWORD 

502 

503 def infer(self): 

504 if self.annotation_node is None: 

505 return NO_VALUES 

506 else: 

507 return self.parent_context.infer_node(self.annotation_node) 

508 

509 

510class DataclassSignature(AbstractSignature): 

511 """ 

512 It represents the ``__init__`` signature of a class with dataclass semantics. 

513 

514 .. code:: python 

515 

516 """ 

517 def __init__(self, value, param_names): 

518 super().__init__(value) 

519 self._param_names = param_names 

520 

521 def get_param_names(self, resolve_stars=False): 

522 return self._param_names 

523 

524 

525class DataclassDecorator(ValueWrapper, FunctionMixin): 

526 """ 

527 A dataclass(-like) decorator with custom parameters. 

528 

529 .. code:: python 

530 

531 @dataclass(init=True) # this 

532 class A: ... 

533 

534 @dataclass_transform 

535 def create_model(*, init=False): pass 

536 

537 @create_model(init=False) # or this 

538 class B: ... 

539 """ 

540 

541 def __init__(self, function, arguments, default_init: bool = True): 

542 """ 

543 Args: 

544 function: Decoratee | function 

545 arguments: The parameters to the dataclass function decorator 

546 default_init: Boolean to indicate the default init value 

547 """ 

548 super().__init__(function) 

549 argument_init = self._init_param_value(arguments) 

550 self.init_param_mode = ( 

551 argument_init if argument_init is not None else default_init 

552 ) 

553 

554 def _init_param_value(self, arguments) -> Optional[bool]: 

555 if not arguments.argument_node: 

556 return None 

557 

558 arg_nodes = ( 

559 arguments.argument_node.children 

560 if arguments.argument_node.type == "arglist" 

561 else [arguments.argument_node] 

562 ) 

563 

564 return init_param_value(arg_nodes) 

565 

566 

567class DataclassTransformer(ValueWrapper, ClassMixin): 

568 """ 

569 A class decorated with the ``dataclass_transform`` decorator. dataclass-like 

570 semantics will be assumed for any class that directly or indirectly derives 

571 from the decorated class or uses the decorated class as a metaclass. 

572 Attributes on the decorated class and its base classes are not considered to 

573 be fields. 

574 """ 

575 def __init__(self, wrapped_value): 

576 super().__init__(wrapped_value) 

577 

578 def init_mode_from_new(self) -> bool: 

579 """Default value if missing is ``True``""" 

580 new_methods = self._wrapped_value.py__getattribute__("__new__") 

581 

582 if not new_methods: 

583 return True 

584 

585 new_method = list(new_methods)[0] 

586 

587 for param in new_method.get_param_names(): 

588 if ( 

589 param.string_name == "init" 

590 and param.default_node 

591 and param.default_node.type == "keyword" 

592 ): 

593 if param.default_node.value == "False": 

594 return False 

595 elif param.default_node.value == "True": 

596 return True 

597 

598 return True 

599 

600 @property 

601 def init_mode_from_init_subclass(self) -> Optional[bool]: 

602 # def __init_subclass__(cls) -> None: ... is hardcoded in the typeshed 

603 # so the extra parameters can not be inferred. 

604 return True 

605 

606 

607class DataclassWrapper(ValueWrapper, ClassMixin): 

608 """ 

609 A class with dataclass semantics from a decorator. The init parameters are 

610 only from the current class and parent classes decorated where the ``init`` 

611 parameter was ``True``. 

612 

613 .. code:: python 

614 

615 @dataclass 

616 class A: ... # this 

617 

618 @dataclass_transform 

619 def create_model(): pass 

620 

621 @create_model() 

622 class B: ... # or this 

623 """ 

624 

625 def __init__( 

626 self, wrapped_value, should_generate_init: bool 

627 ): 

628 super().__init__(wrapped_value) 

629 self.should_generate_init = should_generate_init 

630 

631 def get_signatures(self): 

632 param_names = [] 

633 for cls in reversed(list(self.py__mro__())): 

634 if ( 

635 isinstance(cls, DataclassWrapper) 

636 and cls.should_generate_init 

637 ): 

638 param_names.extend(get_dataclass_param_names(cls)) 

639 return [DataclassSignature(cls, param_names)] 

640 

641 

642class ClassValue(ClassMixin, FunctionAndClassBase, metaclass=CachedMetaClass): 

643 api_type = 'class' 

644 

645 @inference_state_method_cache() 

646 def list_type_vars(self): 

647 found = [] 

648 arglist = self.tree_node.get_super_arglist() 

649 if arglist is None: 

650 return [] 

651 

652 for stars, node in unpack_arglist(arglist): 

653 if stars: 

654 continue # These are not relevant for this search. 

655 

656 from jedi.inference.gradual.annotation import find_unknown_type_vars 

657 for type_var in find_unknown_type_vars(self.parent_context, node): 

658 if type_var not in found: 

659 # The order matters and it's therefore a list. 

660 found.append(type_var) 

661 return found 

662 

663 def _get_bases_arguments(self): 

664 arglist = self.tree_node.get_super_arglist() 

665 if arglist: 

666 from jedi.inference import arguments 

667 return arguments.TreeArguments(self.inference_state, self.parent_context, arglist) 

668 return None 

669 

670 @inference_state_method_cache(default=()) 

671 def py__bases__(self): 

672 args = self._get_bases_arguments() 

673 if args is not None: 

674 lst = [value for key, value in args.unpack() if key is None] 

675 if lst: 

676 return lst 

677 

678 if self.py__name__() == 'object' \ 

679 and self.parent_context.is_builtins_module(): 

680 return [] 

681 return [LazyKnownValues( 

682 self.inference_state.builtins_module.py__getattribute__('object') 

683 )] 

684 

685 @plugin_manager.decorate() 

686 def get_metaclass_filters(self, metaclasses, is_instance): 

687 debug.warning('Unprocessed metaclass %s', metaclasses) 

688 return [] 

689 

690 @inference_state_method_cache(default=NO_VALUES) 

691 def get_metaclasses(self): 

692 args = self._get_bases_arguments() 

693 if args is not None: 

694 m = [value for key, value in args.unpack() if key == 'metaclass'] 

695 metaclasses = ValueSet.from_sets(lazy_value.infer() for lazy_value in m) 

696 metaclasses = ValueSet(m for m in metaclasses if m.is_class()) 

697 if metaclasses: 

698 return metaclasses 

699 

700 for lazy_base in self.py__bases__(): 

701 for value in lazy_base.infer(): 

702 if value.is_class(): 

703 values = value.get_metaclasses() 

704 if values: 

705 return values 

706 return NO_VALUES 

707 

708 def init_param_mode(self) -> Optional[bool]: 

709 """ 

710 It returns ``True`` if ``class X(init=False):`` else ``False``. 

711 """ 

712 bases_arguments = self._get_bases_arguments() 

713 

714 if bases_arguments is None: 

715 return None 

716 

717 if bases_arguments.argument_node.type != "arglist": 

718 # If it is not inheriting from the base model and having 

719 # extra parameters, then init behavior is not changed. 

720 return None 

721 

722 return init_param_value(bases_arguments.argument_node.children) 

723 

724 @plugin_manager.decorate() 

725 def get_metaclass_signatures(self, metaclasses): 

726 return []