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)
Docker 19.03 (or newer)
Nom Nom App SDK 1.17.1 (or newer)
Nom Nom Data Account and Nominode Server
(Nom Nom Data Account is required. Nominode Server is optional, but is the only way render the UI for your Nom Nom App.)
Install the Prerequisites
To create your first Nom Nom App, you will need to install Python, Docker and the Nom Nom App SDK. MacOS, Windows and Linux are all supported operating systems for your development environment.
1. Install Python. The exact steps to install and configure Python will differ based your operating system. Detailed instructions for all platforms can be found here:
2. Install Docker. The exact steps to install and configure Docker will differ based your operating system. Detailed instructions for Mac and Windows can be found here:
Detailed instructions for Linux can be found here:
3. Create a new Python virtual environment. This will ensure there are no version requirement conflicts with the libraries installed by our SDK. You can use any method that you prefer to create the virtual environment. If you don't have a preferred method, you can use the venv command in Python 3.x. Detailed instructions for all platforms can be found here:
For example, in a bash shell on Linux, you can run these commands:
python -m venv nomnomdata
source nomnomdata/bin/activate
4. Install the Nom Nom App SDK. Run this command in a MacOS terminal window or a Command Prompt:
pip install nomnomdata-tools-engine nomnomdata-engine
Generate and Populate Nom Nom App Files
5. Navigate to the local folder where you want to store Nom Nom Apps and execute this command to automatically generate the files needed for your new Nom Nom App:
nnd engine-tools create-new tutorial
These files and folders will get created locally on your machine to form the structure of your Nom Nom App:
.
└── tutorial
├── Dockerfile
├── main.py
├── requirements.txt
└── pkg
├── __init__.py
├── executable.py
└── tests
├── __init__.py
└── test_executable.py
At this point, it's helpful to understand how each file is used when your Nom Nom App is deployed to our platform.
requirements.txt
The requirements.txt file will contain a single line referencing the nomnomdata-engine required package, but you will need to update it to contain a list of all of the other python packages and versions used by your code.
Dockerfile
When you execute the command to deploy your Nom Nom App, a docker image will be created locally and then uploaded to our secure repository. When it is triggered from a Task on any Nominode, your Nom Nom App code will run inside a container automatically generated from the image. The Dockerfile file contains the commands used to create the image. This line copies a package installation environment from our repository:
FROM registry.gitlab.com/nomnomdata/tools/nomnomdata-engine:latest as builder
These lines copy your requirements.txt file into the installation environment and use its contents to create a pip wheel for installing the packages and versions specified:
COPY requirements.txt /nomnom/requirements.txt
RUN pip wheel --wheel-dir /python_packages -r /nomnom/requirements.txt
This line creates a new image from a slim environment in our repository:
FROM registry.gitlab.com/nomnomdata/tools/nomnomdata-engine:latest-slim
These lines will use the pip wheel created in the installation environment to install the packages in the image:
COPY --from=builder /python_packages /python_packages
RUN pip install --no-index --find-links /python_packages /python_packages/* \
&& rm -rf /python_packages
These lines copy all of the python code for your Nom Nom App into the image:
WORKDIR /nomnom/
COPY main.py /nomnom/
COPY pkg/*.* /nomnom/pkg/
If you have created any python files outside of the pkg folder, then you will need to add additional COPY lines to ensure those are also included.
This line sets the command that will run your code inside the generated container when it is triggered from a Nominode Task:
main.py
The main.py file is required as the entry point for your Nom Nom App. There is no need to change this file's contents.
pkg/__init__.py
The __init__.py file is required to make Python treat the directory containing it as a package. This file's contents can remain empty.
pkg/executable.py
This file is the heart of your Nom Nom App. It contains the python code that runs when a triggered Nominode Task executes one of the actions defined in it. It also contains code that describes how the new Task interface will present the parameter options for your Nom Nom App. Default code is generated when this file is created to give you a template to follow.
pkg/tests/__init__.py
The __init__.py file is required to make Python treat the directory containing it as a package. This file's contents can remain empty.
pkg/tests/test_executable.py
This file contains python code that can be triggered with pytest to automatically test the execution of the code in your Nom Nom App. Default code is generated when this file is created to give you a template to follow. You have to update it to import and trigger the specific actions you have defined in executable.py.
6. Create a folder named icons under the tutorial folder. Add three graphics files under it named icon-1x.png, icon-2x.png and icon-3x.png. Any graphic is fine for the purpose of this tutorial. When creating a real Nom Nom App, these graphics will be the icon that displays everywhere that your Nom Nom App is listed.
7. Create a folder named help under the tutorial folder. Add a text file under it named help.md. This is a file that contains text in markdown format that will render in the slide out help frame on the Nominode. Paste this text into the file:
# Hello World Sample
Hello World Sample demonstrates basic app structure and functionality.
## Hello World
The Hello World action will cause the words Hello World or Hello 'Name',
where 'Name' is a string specified, to be printed in the Task execution
log the number of times specified.
### Repeat
Enter the number of times that Hello World or Hello <Name> should be printed.
### Name
Enter a name that should be printed after Hello instead of World.
8. The executable.py file contains the python code for this example. We will discuss each portion of it below.
This line imports the class needed to write out execution log entries for the Nominode Task running the actions within the Nom Nom App:
These lines import the classes needed to describe the user interface to present within the Task:
from nomnomdata.engine.components import Engine, Parameter, ParameterGroup
from nomnomdata.engine.parameters import Int, String
This line sets the object used to generate execution log entries:
logger = logging.getLogger("engine.hello_world")
These lines define the unique identifier, the display name, the description and the categories that apply to the Nom Nom App:
engine = Engine(
uuid="CHANGE-ME-PLEASE",
alias="Hello World Sample",
description="Demonstrates basic app structure and functionality.",
categories=["general"],
)
Change the uuid= value to a unique string for the Nom Nom App that you are creating. Add the paths to the image files created in Step 5:
engine = Engine(
uuid="YOUR-UNIQUEID",
alias="Hello World",
description="Demonstrates basic app structure and functionality.",
categories=["general"],
icons={
"1x": "icons/icon-1x.png",
"2x": "icons/icon-2x.png",
"3x": "icons/icon-3x.png",
},
)
The UUID specified should only contain capital letters, numbers, dashes or underscores. It must begin and end with a letter or number and contain at least one dash or underscore. It must be at least 8 characters and should be no more than 20 characters. Specifying a UUID that does not match this criteria will lead to errors or unexpected results. Specifying a UUID that already exists will lead to an access denied error if a different Nom Nom Data account owns it or will overwrite the Nom Nom App defined with that UUID if you own it. So be creative!
This line defines one of the actions that the Nom Nom App can execute:
@engine.action(
display_name="Hello World",
description="Prints a greeting multiple times in the Task execution log.",
)
Add the path to markdown help file created in Step 6:
@engine.action(
display_name="Hello World",
description="Prints a greeting multiple times in the Task execution log.",
help_md_path="help/help.md",
)
These lines describe which parameter options will display, and how they display, for this action in the Task interface on the Nominode:
@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,
),
),
)
The code above will cause the Task options user interface to render like this in the Nominode:
These lines define the code that runs when the action is executed by the Task on the Nominode:
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
9. The test_executable.py file contains the test code for this example. We will discuss each portion of it below.
This line imports the functions from the main executable that you want your test code to execute:
from ..executable import hello_world
These lines define the functions that pytest will execute. Each function name must begin with the word 'test':
def test_hello_world_no_name():
args = {"repeat": 1}
api_calls, results = hello_world(**args)
assert results == (args["repeat"], f"Hello World")
def test_hello_world_with_name():
args = {"repeat": 3, "name": "Joe"}
api_calls, results = hello_world(**args)
assert results == (args["repeat"], f"Hello Joe")
Deploy and Publish Your Nom Nom App
10. Execute this command to generate a model.yaml file for your Nom Nom App. The command must be executed from the tutorial folder:
11. Execute this command to log in to your Nom Nom Data account and select the organization that you would like to publish your Nom Nom App to:
A token will automatically be generated when you log in and it will be valid for 30 days. If you are following these steps multiple times, you only need to do this step if it has been more than 30 days since your last login.
12. Execute this command to make your Nom Nom App available to all of the Nominodes in your organization. The command must be executed from the tutorial folder:
nnd engine-tools model-update -c stable
13. Execute this command to create the local docker image for your Nom Nom App and upload it to our secure repository. Your Nom Nom App will not execute properly without this step. The command must be executed from the tutorial folder:
nnd engine-tools deploy -c stable
If you receive this error after executing the command:
docker.errors.DockerException: Error while fetching server API version:
(2, 'CreateFile', 'The system cannot find the file specified.')
Ensure that Docker Desktop / Docker for Linux has been launched and is running successfully.
On Windows, if you received this error after executing the command:
docker.errors.DockerException: Install pypiwin32 package to enable npipe:// support
Try running this command to resolve the error:
python <path-to-python-installation>\Scripts\pywin32_postinstall.py -install
Developer Portal