MCPcopy Index your code
hub / github.com/python/mypy / generate_getattr_wrapper

Function generate_getattr_wrapper

mypyc/irbuild/function.py:377–424  ·  view source on GitHub ↗

Generate a wrapper function for __getattr__ that can be put into the tp_getattro slot. The wrapper takes one argument besides self which is the attribute name. It first checks if the name matches any of the attributes of this class. If it does, it returns that attribute. If none mat

(builder: IRBuilder, cdef: ClassDef, getattr: FuncDef)

Source from the content-addressed store, hash-verified

375
376
377def generate_getattr_wrapper(builder: IRBuilder, cdef: ClassDef, getattr: FuncDef) -> None:
378 """
379 Generate a wrapper function for __getattr__ that can be put into the tp_getattro slot.
380 The wrapper takes one argument besides self which is the attribute name.
381 It first checks if the name matches any of the attributes of this class.
382 If it does, it returns that attribute. If none match, it calls __getattr__.
383
384 __getattr__ is not supported in classes that allow interpreted subclasses because the
385 tp_getattro slot is inherited by subclasses and if the subclass overrides __getattr__,
386 the override would be ignored in our wrapper. TODO: To support this, the wrapper would
387 have to check type of self and if it's not the compiled class, resolve "__getattr__" against
388 the type at runtime and call the returned method, like _Py_slot_tp_getattr_hook in cpython.
389
390 __getattr__ is not supported in classes which inherit from non-native classes because those
391 have __dict__ which currently has some strange interactions when class attributes and
392 variables are assigned through __dict__ vs. through regular attribute access. Allowing
393 __getattr__ on top of that could be problematic.
394 """
395 name = getattr.name + "__wrapper"
396 ir = builder.mapper.type_to_ir[cdef.info]
397 line = getattr.line
398
399 error_base = f'"__getattr__" not supported in class "{cdef.name}" because '
400 if ir.allow_interpreted_subclasses:
401 builder.error(error_base + "it allows interpreted subclasses", line)
402 if ir.inherits_python:
403 builder.error(error_base + "it inherits from a non-native class", line)
404
405 with builder.enter_method(ir, name, object_rprimitive, internal=True):
406 attr_arg = builder.add_argument("attr", object_rprimitive)
407 generic_getattr_result = builder.call_c(generic_getattr, [builder.self(), attr_arg], line)
408
409 return_generic, call_getattr = BasicBlock(), BasicBlock()
410 null = Integer(0, object_rprimitive, line)
411 got_generic = builder.add(
412 ComparisonOp(generic_getattr_result, null, ComparisonOp.NEQ, line)
413 )
414 builder.add_bool_branch(got_generic, return_generic, call_getattr)
415
416 builder.activate_block(return_generic)
417 builder.add(Return(generic_getattr_result, line))
418
419 builder.activate_block(call_getattr)
420 # No attribute matched so call user-provided __getattr__.
421 getattr_result = builder.gen_method_call(
422 builder.self(), getattr.name, [attr_arg], object_rprimitive, line
423 )
424 builder.add(Return(getattr_result, line))
425
426
427def generate_setattr_wrapper(builder: IRBuilder, cdef: ClassDef, setattr: FuncDef) -> None:

Callers 1

handle_ext_methodFunction · 0.85

Calls 13

BasicBlockClass · 0.90
IntegerClass · 0.90
ComparisonOpClass · 0.90
ReturnClass · 0.90
add_argumentMethod · 0.80
errorMethod · 0.45
enter_methodMethod · 0.45
call_cMethod · 0.45
selfMethod · 0.45
addMethod · 0.45
add_bool_branchMethod · 0.45
activate_blockMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…