summaryrefslogtreecommitdiffstats
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.py586
1 files changed, 549 insertions, 37 deletions
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 34e0a9a..f5dff1e 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -1,3 +1,4 @@
+import re
import sys
import types
import unittest
@@ -5,9 +6,11 @@ import inspect
import linecache
import datetime
import collections
+import os
+import shutil
from os.path import normcase
-from test.support import TESTFN, run_unittest
+from test.support import run_unittest, TESTFN, DirsOnSysPath
from test import inspect_fodder as mod
from test import inspect_fodder2 as mod2
@@ -118,8 +121,8 @@ class TestPredicates(IsTestBase):
x = C()
x.a = 42
members = dict(inspect.getmembers(x))
- self.assertTrue('a' in members)
- self.assertTrue('b' not in members)
+ self.assertIn('a', members)
+ self.assertNotIn('b', members)
def test_isabstract(self):
from abc import ABCMeta, abstractmethod
@@ -193,12 +196,12 @@ class TestInterpreterStack(IsTestBase):
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):
@@ -210,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)
@@ -237,6 +240,8 @@ class TestRetrievingSourceCode(GetSourceBase):
self.assertEqual(functions, [('eggs', mod.eggs),
('spam', mod.spam)])
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
def test_getdoc(self):
self.assertEqual(inspect.getdoc(mod), 'A module docstring.')
self.assertEqual(inspect.getdoc(mod.StupidGit),
@@ -294,7 +299,7 @@ class TestRetrievingSourceCode(GetSourceBase):
inspect.getmodule(compile('a=10','','single'))
class TestDecorators(GetSourceBase):
- fodderFile = mod2
+ fodderModule = mod2
def test_wrapped_decorator(self):
self.assertSourceEqual(mod2.wrapped, 14, 17)
@@ -303,7 +308,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)
@@ -345,7 +350,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)
@@ -385,6 +390,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)
+
# Helper for testing classify_class_attrs.
def attrs_wo_objs(cls):
return [t[:3] for t in inspect.classify_class_attrs(cls)]
@@ -486,25 +509,25 @@ class TestClassesAndFunctions(unittest.TestCase):
datablob = '1'
attrs = attrs_wo_objs(A)
- self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
- self.assertTrue(('c', 'class method', A) in attrs, 'missing class method')
- self.assertTrue(('p', 'property', A) in attrs, 'missing property')
- self.assertTrue(('m', 'method', A) in attrs,
- 'missing plain method: %r' % attrs)
- self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
- self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
+ 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: %r' % attrs)
+ self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
+ self.assertIn(('datablob', 'data', A), attrs, 'missing data')
class B(A):
def m(self): pass
attrs = attrs_wo_objs(B)
- self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
- self.assertTrue(('c', 'class method', A) in attrs, 'missing class method')
- self.assertTrue(('p', 'property', A) in attrs, 'missing property')
- self.assertTrue(('m', 'method', B) in attrs, 'missing plain method')
- self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
- self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
+ 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', B), attrs, 'missing plain method')
+ self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
+ self.assertIn(('datablob', 'data', A), attrs, 'missing data')
class C(A):
@@ -513,29 +536,518 @@ class TestClassesAndFunctions(unittest.TestCase):
def c(self): pass
attrs = attrs_wo_objs(C)
- self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
- self.assertTrue(('c', 'method', C) in attrs, 'missing plain method')
- self.assertTrue(('p', 'property', A) in attrs, 'missing property')
- self.assertTrue(('m', 'method', C) in attrs, 'missing plain method')
- self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
- self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
+ self.assertIn(('s', 'static method', A), attrs, 'missing static method')
+ self.assertIn(('c', 'method', C), attrs, 'missing plain method')
+ self.assertIn(('p', 'property', A), attrs, 'missing property')
+ self.assertIn(('m', 'method', C), attrs, 'missing plain method')
+ self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
+ self.assertIn(('datablob', 'data', A), attrs, 'missing data')
class D(B, C):
def m1(self): pass
attrs = attrs_wo_objs(D)
- self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
- self.assertTrue(('c', 'method', C) in attrs, 'missing plain method')
- self.assertTrue(('p', 'property', A) in attrs, 'missing property')
- self.assertTrue(('m', 'method', B) in attrs, 'missing plain method')
- self.assertTrue(('m1', 'method', D) in attrs, 'missing plain method')
- self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
+ self.assertIn(('s', 'static method', A), attrs, 'missing static 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')
+ self.assertIn(('datablob', 'data', A), attrs, 'missing data')
+
+class TestGetcallargsFunctions(unittest.TestCase):
+
+ def assertEqualCallArgs(self, func, call_params_string, locs=None):
+ locs = dict(locs or {}, func=func)
+ r1 = eval('func(%s)' % call_params_string, None, locs)
+ r2 = eval('inspect.getcallargs(func, %s)' % call_params_string, None,
+ locs)
+ self.assertEqual(r1, r2)
+
+ def assertEqualException(self, func, call_param_string, locs=None):
+ locs = dict(locs or {}, func=func)
+ try:
+ eval('func(%s)' % call_param_string, None, locs)
+ 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 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()"""
+ code = "lambda %s: locals()"
+ return eval(code % signature)
+
+ def test_plain(self):
+ f = self.makeCallable('a, b=1')
+ self.assertEqualCallArgs(f, '2')
+ self.assertEqualCallArgs(f, '2, 3')
+ self.assertEqualCallArgs(f, 'a=2')
+ self.assertEqualCallArgs(f, 'b=3, a=2')
+ self.assertEqualCallArgs(f, '2, b=3')
+ # expand *iterable / **mapping
+ self.assertEqualCallArgs(f, '*(2,)')
+ self.assertEqualCallArgs(f, '*[2]')
+ self.assertEqualCallArgs(f, '*(2, 3)')
+ self.assertEqualCallArgs(f, '*[2, 3]')
+ self.assertEqualCallArgs(f, '**{"a":2}')
+ self.assertEqualCallArgs(f, 'b=3, **{"a":2}')
+ self.assertEqualCallArgs(f, '2, **{"b":3}')
+ self.assertEqualCallArgs(f, '**{"b":3, "a":2}')
+ # expand UserList / UserDict
+ 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')
+ self.assertEqualCallArgs(f, '2')
+ self.assertEqualCallArgs(f, '2, 3')
+ self.assertEqualCallArgs(f, '2, 3, 4')
+ self.assertEqualCallArgs(f, '*(2,3,4)')
+ self.assertEqualCallArgs(f, '2, *[3,4]')
+ self.assertEqualCallArgs(f, '2, 3, *collections.UserList([4])')
+
+ def test_varkw(self):
+ f = self.makeCallable('a, b=1, **c')
+ self.assertEqualCallArgs(f, 'a=2')
+ self.assertEqualCallArgs(f, '2, b=3, c=4')
+ self.assertEqualCallArgs(f, 'b=3, a=2, c=4')
+ 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, '**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:
+ f = self.makeCallable('**c')
+ self.assertEqualCallArgs(f, '')
+ self.assertEqualCallArgs(f, 'a=1')
+ self.assertEqualCallArgs(f, 'a=1, b=2')
+ self.assertEqualCallArgs(f, 'c=3, **{"a": 1, "b": 2}')
+ 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, *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, *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('')
+ f1 = self.makeCallable('a, b')
+ f2 = self.makeCallable('a, b=1')
+ # f0 takes no arguments
+ self.assertEqualException(f0, '1')
+ self.assertEqualException(f0, 'x=1')
+ self.assertEqualException(f0, '1,x=1')
+ # f1 takes exactly 2 arguments
+ self.assertEqualException(f1, '')
+ self.assertEqualException(f1, '1')
+ self.assertEqualException(f1, 'a=2')
+ self.assertEqualException(f1, 'b=3')
+ # f2 takes at least 1 argument
+ self.assertEqualException(f2, '')
+ self.assertEqualException(f2, 'b=3')
+ for f in f1, f2:
+ # f1/f2 takes exactly/at most 2 arguments
+ 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')
+ # f got an unexpected keyword argument
+ self.assertEqualException(f, 'c=2')
+ self.assertEqualException(f, '2, c=3')
+ self.assertEqualException(f, '2, 3, c=4')
+ self.assertEqualException(f, '2, c=4, b=3')
+ self.assertEqualException(f, '**{u"\u03c0\u03b9": 4}')
+ # f got multiple values for keyword argument
+ self.assertEqualException(f, '1, a=2')
+ self.assertEqualException(f, '1, **{"a":2}')
+ self.assertEqualException(f, '1, 2, b=3')
+ # XXX: Python inconsistency
+ # - for functions and bound methods: unexpected keyword 'c'
+ # - for unbound methods: multiple values for keyword 'a'
+ #self.assertEqualException(f, '1, c=3, a=2')
+ # 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):
+
+ def setUp(self):
+ class Foo(object):
+ pass
+ self.cls = Foo
+ self.inst = Foo()
+
+ def makeCallable(self, signature):
+ assert 'self' not in signature
+ mk = super(TestGetcallargsMethods, self).makeCallable
+ self.cls.method = mk('self, ' + signature)
+ return self.inst.method
+
+class TestGetcallargsUnboundMethods(TestGetcallargsMethods):
+
+ def makeCallable(self, signature):
+ super(TestGetcallargsUnboundMethods, self).makeCallable(signature)
+ return self.cls.method
+
+ def assertEqualCallArgs(self, func, call_params_string, locs=None):
+ return super(TestGetcallargsUnboundMethods, self).assertEqualCallArgs(
+ *self._getAssertEqualParams(func, call_params_string, locs))
+
+ def assertEqualException(self, func, call_params_string, locs=None):
+ return super(TestGetcallargsUnboundMethods, self).assertEqualException(
+ *self._getAssertEqualParams(func, call_params_string, locs))
+
+ def _getAssertEqualParams(self, func, call_params_string, locs=None):
+ assert 'inst' not in call_params_string
+ 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)
+
+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)
+ run_unittest(
+ TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
+ TestInterpreterStack, TestClassesAndFunctions, TestPredicates,
+ TestGetcallargsFunctions, TestGetcallargsMethods,
+ TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState,
+ TestNoEOL
+ )
if __name__ == "__main__":
test_main()