Metadata-Version: 2.4
Name: lilya
Version: 0.22.11
Summary: Yet another ASGI toolkit that delivers
Project-URL: Homepage, https://github.com/dymmond/lilya
Project-URL: Documentation, https://lilya.dev
Project-URL: Changelog, https://lilya.dev/release-notes/
Project-URL: Funding, https://github.com/sponsors/tarsil
Project-URL: Source, https://github.com/dymmond/lilya
Author-email: Tiago Silva <tiago.arasilva@gmail.com>
License-File: LICENSE
Keywords: ai,aiohttp,anyio,aop,api,api-key,api-server,asgi,async,async-framework,asyncio,authentication,auto-documentation,autodoc,backend,background-tasks,caching,cloud-native,concurrency,controllers,cors,csrf,data-validation,dependency-injection,developer-friendly,django,dymmond,esmerald,event-driven,exception-handling,fastapi,flask,graphql,graphql-support,high-performance,http,hypercorn,interceptors,json,jwt,lilya,machine-learning,microservices,middlewares,ml,modern-python,non-blocking,oauth2,observables,openapi,openapi-schema,openapi3,pydantic,python,python-types,python3,quart,ravyn,ravyn-framework,redoc,request-handling,response-models,rest,rest-api,routing,security,serialization,sse,starlette,streaming,swagger,type-hints,typed-api,uvicorn,validation,web,web-framework,websocket,websocket-server
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: AnyIO
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
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: Topic :: Internet
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: anyio<5,>=3.4.0
Requires-Dist: monkay>=0.4.0
Requires-Dist: multidict<7.0.0,>=6.0.4
Requires-Dist: typing-extensions>=3.10.0; python_version < '3.11'
Provides-Extra: all
Requires-Dist: httpx>=0.25.0; extra == 'all'
Requires-Dist: ipython; extra == 'all'
Requires-Dist: itsdangerous>=2.2.0; extra == 'all'
Requires-Dist: jinja2>=3.1.3; extra == 'all'
Requires-Dist: ptpython; extra == 'all'
Requires-Dist: python-magic; extra == 'all'
Requires-Dist: rich-toolkit>=0.14.7; extra == 'all'
Requires-Dist: sayer>=0.7.4; extra == 'all'
Requires-Dist: uvicorn[standard]>=0.29.0; extra == 'all'
Provides-Extra: cli
Requires-Dist: jinja2>=3.1.3; extra == 'cli'
Requires-Dist: rich-toolkit>=0.14.7; extra == 'cli'
Requires-Dist: sayer>=0.7.4; extra == 'cli'
Requires-Dist: uvicorn[standard]>=0.29.0; extra == 'cli'
Provides-Extra: docs
Requires-Dist: griffe-typingdoc<1.0,>=0.2.2; extra == 'docs'
Requires-Dist: mdx-include>=1.4.2; extra == 'docs'
Requires-Dist: mkdocs-macros-plugin>=0.4.0; extra == 'docs'
Requires-Dist: mkdocs-material>=9.4.4; extra == 'docs'
Requires-Dist: mkdocs-meta-descriptions-plugin>=2.3.0; extra == 'docs'
Requires-Dist: mkdocs<2.0.0,>=1.1.2; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.23.0; extra == 'docs'
Requires-Dist: pyyaml<7.0.0,>=6.0; extra == 'docs'
Requires-Dist: sayer>=0.7.4; extra == 'docs'
Requires-Dist: typing-extensions>=3.10.0; extra == 'docs'
Provides-Extra: openapi
Requires-Dist: pydantic<3,>=2.11.5; extra == 'openapi'
Provides-Extra: standard
Requires-Dist: itsdangerous>=2.2.0; extra == 'standard'
Requires-Dist: jinja2>=3.1.3; extra == 'standard'
Requires-Dist: rich-toolkit>=0.14.7; extra == 'standard'
Requires-Dist: sayer>=0.7.4; extra == 'standard'
Requires-Dist: uvicorn[standard]>=0.29.0; extra == 'standard'
Provides-Extra: test
Requires-Dist: httpx>=0.25.0; extra == 'test'
Provides-Extra: testing
Requires-Dist: a2wsgi<2.0.0,>=1.10.0; extra == 'testing'
Requires-Dist: anyio[trio]<5.0.0,>=3.6.2; extra == 'testing'
Requires-Dist: asyncz; extra == 'testing'
Requires-Dist: autoflake<3.0.0,>=2.0.2; extra == 'testing'
Requires-Dist: databasez>=0.9.7; extra == 'testing'
Requires-Dist: edgy[postgres]>=0.33.0; extra == 'testing'
Requires-Dist: email-validator>=2.1.0.post1; extra == 'testing'
Requires-Dist: flask<4.0.0,>=3.0.2; extra == 'testing'
Requires-Dist: freezegun; extra == 'testing'
Requires-Dist: httpx>=0.25.0; extra == 'testing'
Requires-Dist: ipdb; extra == 'testing'
Requires-Dist: ipython; extra == 'testing'
Requires-Dist: jinja2<4.0.0,>=3.1.3; extra == 'testing'
Requires-Dist: loguru; extra == 'testing'
Requires-Dist: msgpack; extra == 'testing'
Requires-Dist: msgspec<0.20.0,>=0.18.6; extra == 'testing'
Requires-Dist: mypy==1.18.2; extra == 'testing'
Requires-Dist: opentelemetry-exporter-otlp; extra == 'testing'
Requires-Dist: opentelemetry-sdk; extra == 'testing'
Requires-Dist: orjson; extra == 'testing'
Requires-Dist: ptpython; extra == 'testing'
Requires-Dist: pydantic<3,>=2.6.0; extra == 'testing'
Requires-Dist: pyjwt; extra == 'testing'
Requires-Dist: pytest-asyncio>=0.23.2; extra == 'testing'
Requires-Dist: pytest-cov<5.0.0,>=4.0.0; extra == 'testing'
Requires-Dist: pytest-mock>=3.12.0; extra == 'testing'
Requires-Dist: pytest<9.0.0,>=7.2.2; extra == 'testing'
Requires-Dist: python-magic; extra == 'testing'
Requires-Dist: python-multipart>=0.0.13; extra == 'testing'
Requires-Dist: pyyaml<7.0.0,>=6.0; extra == 'testing'
Requires-Dist: redis; extra == 'testing'
Requires-Dist: structlog; extra == 'testing'
Requires-Dist: typing-extensions>=3.10.0; extra == 'testing'
Description-Content-Type: text/markdown

# Lilya

<p align="center">
  <a href="https://lilya.dev"><img src="https://res.cloudinary.com/dymmond/image/upload/v1707501404/lilya/logo_quiotd.png" alt='Lilya'></a>
</p>

<p align="center">
    <em>🚀 Yet another ASGI toolkit that delivers. 🚀</em>
</p>

<p align="center">
<a href="https://github.com/dymmond/lilya/actions/workflows/test-suite.yml/badge.svg?event=push&branch=main" target="_blank">
    <img src="https://github.com/dymmond/lilya/actions/workflows/test-suite.yml/badge.svg?event=push&branch=main" alt="Test Suite">
</a>

<a href="https://pypi.org/project/lilya" target="_blank">
    <img src="https://img.shields.io/pypi/v/lilya?color=%2334D058&label=pypi%20package" alt="Package version">
</a>

<a href="https://pypi.org/project/lilya" target="_blank">
    <img src="https://img.shields.io/pypi/pyversions/lilya.svg?color=%2334D058" alt="Supported Python versions">
</a>
</p>

---

**Documentation**: [https://lilya.dev](https://lilya.dev) 📚

**Source Code**: [https://github.com/dymmond/lilya](https://github.com/dymmond/lilya)

**The official supported version is always the latest released**.

---

## Motivation

In the world of ASGI, alternatives are always great to have and no tool serves it all.
Lilya, coming from the great inspirations of the ones who paved the way, its a more simple, accurate
fast and easy to use Python toolkit/framework that aims for simplicity.

A lot of times you won't be needing a fully fledge Python web framework as it can be overwhelming
for some simple tasks, instead you would prefer a simple ASGI toolkit that helps you designing
production ready, fast, elegant, maintainable and modular applications.

This is where Lilya places itself.

Almost no hard dependencies, 100% pythonic, fully typed and ready for production.

## What does it bring?

Lilya comes bearing fruits.

* A lightweight ASGI toolkit/framework.
* Support for HTTP/WebSocket.
* Tasks (in ASGI known as background tasks).
* Lifespan events (on_startup/on_shutdown and lifespan).
* Native permission system.
* Middlewares (Compressor, CSRF, Session, CORS...).
* A native and **optional** [client](https://lilya.dev/lilya-cli).
* **Directive management control system** for any custom scripts to run inside the application.
* Little hard dependencies.
* Compatibility with `trio` and `asyncio`.
* Dynamic routing system with the help of the native **Include** and minimum boilerplate.
* Native settings system. No more bloated instances.
* Native dependency injection that is extremely scalable, clean and fast.
* Dynamic, native and fast custom serializers.

## Installation

If you want just the toolkit/framework.

```shell
$ pip install lilya
```

If you want the Lilya client (for scaffolds, and other useful tools)

```shell
$ pip install lilya[standard]
```

If you wish to use to extra functionalities such as the **shell** or **directives**
(project scaffold generation to speed up).

```shell
$ pip install lilya[cli,ipython] # for ipython shell
$ pip install lilya[cli,ptpython] # for ptpython shell
```

You can learn more about the [client](https://lilya.dev/directives/discovery) in the documentation.

Or if you want to install everything that will allow you to use all the resources of Lilya, such
as some specific middlewares.

```shell
$ pip install lilya[all]
```

### Additional

You would want to install an ASGI server such as [uvicorn](https://www.uvicorn.org/) or
[hypercorn](https://pgjones.gitlab.io/hypercorn/) as well.

## Quickstart

If you are familiar with other Python frameworks and toolkits, Lilya provides you with the same
feeling.

A Lilya also uses a [native settings system](https://lilya.dev/settings) which is something that can be extremely useful
for any application.

### The normal way

```python
from lilya.apps import Lilya
from lilya.requests import Request
from lilya.responses import Ok
from lilya.routing import Path


async def welcome():
    return Ok({"message": "Welcome to Lilya"})


async def user(user: str):
    return Ok({"message": f"Welcome to Lilya, {user}"})


async def user_in_request(request: Request):
    user = request.path_params["user"]
    return Ok({"message": f"Welcome to Lilya, {user}"})


app = Lilya(
    routes=[
        Path("/{user}", user),
        Path("/in-request/{user}", user_in_request),
        Path("/", welcome),
    ]
)
```

### Using Lilya to decorate

```python
from lilya.apps import Lilya
from lilya.requests import Request
from lilya.responses import Ok

app = Lilya()


@app.get("/")
async def welcome():
    return Ok({"message": "Welcome to Lilya"})


@app.get("/{user}")
async def user(user: str):
    return Ok({"message": f"Welcome to Lilya, {user}"})


@app.get("/in-request/{user}")
async def user_in_request(request: Request):
    user = request.path_params["user"]
    return Ok({"message": f"Welcome to Lilya, {user}"})
```

Is this simple. Although there is a lot to unwrap here. Did you notice the path `/{user}` not only
does not require a `request` to be declared and instead, receives a `user: str`?

Well, Lilya does a lot of internal magic for you. If you don't declare a `request`, that is not a
problem as it will only pass it if its there.

If you have the path parameter declared in the function handler as well, Lilya will automatically
search for the parameters declared and match them against the path parameters declared in the `Path`
and inject them for you.

Pretty cool, right? This is just scratching the surface.

## Definitions

Lilya can be considered a framework or a toolkit and the reasoning for it its because each component
such as middlewares, permissions, Path, Router... can be seen as an independent ASGI application.

In other words, you can build a [middleware](https://lilya.dev/middleware) or a [permission](https://lilya.dev/permissions) and
share those with any other existing ASGI framework out there, meaning, you could design a Lilya
application, middlewares, permissions and any other component and re-use them in [Esmerald][esmerald]
or [FastAPI][fastapi] or any other, really.

**Lilya is not a full-fledge framework like [Esmerald][esmerald] or [FastAPI][fastapi], instead**
**its a lightweight toolkit/framework that can be used to build those as well as working on its own.**

**Example**

```python
from lilya.exceptions import PermissionDenied
from lilya.protocols.permissions import PermissionProtocol
from lilya.requests import Request
from lilya.types import ASGIApp, Receive, Scope, Send


class AllowAccess(PermissionProtocol):
    def __init__(self, app: ASGIApp, *args, **kwargs):
        super().__init__(app, *args, **kwargs)
        self.app = app

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        request = Request(scope=scope, receive=receive, send=send)

        if "allow-admin" in request.headers:
            await self.app(scope, receive, send)
            return
        raise PermissionDenied()
```

## Run the application

To run the application from the example.

```shell
$ uvicorn myapp:app
INFO:     Started server process [140552]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```

## Powered by

Worth mentioning who is helping us.

**JetBrains**

[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSourceSupport)

[esmerald]: https://lilya.dev/esmerald
[fastapi]: https://fastapi.tiangolo.com
