Commit fe98838c authored by da-woods's avatar da-woods Committed by GitHub

Mark reverse operators with METHOD_COEXIST (GH-4753)

This means that reverse operators (e.g. `__radd__`) won't be
hidden by the automatic wrapper that `PyType_Ready()` produces if
the forward method exists. Although they won't work as
in Python, they will be possible to look up and call explicitly.
This should make it easier to write code that's compatible with
Cython 0.29.x and Cython 3 (where reverse operators will be full supported).

Closes https://github.com/cython/cython/issues/4750
parent 4060346c
......@@ -2233,8 +2233,8 @@ class CCodeWriter(object):
method_flags = entry.signature.method_flags()
if not method_flags:
return
if entry.is_special:
from . import TypeSlots
from . import TypeSlots
if entry.is_special or TypeSlots.is_reverse_number_slot(entry.name):
method_flags += [TypeSlots.method_coexist]
func_ptr = wrapper_code_writer.put_pymethoddef_wrapper(entry) if wrapper_code_writer else entry.func_cname
# Add required casts, but try not to shadow real warnings.
......
......@@ -625,6 +625,20 @@ def get_slot_code_by_name(scope, slot_name):
slot = get_slot_by_name(slot_name)
return slot.slot_code(scope)
def is_reverse_number_slot(name):
"""
Tries to identify __radd__ and friends (so the METH_COEXIST flag can be applied).
There's no great consequence if it inadvertently identifies a few other methods
so just use a simple rule rather than an exact list.
"""
if name.startswith("__r") and name.endswith("__"):
forward_name = name.replace("r", "", 1)
for meth in PyNumberMethods:
if getattr(meth, "method_name", None) == forward_name:
return True
return False
#------------------------------------------------------------------------------------------
#
......
......@@ -923,3 +923,27 @@ cdef class VerySpecialSubType(VerySpecial):
def __get__(self, inst, own):
return VerySpecial.__get__(self, inst, own)
cdef class ReverseMethodsExist:
"""
reverse methods (such as __radd__) don't work in Cython <3. However, if they
are defined then it should be possible to look them up explicitly instead of
looking up autogenerated wrapper (which points to the forward method)
>>> o = ReverseMethodsExist()
>>> o + o
'add'
>>> o.__add__(o)
'add'
>>> o.__radd__(o)
'radd'
>>> o.__rsub__(o)
'rsub'
"""
def __add__(self, other):
return "add"
def __radd__(self, other):
return "radd"
def __rsub__(self, other):
return "rsub"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment