Getting Started¶
In this section we will run through the processes of building an application with
pyApp
.
Application Layout¶
We’ll start with a simple application that accepts input from the command line and combines it with a value from configuration.
The default pyApp
configuration makes a number of assumptions as to how your
application is laid out, with each module within your application package
fulfilling a specific purpose. The easiest way to setup a basic app is to use
the pyApp
Cookiecutter to generate an application.
Install cookie-cutter from pip and use the template to start your initial project:
> pip install cookiecutter
> cookiecutter gh:pyapp-org/pyapp.cookiecutter
Project Structure¶
The basic structure of a pyApp
application package consists of the following:
📁 myapp
├📄 __init__.py Python package initialisation
├📄 __main__.py Python main entry point
├📄 cli.py The CLI (referenced from __main__)
├📄 default_settings.py Definition of default runtime configuration
└📄 checks.py Application specific checks
__init__.py
¶
The presence of an __init__.py
file in a folder makes Python use the folder
as a package and contains initialisation code for the package. pyApp
also
uses this file to find information for the application.
__version__
- The version number of the application, it is recommended that this be a
semantic version.
pyApp
also provides tools for this to be fetched from the installed package list.
__main__.py
¶
The main entry point for a Python application when referring to a package using
python -m myapp
. The default cookiecutter application triggers the main
function in the cli module.
cli
¶
This is where the pyApp
CliApplication
instance is defined. The
CliApplication
class handles initialisation of application services before
handing over execution to the command handler of the command requested by the
CLI.
Setting up the CLI¶
Adding a CLI consists of two steps, defining a CliApplication
instance and
using the CliApplication.command
decorator to functions to add commands to
your application.
First create a CliApplication
instance:
from pyapp.app import CliApplication
# Define our application instance
app = CliApplication(
description="My Application"
)
# Define our main entry point
main = app.dispatch
CliApplication
has many options to customise how it works, these are all
provided with defaults but can be customised to change the behaviour, see the
API documentation for more information on other options.
Next CLI commands are created by applying the CliApplication.command
argument
to a python function.
@app.command
def greeting(name: str, *, greeting: str = "Hello"):
"""
Provide a greeting
"""
print(f"{greeting} {name}")
This example adds the greeting command to the CLI that requires a name and allows for an optional greeting to be provided. It can be called using:
> my_app greeting Guido --greeting Hallo
Hallo Guido
Application Settings¶
All of your applications settings are defined in the default_settings.py
file that is located in your applications main package. These settings are
loaded by the CliApplication on startup and combine with settings from pyApp
extensions as well as runtime settings.
The default settings file is a normal python module allows for complex behaviours to be defined. Any variable that consists of all upper-case characters (including _) is considered a setting and is imported into the settings container.
Once an application has been initialised the final set of runtime settings is
available from the settings container pyapp.conf.settings
:
from pyapp.conf import settings
print(settings.MY_SETTING)
Runtime Checks¶
These are functions that are called by the checks report to perform a check against the current settings to assert that the current runtime environment is correct. This can include:
- Checking settings are valid
- Confirming connectivity/access to a database
- Checking free space on the filesystem
These checks can help to diagnose issues, perform basic validation of the runtime environment and provide application monitoring.
A check is defined by:
from pyapp import checks
@checks.register
def debug_is_enabled(settings, **_):
if settings.DEBUG:
return checks.Warning("Debug mode is enabled")
In this example a check returns a warning if DEBUG is True
in settings.