akernel 0.2.0__tar.gz → 0.3.0__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 (46) hide show
  1. akernel-0.3.0/.github/workflows/main.yml +48 -0
  2. akernel-0.3.0/.pre-commit-config.yaml +7 -0
  3. {akernel-0.2.0 → akernel-0.3.0}/PKG-INFO +10 -19
  4. {akernel-0.2.0 → akernel-0.3.0}/README.md +1 -1
  5. {akernel-0.2.0 → akernel-0.3.0}/binder/postBuild +1 -0
  6. akernel-0.3.0/examples/concurrency.ipynb +127 -0
  7. {akernel-0.2.0 → akernel-0.3.0}/examples/reactivity.ipynb +1 -1
  8. akernel-0.3.0/plugins/akernel_task/LICENSE +21 -0
  9. akernel-0.3.0/plugins/akernel_task/README.md +3 -0
  10. akernel-0.3.0/plugins/akernel_task/fps_akernel_task/__init__.py +6 -0
  11. akernel-0.3.0/plugins/akernel_task/fps_akernel_task/akernel_task.py +49 -0
  12. akernel-0.3.0/plugins/akernel_task/fps_akernel_task/main.py +14 -0
  13. akernel-0.3.0/plugins/akernel_task/pyproject.toml +32 -0
  14. {akernel-0.2.0 → akernel-0.3.0}/pyproject.toml +21 -12
  15. akernel-0.3.0/src/akernel/__init__.py +6 -0
  16. akernel-0.3.0/src/akernel/akernel.py +140 -0
  17. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/cache.py +4 -5
  18. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/code.py +27 -28
  19. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/comm/comm.py +17 -18
  20. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/comm/manager.py +6 -5
  21. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/connect.py +7 -7
  22. akernel-0.3.0/src/akernel/display/__init__.py +0 -0
  23. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/display/display.py +3 -2
  24. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/execution.py +10 -11
  25. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/kernel.py +131 -100
  26. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/kernelspec.py +3 -4
  27. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/message.py +41 -51
  28. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/traceback.py +6 -7
  29. {akernel-0.2.0/akernel → akernel-0.3.0}/tests/conftest.py +5 -4
  30. {akernel-0.2.0/akernel → akernel-0.3.0}/tests/test_execution.py +6 -5
  31. {akernel-0.2.0/akernel → akernel-0.3.0}/tests/test_kernel.py +8 -21
  32. {akernel-0.2.0/akernel → akernel-0.3.0}/tests/test_react_code.py +1 -3
  33. akernel-0.2.0/.github/workflows/main.yml +0 -57
  34. akernel-0.2.0/akernel/__init__.py +0 -1
  35. akernel-0.2.0/akernel/akernel.py +0 -38
  36. {akernel-0.2.0 → akernel-0.3.0}/LICENSE +0 -0
  37. {akernel-0.2.0 → akernel-0.3.0}/MANIFEST.in +0 -0
  38. {akernel-0.2.0 → akernel-0.3.0}/binder/environment.yml +0 -0
  39. /akernel-0.2.0/akernel/IPython/core/__init__.py → /akernel-0.3.0/plugins/akernel_task/fps_akernel_task/py.typed +0 -0
  40. {akernel-0.2.0 → akernel-0.3.0}/share/jupyter/kernels/akernel/kernel.json +0 -0
  41. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/IPython/__init__.py +0 -0
  42. {akernel-0.2.0/akernel/display → akernel-0.3.0/src/akernel/IPython/core}/__init__.py +0 -0
  43. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/IPython/core/getipython.py +0 -0
  44. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/IPython/core/interactiveshell.py +0 -0
  45. {akernel-0.2.0 → akernel-0.3.0/src}/akernel/comm/__init__.py +0 -0
  46. {akernel-0.2.0/akernel → akernel-0.3.0}/tests/test_async_code.py +0 -0
@@ -0,0 +1,48 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+
11
+ defaults:
12
+ run:
13
+ shell: bash -l {0}
14
+
15
+ jobs:
16
+ test:
17
+ name: Test
18
+ runs-on: ${{ matrix.os }}
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ os: [ubuntu-latest, macos-latest, windows-latest]
23
+ python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13' ]
24
+
25
+ steps:
26
+ - name: Checkout
27
+ uses: actions/checkout@v4
28
+
29
+ - name: Setup Python
30
+ uses: actions/setup-python@v5
31
+ with:
32
+ python-version: ${{ matrix.python-version }}
33
+
34
+ - name: Install akernel
35
+ run: |
36
+ pip install . --group test
37
+
38
+ - name: Check style and types
39
+ run: |
40
+ ruff check --show-fixes
41
+ ruff format --check
42
+ mypy src
43
+
44
+ - name: Run tests
45
+ run: |
46
+ akernel --help
47
+ test -f ${pythonLocation}/../share/jupyter/kernels/akernel/kernel.json
48
+ pytest -v --reruns 5
@@ -0,0 +1,7 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.11.13
4
+ hooks:
5
+ - id: ruff-check
6
+ args: [--fix, --show-fixes]
7
+ - id: ruff-format
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: akernel
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: An asynchronous Python Jupyter kernel
5
5
  Project-URL: Homepage, https://github.com/davidbrochart/akernel
6
6
  Author-email: David Brochart <david.brochart@gmail.com>
@@ -9,34 +9,25 @@ License-File: LICENSE
9
9
  Keywords: jupyter
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Programming Language :: Python
12
- Classifier: Programming Language :: Python :: 3.8
13
12
  Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
16
17
  Classifier: Programming Language :: Python :: Implementation :: CPython
17
18
  Classifier: Programming Language :: Python :: Implementation :: PyPy
18
- Requires-Python: >=3.8
19
- Requires-Dist: click
19
+ Requires-Python: >=3.9
20
20
  Requires-Dist: colorama
21
21
  Requires-Dist: comm<1,>=0.1.3
22
- Requires-Dist: gast>=0.5.3
22
+ Requires-Dist: gast<0.7.0,>=0.6.0
23
23
  Requires-Dist: python-dateutil
24
- Requires-Dist: pyzmq
25
- Requires-Dist: typer>=0.4.0
26
24
  Provides-Extra: cache
27
25
  Requires-Dist: zict; extra == 'cache'
28
26
  Provides-Extra: react
29
27
  Requires-Dist: ipyx>=0.1.7; extra == 'react'
30
- Provides-Extra: test
31
- Requires-Dist: black; extra == 'test'
32
- Requires-Dist: ipyx>=0.1.7; extra == 'test'
33
- Requires-Dist: kernel-driver>=0.0.7; extra == 'test'
34
- Requires-Dist: mypy; extra == 'test'
35
- Requires-Dist: pytest; extra == 'test'
36
- Requires-Dist: pytest-asyncio; extra == 'test'
37
- Requires-Dist: ruff; extra == 'test'
38
- Requires-Dist: types-python-dateutil; extra == 'test'
39
- Requires-Dist: zict; extra == 'test'
28
+ Provides-Extra: subprocess
29
+ Requires-Dist: typer>=0.4.0; extra == 'subprocess'
30
+ Requires-Dist: zmq-anyio<0.4.0,>=0.3.9; extra == 'subprocess'
40
31
  Description-Content-Type: text/markdown
41
32
 
42
33
  [![Build Status](https://github.com/davidbrochart/akernel/workflows/CI/badge.svg)](https://github.com/davidbrochart/akernel/actions)
@@ -90,7 +81,7 @@ If you want to go all the way and have cells execute concurrently, you can also
90
81
 
91
82
  ## Features
92
83
 
93
- ### Asynchronous execution
84
+ ### Concurrent execution
94
85
 
95
86
  First, set the concurrent execution mode in order to have async cells execute concurrently
96
87
  (you could also do that at install-time with `akernel install concurrent`):
@@ -49,7 +49,7 @@ If you want to go all the way and have cells execute concurrently, you can also
49
49
 
50
50
  ## Features
51
51
 
52
- ### Asynchronous execution
52
+ ### Concurrent execution
53
53
 
54
54
  First, set the concurrent execution mode in order to have async cells execute concurrently
55
55
  (you could also do that at install-time with `akernel install concurrent`):
@@ -1,4 +1,5 @@
1
1
  #!/bin/bash
2
2
 
3
3
  python -m pip install -e .
4
+ akernel install
4
5
  akernel install react
@@ -0,0 +1,127 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "1424909b-49ae-4f63-938c-c72cb3f84550",
6
+ "metadata": {},
7
+ "source": [
8
+ "If you execute the three following for-loops, you can see that they are executed concurrently."
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "execution_count": null,
14
+ "id": "97b4a9c1-6818-404d-9e4f-64569dd9351f",
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "__unchain_execution__()"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "code",
23
+ "execution_count": null,
24
+ "id": "073b08dd-d004-4f94-8522-bfa1002c9694",
25
+ "metadata": {},
26
+ "outputs": [],
27
+ "source": [
28
+ "for i in range(5):\n",
29
+ " await asyncio.sleep(1)\n",
30
+ " print(f\"{i=}\")"
31
+ ]
32
+ },
33
+ {
34
+ "cell_type": "code",
35
+ "execution_count": null,
36
+ "id": "1ced9a54-9d08-4cb7-bd57-e68db9b1d7fb",
37
+ "metadata": {},
38
+ "outputs": [],
39
+ "source": [
40
+ "for j in range(5):\n",
41
+ " await asyncio.sleep(1)\n",
42
+ " print(f\"{j=}\")"
43
+ ]
44
+ },
45
+ {
46
+ "cell_type": "code",
47
+ "execution_count": null,
48
+ "id": "98e994bb-caa2-45f7-b35d-a183facb1b72",
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "for k in range(5):\n",
53
+ " await asyncio.sleep(1)\n",
54
+ " print(f\"{k=}\")"
55
+ ]
56
+ },
57
+ {
58
+ "cell_type": "markdown",
59
+ "id": "558b8d22-d221-4ea8-bc25-e261ea491b7d",
60
+ "metadata": {},
61
+ "source": [
62
+ "Now if you execute the three following for-loops, you can see that they are executed one after the other."
63
+ ]
64
+ },
65
+ {
66
+ "cell_type": "code",
67
+ "execution_count": null,
68
+ "id": "422c2851-f7c8-460c-9544-13c9c8ebfe0b",
69
+ "metadata": {},
70
+ "outputs": [],
71
+ "source": [
72
+ "__chain_execution__()"
73
+ ]
74
+ },
75
+ {
76
+ "cell_type": "code",
77
+ "execution_count": null,
78
+ "id": "21b5428c-9fcf-4150-af59-635deab42833",
79
+ "metadata": {},
80
+ "outputs": [],
81
+ "source": [
82
+ "for i in range(5):\n",
83
+ " await asyncio.sleep(1)\n",
84
+ " print(f\"{i=}\")"
85
+ ]
86
+ },
87
+ {
88
+ "cell_type": "code",
89
+ "execution_count": null,
90
+ "id": "5ee578b3-6b4d-4315-ab17-8c845d740b36",
91
+ "metadata": {},
92
+ "outputs": [],
93
+ "source": [
94
+ "for j in range(5):\n",
95
+ " await asyncio.sleep(1)\n",
96
+ " print(f\"{j=}\")"
97
+ ]
98
+ },
99
+ {
100
+ "cell_type": "code",
101
+ "execution_count": null,
102
+ "id": "16f0146a-fdf8-4fbe-bf37-63b2da2fe1e0",
103
+ "metadata": {},
104
+ "outputs": [],
105
+ "source": [
106
+ "for k in range(5):\n",
107
+ " await asyncio.sleep(1)\n",
108
+ " print(f\"{k=}\")"
109
+ ]
110
+ }
111
+ ],
112
+ "metadata": {
113
+ "kernelspec": {
114
+ "display_name": "Python 3 (akernel)",
115
+ "language": "python",
116
+ "name": "akernel"
117
+ },
118
+ "language_info": {
119
+ "file_extension": ".py",
120
+ "mimetype": "text/x-python",
121
+ "name": "python",
122
+ "version": "3.11.4"
123
+ }
124
+ },
125
+ "nbformat": 4,
126
+ "nbformat_minor": 5
127
+ }
@@ -257,7 +257,7 @@
257
257
  "kernelspec": {
258
258
  "display_name": "Python 3 (akernel-react)",
259
259
  "language": "python",
260
- "name": "akernel"
260
+ "name": "akernel-react"
261
261
  },
262
262
  "language_info": {
263
263
  "file_extension": ".py",
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 David Brochart
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ # fps-akernel-task
2
+
3
+ An FPS plugin for the kernel task API.
@@ -0,0 +1,6 @@
1
+ import importlib.metadata
2
+
3
+ try:
4
+ __version__ = importlib.metadata.version("fps_akernel_task")
5
+ except importlib.metadata.PackageNotFoundError:
6
+ __version__ = "unknown"
@@ -0,0 +1,49 @@
1
+ from __future__ import annotations
2
+
3
+ from anyio import TASK_STATUS_IGNORED, create_task_group, sleep_forever
4
+ from anyio.abc import TaskStatus
5
+ from jupyverse_api.kernel import Kernel as _Kernel
6
+
7
+ from akernel.kernel import Kernel
8
+
9
+
10
+ class AKernelTask(_Kernel):
11
+ def __init__(self, *args, **kwargs):
12
+ super().__init__()
13
+
14
+ async def start(self, *, task_status: TaskStatus[None] = TASK_STATUS_IGNORED) -> None:
15
+ async with (
16
+ create_task_group() as self.task_group,
17
+ self._to_shell_send_stream,
18
+ self._to_shell_receive_stream,
19
+ self._from_shell_send_stream,
20
+ self._from_shell_receive_stream,
21
+ self._to_control_send_stream,
22
+ self._to_control_receive_stream,
23
+ self._from_control_send_stream,
24
+ self._from_control_receive_stream,
25
+ self._to_stdin_send_stream,
26
+ self._to_stdin_receive_stream,
27
+ self._from_stdin_send_stream,
28
+ self._from_stdin_receive_stream,
29
+ self._from_iopub_send_stream,
30
+ self._from_iopub_receive_stream,
31
+ ):
32
+ self.kernel = Kernel(
33
+ self._to_shell_receive_stream,
34
+ self._from_shell_send_stream,
35
+ self._to_control_receive_stream,
36
+ self._from_control_send_stream,
37
+ self._to_stdin_receive_stream,
38
+ self._from_stdin_send_stream,
39
+ self._from_iopub_send_stream,
40
+ )
41
+ self.task_group.start_soon(self.kernel.start)
42
+ task_status.started()
43
+ await sleep_forever()
44
+
45
+ async def stop(self) -> None:
46
+ self.task_group.cancel_scope.cancel()
47
+
48
+ async def interrupt(self) -> None:
49
+ pass
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ from fps import Module
4
+
5
+ from jupyverse_api.kernel import KernelFactory
6
+ from jupyverse_api.kernels import Kernels
7
+
8
+ from .akernel_task import AKernelTask
9
+
10
+
11
+ class AKernelTaskModule(Module):
12
+ async def prepare(self) -> None:
13
+ kernels = await self.get(Kernels)
14
+ kernels.register_kernel_factory("akernel", KernelFactory(AKernelTask))
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "fps_akernel_task"
7
+ version = "0.1.0"
8
+ description = "An FPS plugin for the kernel task API"
9
+ keywords = ["jupyter", "server", "fastapi", "plugins"]
10
+ requires-python = ">=3.9"
11
+ dependencies = [
12
+ "jupyverse-api >=0.10.0,<0.11.0",
13
+ "anyio",
14
+ ]
15
+
16
+ [[project.authors]]
17
+ name = "David Brochart"
18
+ email = "david.brochart@gmail.com"
19
+
20
+ [project.readme]
21
+ file = "README.md"
22
+ content-type = "text/markdown"
23
+
24
+ [project.license]
25
+ text = "MIT"
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/davidbrochart/akernel"
29
+
30
+ [project.entry-points]
31
+ "fps.modules" = {akernel_task = "fps_akernel_task.main:AKernelTaskModule"}
32
+ "jupyverse.modules" = {akernel_task = "fps_akernel_task.main:AKernelTaskModule"}
@@ -4,46 +4,50 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "akernel"
7
- dynamic = ["version"]
7
+ version = "0.3.0"
8
8
  description = "An asynchronous Python Jupyter kernel"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
11
- requires-python = ">=3.8"
11
+ requires-python = ">=3.9"
12
12
  authors = [{name = "David Brochart", email = "david.brochart@gmail.com"}]
13
13
  classifiers = [
14
14
  "Development Status :: 4 - Beta",
15
15
  "Programming Language :: Python",
16
- "Programming Language :: Python :: 3.8",
17
16
  "Programming Language :: Python :: 3.9",
18
17
  "Programming Language :: Python :: 3.10",
19
18
  "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
20
21
  "Programming Language :: Python :: Implementation :: CPython",
21
22
  "Programming Language :: Python :: Implementation :: PyPy",
22
23
  ]
23
24
  keywords = [ "jupyter" ]
24
25
  dependencies = [
25
- "pyzmq",
26
- "typer >=0.4.0",
27
- "click",
28
26
  "python-dateutil",
29
27
  "colorama",
30
- "gast >=0.5.3",
28
+ "gast >=0.6.0, <0.7.0",
31
29
  "comm >=0.1.3,<1",
32
30
  ]
33
31
 
34
- [project.optional-dependencies]
32
+ [dependency-groups]
35
33
  test = [
36
34
  "mypy",
37
35
  "ruff",
38
- "black",
39
36
  "pytest",
40
37
  "pytest-asyncio",
38
+ "pytest-rerunfailures",
41
39
  "types-python-dateutil",
42
40
  "kernel_driver >=0.0.7",
43
41
  "ipyx >=0.1.7",
44
42
  "zict",
45
43
  ]
46
44
 
45
+ [project.optional-dependencies]
46
+ subprocess = [
47
+ "zmq-anyio >=0.3.9,<0.4.0",
48
+ "typer >=0.4.0",
49
+ ]
50
+
47
51
  react = [
48
52
  "ipyx >=0.1.7",
49
53
  ]
@@ -55,14 +59,19 @@ cache = [
55
59
  [project.scripts]
56
60
  akernel = "akernel.akernel:cli"
57
61
 
62
+ [tool.hatch.build.targets.wheel]
63
+ ignore-vcs = true
64
+ packages = ["src/akernel"]
65
+
58
66
  [tool.hatch.build.targets.wheel.shared-data]
59
67
  "share/jupyter/kernels/akernel/kernel.json" = "share/jupyter/kernels/akernel/kernel.json"
60
68
 
61
69
  [project.urls]
62
70
  Homepage = "https://github.com/davidbrochart/akernel"
63
71
 
64
- [tool.hatch.version]
65
- path = "akernel/__init__.py"
66
-
67
72
  [tool.ruff]
68
73
  line-length = 100
74
+ exclude = ["examples"]
75
+
76
+ [tool.uv.sources]
77
+ fps-akernel-task = { workspace = true }
@@ -0,0 +1,6 @@
1
+ import importlib.metadata
2
+
3
+ try:
4
+ __version__ = importlib.metadata.version("akernel")
5
+ except importlib.metadata.PackageNotFoundError:
6
+ __version__ = "unknown"
@@ -0,0 +1,140 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import cast
5
+
6
+ import typer
7
+ from anyio import create_memory_object_stream, create_task_group, run, sleep_forever
8
+
9
+ from .connect import connect_channel
10
+ from .kernel import Kernel
11
+ from .kernelspec import write_kernelspec
12
+ from .message import receive_message, send_message
13
+
14
+
15
+ cli = typer.Typer()
16
+
17
+
18
+ @cli.command()
19
+ def install(
20
+ mode: str = typer.Argument("", help="Mode of the kernel to install."),
21
+ cache_dir: str | None = typer.Option(
22
+ None, "-c", help="Path to the cache directory, if mode is 'cache'."
23
+ ),
24
+ ):
25
+ kernel_name = "akernel"
26
+ if mode:
27
+ modes = mode.split("-")
28
+ modes.sort()
29
+ mode = "-".join(modes)
30
+ kernel_name += f"-{mode}"
31
+ display_name = f"Python 3 ({kernel_name})"
32
+ write_kernelspec(kernel_name, mode, display_name, cache_dir)
33
+
34
+
35
+ @cli.command()
36
+ def launch(
37
+ mode: str = typer.Argument("", help="Mode of the kernel to launch."),
38
+ cache_dir: str | None = typer.Option(
39
+ None, "-c", help="Path to the cache directory, if mode is 'cache'."
40
+ ),
41
+ connection_file: str | None = typer.Option(None, "-f", help="Path to the connection file."),
42
+ ):
43
+ akernel = AKernel(mode, cache_dir, connection_file)
44
+ run(akernel.start)
45
+
46
+
47
+ class AKernel:
48
+ def __init__(self, mode, cache_dir, connection_file):
49
+ self._to_shell_send_stream, self._to_shell_receive_stream = create_memory_object_stream[list[bytes]]()
50
+ self._from_shell_send_stream, self._from_shell_receive_stream = create_memory_object_stream[list[bytes]]()
51
+ self._to_control_send_stream, self._to_control_receive_stream = create_memory_object_stream[list[bytes]]()
52
+ self._from_control_send_stream, self._from_control_receive_stream = create_memory_object_stream[list[bytes]]()
53
+ self._to_stdin_send_stream, self._to_stdin_receive_stream = create_memory_object_stream[list[bytes]]()
54
+ self._from_stdin_send_stream, self._from_stdin_receive_stream = create_memory_object_stream[list[bytes]]()
55
+ self._from_iopub_send_stream, self._from_iopub_receive_stream = create_memory_object_stream[list[bytes]](max_buffer_size=float("inf"))
56
+ self.kernel = Kernel(
57
+ self._to_shell_receive_stream,
58
+ self._from_shell_send_stream,
59
+ self._to_control_receive_stream,
60
+ self._from_control_send_stream,
61
+ self._to_stdin_receive_stream,
62
+ self._from_stdin_send_stream,
63
+ self._from_iopub_send_stream,
64
+ mode,
65
+ cache_dir,
66
+ )
67
+ with open(connection_file) as f:
68
+ connection_cfg = json.load(f)
69
+ self.kernel.key = cast(str, connection_cfg["key"])
70
+ self.shell_channel = connect_channel("shell", connection_cfg)
71
+ self.iopub_channel = connect_channel("iopub", connection_cfg)
72
+ self.control_channel = connect_channel("control", connection_cfg)
73
+ self.stdin_channel = connect_channel("stdin", connection_cfg)
74
+
75
+ async def start(self) -> None:
76
+ async with (
77
+ create_task_group() as tg,
78
+ self._to_shell_send_stream,
79
+ self._to_shell_receive_stream,
80
+ self._from_shell_send_stream,
81
+ self._from_shell_receive_stream,
82
+ self._to_control_send_stream,
83
+ self._to_control_receive_stream,
84
+ self._from_control_send_stream,
85
+ self._from_control_receive_stream,
86
+ self._to_stdin_send_stream,
87
+ self._to_stdin_receive_stream,
88
+ self._from_stdin_send_stream,
89
+ self._from_stdin_receive_stream,
90
+ self._from_iopub_send_stream,
91
+ self._from_iopub_receive_stream,
92
+ self.shell_channel,
93
+ self.control_channel,
94
+ self.stdin_channel,
95
+ self.iopub_channel,
96
+ ):
97
+ tg.start_soon(self.kernel.start)
98
+ tg.start_soon(self.to_shell)
99
+ tg.start_soon(self.from_shell)
100
+ tg.start_soon(self.to_control)
101
+ tg.start_soon(self.from_control)
102
+ tg.start_soon(self.to_stdin)
103
+ tg.start_soon(self.from_stdin)
104
+ tg.start_soon(self.from_iopub)
105
+ await sleep_forever()
106
+
107
+ async def to_shell(self) -> None:
108
+ while True:
109
+ msg = await receive_message(self.shell_channel)
110
+ await self._to_shell_send_stream.send(msg)
111
+
112
+ async def from_shell(self) -> None:
113
+ async for msg in self._from_shell_receive_stream:
114
+ await send_message(msg, self.shell_channel)
115
+
116
+ async def to_control(self) -> None:
117
+ while True:
118
+ msg = await receive_message(self.control_channel)
119
+ await self._to_control_send_stream.send(msg)
120
+
121
+ async def from_control(self) -> None:
122
+ async for msg in self._from_control_receive_stream:
123
+ await send_message(msg, self.control_channel)
124
+
125
+ async def to_stdin(self) -> None:
126
+ while True:
127
+ msg = await receive_message(self.stdin_channel)
128
+ await self._to_stdin_send_stream.send(msg)
129
+
130
+ async def from_stdin(self) -> None:
131
+ async for msg in self._from_stdin_receive_stream:
132
+ await send_message(msg, self.stdin_channel)
133
+
134
+ async def from_iopub(self) -> None:
135
+ async for msg in self._from_iopub_receive_stream:
136
+ await send_message(msg, self.iopub_channel)
137
+
138
+
139
+ if __name__ == "__main__":
140
+ cli()
@@ -1,17 +1,16 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
4
  import pickle
3
5
  import sys
4
6
  import zlib
5
- from typing import Optional
6
7
 
7
8
  from zict import File, Func, LRU # type: ignore
8
9
 
9
10
 
10
- def cache(cache_dir: Optional[str]):
11
+ def cache(cache_dir: str | None):
11
12
  if not cache_dir:
12
- cache_dir = os.path.join(
13
- sys.prefix, "share", "jupyter", "kernels", "akernel", "cache"
14
- )
13
+ cache_dir = os.path.join(sys.prefix, "share", "jupyter", "kernels", "akernel", "cache")
15
14
 
16
15
  l4 = File(cache_dir)
17
16
  l3 = Func(zlib.compress, zlib.decompress, l4)