From cf1a9ac320717f5db042130eb995e42f1e3d3a6c Mon Sep 17 00:00:00 2001 From: Zev Benjamin Date: Thu, 24 Sep 2015 15:08:48 -0700 Subject: Ensure each generated function has a unique filename Some profilers (such as cProfile) depend on the tuple of (, , ) being unique. If the filenames of generated functions are all the same, such profilers can produce incorrect profiles. --- src/decorator.py | 11 ++++++++++- src/tests/test.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/decorator.py b/src/decorator.py index 7a8b232..9264998 100644 --- a/src/decorator.py +++ b/src/decorator.py @@ -87,6 +87,10 @@ class FunctionMaker(object): It has attributes name, doc, module, signature, defaults, dict and methods update and make. """ + + # Atomic get-and-increment provided by the GIL + _compile_count = itertools.count() + def __init__(self, func=None, name=None, signature=None, defaults=None, doc=None, module=None, funcdict=None): self.shortsignature = signature @@ -176,8 +180,13 @@ class FunctionMaker(object): raise NameError('%s is overridden in\n%s' % (n, src)) if not src.endswith('\n'): # add a newline just for safety src += '\n' # this is needed in old versions of Python + + # Ensure each generated function has a unique filename for profilers + # (such as cProfile) that depend on the tuple of (, + # , ) being unique. + filename = '' % (next(self._compile_count),) try: - code = compile(src, '', 'single') + code = compile(src, filename, 'single') exec(code, evaldict) except: print('Error in generated code:', file=sys.stderr) diff --git a/src/tests/test.py b/src/tests/test.py index 45a9b9b..ab65dfa 100644 --- a/src/tests/test.py +++ b/src/tests/test.py @@ -6,7 +6,7 @@ import decimal import inspect import functools import collections -from decorator import dispatch_on, contextmanager +from decorator import dispatch_on, contextmanager, decorator try: from . import documentation as doc except (SystemError, ValueError): @@ -52,6 +52,33 @@ class ExtraTestCase(unittest.TestCase): sig = inspect.signature(doc.f1) self.assertEqual(str(sig), '(x)') + def test_unique_filenames(self): + @decorator + def d1(f, *args, **kwargs): + return f(*args, **kwargs) + + @decorator + def d2(f, *args, **kwargs): + return f(*args, **kwargs) + + @d1 + def f1(x, y, z): + pass + + @d2 + def f2(x, y, z): + pass + + f1_orig = f1 + + @d1 + def f1(x, y, z): + pass + + self.assertNotEqual(d1.__code__.co_filename, d2.__code__.co_filename) + self.assertNotEqual(f1.__code__.co_filename, f2.__code__.co_filename) + self.assertNotEqual(f1_orig.__code__.co_filename, f1.__code__.co_filename) + # ################### test dispatch_on ############################# # # adapted from test_functools in Python 3.5 singledispatch = dispatch_on('obj') -- cgit v1.2.1