mirror of
https://github.com/micropython/micropython.git
synced 2026-01-29 07:10:17 +01:00
This commit adds support to the `marshal` module to be able to dump
functions that have child functions. For example:
import marshal
def f():
def child():
return 1
return child
marshal.dumps(f.__code__)
It also covers the case of marshalling functions that use list
comprehensions, because a list comprehension uses a child function.
This is made possible by the newly enhanced
`mp_raw_code_save_fun_to_bytes()` that can now handle nested functions.
Unmarshalling via `marshal.loads()` already supports nested functions
because it uses the standard `mp_raw_code_load_mem()` function which is
used to import mpy files (and hence can handle all possibilities).
Signed-off-by: Damien George <damien@micropython.org>
80 lines
1.7 KiB
Python
80 lines
1.7 KiB
Python
# Test the marshal module, with functions that have children.
|
|
|
|
try:
|
|
import marshal
|
|
|
|
(lambda: 0).__code__
|
|
except (AttributeError, ImportError):
|
|
print("SKIP")
|
|
raise SystemExit
|
|
|
|
|
|
def f_with_child():
|
|
def child():
|
|
return a
|
|
|
|
return child
|
|
|
|
|
|
def f_with_child_defargs():
|
|
def child(a="default"):
|
|
return a
|
|
|
|
return child
|
|
|
|
|
|
def f_with_child_closure():
|
|
a = "closure 1"
|
|
|
|
def child():
|
|
return a
|
|
|
|
a = "closure 2"
|
|
return child
|
|
|
|
|
|
def f_with_child_closure_defargs():
|
|
a = "closure defargs 1"
|
|
|
|
def child(b="defargs default"):
|
|
return (a, b)
|
|
|
|
a = "closure defargs 1"
|
|
return child
|
|
|
|
|
|
def f_with_list_comprehension(a):
|
|
return [i + a for i in range(4)]
|
|
|
|
|
|
ftype = type(lambda: 0)
|
|
|
|
# Test function with a child.
|
|
f = ftype(marshal.loads(marshal.dumps(f_with_child.__code__)), {"a": "global"})
|
|
print(f()())
|
|
|
|
# Test function with a child that has default arguments.
|
|
f = ftype(marshal.loads(marshal.dumps(f_with_child_defargs.__code__)), {})
|
|
print(f()())
|
|
print(f()("non-default"))
|
|
|
|
# Test function with a child that is a closure.
|
|
f = ftype(marshal.loads(marshal.dumps(f_with_child_closure.__code__)), {})
|
|
print(f()())
|
|
|
|
# Test function with a child that is a closure and has default arguments.
|
|
f = ftype(marshal.loads(marshal.dumps(f_with_child_closure_defargs.__code__)), {})
|
|
print(f()())
|
|
print(f()("defargs non-default"))
|
|
|
|
# Test function with a list comprehension (which will be an anonymous child).
|
|
f = ftype(marshal.loads(marshal.dumps(f_with_list_comprehension.__code__)), {})
|
|
print(f(10))
|
|
|
|
# Test child within a module (the outer scope).
|
|
code = compile("def child(a): return a", "", "exec")
|
|
f = marshal.loads(marshal.dumps(code))
|
|
ctx = {}
|
|
exec(f, ctx)
|
|
print(ctx["child"]("arg"))
|