class test_CodeBuild_Jupyter_Helper(Test_Helper): def setUp(self): super().setUp() self.api = CodeBuild_Jupyter_Helper() self.result = None def tearDown(self): if self.result: Dev.pprint(self.result) def test_get_active_build_id(self): self.result = self.api.get_active_build_id() def test_get_active_builds(self): builds = self.api.get_active_builds() print() for id, build in builds.items(): #assert build.build_status() == 'IN_PROGRESS' #assert build.build_phase() == 'BUILD' # need to improve the resilience of this test print(id, build.build_status(), build.build_phase()) def test_start_build(self): result = self.api.start_build() Dev.pprint(result.build_info()) def test_start_build_and_wait_for_jupyter_load(self): result = self.api.start_build_and_wait_for_jupyter_load() Dev.pprint(result.build_status()) def test_start_build_for_repo__server_size(self): repo = 'gs-notebook-gscs' self.api.start_build_for_repo(repo, server_size='small') self.api.start_build_for_repo(repo, server_size='medium') self.api.start_build_for_repo(repo, server_size='large') def test_start_build_for_repo_and_wait_for_jupyter_load(self): repo = 'gwbot-jupyter-notebooks' self.result = self.api.start_build_for_repo_and_wait_for_jupyter_load( repo) def test_stop_all_active(self): result = CodeBuild_Jupyter_Helper().stop_all_active() Dev.pprint("stopped builds {0}".format(result)) def test_save_active_server_details(self): tmp_file = '/tmp/active_jupyter_server.yml' self.result = self.api.save_active_server_details(tmp_file) def test_gw_repo_start_build_for_repo__server_size(self): repo_name = 'gwbot-jupyter-notebooks' self.result = self.api.start_build_for_repo(repo_name, server_size='medium')
class Live_Notebook: def __init__(self, short_id=None, headless=True): self.headless = headless self.short_id = None self.build_id = None self._browser = None self._code_build_Jupyter = None self._jupyter_cell = None self._jupyter_web = None self._jupyter_api = None self._server_details = None self._needs_login = True self.jupyter_helper = CodeBuild_Jupyter_Helper() self.execute_python_file = 'notebooks/setup/gsbot-invoke.ipynb' if short_id: self.set_build_from_short_id(short_id) # global objects def browser( self ): # we have make sure there is only one instance of browser created if self._browser is None: from osbot_browser.browser.Browser_Lamdba_Helper import Browser_Lamdba_Helper browser_helper = Browser_Lamdba_Helper( headless=self.headless).setup() self._browser = browser_helper.api_browser return self._browser def jupyter_cell(self): if self._jupyter_cell is None: server, token = self.server_details() self._jupyter_cell = Jupyter_Web_Cell(server=server, token=token, headless=self.headless, browser=self.browser()) return self._jupyter_cell def jupyter_web(self): if self._jupyter_web is None: server, token = self.server_details() self._jupyter_web = Jupyter_Web(server=server, token=token, headless=self.headless, browser=self.browser()) return self._jupyter_web def jupyter_api(self): if self._jupyter_api is None: server, token = self.server_details() self._jupyter_api = Jupyter_API(server=server, token=token) return self._jupyter_api # config methods def set_build_id(self, build_id): self.build_id = build_id return self def set_build_from_short_id(self, short_id): if short_id and type(short_id) is str: active_builds = self.jupyter_helper.get_active_builds() if active_builds: for build_id, build in active_builds.items(): if short_id in build_id: # search on build_id self.build_id = build_id self.short_id = short_id return self repo_name = build.build_environment_variables().get( 'repo_name') # search on repo_name if short_id in repo_name: self.build_id = build_id self.short_id = build_id # in this case use the actual build id as the short id return self return None def code_build_Jupyter(self): if self._code_build_Jupyter is None and self.build_id: self._code_build_Jupyter = CodeBuild_Jupyter(self.build_id) return self._code_build_Jupyter # # NOT WORKING IN LAMBDA (I think it is because the Javascript is not being executed ok) # def execute_python(self, python_code,keep_contents=True, target=None): # jp_web = self.jupyter_web() # jp_cell = self.jupyter_cell() # the prob is the browser object is being created twice # if target is None: # target = self.execute_python_file # if (target in jp_web.url()) is False: # jp_web.open(target) # if not keep_contents: # jp_cell.clear() # jp_cell.execute(python_code) # #jp_cell.new() # #jp_cell.text('some content') # return jp_cell.output_wait_for_data() def server_details(self): if self._server_details is None: if self.code_build_Jupyter(): self._server_details = self.code_build_Jupyter( ).get_server_details_from_logs() return self._server_details # api Methods def files(self, path=''): text_body = "" data = self.jupyter_api().contents(path) if data is None: text_title = ":red_circle: Folder `{0}` not found in server `{1}`".format( path, self.short_id) else: if path == '': path = '/' files = [] folders = [] text_title = ":point_right: Here are the files and folders for `{0}` in the server `{1}`".format( path, data.get('type'), self.short_id) for item in data.get('content'): url = "{0}/tree/{1}".format(self.jupyter_api().server, item.get('path')) url_preview = "{0}/{1}".format( self.jupyter_web().server, self.jupyter_web().resolve_url_notebook_preview( item.get('path'))) if item.get('type') == 'directory': #folders.append("<{0}|{1}> (<{2}|preview>)".format(url,item.get('name'), url_preview)) folders.append("<{0}|{1}>".format(url, item.get('name'))) else: files.append( " - {0} (<{1}|edit> , <{2}|preview>)\n".format( item.get('name'), url, url_preview)) #files.append("<{0}|{1}>".format(url,item.get('name'))) if files: text_body += '*Files:* \n{0}\n\n'.format(''.join(files)) if folders: text_body += '*Folders:* {0}'.format(' , '.join(folders)) return text_title, text_body def screenshot(self, path=None, width=None, height=None, delay=None, apply_ui_fixes=True): jupyter_web = self.login() (jupyter_web.open(path).browser_size(width, height).wait_seconds(delay)) jupyter_web.ui_add_jquery() if apply_ui_fixes: jupyter_web.ui_css_fixes(width) if path and 'osbot-no-code' in path: jupyter_web.ui_hide_input_boxes() return jupyter_web.screenshot_base64() def login(self): if self._needs_login is True: self.jupyter_web().login() self._needs_login = False return self.jupyter_web() def stop(self): return self.code_build_Jupyter().code_build.codebuild.stop_build( id=self.build_id).get('build') def execute_python_in_notebook(self, target_notebook, code, source_event): self.login() self.jupyter_web().open(target_notebook) self.jupyter_cell().wait_seconds(1) # refactor with better method self.jupyter_cell().new_top() \ .to_markdown() \ .text("### Code above requested by: \n ```{0}```".format(source_event)) \ .execute() result = self.jupyter_cell().execute_python( code).output_wait_for_data() self.jupyter_cell().save_notebook() return result def get_python_invoke_file(self): today = '{0}'.format(datetime.date.today().strftime('%d-%b-%y')) target_notebook = 'users/gsbot/invoke-{0}.ipynb'.format(today) created = False if self.jupyter_api().contents( target_notebook) is None: # we need to create the file self.jupyter_api().notebook_create(target_notebook) created = True target_notebook = "notebooks/{0}".format(target_notebook) return target_notebook, created