Separating UI Code in Your Nom Nom App

Separating UI Code in Your Nom Nom App

This article explains a best practice for moving different portions of your Nom Nom App code into different files.  Specifically it focuses on moving the portion of the code that controls the user interface to a different file, but the techniques described can be generalized and applied to any logical separations that you would like to have.  It is assumed that the reader is already familiar with the information in the Creating Your First Nom Nom App article.

Identify Code to Move

The highlighted portion of the sample app code below is the code that tells the Nominode how the user interface for the app should be rendered.  In this example, we will explain how to move that code from the pkg/executable.py file to a different file within your app.
import logging

from nomnomdata.engine import Engine, Parameter, ParameterGroup
from nomnomdata.engine.parameters import Int, String

logger = logging.getLogger("engine.hello_world")

engine = Engine(
    uuid="CHANGE-ME-PLEASE",
    alias="Hello World Sample",
    description="Demonstrates basic app structure and functionality.",
    categories=["general"],
)

@engine.action(
    display_name="Hello World",
    description="Prints a greeting multiple times in the Task execution log.",
)
@engine.parameter_group(
    name="general_parameters",
    display_name="General Parameters",
    description="Parameters for Hello World",
    parameter_group=ParameterGroup(
        Parameter(
            type=Int(),
            name="repeat",
            display_name="Repeat",
            description="Specify how many times to print.",
            default=1,
            required=True,
        ),
        Parameter(
            type=String(),
            name="name",
            display_name="Name",
            description="Specify a name to print instead of World.",
            required=False,
        ),
    ),
)
def hello_world(parameters):
    i = 0
    x = f"Hello {parameters.get('name') or 'World'}"
    while i < parameters["repeat"]:
        logger.info(x)
        i += 1
    return i, x
In the example above, there is just a single parameter group with only two parameters.  However, an app might have 20 or 30 parameters spread across 5 to 10 parameter groups.  In a situation like that, separating the parameter group code is definitely desirable to increase the readability and maintenance ease for the app.  Moving parameter group definitions to separate files also makes it much easier to reuse them in several different apps.

Update pkg/executable.py

Below is an example of what the same code above will look like after the single General Parameters parameter group is split into two parameter groups and definition for each is replaced by a variables that will be defined in a separate file called models.py.  The variables are then imported using a line that begins with from followed by the file name without extension preceded by a period.  Lines added or changed are highlighted.
import logging

from nomnomdata.engine import Engine
from .models import name_parameters, repeat_parameters

logger = logging.getLogger("engine.hello_world")

engine = Engine(
    uuid="CHANGE-ME-PLEASE",
    alias="Hello World Sample",
    description="Demonstrates basic app structure and functionality.",
    categories=["general"],
)

@engine.action(
    display_name="Hello World",
    description="Prints a greeting multiple times in the Task execution log.",
)
@engine.parameter_group(name_parameters)
@engine.parameter_group(repeat_parameters)
def hello_world(parameters):
    i = 0
    x = f"Hello {parameters.get('name') or 'World'}"
    while i < parameters["repeat"]:
        logger.info(x)
        i += 1
    return i, x
It is important to note that the order in which the parameter groups are listed in the code above is significant.  The name_parameters group is listed before the repeat_parameters group, which will cause it to be rendered after the repeat_parameters group in the Task user interface.  Parameter groups are rendered in the opposite order of how they are listed in the code.

Create models.py

You can create as many separate files for parameter groups that you want and can name each file however you like.  In this example, we will create a single file called models.py with each parameter individually defined and referenced in a defined parameter group.  Below is the content of the file.
from nomnomdata.engine import Parameter, ParameterGroup
from nomnomdata.engine.parameters import Int, String

repeat_param = Parameter(
    type=Int(),
    name="repeat",
    display_name="Repeat",
    description="Specify how many times to print.",
    default=1,
    required=True,
)

name_param = Parameter(
    type=String(),
    name="name",
    display_name="Name",
    description="Specify a name to print instead of World.",
    required=False,
)

repeat_parameters = ParameterGroup(
    repeat_param,
    name="repeat_parameters",
    display_name="Repeat Parameters",
    description="Parameters for Repeating",
)

name_parameters = ParameterGroup(
    name_param,
    name="name_parameters",
    display_name="Name Parameters",
    description="Parameters for Name Replacement",
)
Though this example doesn't demonstrate it, multiple parameters can be included within each parameter group definition and they can be defined inline rather than separately.  Refer to the original pkg/executable.py content for an example of that.
    • Related Articles

    • Creating Your First Nom Nom App

      In this tutorial, we will be examining the contents of the template Nom Nom App generated from the SDK and making it available to Tasks on your Nominode. Prerequisites Python 3.7.4 (or newer) https://www.python.org/downloads/ Docker 19.03 (or newer) ...
    • Testing Your Nom Nom App

      Local Testing For Nom Nom Apps created in Python, we recommend using pytest to locally test the code that you have written.  Follow this link for a general overview on how to install and use pytest.  In this article, we will discuss a few suggestions ...
    • Adding Your Nom Nom App to Our Store

      When you deploy a Nom Nom App that you have created, it is immediately available to be used on all of the Nominodes within your Nom Nom Data organization.  However, if you want to share your Nom Nom App with others outside of your organization, ...
    • Using an External Process in Your Nom Nom App

      This article explains how to leverage an external process from your Nom Nom App.  Specifically it discusses how to use the Scrapy python package.  It is assumed that the reader is already familiar with the information in the Creating Your First Nom ...
    • Reporting and Maintaining Progress in Your Nom Nom App

      This article explains the best practices for reporting Task progress in your Nom Nom App code and for updating a parameter value in a Task from your Nom Nom App code so that you can maintain progress across multiple Task executions.  Specifically it ...