Imagine I have a big CLI application with many different commands (think, for example image-magick).
I wanted to organize this application into modules and etc. So, there would be a master click.group
somewhere:
#main.py file
@click.group()
def my_app():
pass
if __name__ == "__main__":
my_app()
that can be imported in each module that define a command:
from main import my_app
# command_x.py
@my_app.command()
def command_x():
pass
The problem is that I run into a circular import problem, since the main.py
file knows nothing about command_x.py
and I would have to import it before calling the main section.
This happens in Flask too and is usually dealt with the app factory pattern. Usually you would have the app being created before the views:
app = Flask("my_app")
@my_app.route("/")
def view_x():
pass
if __name__ == "__main__":
app.run()
In the app factory pattern you postpone the "registration" of the blueprints:
# blueprints.py
blueprint = Blueprint(yaddayadda)
@blueprint.route("/")
def view_x():
pass
And make a factory that knows how to build the app and register the blueprints:
#app_factory.py
from blueprints import view_x
def create_app():
app = Flask()
view_x.init_app(app)
return app
And you can then create a script to run the app:
#main.py
from app_factory import create_app
if __name__ == "__main__":
app = create_app()
app.run()
Can a similar pattern be used with Click? Could I just create a "click app" (maybe extending click.Group
) where I register the "controllers" which are the individual commands?
Maybe late, but I was also searching for a solution to put commands to separate modules. Simply use a decorator to inject commands from modules:
#main.py file
import click
import commands
def lazyloader(f):
# f is an instance of click.Group
f.add_command(commands.my_command)
return f
@lazyloader
@click.group()
def my_app():
pass
if __name__ == "__main__":
my_app()
The separated command can use the usual decorators from click.
#commands.py
import click
@click.command()
def my_command():
pass