Data Model API
Tier: Stable Core
Structured tags, IEC data types, and memory block primitives.
pyrung.Field
dataclass
Field metadata used by udt and named_array declarations.
pyrung.auto
Create a per-instance numeric default sequence descriptor.
pyrung.udt
Decorator that builds a mixed-type structured runtime from annotations.
pyrung.named_array
named_array(
base_type: object, *, count: int = 1, stride: int = 1
) -> Callable[[type[Any]], _NamedArrayRuntime]
Decorator that builds a single-type, instance-interleaved structured runtime.
pyrung.TagType
Bases: Enum
Data types for tags (IEC 61131-3 naming).
pyrung.Bool
dataclass
pyrung.Int
dataclass
pyrung.Dint
dataclass
pyrung.Real
dataclass
pyrung.Char
dataclass
pyrung.Word
dataclass
pyrung.Block
dataclass
Factory for creating Tags from a typed memory region.
Block defines a named, 1-indexed memory region where every address shares
the same TagType. Indexing a Block returns a cached LiveTag. The block
holds no runtime values — all values live in SystemState.tags.
Address bounds are inclusive on both ends: Block("DS", INT, 1, 100)
defines addresses 1–100 (100 tags). Indexing outside this range raises
IndexError. Slice syntax (block[1:10]) is rejected — use
.select(start, end) instead.
For sparse blocks (e.g. Click X/Y banks with non-contiguous valid addresses),
pass valid_ranges to restrict which addresses within [start, end] are
legal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Block prefix used to generate tag names (e.g. |
required |
type
|
TagType
|
|
required |
start
|
int
|
Inclusive lower bound address (must be ≥ 0). |
required |
end
|
int
|
Inclusive upper bound address (must be ≥ start). |
required |
retentive
|
bool
|
Whether tags in this block survive power cycles.
Default |
False
|
valid_ranges
|
tuple[tuple[int, int], ...] | None
|
Optional tuple of |
None
|
address_formatter
|
Callable[[str, int], str] | None
|
Optional callable |
None
|
Example
DS = Block("DS", TagType.INT, 1, 100)
DS[1] # → LiveTag("DS1", TagType.INT)
DS[101] # → IndexError
# Range for block operations:
DS.select(1, 10) # → BlockRange, tags DS1..DS10
# Indirect (pointer) addressing:
idx = Int("Idx")
DS[idx] # → IndirectRef, resolved at scan time
DS[idx + 1] # → IndirectExprRef
rename_slot
Set the first-class logical name for one slot before materialization.
clear_slot_name
Clear a first-class slot name override for one address.
configure_slot
Set per-slot runtime policy before this slot is materialized.
configure_range
configure_range(
start: int,
end: int,
*,
retentive: bool | None = None,
default: object = UNSET,
) -> None
Set per-slot policy for all valid addresses in the inclusive window.
clear_slot_config
Clear per-slot policy overrides for one address.
clear_range_config
Clear per-slot policy overrides for all valid addresses in a window.
slot_config
Return the effective runtime slot policy without materializing a Tag.
select
Select an inclusive range of addresses for block operations.
Both start and end are inclusive: DS.select(1, 10) yields
10 tags (1, 2, … 10). This mirrors the block constructor convention and
avoids the off-by-one confusion of Python's half-open slices.
For sparse blocks (valid_ranges set), returns only the valid addresses
within the window — gaps are silently skipped.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
int | Tag | Any
|
Start address. |
required |
end
|
int | Tag | Any
|
End address. |
required |
Returns:
| Type | Description |
|---|---|
BlockRange | IndirectBlockRange
|
|
BlockRange | IndirectBlockRange
|
definition time). |
BlockRange | IndirectBlockRange
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
IndexError
|
If either bound is outside the block's |
Example
# Static range
DS.select(1, 100) # BlockRange, DS1..DS100
# Sparse window (Click X bank)
x.select(1, 21) # valid tags only: X001..X016, X021
# Dynamic range (resolved each scan)
DS.select(start_tag, end_tag) # IndirectBlockRange
# Use with bulk instructions:
fill(0, DS.select(1, 10))
blockcopy(DS.select(1, 10), DD.select(1, 10))
search(">=", 100, DS.select(1, 100), result=Found, found=FoundFlag)
pyrung.InputBlock
dataclass
Bases: Block
Factory for creating InputTag instances from a physical input memory region.
InputBlock is identical to Block except:
- Indexing returns
LiveInputTag(notLiveTag), so elements have.immediate. - Always non-retentive — physical inputs do not survive power cycles.
Use InputBlock when the tags represent real hardware inputs (sensors,
switches, etc.). In simulation, values are supplied via runner.patch() or
runner.add_force() during the Read Inputs scan phase.
Example
pyrung.OutputBlock
dataclass
Bases: Block
Factory for creating OutputTag instances from a physical output memory region.
OutputBlock is identical to Block except:
- Indexing returns
LiveOutputTag(notLiveTag), so elements have.immediate. - Always non-retentive — physical outputs do not survive power cycles.
Writes to OutputTag elements are immediately visible to subsequent rungs
within the same scan (standard PLC behavior). The actual hardware write
happens at the Write Outputs scan phase (phase 6).
Example
pyrung.SlotConfig
dataclass
Effective runtime policy for one block slot.