6.8 KiB
name, description
| name | description |
|---|---|
| ignition-exchange-conformance | Check whether an Ignition project follows Inductive Automation's Exchange Resources Style Guide before publishing it to the Ignition Exchange — resource namespacing, Perspective/Vision/Python naming, session-property and client-tag prohibitions, database and logger conventions. Use when asked whether a project is Exchange-ready, when reviewing a project intended for the Exchange, or before packaging one for upload. Bundles a stdlib-only checker (exchange_lint.py) with 38 rules traceable to guide sections. Not for converting a project into that shape (use ignition-exchange-convert) or for packaging and upload (use ignition-exchange-publish). |
Ignition Exchange conformance
Tests an Ignition project against the Exchange Resources Style Guide v1.1.0.
Run exchange_lint.py (next to this file) rather than checking by eye — the rules
are numerous, mechanical, and easy to half-apply.
python3 skills/ignition-exchange-conformance/exchange_lint.py /path/to/Project
Stdlib only, Python 3.8+. Accepts a project folder, a folder containing several
projects (a gateway's projects/ directory, an unpacked backup, a repo), or a
project export .zip. Infers the resource name from the namespace the project
already uses — no configuration.
Exit codes: 0 clean · 1 findings · 2 bad invocation.
The one rule that is actually mandatory
The guide states exactly one must:
Views, Styles, Scripts, etc. must all be contained within an appropriately named folder. This allows easy imports into existing projects, where those project resources won't overlap, interfere, or overwrite existing parts of a user's project.
Everything else — every naming convention — the guide explicitly calls optional:
We encourage you to follow the naming conventions outlined here, however these conventions are not required.
So exchange_lint.py reports FAIL only for namespacing, the storage
prohibitions, and the project-name character set. Naming is warn. Don't
report warnings as blockers, and don't contort a project to silence them —
a consistent house style is defensible and the guide says so.
Namespace roots — two spellings, both correct
Per the guide's Project Browser screenshots:
Under Exchange/<ResourceName>/ |
Under exchange/<resource-name>/ |
|---|---|
| Views, Windows, Templates | Style classes |
| Named queries, Reports | Project library (scripts) |
| SFCs, Transaction groups | WebDev sources |
| Alarm pipelines, Tags | Images |
Uppercase roots take Title Case or PascalCase names; lowercase roots take
kebab-case — except the project library, which is code-facing and uses
lowercase or camelCase (exchange.resourceName.scriptName), matching the
logger convention exchange.resourceName.LoggerName.
The storage prohibitions
Both are FAILs because both break a clean import, and both are easy to miss:
- Perspective session custom properties. Importing merges them into the host
project's session props. Use view
params/customplus, for genuinely non-reactive cross-session state,system.util.getGlobals()['exchange']['resourceName']. - Vision client tags. Same reasoning.
What the checker cannot tell you
A clean report is not "ready to publish". Four gaps, all of which have bitten:
- Content. It reads names and structure, never label text. A visible string
like
"Acme Internal — do not distribute"passes silently. Always sweep user-visible strings separately:python3 - <<'PY' import json, glob, re bad = re.compile(r"internal|confidential|do not|contest|demo only|todo|fixme", re.I) for f in glob.glob("<project>/com.inductiveautomation.perspective/views/**/view.json", recursive=True): v = json.load(open(f)) def walk(n): yield n for c in (n.get("children") or []): yield from walk(c) for n in walk(v.get("root") or {}): t = (n.get("props") or {}).get("text") if isinstance(t, str) and bad.search(t): print(f, repr(t)) PY - Referential integrity. It does not check that embedded view paths, style
classes or script calls resolve. See
ignition-exchange-convert. - Runtime. Nothing is executed or rendered. Load it on a gateway.
- The shipped package.
E-UP-DOCSchecks the working directory, not the export zip. Seeignition-exchange-publish.
Findings that need interpretation
E-STYLE-HIER false positives. It decides where a style class belongs by
finding which views reference it, reading only literal props.style.classes
strings. A class name built in a binding —
'exchange/my-resource/priority/' + level.lower() — is invisible, so a shared
class gets reported as single-use. Verify before acting; do not duplicate style
classes to silence it.
E-PAGE-ROOT is not in the guide. It is an added caution: a page mapped to
/ takes over the root URL of any project the resource is imported into. Real
trade-off — a resource with no / page cannot be launched from the gateway's
Perspective project list, only from its full page URL
(/data/perspective/client/<project>/<page>). Flag the trade-off; let the user
decide.
E-PY-VAR volume. A project written in idiomatic snake_case produces
hundreds of warnings, since the guide wants camelCase for variables and
functions (deliberately diverging from PEP-8; UPPER_SNAKE constants are
exempt). Offer --ignore E-PY-VAR,E-PY-FUNC rather than a mass rename, unless
the user wants full conformance.
Useful flags
| Flag | Effect |
|---|---|
--strict |
Warnings become failures |
--ignore E-PY-VAR,E-COMP-NAME |
Suppress rules |
-v |
Every occurrence (default collapses at 8 per rule) |
--json |
Machine-readable, for CI |
--list-rules |
All 38 rules with descriptions |
Reporting results
The summary reads N of 38 rules exercised. Quote it. A project with no
database, tags or named queries legitimately leaves those rules unexercised, and
a narrow pass should never be presented as a broad one.
Self-test
test_exchange_lint.py builds a conforming and a non-conforming project in a
temp dir, asserts the checker is silent on the first and fires the expected rule
id on the second, and asserts every declared rule is reachable in the source.
Run it after changing any rule.
python3 skills/ignition-exchange-conformance/test_exchange_lint.py
Provenance
Rules derived from Exchange Resources Style Guide v1.1.0. Checker exercised
against four real Perspective projects and validated on Ignition 8.1.20 and
8.3.7 gateways (2026-09-15). Where a rule is an inference rather than guide
text it says so in its description — currently only E-PAGE-ROOT.