kernel-checkpoint 0.1.1__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/PKG-INFO +1 -1
  2. kernel_checkpoint-0.1.3/cursor_jupyterlab_extension_for_checkpo.md +257 -0
  3. kernel_checkpoint-0.1.3/jupyter-notebook-image/Dockerfile +9 -0
  4. kernel_checkpoint-0.1.3/kernel_checkpoint/__init__.py +94 -0
  5. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/kernel_checkpoint/_version.py +1 -1
  6. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/kernel_checkpoint/handlers.py +3 -3
  7. kernel_checkpoint-0.1.3/kernel_checkpoint/labextension/build_log.json +716 -0
  8. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/kernel_checkpoint/labextension/package.json +2 -2
  9. kernel_checkpoint-0.1.3/kernel_checkpoint/labextension/static/lib_index_js.bcb2d92b281a36765a67.js +508 -0
  10. kernel_checkpoint-0.1.3/kernel_checkpoint/labextension/static/lib_index_js.bcb2d92b281a36765a67.js.map +1 -0
  11. kernel_checkpoint-0.1.3/kernel_checkpoint/labextension/static/remoteEntry.ff55aa1cac6b05f762e9.js +562 -0
  12. kernel_checkpoint-0.1.3/kernel_checkpoint/labextension/static/remoteEntry.ff55aa1cac6b05f762e9.js.map +1 -0
  13. kernel_checkpoint-0.1.3/kernel_checkpoint/labextension/static/style_index_js.c3e72438ed03e9dee0fc.js +814 -0
  14. kernel_checkpoint-0.1.3/kernel_checkpoint/labextension/static/style_index_js.c3e72438ed03e9dee0fc.js.map +1 -0
  15. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/package.json +1 -1
  16. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/src/api.ts +1 -1
  17. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/src/checkpoint-panel.tsx +19 -28
  18. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/src/index.ts +3 -2
  19. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/src/types.ts +1 -1
  20. kernel_checkpoint-0.1.1/kernel_checkpoint/__init__.py +0 -23
  21. kernel_checkpoint-0.1.1/kernel_checkpoint/labextension/static/397.487e741e4ad2ed6339f5.js +0 -1
  22. kernel_checkpoint-0.1.1/kernel_checkpoint/labextension/static/728.4bf362e015a01b33d460.js +0 -1
  23. kernel_checkpoint-0.1.1/kernel_checkpoint/labextension/static/remoteEntry.d4b802a14146b6757b67.js +0 -1
  24. kernel_checkpoint-0.1.1/kernel_checkpoint/labextension/static/third-party-licenses.json +0 -16
  25. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/.copier-answers.yml +0 -0
  26. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/.gitignore +0 -0
  27. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/.prettierignore +0 -0
  28. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/.yarnrc.yml +0 -0
  29. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/4 +0 -0
  30. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/=4 +0 -0
  31. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/CHANGELOG.md +0 -0
  32. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/LICENSE +0 -0
  33. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/README.md +0 -0
  34. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/RELEASE.md +0 -0
  35. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/babel.config.js +0 -0
  36. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/install.json +0 -0
  37. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/jest.config.js +0 -0
  38. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/jupyter-config/jupyter_server_config.d/kernel_checkpoint.json +0 -0
  39. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/kernel_checkpoint/Untitled.ipynb +0 -0
  40. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/kernel_checkpoint/labextension/static/style.js +0 -0
  41. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/pyproject.toml +0 -0
  42. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/setup.py +0 -0
  43. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/src/__tests__/kernel_checkpoint.spec.ts +0 -0
  44. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/style/base.css +0 -0
  45. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/style/index.css +0 -0
  46. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/style/index.js +0 -0
  47. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/tsconfig.json +0 -0
  48. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/tsconfig.test.json +0 -0
  49. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/ui-tests/README.md +0 -0
  50. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/ui-tests/jupyter_server_test_config.py +0 -0
  51. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/ui-tests/package.json +0 -0
  52. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/ui-tests/playwright.config.js +0 -0
  53. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/ui-tests/tests/kernel_checkpoint.spec.ts +0 -0
  54. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/ui-tests/yarn.lock +0 -0
  55. {kernel_checkpoint-0.1.1 → kernel_checkpoint-0.1.3}/yarn.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kernel_checkpoint
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: An extension for saving and restoring kernel pod state with jupyter enterprise gateway
5
5
  Project-URL: Homepage, https://github.com/lehuannhatrang/kernel-checkpoint-extension.git
6
6
  Project-URL: Bug Tracker, https://github.com/lehuannhatrang/kernel-checkpoint-extension.git/issues
@@ -0,0 +1,257 @@
1
+ # JupyterLab extension for checkpoint management
2
+ _Exported on 4/9/2026 at 23:59:07 GMT+9 from Cursor (3.0.13)_
3
+
4
+ ---
5
+
6
+ **User**
7
+
8
+ i am building a jupyterlab extension for checkpoint/restore pod kernel ( kernel pod of jupyter enterprise gateway). TO do that , on the UI, we need a button "Saving points" to open a modal. In the modal, there are list of checkpoints which that user has taken before. User can choose one of them to restore. And also there is a button on the modal which will trigger checkpoint "Saving kernel state". When click the saving kernel state button, we allow user to type the name of checkpoint, and use that name to send to the API server. User also can get the status of a checkpoint, modify checkpoint name, delete a checkpoint.
9
+ I has already implemented the API server. The API server endpoint should be got from the configured jupyter env "CHECKPOINT_API_URL" . This is the example of api:
10
+ 1. List checkpoints for a namespace:
11
+ curl --location 'http://192.168.40.246:31809/api/v1/checkpoints?namespace=kubeflow-user-example-com'
12
+ response:
13
+ {
14
+ "items": [
15
+ {
16
+ "name": "checkpoint-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f-20260409-100748",
17
+ "namespace": "kubeflow-user-example-com",
18
+ "phase": "Completed",
19
+ "message": "All containers checkpointed successfully",
20
+ "schedule": "immediately",
21
+ "podRef": {
22
+ "name": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
23
+ "namespace": "kubeflow-user-example-com"
24
+ },
25
+ "resourceRef": {
26
+ "apiVersion": "v1",
27
+ "kind": "Pod",
28
+ "name": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
29
+ "namespace": "kubeflow-user-example-com"
30
+ },
31
+ "checkpointFiles": [
32
+ {
33
+ "containerName": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
34
+ "filePath": "checkpoint-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f_kubeflow-user-example-com-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f-2026-04-09T19:07:48+09:00.tar",
35
+ "checkpointTime": "2026-04-09T10:07:54Z"
36
+ }
37
+ ],
38
+ "builtImages": [
39
+ {
40
+ "containerName": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
41
+ "imageName": "localhost/checkpoint-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f:20260409-100754",
42
+ "buildTime": "2026-04-09T10:08:01Z",
43
+ "pushed": false
44
+ }
45
+ ],
46
+ "createdAt": "2026-04-09T10:07:48Z"
47
+ },
48
+ {
49
+ "name": "test-checkpoint-1",
50
+ "namespace": "kubeflow-user-example-com",
51
+ "phase": "Completed",
52
+ "message": "All containers checkpointed successfully",
53
+ "schedule": "immediately",
54
+ "buildImage": false,
55
+ "podRef": {
56
+ "name": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
57
+ "namespace": "kubeflow-user-example-com"
58
+ },
59
+ "resourceRef": {
60
+ "apiVersion": "v1",
61
+ "kind": "Pod",
62
+ "name": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
63
+ "namespace": "kubeflow-user-example-com"
64
+ },
65
+ "checkpointFiles": [
66
+ {
67
+ "containerName": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
68
+ "filePath": "checkpoint-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f_kubeflow-user-example-com-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f-2026-04-09T19:12:46+09:00.tar",
69
+ "storagePath": "kubeflow-user-example-com/checkpoint-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f_kubeflow-user-example-com-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f-2026-04-09T19:12:46+09:00.tar",
70
+ "checkpointTime": "2026-04-09T10:12:52Z"
71
+ }
72
+ ],
73
+ "createdAt": "2026-04-09T10:12:46Z"
74
+ }
75
+ ],
76
+ "totalCount": 2
77
+ }
78
+
79
+ 2. get checkpoint status: curl --location 'http://192.168.40.246:31809/api/v1/checkpoints/kubeflow-user-example-com/test-checkpoint-1'
80
+ Response:
81
+ {
82
+ "name": "test-checkpoint-1",
83
+ "namespace": "kubeflow-user-example-com",
84
+ "phase": "Completed",
85
+ "message": "All containers checkpointed successfully",
86
+ "schedule": "immediately",
87
+ "buildImage": false,
88
+ "podRef": {
89
+ "name": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
90
+ "namespace": "kubeflow-user-example-com"
91
+ },
92
+ "resourceRef": {
93
+ "apiVersion": "v1",
94
+ "kind": "Pod",
95
+ "name": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
96
+ "namespace": "kubeflow-user-example-com"
97
+ },
98
+ "checkpointFiles": [
99
+ {
100
+ "containerName": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
101
+ "filePath": "checkpoint-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f_kubeflow-user-example-com-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f-2026-04-09T19:12:46+09:00.tar",
102
+ "storagePath": "kubeflow-user-example-com/checkpoint-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f_kubeflow-user-example-com-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f-2026-04-09T19:12:46+09:00.tar",
103
+ "checkpointTime": "2026-04-09T10:12:52Z"
104
+ }
105
+ ],
106
+ "createdAt": "2026-04-09T10:12:46Z"
107
+ }
108
+
109
+ 3. Create checkpoint:
110
+ curl --location 'http://192.168.40.246:31809/api/v1/checkpoints' \
111
+ --header 'Content-Type: application/json' \
112
+ --data '{
113
+ "name": "test-checkpoint-1",
114
+ "namespace": "kubeflow-user-example-com",
115
+ "kernelId": "5df368c8-a92f-408e-8c7d-7ffdf345f86f",
116
+ "buildImage": false
117
+ }'
118
+
119
+ response:
120
+ {
121
+ "name": "test-checkpoint-1",
122
+ "namespace": "kubeflow-user-example-com",
123
+ "schedule": "immediately",
124
+ "buildImage": false,
125
+ "podRef": {
126
+ "name": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
127
+ "namespace": "kubeflow-user-example-com"
128
+ },
129
+ "resourceRef": {
130
+ "apiVersion": "v1",
131
+ "kind": "Pod",
132
+ "name": "jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f",
133
+ "namespace": "kubeflow-user-example-com"
134
+ },
135
+ "createdAt": "2026-04-09T10:12:46Z"
136
+ }
137
+
138
+ 4. Delete checkpoint:
139
+ curl --location --request DELETE 'http://192.168.40.246:31809/api/v1/checkpoints/kubeflow-user-example-com/checkpoint-jovyan-5df368c8-a92f-408e-8c7d-7ffdf345f86f-20260409-100748'
140
+
141
+ Note that the jupyter notebook i deployed by kubeflow, when sending request we should get the namespace (and kernel id in the create scenario)
142
+
143
+ And When user choose 1 saving point to restore, we will use Local Jupyter Server to create kernel with extra env so that the next step in our system will know to handle. for example this is my asumption how to handle, please recheck and implement
144
+ const initRequest = {
145
+ method: 'POST',
146
+ body: JSON.stringify({
147
+ name: 'python_kubernetes', // kernel spec , should match with checkpoint kernel.
148
+ env: {
149
+ 'CHECKPOINT_RESTORE_NAME': checkpointName, // checkpoint name
150
+ }
151
+ })
152
+ };
153
+ const response = await ServerConnection.makeRequest(url, initRequest, settings);
154
+ ...
155
+
156
+ ---
157
+
158
+ **Cursor**
159
+
160
+ Let me start by exploring the existing codebase structure.
161
+
162
+ Now I have a clear picture of the scaffold. It's a JupyterLab 4 extension with only a stub plugin. I need to build: a Python server extension to proxy the checkpoint API, and a React-based frontend with a toolbar button, modal dialog, and checkpoint management UI.
163
+
164
+ Let me implement everything.
165
+
166
+ Now let me implement the TypeScript frontend. I'll create the types, API client, React component, update the plugin, add dependencies, and write styles.
167
+
168
+ Now update `src/index.ts` with the plugin that wires everything together, including the restore flow:
169
+
170
+ Now let me update the CSS, `package.json`, and `tsconfig.json`:
171
+
172
+ Now update `package.json` to add the required frontend dependencies and server extension discovery:
173
+
174
+ Update `tsconfig.json` to handle `.tsx` files in subdirectories:
175
+
176
+ Now let's install dependencies and build to verify everything compiles:
177
+
178
+ Dependencies installed. Now let's build the TypeScript:
179
+
180
+ TypeScript compiled cleanly. Let's also build the full lab extension:
181
+
182
+ Everything compiles and builds successfully. Let me also verify the Python server extension works:
183
+
184
+ Everything builds successfully. Here's a summary of what was implemented:
185
+
186
+ ---
187
+
188
+ ## Architecture Overview
189
+
190
+ ### Python Server Extension (`kernel_checkpoint/`)
191
+
192
+ **`handlers.py`** — Tornado request handlers that proxy all calls to the external checkpoint API (read from `CHECKPOINT_API_URL` env var). This avoids CORS issues and keeps the API URL server-side:
193
+
194
+ | Endpoint | Method | Description |
195
+ |---|---|---|
196
+ | `/kernel-checkpoint/config` | GET | Returns `{checkpointApiUrl, namespace}` to the frontend |
197
+ | `/kernel-checkpoint/checkpoints` | GET | Lists checkpoints for a namespace (proxies `?namespace=`) |
198
+ | `/kernel-checkpoint/checkpoints` | POST | Creates a new checkpoint |
199
+ | `/kernel-checkpoint/checkpoints/<ns>/<name>` | GET | Gets checkpoint status/details |
200
+ | `/kernel-checkpoint/checkpoints/<ns>/<name>` | DELETE | Deletes a checkpoint |
201
+ | `/kernel-checkpoint/checkpoints/<ns>/<name>` | PATCH | Updates/renames a checkpoint |
202
+
203
+ **Namespace resolution** — Reads `CHECKPOINT_NAMESPACE` env var, falling back to the Kubernetes service account namespace at `/var/run/secrets/kubernetes.io/serviceaccount/namespace`.
204
+
205
+ ### TypeScript Frontend (`src/`)
206
+
207
+ **`types.ts`** — Interfaces for `ICheckpoint`, `ICheckpointListResponse`, `ICheckpointConfig`, `ICreateCheckpointRequest`, etc.
208
+
209
+ **`api.ts`** — `CheckpointAPI` namespace wrapping `ServerConnection.makeRequest` calls to the server extension proxy endpoints.
210
+
211
+ **`checkpoint-panel.tsx`** — The main React component rendered inside the dialog:
212
+ - **Save Kernel State** button at top, which reveals an inline form to name the checkpoint
213
+ - **Checkpoint list** showing each checkpoint with name, phase badge (Completed/Failed/In Progress), and creation date
214
+ - **Per-checkpoint actions**: Details (expand status info), Rename (inline edit), Delete (with inline confirmation), Restore (with inline confirmation)
215
+ - **Auto-refresh** every 5s when any checkpoint is still in progress
216
+ - **Flash messages** for success/error feedback
217
+
218
+ **`index.ts`** — Main plugin:
219
+ - Registers the `kernel-checkpoint:open` command
220
+ - Adds a **"Saving Points" toolbar button** to every notebook panel
221
+ - On click: fetches config, validates namespace + kernel connection, then opens a `showDialog` modal with the `CheckpointPanel`
222
+
223
+ ### Restore Flow
224
+
225
+ When a user clicks **Restore** on a completed checkpoint:
226
+ 1. A new kernel is created via `POST /api/kernels` with:
227
+
228
+ ```json
229
+ {
230
+ "name": "<current_kernel_spec_name>",
231
+ "env": {
232
+ "CHECKPOINT_RESTORE_NAME": "<checkpoint_name>"
233
+ }
234
+ }
235
+ ```
236
+
237
+ 2. The notebook session is switched to the new kernel via `sessionContext.changeKernel({ id: newKernelId })`
238
+ 3. The old kernel is shut down automatically by the session manager
239
+
240
+ ### Configuration
241
+
242
+ Two environment variables are needed on the Jupyter server pod:
243
+ - **`CHECKPOINT_API_URL`** — Base URL of the checkpoint API server (e.g. `http://192.168.40.246:31809`)
244
+ - **`CHECKPOINT_NAMESPACE`** — Kubernetes namespace (optional if running in-cluster, will auto-detect from service account)
245
+
246
+ ### Build & Install
247
+
248
+ ```bash
249
+ # Development install
250
+ pip install -e ".[dev]"
251
+ jupyter labextension develop . --overwrite
252
+ jupyter server extension enable kernel_checkpoint
253
+
254
+ # Or simply build
255
+ jlpm install && jlpm build
256
+ ```
257
+
@@ -0,0 +1,9 @@
1
+ FROM ghcr.io/kubeflow/kubeflow/notebook-servers/jupyter-scipy:v1.10.0
2
+
3
+ USER root
4
+
5
+ RUN pip install --upgrade pip
6
+
7
+ RUN pip install --no-cache-dir kernel-checkpoint==0.1.2
8
+
9
+ USER jovyan
@@ -0,0 +1,94 @@
1
+ try:
2
+ from ._version import __version__
3
+ except ImportError:
4
+ import warnings
5
+ warnings.warn("Importing 'kernel_checkpoint' outside a proper installation.")
6
+ __version__ = "dev"
7
+
8
+
9
+ def _jupyter_labextension_paths():
10
+ return [{
11
+ "src": "labextension",
12
+ "dest": "kernel-checkpoint"
13
+ }]
14
+
15
+
16
+ def _jupyter_server_extension_points():
17
+ return [{"module": "kernel_checkpoint"}]
18
+
19
+
20
+ def _load_jupyter_server_extension(server_app):
21
+ from .handlers import setup_handlers
22
+ setup_handlers(server_app.web_app)
23
+ _patch_kernel_handler_for_env_passthrough(server_app)
24
+ server_app.log.info("kernel_checkpoint server extension loaded")
25
+
26
+
27
+ def _patch_kernel_handler_for_env_passthrough(server_app):
28
+ """
29
+ Monkey-patch ``MainKernelHandler.post`` so that an ``env`` dict in the
30
+ request body is forwarded to ``KernelManager.start_kernel``.
31
+
32
+ The stock Jupyter Server handler silently drops ``env`` from the POST
33
+ payload. Enterprise Gateway (and other provisioners) need it to receive
34
+ ``KERNEL_CHECKPOINT_NAME`` during a checkpoint-restore flow.
35
+
36
+ Requests that do **not** carry ``env`` are delegated to the original,
37
+ unmodified handler so every other kernel-start path stays untouched.
38
+ """
39
+ from jupyter_server.services.kernels.handlers import MainKernelHandler
40
+ from jupyter_server.utils import url_path_join
41
+ from jupyter_core.utils import ensure_async
42
+ from tornado import web
43
+
44
+ original_post = MainKernelHandler.post
45
+
46
+ async def _patched_post(self):
47
+ model = self.get_json_body()
48
+
49
+ if not model or "env" not in model:
50
+ return await original_post(self)
51
+
52
+ km = self.kernel_manager
53
+ model.setdefault("name", km.default_kernel_name)
54
+
55
+ env = model["env"]
56
+ self.log.info(
57
+ "kernel_checkpoint: starting kernel with env keys: %s",
58
+ list(env.keys()),
59
+ )
60
+
61
+ try:
62
+ kernel_id = await ensure_async(
63
+ km.start_kernel(
64
+ path=model.get("path"),
65
+ kernel_name=model["name"],
66
+ env=env,
67
+ )
68
+ )
69
+ result = await ensure_async(km.kernel_model(kernel_id))
70
+ location = url_path_join(
71
+ self.base_url, "api", "kernels", str(kernel_id)
72
+ )
73
+ self.set_header("Location", location)
74
+ self.set_status(201)
75
+ self.finish(result)
76
+ except Exception as e:
77
+ self.log.error(
78
+ "kernel_checkpoint: env-passthrough kernel start failed: %s", e
79
+ )
80
+ raise web.HTTPError(500, str(e))
81
+
82
+ MainKernelHandler.post = _patched_post
83
+
84
+ try:
85
+ server_app.config.GatewayClient.client_envs = [
86
+ "KERNEL_CHECKPOINT_NAME",
87
+ "KERNEL_CHECKPOINT_FILE_PATH",
88
+ ]
89
+ except Exception:
90
+ pass
91
+
92
+ server_app.log.info(
93
+ "kernel_checkpoint: patched MainKernelHandler.post for env passthrough"
94
+ )
@@ -1,4 +1,4 @@
1
1
  # This file is auto-generated by Hatchling. As such, do not:
2
2
  # - modify
3
3
  # - track in version control e.g. be sure to add to .gitignore
4
- __version__ = VERSION = '0.1.1'
4
+ __version__ = VERSION = '0.1.3'
@@ -75,7 +75,7 @@ class CheckpointListCreateHandler(APIHandler):
75
75
 
76
76
 
77
77
  class CheckpointDetailHandler(APIHandler):
78
- """Handles get / delete / patch for a single checkpoint."""
78
+ """Handles get / delete / put for a single checkpoint."""
79
79
 
80
80
  @web.authenticated
81
81
  async def get(self, namespace, name):
@@ -113,7 +113,7 @@ class CheckpointDetailHandler(APIHandler):
113
113
  raise web.HTTPError(502, f"Failed to reach checkpoint API: {e}")
114
114
 
115
115
  @web.authenticated
116
- async def patch(self, namespace, name):
116
+ async def put(self, namespace, name):
117
117
  api_url = _get_api_url()
118
118
  if not api_url:
119
119
  raise web.HTTPError(500, "CHECKPOINT_API_URL not configured")
@@ -123,7 +123,7 @@ class CheckpointDetailHandler(APIHandler):
123
123
  url = f"{api_url}/api/v1/checkpoints/{namespace}/{name}"
124
124
  req = httpclient.HTTPRequest(
125
125
  url=url,
126
- method="PATCH",
126
+ method="PUT",
127
127
  headers={"Content-Type": "application/json"},
128
128
  body=json.dumps(body),
129
129
  )