Piccolo Apps

By leveraging Piccolo apps you can:

  • Modularise your code.

  • Share your apps with other Piccolo users.

  • Unlock some useful functionality like auto migrations.


Creating an app

Run the following command within your project:

piccolo app new my_app

Where my_app is your new app’s name. This will create a folder like this:

my_app/
    __init__.py
    piccolo_app.py
    piccolo_migrations/
        __init__.py
    tables.py

It’s important to register your new app with the APP_REGISTRY in piccolo_conf.py.

# piccolo_conf.py
APP_REGISTRY = AppRegistry(apps=['my_app.piccolo_app'])

Anytime you invoke the piccolo command, you will now be able to perform operations on your app, such as Migrations.


AppConfig

Inside your app’s piccolo_app.py file is an AppConfig instance. This is how you customise your app’s settings.

# piccolo_app.py
import os

from piccolo.conf.apps import AppConfig
from .tables import (
    Author,
    Post,
    Category,
    CategoryToPost,
)


CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__))


APP_CONFIG = AppConfig(
    app_name='blog',
    migrations_folder_path=os.path.join(
        CURRENT_DIRECTORY,
        'piccolo_migrations'
    ),
    table_classes=[Author, Post, Category, CategoryToPost],
    migration_dependencies=[],
    commands=[]
)

app_name

This is used to identify your app, when using the piccolo CLI, for example:

piccolo migrations forwards blog

migrations_folder_path

Specifies where your app’s migrations are stored. By default, a folder called piccolo_migrations is used.

table_classes

Use this to register your app’s Table subclasses. This is important for auto migrations.

You can register them manually (see the example above), or can use table_finder.

migration_dependencies

Used to specify other Piccolo apps whose migrations need to be run before the current app’s migrations.

commands

You can register functions and coroutines, which are automatically added to the piccolo CLI.

The targ library is used under the hood. It makes it really easy to write command lines tools - just use type annotations and docstrings. Here’s an example:

def say_hello(name: str):
    """
    Say hello.

    :param name:
        The person to greet.

    """
    print("hello,", name)

We then register it with the AppConfig.

# piccolo_app.py

APP_CONFIG = AppConfig(
    # ...
    commands=[say_hello]
)

And from the command line:

>>> piccolo my_app say_hello bob
hello, bob

If the code contains an error to see more details in the output add a --trace flag to the command line.

>>> piccolo my_app say_hello bob --trace

By convention, store the command definitions in a commands folder in your app.

my_app/
    __init__.py
    piccolo_app.py
    commands/
        __init__.py
        say_hello.py

Piccolo itself is bundled with several apps - have a look at the source code for inspiration.


table_finder

Instead of manually registering Table subclasses, you can use table_finder to automatically import any Table subclasses from a given list of modules.

from piccolo.conf.apps import table_finder

APP_CONFIG = AppConfig(
    app_name='blog',
    migrations_folder_path=os.path.join(
        CURRENT_DIRECTORY,
        'piccolo_migrations'
    ),
    table_classes=table_finder(modules=['blog.tables']),
    migration_dependencies=[],
    commands=[]
)

The module path should be from the root of the project (the same directory as your piccolo_conf.py file, rather than a relative path).

You can filter the Table subclasses returned using tags.

Source

piccolo.conf.apps.table_finder(modules: Sequence[str], include_tags: Optional[Sequence[str]] = None, exclude_tags: Optional[Sequence[str]] = None, exclude_imported: bool = False) List[Type[Table]]

Rather than explicitly importing and registering table classes with the AppConfig, table_finder can be used instead. It imports any Table subclasses in the given modules. Tags can be used to limit which Table subclasses are imported.

Parameters:
  • modules – The module paths to check for Table subclasses. For example, ['blog.tables']. The path should be from the root of your project, not a relative path.

  • include_tags – If the Table subclass has one of these tags, it will be imported. The special tag '__all__' will import all Table subclasses found.

  • exclude_tags – If the Table subclass has any of these tags, it won’t be imported. exclude_tags overrides include_tags.

  • exclude_imported

    If True, only Table subclasses defined within the module are used. Any Table subclasses imported by that module from other modules are ignored. For example:

    from piccolo.table import Table
    from piccolo.column import Varchar, ForeignKey
    from piccolo.apps.user.tables import BaseUser # excluded
    
    class Task(Table): # included
        title = Varchar()
        creator = ForeignKey(BaseUser)
    


Sharing Apps

By breaking up your project into apps, the project becomes more maintainable. You can also share these apps between projects, and they can even be installed using pip.