Python API

The pdk package can be used as a library, for example to validate views from another tool or a CI pipeline. This reference is generated from the docstrings in the source code. The command line and the MCP server are the supported interfaces; the Python API may change between minor versions until 1.0.

Example: validate a view from Python.

from pathlib import Path

from pdk.bundle import load_bundle
from pdk.diagnostics import render
from pdk.validate import validate_file

result = validate_file(Path("view.json"), load_bundle())
print(render(result.diagnostics, title="view.json"))
errors = [d for d in result.diagnostics if d["severity"] == "error"]

Validation

Validate raw view.json against the exact schemas of the installed Perspective version.

class pdk.validate.FileResult(path: 'Path', diagnostics: 'list[Diagnostic]', project: 'Project | None' = None, view_path: 'str | None' = None)[source]
Parameters:
  • path (Path)

  • diagnostics (list[Diagnostic])

  • project (Project | None)

  • view_path (str | None)

pdk.validate.validate_text(text, bundle, *, project=None, view_path=None, profile=None, compiler=None)[source]

With compiler (pdk.sync.compiler: the gateway’s Jython), a view without errors also gets its scripts compiled.

Parameters:
  • text (str)

  • bundle (Bundle)

  • project (Project | None)

  • view_path (str | None)

  • profile (str | None)

  • compiler (Callable[[str], list[Diagnostic]] | None)

Return type:

list[Diagnostic]

Diagnostics: the stable code table, construction, ordering and budgeted rendering.

class pdk.diagnostics.Diagnostic[source]
pdk.diagnostics.ordered(diagnostics)[source]

Deduplicate and order: severity, then document position, then code.

Parameters:

diagnostics (list[Diagnostic])

Return type:

list[Diagnostic]

pdk.diagnostics.render(diagnostics, *, title, budget=DEFAULT_BUDGET, focus=None)[source]

Compact, budgeted text for agents. focus expands matching diagnostics with their detail.

Parameters:
  • diagnostics (list[Diagnostic])

  • title (str)

  • budget (int)

  • focus (str | None)

Return type:

str

Schema bundle: extraction from the installed Perspective module and loading for validation.

A bundle is a verbatim copy of the JSON resources Perspective itself ships (component descriptors, schemas/, the Designer’s DOM event list) plus a manifest. It lives under schemas/<perspective-version>/ and is not versioned: regenerate it with pdk schemas extract.

exception pdk.bundle.BundleError[source]

The schema bundle is missing, incomplete or cannot be extracted.

pdk.bundle.extract_bundle(modl_path, out_root, ignition_home=None)[source]

Copy Perspective’s schema resources from modl_path into out_root/<version>/.

Parameters:
  • modl_path (Path)

  • out_root (Path)

  • ignition_home (Path | None)

Return type:

Path

class pdk.bundle.Component(id: 'str', name: 'str', category: 'str', tooltip: 'str', schema: 'dict[str, Any]', child_position_schema: 'dict[str, Any] | None', events: 'dict[str, dict[str, Any]]', deprecated: 'bool', default_meta_name: 'str | None', library: 'str', variants: 'tuple[dict[str, Any], ...]' = (), extension_functions: 'dict[str, dict[str, Any]]' = <factory>)[source]
Parameters:
  • id (str)

  • name (str)

  • category (str)

  • tooltip (str)

  • schema (dict[str, Any])

  • child_position_schema (dict[str, Any] | None)

  • events (dict[str, dict[str, Any]])

  • deprecated (bool)

  • default_meta_name (str | None)

  • library (str)

  • variants (tuple[dict[str, Any], ...])

  • extension_functions (dict[str, dict[str, Any]])

pdk.bundle.is_typed_value(value, tag=None)[source]

Ignition’s typed JSON encoding, e.g. a Date: {“$”: [“ts”, 0, 1757428595830], “$ts”: 1757428589273}.

Parameters:
  • value (Any)

  • tag (str | None)

Return type:

bool

class pdk.bundle.Functions(expression, script, ignition=None)[source]

What code may call, as read from a running gateway (pdk schemas functions): expression functions by lower-case name, and the names under system.* (functions and the modules on the way to them).

Parameters:
  • expression (dict[str, str])

  • script (frozenset[str])

  • ignition (str | None)

pdk.bundle.load_functions(base)[source]

The functions.json next to a bundle, or None (offline checks of function names are then skipped).

Parameters:

base (Path)

Return type:

Functions | None

pdk.bundle.save_functions(base, listing, ignition)[source]

Write the gateway’s /functions listing next to the bundle.

Parameters:
  • base (Path)

  • listing (dict[str, Any])

  • ignition (str | None)

Return type:

Path

class pdk.bundle.Bundle(version: 'str', root: 'Path', manifest: 'dict[str, Any]', components: 'dict[str, Component]', schemas: 'dict[str, dict[str, Any]]', dom_events: 'dict[str, str]', registry: 'Registry', validator_class: 'type[Validator]' = <class 'jsonschema.validators.Draft4Validator'>, functions: 'Functions | None' = None, _validators: 'dict[int, Validator]'=<factory>)[source]
Parameters:
  • version (str)

  • root (Path)

  • manifest (dict[str, Any])

  • components (dict[str, Component])

  • schemas (dict[str, dict[str, Any]])

  • dom_events (dict[str, str])

  • registry (Registry)

  • validator_class (type[Validator])

  • functions (Functions | None)

  • _validators (dict[int, Validator])

schema(name)[source]

A schema by file name, e.g. meta-schema.json.

Parameters:

name (str)

Return type:

dict[str, Any]

Catalog: compact, budgeted answers about components, props, bindings and events, from the exact schemas.

pdk.catalog.find_component(bundle, name)[source]

By id (ia.display.label), short id (label, display.label), display name (Label), or the start of a short id or display name when only one component has it (numeric entry -> ia.input.numeric-entry-field).

Parameters:
Return type:

Component | None

Read-only view of an Ignition project directory: views, their params and style classes.

class pdk.project.ViewParam(name: 'str', direction: 'str', default: 'Any')[source]
Parameters:
  • name (str)

  • direction (str)

  • default (Any)

class pdk.project.Project(root: 'Path', parent: 'Project | None' = None, _views: 'dict[str, Path] | None'=None, _params: 'dict[str, dict[str, ViewParam]]'=<factory>, _stylesheet_classes: 'set[str] | None' = None, _named_queries: 'list[str] | None' = None)[source]
Parameters:
  • root (Path)

  • parent (Project | None)

  • _views (dict[str, Path] | None)

  • _params (dict[str, dict[str, ViewParam]])

  • _stylesheet_classes (set[str] | None)

  • _named_queries (list[str] | None)

named_queries()[source]

Named query paths (Folder/Name) of this project and its parents: each ignition/named-query/<path>/query.sql.

Return type:

list[str]

pdk.project.open_project(spec)[source]

A project directory, or the name of a project on the local gateway.

Parameters:

spec (str)

Return type:

Project

pdk.project.locate(view_file)[source]

Project and view path for a view.json stored inside a project tree.

Parameters:

view_file (Path)

Return type:

tuple[Project, str] | None

Gateway

Client for the pdk-gateway module: loopback HTTP plus the token the module writes on every startup.

exception pdk.gateway.client.GatewayError(code, message, *, status=None, payload=None)[source]

A failed call to the module, with a stable G-code, a hint and the module’s JSON payload.

Parameters:
  • code (str)

  • message (str)

  • status (int | None)

  • payload (dict[str, Any] | None)

pdk.gateway.client.read_token(ignition_home=None)[source]

The current token: PDK_GATEWAY_TOKEN, else the file the module rewrites on every startup.

Parameters:

ignition_home (Path | None)

Return type:

str | None

pdk.gateway.client.read_token_file(ignition_home=None)[source]

The token the module wrote on its last startup, ignoring PDK_GATEWAY_TOKEN.

Parameters:

ignition_home (Path | None)

Return type:

str | None

pdk.gateway.client.unwrap_arrays(node)[source]

Module builds before 2026-10-05 leave qualified arrays as {“$a”: […]} and their quality paths as x.$a[i].

Parameters:

node (Any)

Return type:

Any

class pdk.gateway.client.Gateway(url: 'str' = <factory>, token: 'str | None' = None, timeout: 'float' = 30.0)[source]
Parameters:
  • url (str)

  • token (str | None)

  • timeout (float)

health(refresh=False)[source]

The module’s /health, asked once per instance unless refresh is set.

Parameters:

refresh (bool)

Return type:

dict[str, Any]

resource(project, type_key, path='')[source]

A resource with its files and signature, or the listing of a folder.

Parameters:
  • project (str)

  • type_key (str)

  • path (str)

Return type:

dict[str, Any]

put_resource(project, type_key, path, files, signature=None, scope=None)[source]

Create (signature None) or modify (the signature you read). A stale signature raises G008.

Parameters:
  • project (str)

  • type_key (str)

  • path (str)

  • files (dict[str, str])

  • signature (str | None)

  • scope (str | None)

Return type:

dict[str, Any]

scan()[source]

Make the gateway re-read project files changed on disk.

Return type:

dict[str, Any]

changes(since=0, limit=200)[source]

Sandbox resource changes after sequence since, each with origin pdk or external.

Parameters:
  • since (int)

  • limit (int)

Return type:

dict[str, Any]

catalog(full=False)[source]

Components registered in the gateway; full adds schemas, events and palette.

Parameters:

full (bool)

Return type:

dict[str, Any]

sessions(project)[source]

Client sessions of a project, with their pages and the view instances on each.

Parameters:

project (str)

Return type:

dict[str, Any]

close_session(project, page_id)[source]

Close the sandbox session that owns a page, so it does not hold a session slot until it times out.

Parameters:
  • project (str)

  • page_id (str)

Return type:

dict[str, Any]

functions()[source]

Expression functions ({name, category}) and system.* scripting names registered on the gateway.

Return type:

dict[str, Any]

compile_scripts(sources)[source]

[{id, code}] compiled (never run) with the gateway’s Jython: [{id, ok, line?, column?, message?}].

Parameters:

sources (list[dict[str, str]])

Return type:

list[dict[str, Any]]

page(project, page_id)[source]

The evaluated tree of every view on a page: plain values, non-Good qualities and configured bindings.

Parameters:
  • project (str)

  • page_id (str)

Return type:

dict[str, Any]

logs(since=0, limit=200, project=None, view=None)[source]

WARN/ERROR gateway log events after since, filtered by project and view (resource path) via the MDC.

Parameters:
  • since (int)

  • limit (int)

  • project (str | None)

  • view (str | None)

Return type:

dict[str, Any]

tags(path=None, depth=1)[source]

Nodes under a tag folder (any provider), flat, with data type, value and quality.

Parameters:
  • path (str | None)

  • depth (int)

Return type:

dict[str, Any]

read_tags(paths)[source]

Value, quality and timestamp of each tag path (any provider).

Parameters:

paths (list[str])

Return type:

dict[str, Any]

write_tags(writes)[source]

[{“path”, “value”, “quality”?}] under PDK/: the write result and the read-back of each.

Parameters:

writes (list[dict[str, Any]])

Return type:

dict[str, Any]

import_tags(path, tags)[source]

Tag export JSON (folders and memory tags) into a folder under PDK/, overwriting what is there.

Parameters:
  • path (str)

  • tags (dict[str, Any])

Return type:

dict[str, Any]

alarms(path=None)[source]

Alarm events of the tags at or under a path (default PDK/).

Parameters:

path (str | None)

Return type:

dict[str, Any]

history_providers()[source]

The gateway’s tag history providers.

Return type:

list[str]

store_history(provider, points)[source]

[{path, value, timestamp (ms), quality?}] of tags under PDK/ into a history provider.

Parameters:
  • provider (str)

  • points (list[dict[str, Any]])

Return type:

dict[str, Any]

acknowledge_alarms(path)[source]

Acknowledge the unacknowledged alarm events of the tags under a path in PDK/.

Parameters:

path (str)

Return type:

dict[str, Any]

Build, install and restart the pdk-gateway module.

The build runs javac –release 17 from any JDK >= 17 against the jars of the installed gateway, so the module links against exactly the Ignition and Perspective it runs on, without Gradle. Installing and restarting go through the gateway’s own REST API with an Ignition API key that has the Gateway Write permission.

exception pdk.gateway.module.ModuleError[source]

The module cannot be built, installed or restarted.

class pdk.gateway.module.BuildResult(modl: 'Path', version: 'str', classes: 'int')[source]
Parameters:
  • modl (Path)

  • version (str)

  • classes (int)

pdk.gateway.module.module_version(now=None)[source]

<pdk version>.<yyDDDHHmm>: the build number grows with every build and fits Ignition’s int.

A version between releases (0.2.1.dev3+g1a2b3c4) keeps only its X.Y.Z.

Parameters:

now (datetime | None)

Return type:

str

pdk.gateway.module.find_javac()[source]

A javac from a JDK >= 17: JAVA_HOME, then PATH, then the usual install folders.

Return type:

Path

pdk.gateway.module.compile_classpath(ignition_home, cache)[source]

The installed platform jars plus Perspective’s jars, unpacked from its .modl into cache.

Parameters:
  • ignition_home (Path)

  • cache (Path)

Return type:

list[Path]

pdk.gateway.module.argfile_text(args)[source]

javac @file syntax: one quoted argument per line (paths already use forward slashes).

Parameters:

args (Sequence[str])

Return type:

str

pdk.gateway.module.build(ignition_home=None, out_dir=BUILD_DIR, now=None)[source]

Compile gateway/src/main/java and package an unsigned .modl in out_dir.

Parameters:
  • ignition_home (Path | None)

  • out_dir (Path)

  • now (datetime | None)

Return type:

BuildResult

pdk.gateway.module.install(modl, base=None)[source]

Upload and install the module. It loads on the next gateway restart (8.3 has no hot reload).

Parameters:
  • modl (Path)

  • base (str | None)

Return type:

dict[str, Any]

pdk.gateway.module.accept_certificate(base=None, key=None)[source]

Accept the (empty) certificate of the unsigned module after every upload.

Each upload clears the acceptance; without it the next start stops at commissioning and quarantines the module. Needs -Dignition.allowunsignedmodules=true, otherwise the gateway refuses unsigned modules.

Parameters:
  • base (str | None)

  • key (str | None)

Return type:

None

pdk.gateway.module.gateway_state(base, timeout=5)[source]

RUNNING, STARTING…, or COMMISSIONING when the gateway waits for someone to accept a new module.

Parameters:
  • base (str)

  • timeout (float)

Return type:

str | None

pdk.gateway.module.restart(base=None, timeout=300, poll=2.0)[source]

Restart the gateway, wait for RUNNING, then for the module’s /health with its new token.

Parameters:
  • base (str | None)

  • timeout (float)

  • poll (float)

Return type:

dict[str, Any]

Pull, deploy, promote and delete views through the pdk-gateway module.

A pulled view lives in work/<project>/<view path>/view.json, next to a .pdk-base.json sidecar with the signature it was read at and its text. Every write sends that signature: if the view changed on the gateway since (a Designer save, another agent), the module answers 409 and nothing is written. The 409 is reported as a diff by JSON pointer — what changed on the gateway since the pull and what you changed — and the gateway version is saved as view.gateway.json to merge from. –resolved then writes over that newer version.

Agent work lives under PDK/ in the sandbox; promote copies PDK/X to X in the same project, signed the same way, or to the target project (-Dpdk.target), which takes finished views only: no PDK/, no preview page. Every deployed view gets a page at /pdk/<view path> in page-config, so it can be opened in a browser; page-config is edited additively with its own signature and re-read on a 409.

class pdk.sync.Outcome(ok: 'bool', text: 'str')[source]
Parameters:
  • ok (bool)

  • text (str)

pdk.sync.pull(gateway, path, project=None, *, force=False, root=None)[source]

Download a view, or every view below a folder, with its signature. path may be a local copy.

Parameters:
  • gateway (Gateway)

  • path (str)

  • project (str | None)

  • force (bool)

  • root (Path | None)

Return type:

Outcome

pdk.sync.deploy(gateway, location, bundle, *, resolved=False, root=None, budget=DEFAULT_BUDGET, _promoting=False)[source]

Validate the local view.json and write it with the signature of the pull (create if never pulled).

The target project only gets views through promote, and never a preview page. The stylesheet goes to pdk.stylesheet.

Parameters:
  • gateway (Gateway)

  • location (Path)

  • bundle (Bundle)

  • resolved (bool)

  • root (Path | None)

  • budget (int)

  • _promoting (bool)

Return type:

Outcome

pdk.sync.compiled(gateway, text, *, strict=False)[source]

E009 for the scripts of a view that the gateway’s Jython does not compile. Without strict, nothing when the gateway cannot compile (an older module without the route); with it, that GatewayError propagates.

Parameters:
  • gateway (Gateway)

  • text (str)

  • strict (bool)

Return type:

list[Diagnostic]

pdk.sync.compiler(gateway)[source]

For validate’s compiler: the scripts of a view compiled by the gateway (GatewayError if it cannot).

Parameters:

gateway (Gateway)

Return type:

Callable[[str], list[Diagnostic]]

pdk.sync.promote(gateway, location, bundle, *, to=None, to_project=None, resolved=False, root=None, budget=DEFAULT_BUDGET)[source]

Copy a deployed sandbox view PDK/X to X (or to) in the same project, with the target’s signature.

With to_project (“target” or its name) the copy goes to the target project instead; there it may not reference PDK/ views, and views it references that the target lacks are reported.

The target’s own sidecar holds the signature it was promoted or pulled at: a target someone edited since gives the usual 409; a target that exists but was never pulled gives a create conflict.

Parameters:
  • gateway (Gateway)

  • location (Path)

  • bundle (Bundle)

  • to (str | None)

  • to_project (str | None)

  • resolved (bool)

  • root (Path | None)

  • budget (int)

Return type:

Outcome

pdk.sync.delete(gateway, location, *, resolved=False, root=None, budget=DEFAULT_BUDGET)[source]

Delete a pulled view on the gateway, only if it is still the version you pulled.

Parameters:
  • gateway (Gateway)

  • location (Path)

  • resolved (bool)

  • root (Path | None)

  • budget (int)

Return type:

Outcome

pdk.sync.page_url(view_path)[source]

The preview page of a view: /pdk/<view path>, blanks turned into dashes.

Parameters:

view_path (str)

Return type:

str

pdk.sync.ensure_preview(gateway, project, view_path)[source]

Map /pdk/<view path> to the view in page-config; a warning if it cannot.

Parameters:
  • gateway (Gateway)

  • project (str)

  • view_path (str)

Return type:

str | None

pdk.sync.json_diff(a, b, pointer='')[source]

(pointer, old, new) for every leaf that differs; MISSING marks an added or removed member.

Parameters:
  • a (Any)

  • b (Any)

  • pointer (str)

Return type:

list[tuple[str, Any, Any]]

pdk.sync.overlapping(theirs, mine, theirs_doc, mine_doc)[source]

Pointers both sides changed (one inside the other) to different results.

Parameters:
  • theirs (list[tuple[str, Any, Any]])

  • mine (list[tuple[str, Any, Any]])

  • theirs_doc (Any)

  • mine_doc (Any)

Return type:

list[str]

pdk.sync.diff_section(title, changes, before, after)[source]

One line per change, with the component it falls in (named from the side where it exists).

Parameters:
  • title (str)

  • changes (list[tuple[str, Any, Any]])

  • before (Any)

  • after (Any)

Return type:

str

Pull, deploy and delete the project stylesheet through the pdk-gateway module.

On the gateway it is a singleton resource (type com.inductiveautomation.perspective/stylesheet, path “”, one file stylesheet.css). Locally it lives in work/<project>/_stylesheet/stylesheet.css next to the same .pdk-base.json sidecar views use: every write sends the signature of the pull, and a 409 saves the gateway version as stylesheet.gateway.css and reports a unified diff. It is edited in the sandbox; the target project (-Dpdk.target) takes it only through promote –to-project.

pdk.stylesheet.is_stylesheet(location)[source]

A stylesheet.css, its _stylesheet folder, or any folder whose sidecar says so.

Parameters:

location (Path)

Return type:

bool

pdk.stylesheet.check_css(text)[source]

Syntax problems that break a stylesheet: unterminated comment or string, unbalanced braces.

Parameters:

text (str)

Return type:

list[str]

pdk.stylesheet.pull(gateway, project=None, *, force=False, root=None, path=None)[source]

Download the stylesheet with its signature. path may be a local copy, which names the project.

Parameters:
  • gateway (Gateway)

  • project (str | None)

  • force (bool)

  • root (Path | None)

  • path (str | None)

Return type:

Outcome

pdk.stylesheet.deploy(gateway, location, *, resolved=False, root=None, budget=DEFAULT_BUDGET, _promoting=False)[source]

Check the local stylesheet.css and write it with the signature of the pull (create if never pulled).

Parameters:
  • gateway (Gateway)

  • location (Path)

  • resolved (bool)

  • root (Path | None)

  • budget (int)

  • _promoting (bool)

Return type:

Outcome

pdk.stylesheet.promote(gateway, location, *, to_project=None, resolved=False, root=None, budget=DEFAULT_BUDGET)[source]

Copy the deployed sandbox stylesheet to the target project, with the target’s own signature.

Parameters:
  • gateway (Gateway)

  • location (Path)

  • to_project (str | None)

  • resolved (bool)

  • root (Path | None)

  • budget (int)

Return type:

Outcome

pdk.stylesheet.delete(gateway, location, *, resolved=False, root=None, budget=DEFAULT_BUDGET)[source]

Delete the stylesheet on the gateway, only if it is still the version you pulled.

Parameters:
  • gateway (Gateway)

  • location (Path)

  • resolved (bool)

  • root (Path | None)

  • budget (int)

Return type:

Outcome

Simulated tags (F5 part B): memory tags under [provider]PDK/ of the development gateway.

The module imports Ignition’s own tag export JSON (folders, memory tags, UDT definitions under _types_/PDK/ with memory members and instances of them), writes values with a quality and reads them back, lists the alarm events of those tags, and stores synthetic history points for them. Paths without [provider] hang from PDK/: Sandbox/Setpoint is [default]PDK/Sandbox/Setpoint; _types_/PDK/… is where UDT definitions go. Reads take any path; writes only PDK/ and _types_/PDK/ (G013).

pdk.tags.full_path(path)[source]

Sandbox/Setpoint -> PDK/Sandbox/Setpoint; paths with [provider] or already under PDK/ stay as they are.

Parameters:

path (str)

Return type:

str

pdk.tags.parse_value(raw)[source]

A written or expected value: JSON numbers, true/false and null; anything else is a string.

Parameters:

raw (str)

Return type:

Any

pdk.tags.matches(actual, raw)[source]

A read value against the expected text: numbers within float precision, else equal as text.

Parameters:
  • actual (Any)

  • raw (str)

Return type:

bool

pdk.tags.write(gateway, path, raw, quality=None)[source]

Write one tag (raw None keeps its current value, to change only the quality); raises ValueError with the reason when the gateway does not take it.

Parameters:
  • gateway (Gateway)

  • path (str)

  • raw (str | None)

  • quality (str | None)

Return type:

dict[str, Any]

class pdk.tags.Probe(gateway)[source]

Tag reads for expectations, cached for one inspect.

Parameters:

gateway (Gateway)

pdk.tags.apply(gateway, file, to=FOLDER)[source]

Import a tag export JSON file into to (under PDK/): tags are created, or overwritten with their declared values, and their alarm events acknowledged, which resets them between runs.

Parameters:
  • gateway (Gateway)

  • file (Path)

  • to (str)

Return type:

str

pdk.tags.duration_ms(text)[source]

500ms, 30s, 1m, 2h, 1d (a bare number is seconds) in milliseconds.

Parameters:

text (str)

Return type:

int

pdk.tags.history(gateway, path, values, *, every='1m', provider=None, quality=None, end_ms=None)[source]

Store values as the history of a tag under PDK/, one every every, the last one now (or at end_ms), in provider (the gateway’s only history provider when not given).

Parameters:
  • gateway (Gateway)

  • path (str)

  • values (list[str])

  • every (str)

  • provider (str | None)

  • quality (str | None)

  • end_ms (int | None)

Return type:

str

The live catalog: what the running gateway’s Perspective registers, against the offline bundle.

pdk schemas sync compares every registered component with the descriptor the bundle extracted from the installed .modl (drift), and writes the components the bundle lacks — third-party modules — to components/live.components.json inside the bundle, where the loader already picks them up.

class pdk.live.Drift(version: 'str', built_in: 'int' = 0, bundled: 'int' = 0, differing: 'dict[str, list[str]]'=<factory>, missing: 'list[str]' = <factory>, live_only: 'list[dict[str, Any]]'=<factory>, without_schema: 'list[str]' = <factory>, built_in_ids: 'set[str]' = <factory>)[source]
Parameters:
  • version (str)

  • built_in (int)

  • bundled (int)

  • differing (dict[str, list[str]])

  • missing (list[str])

  • live_only (list[dict[str, Any]])

  • without_schema (list[str])

  • built_in_ids (set[str])

pdk.live.offline_descriptors(bundle_dir)[source]

id -> (file name, raw descriptor) as extracted from the .modl, without the live file.

Parameters:

bundle_dir (Path)

Return type:

dict[str, tuple[str, dict[str, Any]]]

pdk.live.comparable(descriptor, declared=None)[source]

The parts validation relies on, normalized so absent and empty mean the same on both sides.

The registry fills metadata the file leaves out (a derived name or defaultMetaName, category “unknown”) and marks components hidden from the palette (showOnPalette: false) as deprecated: metadata is compared only where the offline descriptor (declared) states it.

Parameters:
  • descriptor (dict[str, Any])

  • declared (dict[str, Any] | None)

Return type:

dict[str, Any]

pdk.live.sync(gateway, root=None, budget=DEFAULT_BUDGET)[source]

Compare the gateway’s components with the bundle of its Perspective version; write the live-only ones.

Parameters:
  • gateway (Gateway)

  • root (Path | None)

  • budget (int)

Return type:

tuple[bool, str]

pdk.live.changes_text(page)[source]

One line per change event, for pdk gateway changes.

Parameters:

page (dict[str, Any])

Return type:

str

pdk.live.sessions_text(listing)[source]

One line per page, for pdk gateway sessions.

Parameters:

listing (dict[str, Any])

Return type:

str

pdk.live.logs_text(page)[source]

One block per log event, for pdk gateway logs.

Parameters:

page (dict[str, Any])

Return type:

str

Eyes

Open, inspect and screenshot a deployed view: the eyes’ entry points for the CLI and the MCP server.

The view.json joined with the page is the one the gateway has (what is rendered), not the local copy; when the local copy differs, the report says the edits are not deployed. The gateway log cursor is taken before the page (re)loads, so startup scripts that fail are caught. Bindings start Uncertain until their first value arrives: the gateway tree is read again for a short while until no quality is Uncertain.

class pdk.eyes.inspect.Target(project: 'str', path: 'str', view: 'dict[str, Any]', note: 'str | None')[source]
Parameters:
  • project (str)

  • path (str)

  • view (dict[str, Any])

  • note (str | None)

class pdk.eyes.inspect.Result(ok: 'bool', text: 'str', errors: 'int' = 0)[source]
Parameters:
  • ok (bool)

  • text (str)

  • errors (int)

pdk.eyes.inspect.resolve(gateway, location)[source]

A local view (folder or view.json under work/) or a view path in the sandbox, read from the gateway.

Parameters:
Return type:

Target

pdk.eyes.inspect.session_closer(gateway)[source]

Eyes’ release: close the sandbox sessions of the browser’s pages on the gateway (best effort, so a module without the route only leaves them to time out).

Parameters:

gateway (Gateway)

Return type:

Any

class pdk.eyes.inspect.Popup(id: 'str', path: 'str', view: 'dict[str, Any]', extracted: 'dict[str, Any]')[source]
Parameters:
  • id (str)

  • path (str)

  • view (dict[str, Any])

  • extracted (dict[str, Any])

pdk.eyes.inspect.open_view(eyes, gateway, location, viewport=None)[source]

Open the view’s preview in a fresh tab and report whether it renders.

Parameters:
  • eyes (Eyes)

  • gateway (Gateway)

  • location (str)

  • viewport (str | None)

Return type:

Result

pdk.eyes.inspect.inspect_view(eyes, gateway, location, viewport=None, *, focus=None, budget=DEFAULT_BUDGET, query=None, expect=None, act=None)[source]

Reload the view and report its anomalies: rendering, gateway qualities, logged script errors, console; with act, after performing those steps (pdk.eyes.act); with query, also what was measured of the matching components (measure.describe); with expect, the expectations that fail, as A diagnostics (expect.check). Several viewports (comma-separated, or presets like phone) give one report each, with the budget shared; the sessions of the extra ones are closed afterwards.

Parameters:
  • eyes (Eyes)

  • gateway (Gateway)

  • location (str)

  • viewport (str | None)

  • focus (str | None)

  • budget (int)

  • query (str | None)

  • expect (str | None)

  • act (str | None)

Return type:

Result

pdk.eyes.inspect.screenshot(eyes, gateway, location, viewport=None, component=None, act=None, compare=None)[source]

PNG of the view (opened afresh) or of one component, by name path (root/Panel/Label), DOM path (C.0:1) or, once act has opened it, popup:<id>/root/… With act, the steps (pdk.eyes.act) run before capturing: a step that cannot be read comes back as A005, one that cannot be done as A004, and neither gives a PNG. With compare (the bytes of a PNG taken before), the text ends with the comparison line (see compare_screenshot).

Parameters:
  • eyes (Eyes)

  • gateway (Gateway)

  • location (str)

  • viewport (str | None)

  • component (str | None)

  • act (str | None)

  • compare (bytes | None)

Return type:

tuple[bytes | None, str]

pdk.eyes.inspect.compare_screenshot(eyes, gateway, location, before, viewport=None, component=None, act=None)[source]

screenshot, compared with before (a PNG of the same view, viewport and component): (png, diff_png, text). diff_png is the new PNG with the changed pixels in red; None when nothing changed or the sizes differ.

Parameters:
  • eyes (Eyes)

  • gateway (Gateway)

  • location (str)

  • before (bytes)

  • viewport (str | None)

  • component (str | None)

  • act (str | None)

Return type:

tuple[bytes | None, bytes | None, str]

Chromium side of the eyes: readiness, stability, DOM extraction, console and screenshots.

Ported from perspective-compiler’s runtime harness (open_ready_page, geometry stability, extraction) without the IR, hashes or artifacts. Playwright’s sync API is bound to the thread that started it and refuses to run inside an asyncio loop (the MCP server has one), so every browser call runs on one dedicated worker thread owned by Eyes. One Chromium and one context per viewport stay open between calls: Maker caps concurrent Perspective sessions, and a kept context keeps its session; every open is a new tab, so a new Perspective page whose views start afresh.

exception pdk.eyes.browser.EyesError(status, message, evidence=None)[source]

Opening or reading the page failed; status is one of the constants above.

Parameters:
  • status (str)

  • message (str)

  • evidence (dict[str, Any] | None)

class pdk.eyes.browser.Viewport(width: 'int', height: 'int')[source]
Parameters:
  • width (int)

  • height (int)

classmethod parse(text)[source]

WIDTHxHEIGHT or a preset name (desktop, tablet, phone, wide).

Parameters:

text (str | None)

Return type:

Viewport

classmethod parse_many(text)[source]

One or more viewports, comma-separated, without repeats.

Parameters:

text (str | None)

Return type:

list[Viewport]

class pdk.eyes.browser.Opened(url, viewport, page, page_id, readiness_ms, maker_notice, console=<factory>, endless=<factory>)[source]

A ready page. Only the worker thread may touch page.

Parameters:
  • url (str)

  • viewport (Viewport)

  • page (Any)

  • page_id (str | None)

  • readiness_ms (float)

  • maker_notice (bool)

  • console (list[dict[str, str]])

  • endless (list[str])

class pdk.eyes.browser.Eyes(headless=True, idle_s=None, release=None)[source]

A long-lived headless Chromium; every method blocks until its work on the browser thread is done.

With idle_s, the browser closes after that long without work: an open page keeps its Perspective session connected (Maker caps them per gateway), and a long-lived server would otherwise hold it forever. The next call starts it again. A browser that goes away only disconnects its sessions, which then hold their slots until they time out: release(page_ids), called before the contexts close with one page of each session, closes them on the gateway.

Parameters:
  • headless (bool)

  • idle_s (float | None)

  • release (Callable[[list[str]], None] | None)

open(url, viewport=None, *, fresh=True)[source]

Open url in a new tab (replacing the one already open, unless fresh is False) and wait until it is ready and stable.

Parameters:
  • url (str)

  • viewport (Viewport | None)

  • fresh (bool)

Return type:

Opened

extract(opened, root=ROOT_PATH)[source]

Boxes, text and overflow of every component under the root (C.0, or P<id>.0 for a popup), after the geometry is stable again.

Parameters:
Return type:

dict[str, Any]

location(opened)[source]

The page’s URL now (a step may have navigated it).

Parameters:

opened (Opened)

Return type:

str

popups(opened)[source]

Ids of the popups open on the page, in stacking order.

Parameters:

opened (Opened)

Return type:

list[str]

act(opened, steps, pointers, resolve=None, tags=None)[source]

Perform pdk.eyes.act steps on the page, letting it settle after each one.

Parameters:
  • opened (Opened)

  • steps (list[Any])

  • pointers (dict[str, str])

  • resolve (Callable[[str], str | None] | None)

  • tags (Callable[[Any], Any] | None)

Return type:

Any

screenshot(opened, component=None)[source]

PNG of the viewport, or of one component by its DOM path (e.g. C.0:3:0).

Parameters:
  • opened (Opened)

  • component (str | None)

Return type:

bytes

compare(opened, before, after, threshold=32, cell=16)[source]

Pixel comparison of two PNGs of the same view, in the page (COMPARE_JS): changed of total pixels differ by more than threshold in one channel, regions boxes them (largest first, at most 20; region_count is the real number) and diff_png is the after image with the changes in red. Sizes that differ come back as size_before and size_after only.

Parameters:
  • opened (Opened)

  • before (bytes)

  • after (bytes)

  • threshold (int)

  • cell (int)

Return type:

dict[str, Any]

forget(viewport)[source]

Close the context of one viewport and release its session (an extra viewport of one inspection).

Parameters:

viewport (Viewport)

Return type:

None

close()[source]

Idempotent; safe from atexit, where the worker pool may already be shut down.

Return type:

None

pdk.eyes.browser.classify_state(state)[source]

A terminal failure visible in the page state, or None while it may still become ready.

Parameters:

state (dict[str, Any])

Return type:

tuple[str, str] | None

pdk.eyes.browser.geometry_delta(previous, current)[source]

The largest move of any component present in both samples, and its path.

Parameters:
  • previous (dict[str, list[float]])

  • current (dict[str, list[float]])

Return type:

tuple[float, str | None]

Join of the three views of one component: the local view.json, the DOM and the gateway’s evaluated tree.

All three address components by child index from the root: the view.json pointer /root/children/1/children/0, the gateway address path 0:1:0 and the DOM path <mountPath>.0:1:0 (C.0:1:0 for the routed view). Descendants of embedded views carry a $ in the DOM path, docks a T[/L[/R[/B[ prefix; neither belongs to the inspected view.

class pdk.eyes.join.Part(node, dom=None, live=None, mount='C', prefix='')[source]

One component of the view.json and what was observed of it.

Parameters:
  • node (Node)

  • dom (dict[str, Any] | None)

  • live (dict[str, Any] | None)

  • mount (str)

  • prefix (str)

class pdk.eyes.join.Joined(parts: 'list[Part]', view: 'dict[str, Any]', live_view: 'dict[str, Any] | None', viewport: 'dict[str, int]', by_dom: 'dict[str, Part]'=<factory>, by_name: 'dict[str, Part]'=<factory>, mismatches: 'list[str]' = <factory>, foreign: 'int' = 0, mount: 'str' = 'C', popups: 'dict[str, str]'=<factory>, url: 'str' = '', routed: 'str | None' = None)[source]
Parameters:
  • parts (list[Part])

  • view (dict[str, Any])

  • live_view (dict[str, Any] | None)

  • viewport (dict[str, int])

  • by_dom (dict[str, Part])

  • by_name (dict[str, Part])

  • mismatches (list[str])

  • foreign (int)

  • mount (str)

  • popups (dict[str, str])

  • url (str)

  • routed (str | None)

pdk.eyes.join.live_view(page, view_path, mount=MOUNT)[source]

The instance of view_path mounted at mount (C routed, P<id> popup), if the gateway reported it.

Parameters:
  • page (dict[str, Any] | None)

  • view_path (str)

  • mount (str)

Return type:

dict[str, Any] | None

pdk.eyes.join.mounted_view(page, mount=MOUNT)[source]

The view the gateway lists at mount on the page (C: the routed view), if it reported the page.

Parameters:
  • page (dict[str, Any] | None)

  • mount (str)

Return type:

str | None

pdk.eyes.join.mounted_by_design(part)[source]

False when the component may legitimately be absent from the DOM.

Parameters:

part (Part)

Return type:

bool

Anomaly rules over a joined view: geometry (V), gateway qualities (Q), gateway log (L), browser console (C) and the state of the eyes themselves (X). They produce the validator’s Diagnostic, pointing into the local view.json, so pdk.diagnostics.render budgets and focuses them the same way.

The geometry rules are perspective-compiler’s VIS001/002/003/007 on the joined model, with two changes: text cut with an ellipsis counts (it hides information too), and a collapse is any component with content shrunk to zero inside a parent that has room, not only leaves.

pdk.eyes.rules.scrolls(dom, axis)[source]

The component scrolls along x or y (overflow auto or scroll) instead of clipping or spilling.

Parameters:
  • dom (dict[str, Any])

  • axis (str)

Return type:

bool

pdk.eyes.rules.scroll_extent(dom, axis)[source]

How far the content runs past the component’s content box along x or y.

Parameters:
  • dom (dict[str, Any])

  • axis (str)

Return type:

float

pdk.eyes.rules.text_clipped(joined)[source]

V001: visible text of a label, button or link runs past the rectangle that clips it. Along an axis a scroll container scrolls, text past its edge is scrolled out of view, not cut (cut_rect leaves those axes out).

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.component_overflow(joined)[source]

V002: a container’s children overflow its content box, along an axis it does not scroll.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.viewport_overflow(joined)[source]

V003: the view’s content does not fit the viewport; reported on the deepest component that sticks out.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.collapsed(joined)[source]

V007: a component with content is rendered with zero width or height inside a parent that has room.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.not_mounted(joined)[source]

V010: a component of the view.json is not in the page (only the topmost missing one is reported).

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.failed_views(joined)[source]

V011: an embedded view or repeater shows Perspective’s failed-view placeholder instead of its view.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.unrequested_scroll(joined, declared=None)[source]

V014: a container scrolls (its content overflows along an axis with overflow auto or scroll), or shows a scrollbar with nothing to scroll (overflow scroll), and no scrolls expectation declares it. A scroll hides content the way V002 reports, so one the view did not ask for is usually V002 silenced. It is an error when it is plainly not a scrolling area: nested in another scroll along the same axis, or for a sliver of content.

Parameters:
  • joined (Joined)

  • declared (Mapping[str, Set[str]] | None)

Return type:

list[Diagnostic]

pdk.eyes.rules.repeater_overflow(joined)[source]

V012: a flex repeater’s instances are bigger than the repeater along the axis the instance count does not explain (the cross axis without wrap, the main axis with it), so each one scrolls inside a strip of it.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.contrast_ratio(color, background)[source]

WCAG contrast of a text color (its alpha composited over the background) on an opaque background.

Parameters:
  • color (str | None)

  • background (str | None)

Return type:

float | None

pdk.eyes.rules.low_contrast(joined)[source]

V013: text whose color is too close to what is behind it (WCAG AA: 4.5:1, or 3:1 for large text), on the components whose text is theirs to color (CONTRAST_TYPES), when the view chose those colors (the theme’s defaults are not judged). Disabled controls are exempt, and text over a background image is not judged.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.qualities(joined)[source]

Q001/Q002/Q003: a property the gateway evaluated is Bad, Error or Uncertain, on the binding that feeds it.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.overlays(joined)[source]

Without the gateway tree: Q001/Q002 from the quality overlay Perspective draws over a bad binding.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.logged(joined, events)[source]

L001: the gateway logged a script error for this view, attributed to the component in the MDC.

Parameters:
  • joined (Joined)

  • events (list[dict[str, Any]])

Return type:

list[Diagnostic]

pdk.eyes.rules.console(entries)[source]

C001: an uncaught exception or a console error in the browser.

Parameters:

entries (list[dict[str, str]])

Return type:

list[Diagnostic]

pdk.eyes.rules.degraded(reasons)[source]

X001: part of the eyes is missing, so some anomalies cannot be seen.

Parameters:

reasons (list[str])

Return type:

list[Diagnostic]

pdk.eyes.rules.out_of_sync(joined)[source]

X002: the open page does not render this view.json, so nothing else can be trusted.

Parameters:

joined (Joined)

Return type:

list[Diagnostic]

pdk.eyes.rules.evaluate(joined, *, logs=None, console_entries=None, degraded_reasons=None, declared_scrolls=None)[source]

Every anomaly of one inspection. A page out of sync with the view.json reports only that, and what happens inside a collapsed component is reported once, as that component’s V007. declared_scrolls maps component names to the axes scrolls expectations ask for (expect.declared_scrolls); V014 leaves those alone.

Parameters:
  • joined (Joined)

  • logs (list[dict[str, Any]] | None)

  • console_entries (list[dict[str, str]] | None)

  • degraded_reasons (list[str] | None)

  • declared_scrolls (Mapping[str, Set[str]] | None)

Return type:

list[Diagnostic]

What was measured of selected components: one compact line each, so an agent can check a layout without a screenshot.

A query is a comma-separated list of terms: a name path (root/Header matches it and its subtree), a component type (ia.display.label), a pointer prefix (/root/children/0) or * for every component. Values that are at their neutral default (no padding, no border, transparent background, no gap) are left out; coordinates are viewport pixels.

Expectations about a rendered view, checked against what was measured (A001-A003).

One expectation per ; or line, <component> <relation> [args], components by name path (quote names with spaces):

root/Subtitle below root/Title [gap 8] also above, left-of, right-of; gap >= 8, gap 8..16 root/Log/Last inside root/Log within its box, or its content along an axis it scrolls root/Save aligned right root/Form edges: left right top bottom center-x center-y root/Table width 100% width height x y; =, >=, <=, >, <; px or % of the parent’s content root/Pump x 150 x and y from the parent’s inner top-left (coord’s position.x/y) root/Title text “Pump 1” text ~ “Pump” for contains; embedded view: its text; input: its value root/Alarm visible or hidden (rendered with a size, wherever it is scrolled to) root/Save enabled or disabled (the control, or the input inside it) popup detail open or closed; inside an open popup: popup:detail/root/Name text “P-1” root/Log scrolls [y] its content overflows along x/y (either) and it scrolls there root/Log/Last in-view wholly in sight: not scrolled away, clipped, or off the viewport root/Title color #323232 color, bg (hex, rgb(), rgba()), font-size [op] N, font-weight N root/Bar prop value >= 40 a property as the gateway evaluated it: props, or position/custom/meta view prop custom.total = 3 the routed view’s params or custom, from the gateway’s entry for it page /detail the page’s URL path (page ~ /det contains); after a nav action page shows PDK/Detail the view the page shows (a nav action may swap it, URL or not) tag Sandbox/Setpoint = 42 a simulated tag’s value (read back from the gateway), under PDK/ tag Sandbox/Setpoint quality Bad_Stale its quality: a name, or a level (Good, Bad, Uncertain, Error) alarm North/Level active or cleared: alarm events of the tags at or under the path

Lengths compare with a 1px tolerance (sub-pixel layout); edges are viewport pixels of the component’s box, except x and y, which are measured from the parent’s padding box (the viewport for root), like position.x/y in a coord.

class pdk.eyes.expect.TagReader(*args, **kwargs)[source]
class pdk.eyes.expect.Outcome(total: 'int', diagnostics: 'list[Diagnostic]')[source]
Parameters:
pdk.eyes.expect.split(text)[source]

Expectations separated by ; or newlines, outside quotes.

Parameters:

text (str)

Return type:

list[str]

pdk.eyes.expect.check(joined, text, tags=None)[source]

tags reads simulated tags and their alarms (pdk.tags.Probe) for the tag and alarm expectations.

Parameters:
Return type:

Outcome

pdk.eyes.expect.declared_scrolls(text)[source]

The components scrolls expectations ask to scroll, with their axes (both without one): those scrolls are by design, so V014 does not report them, whether or not the expectation passes.

Parameters:

text (str | None)

Return type:

dict[str, set[str]]

pdk.eyes.expect.page_location(url)[source]

A Perspective page’s path inside its project (/data/perspective/client/<project>/<path>, with the query), decoded; any other URL whole.

Parameters:

url (str | None)

Return type:

str

pdk.eyes.expect.normalize_color(value)[source]

Computed-style form: rgb(r, g, b) or rgba(r, g, b, a); hex and opaque rgba are converted.

Parameters:

value (str)

Return type:

str

Actions on an open view before it is measured: click, type, choose dropdown options, hover, scroll, slide, press keys, select a table row, wait (F5 part A), and set a simulated tag (part B).

Steps are written like expectations (; or newlines, components by name path):

click root/Save; type root/Name “Pump 2”; row root/Table 1; wait 500; click popup:detail/root/Ok select root/Mode “Auto”; slide root/Speed 40; scroll root/Feed bottom; key root/Name Enter; hover root/Help tag Sandbox/Setpoint 42; tag Sandbox/Message “en marcha”; tag Sandbox/Setpoint quality Bad_Stale

Tag paths without [provider] hang from PDK/; the view gets the new value through its subscription.

They run in the browser in order; after each one the page settles like after opening it. A step that cannot be done stops the sequence and comes back as A004 (with the reason); a step that cannot be read is A005.

class pdk.eyes.act.Step(verb: 'str', text: 'str', component: 'str | None' = None, dom_path: 'str | None' = None, value: 'str | None' = None, number: 'int' = 0, tag: 'str | None' = None, quality: 'str | None' = None, labels: 'tuple[str, ...]' = (), key: 'str | None' = None, scroll: 'str | int | None' = None, level: 'float | None' = None)[source]
Parameters:
  • verb (str)

  • text (str)

  • component (str | None)

  • dom_path (str | None)

  • value (str | None)

  • number (int)

  • tag (str | None)

  • quality (str | None)

  • labels (tuple[str, ...])

  • key (str | None)

  • scroll (str | int | None)

  • level (float | None)

class pdk.eyes.act.Outcome(total: 'int', done: 'int', diagnostics: 'list[Diagnostic]')[source]
Parameters:
  • total (int)

  • done (int)

  • diagnostics (list[Diagnostic])

exception pdk.eyes.act.Malformed[source]
pdk.eyes.act.parse(text, nodes)[source]

Steps for the view’s components (name path -> node); malformed steps come back as A005.

Parameters:
  • text (str)

  • nodes (dict[str, Node])

Return type:

tuple[list[Step], list[Diagnostic]]

pdk.eyes.act.run(page, steps, settle, pointers, resolve=None, tags=None)[source]

Perform the steps on the worker thread; settle(page) waits for a stable layout after each one, resolve(name) gives the DOM path of a popup:<id>/… component once its popup is open, and tags(step) writes a tag step through the gateway.

Parameters:
  • page (Any)

  • steps (list[Step])

  • settle (Any)

  • pointers (dict[str, str])

  • resolve (Callable[[str], str | None] | None)

  • tags (Callable[[Step], Any] | None)

Return type:

Outcome

Environment

Per-machine settings: an optional TOML file whose values fill in the PDK environment variables that are unset.

Everything in PDK reads environment variables; this file only spares setting them for every shell, the MCP server and the hook. Default location ~/.pdk/config.toml, or PDK_CONFIG. Example:

gateway_url = “http://127.0.0.1:8088” ignition_home = “C:/Program Files/Inductive Automation/Ignition” api_key = “…” # or keep it in ~/.pdk/ignition-api-key

pdk.config.load()[source]

The config file, the variables it set (unset ones only), and a problem reading it, if any.

Return type:

tuple[Path, dict[str, str], str | None]

pdk doctor: check every prerequisite of a working PDK on this machine and say how to fix what is missing.

Ordered from the local install to the gateway; a check whose prerequisite failed is skipped. –fix applies only local, reversible fixes (extract the schema bundle, download Playwright’s Chromium). It never touches the gateway, ignition.conf or anything that needs admin rights or a restart: those are printed for the user to do.

class pdk.doctor.Check(name: 'str', status: 'str', detail: 'str', fix: 'str | None' = None)[source]
Parameters:
  • name (str)

  • status (str)

  • detail (str)

  • fix (str | None)

class pdk.doctor.State(ignition_home=None, perspective=None, gateway_up=False, health=None, sandbox_flag=None)[source]

What earlier checks found, for the later ones.

Parameters:
  • ignition_home (Path | None)

  • perspective (str | None)

  • gateway_up (bool)

  • health (dict | None)

  • sandbox_flag (str | None)