async-kernel 0.16.0__tar.gz → 0.16.1__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 (103) hide show
  1. {async_kernel-0.16.0 → async_kernel-0.16.1}/.github/workflows/ci.yml +2 -1
  2. {async_kernel-0.16.0 → async_kernel-0.16.1}/CHANGELOG.md +13 -0
  3. {async_kernel-0.16.0 → async_kernel-0.16.1}/PKG-INFO +2 -1
  4. {async_kernel-0.16.0 → async_kernel-0.16.1}/_version.py +2 -2
  5. {async_kernel-0.16.0 → async_kernel-0.16.1}/pyproject.toml +1 -0
  6. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/caller.py +1 -3
  7. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/common.py +11 -10
  8. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/kernel.py +8 -8
  9. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/pending.py +9 -3
  10. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/typing.py +11 -1
  11. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_typing.py +5 -0
  12. {async_kernel-0.16.0 → async_kernel-0.16.1}/.github/dependabot.yaml +0 -0
  13. {async_kernel-0.16.0 → async_kernel-0.16.1}/.github/release.yml +0 -0
  14. {async_kernel-0.16.0 → async_kernel-0.16.1}/.github/workflows/enforce-label.yml +0 -0
  15. {async_kernel-0.16.0 → async_kernel-0.16.1}/.github/workflows/new_release.yml +0 -0
  16. {async_kernel-0.16.0 → async_kernel-0.16.1}/.github/workflows/pre-commit.yml +0 -0
  17. {async_kernel-0.16.0 → async_kernel-0.16.1}/.github/workflows/publish-docs.yml +0 -0
  18. {async_kernel-0.16.0 → async_kernel-0.16.1}/.github/workflows/publish-to-pypi.yml +0 -0
  19. {async_kernel-0.16.0 → async_kernel-0.16.1}/.gitignore +0 -0
  20. {async_kernel-0.16.0 → async_kernel-0.16.1}/.pre-commit-config.yaml +0 -0
  21. {async_kernel-0.16.0 → async_kernel-0.16.1}/.vscode/launch.json +0 -0
  22. {async_kernel-0.16.0 → async_kernel-0.16.1}/.vscode/settings.json +0 -0
  23. {async_kernel-0.16.0 → async_kernel-0.16.1}/.vscode/spellright.dict +0 -0
  24. {async_kernel-0.16.0 → async_kernel-0.16.1}/CONTRIBUTING.md +0 -0
  25. {async_kernel-0.16.0 → async_kernel-0.16.1}/IPYTHON_LICENSE +0 -0
  26. {async_kernel-0.16.0 → async_kernel-0.16.1}/LICENSE +0 -0
  27. {async_kernel-0.16.0 → async_kernel-0.16.1}/README.md +0 -0
  28. {async_kernel-0.16.0 → async_kernel-0.16.1}/cliff.toml +0 -0
  29. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/about/changelog.md +0 -0
  30. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/about/contributing.md +0 -0
  31. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/about/index.md +0 -0
  32. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/about/license.md +0 -0
  33. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/index.md +0 -0
  34. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/javascripts/extra.js +0 -0
  35. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/notebooks/caller.ipynb +0 -0
  36. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/notebooks/concurrency.ipynb +0 -0
  37. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/overrides/main.html +0 -0
  38. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/asyncshell.md +0 -0
  39. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/caller.md +0 -0
  40. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/comm.md +0 -0
  41. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/command.md +0 -0
  42. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/common.md +0 -0
  43. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/debugger.md +0 -0
  44. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/event_loop.md +0 -0
  45. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/index.md +0 -0
  46. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/interface.md +0 -0
  47. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/kernel.md +0 -0
  48. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/kernelspec.md +0 -0
  49. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/pending.md +0 -0
  50. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/typing.md +0 -0
  51. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/reference/utils.md +0 -0
  52. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/stylesheets/extra.css +0 -0
  53. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/thread_safety.md +0 -0
  54. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/usage/commands.md +0 -0
  55. {async_kernel-0.16.0 → async_kernel-0.16.1}/docs/usage/index.md +0 -0
  56. {async_kernel-0.16.0 → async_kernel-0.16.1}/hatch_build.py +0 -0
  57. {async_kernel-0.16.0 → async_kernel-0.16.1}/mkdocs.yml +0 -0
  58. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/__init__.py +0 -0
  59. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/__main__.py +0 -0
  60. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/asyncshell.py +0 -0
  61. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/comm.py +0 -0
  62. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/command.py +0 -0
  63. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/compat/json.py +0 -0
  64. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/compiler.py +0 -0
  65. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/debugger.py +0 -0
  66. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/event_loop/__init__.py +0 -0
  67. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/event_loop/asyncio_guest.py +0 -0
  68. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/event_loop/qt_host.py +0 -0
  69. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/event_loop/run.py +0 -0
  70. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/event_loop/tk_host.py +0 -0
  71. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/interface/__init__.py +0 -0
  72. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/interface/base.py +0 -0
  73. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/interface/callable.py +0 -0
  74. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/interface/zmq.py +0 -0
  75. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/iostream.py +0 -0
  76. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/kernelspec.py +0 -0
  77. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/py.typed +0 -0
  78. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/resources/logo-32x32.png +0 -0
  79. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/resources/logo-64x64.png +0 -0
  80. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/resources/logo-svg.svg +0 -0
  81. {async_kernel-0.16.0 → async_kernel-0.16.1}/src/async_kernel/utils.py +0 -0
  82. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/__init__.py +0 -0
  83. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/conftest.py +0 -0
  84. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/references.py +0 -0
  85. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_callable_kernel_interface.py +0 -0
  86. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_caller.py +0 -0
  87. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_comm.py +0 -0
  88. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_command.py +0 -0
  89. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_common.py +0 -0
  90. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_compat.py +0 -0
  91. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_debugger.py +0 -0
  92. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_enter_kernel.py +0 -0
  93. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_event_loop.py +0 -0
  94. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_iostream.py +0 -0
  95. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_kernel.py +0 -0
  96. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_kernel_subclass.py +0 -0
  97. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_kernelspec.py +0 -0
  98. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_message_spec.py +0 -0
  99. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_pending.py +0 -0
  100. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_utils.py +0 -0
  101. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/test_zmq_messaging.py +0 -0
  102. {async_kernel-0.16.0 → async_kernel-0.16.1}/tests/utils.py +0 -0
  103. {async_kernel-0.16.0 → async_kernel-0.16.1}/uv.lock +0 -0
@@ -39,6 +39,7 @@ jobs:
39
39
  - "3.12"
40
40
  - "3.13"
41
41
  - "3.14t"
42
+ - "3.15"
42
43
  steps:
43
44
  - name: Checkout
44
45
  uses: actions/checkout@v6
@@ -53,7 +54,7 @@ jobs:
53
54
  - name: Install the project
54
55
  run: uv sync --locked --dev
55
56
 
56
- - if: ${{ startsWith(matrix.os, 'windows') && !endsWith(matrix.python-version, 't')}}
57
+ - if: ${{ startsWith(matrix.os, 'windows') && !endsWith(matrix.python-version, 't') && !startsWith(matrix.python-version, '3.15')}}
57
58
  # Pyside does not have free-threaded binary
58
59
  run: uv sync --locked --dev --group gui
59
60
 
@@ -5,6 +5,16 @@ 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.16.1] - 2026-04-08
9
+
10
+ ### <!-- 1 --> 🚀 Features
11
+
12
+ - Add shield option to Pending.cancel_wait. [#421](https://github.com/fleming79/async-kernel/pull/421)
13
+
14
+ ### <!-- 6 --> 🌀 Miscellaneous
15
+
16
+ - Test against Python 3.15 [#422](https://github.com/fleming79/async-kernel/pull/422)
17
+
8
18
  ## [0.16.0] - 2026-04-06
9
19
 
10
20
  ### <!-- 0 --> 🏗️ Breaking changes
@@ -27,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
27
37
 
28
38
  ### <!-- 6 --> 🌀 Miscellaneous
29
39
 
40
+ - Prepare for release v0.16.0 [#420](https://github.com/fleming79/async-kernel/pull/420)
41
+
30
42
  - Caller refactoring [#419](https://github.com/fleming79/async-kernel/pull/419)
31
43
 
32
44
  - Convert Caller._get_task_factory to a function [#416](https://github.com/fleming79/async-kernel/pull/416)
@@ -1145,6 +1157,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1145
1157
 
1146
1158
  - Bump the actions group across 1 directory with 2 updates [#3](https://github.com/fleming79/async-kernel/pull/3)
1147
1159
 
1160
+ [0.16.1]: https://github.com/fleming79/async-kernel/compare/v0.16.0..v0.16.1
1148
1161
  [0.16.0]: https://github.com/fleming79/async-kernel/compare/v0.15.0..v0.16.0
1149
1162
  [0.15.0]: https://github.com/fleming79/async-kernel/compare/v0.14.0..v0.15.0
1150
1163
  [0.14.0]: https://github.com/fleming79/async-kernel/compare/v0.13.3..v0.14.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: async-kernel
3
- Version: 0.16.0
3
+ Version: 0.16.1
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 :: 3.15
32
33
  Classifier: Programming Language :: Python :: Free Threading :: 1 - Unstable
33
34
  Classifier: Typing :: Typed
34
35
  Requires-Python: >=3.11
@@ -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.16.0'
22
- __version_tuple__ = version_tuple = (0, 16, 0)
21
+ __version__ = version = '0.16.1'
22
+ __version_tuple__ = version_tuple = (0, 16, 1)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -31,6 +31,7 @@ classifiers = [
31
31
  "Programming Language :: Python :: 3.12",
32
32
  "Programming Language :: Python :: 3.13",
33
33
  "Programming Language :: Python :: 3.14",
34
+ "Programming Language :: Python :: 3.15",
34
35
  "Programming Language :: Python :: Free Threading :: 1 - Unstable",
35
36
  ]
36
37
  requires-python = ">=3.11"
@@ -1042,13 +1042,11 @@ class Caller(anyio.AsyncContextManagerMixin):
1042
1042
  pen_.result()
1043
1043
  finally:
1044
1044
  queue.stop()
1045
- pen_.cancel()
1046
1045
  for pen in unfinished:
1047
1046
  pen.remove_done_callback(queue.append)
1048
1047
  if cancel_unfinished:
1049
1048
  pen.cancel("Cancelled by as_completed")
1050
- with anyio.CancelScope():
1051
- await pen_.wait(result=False)
1049
+ await pen_.cancel_wait(shield=True)
1052
1050
 
1053
1051
  async def wait(
1054
1052
  self,
@@ -202,16 +202,17 @@ class SingleAsyncQueue(Generic[T]):
202
202
  queue = self.queue
203
203
  try:
204
204
  while self._active:
205
- await checkpoint()
206
- if self._active:
207
- try:
208
- yield queue.popleft()
209
- except IndexError:
210
- event = create_async_event()
211
- self._resume = event.set
212
- if not queue and self._active:
213
- await event
214
- self._resume = noop
205
+ if queue:
206
+ yield queue.popleft()
207
+ await checkpoint()
208
+ else:
209
+ event = create_async_event()
210
+ self._resume = event.set
211
+ if not queue and self._active:
212
+ await event
213
+ self._resume = noop
214
+ except IndexError:
215
+ pass
215
216
  finally:
216
217
  self._resume = noop
217
218
  self.stop()
@@ -505,16 +505,16 @@ class Kernel(traitlets.HasTraits, anyio.AsyncContextManagerMixin):
505
505
  # return RunMode(run_mode)
506
506
  if msg_type is MsgType.execute_request:
507
507
  if content := job["msg"].get("content", {}):
508
- if code := content.get("code"):
509
- try:
510
- if (code := code.strip().split("\n", maxsplit=1)[0]).startswith(("# ", "##")):
511
- return RunMode(code[2:])
512
- except ValueError:
513
- pass
508
+ if (code := content.get("code")) and (
509
+ mode := RunMode.to_runmode(code.strip().split("\n", maxsplit=1)[0])
510
+ ):
511
+ return mode
514
512
  if content.get("silent"):
515
513
  return RunMode.task
516
- if mode_ := set(utils.get_tags(job)).intersection(RunMode):
517
- return RunMode(next(iter(mode_)))
514
+ try:
515
+ return next(mode for tag in utils.get_tags(job) if (mode := RunMode.to_runmode(tag)))
516
+ except Exception:
517
+ pass
518
518
  return RunMode.queue
519
519
 
520
520
  async def kernel_info_request(self, job: Job[Content], /) -> Content:
@@ -612,12 +612,18 @@ class Pending(Awaitable[T]):
612
612
  canceller(msg)
613
613
  return self._cancelled is not None
614
614
 
615
- async def cancel_wait(self, msg: str | None, *, timeout: float | None = None) -> None:
616
- "Cancel the pending and wait for it to be done."
615
+ async def cancel_wait(self, msg: str | None = None, *, timeout: float | None = None, shield: bool = False) -> None:
616
+ """
617
+ Cancel the pending and wait for it to be done.
618
+
619
+ Args:
620
+ timeout: Timeout in seconds.
621
+ shield: Shield from external cancellation.
622
+ """
617
623
  if not self._done:
618
624
  self.cancel(msg)
619
625
  if not self._done:
620
- await self.wait(result=False, timeout=timeout)
626
+ await self.wait(result=False, timeout=timeout, shield=shield)
621
627
 
622
628
  def cancelled(self) -> bool:
623
629
  """
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import enum
4
4
  from collections.abc import Awaitable, Callable
5
- from typing import TYPE_CHECKING, Any, Generic, Literal, NotRequired, ParamSpec, TypedDict, TypeVar
5
+ from typing import TYPE_CHECKING, Any, Generic, Literal, NotRequired, ParamSpec, Self, TypedDict, TypeVar
6
6
 
7
7
  from typing_extensions import Sentinel, override
8
8
 
@@ -113,6 +113,16 @@ class RunMode(enum.StrEnum):
113
113
  def __hash__(self) -> int:
114
114
  return hash(self.name)
115
115
 
116
+ @classmethod
117
+ def to_runmode(cls, value: Any, default: T = None, /) -> Self | T:
118
+ "Converts value to `Runmode` or default where it is not possible."
119
+ try:
120
+ return cls(value)
121
+ except ValueError:
122
+ if isinstance(value, str) and value.startswith(("# ", "##")):
123
+ return cls.to_runmode(value[2:], default)
124
+ return default
125
+
116
126
  queue = "queue"
117
127
  "Run the message handler using [async_kernel.caller.Caller.queue_call][]."
118
128
 
@@ -17,6 +17,11 @@ class TestRunMode:
17
17
  assert list(RunMode) == ["# queue", "# task", "# thread"]
18
18
  assert list(RunMode) == ["<RunMode.queue: 'queue'>", "<RunMode.task: 'task'>", "<RunMode.thread: 'thread'>"]
19
19
 
20
+ def test_is_runmode(self):
21
+ assert RunMode.to_runmode("# thread") is RunMode.thread
22
+ assert not RunMode.to_runmode(1)
23
+ assert RunMode.to_runmode(1, RunMode.queue) is RunMode.queue
24
+
20
25
 
21
26
  class TestMsgType:
22
27
  def test_all_names(self):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes