Commit 3ba2543c authored by Iliya Manolov's avatar Iliya Manolov Committed by Ivan Tyagov

Added a warning about using old references on Jupyter notebooks

@Tyagov @luke 

This MR adds the following to all Jupyter notebooks:
 - A warning when a user inputs a reference that has already been used in one of his old Jupyter notebooks. 
 - Some extra information when entering magics such as the remaining required magics.
 - Entering the reference MUST now be the last magic entered(otherwise the reference check doesn't work).
 - A small addition to the message at the top of the notebook for the command ```%notebook_set_title```

Also, do note that the edited kernel uses files from [this commit](nexedi/erp5@4a3e5173) from my erp5 repo, so the changes there must be available for the kernel to work. [This merge request](nexedi/erp5!283) addresses those changes.

Sample screenshot:
![Screenshot](/uploads/a34e0b70b991302539c572ad4344ba56/Screenshot.png)


/reviewed-on nexedi/slapos!177
parent 660ff50a
...@@ -47,7 +47,7 @@ md5sum = d7d4a7e19d55bf14007819258bf42100 ...@@ -47,7 +47,7 @@ md5sum = d7d4a7e19d55bf14007819258bf42100
[erp5-kernel] [erp5-kernel]
<= download-file-base <= download-file-base
filename = ERP5kernel.py.jinja filename = ERP5kernel.py.jinja
md5sum = 0bcc802a7723b58c1e71269951d751eb md5sum = b5bb94181f7faee42ad18a909a648fe5
[kernel-json] [kernel-json]
<= download-file-base <= download-file-base
...@@ -57,7 +57,7 @@ md5sum = ab6e78ea20855e07d388b5b86d1770fe ...@@ -57,7 +57,7 @@ md5sum = ab6e78ea20855e07d388b5b86d1770fe
[custom-js] [custom-js]
<= download-file-base <= download-file-base
filename = custom.js.jinja filename = custom.js.jinja
md5sum = a851a68667a4e676cfa86b34a86b4239 md5sum = 13561a9d86c488be752795e7bc23474a
[instance-jupyter] [instance-jupyter]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
......
...@@ -106,11 +106,32 @@ class ERP5Kernel(Kernel): ...@@ -106,11 +106,32 @@ class ERP5Kernel(Kernel):
# Get the magic value recived via code from frontend # Get the magic value recived via code from frontend
magic_value = code.split()[1] magic_value = code.split()[1]
# Set magic_value to the required attribute # Set magic_value to the required attribute
if magic_info.magic_name == 'notebook_set_reference':
required_attributes = ['url', 'password', 'user']
missing_attributes = []
for attribute in required_attributes:
if not getattr(self, attribute):
missing_attributes.append(attribute)
if missing_attributes != []:
self.response = "You still haven't entered all required magics. \
Please do so before inputting your reference."
else:
if self.check_existing_reference(reference=magic_value):
self.response = 'WARNING: You already have a notebook with \
reference %s. It might be a good idea to use different references for new \
notebooks. \n' % magic_value
else:
self.response = ''
setattr(self, magic_info.variable_name , magic_value)
self.response = self.response + 'Your %s is %s. '%(magic_info.magic_name, magic_value)
elif magic_info.magic_name != 'erp5_password':
setattr(self, magic_info.variable_name , magic_value) setattr(self, magic_info.variable_name , magic_value)
if magic_info.magic_name != "erp5_password": self.response = 'Your %s is %s. '%(magic_info.magic_name, magic_value)
self.response = 'Your %s is %s.\n'%(magic_info.magic_name, magic_value)
else: else:
self.response = None setattr(self, magic_info.variable_name , magic_value)
self.response = ""
# Catch exception while setting attribute and set message in response # Catch exception while setting attribute and set message in response
except AttributeError: except AttributeError:
...@@ -129,7 +150,8 @@ class ERP5Kernel(Kernel): ...@@ -129,7 +150,8 @@ class ERP5Kernel(Kernel):
# Display the message/response from this fucntion before moving forward so # Display the message/response from this fucntion before moving forward so
# as to keep track of the status # as to keep track of the status
self.display_response(response=self.response) if self.response != "":
self.display_response(response=(self.response + '\n'))
def check_required_attributes(self): def check_required_attributes(self):
""" """
...@@ -141,25 +163,36 @@ class ERP5Kernel(Kernel): ...@@ -141,25 +163,36 @@ class ERP5Kernel(Kernel):
made to ask user to enter value. made to ask user to enter value.
""" """
result_list = [] result_list = []
required_attributes = ['url', 'password', 'user', 'reference'] required_attributes = ['url', 'user', 'password', 'reference']
missing_attributes = []
# Set response to empty so as to flush the response set by some earlier fucntion call # Set response to empty so as to flush the response set by some earlier fucntion call
self.response = '' self.response = ''
# Loop to check if the attributes are set # Loop to check if the required attributes are set
for attribute in required_attributes: for attribute in required_attributes:
if getattr(self, attribute): if getattr(self, attribute):
result_list.append(True) result_list.append(True)
else: else:
# Set response/message for attributes which aren't set # Set response/message for attributes which aren't set
self.response = '\nPlease enter %s in next cell. '%attribute missing_attributes.append(attribute)
result_list.append(False) result_list.append(False)
# Compare result_list to get True for all True results and False for any False result # Compare result_list to get True for all True results and False for any False result
check_attributes = all(result_list) check_attributes = all(result_list)
if check_attributes:
self.response = 'You have entered all required magics. You may now use your notebook.'
else:
self.response = '''You have these required magics remaining: %s. \nYour current \
backend url is %s (you can change it with %serp5_url)''' % (
', '.join(map(str, missing_attributes)),
str(self.url),
'%'
)
# Display response to frontend before moving forward # Display response to frontend before moving forward
self.display_response(response=self.response) self.display_response(response=(self.response + '\n'))
return check_attributes return check_attributes
...@@ -241,7 +274,7 @@ class ERP5Kernel(Kernel): ...@@ -241,7 +274,7 @@ class ERP5Kernel(Kernel):
checked_attribute = self.check_required_attributes() checked_attribute = self.check_required_attributes()
if checked_attribute and magic_info.send_request: if checked_attribute and magic_info.send_request:
# Call the function to send request to erp5 with the arguments given # Call the function to send request to erp5 with the arguments given
self.make_erp5_request(message='\nPlease proceed', self.make_erp5_request(message='Please proceed\n',
request_reference=magic_info.request_reference, request_reference=magic_info.request_reference,
display_message=magic_info.display_message) display_message=magic_info.display_message)
...@@ -249,6 +282,7 @@ class ERP5Kernel(Kernel): ...@@ -249,6 +282,7 @@ class ERP5Kernel(Kernel):
# Since this response would be either success message or failure # Since this response would be either success message or failure
# error message, both of which are string type, so, we can simply # error message, both of which are string type, so, we can simply
# display the stream response. # display the stream response.
if self.response != 'Please proceed\n':
self.display_response(response=self.response) self.display_response(response=self.response)
else: else:
...@@ -341,5 +375,30 @@ class ERP5Kernel(Kernel): ...@@ -341,5 +375,30 @@ class ERP5Kernel(Kernel):
return reply_content return reply_content
# Checks the ERP5 site if there are existing notebooks with the same reference.
# Returns True if there are.
def check_existing_reference(self, reference):
if reference == None:
return False
modified_url = self.url[:self.url.rfind('/')] + '/Base_checkExistingReference'
result = True
try:
erp5_request = requests.post(
modified_url,
verify=False,
auth=(self.user, self.password),
data={
'reference': reference,
})
result = erp5_request.content
except requests.exceptions.RequestException as e:
self.response = str(e)
return result
if __name__ == '__main__': if __name__ == '__main__':
IPKernelApp.launch_instance(kernel_class=ERP5Kernel) IPKernelApp.launch_instance(kernel_class=ERP5Kernel)
...@@ -94,6 +94,7 @@ $([IPython.events]).on('notebook_loaded.Notebook', function(){ ...@@ -94,6 +94,7 @@ $([IPython.events]).on('notebook_loaded.Notebook', function(){
5. As soon as you see 'Please Proceed' message you can now access your erp5 using notebook.</br>\ 5. As soon as you see 'Please Proceed' message you can now access your erp5 using notebook.</br>\
<p><u>OTHER USEFUL MAGICS</u> -</br>\ <p><u>OTHER USEFUL MAGICS</u> -</br>\
<b>%my_notebooks</b> -This is used to display all the notebooks created by the specific user.</br>\ <b>%my_notebooks</b> -This is used to display all the notebooks created by the specific user.</br>\
<b>%notebook_set_title</b> -This sets the title of the current notebook.</br>\
NOTE: Do not dynamically alter imported module objects as they are not being saved in DB, </br>\ NOTE: Do not dynamically alter imported module objects as they are not being saved in DB, </br>\
so changes to them would be disregarded and would throw an error.</br>\ so changes to them would be disregarded and would throw an error.</br>\
<p><u>About classes, functions and global state on modules:</u></p>\ <p><u>About classes, functions and global state on modules:</u></p>\
......
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