Skip to content

Commit

Permalink
bpo-36743: __get__ is sometimes called without the owner argument (py…
Browse files Browse the repository at this point in the history
  • Loading branch information
rhettinger authored Aug 29, 2019
1 parent 84125fe commit 0dac68f
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 13 deletions.
25 changes: 18 additions & 7 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1618,21 +1618,32 @@ refers to the attribute whose name is the key of the property in the owner
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
instance of that class (instance attribute access). *owner* is always the owner
class, while *instance* is the instance that the attribute was accessed through,
or ``None`` when the attribute is accessed through the *owner*. This method
should return the (computed) attribute value or raise an :exc:`AttributeError`
exception.
Called to get the attribute of the owner class (class attribute access) or
of an instance of that class (instance attribute access). The optional
*owner* argument is the owner class, while *instance* is the instance that
the attribute was accessed through, or ``None`` when the attribute is
accessed through the *owner*.

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)

Called to set the attribute on an instance *instance* of the owner class to a
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)

Expand Down
2 changes: 1 addition & 1 deletion Lib/_pyio.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def _open_code_with_warning(path):
class DocDescriptor:
"""Helper for builtins.open.__doc__
"""
def __get__(self, obj, typ):
def __get__(self, obj, typ=None):
return (
"open(file, mode='r', buffering=-1, encoding=None, "
"errors=None, newline=None, closefd=True)\n\n" +
Expand Down
6 changes: 3 additions & 3 deletions Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ def _method(cls_or_self, /, *args, **keywords):
_method._partialmethod = self
return _method

def __get__(self, obj, cls):
def __get__(self, obj, cls=None):
get = getattr(self.func, "__get__", None)
result = None
if get is not None:
Expand Down Expand Up @@ -888,7 +888,7 @@ def register(self, cls, method=None):
"""
return self.dispatcher.register(cls, func=method)

def __get__(self, obj, cls):
def __get__(self, obj, cls=None):
def _method(*args, **kwargs):
method = self.dispatcher.dispatch(args[0].__class__)
return method.__get__(obj, cls)(*args, **kwargs)
Expand Down Expand Up @@ -926,7 +926,7 @@ def __set_name__(self, owner, name):
f"({self.attrname!r} and {name!r})."
)

def __get__(self, instance, owner):
def __get__(self, instance, owner=None):
if instance is None:
return self
if self.attrname is None:
Expand Down
2 changes: 1 addition & 1 deletion Lib/unittest/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -2804,7 +2804,7 @@ class PropertyMock(Mock):
def _get_child_mock(self, /, **kwargs):
return MagicMock(**kwargs)

def __get__(self, obj, obj_type):
def __get__(self, obj, obj_type=None):
return self()
def __set__(self, obj, val):
self(val)
Expand Down
2 changes: 1 addition & 1 deletion Tools/demo/eiffel.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def __init__(self, func, pre, post):
self.__name__ = func.__name__
self.__doc__ = func.__doc__

def __get__(self, obj, cls):
def __get__(self, obj, cls=None):
return EiffelMethodWrapper(obj, self)

def callmethod(self, inst, args, kwargs):
Expand Down

0 comments on commit 0dac68f

Please sign in to comment.