Instead of the verbose "boilerplate"
def main(): ...
if __name__ == '__main__':
main()
mainpy can be used to write it as:
from mainpy import main
@main
def app(): ...
Similarly, the async boilerplate
import asyncio
async def main(): ...
if __name__ == '__main__':
asyncio.run(main())
can be replaced with
@main
async def async_app(): ...
If, for some reason, you cannot or don't want to use a decorator, you can also call the decorator with the function as an argument:
import mainpy
def main(): ...
mainpy.main(main)
With click
you can simply add the decorator as usual, as long as you keep in mind that it has to be the first decorator (i.e. above the @click.command()
):
import click
import mainpy
@mainpy.main
@click.command()
def click_command():
click.echo('Hello from click_command')
If you want to use @click.group
you probably don't want to decorate the group because the decorator will immediately execute. In those cases you probably want to move the mainpy.main(...)
execution to the bottom of the file:
import click
import mainpy
@click.group()
def group(): ...
@group.command()
def command(): ...
mainpy.main(group)
When using typer
you also need to use the regular call instead of the decorator:
import typer
import mainpy
app = typer.Typer()
@app.command()
def command():
typer.echo('typer.Typer()')
mainpy.main(app)
If you have uvloop installed, mainpy
will automatically call uvloop.install()
before running your async main
function. This can be disabled by setting use_uvloop=False
, e.g.:
@main(use_uvloop=False)
async def app(): ...
Optionally, python's development mode
can be emulated by setting debug=True
in @main
. This will enable the
faulthandler,
configure the warnings
filter to display all warnings, and activate the
asyncio debug mode:
@main(debug=True)
def app(): ...
pip install mainpy
requires python > 3.7