Skip to content

Commit

Permalink
Merge pull request #422 from Jongy/teleport-function-kwdefaults
Browse files Browse the repository at this point in the history
Teleport functions' keyword-only argument defaults
  • Loading branch information
comrumino committed Dec 25, 2020
2 parents 36d80aa + dd88a47 commit 28be845
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 16 deletions.
31 changes: 17 additions & 14 deletions rpyc/utils/teleportation.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import opcode
import sys
try:
import __builtin__
except ImportError:
import builtins as __builtin__ # noqa: F401

from rpyc.lib.compat import is_py_gte38
from types import CodeType, FunctionType
from rpyc.core import brine, netref
Expand Down Expand Up @@ -67,16 +63,21 @@ def _export_codeobj(cobj):


def export_function(func):
func_closure = func.__closure__
func_code = func.__code__
func_defaults = func.__defaults__

if func_closure:
closure = func.__closure__
code = func.__code__
defaults = func.__defaults__
kwdefaults = func.__kwdefaults__
if kwdefaults is not None:
kwdefaults = tuple(kwdefaults.items())

if closure:
raise TypeError("Cannot export a function closure")
if not brine.dumpable(func_defaults):
raise TypeError("Cannot export a function with non-brinable defaults (func_defaults)")
if not brine.dumpable(defaults):
raise TypeError("Cannot export a function with non-brinable defaults (__defaults__)")
if not brine.dumpable(kwdefaults):
raise TypeError("Cannot export a function with non-brinable defaults (__kwdefaults__)")

return func.__name__, func.__module__, func_defaults, _export_codeobj(func_code)[1]
return func.__name__, func.__module__, defaults, kwdefaults, _export_codeobj(code)[1]


def _import_codetup(codetup):
Expand Down Expand Up @@ -106,7 +107,7 @@ def _import_codetup(codetup):


def import_function(functup, globals=None, def_=True):
name, modname, defaults, codetup = functup
name, modname, defaults, kwdefaults, codetup = functup
if globals is None:
try:
mod = __import__(modname, None, None, "*")
Expand All @@ -120,6 +121,8 @@ def import_function(functup, globals=None, def_=True):
globals.setdefault('__builtins__', __builtins__)
codeobj = _import_codetup(codetup)
funcobj = FunctionType(codeobj, globals, name, defaults)
if kwdefaults is not None:
funcobj.__kwdefaults__ = {t[0]: t[1] for t in kwdefaults}
if def_:
globals[name] = funcobj
return funcobj
20 changes: 18 additions & 2 deletions tests/test_teleportation.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def g(b):
return g


def defaults(a=5, b="hi", c=(5.5, )):
return a, b, c


def kwdefaults(pos=5, *, a=42, b="bye", c=(12.4, )):
return pos, a, b, c


def h(a):
import os
return a * os.getpid()
Expand Down Expand Up @@ -82,6 +90,14 @@ def test_def(self):
self.assertEqual(foo_(), 43)
self.assertEqual(bar_(), 42)

def test_defaults(self):
defaults_ = teleport_function(self.conn, defaults)
self.assertEqual(defaults_(), defaults())

def test_kwdefaults(self):
kwdefaults_ = teleport_function(self.conn, kwdefaults)
self.assertEqual(kwdefaults_(), kwdefaults())

def test_compat(self): # assumes func has only brineable types

def get37_schema(cobj):
Expand All @@ -101,8 +117,8 @@ def get38_schema(cobj):
pow38 = lambda x, y : x ** y # noqa
export37 = get37_schema(pow37.__code__)
export38 = get38_schema(pow38.__code__)
schema37 = (pow37.__name__, pow37.__module__, pow37.__defaults__, export37)
schema38 = (pow38.__name__, pow38.__module__, pow38.__defaults__, export38)
schema37 = (pow37.__name__, pow37.__module__, pow37.__defaults__, pow37.__kwdefaults__, export37)
schema38 = (pow38.__name__, pow38.__module__, pow38.__defaults__, pow38.__kwdefaults__, export38)
pow37_netref = self.conn.modules["rpyc.utils.teleportation"].import_function(schema37)
pow38_netref = self.conn.modules["rpyc.utils.teleportation"].import_function(schema38)
self.assertEqual(pow37_netref(2, 3), pow37(2, 3))
Expand Down

0 comments on commit 28be845

Please sign in to comment.