@@ -1034,7 +1034,8 @@ def apply_compile_fun(target):
1034
1034
def compile_fun_manually (target ,
1035
1035
recurse = True , # type: Union[bool, Callable]
1036
1036
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
1038
1039
):
1039
1040
"""
1040
1041
@@ -1044,12 +1045,27 @@ def compile_fun_manually(target,
1044
1045
if not isinstance (target , FunctionType ):
1045
1046
raise UnsupportedForCompilation ("Only functions can be compiled by this decorator" )
1046
1047
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)
1053
1069
1054
1070
# first make sure that source code is available for compilation
1055
1071
try :
@@ -1070,38 +1086,44 @@ def compile_fun_manually(target,
1070
1086
func_closure = target .func_closure
1071
1087
func_code = target .func_code
1072
1088
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
1105
1127
1106
1128
# now compile from sources
1107
1129
lines = dedent (lines )
0 commit comments