From 2df5868dea5852206aad7be6612e31782d9e147a Mon Sep 17 00:00:00 2001 From: Jon Parise Date: Wed, 17 Aug 2016 11:05:35 -0700 Subject: [PATCH] Assign generated init funcs unique names Previously, all generated init funcs would receive the same name, which made them impossible to differentiate in traces and profiling output. We now assign each function a unique name based on its associated class. Further, we can now add "fake" linecache entries for our generated functions so that debuggers (like PDB) and the traceback module can better understand the generated code. --- tests/test_base.py | 7 +++++++ thriftpy/thrift.py | 15 +++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index 474b9fa..c67dd6e 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- +import linecache + import pytest import thriftpy @@ -68,3 +70,8 @@ def test_parse_spec(): for spec, res in cases: assert parse_spec(*spec) == res + + +def test_init_func(): + thriftpy.load("addressbook.thrift") + assert linecache.getline('', 1) != '' diff --git a/thriftpy/thrift.py b/thriftpy/thrift.py index 6a7744a..bf1db20 100644 --- a/thriftpy/thrift.py +++ b/thriftpy/thrift.py @@ -10,6 +10,7 @@ from __future__ import absolute_import import functools +import linecache import types from ._compat import with_metaclass @@ -39,7 +40,7 @@ def _type(s): return "MAP<%s, %s>" % (_type(spec[0]), _type(spec[1])) -def init_func_generator(spec): +def init_func_generator(cls, spec): """Generate `__init__` function based on TPayload.default_spec For example:: @@ -63,9 +64,14 @@ def __init__(self): init = "def __init__(self, {0}):\n".format(args) init += "\n".join(map(' self.{0} = {0}'.format, varnames)) - code = compile(init, '', 'exec') + name = ''.format(cls.__name__) + code = compile(init, name, 'exec') func = next(c for c in code.co_consts if isinstance(c, types.CodeType)) + # Add a fake linecache entry so debuggers and the traceback module can + # better understand our generated code. + linecache.cache[name] = (len(init), None, init.splitlines(True), name) + return types.FunctionType(func, {}, argdefs=defaults) @@ -122,7 +128,8 @@ class TPayloadMeta(type): def __new__(cls, name, bases, attrs): if "default_spec" in attrs: - attrs["__init__"] = init_func_generator(attrs.pop("default_spec")) + spec = attrs.pop("default_spec") + attrs["__init__"] = init_func_generator(cls, spec) return super(TPayloadMeta, cls).__new__(cls, name, bases, attrs) @@ -131,7 +138,7 @@ def gen_init(cls, thrift_spec=None, default_spec=None): cls.thrift_spec = thrift_spec if default_spec is not None: - cls.__init__ = init_func_generator(default_spec) + cls.__init__ = init_func_generator(cls, default_spec) return cls