Skip to main content

No project description provided

Project description

Aloni

Aloni is a Python framework designed to increase productivity when developing applications. Simplicity, productivity, and great developer experience are our primary goals.

It is based on an innovative Role-Based Services approach. (more info below).

It is async and thus performs well with IO-bound services (for example, anything that makes a lot of long-running HTTP calls to large language models or uses a lot of microservices and third-party services)—but not just those.

Try it out

Aloni will take only a few minutes to set up, and it might amaze you and change how you develop apps. :)

Key Features

  • Effortlessly split your project into multiple files: Aloni automatically combines your project files based on the roles you assign them, making it easy to manage large projects.
  • Dependency Injection: Manage your application's dependencies effortlessly with a container that holds one instance of each service, ensuring efficient resource management.
  • Async-First: Aloni is optimized for asynchronous programming, making it perfect for IO-bound tasks.
  • Minial boilerplate: Aloni adds no redundant boilerplate code. Keep your project as simple as possible.

Getting Started

Installation

Requirements

Linux or MacOS (should work on all Unix systems). It does not work on Windows because Aloni requires the fork multiprocessing method (which Windows does not have).

That might change in the future (see also: https://github.com/emmett-framework/granian/issues/330).

Steps

Aloni works best with Poetry. Install Poetry first and follow the steps:

  1. Create a new Poetry project, then install Aloni:
    poetry add aloni
    
  2. Create your application's module:
    mkdir my_app
    
    touch my_app/__init__.py
    
  3. Create the app.py (primary application file). That is the entire boilerplate code that Aloni needs to work:
    import my_app
    import aloni
    
    aloni.start(my_app).exit_after_finishing()
    

Invoking poetry run python ./app.py should display something like:

usage: app.py [-h] {hello,serve} ...

Aloni CLI

positional arguments:
  {serve}
    serve        Start the app in HTTP server mode

options:
  -h, --help     show this help message and exit

Congratulations! You have installed the Aloni project. You can continue with the next steps.

Usage

Check the demo project for basic usage.

Aloni will scan your module (in this case, my_app) for services with a role decorator and start your CLI application. That's it!

Add a new CLI command if you want to start developing something new. Use responds_to_cli role. Add a new file in my_app/hello_command.py (file name can be anything; it's just an example - file names and directory structure do not matter for Aloni):

from aloni.cli_foundation import Command
from aloni.role import responds_to_cli


@responds_to_cli(
    name="hello",
    description="Say hello!",
)
class Hello(Command):
    async def respond(self) -> int:
        print("Hello, World!")

        return 0

You can then run it with:

python ./app.py hello

You should see:

Hello, World!

Quick Tutorials

Responding to HTTP Requests

Create a responder in your application's module. Filename and location do not matter:

from aloni.http import Responder, TextResponse
from aloni.role import responds_to_http


@responds_to_http(pattern='/ping')
class Ping(Responder):
    async def respond(self) -> TextResponse:
        return TextResponse("pong")

Responding with Jinja2 Templates

Place a template inside your application's templates directory. Name it hello.j2:

<p>Hello, world!</p>
from aloni.http import Responder, JinjaResponse
from aloni.role import responds_to_http


@responds_to_http(pattern='/hello')
class Hello(Responder):
    async def respond(self) -> JinjaResponse:
        return JinjaResponse('hello.j2')

Injecting Services

Create a service in your application's module. Filename and location do not matter:

from aloni.role import service


@service
class MyService:
    pass

Use it in your other services:

from aloni.role import service

from .my_service import MyService


@service
class OtherService:
    def __init__(self, my_service: MyService) -> None:
        self.my_service = my_service

Creating Service Providers

Create a base service class in your application's module. Do not add @service role to that class:

class MyService:
    def __init__(self, foo: str) -> None:
        self.foo = foo

Create service provider (again, location and filename do not matter as long as it's in your application's module):

from aloni.application_state import ApplicationState
from aloni.role import service_provider
from aloni.service_provider import ServiceProvider

from .my_service import MyService


@service_provider(provides=MyService)
class MyServiceProvider(ServiceProvider[MyService]):
    def provide(self) -> MyService:
        return MyService(foo="bar")

Use it in your other services:

from aloni.role import service

from .my_service import MyService


@service
class OtherService:
    def __init__(self, my_service: MyService) -> None:
        self.my_service = my_service

Registering Jinja Functions

Custom Jinja functions have their constructor (__init__) arguments injected by the dependency injection container.

Arguments passed to the __call__ method are passed from a template.

from aloni.jinja_function import JinjaFunction
from aloni.role.jinja_function import jinja_function


@jinja_function(name="say_hello")
class UrlFor(JinjaFunction):
    def __call__(self) -> str:
        return "Hello, world!"

Then use it in a template:

{{ say_hello() }}

API Reference

HTTP Responses

All the available roles are accessible from aloni.http module.

For example:

from aloni.http import AssetResponse
Response Description
AssetResponse Returns an asset file if it is present inside your application's assets directory
JinjaResponse Returns a parsed Jinja2 template if it is present inside your application's templates directory
TextResponse Returns a plain text response

Available Roles

All the available roles are accessible from aloni.role module.

For example:

from aloni.role import responds_to_http
Role Description
intercepts_http_response Allows to intercept any response returned by your http responder and convert it into a renderable response. It acts kind of like inversed middleware - instead of intercepting a request, it intercepts and modifies a response.
responds_to_cli Responds to CLI command
responds_to_http Responds to HTTP request
service Marks the current class as a service. Its constructor arguments will be injected from the dependency injection container
service_provider Registers a service provider for dependency injection. Use it to create a class that provides an instance of a different class to the dependency injection container.

Special Thanks

  • Granian for creating an awesome HTTP Python runner with excellent performance

License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aloni-0.2.3.tar.gz (27.1 kB view details)

Uploaded Source

Built Distribution

aloni-0.2.3-py3-none-any.whl (45.4 kB view details)

Uploaded Python 3

File details

Details for the file aloni-0.2.3.tar.gz.

File metadata

  • Download URL: aloni-0.2.3.tar.gz
  • Upload date:
  • Size: 27.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.11.9 Linux/6.7.12-amd64

File hashes

Hashes for aloni-0.2.3.tar.gz
Algorithm Hash digest
SHA256 58b30b1e53c0309268422ad8fea4cd3ae7986986208d4ef54fc4949332a6e503
MD5 de741efabc553f27fa161617fede2fc2
BLAKE2b-256 b8c352813c8c0c6771d0b12aba80350c84590200d2900180301a2e1a95b73fa0

See more details on using hashes here.

File details

Details for the file aloni-0.2.3-py3-none-any.whl.

File metadata

  • Download URL: aloni-0.2.3-py3-none-any.whl
  • Upload date:
  • Size: 45.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.11.9 Linux/6.7.12-amd64

File hashes

Hashes for aloni-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 40327af14ea31b4d091183e4e8e262abd8a8a0b3a7e03f2524ab434e8c2c5f94
MD5 30d20a74793b7ac37c18de326fb44cba
BLAKE2b-256 96df123637359b90586029c0c35ffbc8d265b624f1d9ed00ebcbf4363caf2679

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page