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

erp5_data_notebook: python3 support.

Jupyter integration is more or less abandoned. Just do the minimum to make tests pass.
parent e3afb300
...@@ -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
...@@ -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)
...@@ -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':
...@@ -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__
...@@ -903,6 +920,19 @@ class ImportFixer(ast.NodeTransformer): ...@@ -903,6 +920,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)
......
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