bpo-36743: __get__ is sometimes called without the owner argument (GH-12992) (GH-15589)

(cherry picked from commit 0dac68f1e5)

Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot) 2019-08-29 02:02:51 -07:00 committed by Raymond Hettinger
parent 0d45d50e42
commit c71ae1a45b
5 changed files with 24 additions and 13 deletions

View File

@ -1618,21 +1618,32 @@ refers to the attribute whose name is the key of the property in the owner
class' :attr:`~object.__dict__`. class' :attr:`~object.__dict__`.
.. method:: object.__get__(self, instance, owner) .. method:: object.__get__(self, instance, owner=None)
Called to get the attribute of the owner class (class attribute access) or of an Called to get the attribute of the owner class (class attribute access) or
instance of that class (instance attribute access). *owner* is always the owner of an instance of that class (instance attribute access). The optional
class, while *instance* is the instance that the attribute was accessed through, *owner* argument is the owner class, while *instance* is the instance that
or ``None`` when the attribute is accessed through the *owner*. This method the attribute was accessed through, or ``None`` when the attribute is
should return the (computed) attribute value or raise an :exc:`AttributeError` accessed through the *owner*.
exception.
This method should return the computed attribute value or raise an
:exc:`AttributeError` exception.
:PEP:`252` specifies that :meth:`__get__` is callable with one or two
arguments. Python's own built-in descriptors support this specification;
however, it is likely that some third-party tools have descriptors
that require both arguments. Python's own :meth:`__getattribute__`
implementation always passes in both arguments whether they are required
or not.
.. method:: object.__set__(self, instance, value) .. method:: object.__set__(self, instance, value)
Called to set the attribute on an instance *instance* of the owner class to a Called to set the attribute on an instance *instance* of the owner class to a
new value, *value*. new value, *value*.
Note, adding :meth:`__set__` or :meth:`__delete__` changes the kind of
descriptor to a "data descriptor". See :ref:`descriptor-invocation` for
more details.
.. method:: object.__delete__(self, instance) .. method:: object.__delete__(self, instance)

View File

@ -281,7 +281,7 @@ except AttributeError:
class DocDescriptor: class DocDescriptor:
"""Helper for builtins.open.__doc__ """Helper for builtins.open.__doc__
""" """
def __get__(self, obj, typ): def __get__(self, obj, typ=None):
return ( return (
"open(file, mode='r', buffering=-1, encoding=None, " "open(file, mode='r', buffering=-1, encoding=None, "
"errors=None, newline=None, closefd=True)\n\n" + "errors=None, newline=None, closefd=True)\n\n" +

View File

@ -400,7 +400,7 @@ class partialmethod(object):
_method._partialmethod = self _method._partialmethod = self
return _method return _method
def __get__(self, obj, cls): def __get__(self, obj, cls=None):
get = getattr(self.func, "__get__", None) get = getattr(self.func, "__get__", None)
result = None result = None
if get is not None: if get is not None:
@ -905,7 +905,7 @@ class singledispatchmethod:
""" """
return self.dispatcher.register(cls, func=method) return self.dispatcher.register(cls, func=method)
def __get__(self, obj, cls): def __get__(self, obj, cls=None):
def _method(*args, **kwargs): def _method(*args, **kwargs):
method = self.dispatcher.dispatch(args[0].__class__) method = self.dispatcher.dispatch(args[0].__class__)
return method.__get__(obj, cls)(*args, **kwargs) return method.__get__(obj, cls)(*args, **kwargs)
@ -943,7 +943,7 @@ class cached_property:
f"({self.attrname!r} and {name!r})." f"({self.attrname!r} and {name!r})."
) )
def __get__(self, instance, owner): def __get__(self, instance, owner=None):
if instance is None: if instance is None:
return self return self
if self.attrname is None: if self.attrname is None:

View File

@ -2806,7 +2806,7 @@ class PropertyMock(Mock):
def _get_child_mock(self, /, **kwargs): def _get_child_mock(self, /, **kwargs):
return MagicMock(**kwargs) return MagicMock(**kwargs)
def __get__(self, obj, obj_type): def __get__(self, obj, obj_type=None):
return self() return self()
def __set__(self, obj, val): def __set__(self, obj, val):
self(val) self(val)

View File

@ -78,7 +78,7 @@ class EiffelDescriptor:
self.__name__ = func.__name__ self.__name__ = func.__name__
self.__doc__ = func.__doc__ self.__doc__ = func.__doc__
def __get__(self, obj, cls): def __get__(self, obj, cls=None):
return EiffelMethodWrapper(obj, self) return EiffelMethodWrapper(obj, self)
def callmethod(self, inst, args, kwargs): def callmethod(self, inst, args, kwargs):