Esempio n. 1
0
class Kernel:
    name: str
    init_code: str = ""
    language: str = ""
    manager: Optional[KernelManager] = field(default=None, init=False)
    client: Optional[KernelClient] = field(default=None, init=False)
    report: Dict[str, Any] = field(default_factory=dict, init=False)

    def __post_init__(self):
        self.report["total"] = datetime.timedelta(0)
        kernel_spec = get_kernel_spec(self.name)
        self.language = kernel_spec.language
        if self.language == "python":
            self.init_code = (
                "from pheasant.renderers.jupyter.ipython import register_formatters\n"
                "register_formatters()")

        def shutdown():  # pragma: no cover
            if self.manager:
                print(f"Shutting down kernel [{self.name}]...", end="")
                self.manager.shutdown_kernel()
                print("Done.")

        atexit.register(shutdown)

    def start(self, timeout=10, silent=True) -> KernelClient:
        if self.manager:
            if self.manager.is_alive():
                return self.client
            else:  # pragma: no cover
                raise RuntimeError(f"Kernel {self.name} is not alive.")

        def start():
            self.manager = KernelManager(kernel_name=self.name)
            self.manager.start_kernel()
            self.client = self.manager.blocking_client()
            self.client.start_channels()
            try:
                self.client.wait_for_ready(timeout=timeout)
            except TimeoutError:  # pragma: no cover
                self.manager.shutdown_kernel()
                return False
            else:
                self.client.execute_interactive(self.init_code)
                return self.client

        init = f"Starting kernel [{self.name}]"
        progress_bar = progress_bar_factory(total=3, init=init)
        now = datetime.datetime.now()

        def message(result):
            dt = format_timedelta_human(datetime.datetime.now() - now)
            return f"Kernel [{self.name}] started ({dt})" if result else "Retrying..."

        for k in range(progress_bar.total):
            if silent and start():
                break
            elif silent:
                continue
            elif progress_bar.progress(start, message):
                progress_bar.finish()
                break
        else:
            raise TimeoutError  # pragma: no cover
        return self.client

    def shutdown(self) -> None:
        if self.manager:
            self.manager.shutdown_kernel()
            del self.client
            self.client = None
            del self.manager
            self.manager = None

    def restart(self) -> None:
        if self.manager:
            self.manager.restart_kernel()
            if self.client and self.init_code:
                self.client.execute_interactive(self.init_code)

    def execute(self, code: str, output_hook=None) -> List:
        client = self.client or self.start()
        outputs = []

        def _output_hook(msg):
            if output_hook:
                output_hook(msg)
            output = output_from_msg(msg)
            if output:
                outputs.append(output)

        msg = client.execute_interactive(code, output_hook=_output_hook)
        update_report(self.report, msg)
        return list(stream_joiner(outputs))

    def inspect(self,
                code: str,
                func: str = "getsource",
                output_hook=None) -> List:
        self.execute("import inspect")
        self.execute(code, output_hook=output_hook)
        outputs = self.execute(code_for_inspect(func))
        if len(outputs) == 1 and outputs[0]["type"] == "execute_result":
            source = ast.literal_eval(outputs[0]["data"]["text/plain"])
            return [dict(type="stream", name="source", text=source)]
        else:
            return outputs