Skip to content

Commit 3fba030

Browse files
author
Linux
committed
update
1 parent 4c9c495 commit 3fba030

File tree

10 files changed

+204
-0
lines changed

10 files changed

+204
-0
lines changed

.github/workflows/mypy_check.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# This workflow will install Python dependencies, run tests and lint with a single version of Python
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3+
4+
name: mypy
5+
6+
on:
7+
push:
8+
branches: [ "main" ]
9+
pull_request:
10+
branches: [ "main" ]
11+
12+
permissions:
13+
contents: read
14+
15+
jobs:
16+
build:
17+
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- uses: actions/checkout@v3
22+
- name: Set up Python 3.10
23+
uses: actions/setup-python@v3
24+
with:
25+
python-version: "3.10"
26+
27+
- name: Install dependencies
28+
run: |
29+
python -m pip install --upgrade pip
30+
pip install .
31+
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
32+
33+
- name: Lint with ruff
34+
run: |
35+
ruff check
36+
37+
- name: Type checking with mypy
38+
run: |
39+
mypy --strict --exclude build .

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[![ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
2+
[![mypy](https://github.com/guangrei/syncio/actions/workflows/mypy_check.yml/badge.svg)](https://github.com/guangrei/syncio/actions)
3+
4+
Syncio is inspired by `asyncio`. you can easy to create task and gather with `syncio.gather()` (multiprocessing) or `syncio.thread_gather()` (threading).
5+
6+
## Example
7+
```python
8+
from syncio import create_task, gather
9+
10+
11+
def hello(n: int) -> str:
12+
return f"hello {n + 1}"
13+
14+
15+
tasks = [create_task(hello)(i) for i in range(3)]
16+
results = gather(*tasks)
17+
print("output task_1:", results["task_1"])
18+
print("output task_2:", results["task_2"])
19+
print("output task_3:", results["task_3"])
20+
21+
# or using iterator
22+
23+
for result in results:
24+
print(result)
25+
26+
```
27+
author: guangrei.

requirements-dev.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
mypy
2+
ruff
3+
typing-extensions
4+
twine
5+
setuptools
6+
types-setuptools

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[bdist_wheel]
2+
universal = 1

setup.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env python
2+
from setuptools import setup
3+
from os import path
4+
5+
6+
this_directory = path.abspath(path.dirname(__file__))
7+
with open(path.join(this_directory, "README.md")) as f:
8+
long_description = f.read()
9+
10+
requirements = [
11+
"typing-extensions",
12+
]
13+
14+
setup(
15+
name="syncio",
16+
version="v0.0.1",
17+
description="type safe for synchronous python concurrently",
18+
long_description=long_description,
19+
long_description_content_type="text/markdown",
20+
author="guangrei",
21+
author_email="[email protected]",
22+
url="https://github.com/guangrei/syncio",
23+
packages=["syncio"],
24+
package_data={"syncio": ["py.typed"]},
25+
license="MIT",
26+
platforms="any",
27+
install_requires=requirements,
28+
)

syncio/Multiprocessing.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# -*-coding:utf8;-*-
2+
from multiprocessing import Process, Manager
3+
from syncio.Task import NewTask, TaskOutput
4+
5+
6+
def gather(*args: NewTask) -> TaskOutput:
7+
manager = Manager()
8+
ret = manager.dict()
9+
tasklist = []
10+
11+
def runner(tasker: NewTask, task_id: int) -> None:
12+
task_id += 1
13+
result = tasker.func(*tasker.args, **tasker.kwargs)
14+
ret[f"task_{task_id}"] = result
15+
16+
for k, f in enumerate(args):
17+
p = Process(target=runner, kwargs={"tasker": f, "task_id": k})
18+
p.start()
19+
tasklist.append(p)
20+
for p in tasklist:
21+
p.join()
22+
23+
return TaskOutput(dict(ret))

syncio/Task.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# -*-coding:utf8;-*-
2+
from abc import ABC, abstractmethod
3+
from typing import Callable, List, Any, Iterator, Dict
4+
from typing_extensions import Self
5+
6+
7+
class NewTask(ABC):
8+
func: Callable[..., Any]
9+
args: List[Any]
10+
kwargs: Dict[str, Any]
11+
12+
@abstractmethod
13+
def __init__(self, func: Callable[..., Any]) -> None:
14+
pass
15+
16+
@abstractmethod
17+
def __call__(self, *args: Any, **kwargs: Any) -> Self:
18+
pass
19+
20+
21+
class create_task(NewTask):
22+
def __init__(self, func: Callable[..., Any]) -> None:
23+
self.func = func
24+
self.args: List[Any] = []
25+
self.kwargs: Dict[str, Any] = {}
26+
27+
def __call__(self, *args: Any, **kwargs: Any) -> Self:
28+
self.args = list(args)
29+
self.kwargs = dict(kwargs)
30+
return self
31+
32+
33+
class TaskOutput(dict): # type: ignore[type-arg]
34+
def __init__(self, data: Dict[str, Any]) -> None:
35+
self._data = data
36+
super().__init__(data)
37+
38+
def __iter__(self) -> Iterator[Any]:
39+
output: List[Any] = []
40+
for _, v in self._data.items():
41+
output.append(v)
42+
self._output_list = output
43+
self._index = 0
44+
return self
45+
46+
def __next__(self) -> Any:
47+
if self._index >= len(self._output_list):
48+
raise StopIteration
49+
value: Any = self._output_list[self._index]
50+
self._index += 1
51+
return value

syncio/Threading.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# -*-coding:utf8;-*-
2+
from threading import Thread
3+
from syncio.Task import NewTask, TaskOutput
4+
5+
6+
def thread_gather(*args: NewTask) -> TaskOutput:
7+
ret = {}
8+
tasklist = []
9+
10+
def runner(tasker: NewTask, task_id: int) -> None:
11+
task_id += 1
12+
result = tasker.func(*tasker.args, **tasker.kwargs)
13+
ret[f"task_{task_id}"] = result
14+
15+
for k, f in enumerate(args):
16+
p = Thread(target=runner, kwargs={"tasker": f, "task_id": k})
17+
p.start()
18+
tasklist.append(p)
19+
for p in tasklist:
20+
p.join()
21+
22+
return TaskOutput(ret)

syncio/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# -*-coding:utf8;-*-
2+
from syncio.Task import create_task
3+
from syncio.Multiprocessing import gather
4+
from syncio.Threading import thread_gather
5+
6+
__all__ = ["create_task", "gather", "thread_gather"]

syncio/py.typed

Whitespace-only changes.

0 commit comments

Comments
 (0)