summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Heimes <christian@cheimes.de>2007-11-25 09:39:14 (GMT)
committerChristian Heimes <christian@cheimes.de>2007-11-25 09:39:14 (GMT)
commit4a22b5dee77b6a3439e4a09362586c390bbdef02 (patch)
tree670472c02e788fe4d027f7967fbbd8253e18cb5f
parent91c77301bf0246deabcdcd80bc7bedb169e2f964 (diff)
downloadcpython-4a22b5dee77b6a3439e4a09362586c390bbdef02.zip
cpython-4a22b5dee77b6a3439e4a09362586c390bbdef02.tar.gz
cpython-4a22b5dee77b6a3439e4a09362586c390bbdef02.tar.bz2
Patch from Georg Brandl and me for #1493
Remove unbound method objects
-rw-r--r--Lib/DocXMLRPCServer.py2
-rw-r--r--Lib/inspect.py4
-rw-r--r--Lib/test/inspect_fodder2.py2
-rw-r--r--Lib/test/output/test_extcall2
-rw-r--r--Lib/test/test_class.py2
-rw-r--r--Lib/test/test_descr.py19
-rw-r--r--Lib/test/test_descrtut.py4
-rw-r--r--Lib/test/test_extcall.py14
-rw-r--r--Lib/test/test_funcattrs.py61
-rw-r--r--Lib/test/test_inspect.py5
-rw-r--r--Lib/test/test_pyclbr.py22
-rw-r--r--Lib/test/test_repr.py4
-rw-r--r--Lib/test/test_sys.py2
-rw-r--r--Lib/test/test_typechecks.py12
-rw-r--r--Lib/test/test_weakref.py5
-rw-r--r--Lib/types.py1
-rw-r--r--Lib/unittest.py11
-rw-r--r--Lib/xml/dom/minicompat.py2
-rw-r--r--Objects/funcobject.c6
19 files changed, 65 insertions, 115 deletions
diff --git a/Lib/DocXMLRPCServer.py b/Lib/DocXMLRPCServer.py
index 111e5f6..08e1f10 100644
--- a/Lib/DocXMLRPCServer.py
+++ b/Lib/DocXMLRPCServer.py
@@ -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 (
diff --git a/Lib/inspect.py b/Lib/inspect.py
index d0608d7..3a95796 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -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:
diff --git a/Lib/test/inspect_fodder2.py b/Lib/test/inspect_fodder2.py
index 7a9f84e..d244935 100644
--- a/Lib/test/inspect_fodder2.py
+++ b/Lib/test/inspect_fodder2.py
@@ -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):
diff --git a/Lib/test/output/test_extcall b/Lib/test/output/test_extcall
index 323fe7a..63f5b71 100644
--- a/Lib/test/output/test_extcall
+++ b/Lib/test/output/test_extcall
@@ -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'
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py
index 76b30a3..ab44a4c 100644
--- a/Lib/test/test_class.py
+++ b/Lib/test/test_class.py
@@ -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():
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 1ea93bb..e093ce8 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -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
diff --git a/Lib/test/test_descrtut.py b/Lib/test/test_descrtut.py
index ea75366..5ce2119 100644
--- a/Lib/test/test_descrtut.py
+++ b/Lib/test/test_descrtut.py
@@ -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):
diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py
index 56a207a..611f4ab 100644
--- a/Lib/test/test_extcall.py
+++ b/Lib/test/test_extcall.py
@@ -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
diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py
index 66ba9cb..bd9caff 100644
--- a/Lib/test/test_funcattrs.py
+++ b/Lib/test/test_funcattrs.py
@@ -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()
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 1858372..3752810 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -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')
diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py
index caccf11..bcb7988 100644
--- a/Lib/test/test_pyclbr.py
+++ b/Lib/test/test_pyclbr.py
@@ -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
diff --git a/Lib/test/test_repr.py b/Lib/test/test_repr.py
index 8d9e99d..af66e97 100644
--- a/Lib/test/test_repr.py
+++ b/Lib/test/test_repr.py
@@ -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(
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index dfad172..9a285c5 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -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
)
diff --git a/Lib/test/test_typechecks.py b/Lib/test/test_typechecks.py
index 632598c..1dcc82c 100644
--- a/Lib/test/test_typechecks.py
+++ b/Lib/test/test_typechecks.py
@@ -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)
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index 1a49aea..922b293 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -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()
diff --git a/Lib/types.py b/Lib/types.py
index 5c1f249..402fa18 100644
--- a/Lib/types.py
+++ b/Lib/types.py
@@ -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)
diff --git a/Lib/unittest.py b/Lib/unittest.py
index c590558..c4b124b 100644
--- a/Lib/unittest.py
+++ b/Lib/unittest.py
@@ -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
diff --git a/Lib/xml/dom/minicompat.py b/Lib/xml/dom/minicompat.py
index c0a797e..2e6cc7e 100644
--- a/Lib/xml/dom/minicompat.py
+++ b/Lib/xml/dom/minicompat.py
@@ -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))
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 408be4c..f9b0346 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -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);
}