'Yury Selivanov <yselivanov@sprymix.com>')
import ast
+import dis
import enum
import importlib.machinery
import itertools
from collections import namedtuple, OrderedDict
# Create constants for the compiler flags in Include/code.h
-# We try to get them from dis to avoid duplication, but fall
-# back to hard-coding so the dependency is optional
-try:
- from dis import COMPILER_FLAG_NAMES as _flag_names
-except ImportError:
- CO_OPTIMIZED, CO_NEWLOCALS = 0x1, 0x2
- CO_VARARGS, CO_VARKEYWORDS = 0x4, 0x8
- CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40
-else:
- mod_dict = globals()
- for k, v in _flag_names.items():
- mod_dict["CO_" + v] = k
+# We try to get them from dis to avoid duplication
+mod_dict = globals()
+for k, v in dis.COMPILER_FLAG_NAMES.items():
+ mod_dict["CO_" + v] = k
# See Include/object.h
TPFLAGS_IS_ABSTRACT = 1 << 20
pass
return lines[:blockfinder.last]
+def _line_number_helper(code_obj, lines, lnum):
+ """Return a list of source lines and starting line number for a code object.
+
+ The arguments must be a code object with lines and lnum from findsource.
+ """
+ _, end_line = list(dis.findlinestarts(code_obj))[-1]
+ return lines[lnum:end_line], lnum + 1
+
def getsourcelines(object):
"""Return a list of source lines and starting line number for an object.
object = unwrap(object)
lines, lnum = findsource(object)
- if ismodule(object): return lines, 0
- else: return getblock(lines[lnum:]), lnum + 1
+ if ismodule(object):
+ return lines, 0
+ elif iscode(object):
+ return _line_number_helper(object, lines, lnum)
+ elif isfunction(object):
+ return _line_number_helper(object.__code__, lines, lnum)
+ elif ismethod(object):
+ return _line_number_helper(object.__func__.__code__, lines, lnum)
+ else:
+ return getblock(lines[lnum:]), lnum + 1
def getsource(object):
"""Return the text of the source code for an object.
finally:
linecache.getlines = getlines
+ def test_getsource_on_code_object(self):
+ self.assertSourceEqual(mod.eggs.__code__, 12, 18)
+
class TestDecorators(GetSourceBase):
fodderModule = mod2
self.assertSourceEqual(mod2.gone, 9, 10)
def test_getsource_unwrap(self):
- self.assertSourceEqual(mod2.real, 122, 124)
+ self.assertSourceEqual(mod2.real, 130, 132)
+
+ def test_decorator_with_lambda(self):
+ self.assertSourceEqual(mod2.func114, 113, 115)
class TestOneliners(GetSourceBase):
fodderModule = mod2
self.assertRaises(IOError, inspect.findsource, co)
self.assertRaises(IOError, inspect.getsource, co)
+ def test_getsource_on_method(self):
+ self.assertSourceEqual(mod2.ClassWithMethod.method, 118, 119)
+
class TestNoEOL(GetSourceBase):
def __init__(self, *args, **kwargs):
self.tempdir = TESTFN + '_dir'