]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Patch from Georg Brandl and me for #1493
authorChristian Heimes <christian@cheimes.de>
Sun, 25 Nov 2007 09:39:14 +0000 (09:39 +0000)
committerChristian Heimes <christian@cheimes.de>
Sun, 25 Nov 2007 09:39:14 +0000 (09:39 +0000)
Remove unbound method objects

19 files changed:
Lib/DocXMLRPCServer.py
Lib/inspect.py
Lib/test/inspect_fodder2.py
Lib/test/output/test_extcall
Lib/test/test_class.py
Lib/test/test_descr.py
Lib/test/test_descrtut.py
Lib/test/test_extcall.py
Lib/test/test_funcattrs.py
Lib/test/test_inspect.py
Lib/test/test_pyclbr.py
Lib/test/test_repr.py
Lib/test/test_sys.py
Lib/test/test_typechecks.py
Lib/test/test_weakref.py
Lib/types.py
Lib/unittest.py
Lib/xml/dom/minicompat.py
Objects/funcobject.c

index 111e5f602ad7e17fb07a285b0bdd7449dab25a02..08e1f10f9faa2b29f941d03c81d068800f98dd31 100644 (file)
@@ -74,7 +74,7 @@ class ServerHTMLDoc(pydoc.HTMLDoc):
         title = '<a name="%s"><strong>%s</strong></a>' % (anchor, name)
 
         if inspect.ismethod(object):
-            args, varargs, varkw, defaults = inspect.getargspec(object.im_func)
+            args, varargs, varkw, defaults = inspect.getargspec(object)
             # exclude the argument bound to the instance, it will be
             # confusing to the non-Python user
             argspec = inspect.formatargspec (
index d0608d7cd6efa8e14afa3f61e410c68bd9c40659..3a95796792fcf864b7c3d8a8d9af16078f3ba6b2 100644 (file)
@@ -57,7 +57,7 @@ def ismethod(object):
         __name__        name with which this method was defined
         im_class        class object in which this method belongs
         im_func         function object containing implementation of method
-        im_self         instance to which this method is bound, or None"""
+        im_self         instance to which this method is bound"""
     return isinstance(object, types.MethodType)
 
 def ismethoddescriptor(object):
@@ -269,7 +269,7 @@ def classify_class_attrs(cls):
             kind = "class method"
         elif isinstance(obj, property):
             kind = "property"
-        elif (ismethod(obj_via_getattr) or
+        elif (isfunction(obj_via_getattr) or
               ismethoddescriptor(obj_via_getattr)):
             kind = "method"
         else:
index 7a9f84ea82ef5444f0b2b0c6157515f985335d92..d244935038a7fa2ffe452499c304a54980c7179b 100644 (file)
@@ -96,7 +96,7 @@ def f():
             "doc"
             return 42
     return X
-method_in_dynamic_class = f().g.im_func
+method_in_dynamic_class = f().g
 
 #line 101
 def keyworded(*arg1, arg2=1):
index 323fe7ac145d94c47e232656c86f61e44ab7ae49..63f5b7116addef576ae6c88fa3f4fdba84f087b8 100644 (file)
@@ -38,6 +38,8 @@ dir() got multiple values for keyword argument 'b'
 3 512 True
 3
 3
+5
+5
 za () {} -> za() takes exactly 1 positional argument (0 given)
 za () {'a': 'aa'} -> ok za aa B D E V a
 za () {'d': 'dd'} -> za() got an unexpected keyword argument 'd'
index 76b30a389807213893b8bc6fe186671256240eb3..ab44a4cb3cd3e827b36acf54621e641af2db7e5b 100644 (file)
@@ -552,7 +552,7 @@ class ClassTests(unittest.TestCase):
         self.assertEquals(hash(B.f), hash(A.f))
 
         # the following triggers a SystemError in 2.4
-        a = A(hash(A.f.im_func)^(-1))
+        a = A(hash(A.f)^(-1))
         hash(a.f)
 
 def test_main():
index 1ea93bb9ab7b4a3fca1a7a7e4ac239c0a4cdc064..e093ce8edfb689481a5a86885e2b7f8dd7d8e7bc 100644 (file)
@@ -280,12 +280,12 @@ def test_dir():
 
     c = C()
     vereq(interesting(dir(c)), cstuff)
-    verify('im_self' in dir(C.Cmethod))
+    #verify('im_self' in dir(C.Cmethod))
 
     c.cdata = 2
     c.cmethod = lambda self: 0
     vereq(interesting(dir(c)), cstuff + ['cdata', 'cmethod'])
-    verify('im_self' in dir(c.Cmethod))
+    #verify('im_self' in dir(c.Cmethod))
 
     class A(C):
         Adata = 1
@@ -293,13 +293,13 @@ def test_dir():
 
     astuff = ['Adata', 'Amethod'] + cstuff
     vereq(interesting(dir(A)), astuff)
-    verify('im_self' in dir(A.Amethod))
+    #verify('im_self' in dir(A.Amethod))
     a = A()
     vereq(interesting(dir(a)), astuff)
     a.adata = 42
     a.amethod = lambda self: 3
     vereq(interesting(dir(a)), astuff + ['adata', 'amethod'])
-    verify('im_self' in dir(a.Amethod))
+    #verify('im_self' in dir(a.Amethod))
 
     # Try a module subclass.
     import sys
@@ -1504,8 +1504,10 @@ def classic():
     vereq(D.foo(d, 1), (d, 1))
     class E: # *not* subclassing from C
         foo = C.foo
-    vereq(E().foo, C.foo) # i.e., unbound
-    verify(repr(C.foo.__get__(C())).startswith("<bound method "))
+    r = repr(E().foo)
+    verify(r.startswith("<bound method E.foo "), r)
+    r = repr(C.foo.__get__(C()))
+    verify(r.startswith("<bound method ?.foo "), r)
 
 def compattr():
     if verbose: print("Testing computed attributes...")
@@ -1685,8 +1687,9 @@ def methods():
     vereq(d2.goo(), 1)
     class E(object):
         foo = C.foo
-    vereq(E().foo, C.foo) # i.e., unbound
-    verify(repr(C.foo.__get__(C(1))).startswith("<bound method "))
+    vereq(E().foo.im_func, C.foo) # i.e., unbound
+    r = repr(C.foo.__get__(C(1)))
+    verify(r.startswith("<bound method "), r)
 
 def specials():
     # Test operators like __hash__ for which a built-in default exists
index ea75366321adb76b7d33d5895d225f518d44ca1b..5ce2119f6818a6e4db05b14213636e1c5eb31f31 100644 (file)
@@ -444,9 +444,7 @@ Backwards incompatibilities
 ...         B.foo(self)
 
 >>> C().foo()
-Traceback (most recent call last):
- ...
-TypeError: unbound method foo() must be called with B instance as first argument (got C instance instead)
+called A.foo()
 
 >>> class C(A):
 ...     def foo(self):
index 56a207af59e8b9ee865fd04e6f5e450da744b483..611f4ab1e258ebaff2968bbed99a8beebc3ee0e2 100644 (file)
@@ -231,18 +231,8 @@ class Foo:
 x = Foo()
 print(Foo.method(*(x, 1, 2)))
 print(Foo.method(x, *(1, 2)))
-try:
-    print(Foo.method(*(1, 2, 3)))
-except TypeError as err:
-    pass
-else:
-    print('expected a TypeError for unbound method call')
-try:
-    print(Foo.method(1, *(2, 3)))
-except TypeError as err:
-    pass
-else:
-    print('expected a TypeError for unbound method call')
+print(Foo.method(*(1, 2, 3)))
+print(Foo.method(1, *(2, 3)))
 
 # A PyCFunction that takes only positional parameters should allow an
 # empty keyword dictionary to pass without a complaint, but raise a
index 66ba9cb999743ee4da44de0137e8582e5a02e3f5..bd9caffd6f0f7c106f858eea217e8fff5aa6cedd 100644 (file)
@@ -67,13 +67,8 @@ else: raise TestFailed('expected AttributeError')
 
 # In Python 2.1 beta 1, we disallowed setting attributes on unbound methods
 # (it was already disallowed on bound methods).  See the PEP for details.
-try:
-    F.a.publish = 1
-except (AttributeError, TypeError): pass
-else: raise TestFailed('expected AttributeError or TypeError')
-
-# But setting it explicitly on the underlying function object is okay.
-F.a.im_func.publish = 1
+# In Python 3.0 unbound methods are gone.
+F.a.publish = 1
 
 if F.a.publish != 1:
     raise TestFailed('unbound method attribute not set to expected value')
@@ -92,30 +87,8 @@ try:
 except (AttributeError, TypeError): pass
 else: raise TestFailed('expected AttributeError or TypeError')
 
-# See the comment above about the change in semantics for Python 2.1b1
-try:
-    F.a.myclass = F
-except (AttributeError, TypeError): pass
-else: raise TestFailed('expected AttributeError or TypeError')
-
-F.a.im_func.myclass = F
-
-f1.a.myclass
-f2.a.myclass
-f1.a.myclass
-F.a.myclass
-
-if f1.a.myclass is not f2.a.myclass or \
-       f1.a.myclass is not F.a.myclass:
-    raise TestFailed('attributes were not the same')
-
 # try setting __dict__
-try:
-    F.a.__dict__ = (1, 2, 3)
-except (AttributeError, TypeError): pass
-else: raise TestFailed('expected TypeError or AttributeError')
-
-F.a.im_func.__dict__ = {'one': 11, 'two': 22, 'three': 33}
+F.a.__dict__ = {'one': 11, 'two': 22, 'three': 33}
 
 if f1.a.two != 22:
     raise TestFailed('setting __dict__')
@@ -315,9 +288,9 @@ def test_func_dict():
 def test_im_class():
     class C:
         def foo(self): pass
-    verify(C.foo.im_class is C)
+    #verify(C.foo.im_class is C)
     verify(C().foo.im_class is C)
-    cantset(C.foo, "im_class", C)
+    #cantset(C.foo, "im_class", C)
     cantset(C().foo, "im_class", C)
 
 def test_im_func():
@@ -325,19 +298,19 @@ def test_im_func():
     class C:
         pass
     C.foo = foo
-    verify(C.foo.im_func is foo)
+    #verify(C.foo.im_func is foo)
     verify(C().foo.im_func is foo)
-    cantset(C.foo, "im_func", foo)
+    #cantset(C.foo, "im_func", foo)
     cantset(C().foo, "im_func", foo)
 
 def test_im_self():
     class C:
         def foo(self): pass
-    verify(C.foo.im_self is None)
+    #verify(C.foo.im_self is None)
     c = C()
-    verify(c.foo.im_self is c)
-    cantset(C.foo, "im_self", None)
-    cantset(c.foo, "im_self", c)
+    #verify(c.foo.im_self is c)
+    #cantset(C.foo, "im_self", None)
+    #cantset(c.foo, "im_self", c)
 
 def test_im_dict():
     class C:
@@ -345,24 +318,24 @@ def test_im_dict():
         foo.bar = 42
     verify(C.foo.__dict__ == {'bar': 42})
     verify(C().foo.__dict__ == {'bar': 42})
-    cantset(C.foo, "__dict__", C.foo.__dict__)
-    cantset(C().foo, "__dict__", C.foo.__dict__)
+    #cantset(C.foo, "__dict__", C.foo.__dict__)
+    #cantset(C().foo, "__dict__", C.foo.__dict__)
 
 def test_im_doc():
     class C:
         def foo(self): "hello"
     verify(C.foo.__doc__ == "hello")
     verify(C().foo.__doc__ == "hello")
-    cantset(C.foo, "__doc__", "hello")
-    cantset(C().foo, "__doc__", "hello")
+    #cantset(C.foo, "__doc__", "hello")
+    #cantset(C().foo, "__doc__", "hello")
 
 def test_im_name():
     class C:
         def foo(self): pass
     verify(C.foo.__name__ == "foo")
     verify(C().foo.__name__ == "foo")
-    cantset(C.foo, "__name__", "foo")
-    cantset(C().foo, "__name__", "foo")
+    #cantset(C.foo, "__name__", "foo")
+    #cantset(C().foo, "__name__", "foo")
 
 def testmore():
     test_func_closure()
index 1858372b44b10f8beeae0bd4613530c9fbeec96c..37528105134a9b3d15c06fa9079e68fdf5c5cc1c 100644 (file)
@@ -65,7 +65,7 @@ class TestPredicates(IsTestBase):
         self.istest(inspect.iscode, 'mod.spam.__code__')
         self.istest(inspect.isframe, 'tb.tb_frame')
         self.istest(inspect.isfunction, 'mod.spam')
-        self.istest(inspect.ismethod, 'mod.StupidGit.abuse')
+        self.istest(inspect.isfunction, 'mod.StupidGit.abuse')
         self.istest(inspect.ismethod, 'git.argue')
         self.istest(inspect.ismodule, 'mod')
         self.istest(inspect.istraceback, 'tb')
@@ -395,7 +395,8 @@ class TestClassesAndFunctions(unittest.TestCase):
         self.assert_(('s', 'static method', A) in attrs, 'missing static method')
         self.assert_(('c', 'class method', A) in attrs, 'missing class method')
         self.assert_(('p', 'property', A) in attrs, 'missing property')
-        self.assert_(('m', 'method', A) in attrs, 'missing plain method')
+        self.assert_(('m', 'method', A) in attrs,
+            'missing plain method: %r' % attrs)
         self.assert_(('m1', 'method', A) in attrs, 'missing plain method')
         self.assert_(('datablob', 'data', A) in attrs, 'missing data')
 
index caccf1107f866ef65efd07abf598c3bb90afc302..bcb79880d3bdff452ac06b7f509dccf7ce7e50cd 100644 (file)
@@ -64,23 +64,17 @@ class PyclbrTest(TestCase):
 
         def ismethod(oclass, obj, name):
             classdict = oclass.__dict__
-            if isinstance(obj, FunctionType):
-                if not isinstance(classdict[name], StaticMethodType):
+            if isinstance(obj, MethodType):
+                # could be a classmethod
+                if (not isinstance(classdict[name], ClassMethodType) or
+                    obj.im_self is not oclass):
                     return False
-            else:
-                if not  isinstance(obj, MethodType):
-                    return False
-                if obj.im_self is not None:
-                    if (not isinstance(classdict[name], ClassMethodType) or
-                        obj.im_self is not oclass):
-                        return False
-                else:
-                    if not isinstance(classdict[name], FunctionType):
-                        return False
+            elif not isinstance(obj, FunctionType):
+                return False
 
             objname = obj.__name__
             if objname.startswith("__") and not objname.endswith("__"):
-                objname = "_%s%s" % (obj.im_class.__name__, objname)
+                objname = "_%s%s" % (oclass.__name__, objname)
             return objname == name
 
         # Make sure the toplevel functions and classes are the same.
@@ -154,7 +148,7 @@ class PyclbrTest(TestCase):
         # XXX: See comment in pyclbr_input.py for a test that would fail
         #      if it were not commented out.
         #
-        self.checkModule('test.pyclbr_input')
+        self.checkModule('test.pyclbr_input', ignore=['om'])
 
     def test_others(self):
         cm = self.checkModule
index 8d9e99d28ebbe79092b44025d24535bcbdd4ab49..af66e979e0c347fd5319ff3b251ad988b5e31bf9 100644 (file)
@@ -280,8 +280,8 @@ class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 ''')
         from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux
         # Unbound methods first
-        eq(repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod),
-        '<unbound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod>')
+        self.failUnless(repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod).startswith(
+        '<function amethod'))
         # Bound method next
         iqux = qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
         self.failUnless(repr(iqux.amethod).startswith(
index dfad1727e2b2efc80437c86d783509ff18649e0d..9a285c5ebf61139ebe003934f04e35c3d983c119 100644 (file)
@@ -183,7 +183,7 @@ class SysModuleTest(unittest.TestCase):
         self.assertRaises(TypeError, sys._getframe, 42, 42)
         self.assertRaises(ValueError, sys._getframe, 2000000000)
         self.assert_(
-            SysModuleTest.test_getframe.im_func.__code__ \
+            SysModuleTest.test_getframe.__code__ \
             is sys._getframe().f_code
         )
 
index 632598cc05fed8afdc02e7a21c41e2f53e2e80d8..1dcc82c18690b96077bea1a90bffbf8f8f84a545 100644 (file)
@@ -18,19 +18,13 @@ class ABC(type):
 
 
 class Integer(metaclass=ABC):
-
     __subclass__ = {int}
 
 
 class SubInt(Integer):
-
     pass
 
 
-class Evil:
-    def __instancecheck__(self, inst): return False
-
-
 class TypeChecksTest(unittest.TestCase):
 
     def testIsSubclassInternal(self):
@@ -60,12 +54,6 @@ class TypeChecksTest(unittest.TestCase):
         self.assertEqual(isinstance(SubInt(), SubInt), True)
         self.assertEqual(isinstance(42, SubInt), False)
 
-    def testInfiniteRecursionCaughtProperly(self):
-        e = Evil()
-        # This invokes isinstance() recursively, until the stack is exhausted.
-        self.assertRaises(RuntimeError, isinstance, e, Evil)
-        # XXX How to check the same situation for issubclass()?
-
 
 def test_main():
     test_support.run_unittest(TypeChecksTest)
index 1a49aea24a4e1d338bd783eda83928dd5102bf1d..922b2939d5dbdb5176fe73114c7facf9f64a9326 100644 (file)
@@ -28,9 +28,6 @@ def create_function():
 def create_bound_method():
     return C().method
 
-def create_unbound_method():
-    return C.method
-
 
 class TestBase(unittest.TestCase):
 
@@ -47,7 +44,6 @@ class ReferencesTestCase(TestBase):
         self.check_basic_ref(C)
         self.check_basic_ref(create_function)
         self.check_basic_ref(create_bound_method)
-        self.check_basic_ref(create_unbound_method)
 
         # Just make sure the tp_repr handler doesn't raise an exception.
         # Live reference:
@@ -62,7 +58,6 @@ class ReferencesTestCase(TestBase):
         self.check_basic_callback(C)
         self.check_basic_callback(create_function)
         self.check_basic_callback(create_bound_method)
-        self.check_basic_callback(create_unbound_method)
 
     def test_multiple_callbacks(self):
         o = C()
index 5c1f2497d1dde478f541c380953f46c04b8119cf..402fa1865e83160bbe8bebb74e6a371256c09719 100644 (file)
@@ -38,7 +38,6 @@ GeneratorType = type(_g())
 class _C:
     def _m(self): pass
 ClassType = type
-UnboundMethodType = type(_C._m)         # Same as MethodType
 MethodType = type(_C()._m)
 
 BuiltinFunctionType = type(len)
index c5905583e76edabbdbb7a7e6e484d25cc279122e..c4b124be10680eca43b36353d518a122b8a9fb27 100644 (file)
@@ -559,13 +559,18 @@ class TestLoader:
             return self.loadTestsFromModule(obj)
         elif isinstance(obj, type) and issubclass(obj, TestCase):
             return self.loadTestsFromTestCase(obj)
-        elif (isinstance(obj, types.UnboundMethodType) and
+        elif (isinstance(obj, types.FunctionType) and
               isinstance(parent, type) and
               issubclass(parent, TestCase)):
-            return TestSuite([parent(obj.__name__)])
+            name = obj.__name__
+            inst = parent(name)
+            # static methods follow a different path
+            if not(isinstance(getattr(inst, name), types.FunctionType)):
+                return TestSuite([inst])
         elif isinstance(obj, TestSuite):
             return obj
-        elif hasattr(obj, '__call__'):
+
+        if hasattr(obj, '__call__'):
             test = obj()
             if isinstance(test, TestSuite):
                 return test
index c0a797eea48da9f8e5f60292c0589ccd1c8d5430..2e6cc7e34c0a0ed9e9eedd846b87cb13fc6949ba 100644 (file)
@@ -95,7 +95,7 @@ class EmptyNodeList(tuple):
 
 
 def defproperty(klass, name, doc):
-    get = getattr(klass, ("_get_" + name)).im_func
+    get = getattr(klass, ("_get_" + name))
     def set(self, value, name=name):
         raise xml.dom.NoModificationAllowedErr(
             "attempt to modify read-only attribute " + repr(name))
index 408be4c0640105abbcfe07d867751b3037450983..f9b0346eaa4b60f6861dda71033b78b0e9c852b4 100644 (file)
@@ -643,8 +643,10 @@ function_call(PyObject *func, PyObject *arg, PyObject *kw)
 static PyObject *
 func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
 {
-       if (obj == Py_None)
-               obj = NULL;
+       if (obj == Py_None || obj == NULL) {
+               Py_INCREF(func);
+               return func;
+       }
        return PyMethod_New(func, obj, type);
 }