Commit be879215 authored by Ayush Tiwari's avatar Ayush Tiwari Committed by Douglas

erp5_data_notebook bt5: Handle case for jupyter_code as comments , giving empty nodelist

parent 06a9fb4b
...@@ -58,7 +58,7 @@ def Base_compileJupyterCode(self, jupyter_code, old_local_variable_dict): ...@@ -58,7 +58,7 @@ def Base_compileJupyterCode(self, jupyter_code, old_local_variable_dict):
# Saving the initial globals dict so as to compare it after code execution # Saving the initial globals dict so as to compare it after code execution
globals_dict = globals() globals_dict = globals()
g['context'] = self g['context'] = self
result_string = None result_string = ''
ename, evalue, tb_list = None, None, None ename, evalue, tb_list = None, None, None
# Update globals dict and use it while running exec command # Update globals dict and use it while running exec command
g.update(old_local_variable_dict['variables']) g.update(old_local_variable_dict['variables'])
...@@ -69,87 +69,88 @@ def Base_compileJupyterCode(self, jupyter_code, old_local_variable_dict): ...@@ -69,87 +69,88 @@ def Base_compileJupyterCode(self, jupyter_code, old_local_variable_dict):
# TODO: This can be refactored by using client side error handling instead of # TODO: This can be refactored by using client side error handling instead of
# catching errors on server/erp5. # catching errors on server/erp5.
status = u'ok' status = u'ok'
local_variable_dict = old_local_variable_dict
# Execute only if jupyter_code is not empty # Execute only if jupyter_code is not empty
if jupyter_code: if jupyter_code:
# Import all the modules from local_variable_dict['imports']
# While any execution, in locals() dict, a module is saved as:
# code : 'from os import path'
# {'path': <module 'posixpath'>}
# So, here we would try to get the name 'posixpath' and import it as 'path'
for k, v in old_local_variable_dict['imports'].iteritems():
import_statement_code = 'import %s as %s'%(v, k)
exec(import_statement_code, g, g)
# Create ast parse tree # Create ast parse tree
ast_node = ast.parse(jupyter_code) ast_node = ast.parse(jupyter_code)
# Get the node list from the parsed tree # Get the node list from the parsed tree
nodelist = ast_node.body nodelist = ast_node.body
# If the last node is instance of ast.Expr, set its interactivity as 'last' # Handle case for empty nodelist(in case of comments as jupyter_code)
# This would be the case if the last node is expression if nodelist:
if isinstance(nodelist[-1], ast.Expr): # Import all the modules from local_variable_dict['imports']
interactivity = "last" # While any execution, in locals() dict, a module is saved as:
else: # code : 'from os import path'
interactivity = "none" # {'path': <module 'posixpath'>}
# So, here we would try to get the name 'posixpath' and import it as 'path'
# Here, we define which nodes to execute with 'single' and which to execute for k, v in old_local_variable_dict['imports'].iteritems():
# with 'exec' mode. import_statement_code = 'import %s as %s'%(v, k)
if interactivity == 'none': exec(import_statement_code, g, g)
to_run_exec, to_run_interactive = nodelist, []
elif interactivity == 'last': # If the last node is instance of ast.Expr, set its interactivity as 'last'
to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:] # This would be the case if the last node is expression
if isinstance(nodelist[-1], ast.Expr):
old_stdout = sys.stdout interactivity = "last"
result = StringIO() else:
sys.stdout = result interactivity = "none"
# Execute the nodes with 'exec' mode # Here, we define which nodes to execute with 'single' and which to execute
for node in to_run_exec: # with 'exec' mode.
mod = ast.Module([node]) if interactivity == 'none':
code = compile(mod, '<string>', "exec") to_run_exec, to_run_interactive = nodelist, []
exec(code, g, g) elif interactivity == 'last':
to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
# Execute the interactive nodes with 'single' mode
for node in to_run_interactive: old_stdout = sys.stdout
mod = ast.Interactive([node]) result = StringIO()
code = compile(mod, '<string>', "single") sys.stdout = result
exec(code, g, g)
# Execute the nodes with 'exec' mode
# Letting the code fail in case of error while executing the python script/code for node in to_run_exec:
# XXX: Need to be refactored so to acclimitize transactions failure as well as mod = ast.Module([node])
# normal python code failure and show it to user on jupyter frontend. code = compile(mod, '<string>', "exec")
# Decided to let this fail silently in backend without letting the frontend exec(code, g, g)
# user know the error so as to let tranasction or its error be handled by ZODB
# in uniform way instead of just using half transactions. # Execute the interactive nodes with 'single' mode
for node in to_run_interactive:
sys.stdout = old_stdout mod = ast.Interactive([node])
result_string = result.getvalue() code = compile(mod, '<string>', "single")
else: exec(code, g, g)
result_string = jupyter_code
# Letting the code fail in case of error while executing the python script/code
# Difference between the globals variable before and after exec/eval so that # XXX: Need to be refactored so to acclimitize transactions failure as well as
# we don't have to save unnecessary variables in database which might or might # normal python code failure and show it to user on jupyter frontend.
# not be picklabale # Decided to let this fail silently in backend without letting the frontend
local_variable_dict = old_local_variable_dict # user know the error so as to let tranasction or its error be handled by ZODB
local_variable_dict_new = {key: val for key, val in g.items() if key not in globals_dict.keys()} # in uniform way instead of just using half transactions.
local_variable_dict['variables'].update(local_variable_dict_new)
sys.stdout = old_stdout
# Differentiate 'module' objects from local_variable_dict and save them as result_string = result.getvalue()
# string in the dict as {'imports': {'numpy': 'np', 'matplotlib': 'mp']}
if 'variables' and 'imports' in local_variable_dict: # Difference between the globals variable before and after exec/eval so that
for key, val in local_variable_dict['variables'].items(): # we don't have to save unnecessary variables in database which might or might
# Check if the val in the dict is ModuleType and remove it in case it is # not be picklabale
if isinstance(val, types.ModuleType): local_variable_dict_new = {key: val for key, val in g.items() if key not in globals_dict.keys()}
# Update local_variable_dict['imports'] dictionary with key, value pairs local_variable_dict['variables'].update(local_variable_dict_new)
# with key corresponding to module name as its imported and value as the
# module name being stored in sys.path # Differentiate 'module' objects from local_variable_dict and save them as
# For example : 'np': <numpy module at ...> -- {'np': numpy} # string in the dict as {'imports': {'numpy': 'np', 'matplotlib': 'mp']}
local_variable_dict['imports'][key] = val.__name__ if 'variables' and 'imports' in local_variable_dict:
for key, val in local_variable_dict['variables'].items():
# XXX: The next line is mutating the dict, beware in case any reference # Check if the val in the dict is ModuleType and remove it in case it is
# is made later on to local_variable_dict['variables'] dictionary if isinstance(val, types.ModuleType):
local_variable_dict['variables'].pop(key) # Update local_variable_dict['imports'] dictionary with key, value pairs
# with key corresponding to module name as its imported and value as the
# module name being stored in sys.path
# For example : 'np': <numpy module at ...> -- {'np': numpy}
local_variable_dict['imports'][key] = val.__name__
# XXX: The next line is mutating the dict, beware in case any reference
# is made later on to local_variable_dict['variables'] dictionary
local_variable_dict['variables'].pop(key)
result = { result = {
'result_string': result_string, 'result_string': result_string,
......
...@@ -47,10 +47,10 @@ ...@@ -47,10 +47,10 @@
<value> <value>
<tuple> <tuple>
<string>W: 50, 2: Using the global statement (global-statement)</string> <string>W: 50, 2: Using the global statement (global-statement)</string>
<string>W: 82, 6: Use of exec (exec-used)</string> <string>W: 91, 8: Use of exec (exec-used)</string>
<string>W:111, 6: Use of exec (exec-used)</string> <string>W:115, 8: Use of exec (exec-used)</string>
<string>W:117, 6: Use of exec (exec-used)</string> <string>W:121, 8: Use of exec (exec-used)</string>
<string>W:212, 4: Using the global statement (global-statement)</string> <string>W:213, 4: Using the global statement (global-statement)</string>
</tuple> </tuple>
</value> </value>
</item> </item>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment