Home | History | Annotate | Download | only in test
      1 import re
      2 import sys
      3 import types
      4 import unittest
      5 import inspect
      6 import linecache
      7 import datetime
      8 from UserList import UserList
      9 from UserDict import UserDict
     10 
     11 from test.test_support import run_unittest, check_py3k_warnings
     12 
     13 with check_py3k_warnings(
     14         ("tuple parameter unpacking has been removed", SyntaxWarning),
     15         quiet=True):
     16     from test import inspect_fodder as mod
     17     from test import inspect_fodder2 as mod2
     18 
     19 # C module for test_findsource_binary
     20 import unicodedata
     21 
     22 # Functions tested in this suite:
     23 # ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode,
     24 # isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers,
     25 # getdoc, getfile, getmodule, getsourcefile, getcomments, getsource,
     26 # getclasstree, getargspec, getargvalues, formatargspec, formatargvalues,
     27 # currentframe, stack, trace, isdatadescriptor
     28 
     29 # NOTE: There are some additional tests relating to interaction with
     30 #       zipimport in the test_zipimport_support test module.
     31 
     32 modfile = mod.__file__
     33 if modfile.endswith(('c', 'o')):
     34     modfile = modfile[:-1]
     35 
     36 import __builtin__
     37 
     38 try:
     39     1 // 0
     40 except:
     41     tb = sys.exc_traceback
     42 
     43 git = mod.StupidGit()
     44 
     45 class IsTestBase(unittest.TestCase):
     46     predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
     47                       inspect.isframe, inspect.isfunction, inspect.ismethod,
     48                       inspect.ismodule, inspect.istraceback,
     49                       inspect.isgenerator, inspect.isgeneratorfunction])
     50 
     51     def istest(self, predicate, exp):
     52         obj = eval(exp)
     53         self.assertTrue(predicate(obj), '%s(%s)' % (predicate.__name__, exp))
     54 
     55         for other in self.predicates - set([predicate]):
     56             if predicate == inspect.isgeneratorfunction and\
     57                other == inspect.isfunction:
     58                 continue
     59             self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp))
     60 
     61 def generator_function_example(self):
     62     for i in xrange(2):
     63         yield i
     64 
     65 class TestPredicates(IsTestBase):
     66     def test_sixteen(self):
     67         count = len(filter(lambda x:x.startswith('is'), dir(inspect)))
     68         # This test is here for remember you to update Doc/library/inspect.rst
     69         # which claims there are 16 such functions
     70         expected = 16
     71         err_msg = "There are %d (not %d) is* functions" % (count, expected)
     72         self.assertEqual(count, expected, err_msg)
     73 
     74 
     75     def test_excluding_predicates(self):
     76         self.istest(inspect.isbuiltin, 'sys.exit')
     77         self.istest(inspect.isbuiltin, '[].append')
     78         self.istest(inspect.iscode, 'mod.spam.func_code')
     79         self.istest(inspect.isframe, 'tb.tb_frame')
     80         self.istest(inspect.isfunction, 'mod.spam')
     81         self.istest(inspect.ismethod, 'mod.StupidGit.abuse')
     82         self.istest(inspect.ismethod, 'git.argue')
     83         self.istest(inspect.ismodule, 'mod')
     84         self.istest(inspect.istraceback, 'tb')
     85         self.istest(inspect.isdatadescriptor, '__builtin__.file.closed')
     86         self.istest(inspect.isdatadescriptor, '__builtin__.file.softspace')
     87         self.istest(inspect.isgenerator, '(x for x in xrange(2))')
     88         self.istest(inspect.isgeneratorfunction, 'generator_function_example')
     89         if hasattr(types, 'GetSetDescriptorType'):
     90             self.istest(inspect.isgetsetdescriptor,
     91                         'type(tb.tb_frame).f_locals')
     92         else:
     93             self.assertFalse(inspect.isgetsetdescriptor(type(tb.tb_frame).f_locals))
     94         if hasattr(types, 'MemberDescriptorType'):
     95             self.istest(inspect.ismemberdescriptor, 'datetime.timedelta.days')
     96         else:
     97             self.assertFalse(inspect.ismemberdescriptor(datetime.timedelta.days))
     98 
     99     def test_isroutine(self):
    100         self.assertTrue(inspect.isroutine(mod.spam))
    101         self.assertTrue(inspect.isroutine([].count))
    102 
    103     def test_isclass(self):
    104         self.istest(inspect.isclass, 'mod.StupidGit')
    105         self.assertTrue(inspect.isclass(list))
    106 
    107         class newstyle(object): pass
    108         self.assertTrue(inspect.isclass(newstyle))
    109 
    110         class CustomGetattr(object):
    111             def __getattr__(self, attr):
    112                 return None
    113         self.assertFalse(inspect.isclass(CustomGetattr()))
    114 
    115     def test_get_slot_members(self):
    116         class C(object):
    117             __slots__ = ("a", "b")
    118 
    119         x = C()
    120         x.a = 42
    121         members = dict(inspect.getmembers(x))
    122         self.assertIn('a', members)
    123         self.assertNotIn('b', members)
    124 
    125     def test_isabstract(self):
    126         from abc import ABCMeta, abstractmethod
    127 
    128         class AbstractClassExample(object):
    129             __metaclass__ = ABCMeta
    130 
    131             @abstractmethod
    132             def foo(self):
    133                 pass
    134 
    135         class ClassExample(AbstractClassExample):
    136             def foo(self):
    137                 pass
    138 
    139         a = ClassExample()
    140 
    141         # Test general behaviour.
    142         self.assertTrue(inspect.isabstract(AbstractClassExample))
    143         self.assertFalse(inspect.isabstract(ClassExample))
    144         self.assertFalse(inspect.isabstract(a))
    145         self.assertFalse(inspect.isabstract(int))
    146         self.assertFalse(inspect.isabstract(5))
    147 
    148 
    149 class TestInterpreterStack(IsTestBase):
    150     def __init__(self, *args, **kwargs):
    151         unittest.TestCase.__init__(self, *args, **kwargs)
    152 
    153         git.abuse(7, 8, 9)
    154 
    155     def test_abuse_done(self):
    156         self.istest(inspect.istraceback, 'git.ex[2]')
    157         self.istest(inspect.isframe, 'mod.fr')
    158 
    159     def test_stack(self):
    160         self.assertTrue(len(mod.st) >= 5)
    161         self.assertEqual(mod.st[0][1:],
    162              (modfile, 16, 'eggs', ['    st = inspect.stack()\n'], 0))
    163         self.assertEqual(mod.st[1][1:],
    164              (modfile, 9, 'spam', ['    eggs(b + d, c + f)\n'], 0))
    165         self.assertEqual(mod.st[2][1:],
    166              (modfile, 43, 'argue', ['            spam(a, b, c)\n'], 0))
    167         self.assertEqual(mod.st[3][1:],
    168              (modfile, 39, 'abuse', ['        self.argue(a, b, c)\n'], 0))
    169 
    170     def test_trace(self):
    171         self.assertEqual(len(git.tr), 3)
    172         self.assertEqual(git.tr[0][1:], (modfile, 43, 'argue',
    173                                          ['            spam(a, b, c)\n'], 0))
    174         self.assertEqual(git.tr[1][1:], (modfile, 9, 'spam',
    175                                          ['    eggs(b + d, c + f)\n'], 0))
    176         self.assertEqual(git.tr[2][1:], (modfile, 18, 'eggs',
    177                                          ['    q = y // 0\n'], 0))
    178 
    179     def test_frame(self):
    180         args, varargs, varkw, locals = inspect.getargvalues(mod.fr)
    181         self.assertEqual(args, ['x', 'y'])
    182         self.assertEqual(varargs, None)
    183         self.assertEqual(varkw, None)
    184         self.assertEqual(locals, {'x': 11, 'p': 11, 'y': 14})
    185         self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals),
    186                          '(x=11, y=14)')
    187 
    188     def test_previous_frame(self):
    189         args, varargs, varkw, locals = inspect.getargvalues(mod.fr.f_back)
    190         self.assertEqual(args, ['a', 'b', 'c', 'd', ['e', ['f']]])
    191         self.assertEqual(varargs, 'g')
    192         self.assertEqual(varkw, 'h')
    193         self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals),
    194              '(a=7, b=8, c=9, d=3, (e=4, (f=5,)), *g=(), **h={})')
    195 
    196 class GetSourceBase(unittest.TestCase):
    197     # Subclasses must override.
    198     fodderFile = None
    199 
    200     def __init__(self, *args, **kwargs):
    201         unittest.TestCase.__init__(self, *args, **kwargs)
    202 
    203         with open(inspect.getsourcefile(self.fodderFile)) as fp:
    204             self.source = fp.read()
    205 
    206     def sourcerange(self, top, bottom):
    207         lines = self.source.split("\n")
    208         return "\n".join(lines[top-1:bottom]) + "\n"
    209 
    210     def assertSourceEqual(self, obj, top, bottom):
    211         self.assertEqual(inspect.getsource(obj),
    212                          self.sourcerange(top, bottom))
    213 
    214 class TestRetrievingSourceCode(GetSourceBase):
    215     fodderFile = mod
    216 
    217     def test_getclasses(self):
    218         classes = inspect.getmembers(mod, inspect.isclass)
    219         self.assertEqual(classes,
    220                          [('FesteringGob', mod.FesteringGob),
    221                           ('MalodorousPervert', mod.MalodorousPervert),
    222                           ('ParrotDroppings', mod.ParrotDroppings),
    223                           ('StupidGit', mod.StupidGit)])
    224         tree = inspect.getclasstree([cls[1] for cls in classes], 1)
    225         self.assertEqual(tree,
    226                          [(mod.ParrotDroppings, ()),
    227                           (mod.StupidGit, ()),
    228                           [(mod.MalodorousPervert, (mod.StupidGit,)),
    229                            [(mod.FesteringGob, (mod.MalodorousPervert,
    230                                                    mod.ParrotDroppings))
    231                             ]
    232                            ]
    233                           ])
    234 
    235     def test_getfunctions(self):
    236         functions = inspect.getmembers(mod, inspect.isfunction)
    237         self.assertEqual(functions, [('eggs', mod.eggs),
    238                                      ('spam', mod.spam)])
    239 
    240     @unittest.skipIf(sys.flags.optimize >= 2,
    241                      "Docstrings are omitted with -O2 and above")
    242     def test_getdoc(self):
    243         self.assertEqual(inspect.getdoc(mod), 'A module docstring.')
    244         self.assertEqual(inspect.getdoc(mod.StupidGit),
    245                          'A longer,\n\nindented\n\ndocstring.')
    246         self.assertEqual(inspect.getdoc(git.abuse),
    247                          'Another\n\ndocstring\n\ncontaining\n\ntabs')
    248 
    249     def test_cleandoc(self):
    250         self.assertEqual(inspect.cleandoc('An\n    indented\n    docstring.'),
    251                          'An\nindented\ndocstring.')
    252 
    253     def test_getcomments(self):
    254         self.assertEqual(inspect.getcomments(mod), '# line 1\n')
    255         self.assertEqual(inspect.getcomments(mod.StupidGit), '# line 20\n')
    256 
    257     def test_getmodule(self):
    258         # Check actual module
    259         self.assertEqual(inspect.getmodule(mod), mod)
    260         # Check class (uses __module__ attribute)
    261         self.assertEqual(inspect.getmodule(mod.StupidGit), mod)
    262         # Check a method (no __module__ attribute, falls back to filename)
    263         self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
    264         # Do it again (check the caching isn't broken)
    265         self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
    266         # Check a builtin
    267         self.assertEqual(inspect.getmodule(str), sys.modules["__builtin__"])
    268         # Check filename override
    269         self.assertEqual(inspect.getmodule(None, modfile), mod)
    270 
    271     def test_getsource(self):
    272         self.assertSourceEqual(git.abuse, 29, 39)
    273         self.assertSourceEqual(mod.StupidGit, 21, 46)
    274 
    275     def test_getsourcefile(self):
    276         self.assertEqual(inspect.getsourcefile(mod.spam), modfile)
    277         self.assertEqual(inspect.getsourcefile(git.abuse), modfile)
    278         fn = "_non_existing_filename_used_for_sourcefile_test.py"
    279         co = compile("None", fn, "exec")
    280         self.assertEqual(inspect.getsourcefile(co), None)
    281         linecache.cache[co.co_filename] = (1, None, "None", co.co_filename)
    282         self.assertEqual(inspect.getsourcefile(co), fn)
    283 
    284     def test_getfile(self):
    285         self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__)
    286 
    287     def test_getmodule_recursion(self):
    288         from types import ModuleType
    289         name = '__inspect_dummy'
    290         m = sys.modules[name] = ModuleType(name)
    291         m.__file__ = "<string>" # hopefully not a real filename...
    292         m.__loader__ = "dummy"  # pretend the filename is understood by a loader
    293         exec "def x(): pass" in m.__dict__
    294         self.assertEqual(inspect.getsourcefile(m.x.func_code), '<string>')
    295         del sys.modules[name]
    296         inspect.getmodule(compile('a=10','','single'))
    297 
    298     def test_proceed_with_fake_filename(self):
    299         '''doctest monkeypatches linecache to enable inspection'''
    300         fn, source = '<test>', 'def x(): pass\n'
    301         getlines = linecache.getlines
    302         def monkey(filename, module_globals=None):
    303             if filename == fn:
    304                 return source.splitlines(True)
    305             else:
    306                 return getlines(filename, module_globals)
    307         linecache.getlines = monkey
    308         try:
    309             ns = {}
    310             exec compile(source, fn, 'single') in ns
    311             inspect.getsource(ns["x"])
    312         finally:
    313             linecache.getlines = getlines
    314 
    315 class TestDecorators(GetSourceBase):
    316     fodderFile = mod2
    317 
    318     def test_wrapped_decorator(self):
    319         self.assertSourceEqual(mod2.wrapped, 14, 17)
    320 
    321     def test_replacing_decorator(self):
    322         self.assertSourceEqual(mod2.gone, 9, 10)
    323 
    324 class TestOneliners(GetSourceBase):
    325     fodderFile = mod2
    326     def test_oneline_lambda(self):
    327         # Test inspect.getsource with a one-line lambda function.
    328         self.assertSourceEqual(mod2.oll, 25, 25)
    329 
    330     def test_threeline_lambda(self):
    331         # Test inspect.getsource with a three-line lambda function,
    332         # where the second and third lines are _not_ indented.
    333         self.assertSourceEqual(mod2.tll, 28, 30)
    334 
    335     def test_twoline_indented_lambda(self):
    336         # Test inspect.getsource with a two-line lambda function,
    337         # where the second line _is_ indented.
    338         self.assertSourceEqual(mod2.tlli, 33, 34)
    339 
    340     def test_onelinefunc(self):
    341         # Test inspect.getsource with a regular one-line function.
    342         self.assertSourceEqual(mod2.onelinefunc, 37, 37)
    343 
    344     def test_manyargs(self):
    345         # Test inspect.getsource with a regular function where
    346         # the arguments are on two lines and _not_ indented and
    347         # the body on the second line with the last arguments.
    348         self.assertSourceEqual(mod2.manyargs, 40, 41)
    349 
    350     def test_twolinefunc(self):
    351         # Test inspect.getsource with a regular function where
    352         # the body is on two lines, following the argument list and
    353         # continued on the next line by a \\.
    354         self.assertSourceEqual(mod2.twolinefunc, 44, 45)
    355 
    356     def test_lambda_in_list(self):
    357         # Test inspect.getsource with a one-line lambda function
    358         # defined in a list, indented.
    359         self.assertSourceEqual(mod2.a[1], 49, 49)
    360 
    361     def test_anonymous(self):
    362         # Test inspect.getsource with a lambda function defined
    363         # as argument to another function.
    364         self.assertSourceEqual(mod2.anonymous, 55, 55)
    365 
    366 class TestBuggyCases(GetSourceBase):
    367     fodderFile = mod2
    368 
    369     def test_with_comment(self):
    370         self.assertSourceEqual(mod2.with_comment, 58, 59)
    371 
    372     def test_multiline_sig(self):
    373         self.assertSourceEqual(mod2.multiline_sig[0], 63, 64)
    374 
    375     def test_nested_class(self):
    376         self.assertSourceEqual(mod2.func69().func71, 71, 72)
    377 
    378     def test_one_liner_followed_by_non_name(self):
    379         self.assertSourceEqual(mod2.func77, 77, 77)
    380 
    381     def test_one_liner_dedent_non_name(self):
    382         self.assertSourceEqual(mod2.cls82.func83, 83, 83)
    383 
    384     def test_with_comment_instead_of_docstring(self):
    385         self.assertSourceEqual(mod2.func88, 88, 90)
    386 
    387     def test_method_in_dynamic_class(self):
    388         self.assertSourceEqual(mod2.method_in_dynamic_class, 95, 97)
    389 
    390     @unittest.skipIf(
    391         not hasattr(unicodedata, '__file__') or
    392             unicodedata.__file__[-4:] in (".pyc", ".pyo"),
    393         "unicodedata is not an external binary module")
    394     def test_findsource_binary(self):
    395         self.assertRaises(IOError, inspect.getsource, unicodedata)
    396         self.assertRaises(IOError, inspect.findsource, unicodedata)
    397 
    398     def test_findsource_code_in_linecache(self):
    399         lines = ["x=1"]
    400         co = compile(lines[0], "_dynamically_created_file", "exec")
    401         self.assertRaises(IOError, inspect.findsource, co)
    402         self.assertRaises(IOError, inspect.getsource, co)
    403         linecache.cache[co.co_filename] = (1, None, lines, co.co_filename)
    404         self.assertEqual(inspect.findsource(co), (lines,0))
    405         self.assertEqual(inspect.getsource(co), lines[0])
    406 
    407     def test_findsource_without_filename(self):
    408         for fname in ['', '<string>']:
    409             co = compile('x=1', fname, "exec")
    410             self.assertRaises(IOError, inspect.findsource, co)
    411             self.assertRaises(IOError, inspect.getsource, co)
    412 
    413 
    414 class _BrokenDataDescriptor(object):
    415     """
    416     A broken data descriptor. See bug #1785.
    417     """
    418     def __get__(*args):
    419         raise AssertionError("should not __get__ data descriptors")
    420 
    421     def __set__(*args):
    422         raise RuntimeError
    423 
    424     def __getattr__(*args):
    425         raise AssertionError("should not __getattr__ data descriptors")
    426 
    427 
    428 class _BrokenMethodDescriptor(object):
    429     """
    430     A broken method descriptor. See bug #1785.
    431     """
    432     def __get__(*args):
    433         raise AssertionError("should not __get__ method descriptors")
    434 
    435     def __getattr__(*args):
    436         raise AssertionError("should not __getattr__ method descriptors")
    437 
    438 
    439 # Helper for testing classify_class_attrs.
    440 def attrs_wo_objs(cls):
    441     return [t[:3] for t in inspect.classify_class_attrs(cls)]
    442 
    443 
    444 class TestClassesAndFunctions(unittest.TestCase):
    445     def test_classic_mro(self):
    446         # Test classic-class method resolution order.
    447         class A:    pass
    448         class B(A): pass
    449         class C(A): pass
    450         class D(B, C): pass
    451 
    452         expected = (D, B, A, C)
    453         got = inspect.getmro(D)
    454         self.assertEqual(expected, got)
    455 
    456     def test_newstyle_mro(self):
    457         # The same w/ new-class MRO.
    458         class A(object):    pass
    459         class B(A): pass
    460         class C(A): pass
    461         class D(B, C): pass
    462 
    463         expected = (D, B, C, A, object)
    464         got = inspect.getmro(D)
    465         self.assertEqual(expected, got)
    466 
    467     def assertArgSpecEquals(self, routine, args_e, varargs_e = None,
    468                             varkw_e = None, defaults_e = None,
    469                             formatted = None):
    470         args, varargs, varkw, defaults = inspect.getargspec(routine)
    471         self.assertEqual(args, args_e)
    472         self.assertEqual(varargs, varargs_e)
    473         self.assertEqual(varkw, varkw_e)
    474         self.assertEqual(defaults, defaults_e)
    475         if formatted is not None:
    476             self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults),
    477                              formatted)
    478 
    479     def test_getargspec(self):
    480         self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted = '(x, y)')
    481 
    482         self.assertArgSpecEquals(mod.spam,
    483                                  ['a', 'b', 'c', 'd', ['e', ['f']]],
    484                                  'g', 'h', (3, (4, (5,))),
    485                                  '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)')
    486 
    487     def test_getargspec_method(self):
    488         class A(object):
    489             def m(self):
    490                 pass
    491         self.assertArgSpecEquals(A.m, ['self'])
    492 
    493     def test_getargspec_sublistofone(self):
    494         with check_py3k_warnings(
    495                 ("tuple parameter unpacking has been removed", SyntaxWarning),
    496                 ("parenthesized argument names are invalid", SyntaxWarning)):
    497             exec 'def sublistOfOne((foo,)): return 1'
    498             self.assertArgSpecEquals(sublistOfOne, [['foo']])
    499 
    500             exec 'def fakeSublistOfOne((foo)): return 1'
    501             self.assertArgSpecEquals(fakeSublistOfOne, ['foo'])
    502 
    503 
    504     def _classify_test(self, newstyle):
    505         """Helper for testing that classify_class_attrs finds a bunch of
    506         different kinds of attributes on a given class.
    507         """
    508         if newstyle:
    509             base = object
    510         else:
    511             class base:
    512                 pass
    513 
    514         class A(base):
    515             def s(): pass
    516             s = staticmethod(s)
    517 
    518             def c(cls): pass
    519             c = classmethod(c)
    520 
    521             def getp(self): pass
    522             p = property(getp)
    523 
    524             def m(self): pass
    525 
    526             def m1(self): pass
    527 
    528             datablob = '1'
    529 
    530             dd = _BrokenDataDescriptor()
    531             md = _BrokenMethodDescriptor()
    532 
    533         attrs = attrs_wo_objs(A)
    534         self.assertIn(('s', 'static method', A), attrs, 'missing static method')
    535         self.assertIn(('c', 'class method', A), attrs, 'missing class method')
    536         self.assertIn(('p', 'property', A), attrs, 'missing property')
    537         self.assertIn(('m', 'method', A), attrs, 'missing plain method')
    538         self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
    539         self.assertIn(('datablob', 'data', A), attrs, 'missing data')
    540         self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
    541         self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
    542 
    543         class B(A):
    544             def m(self): pass
    545 
    546         attrs = attrs_wo_objs(B)
    547         self.assertIn(('s', 'static method', A), attrs, 'missing static method')
    548         self.assertIn(('c', 'class method', A), attrs, 'missing class method')
    549         self.assertIn(('p', 'property', A), attrs, 'missing property')
    550         self.assertIn(('m', 'method', B), attrs, 'missing plain method')
    551         self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
    552         self.assertIn(('datablob', 'data', A), attrs, 'missing data')
    553         self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
    554         self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
    555 
    556 
    557         class C(A):
    558             def m(self): pass
    559             def c(self): pass
    560 
    561         attrs = attrs_wo_objs(C)
    562         self.assertIn(('s', 'static method', A), attrs, 'missing static method')
    563         self.assertIn(('c', 'method', C), attrs, 'missing plain method')
    564         self.assertIn(('p', 'property', A), attrs, 'missing property')
    565         self.assertIn(('m', 'method', C), attrs, 'missing plain method')
    566         self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
    567         self.assertIn(('datablob', 'data', A), attrs, 'missing data')
    568         self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
    569         self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
    570 
    571         class D(B, C):
    572             def m1(self): pass
    573 
    574         attrs = attrs_wo_objs(D)
    575         self.assertIn(('s', 'static method', A), attrs, 'missing static method')
    576         if newstyle:
    577             self.assertIn(('c', 'method', C), attrs, 'missing plain method')
    578         else:
    579             self.assertIn(('c', 'class method', A), attrs, 'missing class method')
    580         self.assertIn(('p', 'property', A), attrs, 'missing property')
    581         self.assertIn(('m', 'method', B), attrs, 'missing plain method')
    582         self.assertIn(('m1', 'method', D), attrs, 'missing plain method')
    583         self.assertIn(('datablob', 'data', A), attrs, 'missing data')
    584         self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
    585         self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
    586 
    587 
    588     def test_classify_oldstyle(self):
    589         """classify_class_attrs finds static methods, class methods,
    590         properties, normal methods, and data attributes on an old-style
    591         class.
    592         """
    593         self._classify_test(False)
    594 
    595 
    596     def test_classify_newstyle(self):
    597         """Just like test_classify_oldstyle, but for a new-style class.
    598         """
    599         self._classify_test(True)
    600 
    601     def test_classify_builtin_types(self):
    602         # Simple sanity check that all built-in types can have their
    603         # attributes classified.
    604         for name in dir(__builtin__):
    605             builtin = getattr(__builtin__, name)
    606             if isinstance(builtin, type):
    607                 inspect.classify_class_attrs(builtin)
    608 
    609     def test_getmembers_method(self):
    610         # Old-style classes
    611         class B:
    612             def f(self):
    613                 pass
    614 
    615         self.assertIn(('f', B.f), inspect.getmembers(B))
    616         # contrary to spec, ismethod() is also True for unbound methods
    617         # (see #1785)
    618         self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
    619         b = B()
    620         self.assertIn(('f', b.f), inspect.getmembers(b))
    621         self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))
    622 
    623         # New-style classes
    624         class B(object):
    625             def f(self):
    626                 pass
    627 
    628         self.assertIn(('f', B.f), inspect.getmembers(B))
    629         self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
    630         b = B()
    631         self.assertIn(('f', b.f), inspect.getmembers(b))
    632         self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))
    633 
    634 
    635 class TestGetcallargsFunctions(unittest.TestCase):
    636 
    637     # tuple parameters are named '.1', '.2', etc.
    638     is_tuplename = re.compile(r'^\.\d+$').match
    639 
    640     def assertEqualCallArgs(self, func, call_params_string, locs=None):
    641         locs = dict(locs or {}, func=func)
    642         r1 = eval('func(%s)' % call_params_string, None, locs)
    643         r2 = eval('inspect.getcallargs(func, %s)' % call_params_string, None,
    644                   locs)
    645         self.assertEqual(r1, r2)
    646 
    647     def assertEqualException(self, func, call_param_string, locs=None):
    648         locs = dict(locs or {}, func=func)
    649         try:
    650             eval('func(%s)' % call_param_string, None, locs)
    651         except Exception, ex1:
    652             pass
    653         else:
    654             self.fail('Exception not raised')
    655         try:
    656             eval('inspect.getcallargs(func, %s)' % call_param_string, None,
    657                  locs)
    658         except Exception, ex2:
    659             pass
    660         else:
    661             self.fail('Exception not raised')
    662         self.assertIs(type(ex1), type(ex2))
    663         self.assertEqual(str(ex1), str(ex2))
    664 
    665     def makeCallable(self, signature):
    666         """Create a function that returns its locals(), excluding the
    667         autogenerated '.1', '.2', etc. tuple param names (if any)."""
    668         with check_py3k_warnings(
    669             ("tuple parameter unpacking has been removed", SyntaxWarning),
    670             quiet=True):
    671             code = ("lambda %s: dict(i for i in locals().items() "
    672                     "if not is_tuplename(i[0]))")
    673             return eval(code % signature, {'is_tuplename' : self.is_tuplename})
    674 
    675     def test_plain(self):
    676         f = self.makeCallable('a, b=1')
    677         self.assertEqualCallArgs(f, '2')
    678         self.assertEqualCallArgs(f, '2, 3')
    679         self.assertEqualCallArgs(f, 'a=2')
    680         self.assertEqualCallArgs(f, 'b=3, a=2')
    681         self.assertEqualCallArgs(f, '2, b=3')
    682         # expand *iterable / **mapping
    683         self.assertEqualCallArgs(f, '*(2,)')
    684         self.assertEqualCallArgs(f, '*[2]')
    685         self.assertEqualCallArgs(f, '*(2, 3)')
    686         self.assertEqualCallArgs(f, '*[2, 3]')
    687         self.assertEqualCallArgs(f, '**{"a":2}')
    688         self.assertEqualCallArgs(f, 'b=3, **{"a":2}')
    689         self.assertEqualCallArgs(f, '2, **{"b":3}')
    690         self.assertEqualCallArgs(f, '**{"b":3, "a":2}')
    691         # expand UserList / UserDict
    692         self.assertEqualCallArgs(f, '*UserList([2])')
    693         self.assertEqualCallArgs(f, '*UserList([2, 3])')
    694         self.assertEqualCallArgs(f, '**UserDict(a=2)')
    695         self.assertEqualCallArgs(f, '2, **UserDict(b=3)')
    696         self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3)')
    697         # unicode keyword args
    698         self.assertEqualCallArgs(f, '**{u"a":2}')
    699         self.assertEqualCallArgs(f, 'b=3, **{u"a":2}')
    700         self.assertEqualCallArgs(f, '2, **{u"b":3}')
    701         self.assertEqualCallArgs(f, '**{u"b":3, u"a":2}')
    702 
    703     def test_varargs(self):
    704         f = self.makeCallable('a, b=1, *c')
    705         self.assertEqualCallArgs(f, '2')
    706         self.assertEqualCallArgs(f, '2, 3')
    707         self.assertEqualCallArgs(f, '2, 3, 4')
    708         self.assertEqualCallArgs(f, '*(2,3,4)')
    709         self.assertEqualCallArgs(f, '2, *[3,4]')
    710         self.assertEqualCallArgs(f, '2, 3, *UserList([4])')
    711 
    712     def test_varkw(self):
    713         f = self.makeCallable('a, b=1, **c')
    714         self.assertEqualCallArgs(f, 'a=2')
    715         self.assertEqualCallArgs(f, '2, b=3, c=4')
    716         self.assertEqualCallArgs(f, 'b=3, a=2, c=4')
    717         self.assertEqualCallArgs(f, 'c=4, **{"a":2, "b":3}')
    718         self.assertEqualCallArgs(f, '2, c=4, **{"b":3}')
    719         self.assertEqualCallArgs(f, 'b=2, **{"a":3, "c":4}')
    720         self.assertEqualCallArgs(f, '**UserDict(a=2, b=3, c=4)')
    721         self.assertEqualCallArgs(f, '2, c=4, **UserDict(b=3)')
    722         self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3, c=4)')
    723         # unicode keyword args
    724         self.assertEqualCallArgs(f, 'c=4, **{u"a":2, u"b":3}')
    725         self.assertEqualCallArgs(f, '2, c=4, **{u"b":3}')
    726         self.assertEqualCallArgs(f, 'b=2, **{u"a":3, u"c":4}')
    727 
    728     def test_varkw_only(self):
    729         # issue11256:
    730         f = self.makeCallable('**c')
    731         self.assertEqualCallArgs(f, '')
    732         self.assertEqualCallArgs(f, 'a=1')
    733         self.assertEqualCallArgs(f, 'a=1, b=2')
    734         self.assertEqualCallArgs(f, 'c=3, **{"a": 1, "b": 2}')
    735         self.assertEqualCallArgs(f, '**UserDict(a=1, b=2)')
    736         self.assertEqualCallArgs(f, 'c=3, **UserDict(a=1, b=2)')
    737 
    738     def test_tupleargs(self):
    739         f = self.makeCallable('(b,c), (d,(e,f))=(0,[1,2])')
    740         self.assertEqualCallArgs(f, '(2,3)')
    741         self.assertEqualCallArgs(f, '[2,3]')
    742         self.assertEqualCallArgs(f, 'UserList([2,3])')
    743         self.assertEqualCallArgs(f, '(2,3), (4,(5,6))')
    744         self.assertEqualCallArgs(f, '(2,3), (4,[5,6])')
    745         self.assertEqualCallArgs(f, '(2,3), [4,UserList([5,6])]')
    746 
    747     def test_multiple_features(self):
    748         f = self.makeCallable('a, b=2, (c,(d,e))=(3,[4,5]), *f, **g')
    749         self.assertEqualCallArgs(f, '2, 3, (4,[5,6]), 7')
    750         self.assertEqualCallArgs(f, '2, 3, *[(4,[5,6]), 7], x=8')
    751         self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]')
    752         self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9')
    753         self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9')
    754         self.assertEqualCallArgs(f, 'x=8, *UserList([2, 3, (4,[5,6])]), '
    755                                  '**{"y":9, "z":10}')
    756         self.assertEqualCallArgs(f, '2, x=8, *UserList([3, (4,[5,6])]), '
    757                                  '**UserDict(y=9, z=10)')
    758 
    759     def test_errors(self):
    760         f0 = self.makeCallable('')
    761         f1 = self.makeCallable('a, b')
    762         f2 = self.makeCallable('a, b=1')
    763         # f0 takes no arguments
    764         self.assertEqualException(f0, '1')
    765         self.assertEqualException(f0, 'x=1')
    766         self.assertEqualException(f0, '1,x=1')
    767         # f1 takes exactly 2 arguments
    768         self.assertEqualException(f1, '')
    769         self.assertEqualException(f1, '1')
    770         self.assertEqualException(f1, 'a=2')
    771         self.assertEqualException(f1, 'b=3')
    772         # f2 takes at least 1 argument
    773         self.assertEqualException(f2, '')
    774         self.assertEqualException(f2, 'b=3')
    775         for f in f1, f2:
    776             # f1/f2 takes exactly/at most 2 arguments
    777             self.assertEqualException(f, '2, 3, 4')
    778             self.assertEqualException(f, '1, 2, 3, a=1')
    779             self.assertEqualException(f, '2, 3, 4, c=5')
    780             self.assertEqualException(f, '2, 3, 4, a=1, c=5')
    781             # f got an unexpected keyword argument
    782             self.assertEqualException(f, 'c=2')
    783             self.assertEqualException(f, '2, c=3')
    784             self.assertEqualException(f, '2, 3, c=4')
    785             self.assertEqualException(f, '2, c=4, b=3')
    786             self.assertEqualException(f, '**{u"\u03c0\u03b9": 4}')
    787             # f got multiple values for keyword argument
    788             self.assertEqualException(f, '1, a=2')
    789             self.assertEqualException(f, '1, **{"a":2}')
    790             self.assertEqualException(f, '1, 2, b=3')
    791             # XXX: Python inconsistency
    792             # - for functions and bound methods: unexpected keyword 'c'
    793             # - for unbound methods: multiple values for keyword 'a'
    794             #self.assertEqualException(f, '1, c=3, a=2')
    795         f = self.makeCallable('(a,b)=(0,1)')
    796         self.assertEqualException(f, '1')
    797         self.assertEqualException(f, '[1]')
    798         self.assertEqualException(f, '(1,2,3)')
    799         # issue11256:
    800         f3 = self.makeCallable('**c')
    801         self.assertEqualException(f3, '1, 2')
    802         self.assertEqualException(f3, '1, 2, a=1, b=2')
    803 
    804 class TestGetcallargsMethods(TestGetcallargsFunctions):
    805 
    806     def setUp(self):
    807         class Foo(object):
    808             pass
    809         self.cls = Foo
    810         self.inst = Foo()
    811 
    812     def makeCallable(self, signature):
    813         assert 'self' not in signature
    814         mk = super(TestGetcallargsMethods, self).makeCallable
    815         self.cls.method = mk('self, ' + signature)
    816         return self.inst.method
    817 
    818 class TestGetcallargsUnboundMethods(TestGetcallargsMethods):
    819 
    820     def makeCallable(self, signature):
    821         super(TestGetcallargsUnboundMethods, self).makeCallable(signature)
    822         return self.cls.method
    823 
    824     def assertEqualCallArgs(self, func, call_params_string, locs=None):
    825         return super(TestGetcallargsUnboundMethods, self).assertEqualCallArgs(
    826             *self._getAssertEqualParams(func, call_params_string, locs))
    827 
    828     def assertEqualException(self, func, call_params_string, locs=None):
    829         return super(TestGetcallargsUnboundMethods, self).assertEqualException(
    830             *self._getAssertEqualParams(func, call_params_string, locs))
    831 
    832     def _getAssertEqualParams(self, func, call_params_string, locs=None):
    833         assert 'inst' not in call_params_string
    834         locs = dict(locs or {}, inst=self.inst)
    835         return (func, 'inst,' + call_params_string, locs)
    836 
    837 def test_main():
    838     run_unittest(
    839         TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
    840         TestInterpreterStack, TestClassesAndFunctions, TestPredicates,
    841         TestGetcallargsFunctions, TestGetcallargsMethods,
    842         TestGetcallargsUnboundMethods)
    843 
    844 if __name__ == "__main__":
    845     test_main()
    846