Skip to main content

pipeline status coverage report PyPI Status PyPI Version PyPI Python PyPI License PyPI Format

Applipy

A library for building modular applications.

pip install applipy

Applipy lets you:

  • implement self-contained or interdependant Modules that you can tell applipy to load for the application through the config file
  • implement AppHandles: instances that implement application lifecycle methods
  • modules can register multiple AppHandles that will be run concurrently
  • load your application from a configuration file
  • applipy will gracefully manage the lifecycle of your application
  • define protocol handlers for a given URI scheme in configuration values. With these you can implement secrets that can be accessed by the application through the configuration.

Usage

An application can be defined by using a JSON (or YAML, if pyyaml is installed).

# dev.yaml
app:
  name: demo
  modules:
  - applipy_http.HttpModule
  - applipy_prometheus.PrometheusModule

logging.level: DEBUG

http.servers:
- host: 0.0.0.0
  port: 8080

Save a file dev.yaml with the contents in the snipet above and run the following commands:

$ pip install pyyaml applipy applipy_http applipy_prometheus
$ applipy

The configuration file above defines an application named demo that installs the applipy web module and the Prometheus module.

You can try it by going to http://localhost:8080. To see some metrics you have to call at least twice on the http://0.0.0.0:8080/metrics endpoint.

Applipy will search for a configuration file named ${APPLIPY_CONFIG_PATH}/${APPLIPY_ENV}.json (and ${APPLIPY_CONFIG_PATH}/${APPLIPY_ENV}.yaml, if pyyaml is installed). The default values are: APPLIPY_ENV=dev and APPLIPY_CONFIG_PATH=..

Another option is to indicate the file directly, using applipy -f ./path/to/file.yaml.

AppHandle

AppHandle is the interface through wich applipy manages the lifecycle of the application. An AppHandle implementation looks like this:

# demo_app.py
from asyncio import get_event_loop
from logging import Logger

from applipy import AppHandle


class MyDemoApp(AppHandle):

    def __init__(self, logger: Logger, name: str):
        self.logger = logger.getChild(name)

    async def on_init(self):
        self.logger.info('initialize resources')
        self.future = get_event_loop().create_future()

    async def on_start(self):
        self.logger.info('run long lived application here')
        await self.future

    async def on_shutdown(self):
        self.logger.info('close and release resources')
        self.future.set_result(None)

As you can see above there is three methods exposed by AppHandles that let applipy run your application.

Applipy is capable of running multiple AppHandles concurrently, taking advantage of async in python.

The lifecycle of an application follow the following diagram:

  Application.start()
           │
           ▼
  AppHandle.on_init()
           │
           ▼
  AppHandle.on_start()        applipy cli
           │                SIGINT   SIGTERM   [Your own stopping mechanism]
           ▼                   └────────┴───────┬───────────┘
start_long_running_task()                       ▼
           │                            Application.stop()
           ▼                                    │
 AppHandle.on_shutdown()◄───────────────────────┘
           │
           ▼
  wait(shutdown_timeout)
           │
           ▼
   cancel_all_tasks()

shutdown_timeout can be set in the app configuration using the key app.shutdown_timeout_seconds. Defaults to 1 second.

It is expected that AppHandle.on_shutdown() will be used to indicate any long running tasks to stop and cleanup, and do any required cleanup itself.

Generally, AppHandle implementations are added to the applipy application by including the modules they are part of and registering the AppHandle in the module configure() function.

Modules

In applipy, modules are the building blocks of an application. They allow to bind instances/classes/providers to types by exposing the an applipy_inject.Injector's bind() function, register application handles by exposing the Application's register() function and define dependencies across modules.

An example of a module implementation looks like this:

# mymodule.py

from applipy import Config, Module, LoggingModule
from demo_app import MyDemoApp


class MyModule(Module):

    def __init__(self, config: Config):
        self._config = config

    def configure(self, bind, register):
        bind(str, 'ModuleDemo')
        register(MyDemoApp)

    @classmethod
    def depends_on(cls):
        return (LoggingModule,)

The way you add modules to an application is through the configuration file by defining a list of fully qualified names of Module implementations with the key app.modules:

app:
  modules:
    - applipy_http.HttpModule
    - applipy_prometheus.PrometheusModule
    - mymodule.MyModule

Modules can only receive one parameter in their constructor and it is a Config instance, as shown in the code above. If your module does not need access to the configuration, you can just not implement a __init__ or have it not have arguments (other than self).

The configure() method is run by the applipy Application when it is started and its purpose is to allow for binding types and registering application handles. Check the extended Module documentation in /docs/module.md.

Finally, the depends_on() class method returns a tuple of the module types the module depends on. In the example above, because the application handle registered by the module requires a logging.Logger, the module declares a dependency with the LoggingModule because we know that it binds the logging.Logger type.

More

For a deeper dive on the features and details feel free to check the /docs subdirectory and the code itself!

Metadata

Release files for applipy 2.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for applipy 2.5.0
File Size Uploaded Provenance Actions
applipy-2.5.0.tar.gz 15.7 kB Without provenance Details for applipy-2.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for applipy 2.5.0
File Interpreter ABI Platform Actions
applipy-2.5.0-py3-none-any.whl Python 3 none any Details for applipy-2.5.0-py3-none-any.whl

Total release size: 28.7 kB

Release files / applipy-2.5.0.tar.gz

Download URL applipy-2.5.0.tar.gz
Size 15.7 kB
Tags Source
SHA-256 checksum
How to use checksums
e23ef48f9db6b98e1f65fdb2c02640b5374097b55575a2541d91a4cd9e1eecaf
BLAKE2b-256 checksum
How to use checksums
cfb2e1fbbaa6773b969afe483de432041ac7a610c4ac8576f8ad5ef439ddeb8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.12.1

Release files / applipy-2.5.0-py3-none-any.whl

Download URL applipy-2.5.0-py3-none-any.whl
Size 12.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0f9cc46438f6991f1b36734220a0e253cb5181efe56cc1cab332054e7eaa8d6a
BLAKE2b-256 checksum
How to use checksums
fe62ca7b0a77e9c4ee6bd66c83c7b73733fd3ca66a70719df00c1bf8e7bc9f45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.12.1

Security for applipy 2.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page