예제 #1
0
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')
예제 #2
0
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