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

Dynamically compile spec'd __init__ functions #210

Merged
merged 1 commit into from
Jun 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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