{"id":27628214,"url":"https://github.com/s3rius/gensyncio","last_synced_at":"2025-08-25T03:49:18.667Z","repository":{"id":261986350,"uuid":"885893642","full_name":"s3rius/gensyncio","owner":"s3rius","description":"Generator-based async library","archived":false,"fork":false,"pushed_at":"2024-12-03T21:03:58.000Z","size":33,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-21T13:59:07.087Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/s3rius.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-11-09T17:08:38.000Z","updated_at":"2025-04-22T12:44:49.000Z","dependencies_parsed_at":"2025-04-23T14:11:34.161Z","dependency_job_id":"c2c64717-9d9c-4382-a307-5e14b9ec2a38","html_url":"https://github.com/s3rius/gensyncio","commit_stats":null,"previous_names":["s3rius/gensyncio"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/s3rius/gensyncio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rius%2Fgensyncio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rius%2Fgensyncio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rius%2Fgensyncio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rius%2Fgensyncio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/s3rius","download_url":"https://codeload.github.com/s3rius/gensyncio/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rius%2Fgensyncio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272004325,"owners_count":24856937,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-25T02:00:12.092Z","response_time":1107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-23T14:11:21.485Z","updated_at":"2025-08-25T03:49:18.639Z","avatar_url":"https://github.com/s3rius.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Generator-based async framework\n\nThis project was created for educational purpose to demonstrate people how to write their own async\nframework with event loop, socket primitives and an HTTP server.\n\n\n# Lib\n\nThe lib is pretty similar with asyncio module. Here's a simple example of an async program:\n\n\n```python\nfrom typing import Generator\nimport gensyncio\n\n\ndef main() -\u003e Generator[None, None, None]:\n    yield from gensyncio.sleep(1)\n    print(\"Hello from async!\")\n\n\nprint(gensyncio.run(main()))\n```\n\nYou can achieve real async by creating tasks in an event loop and gathering them.\n\n```python\nfrom typing import Generator\nimport gensyncio\n\n\ndef print_after_delay(msg: str, delay: int):\n    yield from gensyncio.sleep(delay)\n    print(msg)\n\n\ndef main() -\u003e Generator[None, None, None]:\n    yield from gensyncio.gather(\n        print_after_delay(\"Hello\", 1),\n        print_after_delay(\"from\", 1),\n        print_after_delay(\"async\", 1),\n    )\n\n\ngensyncio.run(main())\n```\n\n# Sync primitives\n\nThis lib implements syncronization primitives for async programming. Such as:\n\n* Event\n* Lock\n\nHere are examples of how they should be used:\n\nAn event:\n```python\nimport gensyncio\n\n\ndef waiter(event: gensyncio.Event):\n    print(\"waiting for it ...\")\n    yield from event.wait()\n    print(\"... got it!\")\n\n\ndef main():\n    # Create an Event object.\n    event = gensyncio.Event()\n\n    # Spawn a Task to wait until 'event' is set.\n    waiter_task = gensyncio.create_task(waiter(event))\n\n    # Sleep for 1 second and set the event.\n    yield from gensyncio.sleep(1)\n    event.set()\n\n    # Wait until the waiter task is finished.\n    yield from waiter_task\n\n\ngensyncio.run(main())\n```\n\nA lock:\n\n```python\nfrom typing import Generator\nimport gensyncio\n\n\ndef print_after(lock: gensyncio.Lock, delay: float, val: str) -\u003e Generator[None, None, None]:\n    \"\"\"Print after delay, but wit aquiring a lock.\"\"\"\n    # Here we are using the lock as a context manager\n    with lock as _lock:\n        # This will yield from the lock, and wait until the lock is released\n        yield from _lock\n        # This will yield from the sleep, and wait until the sleep is done\n        yield from gensyncio.sleep(delay)\n    print(val)\n\n\ndef main() -\u003e Generator[None, None, None]:\n    loop = gensyncio.get_running_loop()\n    lock = gensyncio.Lock()\n    loop.create_task(print_after(lock, 2, \"one\"))\n    t = loop.create_task(print_after(lock, 1, \"two\"))\n    # Here we wait for the task to finish\n    yield from t\n\n\ngensyncio.run(main())\n```\n\n# Queue\n\nThe queue is the same as asyncio Queue. This example is rewritten asyncio.Queue example from python docs.\n\n```python\nimport random\nimport time\n\nimport gensyncio\n\n\ndef worker(name: str, queue: gensyncio.Queue[float]):\n    while True:\n        # Get a \"work item\" out of the queue.\n        sleep_for = yield from queue.get()\n\n        # Sleep for the \"sleep_for\" seconds.\n        yield from gensyncio.sleep(sleep_for)\n\n        # Notify the queue that the \"work item\" has been processed.\n        queue.task_done()\n\n        print(f\"{name} has slept for {sleep_for:.2f} seconds\")\n\n\ndef main():\n    # Create a queue that we will use to store our \"workload\".\n    queue = gensyncio.Queue()\n\n    # Generate random timings and put them into the queue.\n    total_sleep_time = 0\n    for _ in range(20):\n        sleep_for = random.uniform(0.05, 1.0)\n        total_sleep_time += sleep_for\n        queue.put_nowait(sleep_for)\n\n    # Create three worker tasks to process the queue concurrently.\n    tasks = []\n    for i in range(3):\n        task = gensyncio.create_task(worker(f\"worker-{i}\", queue))\n        tasks.append(task)\n\n    # Wait until the queue is fully processed.\n    started_at = time.monotonic()\n    yield from queue.join()\n    total_slept_for = time.monotonic() - started_at\n\n    # Cancel our worker tasks.\n    for task in tasks:\n        try:\n            task.cancel()\n        except gensyncio.GenCancelledError:\n            pass\n    # Wait until all worker tasks are cancelled.\n    yield from gensyncio.gather(*tasks)\n\n    print(\"====\")\n    print(f\"3 workers slept in parallel for {total_slept_for:.2f} seconds\")\n    print(f\"total expected sleep time: {total_sleep_time:.2f} seconds\")\n\n\ngensyncio.run(main())\n```\n\n# Sockets\n\nAlso this lib contains a simple socket implementation which is compatible with generators approach.\nHere's a simple example of using generator based socket:\n\n```python\nimport socket\nfrom typing import Generator\nimport gensyncio\nfrom gensyncio.gensocket import GenSocket\n\n\ndef main() -\u003e Generator[None, None, None]:\n    sock = GenSocket(socket.AF_INET, socket.SOCK_STREAM)\n    yield from sock.connect((\"httpbin.org\", 80))\n    sock.send(b\"GET /get HTTP/1.1\\r\\nHost: httpbin.org\\r\\n\\r\\n\")\n    resp = yield from sock.recv(1024)\n    print(resp.decode(\"utf-8\"))\n\n\ngensyncio.run(main())\n```\n\nGenSocket is alsmost similar to [socket.socket](https://docs.python.org/3/library/socket.html) except it's always nonblocking and some of it's methods should be awaited using `yield from`.\n\n\n# Http module\n\nAlso there's a small HTTP module which you can use to serve and send requests. \n\nHere's a client usage example:\n\n```python\nimport gensyncio\nfrom gensyncio.http import ClientRequest\n\n\ndef main():\n    yield\n    req = ClientRequest(\"http://localhost:8080/\", \"GET\", json={\"one\": \"two\"})\n    resp = yield from req.send()\n    print(resp)\n    print(resp.body.decode(\"utf-8\"))\n\n\ngensyncio.run(main())\n```\n\nAnd here's a simple echo server example:\n\n```python\nimport logging\nfrom typing import Generator\nfrom gensyncio.http import Server\nimport gensyncio\nfrom gensyncio.http.server import Request, Response\n\napp = Server()\n\n\n@app.router.get(\"/\")\ndef index(req: Request) -\u003e Generator[None, None, Response]:\n    body = yield from req.read()\n    return Response(status=200, body=body, content_type=req.content_type)\n\n\nif __name__ == \"__main__\":\n    logging.basicConfig(level=logging.INFO)\n    gensyncio.run(app.run(host=\"0.0.0.0\", port=8080))\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs3rius%2Fgensyncio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fs3rius%2Fgensyncio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs3rius%2Fgensyncio/lists"}