aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/test/test_inspect.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_inspect.py')
-rw-r--r--Lib/test/test_inspect.py712
1 files changed, 528 insertions, 184 deletions
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 30b1556cbfb..4b7ee4ed682 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -5,16 +5,15 @@ import unittest
import inspect
import linecache
import datetime
-from UserList import UserList
-from UserDict import UserDict
+import collections
+import os
+import shutil
+from os.path import normcase
-from test.test_support import run_unittest, check_py3k_warnings
+from test.support import run_unittest, TESTFN, DirsOnSysPath
-with check_py3k_warnings(
- ("tuple parameter unpacking has been removed", SyntaxWarning),
- quiet=True):
- from test import inspect_fodder as mod
- from test import inspect_fodder2 as mod2
+from test import inspect_fodder as mod
+from test import inspect_fodder2 as mod2
# C module for test_findsource_binary
import unicodedata
@@ -33,12 +32,19 @@ modfile = mod.__file__
if modfile.endswith(('c', 'o')):
modfile = modfile[:-1]
-import __builtin__
+# Normalize file names: on Windows, the case of file names of compiled
+# modules depends on the path used to start the python executable.
+modfile = normcase(modfile)
+
+def revise(filename, *args):
+ return (normcase(filename),) + args
+
+import builtins
try:
- 1 // 0
+ 1/0
except:
- tb = sys.exc_traceback
+ tb = sys.exc_info()[2]
git = mod.StupidGit()
@@ -59,12 +65,12 @@ class IsTestBase(unittest.TestCase):
self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp))
def generator_function_example(self):
- for i in xrange(2):
+ for i in range(2):
yield i
class TestPredicates(IsTestBase):
def test_sixteen(self):
- count = len(filter(lambda x:x.startswith('is'), dir(inspect)))
+ count = len([x for x in dir(inspect) if x.startswith('is')])
# This test is here for remember you to update Doc/library/inspect.rst
# which claims there are 16 such functions
expected = 16
@@ -75,16 +81,15 @@ class TestPredicates(IsTestBase):
def test_excluding_predicates(self):
self.istest(inspect.isbuiltin, 'sys.exit')
self.istest(inspect.isbuiltin, '[].append')
- self.istest(inspect.iscode, 'mod.spam.func_code')
+ 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')
- self.istest(inspect.isdatadescriptor, '__builtin__.file.closed')
- self.istest(inspect.isdatadescriptor, '__builtin__.file.softspace')
- self.istest(inspect.isgenerator, '(x for x in xrange(2))')
+ self.istest(inspect.isdatadescriptor, 'collections.defaultdict.default_factory')
+ self.istest(inspect.isgenerator, '(x for x in range(2))')
self.istest(inspect.isgeneratorfunction, 'generator_function_example')
if hasattr(types, 'GetSetDescriptorType'):
self.istest(inspect.isgetsetdescriptor,
@@ -104,9 +109,6 @@ class TestPredicates(IsTestBase):
self.istest(inspect.isclass, 'mod.StupidGit')
self.assertTrue(inspect.isclass(list))
- class newstyle(object): pass
- self.assertTrue(inspect.isclass(newstyle))
-
class CustomGetattr(object):
def __getattr__(self, attr):
return None
@@ -125,8 +127,7 @@ class TestPredicates(IsTestBase):
def test_isabstract(self):
from abc import ABCMeta, abstractmethod
- class AbstractClassExample(object):
- __metaclass__ = ABCMeta
+ class AbstractClassExample(metaclass=ABCMeta):
@abstractmethod
def foo(self):
@@ -158,23 +159,23 @@ class TestInterpreterStack(IsTestBase):
def test_stack(self):
self.assertTrue(len(mod.st) >= 5)
- self.assertEqual(mod.st[0][1:],
+ self.assertEqual(revise(*mod.st[0][1:]),
(modfile, 16, 'eggs', [' st = inspect.stack()\n'], 0))
- self.assertEqual(mod.st[1][1:],
+ self.assertEqual(revise(*mod.st[1][1:]),
(modfile, 9, 'spam', [' eggs(b + d, c + f)\n'], 0))
- self.assertEqual(mod.st[2][1:],
+ self.assertEqual(revise(*mod.st[2][1:]),
(modfile, 43, 'argue', [' spam(a, b, c)\n'], 0))
- self.assertEqual(mod.st[3][1:],
+ self.assertEqual(revise(*mod.st[3][1:]),
(modfile, 39, 'abuse', [' self.argue(a, b, c)\n'], 0))
def test_trace(self):
self.assertEqual(len(git.tr), 3)
- self.assertEqual(git.tr[0][1:], (modfile, 43, 'argue',
- [' spam(a, b, c)\n'], 0))
- self.assertEqual(git.tr[1][1:], (modfile, 9, 'spam',
- [' eggs(b + d, c + f)\n'], 0))
- self.assertEqual(git.tr[2][1:], (modfile, 18, 'eggs',
- [' q = y // 0\n'], 0))
+ self.assertEqual(revise(*git.tr[0][1:]),
+ (modfile, 43, 'argue', [' spam(a, b, c)\n'], 0))
+ self.assertEqual(revise(*git.tr[1][1:]),
+ (modfile, 9, 'spam', [' eggs(b + d, c + f)\n'], 0))
+ self.assertEqual(revise(*git.tr[2][1:]),
+ (modfile, 18, 'eggs', [' q = y / 0\n'], 0))
def test_frame(self):
args, varargs, varkw, locals = inspect.getargvalues(mod.fr)
@@ -187,20 +188,20 @@ class TestInterpreterStack(IsTestBase):
def test_previous_frame(self):
args, varargs, varkw, locals = inspect.getargvalues(mod.fr.f_back)
- self.assertEqual(args, ['a', 'b', 'c', 'd', ['e', ['f']]])
+ self.assertEqual(args, ['a', 'b', 'c', 'd', 'e', 'f'])
self.assertEqual(varargs, 'g')
self.assertEqual(varkw, 'h')
self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals),
- '(a=7, b=8, c=9, d=3, (e=4, (f=5,)), *g=(), **h={})')
+ '(a=7, b=8, c=9, d=3, e=4, f=5, *g=(), **h={})')
class GetSourceBase(unittest.TestCase):
# Subclasses must override.
- fodderFile = None
+ fodderModule = None
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
- with open(inspect.getsourcefile(self.fodderFile)) as fp:
+ with open(inspect.getsourcefile(self.fodderModule)) as fp:
self.source = fp.read()
def sourcerange(self, top, bottom):
@@ -212,7 +213,7 @@ class GetSourceBase(unittest.TestCase):
self.sourcerange(top, bottom))
class TestRetrievingSourceCode(GetSourceBase):
- fodderFile = mod
+ fodderModule = mod
def test_getclasses(self):
classes = inspect.getmembers(mod, inspect.isclass)
@@ -223,11 +224,13 @@ class TestRetrievingSourceCode(GetSourceBase):
('StupidGit', mod.StupidGit)])
tree = inspect.getclasstree([cls[1] for cls in classes], 1)
self.assertEqual(tree,
- [(mod.ParrotDroppings, ()),
- (mod.StupidGit, ()),
- [(mod.MalodorousPervert, (mod.StupidGit,)),
- [(mod.FesteringGob, (mod.MalodorousPervert,
- mod.ParrotDroppings))
+ [(object, ()),
+ [(mod.ParrotDroppings, (object,)),
+ (mod.StupidGit, (object,)),
+ [(mod.MalodorousPervert, (mod.StupidGit,)),
+ [(mod.FesteringGob, (mod.MalodorousPervert,
+ mod.ParrotDroppings))
+ ]
]
]
])
@@ -264,7 +267,7 @@ class TestRetrievingSourceCode(GetSourceBase):
# Do it again (check the caching isn't broken)
self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
# Check a builtin
- self.assertEqual(inspect.getmodule(str), sys.modules["__builtin__"])
+ self.assertEqual(inspect.getmodule(str), sys.modules["builtins"])
# Check filename override
self.assertEqual(inspect.getmodule(None, modfile), mod)
@@ -273,13 +276,13 @@ class TestRetrievingSourceCode(GetSourceBase):
self.assertSourceEqual(mod.StupidGit, 21, 46)
def test_getsourcefile(self):
- self.assertEqual(inspect.getsourcefile(mod.spam), modfile)
- self.assertEqual(inspect.getsourcefile(git.abuse), modfile)
+ self.assertEqual(normcase(inspect.getsourcefile(mod.spam)), modfile)
+ self.assertEqual(normcase(inspect.getsourcefile(git.abuse)), modfile)
fn = "_non_existing_filename_used_for_sourcefile_test.py"
co = compile("None", fn, "exec")
self.assertEqual(inspect.getsourcefile(co), None)
linecache.cache[co.co_filename] = (1, None, "None", co.co_filename)
- self.assertEqual(inspect.getsourcefile(co), fn)
+ self.assertEqual(normcase(inspect.getsourcefile(co)), fn)
def test_getfile(self):
self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__)
@@ -290,8 +293,8 @@ class TestRetrievingSourceCode(GetSourceBase):
m = sys.modules[name] = ModuleType(name)
m.__file__ = "<string>" # hopefully not a real filename...
m.__loader__ = "dummy" # pretend the filename is understood by a loader
- exec "def x(): pass" in m.__dict__
- self.assertEqual(inspect.getsourcefile(m.x.func_code), '<string>')
+ exec("def x(): pass", m.__dict__)
+ self.assertEqual(inspect.getsourcefile(m.x.__code__), '<string>')
del sys.modules[name]
inspect.getmodule(compile('a=10','','single'))
@@ -307,13 +310,13 @@ class TestRetrievingSourceCode(GetSourceBase):
linecache.getlines = monkey
try:
ns = {}
- exec compile(source, fn, 'single') in ns
+ exec(compile(source, fn, 'single'), ns)
inspect.getsource(ns["x"])
finally:
linecache.getlines = getlines
class TestDecorators(GetSourceBase):
- fodderFile = mod2
+ fodderModule = mod2
def test_wrapped_decorator(self):
self.assertSourceEqual(mod2.wrapped, 14, 17)
@@ -322,7 +325,7 @@ class TestDecorators(GetSourceBase):
self.assertSourceEqual(mod2.gone, 9, 10)
class TestOneliners(GetSourceBase):
- fodderFile = mod2
+ fodderModule = mod2
def test_oneline_lambda(self):
# Test inspect.getsource with a one-line lambda function.
self.assertSourceEqual(mod2.oll, 25, 25)
@@ -364,7 +367,7 @@ class TestOneliners(GetSourceBase):
self.assertSourceEqual(mod2.anonymous, 55, 55)
class TestBuggyCases(GetSourceBase):
- fodderFile = mod2
+ fodderModule = mod2
def test_with_comment(self):
self.assertSourceEqual(mod2.with_comment, 58, 59)
@@ -404,6 +407,24 @@ class TestBuggyCases(GetSourceBase):
self.assertEqual(inspect.findsource(co), (lines,0))
self.assertEqual(inspect.getsource(co), lines[0])
+class TestNoEOL(GetSourceBase):
+ def __init__(self, *args, **kwargs):
+ self.tempdir = TESTFN + '_dir'
+ os.mkdir(self.tempdir)
+ with open(os.path.join(self.tempdir,
+ 'inspect_fodder3%spy' % os.extsep), 'w') as f:
+ f.write("class X:\n pass # No EOL")
+ with DirsOnSysPath(self.tempdir):
+ import inspect_fodder3 as mod3
+ self.fodderModule = mod3
+ GetSourceBase.__init__(self, *args, **kwargs)
+
+ def tearDown(self):
+ shutil.rmtree(self.tempdir)
+
+ def test_class(self):
+ self.assertSourceEqual(self.fodderModule.X, 1, 2)
+
class _BrokenDataDescriptor(object):
"""
@@ -436,17 +457,6 @@ def attrs_wo_objs(cls):
class TestClassesAndFunctions(unittest.TestCase):
- def test_classic_mro(self):
- # Test classic-class method resolution order.
- class A: pass
- class B(A): pass
- class C(A): pass
- class D(B, C): pass
-
- expected = (D, B, A, C)
- got = inspect.getmro(D)
- self.assertEqual(expected, got)
-
def test_newstyle_mro(self):
# The same w/ new-class MRO.
class A(object): pass
@@ -458,9 +468,8 @@ class TestClassesAndFunctions(unittest.TestCase):
got = inspect.getmro(D)
self.assertEqual(expected, got)
- def assertArgSpecEquals(self, routine, args_e, varargs_e = None,
- varkw_e = None, defaults_e = None,
- formatted = None):
+ def assertArgSpecEquals(self, routine, args_e, varargs_e=None,
+ varkw_e=None, defaults_e=None, formatted=None):
args, varargs, varkw, defaults = inspect.getargspec(routine)
self.assertEqual(args, args_e)
self.assertEqual(varargs, varargs_e)
@@ -470,13 +479,54 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults),
formatted)
+ def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None,
+ varkw_e=None, defaults_e=None,
+ kwonlyargs_e=[], kwonlydefaults_e=None,
+ ann_e={}, formatted=None):
+ args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
+ inspect.getfullargspec(routine)
+ self.assertEqual(args, args_e)
+ self.assertEqual(varargs, varargs_e)
+ self.assertEqual(varkw, varkw_e)
+ self.assertEqual(defaults, defaults_e)
+ self.assertEqual(kwonlyargs, kwonlyargs_e)
+ self.assertEqual(kwonlydefaults, kwonlydefaults_e)
+ self.assertEqual(ann, ann_e)
+ if formatted is not None:
+ self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults,
+ kwonlyargs, kwonlydefaults, ann),
+ formatted)
+
def test_getargspec(self):
- self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted = '(x, y)')
+ self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted='(x, y)')
self.assertArgSpecEquals(mod.spam,
- ['a', 'b', 'c', 'd', ['e', ['f']]],
- 'g', 'h', (3, (4, (5,))),
- '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)')
+ ['a', 'b', 'c', 'd', 'e', 'f'],
+ 'g', 'h', (3, 4, 5),
+ '(a, b, c, d=3, e=4, f=5, *g, **h)')
+
+ self.assertRaises(ValueError, self.assertArgSpecEquals,
+ mod2.keyworded, [])
+
+ self.assertRaises(ValueError, self.assertArgSpecEquals,
+ mod2.annotated, [])
+ self.assertRaises(ValueError, self.assertArgSpecEquals,
+ mod2.keyword_only_arg, [])
+
+
+ def test_getfullargspec(self):
+ self.assertFullArgSpecEquals(mod2.keyworded, [], varargs_e='arg1',
+ kwonlyargs_e=['arg2'],
+ kwonlydefaults_e={'arg2':1},
+ formatted='(*arg1, arg2=1)')
+
+ self.assertFullArgSpecEquals(mod2.annotated, ['arg1'],
+ ann_e={'arg1' : list},
+ formatted='(arg1: list)')
+ self.assertFullArgSpecEquals(mod2.keyword_only_arg, [],
+ kwonlyargs_e=['arg'],
+ formatted='(*, arg)')
+
def test_getargspec_method(self):
class A(object):
@@ -484,28 +534,9 @@ class TestClassesAndFunctions(unittest.TestCase):
pass
self.assertArgSpecEquals(A.m, ['self'])
- def test_getargspec_sublistofone(self):
- with check_py3k_warnings(
- ("tuple parameter unpacking has been removed", SyntaxWarning),
- ("parenthesized argument names are invalid", SyntaxWarning)):
- exec 'def sublistOfOne((foo,)): return 1'
- self.assertArgSpecEquals(sublistOfOne, [['foo']])
-
- exec 'def fakeSublistOfOne((foo)): return 1'
- self.assertArgSpecEquals(fakeSublistOfOne, ['foo'])
-
-
- def _classify_test(self, newstyle):
- """Helper for testing that classify_class_attrs finds a bunch of
- different kinds of attributes on a given class.
- """
- if newstyle:
- base = object
- else:
- class base:
- pass
+ def test_classify_newstyle(self):
+ class A(object):
- class A(base):
def s(): pass
s = staticmethod(s)
@@ -528,13 +559,15 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('s', 'static method', A), attrs, 'missing static method')
self.assertIn(('c', 'class method', A), attrs, 'missing class method')
self.assertIn(('p', 'property', A), attrs, 'missing property')
- self.assertIn(('m', 'method', A), attrs, 'missing plain method')
+ self.assertIn(('m', 'method', A), attrs,
+ 'missing plain method: %r' % attrs)
self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data')
self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
class B(A):
+
def m(self): pass
attrs = attrs_wo_objs(B)
@@ -549,6 +582,7 @@ class TestClassesAndFunctions(unittest.TestCase):
class C(A):
+
def m(self): pass
def c(self): pass
@@ -563,14 +597,12 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
class D(B, C):
+
def m1(self): pass
attrs = attrs_wo_objs(D)
self.assertIn(('s', 'static method', A), attrs, 'missing static method')
- if newstyle:
- self.assertIn(('c', 'method', C), attrs, 'missing plain method')
- else:
- self.assertIn(('c', 'class method', A), attrs, 'missing class method')
+ self.assertIn(('c', 'method', C), attrs, 'missing plain method')
self.assertIn(('p', 'property', A), attrs, 'missing property')
self.assertIn(('m', 'method', B), attrs, 'missing plain method')
self.assertIn(('m1', 'method', D), attrs, 'missing plain method')
@@ -578,49 +610,53 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
-
- def test_classify_oldstyle(self):
- """classify_class_attrs finds static methods, class methods,
- properties, normal methods, and data attributes on an old-style
- class.
- """
- self._classify_test(False)
-
-
- def test_classify_newstyle(self):
- """Just like test_classify_oldstyle, but for a new-style class.
- """
- self._classify_test(True)
-
def test_classify_builtin_types(self):
# Simple sanity check that all built-in types can have their
# attributes classified.
- for name in dir(__builtin__):
- builtin = getattr(__builtin__, name)
+ for name in dir(__builtins__):
+ builtin = getattr(__builtins__, name)
if isinstance(builtin, type):
inspect.classify_class_attrs(builtin)
- def test_getmembers_method(self):
- # Old-style classes
- class B:
- def f(self):
+ def test_getmembers_descriptors(self):
+ class A(object):
+ dd = _BrokenDataDescriptor()
+ md = _BrokenMethodDescriptor()
+
+ def pred_wrapper(pred):
+ # A quick'n'dirty way to discard standard attributes of new-style
+ # classes.
+ class Empty(object):
pass
+ def wrapped(x):
+ if '__name__' in dir(x) and hasattr(Empty, x.__name__):
+ return False
+ return pred(x)
+ return wrapped
- self.assertIn(('f', B.f), inspect.getmembers(B))
- # contrary to spec, ismethod() is also True for unbound methods
- # (see #1785)
- self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
- b = B()
- self.assertIn(('f', b.f), inspect.getmembers(b))
- self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))
+ ismethoddescriptor = pred_wrapper(inspect.ismethoddescriptor)
+ isdatadescriptor = pred_wrapper(inspect.isdatadescriptor)
+
+ self.assertEqual(inspect.getmembers(A, ismethoddescriptor),
+ [('md', A.__dict__['md'])])
+ self.assertEqual(inspect.getmembers(A, isdatadescriptor),
+ [('dd', A.__dict__['dd'])])
+
+ class B(A):
+ pass
+
+ self.assertEqual(inspect.getmembers(B, ismethoddescriptor),
+ [('md', A.__dict__['md'])])
+ self.assertEqual(inspect.getmembers(B, isdatadescriptor),
+ [('dd', A.__dict__['dd'])])
- # New-style classes
- class B(object):
+ def test_getmembers_method(self):
+ class B:
def f(self):
pass
self.assertIn(('f', B.f), inspect.getmembers(B))
- self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
+ self.assertNotIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
b = B()
self.assertIn(('f', b.f), inspect.getmembers(b))
self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))
@@ -628,9 +664,6 @@ class TestClassesAndFunctions(unittest.TestCase):
class TestGetcallargsFunctions(unittest.TestCase):
- # tuple parameters are named '.1', '.2', etc.
- is_tuplename = re.compile(r'^\.\d+$').match
-
def assertEqualCallArgs(self, func, call_params_string, locs=None):
locs = dict(locs or {}, func=func)
r1 = eval('func(%s)' % call_params_string, None, locs)
@@ -642,29 +675,25 @@ class TestGetcallargsFunctions(unittest.TestCase):
locs = dict(locs or {}, func=func)
try:
eval('func(%s)' % call_param_string, None, locs)
- except Exception, ex1:
- pass
+ except Exception as e:
+ ex1 = e
else:
self.fail('Exception not raised')
try:
eval('inspect.getcallargs(func, %s)' % call_param_string, None,
locs)
- except Exception, ex2:
- pass
+ except Exception as e:
+ ex2 = e
else:
self.fail('Exception not raised')
self.assertIs(type(ex1), type(ex2))
self.assertEqual(str(ex1), str(ex2))
+ del ex1, ex2
def makeCallable(self, signature):
- """Create a function that returns its locals(), excluding the
- autogenerated '.1', '.2', etc. tuple param names (if any)."""
- with check_py3k_warnings(
- ("tuple parameter unpacking has been removed", SyntaxWarning),
- quiet=True):
- code = ("lambda %s: dict(i for i in locals().items() "
- "if not is_tuplename(i[0]))")
- return eval(code % signature, {'is_tuplename' : self.is_tuplename})
+ """Create a function that returns its locals()"""
+ code = "lambda %s: locals()"
+ return eval(code % signature)
def test_plain(self):
f = self.makeCallable('a, b=1')
@@ -683,16 +712,11 @@ class TestGetcallargsFunctions(unittest.TestCase):
self.assertEqualCallArgs(f, '2, **{"b":3}')
self.assertEqualCallArgs(f, '**{"b":3, "a":2}')
# expand UserList / UserDict
- self.assertEqualCallArgs(f, '*UserList([2])')
- self.assertEqualCallArgs(f, '*UserList([2, 3])')
- self.assertEqualCallArgs(f, '**UserDict(a=2)')
- self.assertEqualCallArgs(f, '2, **UserDict(b=3)')
- self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3)')
- # unicode keyword args
- self.assertEqualCallArgs(f, '**{u"a":2}')
- self.assertEqualCallArgs(f, 'b=3, **{u"a":2}')
- self.assertEqualCallArgs(f, '2, **{u"b":3}')
- self.assertEqualCallArgs(f, '**{u"b":3, u"a":2}')
+ self.assertEqualCallArgs(f, '*collections.UserList([2])')
+ self.assertEqualCallArgs(f, '*collections.UserList([2, 3])')
+ self.assertEqualCallArgs(f, '**collections.UserDict(a=2)')
+ self.assertEqualCallArgs(f, '2, **collections.UserDict(b=3)')
+ self.assertEqualCallArgs(f, 'b=2, **collections.UserDict(a=3)')
def test_varargs(self):
f = self.makeCallable('a, b=1, *c')
@@ -701,7 +725,7 @@ class TestGetcallargsFunctions(unittest.TestCase):
self.assertEqualCallArgs(f, '2, 3, 4')
self.assertEqualCallArgs(f, '*(2,3,4)')
self.assertEqualCallArgs(f, '2, *[3,4]')
- self.assertEqualCallArgs(f, '2, 3, *UserList([4])')
+ self.assertEqualCallArgs(f, '2, 3, *collections.UserList([4])')
def test_varkw(self):
f = self.makeCallable('a, b=1, **c')
@@ -711,13 +735,9 @@ class TestGetcallargsFunctions(unittest.TestCase):
self.assertEqualCallArgs(f, 'c=4, **{"a":2, "b":3}')
self.assertEqualCallArgs(f, '2, c=4, **{"b":3}')
self.assertEqualCallArgs(f, 'b=2, **{"a":3, "c":4}')
- self.assertEqualCallArgs(f, '**UserDict(a=2, b=3, c=4)')
- self.assertEqualCallArgs(f, '2, c=4, **UserDict(b=3)')
- self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3, c=4)')
- # unicode keyword args
- self.assertEqualCallArgs(f, 'c=4, **{u"a":2, u"b":3}')
- self.assertEqualCallArgs(f, '2, c=4, **{u"b":3}')
- self.assertEqualCallArgs(f, 'b=2, **{u"a":3, u"c":4}')
+ self.assertEqualCallArgs(f, '**collections.UserDict(a=2, b=3, c=4)')
+ self.assertEqualCallArgs(f, '2, c=4, **collections.UserDict(b=3)')
+ self.assertEqualCallArgs(f, 'b=2, **collections.UserDict(a=3, c=4)')
def test_varkw_only(self):
# issue11256:
@@ -726,29 +746,48 @@ class TestGetcallargsFunctions(unittest.TestCase):
self.assertEqualCallArgs(f, 'a=1')
self.assertEqualCallArgs(f, 'a=1, b=2')
self.assertEqualCallArgs(f, 'c=3, **{"a": 1, "b": 2}')
- self.assertEqualCallArgs(f, '**UserDict(a=1, b=2)')
- self.assertEqualCallArgs(f, 'c=3, **UserDict(a=1, b=2)')
-
- def test_tupleargs(self):
- f = self.makeCallable('(b,c), (d,(e,f))=(0,[1,2])')
- self.assertEqualCallArgs(f, '(2,3)')
- self.assertEqualCallArgs(f, '[2,3]')
- self.assertEqualCallArgs(f, 'UserList([2,3])')
- self.assertEqualCallArgs(f, '(2,3), (4,(5,6))')
- self.assertEqualCallArgs(f, '(2,3), (4,[5,6])')
- self.assertEqualCallArgs(f, '(2,3), [4,UserList([5,6])]')
+ self.assertEqualCallArgs(f, '**collections.UserDict(a=1, b=2)')
+ self.assertEqualCallArgs(f, 'c=3, **collections.UserDict(a=1, b=2)')
+
+ def test_keyword_only(self):
+ f = self.makeCallable('a=3, *, c, d=2')
+ self.assertEqualCallArgs(f, 'c=3')
+ self.assertEqualCallArgs(f, 'c=3, a=3')
+ self.assertEqualCallArgs(f, 'a=2, c=4')
+ self.assertEqualCallArgs(f, '4, c=4')
+ self.assertEqualException(f, '')
+ self.assertEqualException(f, '3')
+ self.assertEqualException(f, 'a=3')
+ self.assertEqualException(f, 'd=4')
+
+ f = self.makeCallable('*, c, d=2')
+ self.assertEqualCallArgs(f, 'c=3')
+ self.assertEqualCallArgs(f, 'c=3, d=4')
+ self.assertEqualCallArgs(f, 'd=4, c=3')
def test_multiple_features(self):
- f = self.makeCallable('a, b=2, (c,(d,e))=(3,[4,5]), *f, **g')
- self.assertEqualCallArgs(f, '2, 3, (4,[5,6]), 7')
- self.assertEqualCallArgs(f, '2, 3, *[(4,[5,6]), 7], x=8')
+ f = self.makeCallable('a, b=2, *f, **g')
+ self.assertEqualCallArgs(f, '2, 3, 7')
+ self.assertEqualCallArgs(f, '2, 3, x=8')
self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]')
self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9')
self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9')
- self.assertEqualCallArgs(f, 'x=8, *UserList([2, 3, (4,[5,6])]), '
- '**{"y":9, "z":10}')
- self.assertEqualCallArgs(f, '2, x=8, *UserList([3, (4,[5,6])]), '
- '**UserDict(y=9, z=10)')
+ self.assertEqualCallArgs(f, 'x=8, *collections.UserList('
+ '[2, 3, (4,[5,6])]), **{"y":9, "z":10}')
+ self.assertEqualCallArgs(f, '2, x=8, *collections.UserList([3, '
+ '(4,[5,6])]), **collections.UserDict('
+ 'y=9, z=10)')
+
+ f = self.makeCallable('a, b=2, *f, x, y=99, **g')
+ self.assertEqualCallArgs(f, '2, 3, x=8')
+ self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]')
+ self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9, z=10')
+ self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9, z=10')
+ self.assertEqualCallArgs(f, 'x=8, *collections.UserList('
+ '[2, 3, (4,[5,6])]), q=0, **{"y":9, "z":10}')
+ self.assertEqualCallArgs(f, '2, x=8, *collections.UserList([3, '
+ '(4,[5,6])]), q=0, **collections.UserDict('
+ 'y=9, z=10)')
def test_errors(self):
f0 = self.makeCallable('')
@@ -771,7 +810,8 @@ class TestGetcallargsFunctions(unittest.TestCase):
self.assertEqualException(f, '2, 3, 4')
self.assertEqualException(f, '1, 2, 3, a=1')
self.assertEqualException(f, '2, 3, 4, c=5')
- self.assertEqualException(f, '2, 3, 4, a=1, c=5')
+ # XXX: success of this one depends on dict order
+ ## self.assertEqualException(f, '2, 3, 4, a=1, c=5')
# f got an unexpected keyword argument
self.assertEqualException(f, 'c=2')
self.assertEqualException(f, '2, c=3')
@@ -786,14 +826,13 @@ class TestGetcallargsFunctions(unittest.TestCase):
# - for functions and bound methods: unexpected keyword 'c'
# - for unbound methods: multiple values for keyword 'a'
#self.assertEqualException(f, '1, c=3, a=2')
- f = self.makeCallable('(a,b)=(0,1)')
- self.assertEqualException(f, '1')
- self.assertEqualException(f, '[1]')
- self.assertEqualException(f, '(1,2,3)')
# issue11256:
f3 = self.makeCallable('**c')
self.assertEqualException(f3, '1, 2')
self.assertEqualException(f3, '1, 2, a=1, b=2')
+ f4 = self.makeCallable('*, a, b=0')
+ self.assertEqualException(f3, '1, 2')
+ self.assertEqualException(f3, '1, 2, a=1, b=2')
class TestGetcallargsMethods(TestGetcallargsFunctions):
@@ -828,12 +867,317 @@ class TestGetcallargsUnboundMethods(TestGetcallargsMethods):
locs = dict(locs or {}, inst=self.inst)
return (func, 'inst,' + call_params_string, locs)
+
+class TestGetattrStatic(unittest.TestCase):
+
+ def test_basic(self):
+ class Thing(object):
+ x = object()
+
+ thing = Thing()
+ self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x)
+ self.assertEqual(inspect.getattr_static(thing, 'x', None), Thing.x)
+ with self.assertRaises(AttributeError):
+ inspect.getattr_static(thing, 'y')
+
+ self.assertEqual(inspect.getattr_static(thing, 'y', 3), 3)
+
+ def test_inherited(self):
+ class Thing(object):
+ x = object()
+ class OtherThing(Thing):
+ pass
+
+ something = OtherThing()
+ self.assertEqual(inspect.getattr_static(something, 'x'), Thing.x)
+
+ def test_instance_attr(self):
+ class Thing(object):
+ x = 2
+ def __init__(self, x):
+ self.x = x
+ thing = Thing(3)
+ self.assertEqual(inspect.getattr_static(thing, 'x'), 3)
+ del thing.x
+ self.assertEqual(inspect.getattr_static(thing, 'x'), 2)
+
+ def test_property(self):
+ class Thing(object):
+ @property
+ def x(self):
+ raise AttributeError("I'm pretending not to exist")
+ thing = Thing()
+ self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x)
+
+ def test_descriptor_raises_AttributeError(self):
+ class descriptor(object):
+ def __get__(*_):
+ raise AttributeError("I'm pretending not to exist")
+ desc = descriptor()
+ class Thing(object):
+ x = desc
+ thing = Thing()
+ self.assertEqual(inspect.getattr_static(thing, 'x'), desc)
+
+ def test_classAttribute(self):
+ class Thing(object):
+ x = object()
+
+ self.assertEqual(inspect.getattr_static(Thing, 'x'), Thing.x)
+
+ def test_inherited_classattribute(self):
+ class Thing(object):
+ x = object()
+ class OtherThing(Thing):
+ pass
+
+ self.assertEqual(inspect.getattr_static(OtherThing, 'x'), Thing.x)
+
+ def test_slots(self):
+ class Thing(object):
+ y = 'bar'
+ __slots__ = ['x']
+ def __init__(self):
+ self.x = 'foo'
+ thing = Thing()
+ self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x)
+ self.assertEqual(inspect.getattr_static(thing, 'y'), 'bar')
+
+ del thing.x
+ self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x)
+
+ def test_metaclass(self):
+ class meta(type):
+ attr = 'foo'
+ class Thing(object, metaclass=meta):
+ pass
+ self.assertEqual(inspect.getattr_static(Thing, 'attr'), 'foo')
+
+ class sub(meta):
+ pass
+ class OtherThing(object, metaclass=sub):
+ x = 3
+ self.assertEqual(inspect.getattr_static(OtherThing, 'attr'), 'foo')
+
+ class OtherOtherThing(OtherThing):
+ pass
+ # this test is odd, but it was added as it exposed a bug
+ self.assertEqual(inspect.getattr_static(OtherOtherThing, 'x'), 3)
+
+ def test_no_dict_no_slots(self):
+ self.assertEqual(inspect.getattr_static(1, 'foo', None), None)
+ self.assertNotEqual(inspect.getattr_static('foo', 'lower'), None)
+
+ def test_no_dict_no_slots_instance_member(self):
+ # returns descriptor
+ with open(__file__) as handle:
+ self.assertEqual(inspect.getattr_static(handle, 'name'), type(handle).name)
+
+ def test_inherited_slots(self):
+ # returns descriptor
+ class Thing(object):
+ __slots__ = ['x']
+ def __init__(self):
+ self.x = 'foo'
+
+ class OtherThing(Thing):
+ pass
+ # it would be nice if this worked...
+ # we get the descriptor instead of the instance attribute
+ self.assertEqual(inspect.getattr_static(OtherThing(), 'x'), Thing.x)
+
+ def test_descriptor(self):
+ class descriptor(object):
+ def __get__(self, instance, owner):
+ return 3
+ class Foo(object):
+ d = descriptor()
+
+ foo = Foo()
+
+ # for a non data descriptor we return the instance attribute
+ foo.__dict__['d'] = 1
+ self.assertEqual(inspect.getattr_static(foo, 'd'), 1)
+
+ # if the descriptor is a data-desciptor we should return the
+ # descriptor
+ descriptor.__set__ = lambda s, i, v: None
+ self.assertEqual(inspect.getattr_static(foo, 'd'), Foo.__dict__['d'])
+
+
+ def test_metaclass_with_descriptor(self):
+ class descriptor(object):
+ def __get__(self, instance, owner):
+ return 3
+ class meta(type):
+ d = descriptor()
+ class Thing(object, metaclass=meta):
+ pass
+ self.assertEqual(inspect.getattr_static(Thing, 'd'), meta.__dict__['d'])
+
+
+ def test_class_as_property(self):
+ class Base(object):
+ foo = 3
+
+ class Something(Base):
+ executed = False
+ @property
+ def __class__(self):
+ self.executed = True
+ return object
+
+ instance = Something()
+ self.assertEqual(inspect.getattr_static(instance, 'foo'), 3)
+ self.assertFalse(instance.executed)
+ self.assertEqual(inspect.getattr_static(Something, 'foo'), 3)
+
+ def test_mro_as_property(self):
+ class Meta(type):
+ @property
+ def __mro__(self):
+ return (object,)
+
+ class Base(object):
+ foo = 3
+
+ class Something(Base, metaclass=Meta):
+ pass
+
+ self.assertEqual(inspect.getattr_static(Something(), 'foo'), 3)
+ self.assertEqual(inspect.getattr_static(Something, 'foo'), 3)
+
+ def test_dict_as_property(self):
+ test = self
+ test.called = False
+
+ class Foo(dict):
+ a = 3
+ @property
+ def __dict__(self):
+ test.called = True
+ return {}
+
+ foo = Foo()
+ foo.a = 4
+ self.assertEqual(inspect.getattr_static(foo, 'a'), 3)
+ self.assertFalse(test.called)
+
+ def test_custom_object_dict(self):
+ test = self
+ test.called = False
+
+ class Custom(dict):
+ def get(self, key, default=None):
+ test.called = True
+ super().get(key, default)
+
+ class Foo(object):
+ a = 3
+ foo = Foo()
+ foo.__dict__ = Custom()
+ self.assertEqual(inspect.getattr_static(foo, 'a'), 3)
+ self.assertFalse(test.called)
+
+ def test_metaclass_dict_as_property(self):
+ class Meta(type):
+ @property
+ def __dict__(self):
+ self.executed = True
+
+ class Thing(metaclass=Meta):
+ executed = False
+
+ def __init__(self):
+ self.spam = 42
+
+ instance = Thing()
+ self.assertEqual(inspect.getattr_static(instance, "spam"), 42)
+ self.assertFalse(Thing.executed)
+
+ def test_module(self):
+ sentinel = object()
+ self.assertIsNot(inspect.getattr_static(sys, "version", sentinel),
+ sentinel)
+
+ def test_metaclass_with_metaclass_with_dict_as_property(self):
+ class MetaMeta(type):
+ @property
+ def __dict__(self):
+ self.executed = True
+ return dict(spam=42)
+
+ class Meta(type, metaclass=MetaMeta):
+ executed = False
+
+ class Thing(metaclass=Meta):
+ pass
+
+ with self.assertRaises(AttributeError):
+ inspect.getattr_static(Thing, "spam")
+ self.assertFalse(Thing.executed)
+
+class TestGetGeneratorState(unittest.TestCase):
+
+ def setUp(self):
+ def number_generator():
+ for number in range(5):
+ yield number
+ self.generator = number_generator()
+
+ def _generatorstate(self):
+ return inspect.getgeneratorstate(self.generator)
+
+ def test_created(self):
+ self.assertEqual(self._generatorstate(), inspect.GEN_CREATED)
+
+ def test_suspended(self):
+ next(self.generator)
+ self.assertEqual(self._generatorstate(), inspect.GEN_SUSPENDED)
+
+ def test_closed_after_exhaustion(self):
+ for i in self.generator:
+ pass
+ self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
+
+ def test_closed_after_immediate_exception(self):
+ with self.assertRaises(RuntimeError):
+ self.generator.throw(RuntimeError)
+ self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
+
+ def test_running(self):
+ # As mentioned on issue #10220, checking for the RUNNING state only
+ # makes sense inside the generator itself.
+ # The following generator checks for this by using the closure's
+ # reference to self and the generator state checking helper method
+ def running_check_generator():
+ for number in range(5):
+ self.assertEqual(self._generatorstate(), inspect.GEN_RUNNING)
+ yield number
+ self.assertEqual(self._generatorstate(), inspect.GEN_RUNNING)
+ self.generator = running_check_generator()
+ # Running up to the first yield
+ next(self.generator)
+ # Running after the first yield
+ next(self.generator)
+
+ def test_easy_debugging(self):
+ # repr() and str() of a generator state should contain the state name
+ names = 'GEN_CREATED GEN_RUNNING GEN_SUSPENDED GEN_CLOSED'.split()
+ for name in names:
+ state = getattr(inspect, name)
+ self.assertIn(name, repr(state))
+ self.assertIn(name, str(state))
+
+
def test_main():
run_unittest(
TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
TestInterpreterStack, TestClassesAndFunctions, TestPredicates,
TestGetcallargsFunctions, TestGetcallargsMethods,
- TestGetcallargsUnboundMethods)
+ TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState,
+ TestNoEOL
+ )
if __name__ == "__main__":
test_main()