Since abc._Abstract was replaces by a new type flags the regression test suite fails. I've added a new function inspect.isabstract(). Is the mmethod fine or should I check if object is a instance of type or subclass of object, too?

This commit is contained in:
Christian Heimes 2008-03-03 18:28:04 +00:00
parent 1f178a6fac
commit 608c1d8e87
5 changed files with 24 additions and 4 deletions

View File

@ -307,6 +307,12 @@ Note:
Return true if the object is a user-defined or built-in function or method. Return true if the object is a user-defined or built-in function or method.
.. function:: isabstract(object)
Return true if the object is an abstract base class.
.. versionadded:: 2.6
.. function:: ismethoddescriptor(object) .. function:: ismethoddescriptor(object)

View File

@ -38,11 +38,15 @@ import dis
import imp import imp
import tokenize import tokenize
import linecache import linecache
from abc import ABCMeta
from operator import attrgetter from operator import attrgetter
from collections import namedtuple from collections import namedtuple
from compiler.consts import (CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, from compiler.consts import (CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS,
CO_VARKEYWORDS, CO_GENERATOR) CO_VARKEYWORDS, CO_GENERATOR)
# See Include/object.h
TPFLAGS_IS_ABSTRACT = 1 << 20
# ----------------------------------------------------------- type-checking # ----------------------------------------------------------- type-checking
def ismodule(object): def ismodule(object):
"""Return true if the object is a module. """Return true if the object is a module.
@ -241,6 +245,10 @@ def isgenerator(object):
"""Return true if the object is a generator object.""" """Return true if the object is a generator object."""
return isinstance(object, types.GeneratorType) return isinstance(object, types.GeneratorType)
def isabstract(object):
"""Return true if the object is an abstract base class (ABC)."""
return object.__flags__ & TPFLAGS_IS_ABSTRACT
def getmembers(object, predicate=None): def getmembers(object, predicate=None):
"""Return all members of an object as (name, value) pairs sorted by name. """Return all members of an object as (name, value) pairs sorted by name.
Optionally, only return members that satisfy a given predicate.""" Optionally, only return members that satisfy a given predicate."""

View File

@ -129,6 +129,7 @@ import warnings
import re import re
import cStringIO import cStringIO
import traceback import traceback
from inspect import isabstract
# I see no other way to suppress these warnings; # I see no other way to suppress these warnings;
# putting them in test_grammar.py has no effect: # putting them in test_grammar.py has no effect:
@ -649,7 +650,6 @@ def cleanup_test_droppings(testname, verbose):
def dash_R(the_module, test, indirect_test, huntrleaks): def dash_R(the_module, test, indirect_test, huntrleaks):
# This code is hackish and inelegant, but it seems to do the job. # This code is hackish and inelegant, but it seems to do the job.
import copy_reg, _abcoll import copy_reg, _abcoll
from abc import _Abstract
if not hasattr(sys, 'gettotalrefcount'): if not hasattr(sys, 'gettotalrefcount'):
raise Exception("Tracking reference leaks requires a debug build " raise Exception("Tracking reference leaks requires a debug build "
@ -661,7 +661,7 @@ def dash_R(the_module, test, indirect_test, huntrleaks):
pic = sys.path_importer_cache.copy() pic = sys.path_importer_cache.copy()
abcs = {} abcs = {}
for abc in [getattr(_abcoll, a) for a in _abcoll.__all__]: for abc in [getattr(_abcoll, a) for a in _abcoll.__all__]:
if not issubclass(abc, _Abstract): if not isabstract(abc):
continue continue
for obj in abc.__subclasses__() + [abc]: for obj in abc.__subclasses__() + [abc]:
abcs[obj] = obj._abc_registry.copy() abcs[obj] = obj._abc_registry.copy()
@ -699,7 +699,6 @@ def dash_R_cleanup(fs, ps, pic, abcs):
import _strptime, linecache, dircache import _strptime, linecache, dircache
import urlparse, urllib, urllib2, mimetypes, doctest import urlparse, urllib, urllib2, mimetypes, doctest
import struct, filecmp, _abcoll import struct, filecmp, _abcoll
from abc import _Abstract
from distutils.dir_util import _path_created from distutils.dir_util import _path_created
# Restore some original values. # Restore some original values.
@ -714,7 +713,7 @@ def dash_R_cleanup(fs, ps, pic, abcs):
# Clear ABC registries, restoring previously saved ABC registries. # Clear ABC registries, restoring previously saved ABC registries.
for abc in [getattr(_abcoll, a) for a in _abcoll.__all__]: for abc in [getattr(_abcoll, a) for a in _abcoll.__all__]:
if not issubclass(abc, _Abstract): if not isabstract(abc):
continue continue
for obj in abc.__subclasses__() + [abc]: for obj in abc.__subclasses__() + [abc]:
obj._abc_registry = abcs.get(obj, {}).copy() obj._abc_registry = abcs.get(obj, {}).copy()

View File

@ -7,6 +7,7 @@ import unittest
from test import test_support from test import test_support
import abc import abc
from inspect import isabstract
class TestABC(unittest.TestCase): class TestABC(unittest.TestCase):
@ -43,19 +44,23 @@ class TestABC(unittest.TestCase):
def bar(self): pass # concrete def bar(self): pass # concrete
self.assertEqual(C.__abstractmethods__, set(["foo"])) self.assertEqual(C.__abstractmethods__, set(["foo"]))
self.assertRaises(TypeError, C) # because foo is abstract self.assertRaises(TypeError, C) # because foo is abstract
self.assert_(isabstract(C))
class D(C): class D(C):
def bar(self): pass # concrete override of concrete def bar(self): pass # concrete override of concrete
self.assertEqual(D.__abstractmethods__, set(["foo"])) self.assertEqual(D.__abstractmethods__, set(["foo"]))
self.assertRaises(TypeError, D) # because foo is still abstract self.assertRaises(TypeError, D) # because foo is still abstract
self.assert_(isabstract(D))
class E(D): class E(D):
def foo(self): pass def foo(self): pass
self.assertEqual(E.__abstractmethods__, set()) self.assertEqual(E.__abstractmethods__, set())
E() # now foo is concrete, too E() # now foo is concrete, too
self.failIf(isabstract(E))
class F(E): class F(E):
@abstractthing @abstractthing
def bar(self): pass # abstract override of concrete def bar(self): pass # abstract override of concrete
self.assertEqual(F.__abstractmethods__, set(["bar"])) self.assertEqual(F.__abstractmethods__, set(["bar"]))
self.assertRaises(TypeError, F) # because bar is abstract now self.assertRaises(TypeError, F) # because bar is abstract now
self.assert_(isabstract(F))
def test_subclass_oldstyle_class(self): def test_subclass_oldstyle_class(self):
class A: class A:

View File

@ -447,6 +447,8 @@ Core and builtins
Library Library
------- -------
- Add inspect.isabstract(object) to fix bug #2223
- Add a __format__ method to Decimal, to support PEP 3101. - Add a __format__ method to Decimal, to support PEP 3101.
- Add a timing parameter when using trace.Trace to print out timestamps. - Add a timing parameter when using trace.Trace to print out timestamps.