Metadata-Version: 2.4
Name: asyncify-codemod
Version: 0.2.0
Summary: Codemod to convert synchronous Python code to async.
License: MIT License
        
        Copyright (c) 2026 ryan
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: anyio
Requires-Dist: httpx
Requires-Dist: libcst
Requires-Dist: pytest>=9.0.2
Description-Content-Type: text/markdown

# asyncify-codemod

`asyncify-codemod` is a codemod that converts synchronous Python code into async where
possible. It focuses on a few common patterns (like `requests`, `time.sleep`,
and file I/O) and rewrites them to async equivalents.

## Usage

Run with [pipx](https://github.com/pypa/pipx)

```bash
pipx run asyncify-codemod [files you wish to transform ...]
```

E.g. if your python source files are located in `src/`:

```bash
pipx run asyncify-codemod src/**/*.py
```

```bash
pipx run asyncify-codemod --stdout path/to/file.py path/to/another.py
```

## Comparison: asyncio.to_thread() vs async rewrites

Because “real async I/O” and “sync I/O in a thread” solve different problems, and they behave very differently at scale and under cancellation.

### Where to_thread is great

Fast migration / compatibility shim: you can call existing blocking code from an async app without freezing the event loop.
No behavioral rewrite: minimal code churn; good for legacy code you don’t want to touch yet.
Sync-only dependencies: if there is no solid async alternative, threads are the pragmatic choice.

### Where to_thread breaks down (and why a codemod helps)

- Concurrency limits: to_thread is bounded by a thread pool. You can run thousands of concurrent await httpx/... calls; you generally can’t run thousands of threads. Under load, this becomes queueing/latency rather than throughput.
- Cancellation semantics: cancelling an await to_thread(...) usually does not stop the underlying blocking call; it just stops waiting for it. With real async libs, cancellation is often propagated more cleanly (still not perfect everywhere, but materially better).
- Resource efficiency: threads cost memory + scheduling overhead; async sockets/file ops can be much lighter per in-flight operation.
  You can’t “mix in” async behavior inside: if a function is wrapped, everything inside it stays sync. A codemod can turn the internals into await points (time.sleep → anyio.sleep, requests → httpx, open() → anyio.open_file), enabling cooperative scheduling throughout the call graph.
- Observability/context: thread offloading can complicate tracing/log context propagation and debugging (it’s doable, just another layer). Pure async tends to integrate more directly with async frameworks’
  middleware/instrumentation.

Use a codemod when you want the codebase to become natively async so it scales better, cancels better, and composes naturally with async frameworks—without hand-editing hundreds of mechanical changes.

## Caveats

### Sync-only dependencies

Currently, this codemod only rewrites commonly used I/O-bound operations with async alternatives (as mentioned above). If you're using custom libraries where there are no solid async alternatives, they will in your new async functions after a codemod. **This is a huge performance blocker** and the only way to resolve this right now is to manually update its usages (i.e. send it to `asyncio.to_thread`).
