]> granicus.if.org Git - python/commitdiff
bpo-36743: __get__ is sometimes called without the owner argument (GH-12992) (GH...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 29 Aug 2019 09:02:51 +0000 (02:02 -0700)
committerRaymond Hettinger <rhettinger@users.noreply.github.com>
Thu, 29 Aug 2019 09:02:51 +0000 (02:02 -0700)
(cherry picked from commit 0dac68f1e593c11612ed54af9edb865d398f3b05)

Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com>
Doc/reference/datamodel.rst
Lib/_pyio.py
Lib/functools.py
Lib/unittest/mock.py
Tools/demo/eiffel.py

index d1702ccb6417676e815530f70f3748066e1204a9..8813f57587f01ad12477c8c0964ce9a8aa529a77 100644 (file)
@@ -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)
 
index 650109295fe8e3c9bac53e7ecc16f8e477f8b942..eb4e6620fc65f58c94251b3096547c031981721d 100644 (file)
@@ -281,7 +281,7 @@ except AttributeError:
 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" +
index 64d120182bb07ab33cc95f4744160b5aa431c437..a674a685df6596fee52353f819a26f549a356023 100644 (file)
@@ -400,7 +400,7 @@ class partialmethod(object):
         _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:
@@ -905,7 +905,7 @@ class singledispatchmethod:
         """
         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)
@@ -943,7 +943,7 @@ class cached_property:
                 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:
index 7ab68125918d54546a3a8016c87c24e64eeb081a..4c76f53f3870c09c2b28986a22fb5a9e8b8e48fe 100644 (file)
@@ -2806,7 +2806,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)
index 736abea81738c8fc9b49be8c05d2a6b3340ebdb5..a76c2324dd6a671d615c1d9bf6238b89e4c150ce 100755 (executable)
@@ -78,7 +78,7 @@ class EiffelDescriptor:
         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):