Skip to content
This repository has been archived by the owner on Dec 10, 2018. It is now read-only.

Commit

Permalink
Merge pull request #210 from jparise/init-compile
Browse files Browse the repository at this point in the history
Dynamically compile spec'd __init__ functions
  • Loading branch information
lxyu authored Jun 28, 2016
2 parents 5aa0b90 + 5661d15 commit ec10dca
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 68 deletions.
67 changes: 0 additions & 67 deletions thriftpy/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import platform
import sys
import types

PY3 = sys.version_info[0] == 3
PYPY = "__pypy__" in sys.modules
Expand Down Expand Up @@ -58,69 +57,3 @@ def __new__(cls, name, this_bases, d):
return type.__new__(cls, name, (), d)
return meta(name, bases, d)
return metaclass('temporary_class', None, {})


def init_func_generator(spec):
"""Generate `__init__` function based on TPayload.default_spec
For example::
spec = [('name', 'Alice'), ('number', None)]
will generate::
def __init__(self, name='Alice', number=None):
kwargs = locals()
kwargs.pop('self')
self.__dict__.update(kwargs)
TODO: The `locals()` part may need refine.
"""
if not spec:
def __init__(self):
pass
return __init__

varnames, defaults = zip(*spec)
varnames = ('self', ) + varnames

def init(self):
self.__dict__ = locals().copy()
del self.__dict__['self']

code = init.__code__
if PY3:
new_code = types.CodeType(len(varnames),
0,
len(varnames),
code.co_stacksize,
code.co_flags,
code.co_code,
code.co_consts,
code.co_names,
varnames,
code.co_filename,
"__init__",
code.co_firstlineno,
code.co_lnotab,
code.co_freevars,
code.co_cellvars)
else:
new_code = types.CodeType(len(varnames),
len(varnames),
code.co_stacksize,
code.co_flags,
code.co_code,
code.co_consts,
code.co_names,
varnames,
code.co_filename,
"__init__",
code.co_firstlineno,
code.co_lnotab,
code.co_freevars,
code.co_cellvars)

return types.FunctionType(new_code,
{"__builtins__": __builtins__},
argdefs=defaults)
33 changes: 32 additions & 1 deletion thriftpy/thrift.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
from __future__ import absolute_import

import functools
import types

from ._compat import init_func_generator, with_metaclass
from ._compat import with_metaclass


def args2kwargs(thrift_spec, *args):
Expand All @@ -38,6 +39,36 @@ def _type(s):
return "MAP<%s, %s>" % (_type(spec[0]), _type(spec[1]))


def init_func_generator(spec):
"""Generate `__init__` function based on TPayload.default_spec
For example::
spec = [('name', 'Alice'), ('number', None)]
will generate a types.FunctionType object representing::
def __init__(self, name='Alice', number=None):
self.name = name
self.number = number
"""
if not spec:
def __init__(self):
pass
return __init__

varnames, defaults = zip(*spec)

args = ', '.join(map('{0[0]}={0[1]!r}'.format, spec))
init = "def __init__(self, {0}):\n".format(args)
init += "\n".join(map(' self.{0} = {0}'.format, varnames))

code = compile(init, '<init_func_generator>', 'exec')
func = next(c for c in code.co_consts if isinstance(c, types.CodeType))

return types.FunctionType(func, {}, argdefs=defaults)


class TType(object):
STOP = 0
VOID = 1
Expand Down

0 comments on commit ec10dca

Please sign in to comment.