Skip to main content

pyrung

Write ladder logic in Python. Test it. Deploy it to CLICK.

pyrung turns a Python with block into a ladder rung: condition on the rail, instruction in the body. Same rungs, same scan order, same timers as the CLICK PLC, with git, pytest, and a debugger around them.

from pyrung import Bool, PLC, Program, rung, out

Button = Bool()
Light = Bool()

with Program() as logic:
    with rung(Button):
        out(Light)

with PLC(logic) as plc:
    Button.value = True
    plc.step()
    assert Light.value is True

Why

CLICK PLCs ship with no simulator, no version control beyond copies of a .ckp, and no way to test a program short of downloading it to a real PLC. You draw the ladder in CLICK Programming Software, download it to hardware, and hope. The Structured Text crowd has options. The ladder crowd doesn't. pyrung is that option: write and test the logic in Python first, then move the same rungs into CLICK.

Same source, three paths: pyrung_to_ladder() encodes your rungs for ClickNick to paste into CLICK Programming Software; the CircuitPython dialect generates a scan loop for a P1AM-200; or run it as an emulated CLICK over Modbus and test two programs talking to each other with no hardware.

Who it's for

Controls engineers who want to test CLICK logic without hardware. Write with plain tag names, map them to X, Y, C, and DS addresses when you're ready, and let the validator tell you what CLICK's memory banks will and won't accept before you find out at the PLC.

Python developers entering industrial automation. pyrung teaches ladder logic in the language and tools you already have: Python, pytest, and VS Code. Start with Know Python? Learn Ladder Logic.

Makers and P1AM-200 users who want a real scan cycle without writing the plumbing. The same program you tested on your laptop generates a CircuitPython scan loop with timers, counters, Modbus TCP, and SD-backed retentive state.

Quick start

# Requires Python 3.11+
uv add pyrung

Download the starter project (pyrung-starter-VERSION.zip) from the GitHub releases page for ready-to-run examples with CLICK CSV round-trip. For the VS Code debugger, grab pyrung-debug-VERSION.vsix from the same page and install it:

code --install-extension pyrung-debug-VERSION.vsix

A motor with start/stop logic

from pyrung import Bool, Program, rung, latch, reset

Start = Bool()
Stop = Bool()
Running = Bool()

with Program() as logic:
    with rung(Start):
        latch(Running)
    with rung(Stop):
        reset(Running)

Test it

from pyrung import PLC

with PLC(logic) as plc:
    Start.value = True
    plc.step()
    assert Running.value is True

    # Release start — motor stays latched
    Start.value = False
    plc.step()
    assert Running.value is True

    Stop.value = True
    plc.step()
    assert Running.value is False

Map to CLICK hardware when you're ready

from pyrung.click import ClickBlocks, TagMap

x, y, c, t, ct, sc, ds, dd, dh, df, xd, yd, xd0u, yd0u, td, ctd, sd, txt = ClickBlocks()

mapping = TagMap({
    Start:   x[1],    # Physical input  → X001
    Stop:    x[2],    # Physical input  → X002
    Running: y[1],    # Physical output → Y001
})

mapping.validate(logic)                # Checks against CLICK constraints
mapping.to_nickname_file("motor.csv")  # For CLICK programming software

What's included

Core engine

Coils, latches, timers, counters, branching, subroutines, structured tags, and edge detection. Every scan is a pure function, so you can fork, rewind, and diff any state in history.

CLICK dialect

Map tags to X, Y, C, DS, and the other CLICK banks. The validator checks the program against CLICK's memory rules and instruction set. Export the nickname CSV and the ladder for ClickNick to paste. Import an existing project the other way.

CircuitPython dialect

Generate a self-contained scan loop for the P1AM-200 with 35 supported I/O modules, SD-backed retentive storage, watchdog, and Modbus TCP.

Analysis

logic.simplified()["Motor"] resolves a 14-rung interlock chain to the handful of inputs that actually decide it. plc.cause(Running) names why a tag changed. plc.why(Alarm) does it from a tag dump off a faulted machine. plc.how(Running) finds the input changes that reach a state, or says why none can. how() is experimental; the rest is stable.

VS Code debugger

Step through scans rung by rung, set breakpoints on rungs, force tags, and time-travel through history. Watch tags live, see the dependency graph, and turn a captured session into pytest invariants.

Disclaimers

  • Simulation is best-effort. pyrung models CLICK PLC behavior as closely as practical, but it is not a certified simulator. You are responsible for verifying your program on real hardware before production use.
  • Modbus is unauthenticated. The emulated CLICK Modbus interface and CircuitPython Modbus TCP server listen on the network with no encryption or access control — standard for Modbus, but keep them off untrusted networks.

Metadata

Release files for pyrung 0.15.2

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

Source distribution (sdist)

Source distribution for pyrung 0.15.2
File Size Uploaded
pyrung-0.15.2.tar.gz 4.1 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyrung 0.15.2
File Interpreter ABI Platform
pyrung-0.15.2-py3-none-any.whl Python 3 none any Details

Total release size: 5.6 MB

Release files / pyrung-0.15.2.tar.gz

Download URL pyrung-0.15.2.tar.gz
Size 4.1 MB
Tags Source
SHA-256 checksum
How to use checksums
af6662905ab82140feffaf213be14844fc1be1d67755b7b405c450999d9f96ef
BLAKE2b-256 checksum
How to use checksums
5f6e7836b983f990acdf361ac5050bfee720dce8cedd2dbda1852663a9f4127e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / pyrung-0.15.2-py3-none-any.whl

Download URL pyrung-0.15.2-py3-none-any.whl
Size 1.6 MB
Tags Python 3
SHA-256 checksum
How to use checksums
f64daabf5c413300dd67379ce66f790d290250b8aa9e180ed832378043b10883
BLAKE2b-256 checksum
How to use checksums
2a11b7c5371aafe7b9137e385536b634c578e7b4b3f3f3ffe3fe124834c07787
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.15.2 This release

2 release files

0.15.1

2 release files

0.11.0

2 release files

0.9.2

2 release files

0.9.1

2 release files

0.8.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.1

2 release files

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