`inspect.ismethoddescriptor()` checks for the lack of `__set__`, but ignores `__delete__`. Should it be fixed?

The inspect.ismethoddescriptor() function reports descriptor objects which implement __delete__() but not __set__() as method descriptors (though they are, in fact, data descriptors):

>>> class D1:
...     def __get__(*_): print('get')
...     
>>> class D2:
...     def __get__(*_): print('get')
...     def __set__(*_): print('set')
...     
>>> class D3:
...     def __get__(*_): print('get')
...     def __delete__(*_): print('delete')
...
>>> inspect.ismethoddescriptor(D1())
True
>>> inspect.ismethoddescriptor(D2())
False
>>> inspect.ismethoddescriptor(D3())  # Note this!
True
>>> class Owner:
...     d1 = D1()
...     d2 = D2()
...     d3 = D3()
...     
>>> o.__dict__['d1'] = 42
>>> o.d1
42
>>> o.__dict__['d2'] = 42
>>> o.d2
get
>>> o.d2 = ...
set
>>> o.__dict__['d3'] = 42
>>> o.d2  # Note this!
get
>>> del o.d2  # Note this!
delete

On the other hand, this function works that way for a long time (probably, since the beginning of its existence), and its docs are consistent with its behavior (mentioning only __get__() and __set__(), but not __delete__()) – though, unfortunately, not explicit about ignoring __delete__().

I’d be happy to create an issue + PR with a fix! My question is what action would be most appropriate… In particular whether I should:

  • (1) fix the code + the docs – so that the presence of __delete__() will start to be checked by this function in Python 3.14?

    • (1a) …or, if we consider it a bugfix, maybe in 3.13? (thouhg it feels too intrusive for a bugfix release)
  • (2) change nothing in the code + add a warning to the docs – that the function does not work properly for descriptors with __get__() and __delete__() that do not have __set__()? (i.e., that they are erroneously considered method descriptors, even though they are in fact data descriptors)

  • (3) same as (2) + add a new function which will work correctly, i.e., will not ignore the presence of __delete__()?

Please note that the “sibling” function inspect.isdatadescriptor() works correctly (i.e., it takes into consideration both __set__() and __delete__()):

>>> inspect.isdatadescriptor(D1())
False
>>> inspect.isdatadescriptor(D2())
True
>>> inspect.isdatadescriptor(D3())
True

See also Contradiction in definition of "data descriptor" between (dotted lookup behavior/datamodel documentation) and (inspect lib/descriptor how-to) · Issue #70291 · python/cpython · GitHub.

The definition data descriptors and the implementation of isdatadescriptor() was updated, but for method descriptors it was not.

@storchaka Thank you for your answer! Should I create an issue + PR with a fix? (I’d happy to do so)

I think so.

OK, I’ve created a new issue: inspect.ismethoddescriptor(): lack of __delete__() is not checked · Issue #120381 · python/cpython · GitHub

The corresponding PR will be created soon has also been created.