anyio-executor 0.1.0__tar.gz → 0.2.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.
- anyio_executor-0.2.0/PKG-INFO +65 -0
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/README.md +16 -2
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/pyproject.toml +11 -4
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/src/anyio_executor/__init__.py +1 -1
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/src/anyio_executor/azip.py +1 -7
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/src/anyio_executor/core.py +22 -20
- anyio_executor-0.2.0/src/anyio_executor.egg-info/PKG-INFO +65 -0
- anyio_executor-0.2.0/src/anyio_executor.egg-info/requires.txt +18 -0
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/tests/test_executor.py +45 -7
- anyio_executor-0.1.0/PKG-INFO +0 -45
- anyio_executor-0.1.0/src/anyio_executor.egg-info/PKG-INFO +0 -45
- anyio_executor-0.1.0/src/anyio_executor.egg-info/requires.txt +0 -5
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/LICENSE +0 -0
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/setup.cfg +0 -0
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/src/anyio_executor/py.typed +0 -0
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/src/anyio_executor.egg-info/SOURCES.txt +0 -0
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/src/anyio_executor.egg-info/dependency_links.txt +0 -0
- {anyio_executor-0.1.0 → anyio_executor-0.2.0}/src/anyio_executor.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anyio-executor
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: anyio implementation of an asynchronous Executor.
|
|
5
|
+
Author-email: Vizonex <VizonexBusiness@gmail.com>
|
|
6
|
+
Project-URL: repository, https://github.com/Vizonex/anyio-executor.git
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: aiologic>=0.17.1
|
|
11
|
+
Requires-Dist: anyio>=4.16.0
|
|
12
|
+
Requires-Dist: typing_extensions; python_version < "3.15"
|
|
13
|
+
Provides-Extra: test
|
|
14
|
+
Requires-Dist: pytest; extra == "test"
|
|
15
|
+
Provides-Extra: test-advanced
|
|
16
|
+
Requires-Dist: uvloop; platform_system != "Windows" and extra == "test-advanced"
|
|
17
|
+
Requires-Dist: winloop; platform_system == "Windows" and extra == "test-advanced"
|
|
18
|
+
Requires-Dist: trio; extra == "test-advanced"
|
|
19
|
+
Requires-Dist: pytest; extra == "test-advanced"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Anyio-Executor
|
|
23
|
+
Inspired by the newer [aiolibs-executor](https://github.com/aio-libs/aiolibs-executor) library
|
|
24
|
+
this library provides a asynchronous executor for anyio and has compatability
|
|
25
|
+
with 3.11 and newer versions of python.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
```
|
|
30
|
+
pip install anyio-executor
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
It borrows a simillar interface to that of [aiothreading](https://github.com/Vizonex/aiothreading)
|
|
36
|
+
however this library is a lot more simplistic as an external thread is not being launched.
|
|
37
|
+
As for queues, anyio doesn't support having it's own queue objects so in order to meet demands for
|
|
38
|
+
excellent performance [aiologic](https://github.com/x42005e1f/aiologic) is utilized for that role.
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import anyio
|
|
42
|
+
|
|
43
|
+
from anyio_executor import Executor
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def fn(i: int):
|
|
47
|
+
await anyio.sleep(i)
|
|
48
|
+
print(f"{i} done!")
|
|
49
|
+
return i
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def main():
|
|
53
|
+
async with Executor(10) as e:
|
|
54
|
+
items = await e.map(fn, [1, 2, 1, 2, 3])
|
|
55
|
+
print(items)
|
|
56
|
+
|
|
57
|
+
async with Executor(10) as e:
|
|
58
|
+
# it will also take async for iterations.
|
|
59
|
+
async for i in e.map(fn, [1, 2, 1, 2, 3]):
|
|
60
|
+
print(i)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
anyio.run(main)
|
|
65
|
+
```
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
# Anyio-Executor
|
|
2
2
|
Inspired by the newer [aiolibs-executor](https://github.com/aio-libs/aiolibs-executor) library
|
|
3
|
-
this library provides
|
|
4
|
-
with 3.
|
|
3
|
+
this library provides a asynchronous executor for anyio and has compatability
|
|
4
|
+
with 3.11 and newer versions of python.
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
## Installation
|
|
8
|
+
```
|
|
9
|
+
pip install anyio-executor
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
It borrows a simillar interface to that of [aiothreading](https://github.com/Vizonex/aiothreading)
|
|
15
|
+
however this library is a lot more simplistic as an external thread is not being launched.
|
|
16
|
+
As for queues, anyio doesn't support having it's own queue objects so in order to meet demands for
|
|
17
|
+
excellent performance [aiologic](https://github.com/x42005e1f/aiologic) is utilized for that role.
|
|
18
|
+
|
|
7
19
|
```python
|
|
8
20
|
import anyio
|
|
9
21
|
|
|
@@ -15,6 +27,7 @@ async def fn(i: int):
|
|
|
15
27
|
print(f"{i} done!")
|
|
16
28
|
return i
|
|
17
29
|
|
|
30
|
+
|
|
18
31
|
async def main():
|
|
19
32
|
async with Executor(10) as e:
|
|
20
33
|
items = await e.map(fn, [1, 2, 1, 2, 3])
|
|
@@ -25,6 +38,7 @@ async def main():
|
|
|
25
38
|
async for i in e.map(fn, [1, 2, 1, 2, 3]):
|
|
26
39
|
print(i)
|
|
27
40
|
|
|
41
|
+
|
|
28
42
|
if __name__ == "__main__":
|
|
29
43
|
anyio.run(main)
|
|
30
44
|
```
|
|
@@ -6,10 +6,11 @@ readme = "README.md"
|
|
|
6
6
|
authors = [
|
|
7
7
|
{ name = "Vizonex", email = "VizonexBusiness@gmail.com" }
|
|
8
8
|
]
|
|
9
|
-
requires-python = ">=3.
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"aiologic>=0.
|
|
12
|
-
"anyio>=4.
|
|
11
|
+
"aiologic>=0.17.1",
|
|
12
|
+
"anyio>=4.16.0",
|
|
13
|
+
'typing_extensions; python_version < "3.15"',
|
|
13
14
|
]
|
|
14
15
|
[build-system]
|
|
15
16
|
requires = ["setuptools"]
|
|
@@ -17,6 +18,12 @@ requires = ["setuptools"]
|
|
|
17
18
|
|
|
18
19
|
[project.optional-dependencies]
|
|
19
20
|
test = ["pytest"]
|
|
21
|
+
test-advanced = [
|
|
22
|
+
'uvloop; platform_system != "Windows"',
|
|
23
|
+
'winloop; platform_system == "Windows"',
|
|
24
|
+
'trio',
|
|
25
|
+
'pytest',
|
|
26
|
+
]
|
|
20
27
|
|
|
21
28
|
[project.urls]
|
|
22
29
|
repository = "https://github.com/Vizonex/anyio-executor.git"
|
|
@@ -26,7 +33,7 @@ test = ["pytest"]
|
|
|
26
33
|
version = {attr = "anyio_executor.__version__"}
|
|
27
34
|
|
|
28
35
|
[tool.ruff.lint]
|
|
29
|
-
select = ["E", "I", "UP", "ASYNC"]
|
|
36
|
+
select = ["E", "I", "UP", "ASYNC", "F", "RUF"]
|
|
30
37
|
|
|
31
38
|
[tool.ruff.lint.isort]
|
|
32
39
|
combine-as-imports = true
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import sys
|
|
2
1
|
from collections.abc import AsyncIterable, AsyncIterator
|
|
3
|
-
from typing import Any,
|
|
2
|
+
from typing import Any, TypeVar, overload
|
|
4
3
|
|
|
5
4
|
|
|
6
|
-
if sys.version_info < (3, 11):
|
|
7
|
-
from typing_extensions import Self
|
|
8
|
-
else:
|
|
9
|
-
from typing import Self
|
|
10
|
-
|
|
11
5
|
# There are other asynchronous azip libraries out there
|
|
12
6
|
# but the maitnence of those can be questioned so here's
|
|
13
7
|
# our own version
|
|
@@ -7,14 +7,13 @@ from collections.abc import (
|
|
|
7
7
|
Coroutine,
|
|
8
8
|
Generator,
|
|
9
9
|
Iterable,
|
|
10
|
-
Iterator,
|
|
11
10
|
Sequence,
|
|
12
11
|
)
|
|
13
12
|
from contextlib import contextmanager
|
|
14
13
|
from dataclasses import dataclass
|
|
15
14
|
from functools import partial
|
|
16
15
|
from types import TracebackType
|
|
17
|
-
from typing import Any, Generic, TypeVar, final, overload
|
|
16
|
+
from typing import Any, Generic, Self, TypeVar, final, overload
|
|
18
17
|
|
|
19
18
|
import anyio
|
|
20
19
|
from aiologic import CountdownEvent, SimpleQueue
|
|
@@ -22,11 +21,8 @@ from aiologic import CountdownEvent, SimpleQueue
|
|
|
22
21
|
from .azip import azip
|
|
23
22
|
|
|
24
23
|
|
|
25
|
-
if sys.version_info < (3,
|
|
26
|
-
from typing_extensions import
|
|
27
|
-
else:
|
|
28
|
-
from typing import Self
|
|
29
|
-
|
|
24
|
+
if sys.version_info < (3, 15):
|
|
25
|
+
from typing_extensions import Sentinel as sentinel
|
|
30
26
|
|
|
31
27
|
R = TypeVar("R")
|
|
32
28
|
T = TypeVar("T")
|
|
@@ -36,12 +32,15 @@ T3 = TypeVar("T3")
|
|
|
36
32
|
T4 = TypeVar("T4")
|
|
37
33
|
T5 = TypeVar("T5")
|
|
38
34
|
|
|
35
|
+
MISSING = sentinel("MISSING")
|
|
36
|
+
"""Internal variable not meant to be used publically,
|
|
37
|
+
meant to mark results ran with an exeception handler."""
|
|
39
38
|
|
|
40
|
-
@dataclass(slots=True)
|
|
39
|
+
@dataclass(frozen=True, slots=True)
|
|
41
40
|
class _WorkItem(Generic[T]):
|
|
42
41
|
func: Callable[[], Awaitable[T]]
|
|
43
42
|
exc_handler: Callable[[BaseException], None] | None
|
|
44
|
-
queue: SimpleQueue[T]
|
|
43
|
+
queue: SimpleQueue[T | MISSING]
|
|
45
44
|
|
|
46
45
|
async def execute(self) -> None:
|
|
47
46
|
try:
|
|
@@ -49,26 +48,30 @@ class _WorkItem(Generic[T]):
|
|
|
49
48
|
except Exception as e:
|
|
50
49
|
if self.exc_handler:
|
|
51
50
|
self.exc_handler(e)
|
|
51
|
+
# mark as work done even though there is no objects.
|
|
52
|
+
await self.queue.async_put(MISSING)
|
|
52
53
|
else:
|
|
53
54
|
raise e
|
|
54
55
|
|
|
55
56
|
|
|
56
|
-
@dataclass(slots=True)
|
|
57
|
+
@dataclass(frozen=True, slots=True)
|
|
57
58
|
class ExecutorResult(Awaitable[list[T]], AsyncIterable[T]):
|
|
58
59
|
"""used for waiting upon results to return in different asynchronous
|
|
59
|
-
fashions.
|
|
60
|
+
fashions. It is designed as a hybrid ot be awaited or used in
|
|
61
|
+
async generator fashion."""
|
|
60
62
|
|
|
61
|
-
queue: SimpleQueue[T]
|
|
63
|
+
queue: SimpleQueue[T | MISSING]
|
|
62
64
|
count: CountdownEvent
|
|
63
65
|
executor: "Executor"
|
|
64
66
|
|
|
65
67
|
async def __aiter__(self) -> AsyncIterator[T]:
|
|
66
68
|
while not self.executor.is_closed:
|
|
67
69
|
item = await self.queue.async_get()
|
|
68
|
-
|
|
70
|
+
if item is not MISSING:
|
|
71
|
+
yield item
|
|
69
72
|
|
|
70
73
|
self.count.down()
|
|
71
|
-
if
|
|
74
|
+
if self.count:
|
|
72
75
|
break
|
|
73
76
|
|
|
74
77
|
async def __wait__(self) -> list[T]:
|
|
@@ -87,10 +90,10 @@ class Executor:
|
|
|
87
90
|
|
|
88
91
|
__slots__ = (
|
|
89
92
|
"__weakref__",
|
|
90
|
-
"_num_workers",
|
|
91
|
-
"_work_queue",
|
|
92
93
|
"_exc_handler",
|
|
94
|
+
"_num_workers",
|
|
93
95
|
"_tg",
|
|
96
|
+
"_work_queue",
|
|
94
97
|
"_workers_done",
|
|
95
98
|
)
|
|
96
99
|
|
|
@@ -133,7 +136,7 @@ class Executor:
|
|
|
133
136
|
return self
|
|
134
137
|
|
|
135
138
|
@contextmanager
|
|
136
|
-
def _worker_scope(self) ->
|
|
139
|
+
def _worker_scope(self) -> Generator[None, None, None]:
|
|
137
140
|
"""Assistance with Lazy event up/down event functionality."""
|
|
138
141
|
self._workers_done.up()
|
|
139
142
|
try:
|
|
@@ -278,7 +281,7 @@ class Executor:
|
|
|
278
281
|
raise RuntimeError("Executor already closed.")
|
|
279
282
|
cd = CountdownEvent()
|
|
280
283
|
cd.up()
|
|
281
|
-
queue: SimpleQueue[T] = SimpleQueue()
|
|
284
|
+
queue: SimpleQueue[T | MISSING] = SimpleQueue()
|
|
282
285
|
self._tg.start_soon(
|
|
283
286
|
self._load_tasks_sync_iter,
|
|
284
287
|
queue,
|
|
@@ -376,10 +379,9 @@ class Executor:
|
|
|
376
379
|
if self.is_closed:
|
|
377
380
|
raise RuntimeError("Executor already closed.")
|
|
378
381
|
|
|
379
|
-
queue: SimpleQueue[T] = SimpleQueue()
|
|
380
382
|
cd = CountdownEvent()
|
|
381
383
|
cd.up()
|
|
382
|
-
queue: SimpleQueue[T] = SimpleQueue()
|
|
384
|
+
queue: SimpleQueue[T | MISSING] = SimpleQueue()
|
|
383
385
|
self._tg.start_soon(
|
|
384
386
|
self._load_tasks_async_iter,
|
|
385
387
|
queue,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anyio-executor
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: anyio implementation of an asynchronous Executor.
|
|
5
|
+
Author-email: Vizonex <VizonexBusiness@gmail.com>
|
|
6
|
+
Project-URL: repository, https://github.com/Vizonex/anyio-executor.git
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: aiologic>=0.17.1
|
|
11
|
+
Requires-Dist: anyio>=4.16.0
|
|
12
|
+
Requires-Dist: typing_extensions; python_version < "3.15"
|
|
13
|
+
Provides-Extra: test
|
|
14
|
+
Requires-Dist: pytest; extra == "test"
|
|
15
|
+
Provides-Extra: test-advanced
|
|
16
|
+
Requires-Dist: uvloop; platform_system != "Windows" and extra == "test-advanced"
|
|
17
|
+
Requires-Dist: winloop; platform_system == "Windows" and extra == "test-advanced"
|
|
18
|
+
Requires-Dist: trio; extra == "test-advanced"
|
|
19
|
+
Requires-Dist: pytest; extra == "test-advanced"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Anyio-Executor
|
|
23
|
+
Inspired by the newer [aiolibs-executor](https://github.com/aio-libs/aiolibs-executor) library
|
|
24
|
+
this library provides a asynchronous executor for anyio and has compatability
|
|
25
|
+
with 3.11 and newer versions of python.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
```
|
|
30
|
+
pip install anyio-executor
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
It borrows a simillar interface to that of [aiothreading](https://github.com/Vizonex/aiothreading)
|
|
36
|
+
however this library is a lot more simplistic as an external thread is not being launched.
|
|
37
|
+
As for queues, anyio doesn't support having it's own queue objects so in order to meet demands for
|
|
38
|
+
excellent performance [aiologic](https://github.com/x42005e1f/aiologic) is utilized for that role.
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import anyio
|
|
42
|
+
|
|
43
|
+
from anyio_executor import Executor
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def fn(i: int):
|
|
47
|
+
await anyio.sleep(i)
|
|
48
|
+
print(f"{i} done!")
|
|
49
|
+
return i
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def main():
|
|
53
|
+
async with Executor(10) as e:
|
|
54
|
+
items = await e.map(fn, [1, 2, 1, 2, 3])
|
|
55
|
+
print(items)
|
|
56
|
+
|
|
57
|
+
async with Executor(10) as e:
|
|
58
|
+
# it will also take async for iterations.
|
|
59
|
+
async for i in e.map(fn, [1, 2, 1, 2, 3]):
|
|
60
|
+
print(i)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
anyio.run(main)
|
|
65
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
aiologic>=0.17.1
|
|
2
|
+
anyio>=4.16.0
|
|
3
|
+
|
|
4
|
+
[:python_version < "3.15"]
|
|
5
|
+
typing_extensions
|
|
6
|
+
|
|
7
|
+
[test]
|
|
8
|
+
pytest
|
|
9
|
+
|
|
10
|
+
[test-advanced]
|
|
11
|
+
trio
|
|
12
|
+
pytest
|
|
13
|
+
|
|
14
|
+
[test-advanced:platform_system != "Windows"]
|
|
15
|
+
uvloop
|
|
16
|
+
|
|
17
|
+
[test-advanced:platform_system == "Windows"]
|
|
18
|
+
winloop
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from unittest import mock
|
|
3
|
+
|
|
1
4
|
import anyio
|
|
2
5
|
import pytest
|
|
3
6
|
|
|
@@ -16,17 +19,22 @@ class BaseExecutorTest:
|
|
|
16
19
|
def executor(self) -> Executor:
|
|
17
20
|
return Executor()
|
|
18
21
|
|
|
22
|
+
def executor_with_handler(
|
|
23
|
+
self, handler:Callable[[BaseException], None]
|
|
24
|
+
) -> Executor:
|
|
25
|
+
return Executor(exc_handler=handler)
|
|
26
|
+
|
|
19
27
|
|
|
20
28
|
class TestInvalidStates(BaseExecutorTest):
|
|
21
29
|
@pytest.mark.anyio
|
|
22
30
|
async def test_invalid_worker_amount(self):
|
|
23
|
-
with pytest.raises(ValueError, match="num_wokers must be a positive integer"):
|
|
31
|
+
with pytest.raises(ValueError, match=r"num_wokers must be a positive integer"):
|
|
24
32
|
_ = Executor(-69)
|
|
25
33
|
|
|
26
34
|
@pytest.mark.anyio
|
|
27
35
|
async def test_bad_map_before_entrance(self):
|
|
28
36
|
e = self.executor()
|
|
29
|
-
with pytest.raises(RuntimeError, match="Executor already closed."):
|
|
37
|
+
with pytest.raises(RuntimeError, match=r"Executor already closed."):
|
|
30
38
|
await e.map(noop, [1, 2, 3])
|
|
31
39
|
|
|
32
40
|
@pytest.mark.anyio
|
|
@@ -37,14 +45,14 @@ class TestInvalidStates(BaseExecutorTest):
|
|
|
37
45
|
for i in range(3):
|
|
38
46
|
yield i
|
|
39
47
|
|
|
40
|
-
with pytest.raises(RuntimeError, match="Executor already closed."):
|
|
48
|
+
with pytest.raises(RuntimeError, match=r"Executor already closed."):
|
|
41
49
|
await e.amap(noop, fake_aiter())
|
|
42
50
|
|
|
43
51
|
@pytest.mark.anyio
|
|
44
52
|
async def test_bad_map_after_shutdown(self):
|
|
45
53
|
async with self.executor() as e:
|
|
46
54
|
await e.shutdown()
|
|
47
|
-
with pytest.raises(RuntimeError, match="Executor already closed."):
|
|
55
|
+
with pytest.raises(RuntimeError, match=r"Executor already closed."):
|
|
48
56
|
await e.map(noop, [1, 2, 3])
|
|
49
57
|
|
|
50
58
|
@pytest.mark.anyio
|
|
@@ -56,9 +64,10 @@ class TestInvalidStates(BaseExecutorTest):
|
|
|
56
64
|
for i in range(3):
|
|
57
65
|
yield i
|
|
58
66
|
|
|
59
|
-
with pytest.raises(RuntimeError, match="Executor already closed."):
|
|
67
|
+
with pytest.raises(RuntimeError, match=r"Executor already closed."):
|
|
60
68
|
await e.amap(noop, fake_aiter())
|
|
61
69
|
|
|
70
|
+
@pytest.mark.anyio
|
|
62
71
|
|
|
63
72
|
class TestExecutor(BaseExecutorTest):
|
|
64
73
|
async def wait(self, item: int) -> int:
|
|
@@ -70,7 +79,9 @@ class TestExecutor(BaseExecutorTest):
|
|
|
70
79
|
async with self.executor() as e:
|
|
71
80
|
items = [i for i in range(1, 5)]
|
|
72
81
|
i = await e.map(self.wait, items)
|
|
73
|
-
|
|
82
|
+
# it doesn't matter what order they come back
|
|
83
|
+
# in (as long as they all come back of course)
|
|
84
|
+
assert set(i) == {1, 2, 3, 4}
|
|
74
85
|
|
|
75
86
|
@pytest.mark.anyio
|
|
76
87
|
async def test_map_aiter(self):
|
|
@@ -79,6 +90,10 @@ class TestExecutor(BaseExecutorTest):
|
|
|
79
90
|
async for i in e.map(fast_ret, items):
|
|
80
91
|
assert i in [1, 2, 3, 4]
|
|
81
92
|
|
|
93
|
+
# NOTE: Sometimes trio will attempt to execute things
|
|
94
|
+
# differently example: [4, 1, 2, 3]
|
|
95
|
+
# as long as they all come return back to us then it did
|
|
96
|
+
# it's job.
|
|
82
97
|
@pytest.mark.anyio
|
|
83
98
|
async def test_amap_await(self):
|
|
84
99
|
async def ait():
|
|
@@ -87,7 +102,7 @@ class TestExecutor(BaseExecutorTest):
|
|
|
87
102
|
|
|
88
103
|
async with self.executor() as e:
|
|
89
104
|
i = await e.amap(self.wait, ait())
|
|
90
|
-
assert i ==
|
|
105
|
+
assert set(i) == {1, 2, 3, 4}
|
|
91
106
|
|
|
92
107
|
@pytest.mark.anyio
|
|
93
108
|
async def test_amap_aiter(self):
|
|
@@ -98,3 +113,26 @@ class TestExecutor(BaseExecutorTest):
|
|
|
98
113
|
async with self.executor() as e:
|
|
99
114
|
async for i in e.amap(fast_ret, ait()):
|
|
100
115
|
assert i in [1, 2, 3, 4]
|
|
116
|
+
|
|
117
|
+
@pytest.mark.anyio
|
|
118
|
+
async def test_exception_handler(self):
|
|
119
|
+
callback = mock.Mock()
|
|
120
|
+
|
|
121
|
+
class TornadoError(Exception):
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
def on_exception(exc: Exception):
|
|
125
|
+
assert isinstance(exc, TornadoError)
|
|
126
|
+
callback(exc)
|
|
127
|
+
|
|
128
|
+
async def func(i: int):
|
|
129
|
+
raise TornadoError("Tornado approching...")
|
|
130
|
+
|
|
131
|
+
async with self.executor_with_handler(on_exception) as e:
|
|
132
|
+
ret = await e.map(func, (1,))
|
|
133
|
+
assert not ret
|
|
134
|
+
assert callback.called
|
|
135
|
+
assert callback.call_args.args
|
|
136
|
+
assert isinstance(callback.call_args.args[0], TornadoError)
|
|
137
|
+
|
|
138
|
+
|
anyio_executor-0.1.0/PKG-INFO
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: anyio-executor
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: anyio implementation of an asynchronous Executor.
|
|
5
|
-
Author-email: Vizonex <VizonexBusiness@gmail.com>
|
|
6
|
-
Project-URL: repository, https://github.com/Vizonex/anyio-executor.git
|
|
7
|
-
Requires-Python: >=3.10
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Requires-Dist: aiologic>=0.16.0
|
|
11
|
-
Requires-Dist: anyio>=4.13.0
|
|
12
|
-
Provides-Extra: test
|
|
13
|
-
Requires-Dist: pytest; extra == "test"
|
|
14
|
-
Dynamic: license-file
|
|
15
|
-
|
|
16
|
-
# Anyio-Executor
|
|
17
|
-
Inspired by the newer [aiolibs-executor](https://github.com/aio-libs/aiolibs-executor) library
|
|
18
|
-
this library provides an asynchronous executor support for anyio and has compatability
|
|
19
|
-
with 3.10 and newer version of python.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```python
|
|
23
|
-
import anyio
|
|
24
|
-
|
|
25
|
-
from anyio_executor import Executor
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
async def fn(i: int):
|
|
29
|
-
await anyio.sleep(i)
|
|
30
|
-
print(f"{i} done!")
|
|
31
|
-
return i
|
|
32
|
-
|
|
33
|
-
async def main():
|
|
34
|
-
async with Executor(10) as e:
|
|
35
|
-
items = await e.map(fn, [1, 2, 1, 2, 3])
|
|
36
|
-
print(items)
|
|
37
|
-
|
|
38
|
-
async with Executor(10) as e:
|
|
39
|
-
# it will also take async for iterations.
|
|
40
|
-
async for i in e.map(fn, [1, 2, 1, 2, 3]):
|
|
41
|
-
print(i)
|
|
42
|
-
|
|
43
|
-
if __name__ == "__main__":
|
|
44
|
-
anyio.run(main)
|
|
45
|
-
```
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: anyio-executor
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: anyio implementation of an asynchronous Executor.
|
|
5
|
-
Author-email: Vizonex <VizonexBusiness@gmail.com>
|
|
6
|
-
Project-URL: repository, https://github.com/Vizonex/anyio-executor.git
|
|
7
|
-
Requires-Python: >=3.10
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Requires-Dist: aiologic>=0.16.0
|
|
11
|
-
Requires-Dist: anyio>=4.13.0
|
|
12
|
-
Provides-Extra: test
|
|
13
|
-
Requires-Dist: pytest; extra == "test"
|
|
14
|
-
Dynamic: license-file
|
|
15
|
-
|
|
16
|
-
# Anyio-Executor
|
|
17
|
-
Inspired by the newer [aiolibs-executor](https://github.com/aio-libs/aiolibs-executor) library
|
|
18
|
-
this library provides an asynchronous executor support for anyio and has compatability
|
|
19
|
-
with 3.10 and newer version of python.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```python
|
|
23
|
-
import anyio
|
|
24
|
-
|
|
25
|
-
from anyio_executor import Executor
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
async def fn(i: int):
|
|
29
|
-
await anyio.sleep(i)
|
|
30
|
-
print(f"{i} done!")
|
|
31
|
-
return i
|
|
32
|
-
|
|
33
|
-
async def main():
|
|
34
|
-
async with Executor(10) as e:
|
|
35
|
-
items = await e.map(fn, [1, 2, 1, 2, 3])
|
|
36
|
-
print(items)
|
|
37
|
-
|
|
38
|
-
async with Executor(10) as e:
|
|
39
|
-
# it will also take async for iterations.
|
|
40
|
-
async for i in e.map(fn, [1, 2, 1, 2, 3]):
|
|
41
|
-
print(i)
|
|
42
|
-
|
|
43
|
-
if __name__ == "__main__":
|
|
44
|
-
anyio.run(main)
|
|
45
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anyio_executor-0.1.0 → anyio_executor-0.2.0}/src/anyio_executor.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|