/
serialization.py
64 lines (51 loc) · 1.88 KB
/
serialization.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
"""
Hackish workaround to help serialize a pipeline inclusing its functions.
"""
import functools
import inspect
import os
import shutil
import sys
import tempfile
from importlib import import_module, reload
class SerializableFunc:
"""Decorate a function to become independent from its source file.
Should one pickle a mapping object involving a decorated function, the
unpickled mapping will use the original source code for the function
regardless of subsequent modifications to the file on disk.
.. warning::
This is a hackish solution where only the source file
containing the function is saved, regenerated and reloaded.
Use with care.
"""
def __init__(self, func):
if isinstance(func, SerializableFunc):
self.name = func.name
self.source = func.source
self.func = func.func
else:
self.name = func.__name__
filename = inspect.getsourcefile(func)
if filename is None:
raise RuntimeError("failed to locate source file for " + func.__name__)
with open(filename) as dump_file:
self.source = dump_file.read()
self.func = func
functools.update_wrapper(self, func)
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def __getstate__(self):
return self.source, self.name
def __setstate__(self, state):
self.source, self.name = state
tmpdir = tempfile.mkdtemp()
try:
with open(os.path.join(tmpdir, "module.py"), 'w') as dump_file:
dump_file.write(self.source)
sys.path.insert(0, tmpdir)
module = import_module("module")
module = reload(module)
self.func = getattr(module, self.name)
sys.path.pop(0)
finally:
shutil.rmtree(tmpdir)