{"id":49808231,"url":"https://github.com/aviadr1/winuvloop","last_synced_at":"2026-05-12T23:42:53.212Z","repository":{"id":255053420,"uuid":"848397174","full_name":"aviadr1/winuvloop","owner":"aviadr1","description":"Cross-platform asyncio event loop selector: uvloop on POSIX and winloop on Windows","archived":false,"fork":false,"pushed_at":"2026-05-04T05:44:47.000Z","size":307,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-12T23:42:45.876Z","etag":null,"topics":["asyncio","event-loop","performance","python","uvloop","windows","winloop"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/winuvloop/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aviadr1.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-08-27T17:26:20.000Z","updated_at":"2026-05-04T05:44:50.000Z","dependencies_parsed_at":"2024-08-27T19:38:52.477Z","dependency_job_id":null,"html_url":"https://github.com/aviadr1/winuvloop","commit_stats":null,"previous_names":["aviadr1/winuvloop"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/aviadr1/winuvloop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aviadr1%2Fwinuvloop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aviadr1%2Fwinuvloop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aviadr1%2Fwinuvloop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aviadr1%2Fwinuvloop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aviadr1","download_url":"https://codeload.github.com/aviadr1/winuvloop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aviadr1%2Fwinuvloop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32961785,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-12T23:30:32.555Z","status":"ssl_error","status_checked_at":"2026-05-12T23:30:18.191Z","response_time":102,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["asyncio","event-loop","performance","python","uvloop","windows","winloop"],"created_at":"2026-05-12T23:42:52.486Z","updated_at":"2026-05-12T23:42:53.208Z","avatar_url":"https://github.com/aviadr1.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# winuvloop\n\n[![PyPI](https://img.shields.io/pypi/v/winuvloop.svg)](https://pypi.org/project/winuvloop/)\n[![Python](https://img.shields.io/pypi/pyversions/winuvloop.svg)](https://pypi.org/project/winuvloop/)\n[![Downloads](https://img.shields.io/pypi/dm/winuvloop.svg)](https://pypi.org/project/winuvloop/)\n[![CI](https://github.com/aviadr1/winuvloop/actions/workflows/ci.yml/badge.svg)](https://github.com/aviadr1/winuvloop/actions/workflows/ci.yml)\n[![License](https://img.shields.io/pypi/l/winuvloop.svg)](https://github.com/aviadr1/winuvloop/blob/main/LICENSE)\n\n`winuvloop` is a tiny cross-platform asyncio event loop selector for projects\nthat want one import to do the right thing on developer laptops, CI, and\nproduction runners:\n\n| Platform | Backend used by `winuvloop` |\n| --- | --- |\n| Windows | [`winloop`](https://github.com/Vizonex/Winloop) |\n| Linux, macOS, other POSIX | [`uvloop`](https://github.com/MagicStack/uvloop) |\n\nIt is useful when the same Python application, example, benchmark, CLI, or\nservice should use a high-performance asyncio loop on both Windows and\nUnix-like systems without duplicating platform checks at every entry point.\n\n## Why This Exists\n\n[`uvloop`](https://github.com/MagicStack/uvloop) is the established\nhigh-performance asyncio event loop for Linux, macOS, and other POSIX\nplatforms. It is widely used for network-heavy asyncio workloads such as API\nservers, proxies, websocket services, crawlers, and async database clients.\n\n[`winloop`](https://github.com/Vizonex/Winloop) provides a uvloop-compatible\nAPI for Windows, where `uvloop` itself is not the Windows backend.\n\n`winuvloop` does not replace either upstream project, vendor their code, or\nhide backend bugs. It gives you one import that chooses the right upstream\nbackend:\n\n```python\nimport winuvloop\n\n\nasync def main() -\u003e None:\n    ...\n\n\nwinuvloop.run(main())\n```\n\nThe wrapper stays deliberately small: platform detection, clear diagnostics,\ncommon API re-exports, typing stubs, and platform-specific dependency markers.\nRuntime behavior comes from the selected upstream backend.\n\n## Why Performance Can Matter\n\nThe upstream projects publish benchmark guidance for the workloads they own.\n[`uvloop`](https://github.com/MagicStack/uvloop#performance) reports making\nasyncio 2-4x faster on its echo-server benchmarks. On Windows,\n[`winloop`](https://github.com/Vizonex/Winloop#benchmarks) reports a TCP\nconnection benchmark of 0.493s with `WinLoopPolicy`, compared with 2.510s for\n`WindowsProactorEventLoopPolicy` and 2.723s for\n`WindowsSelectorEventLoopPolicy`.\n\nThose are upstream benchmark numbers, not a universal promise for every\napplication. The practical point for `winuvloop` is simpler: one dependency\nlets a cross-platform project select the optimized backend that upstream\nprojects already benchmark and maintain for each operating system family.\n\n## When To Use It\n\nUse `winuvloop` when:\n\n- your project supports both Windows and Linux/macOS\n- examples or docs should stay platform-neutral\n- your CLI or application wants the fastest available asyncio loop by default\n- you want one dependency that resolves `uvloop` or `winloop` through platform\n  markers\n- you want to log or inspect which optimized backend was selected\n- you maintain library examples that should work for both Unix and Windows\n  users\n\nUse the upstream packages directly when:\n\n- your project only targets Linux/macOS: use `uvloop`\n- your project only targets Windows: use `winloop`\n- you need backend-specific APIs and do not want a selector layer\n- you are debugging an upstream event-loop issue and need to remove wrappers\n\n| Situation | Recommended dependency |\n| --- | --- |\n| Linux/macOS-only service | `uvloop` |\n| Windows-only service | `winloop` |\n| Cross-platform CLI, app, benchmark, or documentation | `winuvloop` |\n| Backend-specific feature work or bug isolation | upstream backend directly |\n\n## Installation\n\n```bash\npip install winuvloop\n```\n\nWith `uv`:\n\n```bash\nuv add winuvloop\n```\n\n`winuvloop` declares platform-specific dependencies. Installers resolve only\nthe backend needed for the current environment.\n\n## Usage\n\nPrefer `run()` for application entry points:\n\n```python\nimport winuvloop\n\n\nasync def main() -\u003e str:\n    return \"done\"\n\n\nresult = winuvloop.run(main())\n```\n\nFor frameworks or legacy code that expects a global event-loop policy, use\n`install()`:\n\n```python\nimport asyncio\n\nimport winuvloop\n\n\nwinuvloop.install()\nasyncio.run(main())\n```\n\nYou can inspect the selected backend for diagnostics and support logs:\n\n```python\nimport winuvloop\n\n\nprint(winuvloop.backend_name())  # \"uvloop\" or \"winloop\"\nprint(winuvloop.backend_version())\nprint(winuvloop.__backend__)\nprint(winuvloop.backend().__name__)\n```\n\nThe module re-exports the common backend API:\n\n- `run`\n- `install`\n- `new_event_loop`\n- `Loop`\n- `EventLoopPolicy`\n- `backend`\n- `backend_name`\n- `backend_version`\n\nBackend-specific attributes are delegated to the selected upstream module.\n\n## Framework Examples\n\n`winuvloop` is most useful at process entry points: command-line scripts,\napplication launchers, benchmark runners, and local development helpers. Install\nthe optimized loop before a framework creates its event loop, or use\n`winuvloop.run()` when you own the top-level coroutine.\n\nThese examples do not mean `winuvloop` depends on the frameworks shown here.\nInstall FastAPI, Uvicorn, aiohttp, or any other framework separately in your\napplication.\n\n### FastAPI And Uvicorn\n\nFor a FastAPI application launched from Python, install the selected backend\nbefore calling `uvicorn.run()`. Pass `loop=\"asyncio\"` so Uvicorn uses the event\nloop policy that `winuvloop.install()` already selected:\n\n```python\n# serve.py\nimport uvicorn\n\nimport winuvloop\n\n\nwinuvloop.install()\n\nuvicorn.run(\n    \"myapp:app\",\n    host=\"127.0.0.1\",\n    port=8000,\n    loop=\"asyncio\",\n)\n```\n\nThen run the launcher instead of invoking `uvicorn` directly:\n\n```bash\npython serve.py\n```\n\nIf your deployment platform already configures the event loop, prefer the\nplatform's documented setting. `winuvloop` is the portable option when you want\nthe same launcher to select `uvloop` on Linux/macOS and `winloop` on Windows.\n\n### aiohttp Web Server\n\nFor an `aiohttp.web` application, use `winuvloop.run()` around the application\nrunner:\n\n```python\nimport asyncio\n\nfrom aiohttp import web\n\nimport winuvloop\n\n\nasync def hello(request: web.Request) -\u003e web.Response:\n    return web.Response(text=\"hello\")\n\n\nasync def main() -\u003e None:\n    app = web.Application()\n    app.router.add_get(\"/\", hello)\n\n    runner = web.AppRunner(app)\n    await runner.setup()\n\n    site = web.TCPSite(runner, \"127.0.0.1\", 8080)\n    await site.start()\n\n    await asyncio.Event().wait()\n\n\nwinuvloop.run(main())\n```\n\n### Async CLI Or Worker\n\nFor scripts, CLIs, and workers, keep the entry point boring:\n\n```python\nimport winuvloop\n\n\nasync def main() -\u003e int:\n    ...\n    return 0\n\n\nraise SystemExit(winuvloop.run(main()))\n```\n\nThis keeps examples and internal tools platform-neutral while still selecting\nthe optimized backend for the current runner.\n\n### Tests And Support Logs\n\nFor compatibility tests, assert the selected backend rather than hard-coding an\noperating system in every test:\n\n```python\nimport sys\n\nimport winuvloop\n\n\ndef test_optimized_backend_is_available() -\u003e None:\n    expected = \"winloop\" if sys.platform == \"win32\" else \"uvloop\"\n\n    assert winuvloop.backend_name() == expected\n    assert winuvloop.backend_version() is not None\n```\n\nFor issue reports, include this diagnostic snippet:\n\n```bash\npython - \u003c\u003c'PY'\nimport platform\nimport winuvloop\n\nprint(\"python:\", platform.python_version(), platform.python_implementation())\nprint(\"platform:\", platform.platform())\nprint(\"backend:\", winuvloop.backend_name(), winuvloop.backend_version())\nPY\n```\n\n## Typing\n\n`winuvloop` ships a `py.typed` marker and public API stubs for the selector\nmodule. The runtime values remain direct aliases to the selected upstream\nbackend, so `winuvloop.Loop` is still `uvloop.Loop` on POSIX and `winloop.Loop`\non Windows.\n\n## Compatibility\n\n`winuvloop` targets CPython 3.8.1 and newer. The optimized backend packages are\nnative CPython packages, so PyPy and other Python implementations are not a\nsupported target for this selector.\n\n| Environment | Status |\n| --- | --- |\n| CPython 3.8-3.14 | Supported by current upstream wheels |\n| Linux/macOS | Uses `uvloop` |\n| Windows | Uses `winloop` |\n| PyPy | Not supported by the upstream native backends |\n| Windows ARM64 | Supported when `winloop` publishes a matching wheel |\n| Linux/macOS ARM64 | Supported when `uvloop` publishes a matching wheel |\n\nIf an upstream backend does not publish a wheel for a specific interpreter or\nplatform, installation may require local build tooling for that backend.\n\n## Upstream Support Boundary\n\nReport selector problems here when platform selection, dependency markers,\ntyping stubs, documentation, or packaging are wrong.\n\nReport backend behavior problems upstream when the issue also reproduces after\nimporting the selected backend directly:\n\n- `uvloop`: \u003chttps://github.com/MagicStack/uvloop/issues\u003e\n- `winloop`: \u003chttps://github.com/Vizonex/Winloop/issues\u003e\n\nThis keeps backend fixes close to the projects that own event-loop internals\nwhile keeping `winuvloop` focused on cross-platform ergonomics.\n\n## Testing Strategy\n\nCI runs on Linux, macOS, and Windows. It includes:\n\n- lockfile validation with `uv lock --check`\n- linting with `ruff`\n- formatting checks with `ruff format --check`\n- bytecode compilation checks for `src` and `tests`\n- wrapper unit tests that mock both backends\n- real backend smoke tests that call `winuvloop.run()` on the platform backend\n- source distribution and wheel builds\n- package metadata validation with `twine check`\n\nThis keeps the wrapper behavior fast to test while still proving that the\npublished backend dependencies are usable on each runner family.\n\n## Development\n\nThis project uses [`uv`](https://docs.astral.sh/uv/) for dependency management,\nlocking, and builds.\n\n```bash\nuv sync\nuv run ruff check .\nuv run ruff format --check .\nuv run pytest\nuv build\nuv run twine check dist/*\n```\n\n## Release And Automation\n\nDependabot updates are grouped for upstream event loops, Python tooling, and\nGitHub Actions. Dependabot PRs auto-merge after the CI workflow passes.\n\nReleases are automatic:\n\n1. Change `project.version` in `pyproject.toml`.\n2. Merge to `main`.\n3. After CI passes on `main`, GitHub Actions creates the missing `vX.Y.Z` tag.\n4. GitHub Actions dispatches `release.yml` for that tag.\n5. The release workflow smoke-tests Linux, macOS, and Windows, then builds,\n   validates, publishes to PyPI, and creates a GitHub Release.\n\nPyPI trusted publishing must be configured for the `release.yml` workflow and\nthe `pypi` environment for credential-free publishing. If the repository still\nuses a `PYPI_API_TOKEN` secret, the release workflow can use that as a fallback.\nManual tag pushes with the `vX.Y.Z` format still run the same release workflow.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faviadr1%2Fwinuvloop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faviadr1%2Fwinuvloop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faviadr1%2Fwinuvloop/lists"}