Skip to content

Commit 44a0251

Browse files
author
Sylvain MARIE
committed
Work in progress to try to fix #52
1 parent 54e0205 commit 44a0251

File tree

1 file changed

+61
-39
lines changed

1 file changed

+61
-39
lines changed

makefun/main.py

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,8 @@ def apply_compile_fun(target):
10341034
def compile_fun_manually(target,
10351035
recurse=True, # type: Union[bool, Callable]
10361036
except_names=(), # type: Iterable[str]
1037-
_evaldict=None # type: Union[bool, Dict]
1037+
_evaldict=None, # type: Union[bool, Dict]
1038+
_nested_call=False # type: bool
10381039
):
10391040
"""
10401041
@@ -1044,12 +1045,27 @@ def compile_fun_manually(target,
10441045
if not isinstance(target, FunctionType):
10451046
raise UnsupportedForCompilation("Only functions can be compiled by this decorator")
10461047

1047-
if _evaldict is None or _evaldict is True:
1048-
if _evaldict is True:
1049-
frame = _get_callerframe(offset=1)
1050-
else:
1051-
frame = _get_callerframe()
1052-
_evaldict, _ = extract_module_and_evaldict(frame)
1048+
if not _nested_call:
1049+
# top call - grab the eval dict from the frame
1050+
if _evaldict is None or _evaldict is True:
1051+
if _evaldict is True:
1052+
frame = _get_callerframe(offset=1)
1053+
else:
1054+
frame = _get_callerframe()
1055+
_evaldict, module_name = extract_module_and_evaldict(frame)
1056+
1057+
if target.__module__ != module_name:
1058+
if hasattr(target, '__globals__'):
1059+
_evaldict = copy(target.__globals__)
1060+
# else:
1061+
# advanced - provided by user
1062+
else:
1063+
# nested: TODO should we propagate the eval dict ? How ? what about locals ?
1064+
# Note: this should be done bu
1065+
if hasattr(target, '__globals__'):
1066+
_evaldict = copy(_evaldict)
1067+
_evaldict.update(target.__globals__)
1068+
# TODO if value is a class, no __globals__ exist (they do on the functions only)
10531069

10541070
# first make sure that source code is available for compilation
10551071
try:
@@ -1070,38 +1086,44 @@ def compile_fun_manually(target,
10701086
func_closure = target.func_closure
10711087
func_code = target.func_code
10721088

1073-
# Does not work: if `self.i` is used in the code, `i` will appear here
1074-
# if func_code is not None:
1075-
# for name in func_code.co_names:
1076-
# try:
1077-
# eval(name, _evaldict)
1078-
# except NameError:
1079-
# raise UndefinedSymbolError("Symbol `%s` does not seem to be defined yet. Make sure you apply "
1080-
# "`compile_fun` *after* all required symbols have been defined." % name)
1081-
1082-
if recurse and func_closure is not None:
1083-
# recurse-compile
1084-
for name, cell in zip(func_code.co_freevars, func_closure):
1085-
if name in except_names:
1086-
continue
1087-
if name not in _evaldict:
1088-
raise UndefinedSymbolError("Symbol %s does not seem to be defined yet. Make sure you apply "
1089-
"`compile_fun` *after* all required symbols have been defined." % name)
1090-
try:
1091-
value = cell.cell_contents
1092-
except ValueError:
1093-
# empty cell
1094-
continue
1095-
else:
1096-
# non-empty cell
1097-
try:
1098-
# note : not sure the compilation will be made in the appropriate order of dependencies...
1099-
# if not, users will have to do it manually
1100-
_evaldict[name] = compile_fun_manually(value,
1101-
recurse=recurse, except_names=except_names,
1102-
_evaldict=_evaldict)
1103-
except (UnsupportedForCompilation, SourceUnavailable):
1104-
pass
1089+
if recurse:
1090+
# recurse-compile used symbols
1091+
# already compiled since part of the source
1092+
# - co_varnames: everything created locally, including args -
1093+
# - co_cellvars: local variables that are referenced by nested functions
1094+
# to compile:
1095+
# - co_freevars: non-local variables that are referenced by nested functions
1096+
# - co_names: global variables used by the bytecode, local names in the class scope, attribute names, names of
1097+
# imported modules, etc. see https://github.com/python/cpython/pull/2743
1098+
if func_code is not None:
1099+
for names, raise_if_unknown in ((func_code.co_freevars, True),
1100+
(func_code.co_names, False) # we can't do this now: this triggers some strange bugs with the docstrings and other things. see deopatch tests.
1101+
):
1102+
for name in names:
1103+
if name in except_names:
1104+
continue
1105+
try:
1106+
value = _evaldict[name]
1107+
except KeyError:
1108+
if raise_if_unknown:
1109+
raise UndefinedSymbolError("Symbol %s does not seem to be defined yet. Make sure you apply "
1110+
"`compile_fun` *after* all required symbols have been defined."
1111+
% name)
1112+
else:
1113+
# names in co_names can be attribute names, e.g. 'i' if self.i is used. So unknown will
1114+
# happen.
1115+
continue
1116+
else:
1117+
try:
1118+
#
1119+
1120+
# note : not sure the compilation will be made in the appropriate order of dependencies...
1121+
# if not, users will have to do it manually
1122+
_evaldict[name] = compile_fun_manually(value,
1123+
recurse=recurse, except_names=except_names,
1124+
_evaldict=_evaldict, _nested_call=True)
1125+
except (UnsupportedForCompilation, SourceUnavailable):
1126+
pass
11051127

11061128
# now compile from sources
11071129
lines = dedent(lines)

0 commit comments

Comments
 (0)