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

Function generate_setattr_wrapper

mypyc/irbuild/function.py:427–475  ·  view source on GitHub ↗

Generate a wrapper function for __setattr__ that can be put into the tp_setattro slot. The wrapper takes two arguments besides self - attribute name and the new value. Returns 0 on success and -1 on failure. Restrictions are similar to the __getattr__ wrapper above. The wrapper

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

Source from the content-addressed store, hash-verified

425
426
427def generate_setattr_wrapper(builder: IRBuilder, cdef: ClassDef, setattr: FuncDef) -> None:
428 """
429 Generate a wrapper function for __setattr__ that can be put into the tp_setattro slot.
430 The wrapper takes two arguments besides self - attribute name and the new value.
431 Returns 0 on success and -1 on failure. Restrictions are similar to the __getattr__
432 wrapper above.
433
434 The wrapper calls the user-defined __setattr__ when the value to set is not NULL.
435 When it's NULL, this means that the call to tp_setattro comes from a del statement,
436 so it calls __delattr__ instead. If __delattr__ is not overridden in the native class,
437 this will call the base implementation in object which doesn't work without __dict__.
438 """
439 name = setattr.name + "__wrapper"
440 ir = builder.mapper.type_to_ir[cdef.info]
441 line = setattr.line
442
443 error_base = f'"__setattr__" not supported in class "{cdef.name}" because '
444 if ir.allow_interpreted_subclasses:
445 builder.error(error_base + "it allows interpreted subclasses", line)
446 if ir.inherits_python:
447 builder.error(error_base + "it inherits from a non-native class", line)
448
449 with builder.enter_method(ir, name, c_int_rprimitive, internal=True):
450 attr_arg = builder.add_argument("attr", object_rprimitive)
451 value_arg = builder.add_argument("value", object_rprimitive)
452
453 call_delattr, call_setattr = BasicBlock(), BasicBlock()
454 null = Integer(0, object_rprimitive, line)
455 is_delattr = builder.add(ComparisonOp(value_arg, null, ComparisonOp.EQ, line))
456 builder.add_bool_branch(is_delattr, call_delattr, call_setattr)
457
458 builder.activate_block(call_delattr)
459 delattr_symbol = cdef.info.get("__delattr__")
460 delattr = delattr_symbol.node if delattr_symbol else None
461 delattr_override = delattr is not None and not delattr.fullname.startswith("builtins.")
462 if delattr_override:
463 builder.gen_method_call(builder.self(), "__delattr__", [attr_arg], None, line)
464 else:
465 # Call internal function that cpython normally calls when deleting an attribute.
466 # Cannot call object.__delattr__ here because it calls PyObject_SetAttr internally
467 # which in turn calls our wrapper and recurses infinitely.
468 # Note that since native classes don't have __dict__, this will raise AttributeError
469 # for dynamic attributes.
470 builder.call_c(generic_setattr, [builder.self(), attr_arg, null], line)
471 builder.add(Return(Integer(0, c_int_rprimitive), line))
472
473 builder.activate_block(call_setattr)
474 builder.gen_method_call(builder.self(), setattr.name, [attr_arg, value_arg], None, line)
475 builder.add(Return(Integer(0, c_int_rprimitive), line))
476
477
478def handle_ext_method(builder: IRBuilder, cdef: ClassDef, fdef: FuncDef) -> None:

Callers 1

handle_ext_methodFunction · 0.85

Calls 15

BasicBlockClass · 0.90
IntegerClass · 0.90
ComparisonOpClass · 0.90
ReturnClass · 0.90
add_argumentMethod · 0.80
errorMethod · 0.45
enter_methodMethod · 0.45
addMethod · 0.45
add_bool_branchMethod · 0.45
activate_blockMethod · 0.45
getMethod · 0.45
startswithMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…