def callable_to_dict(c): """ Turn a callable function of class into a dictionary Used for conversion to JSON Parameters ---------- c : callable (function or class with __call__) the function to be turned into a dict representation Returns ------- dict the dict representation of the callable """ f_module = c.__module__ root_module = f_module.split('.')[0] # is_class = isinstance(c, (type, types.ClassType)) # try saving known external classes of functions, e.g. `msmbuilder` if root_module in ObjectJSON.safe_modules: # only store the function/class and the module return { '_module': c.__module__, '_name': c.__name__ } # if the easy way did not work, try saving it using bytecode if ObjectJSON.allow_marshal and callable(c): # use marshal global_vars = ObjectJSON._find_var(c, opcode.opmap['LOAD_GLOBAL']) import_vars = ObjectJSON._find_var(c, opcode.opmap['IMPORT_NAME']) all_builtins = dir(builtins) global_vars = list(set( [var for var in global_vars if var not in all_builtins])) import_vars = list(set(import_vars)) err = '' if len(global_vars) > 0: err += 'The function you try to save relies on globally set ' \ 'variables and these cannot be saved since storage ' \ 'has no access to the global scope which includes ' \ 'imports! \n\n' err += 'We require that the following globals: ' + \ str(global_vars) + ' either\n' err += '\n1. be replaced by constants' err += '\n2. be defined inside your function,' + \ '\n\n' + '\n'.join( map(lambda x: ' ' * 8 + x + '= ...', global_vars) ) + '\n' err += '\n3. imports need to be "re"-imported inside your ' \ 'function' + \ '\n\n' + '\n'.join( map(lambda x: ' ' * 8 + 'import ' + x, global_vars) ) + '\n' err += '\n4. be passed as an external parameter ' \ '(not for imports!)' err += '\n\n my_cv = FunctionCV("cv_name", ' + \ c.func_name + ', \n' + \ ',\n'.join( map(lambda x: ' ' * 20 + x + '=' + x, global_vars) ) + ')' + '\n' err += '\n and change your function definition like this' err += '\n\n def ' + \ c.func_name + '(snapshot, ..., ' + \ '\n' + ',\n'.join( map(lambda x: ' ' * 16 + x, global_vars) ) + '):' unsafe_modules = [ module for module in import_vars if module not in ObjectJSON.safe_modules ] if ObjectJSON.prevent_unsafe_modules and len(unsafe_modules) > 0: if len(err) > 0: err += '\n\n' err += 'The function you try to save requires the following' \ ' modules to be installed: ' + str(unsafe_modules) + \ ' which are not marked as safe! ' err += 'You can change the list of safe modules using ' err += '\n\n ObjectJSON.safe_modules.extend([' err += '\n' + ',\n'.join( map(lambda x: ' ' * 12 + x, unsafe_modules) ) err += '\n ])' err += '\n\n' err += 'include the import statement in your function like' err += '\n\n' + '\n'.join( [' ' * 8 + 'import ' + v for v in unsafe_modules]) if len(err) > 0: raise RuntimeError('Cannot store function! \n\n' + word_wrap(err, 60)) return { '_marshal': ObjectJSON._to_marshal(c), '_global_vars': global_vars, '_module_vars': import_vars } raise RuntimeError('Locally defined classes are not storable yet')
def callable_to_dict(c): """ Turn a callable function of class into a dictionary Used for conversion to JSON Parameters ---------- c : callable (function or class with __call__) the function to be turned into a dict representation Returns ------- dict the dict representation of the callable """ f_module = c.__module__ root_module = f_module.split('.')[0] # is_class = isinstance(c, (type, types.ClassType)) # try saving known external classes of functions, e.g. `msmbuilder` if root_module in ObjectJSON.safe_modules: # only store the function/class and the module return {'_module': c.__module__, '_name': c.__name__} # if the easy way did not work, try saving it using bytecode if ObjectJSON.allow_marshal and callable(c): # use marshal global_vars = ObjectJSON._find_var(c, opcode.opmap['LOAD_GLOBAL']) import_vars = ObjectJSON._find_var(c, opcode.opmap['IMPORT_NAME']) all_builtins = dir(builtins) global_vars = list( set([var for var in global_vars if var not in all_builtins])) import_vars = list(set(import_vars)) err = '' if len(global_vars) > 0: err += 'The function you try to save relies on globally set ' \ 'variables and these cannot be saved since storage ' \ 'has no access to the global scope which includes ' \ 'imports! \n\n' err += 'We require that the following globals: ' + \ str(global_vars) + ' either\n' err += '\n1. be replaced by constants' err += '\n2. be defined inside your function,' + \ '\n\n' + '\n'.join( map(lambda x: ' ' * 8 + x + '= ...', global_vars) ) + '\n' err += '\n3. imports need to be "re"-imported inside your ' \ 'function' + \ '\n\n' + '\n'.join( map(lambda x: ' ' * 8 + 'import ' + x, global_vars) ) + '\n' err += '\n4. be passed as an external parameter ' \ '(not for imports!)' err += '\n\n my_cv = FunctionCV("cv_name", ' + \ get_name(c) + ', \n' + \ ',\n'.join( map(lambda x: ' ' * 20 + x + '=' + x, global_vars) ) + ')' + '\n' err += '\n and change your function definition like this' err += '\n\n def ' + \ get_name(c) + '(snapshot, ..., ' + \ '\n' + ',\n'.join( map(lambda x: ' ' * 16 + x, global_vars) ) + '):' unsafe_modules = [ module for module in import_vars if module not in ObjectJSON.safe_modules ] if ObjectJSON.prevent_unsafe_modules and len(unsafe_modules) > 0: if len(err) > 0: err += '\n\n' err += 'The function you try to save requires the following' \ ' modules to be installed: ' + str(unsafe_modules) + \ ' which are not marked as safe! ' err += 'You can change the list of safe modules using ' err += '\n\n ObjectJSON.safe_modules.extend([' err += '\n' + ',\n'.join( map(lambda x: ' ' * 12 + x, unsafe_modules)) err += '\n ])' err += '\n\n' err += 'include the import statement in your function like' err += '\n\n' + '\n'.join( [' ' * 8 + 'import ' + v for v in unsafe_modules]) if len(err) > 0: raise RuntimeError('Cannot store function! \n\n' + word_wrap(err, 60)) return { '_marshal': ObjectJSON._to_marshal(c), '_global_vars': global_vars, '_module_vars': import_vars } raise RuntimeError('Locally defined classes are not storable yet')