async-kernel 0.13.3__tar.gz → 0.15.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.
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.github/workflows/ci.yml +9 -3
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.github/workflows/enforce-label.yml +1 -4
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.vscode/launch.json +30 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/CHANGELOG.md +66 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/CONTRIBUTING.md +11 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/PKG-INFO +43 -16
- {async_kernel-0.13.3 → async_kernel-0.15.0}/README.md +40 -14
- async_kernel-0.15.0/_version.py +24 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/notebooks/caller.ipynb +17 -10
- async_kernel-0.15.0/docs/reference/event_loop.md +9 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/index.md +2 -2
- async_kernel-0.15.0/docs/thread_safety.md +40 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/usage/commands.md +18 -18
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/usage/index.md +12 -2
- {async_kernel-0.13.3 → async_kernel-0.15.0}/mkdocs.yml +3 -3
- {async_kernel-0.13.3 → async_kernel-0.15.0}/pyproject.toml +3 -2
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/asyncshell.py +5 -5
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/caller.py +55 -58
- async_kernel-0.15.0/src/async_kernel/common.py +132 -0
- async_kernel-0.15.0/src/async_kernel/compat/json.py +45 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/debugger.py +3 -3
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/event_loop/asyncio_guest.py +1 -1
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/event_loop/qt_host.py +5 -3
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/event_loop/run.py +27 -28
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/event_loop/tk_host.py +14 -11
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/interface/base.py +19 -4
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/interface/callable.py +7 -53
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/interface/zmq.py +12 -19
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/kernel.py +41 -21
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/pending.py +136 -84
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/typing.py +8 -23
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_callable_kernel_interface.py +11 -7
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_caller.py +8 -11
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_command.py +8 -8
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_common.py +2 -22
- async_kernel-0.15.0/tests/test_compat.py +39 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_event_loop.py +84 -8
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_kernel.py +2 -1
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_pending.py +87 -10
- {async_kernel-0.13.3 → async_kernel-0.15.0}/uv.lock +336 -359
- async_kernel-0.13.3/_version.py +0 -34
- async_kernel-0.13.3/docs/reference/event_loop.md +0 -1
- async_kernel-0.13.3/src/async_kernel/common.py +0 -138
- async_kernel-0.13.3/src/async_kernel/event_loop/asyncio_host.py +0 -41
- async_kernel-0.13.3/src/async_kernel/event_loop/trio_host.py +0 -47
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.github/dependabot.yaml +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.github/release.yml +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.github/workflows/new_release.yml +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.github/workflows/pre-commit.yml +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.github/workflows/publish-docs.yml +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.github/workflows/publish-to-pypi.yml +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.gitignore +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.pre-commit-config.yaml +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.vscode/settings.json +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/.vscode/spellright.dict +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/IPYTHON_LICENSE +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/LICENSE +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/cliff.toml +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/about/changelog.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/about/contributing.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/about/index.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/about/license.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/index.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/javascripts/extra.js +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/notebooks/concurrency.ipynb +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/overrides/main.html +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/asyncshell.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/caller.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/comm.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/command.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/common.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/debugger.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/interface.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/kernel.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/kernelspec.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/pending.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/typing.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/reference/utils.md +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/docs/stylesheets/extra.css +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/hatch_build.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/__init__.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/__main__.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/comm.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/command.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/compiler.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/event_loop/__init__.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/interface/__init__.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/iostream.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/kernelspec.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/py.typed +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/resources/logo-32x32.png +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/resources/logo-64x64.png +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/resources/logo-svg.svg +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/src/async_kernel/utils.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/__init__.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/conftest.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/references.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_comm.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_debugger.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_enter_kernel.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_iostream.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_kernel_subclass.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_kernelspec.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_message_spec.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_typing.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_utils.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/test_zmq_messaging.py +0 -0
- {async_kernel-0.13.3 → async_kernel-0.15.0}/tests/utils.py +0 -0
|
@@ -38,8 +38,7 @@ jobs:
|
|
|
38
38
|
- "3.11"
|
|
39
39
|
- "3.12"
|
|
40
40
|
- "3.13"
|
|
41
|
-
- "3.
|
|
42
|
-
# - "3.14t" # re-enabled when free-threading becomes more widely supported.
|
|
41
|
+
- "3.14t"
|
|
43
42
|
steps:
|
|
44
43
|
- name: Checkout
|
|
45
44
|
uses: actions/checkout@v6
|
|
@@ -54,6 +53,10 @@ jobs:
|
|
|
54
53
|
- name: Install the project
|
|
55
54
|
run: uv sync --locked --dev
|
|
56
55
|
|
|
56
|
+
- if: ${{ startsWith(matrix.os, 'windows') && !endsWith(matrix.python-version, 't')}}
|
|
57
|
+
# Pyside does not have free-threaded binary
|
|
58
|
+
run: uv sync --locked --dev --group gui
|
|
59
|
+
|
|
57
60
|
- name: Run tests
|
|
58
61
|
timeout-minutes: 5
|
|
59
62
|
run: uv run pytest -vvl --maxfail=1 --reruns 1
|
|
@@ -75,7 +78,10 @@ jobs:
|
|
|
75
78
|
|
|
76
79
|
- name: Run tests with coverage
|
|
77
80
|
timeout-minutes: 5
|
|
78
|
-
run:
|
|
81
|
+
run: |
|
|
82
|
+
uv sync --locked --dev
|
|
83
|
+
uv pip install orjson>=3.10.16
|
|
84
|
+
uv run pytest --cov --cov-report=xml --junitxml=junit.xml -o junit_family=legacy --cov-fail-under=100 --cov-report markdown-append:$GITHUB_STEP_SUMMARY
|
|
79
85
|
|
|
80
86
|
- name: Upload coverage reports to Codecov
|
|
81
87
|
if: ${{ !cancelled() }}
|
|
@@ -26,6 +26,36 @@
|
|
|
26
26
|
},
|
|
27
27
|
"justMyCode": true,
|
|
28
28
|
"args": ["-X dev", "Wd"]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "Jupyterlab",
|
|
32
|
+
"type": "debugpy",
|
|
33
|
+
"request": "launch",
|
|
34
|
+
"args": [
|
|
35
|
+
"--notebook-dir=docs/notebooks",
|
|
36
|
+
"--no-browser",
|
|
37
|
+
"--ServerApp.token=''",
|
|
38
|
+
"--port=9991"
|
|
39
|
+
],
|
|
40
|
+
"cwd": "${workspaceFolder}",
|
|
41
|
+
"justMyCode": false,
|
|
42
|
+
"module": "jupyterlab",
|
|
43
|
+
"presentation": {
|
|
44
|
+
"hidden": false
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "Editor Browser",
|
|
49
|
+
"type": "editor-browser",
|
|
50
|
+
"request": "launch",
|
|
51
|
+
"url": "http://localhost:9991",
|
|
52
|
+
"webRoot": "${workspaceFolder}"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"compounds": [
|
|
56
|
+
{
|
|
57
|
+
"name": "Python and Jupyterlab",
|
|
58
|
+
"configurations": ["Jupyterlab", "Editor Browser"]
|
|
29
59
|
}
|
|
30
60
|
]
|
|
31
61
|
}
|
|
@@ -5,6 +5,68 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.15.0] - 2026-03-30
|
|
9
|
+
|
|
10
|
+
### <!-- 0 --> 🏗️ Breaking changes
|
|
11
|
+
|
|
12
|
+
- Provide cancellation in Pending by default [#386](https://github.com/fleming79/async-kernel/pull/386)
|
|
13
|
+
|
|
14
|
+
- Use a standard dict for the user_ns (remove LastUpdatedDict) [#380](https://github.com/fleming79/async-kernel/pull/380)
|
|
15
|
+
|
|
16
|
+
### <!-- 1 --> 🚀 Features
|
|
17
|
+
|
|
18
|
+
- Replace aiologic.Lock with aiologic.lowlevel.create_thread_oncelock for improved performance [#389](https://github.com/fleming79/async-kernel/pull/389)
|
|
19
|
+
|
|
20
|
+
- Convert Pending._done_callbacks from deque to list [#383](https://github.com/fleming79/async-kernel/pull/383)
|
|
21
|
+
|
|
22
|
+
- Free-threading preliminary support. [#379](https://github.com/fleming79/async-kernel/pull/379)
|
|
23
|
+
|
|
24
|
+
### <!-- 5 --> 📝 Documentation
|
|
25
|
+
|
|
26
|
+
- Update docstrings [#384](https://github.com/fleming79/async-kernel/pull/384)
|
|
27
|
+
|
|
28
|
+
- Add thread_safety.md [#381](https://github.com/fleming79/async-kernel/pull/381)
|
|
29
|
+
|
|
30
|
+
### <!-- 6 --> 🌀 Miscellaneous
|
|
31
|
+
|
|
32
|
+
- Change Pending.wait_sync signature to be the same as Pending.wait [#393](https://github.com/fleming79/async-kernel/pull/393)
|
|
33
|
+
|
|
34
|
+
- Tidy up [#391](https://github.com/fleming79/async-kernel/pull/391)
|
|
35
|
+
|
|
36
|
+
- Pending refactoring. [#390](https://github.com/fleming79/async-kernel/pull/390)
|
|
37
|
+
|
|
38
|
+
- Use aiologic.lowlevel.create_async_waiter instead of Event for better performance. [#388](https://github.com/fleming79/async-kernel/pull/388)
|
|
39
|
+
|
|
40
|
+
- Pending refactoring [#385](https://github.com/fleming79/async-kernel/pull/385)
|
|
41
|
+
|
|
42
|
+
- Caller.queue_call optimizations [#382](https://github.com/fleming79/async-kernel/pull/382)
|
|
43
|
+
|
|
44
|
+
- Add Kernel.run and refactor the interfaces. [#378](https://github.com/fleming79/async-kernel/pull/378)
|
|
45
|
+
|
|
46
|
+
- Use Kernel._get_run_mode for all message types. [#377](https://github.com/fleming79/async-kernel/pull/377)
|
|
47
|
+
|
|
48
|
+
- Add a VS Code launch config for to launch Jupyterlab [#376](https://github.com/fleming79/async-kernel/pull/376)
|
|
49
|
+
|
|
50
|
+
- Upgrade uv.lock and run gui tests using windows. [#375](https://github.com/fleming79/async-kernel/pull/375)
|
|
51
|
+
|
|
52
|
+
- Update uv.lock [#374](https://github.com/fleming79/async-kernel/pull/374)
|
|
53
|
+
|
|
54
|
+
## [0.14.0] - 2026-03-24
|
|
55
|
+
|
|
56
|
+
### <!-- 0 --> 🏗️ Breaking changes
|
|
57
|
+
|
|
58
|
+
- Rename loop to host and Loop to Hosts [#370](https://github.com/fleming79/async-kernel/pull/370)
|
|
59
|
+
|
|
60
|
+
### <!-- 5 --> 📝 Documentation
|
|
61
|
+
|
|
62
|
+
- Update event loop documentation. [#372](https://github.com/fleming79/async-kernel/pull/372)
|
|
63
|
+
|
|
64
|
+
- Update readme [#371](https://github.com/fleming79/async-kernel/pull/371)
|
|
65
|
+
|
|
66
|
+
### <!-- 6 --> 🌀 Miscellaneous
|
|
67
|
+
|
|
68
|
+
- Prepare for release v0.14.0 [#373](https://github.com/fleming79/async-kernel/pull/373)
|
|
69
|
+
|
|
8
70
|
## [0.13.3] - 2026-03-23
|
|
9
71
|
|
|
10
72
|
### <!-- 0 --> 🏗️ Breaking changes
|
|
@@ -15,6 +77,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
15
77
|
|
|
16
78
|
### <!-- 6 --> 🌀 Miscellaneous
|
|
17
79
|
|
|
80
|
+
- Prepare for release v0.13.3 [#369](https://github.com/fleming79/async-kernel/pull/369)
|
|
81
|
+
|
|
18
82
|
- Minor SingleConsumerAsyncQueue optimization. [#368](https://github.com/fleming79/async-kernel/pull/368)
|
|
19
83
|
|
|
20
84
|
- Fixtest_command_start_kernel_enable_matplotlib [#367](https://github.com/fleming79/async-kernel/pull/367)
|
|
@@ -1023,6 +1087,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1023
1087
|
|
|
1024
1088
|
- Bump the actions group across 1 directory with 2 updates [#3](https://github.com/fleming79/async-kernel/pull/3)
|
|
1025
1089
|
|
|
1090
|
+
[0.15.0]: https://github.com/fleming79/async-kernel/compare/v0.14.0..v0.15.0
|
|
1091
|
+
[0.14.0]: https://github.com/fleming79/async-kernel/compare/v0.13.3..v0.14.0
|
|
1026
1092
|
[0.13.3]: https://github.com/fleming79/async-kernel/compare/v0.13.2..v0.13.3
|
|
1027
1093
|
[0.13.2]: https://github.com/fleming79/async-kernel/compare/v0.13.1..v0.13.2
|
|
1028
1094
|
[0.13.1]: https://github.com/fleming79/async-kernel/compare/v0.13.0..v0.13.1
|
|
@@ -208,3 +208,14 @@ uv run mkdocs build -s
|
|
|
208
208
|
tests can still fail for another os or python version.
|
|
209
209
|
|
|
210
210
|
[^test-pypi]: This workflow also runs on push to the main branch, but will instead publish to [TestPyPI](https://test.pypi.org/project/async-kernel/).
|
|
211
|
+
|
|
212
|
+
## VS code development
|
|
213
|
+
|
|
214
|
+
Debug configurations are included to support debugging with VS Code.
|
|
215
|
+
|
|
216
|
+
- Python: Debug Tests: This config is for attaching a debugger when launching tests.
|
|
217
|
+
The recommended way to debug tests.
|
|
218
|
+
- Python and Jupyterlab (Requires VS Code >1.112.0): This provides a compound launch configuration
|
|
219
|
+
which starts Jupyterlab and Python. The built in browser launches attaches to the Jupyter session
|
|
220
|
+
(refresh may be required after the server has started). The advantage of this configuration
|
|
221
|
+
is that all Python processes are attached to the debugger whenever a kernel is opened.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: async-kernel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: A concurrent python kernel for Jupyter supporting AnyIO, AsyncIO and Trio.
|
|
5
5
|
Project-URL: Homepage, https://fleming79.github.io/async-kernel
|
|
6
6
|
Project-URL: Documentation, https://fleming79.github.io/async-kernel
|
|
@@ -29,6 +29,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
29
29
|
Classifier: Programming Language :: Python :: 3.12
|
|
30
30
|
Classifier: Programming Language :: Python :: 3.13
|
|
31
31
|
Classifier: Programming Language :: Python :: 3.14
|
|
32
|
+
Classifier: Programming Language :: Python :: Free Threading :: 1 - Unstable
|
|
32
33
|
Classifier: Typing :: Typed
|
|
33
34
|
Requires-Python: >=3.11
|
|
34
35
|
Requires-Dist: aiologic>=0.16.0
|
|
@@ -38,7 +39,7 @@ Requires-Dist: ipython>=9.0
|
|
|
38
39
|
Requires-Dist: jupyter-client>=8.8; sys_platform != 'emscripten'
|
|
39
40
|
Requires-Dist: jupyter-core>=5.9.1
|
|
40
41
|
Requires-Dist: matplotlib-inline>0.1
|
|
41
|
-
Requires-Dist: orjson>=3.10.16
|
|
42
|
+
Requires-Dist: orjson>=3.10.16; sys_platform == 'emscripten'
|
|
42
43
|
Requires-Dist: outcome; sys_platform != 'emscripten'
|
|
43
44
|
Requires-Dist: pyzmq>=27.0; sys_platform != 'emscripten'
|
|
44
45
|
Requires-Dist: sniffio>=1.3.0; sys_platform != 'emscripten'
|
|
@@ -65,12 +66,13 @@ that provides concurrent message handling via an asynchronous backend (asyncio o
|
|
|
65
66
|
|
|
66
67
|
The kernel provides two external interfaces:
|
|
67
68
|
|
|
68
|
-
1. Direct ZMQ socket messaging via a configuration file and kernel spec - (Jupyter,
|
|
69
|
+
1. Direct ZMQ socket messaging via a configuration file and kernel spec - (Jupyter, VS Code, etc).
|
|
69
70
|
2. An experimental callback style interface (Jupyterlite).
|
|
70
71
|
|
|
71
72
|
## Highlights
|
|
72
73
|
|
|
73
74
|
- [IPython shell](https://ipython.readthedocs.io/en/stable/overview.html#enhanced-interactive-python-shell)
|
|
75
|
+
- top-level await ('asyncio' or 'trio' backend) in cells
|
|
74
76
|
- [anyio](https://pypi.org/project/anyio/) compatible asynchronous backend ([`asyncio`](https://docs.python.org/3/library/asyncio.html) (default) or [`trio`](https://pypi.org/project/trio/))
|
|
75
77
|
- [aiologic](https://aiologic.readthedocs.io/latest/) thread-safe synchronisation primitives
|
|
76
78
|
- [Backend agnostic multi-thread / multi-event loop management](https://fleming79.github.io/async-kernel/latest/reference/caller/#async_kernel.caller.Caller)
|
|
@@ -85,9 +87,8 @@ The kernel provides two external interfaces:
|
|
|
85
87
|
- [Debugger client](https://jupyterlab.readthedocs.io/en/latest/user/debugger.html#debugger)
|
|
86
88
|
|
|
87
89
|
[^1]:
|
|
88
|
-
A gui (_host_) enabled kernel
|
|
89
|
-
|
|
90
|
-
deliberate design choice to to ensure good performance and reliability.
|
|
90
|
+
A gui (_host_) enabled kernel interface starts a gui's mainloop (host) which starts
|
|
91
|
+
the backend as a guest, then finally the Kernel is started.
|
|
91
92
|
|
|
92
93
|
[^2]:
|
|
93
94
|
The asyncio implementation of `start_guest_run` was written by
|
|
@@ -105,24 +106,40 @@ Another problem exists when an asynchronous execute request awaits a result that
|
|
|
105
106
|
via a kernel message - this will cause a deadlock because the message will be stuck in the queue behind
|
|
106
107
|
the _blocking_ execute request[^5].
|
|
107
108
|
|
|
108
|
-
async-kernel handles messages according to the channel
|
|
109
|
+
async-kernel handles messages according to the channel and message type. So widget com message
|
|
109
110
|
will get processed in a separate queue to an execute request. Further detail is given in the [concurrency notebook](https://fleming79.github.io/async-kernel/latest/notebooks/concurrency/), a Jupyterlite version is available [here](https://fleming79.github.io/echo-kernel/).
|
|
110
111
|
|
|
111
112
|
#### Example
|
|
112
113
|
|
|
113
|
-
|
|
114
|
+
Make a blocking call in a Jupyter lab notebook or console.
|
|
114
115
|
|
|
115
116
|
```python
|
|
116
|
-
# Make the shell thread busy
|
|
117
|
+
# Make the shell's thread busy
|
|
117
118
|
import time
|
|
118
119
|
|
|
119
120
|
time.sleep(1e6)
|
|
120
121
|
```
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
While the above is _blocking_ (the kernel is _busy_).
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
```python
|
|
126
|
+
dir() # try code completion (tab) or view the docstring (shift tab)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Interrupt the kernel.
|
|
130
|
+
|
|
131
|
+
It also works for awaitables.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
import ipywidgets as ipw
|
|
135
|
+
from aiologic import Event
|
|
136
|
+
|
|
137
|
+
b = ipw.Button(description="Click me")
|
|
138
|
+
event = Event()
|
|
139
|
+
b.on_click(lambda _: event.set())
|
|
140
|
+
display(b)
|
|
141
|
+
await event
|
|
142
|
+
```
|
|
126
143
|
|
|
127
144
|
[^5]:
|
|
128
145
|
IPyKernel _solves_ this issue specifically for widgets by using the concept of
|
|
@@ -165,11 +182,11 @@ The kernel can be started with a gui event loop as the _host_ and the _backend_
|
|
|
165
182
|
|
|
166
183
|
```bash
|
|
167
184
|
# tk
|
|
168
|
-
async-kernel -a async-tk --interface.
|
|
185
|
+
async-kernel -a async-tk --interface.host=tk
|
|
169
186
|
|
|
170
187
|
# qt
|
|
171
188
|
pip install PySide6-Essentials
|
|
172
|
-
async-kernel -a async-qt --interface.
|
|
189
|
+
async-kernel -a async-qt --interface.host=qt
|
|
173
190
|
```
|
|
174
191
|
|
|
175
192
|
#### trio backend
|
|
@@ -177,15 +194,25 @@ async-kernel -a async-qt --interface.loop=qt
|
|
|
177
194
|
```bash
|
|
178
195
|
pip install trio
|
|
179
196
|
# tk
|
|
180
|
-
async-kernel -a async-tk --interface.
|
|
197
|
+
async-kernel -a async-tk --interface.host=tk --interface.backend=trio
|
|
181
198
|
|
|
182
199
|
# qt
|
|
183
200
|
pip install PySide6-Essentials
|
|
184
|
-
async-kernel -a async-qt --interface.
|
|
201
|
+
async-kernel -a async-qt --interface.host=qt --interface.backend=trio
|
|
185
202
|
```
|
|
186
203
|
|
|
187
204
|
For further detail about kernel spec customisation see [command line and kernel configuration](https://fleming79.github.io/async-kernel/latest/usage/commands/).
|
|
188
205
|
|
|
206
|
+
## Faster data serialization
|
|
207
|
+
|
|
208
|
+
[orjson](https://github.com/ijl/orjson) (a fast JSON library) is supported and will be used by default if it has been installed.
|
|
209
|
+
|
|
210
|
+
## Free-threading support
|
|
211
|
+
|
|
212
|
+
async-kernel's Caller's are _thread-local_ and it's methods are _internally synchronised_[^4].
|
|
213
|
+
|
|
214
|
+
[^4]: [free threading terminology](https://py-free-threading.github.io/documentation-principles/#free-threading-terminology)
|
|
215
|
+
|
|
189
216
|
## Origin
|
|
190
217
|
|
|
191
218
|
async-kernel started as a [fork](https://github.com/ipython/ipykernel/commit/8322a7684b004ee95f07b2f86f61e28146a5996d)
|
|
@@ -16,12 +16,13 @@ that provides concurrent message handling via an asynchronous backend (asyncio o
|
|
|
16
16
|
|
|
17
17
|
The kernel provides two external interfaces:
|
|
18
18
|
|
|
19
|
-
1. Direct ZMQ socket messaging via a configuration file and kernel spec - (Jupyter,
|
|
19
|
+
1. Direct ZMQ socket messaging via a configuration file and kernel spec - (Jupyter, VS Code, etc).
|
|
20
20
|
2. An experimental callback style interface (Jupyterlite).
|
|
21
21
|
|
|
22
22
|
## Highlights
|
|
23
23
|
|
|
24
24
|
- [IPython shell](https://ipython.readthedocs.io/en/stable/overview.html#enhanced-interactive-python-shell)
|
|
25
|
+
- top-level await ('asyncio' or 'trio' backend) in cells
|
|
25
26
|
- [anyio](https://pypi.org/project/anyio/) compatible asynchronous backend ([`asyncio`](https://docs.python.org/3/library/asyncio.html) (default) or [`trio`](https://pypi.org/project/trio/))
|
|
26
27
|
- [aiologic](https://aiologic.readthedocs.io/latest/) thread-safe synchronisation primitives
|
|
27
28
|
- [Backend agnostic multi-thread / multi-event loop management](https://fleming79.github.io/async-kernel/latest/reference/caller/#async_kernel.caller.Caller)
|
|
@@ -36,9 +37,8 @@ The kernel provides two external interfaces:
|
|
|
36
37
|
- [Debugger client](https://jupyterlab.readthedocs.io/en/latest/user/debugger.html#debugger)
|
|
37
38
|
|
|
38
39
|
[^1]:
|
|
39
|
-
A gui (_host_) enabled kernel
|
|
40
|
-
|
|
41
|
-
deliberate design choice to to ensure good performance and reliability.
|
|
40
|
+
A gui (_host_) enabled kernel interface starts a gui's mainloop (host) which starts
|
|
41
|
+
the backend as a guest, then finally the Kernel is started.
|
|
42
42
|
|
|
43
43
|
[^2]:
|
|
44
44
|
The asyncio implementation of `start_guest_run` was written by
|
|
@@ -56,24 +56,40 @@ Another problem exists when an asynchronous execute request awaits a result that
|
|
|
56
56
|
via a kernel message - this will cause a deadlock because the message will be stuck in the queue behind
|
|
57
57
|
the _blocking_ execute request[^5].
|
|
58
58
|
|
|
59
|
-
async-kernel handles messages according to the channel
|
|
59
|
+
async-kernel handles messages according to the channel and message type. So widget com message
|
|
60
60
|
will get processed in a separate queue to an execute request. Further detail is given in the [concurrency notebook](https://fleming79.github.io/async-kernel/latest/notebooks/concurrency/), a Jupyterlite version is available [here](https://fleming79.github.io/echo-kernel/).
|
|
61
61
|
|
|
62
62
|
#### Example
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
Make a blocking call in a Jupyter lab notebook or console.
|
|
65
65
|
|
|
66
66
|
```python
|
|
67
|
-
# Make the shell thread busy
|
|
67
|
+
# Make the shell's thread busy
|
|
68
68
|
import time
|
|
69
69
|
|
|
70
70
|
time.sleep(1e6)
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
While the above is _blocking_ (the kernel is _busy_).
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
```python
|
|
76
|
+
dir() # try code completion (tab) or view the docstring (shift tab)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Interrupt the kernel.
|
|
80
|
+
|
|
81
|
+
It also works for awaitables.
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
import ipywidgets as ipw
|
|
85
|
+
from aiologic import Event
|
|
86
|
+
|
|
87
|
+
b = ipw.Button(description="Click me")
|
|
88
|
+
event = Event()
|
|
89
|
+
b.on_click(lambda _: event.set())
|
|
90
|
+
display(b)
|
|
91
|
+
await event
|
|
92
|
+
```
|
|
77
93
|
|
|
78
94
|
[^5]:
|
|
79
95
|
IPyKernel _solves_ this issue specifically for widgets by using the concept of
|
|
@@ -116,11 +132,11 @@ The kernel can be started with a gui event loop as the _host_ and the _backend_
|
|
|
116
132
|
|
|
117
133
|
```bash
|
|
118
134
|
# tk
|
|
119
|
-
async-kernel -a async-tk --interface.
|
|
135
|
+
async-kernel -a async-tk --interface.host=tk
|
|
120
136
|
|
|
121
137
|
# qt
|
|
122
138
|
pip install PySide6-Essentials
|
|
123
|
-
async-kernel -a async-qt --interface.
|
|
139
|
+
async-kernel -a async-qt --interface.host=qt
|
|
124
140
|
```
|
|
125
141
|
|
|
126
142
|
#### trio backend
|
|
@@ -128,15 +144,25 @@ async-kernel -a async-qt --interface.loop=qt
|
|
|
128
144
|
```bash
|
|
129
145
|
pip install trio
|
|
130
146
|
# tk
|
|
131
|
-
async-kernel -a async-tk --interface.
|
|
147
|
+
async-kernel -a async-tk --interface.host=tk --interface.backend=trio
|
|
132
148
|
|
|
133
149
|
# qt
|
|
134
150
|
pip install PySide6-Essentials
|
|
135
|
-
async-kernel -a async-qt --interface.
|
|
151
|
+
async-kernel -a async-qt --interface.host=qt --interface.backend=trio
|
|
136
152
|
```
|
|
137
153
|
|
|
138
154
|
For further detail about kernel spec customisation see [command line and kernel configuration](https://fleming79.github.io/async-kernel/latest/usage/commands/).
|
|
139
155
|
|
|
156
|
+
## Faster data serialization
|
|
157
|
+
|
|
158
|
+
[orjson](https://github.com/ijl/orjson) (a fast JSON library) is supported and will be used by default if it has been installed.
|
|
159
|
+
|
|
160
|
+
## Free-threading support
|
|
161
|
+
|
|
162
|
+
async-kernel's Caller's are _thread-local_ and it's methods are _internally synchronised_[^4].
|
|
163
|
+
|
|
164
|
+
[^4]: [free threading terminology](https://py-free-threading.github.io/documentation-principles/#free-threading-terminology)
|
|
165
|
+
|
|
140
166
|
## Origin
|
|
141
167
|
|
|
142
168
|
async-kernel started as a [fork](https://github.com/ipython/ipykernel/commit/8322a7684b004ee95f07b2f86f61e28146a5996d)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.15.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 15, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"\n",
|
|
16
16
|
"_This notebook has the Python dependencies: `trio`, `matplotlib`_\n",
|
|
17
17
|
"\n",
|
|
18
|
-
"`Caller` is a class that
|
|
18
|
+
"`Caller` is a thread-local class that coordinates the execution of functions and coroutines in the event loop of a `asyncio` or `trio` backend."
|
|
19
19
|
]
|
|
20
20
|
},
|
|
21
21
|
{
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"metadata": {},
|
|
36
36
|
"source": [
|
|
37
37
|
"A `Caller` instance can be started with one gui as a host to one backend started as a guest. \n",
|
|
38
|
+
"\n",
|
|
38
39
|
"A second backend can also be started in the same thread with or without a host gui event loop.\n",
|
|
39
40
|
"Potentially the same thread could have up to:\n",
|
|
40
41
|
"\n",
|
|
@@ -77,11 +78,10 @@
|
|
|
77
78
|
"id": "5",
|
|
78
79
|
"metadata": {},
|
|
79
80
|
"source": [
|
|
80
|
-
"There are
|
|
81
|
+
"There are two caller instances associated with the Kernel:\n",
|
|
81
82
|
"\n",
|
|
82
83
|
"- Shell: The caller for the shell channel (normally the MainThread).\n",
|
|
83
|
-
"- Control: The caller for the control channel (a child of the shell)
|
|
84
|
-
"- Shell thread_queue: A separate thread to handle shell messages in a separate thread (queued by message type and subshell_id)."
|
|
84
|
+
"- Control: The caller for the control channel (a child of the shell)."
|
|
85
85
|
]
|
|
86
86
|
},
|
|
87
87
|
{
|
|
@@ -89,7 +89,9 @@
|
|
|
89
89
|
"id": "6",
|
|
90
90
|
"metadata": {},
|
|
91
91
|
"source": [
|
|
92
|
-
"Calling `Caller()` with no arguments will return the caller for the current thread (context in Pyodide).
|
|
92
|
+
"Calling `Caller()` with no arguments will return the caller for the current thread (or context in Pyodide). \n",
|
|
93
|
+
"\n",
|
|
94
|
+
"A runtime error will occur if there is no event loop (backend) running in the current thread (unlikely in Pyodide which provides a running event loop)."
|
|
93
95
|
]
|
|
94
96
|
},
|
|
95
97
|
{
|
|
@@ -111,7 +113,7 @@
|
|
|
111
113
|
"source": [
|
|
112
114
|
"## Modifiers\n",
|
|
113
115
|
"\n",
|
|
114
|
-
"There are four modifiers that determine
|
|
116
|
+
"There are four modifiers that determine which instance is returned when calling `Caller`.\n",
|
|
115
117
|
"\n",
|
|
116
118
|
"- `CurrentThread` (default): Access the caller that belongs to the current thread (or context with Pyodide).\n",
|
|
117
119
|
"- `MainThread`: Access main thread for the Caller.\n",
|
|
@@ -285,7 +287,9 @@
|
|
|
285
287
|
"source": [
|
|
286
288
|
"### Caller.call_using_backend\n",
|
|
287
289
|
"\n",
|
|
288
|
-
"This method calls functions and coroutines using a specific asynchronous backend in the same thread.
|
|
290
|
+
"This method calls functions and coroutines using a specific asynchronous backend in the same thread. \n",
|
|
291
|
+
"\n",
|
|
292
|
+
"When the backend does not match the callers backend, it is run with the backend running as a guest."
|
|
289
293
|
]
|
|
290
294
|
},
|
|
291
295
|
{
|
|
@@ -490,10 +494,13 @@
|
|
|
490
494
|
"metadata": {},
|
|
491
495
|
"outputs": [],
|
|
492
496
|
"source": [
|
|
497
|
+
"import anyio\n",
|
|
498
|
+
"\n",
|
|
493
499
|
"async with caller.create_pending_group() as pg:\n",
|
|
494
|
-
" caller.call_soon(
|
|
495
|
-
" caller.call_later(0,
|
|
496
|
-
" caller.to_thread(
|
|
500
|
+
" caller.call_soon(anyio.sleep, 0.01)\n",
|
|
501
|
+
" caller.call_later(0, anyio.sleep, 0)\n",
|
|
502
|
+
" caller.to_thread(anyio.sleep, 0.01)\n",
|
|
503
|
+
" caller.call_using_backend(\"asyncio\", asyncio.sleep, 0.01)\n",
|
|
497
504
|
" caller.call_using_backend(\"trio\", trio.sleep, 0.01)\n",
|
|
498
505
|
" print(\"In context pending=\", len(pg.pending))\n",
|
|
499
506
|
"\n",
|
|
@@ -12,6 +12,6 @@ The reference section provides documentation for each module in async-kernel.
|
|
|
12
12
|
## Highlights
|
|
13
13
|
|
|
14
14
|
- [Kernel][async_kernel.kernel.Kernel] - The kernel.
|
|
15
|
-
- [Caller][async_kernel.caller.Caller] - Simplifies event loop management and call scheduling
|
|
16
|
-
- [Pending][async_kernel.pending.Pending] - Represents a pending result that can be
|
|
15
|
+
- [Caller][async_kernel.caller.Caller] - Simplifies event loop management and call scheduling.
|
|
16
|
+
- [Pending][async_kernel.pending.Pending] - Represents a pending result (like an [asyncio.Future][] that can be awaited anywhere).
|
|
17
17
|
- [command_line][async_kernel.command.command_line] - The command line interface.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Thread Safety of Built-in Types
|
|
2
|
+
|
|
3
|
+
- [Terminology](https://py-free-threading.github.io/documentation-principles/#free-threading-terminology)
|
|
4
|
+
|
|
5
|
+
_aync-kernel_ utilises [aiologic](https://aiologic.readthedocs.io/latest/index.html) for its _thread-safe_ primitives.
|
|
6
|
+
|
|
7
|
+
## [async_kernel.pending.Pending][]
|
|
8
|
+
|
|
9
|
+
### Guarantees
|
|
10
|
+
|
|
11
|
+
- **Internally synchronised**
|
|
12
|
+
- All Public methods can be safely called from any thread.
|
|
13
|
+
- Instance are sync/async awaitable from any thread with any backend.
|
|
14
|
+
|
|
15
|
+
- **Limitations**
|
|
16
|
+
|
|
17
|
+
[add_done_callback][async_kernel.pending.Pending.add_done_callback]: The callback is called from the thread in which it is set
|
|
18
|
+
so should provide it's own synchronisation as needed.
|
|
19
|
+
|
|
20
|
+
## [async_kernel.caller.Caller][]
|
|
21
|
+
|
|
22
|
+
`Caller` is thread-local in CPython and context-local in Pyodide.
|
|
23
|
+
|
|
24
|
+
### Guarantees
|
|
25
|
+
|
|
26
|
+
- **Internally synchronised**
|
|
27
|
+
|
|
28
|
+
- **Limitations**
|
|
29
|
+
- [queue_call][async_kernel.caller.Caller.queue_call] is internally synchronised per-function after
|
|
30
|
+
the first call (per-function) has returned.
|
|
31
|
+
|
|
32
|
+
## [async_kernel.common.Fixed][]
|
|
33
|
+
|
|
34
|
+
### Guarantees
|
|
35
|
+
|
|
36
|
+
- **Internally synchronised**
|
|
37
|
+
|
|
38
|
+
### Other classes
|
|
39
|
+
|
|
40
|
+
TODO
|