Skip to content

manager

This file implements a jupyter_client KernelManager using the origami library

NoteableKernelManager #

Bases: KernelManagerABC

KernelManager for Noteable client interactions

Source code in papermill_origami/manager.py
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
class NoteableKernelManager(KernelManagerABC):
    """KernelManager for Noteable client interactions"""

    def _requires_client_context(func):
        """A helper for checking if one is in a websocket context or not"""

        @functools.wraps(func)
        async def wrapper(self, *args, **kwargs):
            if not self.client.in_context:
                raise ValueError("Cannot send RTU request outside of a context manager scope.")
            return await func(self, *args, **kwargs)

        return wrapper

    def __init__(
        self, file: NotebookFile, client: NoteableClient, kernel_name: Optional[str] = None, **kw
    ):
        """Sets up basic trackers for the Manager"""
        self.open_context = False
        self.client: NoteableClient = client
        self.file = file

    async def __aenter__(self):
        """Helper for context wrapping the client if so desired"""
        await self.client.__aenter__()
        return self

    async def __aexit__(self, *excinfo):
        """Helper for context wrapping the client if so desired"""
        await self.client.__aexit__(*excinfo)

    @property
    def kernel(self):
        """Returns the session details object holding kernel session info"""
        return self.client.file_session_cache.get(self.file.id)

    # --------------------------------------------------------------------------
    # Expected functions not part of ABC
    # --------------------------------------------------------------------------

    def pre_start_kernel(self, **kw):
        """Can be overwritten to modify kw args. The first return value is always None as
        Noteable does not allow for the kernel command to be overwritten
        """
        return None, kw

    def post_start_kernel(self, **kw) -> None:
        """Can be overwritten to take actions after a kernel cleanup occurs"""
        pass

    # --------------------------------------------------------------------------
    # Kernel management
    # --------------------------------------------------------------------------

    async def async_launch_kernel(self, **kw):
        """Actually launch the kernel

        Override in a subclass to launch kernel subprocesses differently
        """
        import inspect

        func_args = inspect.signature(self.client.get_or_launch_ready_kernel_session).parameters
        filtered_kw = {k: v for k, v in kw.items() if k in func_args}
        filtered_kw.pop('file')  # We're passing it in already
        return await self.client.get_or_launch_ready_kernel_session(self.file, **filtered_kw)

    launch_kernel = run_sync(async_launch_kernel)

    async def async_start_kernel(self, **kw):
        """Launches a new kernel if not already launched"""
        _, kw = self.pre_start_kernel(**kw)
        await self.async_launch_kernel(**kw)
        self.post_start_kernel(**kw)
        return self.kernel

    start_kernel = run_sync(async_start_kernel)

    async def async_shutdown_kernel(self, now=False, restart=False):
        """Shutdown the active or pending kernel pod"""
        await self.client.delete_kernel_session(self.file)

    shutdown_kernel = run_sync(async_shutdown_kernel)

    async def async_restart_kernel(self, now=False, **kw):
        """Restarts a kernel process by forcibly generating a new k8 pod"""
        raise NotImplementedError("TODO")

    restart_kernel = run_sync(async_restart_kernel)

    async def async_has_kernel(self):
        """Causes a request to be made to check on kernel"""
        # TODO: Change to RTU update instead of polling
        session = await self.client.get_kernel_session(self.file)
        return session is not None and not session.kernel.execution_state.is_gone

    has_kernel = run_sync(async_restart_kernel)

    def async_interrupt_kernel(self):
        """Interrupts active execution on a live kernel"""
        raise NotImplementedError("TODO")

    interrupt_kernel = run_sync(async_interrupt_kernel)

    def signal_kernel(self, signum):
        """Not Implemented: Kernel managers can normally forward signals to process based kernels"""
        raise NotImplementedError("Direct process signaling is not allowed for Noteable kernels")

    async def async_is_alive(self):
        """Causes a request to be made to check on kernel"""
        # TODO: Change to RTU update instead of polling
        session = await self.client.get_kernel_session(self.file)
        return session is not None and session.kernel.execution_state.kernel_is_alive

    is_alive = run_sync(async_is_alive)

__aenter__() async #

Helper for context wrapping the client if so desired

Source code in papermill_origami/manager.py
34
35
36
37
async def __aenter__(self):
    """Helper for context wrapping the client if so desired"""
    await self.client.__aenter__()
    return self

__aexit__(*excinfo) async #

Helper for context wrapping the client if so desired

Source code in papermill_origami/manager.py
39
40
41
async def __aexit__(self, *excinfo):
    """Helper for context wrapping the client if so desired"""
    await self.client.__aexit__(*excinfo)

__init__(file, client, kernel_name=None, **kw) #

Sets up basic trackers for the Manager

Source code in papermill_origami/manager.py
26
27
28
29
30
31
32
def __init__(
    self, file: NotebookFile, client: NoteableClient, kernel_name: Optional[str] = None, **kw
):
    """Sets up basic trackers for the Manager"""
    self.open_context = False
    self.client: NoteableClient = client
    self.file = file

async_has_kernel() async #

Causes a request to be made to check on kernel

Source code in papermill_origami/manager.py
101
102
103
104
105
async def async_has_kernel(self):
    """Causes a request to be made to check on kernel"""
    # TODO: Change to RTU update instead of polling
    session = await self.client.get_kernel_session(self.file)
    return session is not None and not session.kernel.execution_state.is_gone

async_interrupt_kernel() #

Interrupts active execution on a live kernel

Source code in papermill_origami/manager.py
109
110
111
def async_interrupt_kernel(self):
    """Interrupts active execution on a live kernel"""
    raise NotImplementedError("TODO")

async_is_alive() async #

Causes a request to be made to check on kernel

Source code in papermill_origami/manager.py
119
120
121
122
123
async def async_is_alive(self):
    """Causes a request to be made to check on kernel"""
    # TODO: Change to RTU update instead of polling
    session = await self.client.get_kernel_session(self.file)
    return session is not None and session.kernel.execution_state.kernel_is_alive

async_launch_kernel(**kw) async #

Actually launch the kernel

Override in a subclass to launch kernel subprocesses differently

Source code in papermill_origami/manager.py
66
67
68
69
70
71
72
73
74
75
76
async def async_launch_kernel(self, **kw):
    """Actually launch the kernel

    Override in a subclass to launch kernel subprocesses differently
    """
    import inspect

    func_args = inspect.signature(self.client.get_or_launch_ready_kernel_session).parameters
    filtered_kw = {k: v for k, v in kw.items() if k in func_args}
    filtered_kw.pop('file')  # We're passing it in already
    return await self.client.get_or_launch_ready_kernel_session(self.file, **filtered_kw)

async_restart_kernel(now=False, **kw) async #

Restarts a kernel process by forcibly generating a new k8 pod

Source code in papermill_origami/manager.py
95
96
97
async def async_restart_kernel(self, now=False, **kw):
    """Restarts a kernel process by forcibly generating a new k8 pod"""
    raise NotImplementedError("TODO")

async_shutdown_kernel(now=False, restart=False) async #

Shutdown the active or pending kernel pod

Source code in papermill_origami/manager.py
89
90
91
async def async_shutdown_kernel(self, now=False, restart=False):
    """Shutdown the active or pending kernel pod"""
    await self.client.delete_kernel_session(self.file)

async_start_kernel(**kw) async #

Launches a new kernel if not already launched

Source code in papermill_origami/manager.py
80
81
82
83
84
85
async def async_start_kernel(self, **kw):
    """Launches a new kernel if not already launched"""
    _, kw = self.pre_start_kernel(**kw)
    await self.async_launch_kernel(**kw)
    self.post_start_kernel(**kw)
    return self.kernel

kernel() property #

Returns the session details object holding kernel session info

Source code in papermill_origami/manager.py
43
44
45
46
@property
def kernel(self):
    """Returns the session details object holding kernel session info"""
    return self.client.file_session_cache.get(self.file.id)

post_start_kernel(**kw) #

Can be overwritten to take actions after a kernel cleanup occurs

Source code in papermill_origami/manager.py
58
59
60
def post_start_kernel(self, **kw) -> None:
    """Can be overwritten to take actions after a kernel cleanup occurs"""
    pass

pre_start_kernel(**kw) #

Can be overwritten to modify kw args. The first return value is always None as Noteable does not allow for the kernel command to be overwritten

Source code in papermill_origami/manager.py
52
53
54
55
56
def pre_start_kernel(self, **kw):
    """Can be overwritten to modify kw args. The first return value is always None as
    Noteable does not allow for the kernel command to be overwritten
    """
    return None, kw

signal_kernel(signum) #

Not Implemented: Kernel managers can normally forward signals to process based kernels

Source code in papermill_origami/manager.py
115
116
117
def signal_kernel(self, signum):
    """Not Implemented: Kernel managers can normally forward signals to process based kernels"""
    raise NotImplementedError("Direct process signaling is not allowed for Noteable kernels")