Skip to content

Commit 5e7ce51

Browse files
committed
gh-122102: Fix/improve docs + tests of descriptor tools in inspect
1 parent 0dcbc83 commit 5e7ce51

File tree

5 files changed

+283
-71
lines changed

5 files changed

+283
-71
lines changed

Doc/library/inspect.rst

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -513,20 +513,19 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
513513
.. function:: ismethoddescriptor(object)
514514

515515
Return ``True`` if the object is a method descriptor, but not if
516-
:func:`ismethod`, :func:`isclass`, :func:`isfunction` or :func:`isbuiltin`
517-
are true.
516+
:func:`isclass`, :func:`ismethod` or :func:`isfunction` are true.
518517

519518
This, for example, is true of ``int.__add__``. An object passing this test
520519
has a :meth:`~object.__get__` method, but not a :meth:`~object.__set__`
521520
method or a :meth:`~object.__delete__` method. Beyond that, the set of
522521
attributes varies. A :attr:`~definition.__name__` attribute is usually
523522
sensible, and :attr:`!__doc__` often is.
524523

525-
Methods implemented via descriptors that also pass one of the other tests
526-
return ``False`` from the :func:`ismethoddescriptor` test, simply because the
527-
other tests promise more -- you can, e.g., count on having the
528-
:attr:`~method.__func__` attribute (etc) when an object passes
529-
:func:`ismethod`.
524+
Objects implemented as descriptors that also pass one of the other tests
525+
(:func:`isclass`, :func:`ismethod` or :func:`isfunction`) make this function
526+
return ``False``, simply because the other tests promise more -- you can,
527+
e.g., count on having the :attr:`~method.__func__` attribute (etc.) when an
528+
object passes :func:`ismethod`.
530529

531530
.. versionchanged:: 3.13
532531
This function no longer incorrectly reports objects with :meth:`~object.__get__`
@@ -536,35 +535,48 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
536535

537536
.. function:: isdatadescriptor(object)
538537

539-
Return ``True`` if the object is a data descriptor.
538+
Return ``True`` if the object is a data descriptor, but not if
539+
:func:`isclass`, :func:`ismethod` or :func:`isfunction` are true.
540540

541-
Data descriptors have a :attr:`~object.__set__` or a :attr:`~object.__delete__` method.
542-
Examples are properties (defined in Python), getsets, and members. The
543-
latter two are defined in C and there are more specific tests available for
544-
those types, which is robust across Python implementations. Typically, data
545-
descriptors will also have :attr:`~definition.__name__` and :attr:`!__doc__` attributes
546-
(properties, getsets, and members have both of these attributes), but this is
547-
not guaranteed.
541+
Data descriptors always have a :meth:`~object.__set__` method and/or
542+
a :meth:`~object.__delete__` method. Optionally, they may also have a
543+
:meth:`~object.__get__` method.
544+
545+
Examples of data descriptors include *properties* (see: :func:`property`),
546+
*getset descriptors* and *member descriptors* (for the latter two, more
547+
specific tests are available as well: :func:`isgetsetdescriptor` and
548+
:func:`ismemberdescriptor`, respectively).
549+
550+
Typically, data descriptors have also :attr:`~definition.__name__` and
551+
:attr:`!__doc__` attributes (*properties*, *getsets*, and *members* have
552+
both of them), but this is not guaranteed.
553+
554+
.. versionchanged:: 3.8
555+
Now this function reports objects with only a :meth:`~object.__set__` method
556+
as being data descriptors (the presence of :meth:`~object.__get__` is no
557+
longer required for that). Moreover, objects with :meth:`~object.__delete__`,
558+
but not :meth:`~object.__set__`, are now properly recognized as data
559+
descriptors as well (formerly, they were not).
548560

549561

550562
.. function:: isgetsetdescriptor(object)
551563

552-
Return ``True`` if the object is a getset descriptor.
564+
Return ``True`` if the object is a *getset descriptor*.
553565

554566
.. impl-detail::
555567

556-
getsets are attributes defined in extension modules via
568+
*getsets* are attributes defined in extension modules via
557569
:c:type:`PyGetSetDef` structures. For Python implementations without such
558570
types, this method will always return ``False``.
559571

560572

561573
.. function:: ismemberdescriptor(object)
562574

563-
Return ``True`` if the object is a member descriptor.
575+
Return ``True`` if the object is a *member descriptor*.
564576

565577
.. impl-detail::
566578

567-
Member descriptors are attributes defined in extension modules via
579+
*Member descriptors* are attributes defined in extension modules via
568580
:c:type:`PyMemberDef` structures. For Python implementations without such
569581
types, this method will always return ``False``.
570582

@@ -1511,11 +1523,11 @@ but avoids executing code when it fetches attributes.
15111523
.. versionadded:: 3.2
15121524

15131525
:func:`getattr_static` does not resolve descriptors, for example slot descriptors or
1514-
getset descriptors on objects implemented in C. The descriptor object
1526+
*getset* descriptors on objects implemented in C. The descriptor object
15151527
is returned instead of the underlying attribute.
15161528

15171529
You can handle these with code like the following. Note that
1518-
for arbitrary getset descriptors invoking these may trigger
1530+
for arbitrary *getset* descriptors invoking these may trigger
15191531
code execution::
15201532

15211533
# example code for resolving the builtin descriptor types

Lib/inspect.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,10 @@ def ismethoddescriptor(object):
313313
often is.
314314
315315
Methods implemented via descriptors that also pass one of the other
316-
tests return false from the ismethoddescriptor() test, simply because
317-
the other tests promise more -- you can, e.g., count on having the
318-
__func__ attribute (etc) when an object passes ismethod()."""
316+
tests (ismethod(), isclass() or isfunction()) make this function
317+
return false, simply because those other tests promise more -- you
318+
can, e.g., count on having the __func__ attribute (etc.) when an
319+
object passes ismethod()."""
319320
if isclass(object) or ismethod(object) or isfunction(object):
320321
# mutual exclusion
321322
return False
@@ -327,8 +328,13 @@ def ismethoddescriptor(object):
327328
def isdatadescriptor(object):
328329
"""Return true if the object is a data descriptor.
329330
331+
But not if ismethod() or isclass() or isfunction() are true.
332+
330333
Data descriptors have a __set__ or a __delete__ attribute. Examples are
331-
properties (defined in Python) and getsets and members (defined in C).
334+
properties, getsets and members (for the latter two, more specific tests
335+
are available as well: isgetsetdescriptor() and ismemberdescriptor(),
336+
respectively).
337+
332338
Typically, data descriptors will also have __name__ and __doc__ attributes
333339
(properties, getsets, and members have both of these attributes), but this
334340
is not guaranteed."""

0 commit comments

Comments
 (0)