Creating Your First NND App

Creating Your First NND App

In this tutorial, we will be examining the contents of the template NND App generated from the SDK and making it available to Tasks on your Nominode.

Prerequisites

Miniconda 4.8.3 (or newer, Python 3.7 version*)
(*Python 3.7.4 or newer is required.  Miniconda is optional.)

Docker 19.03 (or newer)

Nom Nom Data App SDK 0.15.6 (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 NND App.)

Install the Prerequisites

To create your first NND App, you will need to install Miniconda (which includes Python 3.7), Docker and the NND App SDK.  MacOS, Windows and Linux are all supported operating systems for your development environment.

1.  Install Miniconda.  The exact steps to install and configure Miniconda 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 Data App SDK.  Run this command in a MacOS terminal window or an Ananconda Powershell Prompt:
pip install nomnomdata-tools-engine nomnomdata-engine
                  

Generate and Populate NND App Files

5.  Navigate to the local folder where you want to store NND Apps and execute this command to automatically generate the files needed for your new NND App:
nnd engine-tools create-new tutorial
These files and folders will get created locally on your machine to form the structure of your NND 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 NND 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.
      nomnomdata-engine>=0.5.2

Dockerfile

When you execute the command to deploy your NND 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 NND 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 NND 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:
      CMD python main.py run

main.py

The main.py file is required as the entry point for your NND 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 NND 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 NND 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 NND 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.pngicon-2x.png and icon-3x.png.  Any graphic is fine for the purpose of this tutorial.  When creating a real NND App, these graphics will be the icon that displays everywhere that your NND 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 NND App:
      import logging
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 NND 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 NND App that you are creating.  Add the paths to the image files created in Step 5:
      engine = Engine(
            uuid="YOUR-UNIQUE-STRING",
            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",
            },
      )
This line defines one of the actions that the NND 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 NND App

10.  Execute this command to generate a model.yaml file for your NND App.  The command must be executed from the tutorial folder:
python main.py dump-yaml

11.  Execute this command to log in to your Nom Nom Data account and select the organization that you would like to publish your NND App to:
nnd login
 
12.  Execute this command to make your NND 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 NND App and upload it to our secure repository.  Your NND 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

Detailed SDK documentation is available via the Nom Nom Data Developer Portal.

    • Related Articles

    • Testing Your NND App

      Local Testing For NND 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 NND App to Our Store

      When you deploy an NND App that you have created, it is immediately available to be used on all of the Nominodes within your NND organization.  However, if you want to share your NND App with others outside of your organization, either for free or ...
    • Adding a Connection to Your NND App

      In this tutorial, we will discuss how to add a Connection parameter to the template NND App generated from the SDK and how to use it to connect to Slack.  More information about creating Connections is available in the Managing Connections on a ...
    • Separating UI Code in Your NND App

      This article explains a best practice for moving different portions of your NND 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 ...
    • Using an External Process in Your NND App

      This article explains how to leverage an external process from your NND 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 NND App ...