Change the behavior of a command

Now that we have created multiple commands and projects, we are going to change the behavior of these commands for a specific project. This is where things get really interesting because, you can start to shape your framework as you want in order to fit your needs.

How it works?

Socon works with managers and hooks. You can get more information here. Commands are hooks of the CommandManager class. It’s this class that will look for every commands in the management/commands directory that you have in the common space, your projects and even Socon.

When you start a command, Socon will look for this command in a specific order. The last being the most important:

  1. Socon

  2. Plugins

  3. Common

  4. Projects

Here is an example: Let’s use the build command that we created in the previous tutorial. This command is common to all projects. If we don’t redefine this command in one of the project, the CommandManager will return the command from the common space.

Now, if we define the build command in the apollo project, the CommandManager will return that command instead of the one in the common space.

Change the behavior

To show the behavior described above, let’s add a new argument to the apollo project. To do that we will take a shortcut and copy the build.py file from the common space to the apollo project:

$ cp tutorial/management/commands/build.py projects/apollo/management/commands/build.py

If you start the help command using python manage.py help you will see that apollo has now a command called build:

...

[apollo]

    build (P)

If you start the command as usual, you won’t see any difference as it will basically execute the same code. To change its behavior, instead of subclassing this class from the ProjectCommand, we will subclass it by the one in the common space. This way, we use object inheritance and we have an extension of the build command for the apollo project.

The build.py of apollo:

from argparse import ArgumentParser

from tutorial.management.commands.build import BuildCommand

from socon.core.management.base import Config
from socon.core.registry.base import ProjectConfig


class BuildCommand(BuildCommand):
    name = 'build'

    def add_arguments(self, parser: ArgumentParser) -> None:
        super().add_arguments(parser)
        parser.add_argument(
            '--info', help='Add info to the handle command'
        )

    def handle(self, config: Config, project_config: ProjectConfig):
        print(config.getoption('info'))
        super().handle(config, project_config)

Now you just have to execute the command from the apollo project like this:

$ python manage.py build --project apollo --info "5 Days left"

You should see this result:

5 Days left
Building Saturn IB

Congratulations! You have modified the behavior of the build command! You can now build any spacecraft you want :)

Note

This also works for general commands. If you declare the same command in one of your projects you will be able to access it if you add the --project option to the command. Try it for yourself and change the behavior of the createcontainer command!