Commit 11eb5168 authored by Douglas's avatar Douglas

erp5_data_notebook: moves variables and setup storage from ActiveProcess to...

erp5_data_notebook: moves variables and setup storage from ActiveProcess to `notebook_context` property

Notebook's variables and setup were being stored in an ActiveProcess, which is
not needed anymore, because now everything related to user context can be
safely stored in the ZODB.
They are stored in a `notebook_context` property of the Data Notebook
itself. Code and tests were updated properly. The old `process` property was removed.

All the references to *_variable_dict were renamed to  *_notebook_context, documentation
and tests were updated. Related objects like scripts and external methods were renamed
too.

To store objects in the `notebook_context` property we do 2 different tests: the first
to check if the object can be serialized by `ZODB.serialize.ObjectWriter`. If the first
test fails we test if the object can be serialized by cPickle. For the second test we
need to dump & load the object to be completely sure that it can be correctly loaded
later.

The function called by the Base_runJupyterCode external method was renamed from
Base_compileJupyterCode to Base_runJupyterCode be more consistent and avoid confusion.

All errors while running setup functions and now properly propagated to the user
interface in Jupyter and code execution is aborted.
parent 5eb44e82
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<key> <string>categories</string> </key> <key> <string>categories</string> </key>
<value> <value>
<tuple> <tuple>
<string>elementary_type/string</string> <string>elementary_type/object</string>
</tuple> </tuple>
</value> </value>
</item> </item>
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>local_varibale_property</string> </value> <value> <string>notebook_context_property</string> </value>
</item> </item>
<item> <item>
<key> <string>portal_type</string> </key> <key> <string>portal_type</string> </key>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_function</string> </key> <key> <string>_function</string> </key>
<value> <string>AddNewLocalVariableDict</string> </value> <value> <string>createNotebookContext</string> </value>
</item> </item>
<item> <item>
<key> <string>_module</string> </key> <key> <string>_module</string> </key>
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Base_addLocalVariableDict</string> </value> <value> <string>Base_createNotebookContext</string> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -53,33 +53,30 @@ data_notebook_line = data_notebook.DataNotebook_addDataNotebookLine( ...@@ -53,33 +53,30 @@ data_notebook_line = data_notebook.DataNotebook_addDataNotebookLine(
batch_mode=True batch_mode=True
) )
# Get active_process associated with data_notebook object # Gets the context associated to the data notebook being used
process_id = data_notebook.getProcess() #
active_process = portal.portal_activities[process_id] old_notebook_context = data_notebook.getNotebookContext()
# Add a result object to Active Process object if not old_notebook_context:
result_list = active_process.getResultList() old_notebook_context = portal.Base_createNotebookContext()
# Get local variables saves in Active Result, local varibales are saved as
# persistent mapping object
old_local_variable_dict = result_list[0].summary
if not old_local_variable_dict:
old_local_variable_dict = context.Base_addLocalVariableDict()
# Pass all to code Base_runJupyter external function which would execute the code # Pass all to code Base_runJupyter external function which would execute the code
# and returns a dict of result # and returns a dict of result
final_result = context.Base_runJupyter(python_expression, old_local_variable_dict) final_result = context.Base_runJupyter(python_expression, old_notebook_context)
code_result = final_result['result_string'] code_result = final_result['result_string']
new_local_variable_dict = final_result['local_variable_dict'] new_local_variable_dict = final_result['notebook_context']
ename = final_result['ename'] ename = final_result['ename']
evalue = final_result['evalue'] evalue = final_result['evalue']
traceback = final_result['traceback'] traceback = final_result['traceback']
status = final_result['status'] status = final_result['status']
mime_type = final_result['mime_type'] mime_type = final_result['mime_type']
# Call to function to update persistent mapping object with new local variables # Updates the context in the notebook with the resulting context of code
# and save the variables in the Active Result pertaining to the current Data Notebook # execution.
new_dict = context.Base_updateLocalVariableDict(new_local_variable_dict) #
result_list[0].edit(summary=new_dict) try:
data_notebook.setNotebookContext(new_local_variable_dict)
except Exception as e:
return context.Base_getErrorMessageForException(e, new_local_variable_dict)
result = { result = {
u'code_result': code_result, u'code_result': code_result,
......
...@@ -2,31 +2,25 @@ ...@@ -2,31 +2,25 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Standard Property" module="erp5.portal_type"/> <global name="ExternalMethod" module="Products.ExternalMethod.ExternalMethod"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>categories</string> </key> <key> <string>_function</string> </key>
<value> <value> <string>getErrorMessageForException</string> </value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>_module</string> </key>
<value> <value> <string>JupyterCompile</string> </value>
<none/>
</value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>process_property</string> </value> <value> <string>Base_getErrorMessageForException</string> </value>
</item> </item>
<item> <item>
<key> <string>portal_type</string> </key> <key> <string>title</string> </key>
<value> <string>Standard Property</string> </value> <value> <string></string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_function</string> </key> <key> <string>_function</string> </key>
<value> <string>Base_compileJupyterCode</string> </value> <value> <string>Base_runJupyterCode</string> </value>
</item> </item>
<item> <item>
<key> <string>_module</string> </key> <key> <string>_module</string> </key>
......
""" """
Python script to add a new notebook to Data Notebook module. Python script to add a new notebook to Data Notebook module.
This script also concerns for assigning an Active Process for each data notebook This script also concerns for assigning an empty notebook context for each data
created. notebook created.
""" """
from Products.CMFActivity.ActiveResult import ActiveResult # Creating new context via external method to save results in ZODB
notebook_context = context.Base_createNotebookContext()
# Comment out person in case addition of person required to Data Notebook object
#person = context.ERP5Site_getAuthenticatedMemberPersonValue()
# Create new ActiveProcess object and getting its id
active_process = context.portal_activities.newActiveProcess()
active_process_id = active_process.getId()
# Creating new dictionary via external method to save results in ZODB
new_dict = context.Base_addLocalVariableDict()
# Add new ActiveResult object and add it to the activeprocess concerned with ...
# Data Notebook in concern
result = ActiveResult(summary=new_dict)
active_process.activateResult(result)
# Create new notebook # Create new notebook
notebook = context.newContent( notebook = context.newContent(
title=title, title=title,
reference=reference, reference=reference,
process=active_process_id, notebook_context=notebook_context,
portal_type='Data Notebook' portal_type='Data Notebook'
) )
......
...@@ -110,7 +110,7 @@ portal.%s() ...@@ -110,7 +110,7 @@ portal.%s()
# #
result = portal.Base_runJupyter( result = portal.Base_runJupyter(
jupyter_code=jupyter_code, jupyter_code=jupyter_code,
old_local_variable_dict=portal.Base_addLocalVariableDict() old_notebook_context=portal.Base_createNotebookContext()
) )
self.assertEquals(result['ename'], 'NameError') self.assertEquals(result['ename'], 'NameError')
...@@ -280,10 +280,10 @@ portal.%s() ...@@ -280,10 +280,10 @@ portal.%s()
self.assertEquals(result['ename'], 'NameError') self.assertEquals(result['ename'], 'NameError')
self.assertEquals(result['code_result'], None) self.assertEquals(result['code_result'], None)
def testBaseExecuteJupyterSaveActiveResult(self): def testBaseExecuteJupyterSaveNotebookContext(self):
""" """
Test if the result is being saved inside active_process and the user can Test if user context is being saved in the notebook_context property and the
access the loacl variable and execute python expression on them user can access access and execute python code on it.
""" """
portal = self.portal portal = self.portal
self.login('dev_user') self.login('dev_user')
...@@ -303,12 +303,9 @@ portal.%s() ...@@ -303,12 +303,9 @@ portal.%s()
reference=reference reference=reference
) )
notebook = notebook_list[0] notebook = notebook_list[0]
process_id = notebook.getProcess() notebook_context = notebook.getNotebookContext()['variables']
active_process = portal.portal_activities[process_id]
result_list = active_process.getResultList()
local_variable_dict = result_list[0].summary['variables']
result = {'a':2, 'b':3} result = {'a':2, 'b':3}
self.assertDictContainsSubset(result, local_variable_dict) self.assertDictContainsSubset(result, notebook_context)
def testBaseExecuteJupyterRerunWithPreviousLocalVariables(self): def testBaseExecuteJupyterRerunWithPreviousLocalVariables(self):
""" """
...@@ -340,7 +337,7 @@ portal.%s() ...@@ -340,7 +337,7 @@ portal.%s()
def testSavingModuleObjectLocalVariables(self): def testSavingModuleObjectLocalVariables(self):
""" """
Test to check the saving of module objects in local_variable_dict Test to check the saving of module objects in notebook_context
and if they work as expected. and if they work as expected.
""" """
portal = self.portal portal = self.portal
...@@ -390,13 +387,13 @@ image = context.portal_catalog.getResultValue(portal_type='Image',reference='%s' ...@@ -390,13 +387,13 @@ image = context.portal_catalog.getResultValue(portal_type='Image',reference='%s'
context.Base_renderAsHtml(image) context.Base_renderAsHtml(image)
"""%reference """%reference
local_variable_dict = {'setup' : {}, 'variables' : {}} notebook_context = {'setup' : {}, 'variables' : {}}
result = self.portal.Base_runJupyter( result = self.portal.Base_runJupyter(
jupyter_code=jupyter_code, jupyter_code=jupyter_code,
old_local_variable_dict=local_variable_dict old_notebook_context=notebook_context
) )
self.assertEquals(result['result_string'].rstrip(), data_template % base64.b64encode(data)) self.assertTrue((data_template % base64.b64encode(data)) in result['result_string'])
# Mime_type shouldn't be image/png just because of filename, instead it is # Mime_type shouldn't be image/png just because of filename, instead it is
# dependent on file and file data # dependent on file and file data
self.assertNotEqual(result['mime_type'], 'image/png') self.assertNotEqual(result['mime_type'], 'image/png')
......
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