Metadata-Version: 2.4
Name: async-typer
Version: 0.2.1
Summary: Typer with first-class async support: unified sync/async commands, callbacks, and lifecycle event handlers.
Project-URL: Homepage, https://github.com/byunjuneseok/async-typer
Project-URL: Repository, https://github.com/byunjuneseok/async-typer
Project-URL: Bug Tracker, https://github.com/byunjuneseok/async-typer/issues
Author-email: byunjuneseok <byunjuneseok@gmail.com>
License: The MIT License (MIT)
        
        Copyright (c) 2025 Juneseok Byun
        
        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.txt
Keywords: async,asyncio,cli,typer
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: typer<1.0.0,>=0.9.0
Description-Content-Type: text/markdown

# async-typer

[Typer](https://github.com/tiangolo/typer) with first-class async support:
`async def` commands and callbacks work alongside regular sync ones via the
same `@app.command()` decorator — no second API to remember — plus lifecycle
event handlers for setting up and tearing down async resources.

## Features

- **One decorator, sync or async** — `@app.command()` and `@app.callback()`
  accept both regular and `async def` functions. The wrapper is transparent;
  Typer's `--help`, option parsing, and type conversion all work as normal.
- **Shared event loop across the command lifecycle** — startup handlers,
  the command body, and shutdown handlers all run on the same
  [`asyncio.Runner`](https://docs.python.org/3/library/asyncio-runner.html),
  so async resources created on startup (connection pools, HTTP sessions,
  etc.) remain usable by the command and by shutdown.
- **Fully typed** — ships with a `py.typed` marker and strict type hints.
- **Drop-in replacement** — re-exports Typer's public API, so
  `from async_typer import Option, Argument, echo, ...` works without a
  second import line.

## Installation

```bash
pip install async-typer
# or
uv add async-typer
```

Requires Python 3.11+.

## Quick start

```python
from async_typer import AsyncTyper

app = AsyncTyper()


@app.command()
def sync_hello(name: str = "world") -> None:
    print(f"hi {name}")


@app.command()
async def async_hello(name: str = "world") -> None:
    # await anything you need here
    print(f"hello {name}")


if __name__ == "__main__":
    app()
```

## Async callbacks

```python
@app.callback()
async def main(verbose: bool = False) -> None:
    if verbose:
        print("verbose mode")
```

## Lifecycle event handlers

Register `startup` and `shutdown` hooks, sync or async. They run on the
same event loop as the command body, so shared async resources stay alive
across the whole invocation:

```python
import httpx

app = AsyncTyper()
state: dict[str, httpx.AsyncClient] = {}


async def open_client() -> None:
    state["client"] = httpx.AsyncClient()


async def close_client() -> None:
    await state["client"].aclose()


app.add_event_handler("startup", open_client)
app.add_event_handler("shutdown", close_client)


@app.command()
async def fetch(url: str) -> None:
    response = await state["client"].get(url)
    print(response.status_code)
```

The shutdown handler runs even if the command raises — use it to release
resources unconditionally.

## Migrating from 0.1.x

The separate `async_command` / `async_callback` decorators still work but
emit `DeprecationWarning`. Replace them with the unified `command` /
`callback`, which auto-detect `async def`:

```python
# before
@app.async_command()
async def foo(): ...

# after
@app.command()
async def foo(): ...
```

## Development

This repo uses [`uv`](https://github.com/astral-sh/uv),
[`ruff`](https://github.com/astral-sh/ruff), and
[`ty`](https://github.com/astral-sh/ty).

```bash
uv sync --dev
uv run pytest
uv run ruff check .
uv run ty check
```

## License

MIT — see [LICENSE.txt](LICENSE.txt).
