# Running mypy or other static type-checking on Ignition Jython scripts

**URL:** <https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799>\
**Category:** Ignition\
**Tags:** scripting\
**Created:** [June 15, 2022, 4:12pm UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799 "2022-06-15T16:12:53Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![justin.brzozoski](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justin.brzozoski/32/13452_2.png) [@justin.brzozoski](https://forum.inductiveautomation.com/u/justin.brzozoski)\
**Post date:** [June 15, 2022, 4:12pm UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/1 "2022-06-15T16:12:53Z")

</div>

On Python projects unrelated to Ignition, I’ve been starting to use type annotations and static type checking tools like [mypy](http://mypy-lang.org/). I find the type annotations very helpful as reminders of what function parameters are supposed to be, and mypy helps find corner cases that would’ve lead to exceptions.

If you’ve never seen type annotations in Python, the mypy cheat sheets are the simplest demonstration and practical explanation I’ve found. Annotations used to be stored as comments in [Python2](https://mypy.readthedocs.io/en/stable/cheat_sheet.html), but Python3 made it [part of the language](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html). Reading the official [Python PEP on typing](https://peps.python.org/pep-0483/) is a steep learning curve, but does cover more difficult concepts.

Coincidentally, I was trying to setup @thecesrom.git’s excellent `ignition-api` library in my editing environment, and noticed it had annotations for everything it stubbed.

For better or worse, I decided to try annotating and type-checking some of my Ignition scripts. Yeah, I knew that the Jython environment, Java libraries, and wonky namespace setup were going to make it all likely to fail, but that’s half the fun.

I setup a Python2.7 virtualenv, loaded it with ignition-api and the modules needed for mypy to run, and then pointed mypy at a code.py file I had annotated. I had to add a lot of imports at the beginning for everything in `system.*`, all the other script libraries from my Ignition project, and `typing` to make mypy happy. It still complained a lot about unknown libraries, but mostly worked.

The biggest sticking points to using this on a regular basis is that I can’t leave all those `import` lines that mypy wants to see in the script file without messing up Ignition, and I don’t have any sane way for mypy to understand script libraries importing each other. I’ve been pondering making some sort of utility that scans a project directory and copy/renames all of the files out into normal Python module hierarchy filenames and pre-pends the hidden `import` lines to the front of the scripts, but that’s a heck of a lot of work…

I also noticed that both ignition-api and mypy try to bring in slightly different libraries named `typing`. I can’t remember how I resolved that in my virtualenv, but I got around it somehow…

Has anyone else ever played with this and gotten anywhere? Do you have any tricks for running mypy easily without pre-processing the Ignition script files every time?

This whole experiment has convinced me to start annotating all of my Ignition scripts, even if I can’t run mypy, because I found myself instinctively reading the hints to understand functions. Plus, if I keep annotating things, it’ll be less work if I ever find a way to easily run mypy.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [June 15, 2022, 5:50pm UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/2 "2022-06-15T17:50:38Z")

</div>

No thoughts but this is the biggest thing I miss when I am coding with python 3 and can set up typing versus moving to Ignition. I would love to be able to do what you are saying.

Personally right now I still rely completely on documentation to keep track of it

```auto
def doSomething(someParam, someOtherParam):
    """
    Does something
    Args:
        someParam: int, representings something of importance
        someOtherParam: str, something else
    Returns:
        DataSet, data relating to something
    """
    pass

```

Please add this to the wishlist IA!

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [June 15, 2022, 6:35pm UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/3 "2022-06-15T18:35:51Z")

</div>

Parsing type hints would _definitely_ be cool for autocompletion. Running `mypy` directly is probably not in the cards. I wonder if you could do something with ` __init__.py` to make external checkers happy? I assume mypy complains about the `system` functions and any Java calls you make?

---

<div class="post-metadata">

**Author:** ![justin.brzozoski](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justin.brzozoski/32/13452_2.png) [@justin.brzozoski](https://forum.inductiveautomation.com/u/justin.brzozoski)\
**Post date:** [June 15, 2022, 7:28pm UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/4 "2022-06-15T19:28:18Z")

</div>

Yes, mypy initially complained that I never imported anything from system or my script libraries.

I already had `import java.xxx` lines so mypy knew that they existed even though it couldn’t type check them. It’s possible some other Jython user out there has made stubs for all the Java libraries; I haven’t gone looking.

But let’s suppose I had these files:

```auto
my_project/ignition/script-python/foo/code.py
my_project/ignition/script-python/bar/code.py

```

If `bar` uses things from both `system` and `foo`, I would need to add to the top of `bar/code.py` something like this before running mypy on it to get rid of the worst errors:

```auto
import system
import system.util
import system.dataset
import system.tag
import foo

```

At this point, mypy can find and type-check `system` functions thanks to thecesrom’s stub library, and it agrees that `foo` at least exists, but it has no idea where to find `foo` to type-check things used from that scope.

Being able to type-check between my own script libraries would be one of the things that would make mypy worth the effort to me, but is also looking like one of the harder bits to get working.

---

<div class="post-metadata">

**Author:** ![thecesrom.git](https://avatars.discourse-cdn.com/v4/letter/t/dfb087/32.png) [@thecesrom.git](https://forum.inductiveautomation.com/u/thecesrom.git)\
**Post date:** [June 21, 2022, 1:37am UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/5 "2022-06-21T01:37:31Z")

</div>

> [@justin.brzozoski](#):
>
> I also noticed that both ignition-api and mypy try to bring in slightly different libraries named `typing`. I can’t remember how I resolved that in my virtualenv, but I got around it somehow…

Hello there, @justin.brzozoski.

Probably this may sound odd, but after some packages like `black` dropped support for Python 2 I decided to use Python 3 packages for code quality, including `mypy`.

For `mypy` in install the `[python2]` extras, and starting with version `8.1.18` I include `types-enum34`, as I am using the `enum34` package for declaring `Enum`s under `system.bacnet`.

As seen on my CI file:

> <https://github.com/ignition-api/8.1/blob/main/.github/workflows/ci.yml#L19-L20>

As for `pre-commit` and all of the libraries I use for code quality, I install them using Python 3, via [`pipx`](https://pypa.github.io/pipx/). (See: [.pre-commit-config.yaml](https://github.com/ignition-api/8.1/blob/main/.pre-commit-config.yaml)).

Finally, if you want to include `typing` in Ignition, you must install that under `$IGNITION_DIR/user-lib/pylib` as it is not a standard package for Python 2. Which makes it a bit problematic if one were to forget that.

I can get away with adding type hints to all `system` functions for `ignition-api`, but I have not done it on any of my Ignition projects. For that, I rely on PyCharm's code analysis which warns about passing the wrong type.

Thanks for installing `ignition-api`!

---

<div class="post-metadata">

**Author:** ![thecesrom.git](https://avatars.discourse-cdn.com/v4/letter/t/dfb087/32.png) [@thecesrom.git](https://forum.inductiveautomation.com/u/thecesrom.git)\
**Post date:** [June 21, 2022, 2:03am UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/6 "2022-06-21T02:03:56Z")

</div>

Furthermore, I can run sort-all, black, isort, and everything that pre-commit executes against code under `$IGNITION_DIR/data/projects/<project>`.

But I would expect `mypy` to fail caused by the way Ignition stores Python code by creating a `code.py`. Which will break any import statement as `mypy` won’t be able to find the referenced module.

I typically create a pure scripting project in PyCharm or vscode and copy/paste my code manually.

---

<div class="post-metadata">

**Author:** ![thecesrom.git](https://avatars.discourse-cdn.com/v4/letter/t/dfb087/32.png) [@thecesrom.git](https://forum.inductiveautomation.com/u/thecesrom.git)\
**Post date:** [June 24, 2022, 1:34am UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/7 "2022-06-24T01:34:24Z")

</div>

I have an update which may be helpful.

After I had to install `types-enum34` for `mypy`, it gave me the idea that I could create actual stub files (`*.pyi`) for `ignition-api`. So after a quick search, I learned that `mypy` comes with a tool called [`stubgen`](https://mypy.readthedocs.io/en/stable/stubgen.html#stubgen) which will generate the necessary files for running `mypy` against your project.

I was able to generate the stub files for `ignition-api/8.1`, and after I fixed all `from _typeshed import Incomplete` imports and references, I was able to check one of my personal projects ([`incendium`](https://github.com/thecesrom/incendium)).

Here are the steps to get you going:

1. Clone `ignition-api/8.1`
2. Switch to the `8.1` directory
3. Run `stubgen src`
  - This will create a directory called named `out`; this is where all the stub files are located

4. Fix all `Incomplete` imports and references; I replaced that import with `from typing import Any`
5. On your Terminal run:

```nohighlight
export MYPYPATH=path/to/ignition-api/8.1/out

```

6. Now you’ll be able to run `mypy` against your own scripting project

Happy coding!

---

<div class="post-metadata">

**Author:** ![cesrom](https://avatars.discourse-cdn.com/v4/letter/c/ea666f/32.png) [@cesrom](https://forum.inductiveautomation.com/u/cesrom)\
**Post date:** [June 29, 2022, 5:34pm UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/8 "2022-06-29T17:34:22Z")

</div>

Replying to my doppelgänger so it can reply with one very important announcement.

---

<div class="post-metadata">

**Author:** ![thecesrom.git](https://avatars.discourse-cdn.com/v4/letter/t/dfb087/32.png) [@thecesrom.git](https://forum.inductiveautomation.com/u/thecesrom.git)\
**Post date:** [June 29, 2022, 5:34pm UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/9 "2022-06-29T17:34:35Z")

</div>

One more update.

After I followed my own instructions `mypy` still reported some errors when checking `incendium`, so I decided to fix them and after a couple of days I was able to create a stubs package. So I present to the world the `ignition-api-stubs` package exclusively for checking your Ignition scripting projects with `mypy[python2]`.

> **[GitHub - ignition-devs/ignition-api-8.1-stubs: 📦 Collection of stubs for ignition-api-8.1](https://github.com/ignition-devs/ignition-api-8.1-stubs)**
>
> 📦 Collection of stubs for ignition-api-8.1

## Installation

Requirements:

- Python 3.6+
- You have added [type hints](https://mypy.readthedocs.io/en/stable/cheat_sheet.html) to your scripting project

NOTE: I strongly recommend creating a virtual environment.

Command:

```sh
python3 -m pip install ignition-api-stubs

```

## Usage

```sh
$ cd <to-your-scripting-project>
$ mypy --py2 <source-directory>

```

I've added type hints to my `incendium` project, and I was able to run `mypy` successfully.

```sh
$ cd incendium
$ python3 -m pip install ignition-api-stubs
$ mypy --py2 src
Success: no issues found in 14 source files

```

## Conclusion

This package is currently in Alpha, so expect errors. But most importantly, please report them [here](https://github.com/ignition-api/stubs/issues) following our [guidelines](https://github.com/ignition-api/.github/blob/main/CONTRIBUTING.md#found-a-bug).

Hopefully some of you may find it useful.

Happy coding!

---

<div class="post-metadata">

**Author:** ![Jackson\_Lancaster](https://avatars.discourse-cdn.com/v4/letter/j/ebca7d/32.png) [@Jackson\_Lancaster](https://forum.inductiveautomation.com/u/Jackson_Lancaster)\
**Post date:** [May 7, 2025, 8:49pm UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/10 "2025-05-07T20:49:05Z")

</div>

what sub version of python3 and mypy are you running?

---

<div class="post-metadata">

**Author:** ![cesarcoatl](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cesarcoatl/32/84168_2.png) [@cesarcoatl](https://forum.inductiveautomation.com/u/cesarcoatl)\
**Post date:** [May 9, 2025, 7:18am UTC](https://forum.inductiveautomation.com/t/running-mypy-or-other-static-type-checking-on-ignition-jython-scripts/60799/11 "2025-05-09T07:18:21Z")

</div>

I am using Python 3.12 and `mypy[python2]==0.971`.

I explain it in more detail here:

> **[Python 3 tools I use for my Python 2 projects - 2024 edition](https://cesar.coatl.dev/2024/03/01/python-3-tools-i-use-for-my-python-2-projects-2024-edition/#which-python-3)**
>
> Fighting to keep Python 2 alive
