async-kernel 0.20.2__tar.gz → 0.22.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 (133) hide show
  1. {async_kernel-0.20.2 → async_kernel-0.22.0}/.github/workflows/ci.yml +6 -6
  2. {async_kernel-0.20.2 → async_kernel-0.22.0}/.github/workflows/new_release.yml +1 -1
  3. {async_kernel-0.20.2 → async_kernel-0.22.0}/.github/workflows/pre-commit.yml +1 -1
  4. {async_kernel-0.20.2 → async_kernel-0.22.0}/.github/workflows/publish-docs.yml +1 -1
  5. {async_kernel-0.20.2 → async_kernel-0.22.0}/.github/workflows/publish-to-pypi.yml +1 -1
  6. {async_kernel-0.20.2 → async_kernel-0.22.0}/.pre-commit-config.yaml +6 -6
  7. {async_kernel-0.20.2 → async_kernel-0.22.0}/.vscode/settings.json +4 -1
  8. {async_kernel-0.20.2 → async_kernel-0.22.0}/CHANGELOG.md +113 -1
  9. {async_kernel-0.20.2 → async_kernel-0.22.0}/PKG-INFO +15 -60
  10. {async_kernel-0.20.2 → async_kernel-0.22.0}/README.md +12 -57
  11. {async_kernel-0.20.2 → async_kernel-0.22.0}/_version.py +2 -2
  12. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/notebooks/caller.ipynb +18 -18
  13. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/notebooks/concurrency.ipynb +26 -17
  14. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/notebooks/custom_kernel.ipynb +4 -4
  15. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/event_loop.md +2 -0
  16. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/interface.md +0 -2
  17. async_kernel-0.22.0/docs/reference/messaging.md +3 -0
  18. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/usage/commands.md +2 -2
  19. {async_kernel-0.20.2 → async_kernel-0.22.0}/mkdocs.yml +2 -0
  20. async_kernel-0.22.0/pyproject.toml +273 -0
  21. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/caller.py +561 -313
  22. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/comm.py +13 -15
  23. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/command.py +5 -7
  24. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/common.py +11 -25
  25. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/compat/attr_docs.py +0 -1
  26. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/compat/json.py +5 -7
  27. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/compiler.py +2 -4
  28. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/debugger.py +21 -34
  29. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/event_loop/run.py +17 -20
  30. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/event_loop/tk_host.py +3 -7
  31. async_kernel-0.22.0/src/async_kernel/event_loop/zmq_poll.py +427 -0
  32. async_kernel-0.22.0/src/async_kernel/interface/__init__.py +25 -0
  33. async_kernel-0.22.0/src/async_kernel/interface/base.py +558 -0
  34. async_kernel-0.22.0/src/async_kernel/interface/callable.py +116 -0
  35. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/interface/ip_app.py +14 -28
  36. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/kernel.py +128 -182
  37. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/kernelspec.py +9 -13
  38. async_kernel-0.22.0/src/async_kernel/messaging/__init__.py +3 -0
  39. async_kernel-0.22.0/src/async_kernel/messaging/base.py +458 -0
  40. async_kernel-0.22.0/src/async_kernel/messaging/zmq.py +423 -0
  41. async_kernel-0.22.0/src/async_kernel/outstream.py +95 -0
  42. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/pending.py +81 -90
  43. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/shell/base.py +10 -19
  44. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/shell/ipshell.py +68 -88
  45. async_kernel-0.22.0/src/async_kernel/typing.py +615 -0
  46. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/utils.py +32 -41
  47. async_kernel-0.22.0/tests/conftest.py +101 -0
  48. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/references.py +26 -26
  49. async_kernel-0.22.0/tests/test_callable_interface.py +77 -0
  50. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_caller.py +359 -149
  51. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_comm.py +2 -1
  52. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_command.py +24 -65
  53. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_common.py +2 -1
  54. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_compat.py +4 -8
  55. async_kernel-0.22.0/tests/test_connection.py +69 -0
  56. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_debugger.py +15 -22
  57. async_kernel-0.22.0/tests/test_debugger_static.py +59 -0
  58. async_kernel-0.22.0/tests/test_enter_kernel.py +39 -0
  59. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_event_loop.py +10 -3
  60. async_kernel-0.22.0/tests/test_eventloop_zmq_poll.py +250 -0
  61. async_kernel-0.20.2/tests/test_base_interface.py → async_kernel-0.22.0/tests/test_interface.py +67 -22
  62. async_kernel-0.20.2/tests/test_zmq_interface_ip.py → async_kernel-0.22.0/tests/test_ipapp.py +13 -3
  63. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_kernel_ipshell.py +127 -148
  64. async_kernel-0.22.0/tests/test_message_spec.py +283 -0
  65. async_kernel-0.20.2/tests/test_iostream.py → async_kernel-0.22.0/tests/test_outstream.py +15 -9
  66. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_pending.py +45 -3
  67. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_subclass.py +3 -3
  68. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_typing.py +22 -0
  69. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_utils.py +2 -5
  70. async_kernel-0.22.0/tests/test_zmq_connection.py +179 -0
  71. async_kernel-0.22.0/tests/test_zmq_subprocess.py +127 -0
  72. async_kernel-0.22.0/tests/utils.py +80 -0
  73. {async_kernel-0.20.2 → async_kernel-0.22.0}/uv.lock +953 -818
  74. async_kernel-0.20.2/pyproject.toml +0 -254
  75. async_kernel-0.20.2/src/async_kernel/interface/__init__.py +0 -64
  76. async_kernel-0.20.2/src/async_kernel/interface/base.py +0 -539
  77. async_kernel-0.20.2/src/async_kernel/interface/callable.py +0 -151
  78. async_kernel-0.20.2/src/async_kernel/interface/zmq.py +0 -346
  79. async_kernel-0.20.2/src/async_kernel/typing.py +0 -472
  80. async_kernel-0.20.2/tests/conftest.py +0 -195
  81. async_kernel-0.20.2/tests/test_callable_interface.py +0 -96
  82. async_kernel-0.20.2/tests/test_debugger_static.py +0 -67
  83. async_kernel-0.20.2/tests/test_encryption.py +0 -29
  84. async_kernel-0.20.2/tests/test_enter_kernel.py +0 -24
  85. async_kernel-0.20.2/tests/test_message_spec.py +0 -338
  86. async_kernel-0.20.2/tests/test_zmq_interface.py +0 -207
  87. async_kernel-0.20.2/tests/utils.py +0 -209
  88. {async_kernel-0.20.2 → async_kernel-0.22.0}/.github/dependabot.yaml +0 -0
  89. {async_kernel-0.20.2 → async_kernel-0.22.0}/.github/release.yml +0 -0
  90. {async_kernel-0.20.2 → async_kernel-0.22.0}/.github/workflows/enforce-label.yml +0 -0
  91. {async_kernel-0.20.2 → async_kernel-0.22.0}/.gitignore +0 -0
  92. {async_kernel-0.20.2 → async_kernel-0.22.0}/.vscode/launch.json +0 -0
  93. {async_kernel-0.20.2 → async_kernel-0.22.0}/.vscode/spellright.dict +0 -0
  94. {async_kernel-0.20.2 → async_kernel-0.22.0}/CONTRIBUTING.md +0 -0
  95. {async_kernel-0.20.2 → async_kernel-0.22.0}/IPYTHON_LICENSE +0 -0
  96. {async_kernel-0.20.2 → async_kernel-0.22.0}/LICENSE +0 -0
  97. {async_kernel-0.20.2 → async_kernel-0.22.0}/cliff.toml +0 -0
  98. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/about/changelog.md +0 -0
  99. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/about/contributing.md +0 -0
  100. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/about/index.md +0 -0
  101. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/about/license.md +0 -0
  102. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/index.md +0 -0
  103. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/javascripts/extra.js +0 -0
  104. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/overrides/main.html +0 -0
  105. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/caller.md +0 -0
  106. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/comm.md +0 -0
  107. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/command.md +0 -0
  108. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/common.md +0 -0
  109. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/debugger.md +0 -0
  110. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/index.md +0 -0
  111. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/ipshell.md +0 -0
  112. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/kernel.md +0 -0
  113. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/kernelspec.md +0 -0
  114. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/pending.md +0 -0
  115. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/shell.md +0 -0
  116. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/typing.md +0 -0
  117. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/reference/utils.md +0 -0
  118. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/stylesheets/extra.css +0 -0
  119. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/thread_safety.md +0 -0
  120. {async_kernel-0.20.2 → async_kernel-0.22.0}/docs/usage/index.md +0 -0
  121. {async_kernel-0.20.2 → async_kernel-0.22.0}/hatch_build.py +0 -0
  122. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/__init__.py +0 -0
  123. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/__main__.py +0 -0
  124. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/event_loop/__init__.py +0 -0
  125. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/event_loop/asyncio_guest.py +0 -0
  126. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/event_loop/qt_host.py +0 -0
  127. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/py.typed +0 -0
  128. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/resources/logo-32x32.png +0 -0
  129. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/resources/logo-64x64.png +0 -0
  130. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/resources/logo-svg.svg +0 -0
  131. {async_kernel-0.20.2 → async_kernel-0.22.0}/src/async_kernel/shell/__init__.py +0 -0
  132. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/__init__.py +0 -0
  133. {async_kernel-0.20.2 → async_kernel-0.22.0}/tests/test_kernelspec.py +0 -0
@@ -20,12 +20,12 @@ jobs:
20
20
  fetch-depth: 0
21
21
 
22
22
  - name: Install uv
23
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
23
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
24
24
 
25
25
  - name: Type checking with basedpyright
26
26
  run: |
27
27
  uv sync
28
- uvx basedpyright@1.39.8
28
+ uvx basedpyright@1.39.9
29
29
 
30
30
  test:
31
31
  needs: type-checking
@@ -45,7 +45,7 @@ jobs:
45
45
  uses: actions/checkout@v7
46
46
 
47
47
  - name: Install uv
48
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
48
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
49
49
  with:
50
50
  version-file: "pyproject.toml"
51
51
  python-version: ${{ matrix.python-version }}
@@ -71,7 +71,7 @@ jobs:
71
71
  if: ${{runner.debug == '1'}}
72
72
  timeout-minutes: 3
73
73
  run: |
74
- uv run pytest -vvl --override-ini=log_cli_level=DEBUG --override-ini=log_cli=true
74
+ uv run pytest -vvl --override-ini=log_cli_level=DEBUG
75
75
 
76
76
  - name: Run tests
77
77
  if: ${{runner.debug != '1'}}
@@ -87,7 +87,7 @@ jobs:
87
87
  fetch-depth: 0
88
88
 
89
89
  - name: Install uv
90
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
90
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
91
91
  with:
92
92
  version-file: "pyproject.toml"
93
93
  python-version: "3.13"
@@ -116,7 +116,7 @@ jobs:
116
116
  fetch-depth: 0
117
117
 
118
118
  - name: Install uv
119
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
119
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
120
120
  with:
121
121
  version-file: "pyproject.toml"
122
122
 
@@ -31,7 +31,7 @@ jobs:
31
31
  fetch-depth: 0
32
32
  ref: main
33
33
  - name: Install uv
34
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
34
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
35
35
  with:
36
36
  version-file: "pyproject.toml"
37
37
 
@@ -8,7 +8,7 @@ jobs:
8
8
  runs-on: ubuntu-latest
9
9
  steps:
10
10
  - uses: actions/checkout@v7
11
- - uses: actions/setup-python@v6
11
+ - uses: actions/setup-python@v7
12
12
  with:
13
13
  python-version: 3.x
14
14
  - uses: pre-commit/action@v3.0.1
@@ -27,7 +27,7 @@ jobs:
27
27
  git config user.email 41898282+github-actions[bot]@users.noreply.github.com
28
28
 
29
29
  - name: Install uv
30
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
30
+ uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
31
31
  with:
32
32
  version-file: "pyproject.toml"
33
33
 
@@ -31,7 +31,7 @@ jobs:
31
31
  # Fetch full history for setuptools-scm
32
32
  fetch-depth: 0
33
33
  ref: main
34
- - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
34
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
35
35
  with:
36
36
  version-file: "pyproject.toml"
37
37
 
@@ -28,15 +28,15 @@ repos:
28
28
  - id: check-json5
29
29
 
30
30
  - repo: https://github.com/python-jsonschema/check-jsonschema
31
- rev: 0.37.3
31
+ rev: 0.38.0
32
32
  hooks:
33
33
  - id: check-github-workflows
34
34
 
35
35
  - repo: https://github.com/rbubley/mirrors-prettier
36
- rev: v3.8.4
36
+ rev: v3.9.6
37
37
  hooks:
38
38
  - id: prettier
39
- types_or: [yaml, html, json]
39
+ types_or: [yaml, html, json, toml]
40
40
  - id: prettier
41
41
  types_or: [markdown]
42
42
  args: ["--tab-width", "4"]
@@ -48,7 +48,7 @@ repos:
48
48
  additional_dependencies: [black==23.7.0]
49
49
 
50
50
  - repo: https://github.com/codespell-project/codespell
51
- rev: v2.4.2
51
+ rev: v2.4.3
52
52
  hooks:
53
53
  - id: codespell
54
54
  args: ["-L", "sur,nd"]
@@ -59,7 +59,7 @@ repos:
59
59
  - id: python-use-type-annotations
60
60
 
61
61
  - repo: https://github.com/astral-sh/ruff-pre-commit
62
- rev: v0.15.19
62
+ rev: v0.16.3
63
63
  hooks:
64
64
  - id: ruff-check
65
65
  types_or: [python, jupyter]
@@ -68,7 +68,7 @@ repos:
68
68
  types_or: [python, jupyter]
69
69
 
70
70
  - repo: https://github.com/scientific-python/cookie
71
- rev: 2026.06.18
71
+ rev: 2026.08.14
72
72
  hooks:
73
73
  - id: sp-repo-review
74
74
  additional_dependencies: ["repo-review[cli]"]
@@ -18,5 +18,8 @@
18
18
  "tag:yaml.org,2002:python/object/apply:pymdownx.slugs.slugify mapping"
19
19
  ],
20
20
  "spellright.language": ["en"],
21
- "spellright.documentTypes": ["markdown", "plaintext"]
21
+ "spellright.documentTypes": ["markdown", "plaintext"],
22
+ "[toml]": {
23
+ "editor.defaultFormatter": "tamasfe.even-better-toml"
24
+ }
22
25
  }
@@ -5,7 +5,115 @@ 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.20.2] - 2026-06-29
8
+ ## [0.22.0] - 2026-08-17
9
+
10
+ ### <!-- 0 --> 🏗️ Breaking changes
11
+
12
+ - Major interface refactoring, new features and capabilities [#538](https://github.com/fleming79/async-kernel/pull/538)
13
+
14
+ ### <!-- 1 --> 🚀 Features
15
+
16
+ - Add ShieldedTask. [#553](https://github.com/fleming79/async-kernel/pull/553)
17
+
18
+ - Change caller async context manager to be first in last out, intermediate contexts are not managed. [#549](https://github.com/fleming79/async-kernel/pull/549)
19
+
20
+ - Add ProtectedPending to prevent accidental propagation of cancellation of a cancelled waiter. [#546](https://github.com/fleming79/async-kernel/pull/546)
21
+
22
+ - Add cancellation support in ZMQPoll. [#541](https://github.com/fleming79/async-kernel/pull/541)
23
+
24
+ - Rename Poll to ZMQPoll and add ZMQPollSocket [#539](https://github.com/fleming79/async-kernel/pull/539)
25
+
26
+ - Caller async context management changes [#537](https://github.com/fleming79/async-kernel/pull/537)
27
+
28
+ - Split BaseInterface into BaseMessageApplication [#536](https://github.com/fleming79/async-kernel/pull/536)
29
+
30
+ ### <!-- 2 --> 🐛 Fixes
31
+
32
+ - Fix heartbeat [#532](https://github.com/fleming79/async-kernel/pull/532)
33
+
34
+ ### <!-- 5 --> 📝 Documentation
35
+
36
+ - Use Ruff lint pydocstyle [#531](https://github.com/fleming79/async-kernel/pull/531)
37
+
38
+ ### <!-- 6 --> 🌀 Miscellaneous
39
+
40
+ - Bump uv from 0.11.32 to 0.12.4 [#562](https://github.com/fleming79/async-kernel/pull/562)
41
+
42
+ - Bump astral-sh/setup-uv from 9.0.0 to 10.0.1 in the actions group [#559](https://github.com/fleming79/async-kernel/pull/559)
43
+
44
+ - Pre-commit autoupdate and update uv.lock. [#565](https://github.com/fleming79/async-kernel/pull/565)
45
+
46
+ - Fix pyright type hinting of NoValue. [#564](https://github.com/fleming79/async-kernel/pull/564)
47
+
48
+ - Rename ShieldedTask to StartStopTask. [#557](https://github.com/fleming79/async-kernel/pull/557)
49
+
50
+ - More features fro ShieldedTask. [#556](https://github.com/fleming79/async-kernel/pull/556)
51
+
52
+ - Compatibility fix with ipython. [#555](https://github.com/fleming79/async-kernel/pull/555)
53
+
54
+ - Change ShieldedTask to use set_task_function to set the function and caller to avoid clashing when used as a mixin. [#554](https://github.com/fleming79/async-kernel/pull/554)
55
+
56
+ - Refactor Pending._set_done. [#552](https://github.com/fleming79/async-kernel/pull/552)
57
+
58
+ - Refactor Pending._set_done. [#551](https://github.com/fleming79/async-kernel/pull/551)
59
+
60
+ - Improve Caller auto shutdown support [#550](https://github.com/fleming79/async-kernel/pull/550)
61
+
62
+ - Make Caller a bit safer for shutdown where it's context is held inside a pending task. [#548](https://github.com/fleming79/async-kernel/pull/548)
63
+
64
+ - Improve caller shutdown management and tests [#547](https://github.com/fleming79/async-kernel/pull/547)
65
+
66
+ - Bump astral-sh/setup-uv from 8.3.2 to 9.0.0 in the actions group [#544](https://github.com/fleming79/async-kernel/pull/544)
67
+
68
+ - ZMQPoll support multiple context entry and re-entry. [#545](https://github.com/fleming79/async-kernel/pull/545)
69
+
70
+ - Improve kernel shutdown. [#543](https://github.com/fleming79/async-kernel/pull/543)
71
+
72
+ - More Messge types and general fixes. [#542](https://github.com/fleming79/async-kernel/pull/542)
73
+
74
+ - Improve ZMQPollSocket autoclose. [#540](https://github.com/fleming79/async-kernel/pull/540)
75
+
76
+ - Fix the ident of input request messages. [#535](https://github.com/fleming79/async-kernel/pull/535)
77
+
78
+ - Bump the actions group with 2 updates [#533](https://github.com/fleming79/async-kernel/pull/533)
79
+
80
+ - Improve uv magic. [#534](https://github.com/fleming79/async-kernel/pull/534)
81
+
82
+ ## [0.21.0] - 2026-07-19
83
+
84
+ ### <!-- 1 --> 🚀 Features
85
+
86
+ - Add print_concat to concatenate print statements into a single string when 'file' is not specified. [#522](https://github.com/fleming79/async-kernel/pull/522)
87
+
88
+ - Added PollZMQ - a thread based zmq poller callback registry. [#515](https://github.com/fleming79/async-kernel/pull/515)
89
+
90
+ - Support loop_factory as an importable path. [#514](https://github.com/fleming79/async-kernel/pull/514)
91
+
92
+ ### <!-- 6 --> 🌀 Miscellaneous
93
+
94
+ - Prepare for release v0.21.0 [#530](https://github.com/fleming79/async-kernel/pull/530)
95
+
96
+ - Poll maintenance [#529](https://github.com/fleming79/async-kernel/pull/529)
97
+
98
+ - Add threadsafe option to Poll.socket [#528](https://github.com/fleming79/async-kernel/pull/528)
99
+
100
+ - Update lock files and pre-commit and basedpyright. [#527](https://github.com/fleming79/async-kernel/pull/527)
101
+
102
+ - Kernel updates - handle external kernel interrupt. [#526](https://github.com/fleming79/async-kernel/pull/526)
103
+
104
+ - Add docstrings for Poll [#525](https://github.com/fleming79/async-kernel/pull/525)
105
+
106
+ - Bump astral-sh/setup-uv from 8.2.0 to 8.3.0 in the actions group [#518](https://github.com/fleming79/async-kernel/pull/518)
107
+
108
+ - Change PollZMQ to Poll and move to event_loop/zmq_poll.py. [#524](https://github.com/fleming79/async-kernel/pull/524)
109
+
110
+ - Add more log messages when running pytest from the command line. [#523](https://github.com/fleming79/async-kernel/pull/523)
111
+
112
+ - Move OutStream from kernel.py to outstream.py [#521](https://github.com/fleming79/async-kernel/pull/521)
113
+
114
+ - Refactor Caller. [#520](https://github.com/fleming79/async-kernel/pull/520)
115
+
116
+ ## [0.20.2] - 2026-06-30
9
117
 
10
118
  ### <!-- 5 --> 📝 Documentation
11
119
 
@@ -13,6 +121,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
121
 
14
122
  ### <!-- 6 --> 🌀 Miscellaneous
15
123
 
124
+ - Prepare for release v0.20.2 [#512](https://github.com/fleming79/async-kernel/pull/512)
125
+
16
126
  - Avoid attribute error in Comm.publish_msg in case the parent is gc before the object. [#511](https://github.com/fleming79/async-kernel/pull/511)
17
127
 
18
128
  - Update uv.lock and pre-commit-config.yaml [#510](https://github.com/fleming79/async-kernel/pull/510)
@@ -1419,6 +1529,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1419
1529
 
1420
1530
  - Bump the actions group across 1 directory with 2 updates [#3](https://github.com/fleming79/async-kernel/pull/3)
1421
1531
 
1532
+ [0.22.0]: https://github.com/fleming79/async-kernel/compare/v0.21.0..v0.22.0
1533
+ [0.21.0]: https://github.com/fleming79/async-kernel/compare/v0.20.2..v0.21.0
1422
1534
  [0.20.2]: https://github.com/fleming79/async-kernel/compare/v0.20.1..v0.20.2
1423
1535
  [0.20.1]: https://github.com/fleming79/async-kernel/compare/v0.20.0..v0.20.1
1424
1536
  [0.20.0]: https://github.com/fleming79/async-kernel/compare/v0.19.2..v0.20.0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: async-kernel
3
- Version: 0.20.2
3
+ Version: 0.22.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
@@ -36,7 +36,7 @@ Requires-Python: >=3.11
36
36
  Requires-Dist: aiologic>=0.17.0
37
37
  Requires-Dist: anyio>=4.12
38
38
  Requires-Dist: comm>=0.2
39
- Requires-Dist: ipython>=9.0
39
+ Requires-Dist: ipython>=9.16.1
40
40
  Requires-Dist: jupyter-client>=8.9.1; sys_platform != 'emscripten'
41
41
  Requires-Dist: jupyter-core>=5.9.1
42
42
  Requires-Dist: matplotlib-inline>0.1
@@ -62,22 +62,24 @@ Description-Content-Type: text/markdown
62
62
 
63
63
  ![logo-svg](https://github.com/user-attachments/assets/6781ec08-94e9-4640-b8f9-bb07a08e9587)
64
64
 
65
- async-kernel is a Python kernel for [Jupyter](https://docs.jupyter.org/en/latest/projects/kernels.html#kernels-programming-languages)
66
- that provides concurrent message handling via an asynchronous backend (asyncio or trio).
65
+ async-kernel provides Python [Jupyter](https://docs.jupyter.org/en/latest/projects/kernels.html#kernels-programming-languages) kernels and clients
66
+ compatible with CPython (Jupyter & VS code) and Pyodide (Jupyterlite).
67
67
 
68
- The kernel provides two external interfaces:
68
+ The kernel interface supports multiple connections including:
69
69
 
70
- 1. Direct ZMQ socket messaging via a configuration file and kernel spec - (Jupyter, VS Code, etc).
71
- 2. An experimental callback style interface (Jupyterlite).
70
+ 1. Messaging via ZMQ sockets (Jupyter, VS Code, etc).
71
+ 2. Same-process local client enabling (Jupyterlite) and user access.
72
72
 
73
73
  ## Highlights
74
74
 
75
+ - Built using [aiologic](https://aiologic.readthedocs.io/latest/) thread-safe synchronisation primitives.
76
+ - The [`Caller`](https://fleming79.github.io/async-kernel/latest/reference/caller/#async_kernel.caller.Caller)
77
+ class provides a powerful but simple interface for cross-thread code execution in asyncio and trio
78
+ backends, with guest event loop support built in.
79
+ - A zmq poll event loop for thread-safe zmq sockets.
75
80
  - [IPython shell](https://ipython.readthedocs.io/en/stable/overview.html#enhanced-interactive-python-shell)
76
81
  - top-level await ('asyncio' or 'trio' backend) in cells
77
82
  - async magic function support in cells
78
- - [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/))
79
- - [aiologic](https://aiologic.readthedocs.io/latest/) thread-safe synchronisation primitives
80
- - [Backend agnostic multi-thread / multi-event loop management](https://fleming79.github.io/async-kernel/latest/reference/caller/#async_kernel.caller.Caller)
81
83
  - Per-subshell user_ns
82
84
  - GUI event loops [^1]
83
85
  - [x] inline
@@ -88,6 +90,8 @@ The kernel provides two external interfaces:
88
90
  [Jupyterlite](https://github.com/jupyterlite/jupyterlite) (try it online [here](https://fleming79.github.io/echo-kernel/) 👈)
89
91
  - `%pip install` magic (using micropip)
90
92
  - [Debugger client](https://jupyterlab.readthedocs.io/en/latest/user/debugger.html#debugger)
93
+ - Local client.
94
+ - ZMQ client.
91
95
 
92
96
  [^1]:
93
97
  A gui (_host_) enabled kernel interface starts a gui's mainloop (host) which starts
@@ -100,55 +104,6 @@ The kernel provides two external interfaces:
100
104
 
101
105
  [^3]: trio's [start_guest_run](https://trio.readthedocs.io/en/stable/reference-lowlevel.html#trio.lowlevel.start_guest_run).
102
106
 
103
- ### Avoid deadlocks
104
-
105
- The standard (synchronous) kernel implementation processes messages sequentially irrespective
106
- of the message type. The problem being that long running execute requests make the kernel non-responsive.
107
-
108
- Another problem exists when an asynchronous execute request awaits a result that is delivered
109
- via a kernel message - this will cause a deadlock because the message will be stuck in the queue behind
110
- the _blocking_ execute request[^5].
111
-
112
- async-kernel handles messages according to the channel and message type. So widget com message
113
- 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/).
114
-
115
- #### Example
116
-
117
- Make a blocking call in a Jupyter lab notebook or console.
118
-
119
- ```python
120
- # Make the shell's thread busy
121
- import time
122
-
123
- time.sleep(1e6)
124
- ```
125
-
126
- While the above is _blocking_ (the kernel is _busy_).
127
-
128
- ```python
129
- dir() # try code completion (tab) or view the docstring (shift tab)
130
- ```
131
-
132
- Interrupt the kernel.
133
-
134
- It also works for awaitables.
135
-
136
- ```python
137
- import ipywidgets as ipw
138
- from aiologic import Event
139
-
140
- b = ipw.Button(description="Click me")
141
- event = Event()
142
- b.on_click(lambda _: event.set())
143
- display(b)
144
- await event
145
- ```
146
-
147
- [^5]:
148
- IPyKernel _solves_ this issue specifically for widgets by using the concept of
149
- 'widget coms over subshells'. Widget messages arrive in a different thread which on
150
- occasion can cause unexpected behaviour, especially when using asynchronous libraries.
151
-
152
107
  ## Installation
153
108
 
154
109
  ```bash
@@ -11,22 +11,24 @@
11
11
 
12
12
  ![logo-svg](https://github.com/user-attachments/assets/6781ec08-94e9-4640-b8f9-bb07a08e9587)
13
13
 
14
- async-kernel is a Python kernel for [Jupyter](https://docs.jupyter.org/en/latest/projects/kernels.html#kernels-programming-languages)
15
- that provides concurrent message handling via an asynchronous backend (asyncio or trio).
14
+ async-kernel provides Python [Jupyter](https://docs.jupyter.org/en/latest/projects/kernels.html#kernels-programming-languages) kernels and clients
15
+ compatible with CPython (Jupyter & VS code) and Pyodide (Jupyterlite).
16
16
 
17
- The kernel provides two external interfaces:
17
+ The kernel interface supports multiple connections including:
18
18
 
19
- 1. Direct ZMQ socket messaging via a configuration file and kernel spec - (Jupyter, VS Code, etc).
20
- 2. An experimental callback style interface (Jupyterlite).
19
+ 1. Messaging via ZMQ sockets (Jupyter, VS Code, etc).
20
+ 2. Same-process local client enabling (Jupyterlite) and user access.
21
21
 
22
22
  ## Highlights
23
23
 
24
+ - Built using [aiologic](https://aiologic.readthedocs.io/latest/) thread-safe synchronisation primitives.
25
+ - The [`Caller`](https://fleming79.github.io/async-kernel/latest/reference/caller/#async_kernel.caller.Caller)
26
+ class provides a powerful but simple interface for cross-thread code execution in asyncio and trio
27
+ backends, with guest event loop support built in.
28
+ - A zmq poll event loop for thread-safe zmq sockets.
24
29
  - [IPython shell](https://ipython.readthedocs.io/en/stable/overview.html#enhanced-interactive-python-shell)
25
30
  - top-level await ('asyncio' or 'trio' backend) in cells
26
31
  - async magic function support in cells
27
- - [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/))
28
- - [aiologic](https://aiologic.readthedocs.io/latest/) thread-safe synchronisation primitives
29
- - [Backend agnostic multi-thread / multi-event loop management](https://fleming79.github.io/async-kernel/latest/reference/caller/#async_kernel.caller.Caller)
30
32
  - Per-subshell user_ns
31
33
  - GUI event loops [^1]
32
34
  - [x] inline
@@ -37,6 +39,8 @@ The kernel provides two external interfaces:
37
39
  [Jupyterlite](https://github.com/jupyterlite/jupyterlite) (try it online [here](https://fleming79.github.io/echo-kernel/) 👈)
38
40
  - `%pip install` magic (using micropip)
39
41
  - [Debugger client](https://jupyterlab.readthedocs.io/en/latest/user/debugger.html#debugger)
42
+ - Local client.
43
+ - ZMQ client.
40
44
 
41
45
  [^1]:
42
46
  A gui (_host_) enabled kernel interface starts a gui's mainloop (host) which starts
@@ -49,55 +53,6 @@ The kernel provides two external interfaces:
49
53
 
50
54
  [^3]: trio's [start_guest_run](https://trio.readthedocs.io/en/stable/reference-lowlevel.html#trio.lowlevel.start_guest_run).
51
55
 
52
- ### Avoid deadlocks
53
-
54
- The standard (synchronous) kernel implementation processes messages sequentially irrespective
55
- of the message type. The problem being that long running execute requests make the kernel non-responsive.
56
-
57
- Another problem exists when an asynchronous execute request awaits a result that is delivered
58
- via a kernel message - this will cause a deadlock because the message will be stuck in the queue behind
59
- the _blocking_ execute request[^5].
60
-
61
- async-kernel handles messages according to the channel and message type. So widget com message
62
- 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/).
63
-
64
- #### Example
65
-
66
- Make a blocking call in a Jupyter lab notebook or console.
67
-
68
- ```python
69
- # Make the shell's thread busy
70
- import time
71
-
72
- time.sleep(1e6)
73
- ```
74
-
75
- While the above is _blocking_ (the kernel is _busy_).
76
-
77
- ```python
78
- dir() # try code completion (tab) or view the docstring (shift tab)
79
- ```
80
-
81
- Interrupt the kernel.
82
-
83
- It also works for awaitables.
84
-
85
- ```python
86
- import ipywidgets as ipw
87
- from aiologic import Event
88
-
89
- b = ipw.Button(description="Click me")
90
- event = Event()
91
- b.on_click(lambda _: event.set())
92
- display(b)
93
- await event
94
- ```
95
-
96
- [^5]:
97
- IPyKernel _solves_ this issue specifically for widgets by using the concept of
98
- 'widget coms over subshells'. Widget messages arrive in a different thread which on
99
- occasion can cause unexpected behaviour, especially when using asynchronous libraries.
100
-
101
56
  ## Installation
102
57
 
103
58
  ```bash
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.20.2'
22
- __version_tuple__ = version_tuple = (0, 20, 2)
21
+ __version__ = version = '0.22.0'
22
+ __version_tuple__ = version_tuple = (0, 22, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -13,9 +13,9 @@
13
13
  "source": [
14
14
  "# Caller: A backend agnostic executor (notebook)\n",
15
15
  "\n",
16
- "_This notebook has the Python dependencies: `trio`, `matplotlib`_\n",
16
+ "_This notebook uses `trio` in some cells._\n",
17
17
  "\n",
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."
18
+ "`Caller` is a thread-local object that coordinates the execution of functions and coroutines in the event loop of an `asyncio` or `trio` backend."
19
19
  ]
20
20
  },
21
21
  {
@@ -36,13 +36,13 @@
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
38
  "\n",
39
- "A second backend can also be started in the same thread with or without a host gui event loop.\n",
39
+ "A second backend can also be started in the same thread/caller with or without a host gui event loop.\n",
40
40
  "Potentially the same thread could have up to:\n",
41
41
  "\n",
42
42
  "- One host gui event loop (`tk`, `qt`, `...`)\n",
43
43
  "- Two asynchronous backends (`asyncio`, `trio`)\n",
44
44
  "\n",
45
- "It should be noted that gui's generally assume/require their mainloop runs in the main thread."
45
+ "It should be noted that gui's generally assume/require that their mainloop runs in the main thread."
46
46
  ]
47
47
  },
48
48
  {
@@ -74,7 +74,7 @@
74
74
  "id": "5",
75
75
  "metadata": {},
76
76
  "source": [
77
- "There are two caller instances associated with the Kernel:\n",
77
+ "There are two caller instances associated with the kernel interface:\n",
78
78
  "\n",
79
79
  "- Shell: The caller for the shell channel (normally the MainThread).\n",
80
80
  "- Control: The caller for the control channel (a child of the shell)."
@@ -109,12 +109,11 @@
109
109
  "source": [
110
110
  "## Modifiers\n",
111
111
  "\n",
112
- "There are four modifiers that determine which instance is returned when calling `Caller`.\n",
112
+ "There are three modifiers that can change the instance that is returned when calling `Caller`.\n",
113
113
  "\n",
114
114
  "- `CurrentThread` (default): Access the caller that belongs to the current thread (or context with Pyodide).\n",
115
115
  "- `MainThread`: Access main thread for the Caller.\n",
116
- "- `NewThread`: Create a new thread.\n",
117
- "- `manual`: Manually create a new instance for the current thread (must be started manually)."
116
+ "- `NewThread`: Create a new thread."
118
117
  ]
119
118
  },
120
119
  {
@@ -186,9 +185,11 @@
186
185
  "source": [
187
186
  "## Caller.get\n",
188
187
  "\n",
189
- "`Caller.get` is a method to get an instance of a `Caller` by name, passing the same name will return the same caller on subsequent calls.\n",
190
- "The same [options](#caller-creation-options) for creation of a new `Caller` can be specified. Calling `caller.get()` with no `name` will always return a\n",
191
- "new instance of a `Caller`."
188
+ "`Caller.get` is a method to obtain a _child_ instance of a `Caller` by name. \n",
189
+ "Passing the same name on the same caller will return the same child caller on subsequent calls.\n",
190
+ "The same [options](#caller-creation-options) for creation of a new `Caller` can be specified. \n",
191
+ "Calling `caller.get()` with no `name` will always return a new instance of a `Caller`. All children\n",
192
+ "of a caller will stop when the parent stops."
192
193
  ]
193
194
  },
194
195
  {
@@ -319,7 +320,7 @@
319
320
  "\n",
320
321
  "### Caller.queue_call\n",
321
322
  "\n",
322
- "This method is used extensively by the kernel for message handling. Each time the `queue_call` is called with the same function the function and call arguments are appended to a queue. On the first call a task is started in the backend to process the queue as items are added. The task remains alive until the function is deleted or the queue is stopped. Any exceptions that occur are logged."
323
+ "This method is used extensively by the kernel for message handling. Each time the `queue_call` is called with the same function, the function and call arguments are appended to a queue. On the first call a task is started in the backend to process the queue as items are added. The task remains alive until the function is deleted or the queue is stopped. Any exceptions that occur are logged."
323
324
  ]
324
325
  },
325
326
  {
@@ -338,7 +339,7 @@
338
339
  "def f(n):\n",
339
340
  " float(n)\n",
340
341
  " done.down()\n",
341
- " print(done)\n",
342
+ " print(done.value, \"Pending id:\", id(Caller.current_pending()))\n",
342
343
  "\n",
343
344
  "\n",
344
345
  "for i in range(N):\n",
@@ -413,13 +414,11 @@
413
414
  "import random\n",
414
415
  "import time\n",
415
416
  "\n",
416
- "import anyio\n",
417
417
  "import ipywidgets as ipw\n",
418
418
  "\n",
419
419
  "outputs = {}\n",
420
420
  "stop = ipw.RadioButtons(value=None, options=[\"Stop\"])\n",
421
421
  "box = ipw.VBox([stop])\n",
422
- "await anyio.sleep(0.2)\n",
423
422
  "display(box)\n",
424
423
  "\n",
425
424
  "\n",
@@ -476,13 +475,14 @@
476
475
  "source": [
477
476
  "## Caller.create_pending_group\n",
478
477
  "\n",
479
- "A `PendingGroup` is an asynchronous context manager for for `Pending`. All pending that 'opt-in' when created are added to the pending group (`Caller` methods that return `Pending` 'opt-in').\n",
478
+ "A `PendingGroup` is an asynchronous context manager for `Pending`. All pending that 'opt-in' when created are added to the pending group (`Caller` methods that return `Pending` 'opt-in').\n",
480
479
  "\n",
481
480
  "The `PendingGroup` has different modes:\n",
482
481
  "\n",
483
- "- 0: Ignore cancellation of pending.\n",
482
+ "- 0: Ignore cancellation of pending, if any pending is cancelled - exit quietly.\n",
484
483
  "- 1: Cancel if any pending is cancelled - raise PendingCancelled on exit.\n",
485
- "- 2: Cancel if any pending is cancelled - exit quietly."
484
+ "- 2: Cancel if any pending is cancelled - exit quietly.\n",
485
+ "- 3: Ignore cancellation of pending, if any pending is cancelled - raise PendingCancelled on exit."
486
486
  ]
487
487
  },
488
488
  {