Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
140
Merge Requests
140
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
erp5
Commits
42bdc7a0
Commit
42bdc7a0
authored
Apr 03, 2024
by
Jérome Perrin
Committed by
Arnaud Fontaine
Jul 31, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
data_notebook: py3
parent
75d7d9bb
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
47 additions
and
19 deletions
+47
-19
bt5/erp5_data_notebook/ExtensionTemplateItem/portal_components/extension.erp5.JupyterCompile.py
...teItem/portal_components/extension.erp5.JupyterCompile.py
+47
-19
No files found.
bt5/erp5_data_notebook/ExtensionTemplateItem/portal_components/extension.erp5.JupyterCompile.py
View file @
42bdc7a0
...
...
@@ -17,7 +17,7 @@ import Acquisition
import
astor
import
importlib
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
# the original python kernel
...
...
@@ -447,7 +447,7 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context):
"_result = %s()
\
n
"
"if _result and isinstance(_result, dict):
\
n
"
" globals().update(_result)
\
n
"
"_volatile_variable_list +=
_result.keys(
)
\
n
"
"_volatile_variable_list +=
list(_result.keys()
)
\
n
"
"del %s, _result
\
n
"
)
%
(
data
[
'code'
],
func_name
,
func_name
)
notebook_context
[
'setup'
][
data
[
'alias'
]]
=
{
...
...
@@ -468,7 +468,10 @@ def Base_runJupyterCode(self, jupyter_code, old_notebook_context):
# Execute the nodes with 'exec' mode
for
node
in
to_run_exec
:
mod
=
ast
.
Module
([
node
])
if
six
.
PY2
:
mod
=
ast
.
Module
([
node
])
else
:
mod
=
ast
.
Module
([
node
],
[])
code
=
compile
(
mod
,
'<string>'
,
"exec"
)
try
:
exec
(
code
,
user_context
,
user_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
.
append
(
'__builtins__'
)
for
key
,
val
in
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
:
for
key
,
val
in
ensure_list
(
user_context
.
items
()
):
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
):
notebook_context
[
'variables'
][
key
]
=
val
else
:
...
...
@@ -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
# 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
:
del
notebook_context
[
'variables'
][
key
]
...
...
@@ -612,20 +615,30 @@ class CustomPrint(object):
def
__init__
(
self
):
self
.
captured_output_list
=
[]
def
write
(
self
,
*
args
):
def
write
(
self
,
*
args
):
# BBB PY2
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
):
return
''
.
join
(
self
.
captured_output_list
)
return
''
.
join
(
s
tr
(
o
)
for
o
in
s
elf
.
captured_output_list
)
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
())
node
.
dest
=
_print_name_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
):
"""
...
...
@@ -706,6 +719,8 @@ class EnvironmentParser(ast.NodeTransformer):
ast
.
Str
:
lambda
node
:
node
.
s
,
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
)
self
.
environment_var_dict
[
arg_name
]
=
arg_value
elif
name
==
'environment'
and
function
.
attr
==
'undefine'
:
...
...
@@ -769,7 +784,7 @@ class Environment(object):
class
ImportFixer
(
ast
.
NodeTransformer
):
"""
The ImportFixer class is responsi
v
le for fixing "normal" imports that users
The ImportFixer class is responsi
b
le for fixing "normal" imports that users
might try to execute.
It will automatically replace them with the proper usage of the environment
...
...
@@ -782,7 +797,7 @@ class ImportFixer(ast.NodeTransformer):
def
visit_FunctionDef
(
self
,
node
):
"""
Processes funcion definition nodes. We want to store a list of all the
Processes func
t
ion definition nodes. We want to store a list of all the
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
there.
...
...
@@ -816,12 +831,14 @@ class ImportFixer(ast.NodeTransformer):
module_names
=
[]
star_import_used
=
False
if
getattr
(
node
,
"module"
,
None
)
is
not
None
:
# case when 'from <module_name> import <something>'
root_module_name
=
node
.
module
if
(
node
.
names
[
0
].
name
==
'*'
):
# case when "from <module_name> import *"
star_import_used
=
True
mod
=
importlib
.
import_module
(
node
.
module
)
tmp_dict
=
mod
.
__dict__
...
...
@@ -846,27 +863,25 @@ class ImportFixer(ast.NodeTransformer):
test_import_string
=
"from %s import "
%
(
node
.
module
)
for
i
in
range
(
0
,
len
(
original_names
)):
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
+
', '
test_import_string
=
test_import_string
[:
-
2
]
module_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
])
else
:
module_names
.
append
(
original_names
[
i
])
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
])
else
:
result_name
=
result_name
+
'%s_'
%
(
original_names
[
i
])
result_name
=
result_name
[:
-
1
]
elif
getattr
(
node
.
names
[
0
],
'asname'
):
# case when "import <module_name> as <name>""
module_names
=
[(
node
.
names
[
0
].
asname
),
]
...
...
@@ -878,7 +893,7 @@ class ImportFixer(ast.NodeTransformer):
else
:
# case when "import <module_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
root_module_name
=
node
.
names
[
0
].
name
...
...
@@ -903,6 +918,19 @@ class ImportFixer(ast.NodeTransformer):
empty_function
=
self
.
newEmptyFunction
(
"%s_setup"
%
dotless_result_name
)
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
]
environment_set
=
self
.
newEnvironmentSetCall
(
"%s_setup"
%
dotless_result_name
)
self
.
newImportWarningCall
(
root_module_name
,
dotless_result_name
)
...
...
@@ -1050,7 +1078,7 @@ class ERP5ImageProcessor(ObjectProcessor):
def
process
(
self
):
from
base64
import
b64encode
figure_data
=
b64encode
(
self
.
subject
.
getData
())
figure_data
=
b64encode
(
self
.
subject
.
getData
())
.
decode
()
mime_type
=
self
.
subject
.
getContentType
()
return
'<img src="data:%s;base64,%s" /><br />'
%
(
mime_type
,
figure_data
),
'text/html'
...
...
@@ -1193,7 +1221,7 @@ def erp5PivotTableUI(self, df):
"""
html_string
=
template
%
df
.
to_csv
()
from
hashlib
import
sha512
key
=
sha512
(
html_string
).
hexdigest
()
key
=
sha512
(
str2bytes
(
html_string
)
).
hexdigest
()
storeIFrame
(
self
,
html_string
,
key
)
iframe_host
=
self
.
REQUEST
[
'HTTP_X_FORWARDED_HOST'
].
split
(
','
)[
0
]
url
=
"https://%s/erp5/Base_displayPivotTableFrame?key=%s"
%
(
iframe_host
,
key
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment