Commit faff3a73 authored by Jérome Perrin's avatar Jérome Perrin Committed by Arnaud Fontaine

data_notebook: py3

parent ef5d482e
...@@ -17,7 +17,7 @@ import Acquisition ...@@ -17,7 +17,7 @@ import Acquisition
import astor import astor
import importlib import importlib
from erp5.component.module.Log import log from erp5.component.module.Log import log
from Products.ERP5Type.Utils import ensure_list from Products.ERP5Type.Utils import ensure_list, str2bytes
# Display matplotlib figure automatically like # Display matplotlib figure automatically like
# the original python kernel # the original python kernel
...@@ -447,7 +447,7 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context): ...@@ -447,7 +447,7 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context):
"_result = %s()\n" "_result = %s()\n"
"if _result and isinstance(_result, dict):\n" "if _result and isinstance(_result, dict):\n"
" globals().update(_result)\n" " globals().update(_result)\n"
"_volatile_variable_list += _result.keys()\n" "_volatile_variable_list += list(_result.keys())\n"
"del %s, _result\n" "del %s, _result\n"
) % (data['code'], func_name, func_name) ) % (data['code'], func_name, func_name)
notebook_context['setup'][data['alias']] = { notebook_context['setup'][data['alias']] = {
...@@ -468,7 +468,10 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context): ...@@ -468,7 +468,10 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context):
# Execute the nodes with 'exec' mode # Execute the nodes with 'exec' mode
for node in to_run_exec: for node in to_run_exec:
if six.PY2:
mod = ast.Module([node]) mod = ast.Module([node])
else:
mod = ast.Module([node], [])
code = compile(mod, '<string>', "exec") code = compile(mod, '<string>', "exec")
try: try:
exec(code, user_context, user_context) exec(code, user_context, user_context)
...@@ -500,8 +503,8 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context): ...@@ -500,8 +503,8 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context):
volatile_variable_list = ensure_list(current_setup_dict.keys()) + ensure_list(inject_variable_dict.keys()) + user_context.get('_volatile_variable_list', []) volatile_variable_list = ensure_list(current_setup_dict.keys()) + ensure_list(inject_variable_dict.keys()) + user_context.get('_volatile_variable_list', [])
volatile_variable_list.append('__builtins__') volatile_variable_list.append('__builtins__')
for key, val in user_context.items(): for key, val in ensure_list(user_context.items()):
if not key in globals_dict.keys() and not isinstance(val, well_known_unserializable_type_tuple) and not key in volatile_variable_list: if key not in globals_dict and not isinstance(val, well_known_unserializable_type_tuple) and not key in volatile_variable_list:
if canSerialize(val): if canSerialize(val):
notebook_context['variables'][key] = val notebook_context['variables'][key] = val
else: else:
...@@ -516,7 +519,7 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context): ...@@ -516,7 +519,7 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context):
# Deleting from the variable storage the keys that are not in the user # Deleting from the variable storage the keys that are not in the user
# context anymore (i.e., variables that are deleted by the user). # context anymore (i.e., variables that are deleted by the user).
for key in notebook_context['variables'].keys(): for key in ensure_list(notebook_context['variables'].keys()):
if not key in user_context: if not key in user_context:
del notebook_context['variables'][key] del notebook_context['variables'][key]
...@@ -612,20 +615,30 @@ class CustomPrint(object): ...@@ -612,20 +615,30 @@ class CustomPrint(object):
def __init__(self): def __init__(self):
self.captured_output_list = [] self.captured_output_list = []
def write(self, *args): def write(self, *args): # BBB PY2
self.captured_output_list += args self.captured_output_list += args
def __call__ (self, *args, **kw):
self.captured_output_list.extend(args)
self.captured_output_list.append(kw.get("end", "\n"))
def getCapturedOutputString(self): def getCapturedOutputString(self):
return ''.join(self.captured_output_list) return ''.join(str(o) for o in self.captured_output_list)
class PrintFixer(ast.NodeTransformer): class PrintFixer(ast.NodeTransformer):
def visit_Print(self, node): def visit_Print(self, node): # BBB PY2
_print_name_node = ast.Name(id="_print", ctx=ast.Load()) _print_name_node = ast.Name(id="_print", ctx=ast.Load())
node.dest = _print_name_node node.dest = _print_name_node
return node return node
def visit_Call(self, node):
# XXX this assumes that print was not renamed
if isinstance(node.func, ast.Name) and node.func.id == "print":
node.func.id = "_print"
return node
class EnvironmentParser(ast.NodeTransformer): class EnvironmentParser(ast.NodeTransformer):
""" """
...@@ -706,6 +719,8 @@ class EnvironmentParser(ast.NodeTransformer): ...@@ -706,6 +719,8 @@ class EnvironmentParser(ast.NodeTransformer):
ast.Str: lambda node: node.s, ast.Str: lambda node: node.s,
ast.Name: lambda node: node.id ast.Name: lambda node: node.id
} }
if six.PY3:
node_value_dict[ast.Constant] = lambda node: node.value
arg_value = node_value_dict[type(arg_value_node)](arg_value_node) arg_value = node_value_dict[type(arg_value_node)](arg_value_node)
self.environment_var_dict[arg_name] = arg_value self.environment_var_dict[arg_name] = arg_value
elif name == 'environment' and function.attr == 'undefine': elif name == 'environment' and function.attr == 'undefine':
...@@ -769,7 +784,7 @@ class Environment(object): ...@@ -769,7 +784,7 @@ class Environment(object):
class ImportFixer(ast.NodeTransformer): class ImportFixer(ast.NodeTransformer):
""" """
The ImportFixer class is responsivle for fixing "normal" imports that users The ImportFixer class is responsible for fixing "normal" imports that users
might try to execute. might try to execute.
It will automatically replace them with the proper usage of the environment It will automatically replace them with the proper usage of the environment
...@@ -782,7 +797,7 @@ class ImportFixer(ast.NodeTransformer): ...@@ -782,7 +797,7 @@ class ImportFixer(ast.NodeTransformer):
def visit_FunctionDef(self, node): def visit_FunctionDef(self, node):
""" """
Processes funcion definition nodes. We want to store a list of all the Processes function definition nodes. We want to store a list of all the
import that are inside functions, because they do not affect the outter import that are inside functions, because they do not affect the outter
user context, thus do not imply in any un-pickleable variable being added user context, thus do not imply in any un-pickleable variable being added
there. there.
...@@ -816,12 +831,14 @@ class ImportFixer(ast.NodeTransformer): ...@@ -816,12 +831,14 @@ class ImportFixer(ast.NodeTransformer):
module_names = [] module_names = []
star_import_used = False
if getattr(node, "module", None) is not None: if getattr(node, "module", None) is not None:
# case when 'from <module_name> import <something>' # case when 'from <module_name> import <something>'
root_module_name = node.module root_module_name = node.module
if (node.names[0].name == '*'): if (node.names[0].name == '*'):
# case when "from <module_name> import *" # case when "from <module_name> import *"
star_import_used = True
mod = importlib.import_module(node.module) mod = importlib.import_module(node.module)
tmp_dict = mod.__dict__ tmp_dict = mod.__dict__
...@@ -846,27 +863,25 @@ class ImportFixer(ast.NodeTransformer): ...@@ -846,27 +863,25 @@ class ImportFixer(ast.NodeTransformer):
test_import_string = "from %s import " %(node.module) test_import_string = "from %s import " %(node.module)
for i in range(0, len(original_names)): for i in range(0, len(original_names)):
test_import_string = test_import_string + original_names[i] test_import_string = test_import_string + original_names[i]
if as_names[i]!=None: if as_names[i] is not None:
test_import_string = test_import_string + ' as %s' %(as_names[i]) test_import_string = test_import_string + ' as %s' %(as_names[i])
test_import_string = test_import_string + ', ' test_import_string = test_import_string + ', '
test_import_string = test_import_string[:-2] test_import_string = test_import_string[:-2]
module_names = [] module_names = []
for i in range(0, len(original_names)): for i in range(0, len(original_names)):
if as_names[i]!=None: if as_names[i] is not None:
module_names.append(as_names[i]) module_names.append(as_names[i])
else: else:
module_names.append(original_names[i]) module_names.append(original_names[i])
for i in range(0, len(original_names)): for i in range(0, len(original_names)):
if as_names[i]!=None: if as_names[i] is not None:
result_name = result_name + '%s_' %(as_names[i]) result_name = result_name + '%s_' %(as_names[i])
else: else:
result_name = result_name + '%s_' %(original_names[i]) result_name = result_name + '%s_' %(original_names[i])
result_name = result_name[:-1] result_name = result_name[:-1]
elif getattr(node.names[0], 'asname'): elif getattr(node.names[0], 'asname'):
# case when "import <module_name> as <name>"" # case when "import <module_name> as <name>""
module_names = [(node.names[0].asname), ] module_names = [(node.names[0].asname), ]
...@@ -878,7 +893,7 @@ class ImportFixer(ast.NodeTransformer): ...@@ -878,7 +893,7 @@ class ImportFixer(ast.NodeTransformer):
else: else:
# case when "import <module_name>" # case when "import <module_name>"
module_names = [(node.names[0].name), ] module_names = [(node.names[0].name), ]
test_import_string = "import %s" %node.names[0].name test_import_string = "import %s" % node.names[0].name
result_name = node.names[0].name result_name = node.names[0].name
root_module_name = node.names[0].name root_module_name = node.names[0].name
...@@ -903,6 +918,19 @@ class ImportFixer(ast.NodeTransformer): ...@@ -903,6 +918,19 @@ class ImportFixer(ast.NodeTransformer):
empty_function = self.newEmptyFunction("%s_setup" %dotless_result_name) empty_function = self.newEmptyFunction("%s_setup" %dotless_result_name)
return_dict = self.newReturnDict(final_module_names) return_dict = self.newReturnDict(final_module_names)
if six.PY3 and star_import_used:
# since we are generating a function on the fly, we can not generate something
# like this, because star import are only allowed at module level:
# def f():
# from mod import *
# in that case we transform the ast to something like:
# def f():
# from mod import a, b, c
#
# this would be more correct to do it on python 2, but this triggers an error
# ( AttributeError: 'alias' object has no attribute 'asname' ) in astor codegen,
# so we ignore this on python 2.
node.names = [ast.alias(name=n) for n in final_module_names]
empty_function.body = [node, return_dict] empty_function.body = [node, return_dict]
environment_set = self.newEnvironmentSetCall("%s_setup" %dotless_result_name) environment_set = self.newEnvironmentSetCall("%s_setup" %dotless_result_name)
self.newImportWarningCall(root_module_name, dotless_result_name) self.newImportWarningCall(root_module_name, dotless_result_name)
...@@ -1050,7 +1078,7 @@ class ERP5ImageProcessor(ObjectProcessor): ...@@ -1050,7 +1078,7 @@ class ERP5ImageProcessor(ObjectProcessor):
def process(self): def process(self):
from base64 import b64encode from base64 import b64encode
figure_data = b64encode(self.subject.getData()) figure_data = b64encode(self.subject.getData()).decode()
mime_type = self.subject.getContentType() mime_type = self.subject.getContentType()
return '<img src="data:%s;base64,%s" /><br />' % (mime_type, figure_data), 'text/html' return '<img src="data:%s;base64,%s" /><br />' % (mime_type, figure_data), 'text/html'
...@@ -1193,7 +1221,7 @@ def erp5PivotTableUI(self, df): ...@@ -1193,7 +1221,7 @@ def erp5PivotTableUI(self, df):
""" """
html_string = template % df.to_csv() html_string = template % df.to_csv()
from hashlib import sha512 from hashlib import sha512
key = sha512(html_string).hexdigest() key = sha512(str2bytes(html_string)).hexdigest()
storeIFrame(self, html_string, key) storeIFrame(self, html_string, key)
iframe_host = self.REQUEST['HTTP_X_FORWARDED_HOST'].split(',')[0] iframe_host = self.REQUEST['HTTP_X_FORWARDED_HOST'].split(',')[0]
url = "https://%s/erp5/Base_displayPivotTableFrame?key=%s" % (iframe_host, key) url = "https://%s/erp5/Base_displayPivotTableFrame?key=%s" % (iframe_host, key)
......
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