Skip to main content

tlaplus-state-graph-utils.py

Python utilities for working with TLA+ state graphs

Installation

pip install tlaplus-state-graph-utils

Using the CLI

Installing the package puts a CLI program named tlaplus-state-graph-utils.py in your PATH. Here is its --help text:

usage: tlaplus-state-graph-utils.py [-h] [--version] COMMAND ...

utilities for working with TLA+ state graphs

options:
  -h, --help  show this help message and exit
  --version   show program's version number and exit

subcommands:
  COMMAND     description
    convert   convert between state graph formats

It currently has only one subcommand called convert which can be used to convert between different representations of TLA+ state graphs. Here is its --help text:

usage: tlaplus-state-graph-utils.py convert [-h] [--output OUTPUT]
                                    [--from {reasonable-json,tlaplus-dot-json}]
                                    [--to {reasonable-json,d2}] [--pretty]
                                    [--reasonable-json-structured-state]
                                    [--reasonable-json-simple-structured-state]
                                    [--reasonable-json-itf-state]
                                    [--d2-output-state-as D2_OUTPUT_STATE_AS]
                                    [input]

convert between TLA+ state graph formats/representations

positional arguments:
  input                 input file path or '-' to use stdin (the default)

options:
  -h, --help            show this help message and exit
  --output OUTPUT, -o OUTPUT
                        output file path or '-' to use stdout (the default)
  --from {reasonable-json,tlaplus-dot-json}, -f {reasonable-json,tlaplus-dot-json}
                        input format (guessed from extension & content if not
                        given)
  --to {reasonable-json,d2}, -t {reasonable-json,d2}
                        output format (if not given, defaults to reasonable-
                        json when outputting to stdout, otherwise guessed from
                        extension)
  --pretty              produce pretty-printed rather than compact output

reasonable-json options:
  options relevant when outputting in reasonable-json format

  --reasonable-json-structured-state
                        include state contents represented as structured JSON
  --reasonable-json-simple-structured-state
                        include state contents represented as simplified
                        structured JSON (lossy, i.e. doesn't encode all
                        details of TLA+, but easy to work with)
  --reasonable-json-itf-state
                        include state contents represented in ITF state format
                        (see: https://apalache-mc.org/docs/adr/015adr-
                        trace.html)

D2 options:
  options relevant when outputting in D2 format

  --d2-output-state-as D2_OUTPUT_STATE_AS
                        how to represent individual states in the D2 output:
                        label: without modification as a D2 node label; latex:
                        as a LaTeX equation which D2 will render; nested-
                        containers: as nested containers, one per variable,
                        record, etc.; nested-containers-simple-values-inline:
                        as above but with terminal/simple values not getting
                        their own container; nested-containers-simple-values-
                        inline-newline: as above but with keys and terminal
                        values separated by newlines

For instance, this converts a GraphViz dot file produced by TLA+'s state diagram output into a "reasonable" JSON format that's easier to work with:

# In your TLA+ Model directory:
dot -Tjson Model_1.dot | tlaplus-state-graph-utils.py convert -t reasonable-json

The following sections go into more details about the supported input and output formats.

Input formats

dot JSON

TLA+ does not currently have a "canonical" format for state graphs (see TLA+ GitHub issue #639) and so the only halfway convenient way to get this information out of TLA+ is to process the GraphViz dot files it produces.

In particular, as suggested in a comment on the aforementioned issue, dot itself can convert these into a JSON representation (dot -Tjson), which can then by read in by this utility (it automatically considers filenames ending in .dot.json to be such files).

Reasonable JSON

Another possible input format is the "reasonable JSON" format produced by this tool itself - it is explained in more detail in the Output formats section below.

Output formats

"Reasonable JSON"

The aforementioned "reasonable JSON" format is meant to make it easier for other tools to work with TLA+ state graphs. It looks like this:

{
  "metadata": {
    "format": {
      "name": "reasonable-tlaplus-state-graph-json",
      "version": "0.1.1"
    }
  },
  "states": [
    {
      "id": 1,
      "labelTlaPlus": "/\\ a = 1 /\\ b = 2 \n ...",
      // optional, if requested:
      "structuredState": ...,
      "simpleStructuredState": ...,
      "itfState": ...
      // optional, if added by user:
      "styleClass": "someclass"
    },
    ...
  ],
  "steps": [
    {
      "id": 0,
      "actionName": "CheckFileExists",
      "fromStateId": 1,
      "toStateId": 2,
      "colorId": "1"
    },
    ...
  ]
}
Structured state

If present, the optional fields structuredState, simpleStructuredState and itfState contain different JSON representations of each state's "content" (i.e. the set of variables and their values for that state). They can be switched on independently of one another via the --reasonable-json-structured-state, --reasonable-json-simple-structured-state, and --reasonable-json-simple-structured-state CLI flags.

The "structured" and "simple-structured" formats are ad-hoc formats defined by this tool (if you need docs for this please open an issue).

The ITF state format is the same as that used in traces output by the Apalache model checker and described in the "State object" section of its ADR-015.

Style class

The optional field styleClass represents a "class" of styling options to apply to the state in question and will be included in output formats that support such a "class" concept (e.g. D2 - see below).

D2

Another supported output format is D2, but to use it, the package's d2 extra needs to be installed:

pip install tlaplus-state-graph-utils[d2]'

Here is an example showing how to go from a dot file produced by TLA+ to a graph rendered using D2 in one shell command:

# In your TLA+ Model directory:
dot -Tjson Model_1.dot \
| tlaplus-state-graph-utils.py convert -t d2 \
| D2_LAYOUT=elk d2 - > Model_1.svg

There are many different ways to represent the contents of each state (i.e. the set of variables and their values) in D2, which can be configured via the --d2-output-state-as option:

label
latex
nested-containers
nested-containers-simple-values-inline
nested-containers-simple-values-inline-newline

Cookbook / advanced techniques

Conditional styling

While there is no built-in support for making styleClass dependent on the TLA+ state contents (yet?), it's possible to hack something together using structured/JSON state output and the jq JSON processing tool, e.g.:

tlaplus-state-graph-utils.py convert --reasonable-json-simple-structured-state \
| jq '.states[] |= (.styleClass =
if .someKey == "some-value" then
  "class1"
elif .someKey == "some-other-value" then
  "class2"
else
  .styleClass
end
)'

This overwrites the styleClass attribute of each state (adding it if it doesn't exist) depending on the value of the someKey variable in it.

It is recommended to use the simple-structured-state format for such kinds of processing because it's designed to be easy to work with in jq.

styleClass is included in e.g. the D2 output, making it possible to create graphs like this with this technique (see dev/render-test-examples.sh for the full script to generate this one):

Use as a library

I'm too lazy to write this or set up automated API docs, especially considering nobody is going to use it. If you want to use this as a library, please just open an issue saying so and I'll get started (and maybe clean things up a little).

Metadata

Release files for tlaplus-state-graph-utils 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tlaplus-state-graph-utils 0.2.0
File Size Uploaded Provenance Actions
tlaplus_state_graph_utils-0.2.0.tar.gz 34.9 kB Without provenance Details for tlaplus_state_graph_utils-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for tlaplus-state-graph-utils 0.2.0
File Interpreter ABI Platform Actions
tlaplus_state_graph_utils-0.2.0-py3-none-any.whl Python 3 none any Details for tlaplus_state_graph_utils-0.2.0-py3-none-any.whl

Total release size: 59.7 kB

Release files / tlaplus_state_graph_utils-0.2.0.tar.gz

Download URL tlaplus_state_graph_utils-0.2.0.tar.gz
Size 34.9 kB
Tags Source
SHA-256 checksum
How to use checksums
18c3260769861d30a273feadf7707973309f6cdc08f23eb273287d462ac44f02
BLAKE2b-256 checksum
How to use checksums
4aebf279fc482632c221f8869be4851dde3ee09ec4ebfc5fd1b820d18d467679
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.1.1 CPython/3.12.7

Release files / tlaplus_state_graph_utils-0.2.0-py3-none-any.whl

Download URL tlaplus_state_graph_utils-0.2.0-py3-none-any.whl
Size 24.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1b58250bd3fb3426dff1cc0731984eacc0ee74df7baf9e09382b42391efdfa3e
BLAKE2b-256 checksum
How to use checksums
705a55013e9b3d3a9df6bf56d51f788bfa8f8bf753a33a2eb280a9c873028a3f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.1.1 CPython/3.12.7

Security for tlaplus-state-graph-utils 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page