Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,67 @@ on:
types:
- published

permissions:
contents: read

concurrency:
group: release-${{ github.event.release.tag_name }}
cancel-in-progress: false

jobs:
publish:
if: ${{ !github.event.release.draft && !github.event.release.prerelease }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Verify release target
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
python - <<'PY'
import os
import subprocess
import sys
import tomllib

with open("pyproject.toml", "rb") as pyproject:
version = tomllib.load(pyproject)["project"]["version"]

release_tag = os.environ["RELEASE_TAG"]
expected_tag = f"v{version}"
if release_tag != expected_tag:
print(
f"::error::Release tag {release_tag!r} does not match "
f"pyproject.toml version {version!r}; expected {expected_tag!r}."
)
sys.exit(1)

def git(*args: str) -> str:
return subprocess.check_output(("git", *args), text=True).strip()

release_commit = git("rev-list", "-n", "1", release_tag)
master_commit = git("rev-parse", "origin/master")
if release_commit != master_commit:
print(
f"::error::Release tag {release_tag!r} points at "
f"{release_commit}, but origin/master is {master_commit}."
)
sys.exit(1)
PY
- name: Check PyPI token
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
run: |
if [ -z "$POETRY_PYPI_TOKEN_PYPI" ]; then
echo "::error::PYPI_TOKEN secret is not configured or is empty."
exit 1
fi
- name: Install Poetry
run: python -m pip install "poetry>=2.0,<3.0"
- name: Install dependencies
Expand Down
4 changes: 1 addition & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ run-to-completion execution core.
- License: MIT
- Python: 3.13+
- Runtime dependencies: none
- Current status: alpha, version `0.7.0` (release-ready; PyPI publish pending)
- Current status: alpha, version `0.7.0`

The central bet is simple: charts designed in Stately or shared with a
JavaScript frontend should load directly as Python `dict` / JSON data, with
Expand Down Expand Up @@ -87,8 +87,6 @@ Working:
Known gaps:

- Full SCXML conformance still has known `more-parallel` failures.
- Publishing `0.7.0` to PyPI is still a release task after the merged
release-readiness work.
- Graphviz export and graph/test helper APIs beyond Mermaid are future work.
- SCXML condition support is intentionally not a general JavaScript evaluator.

Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

All notable changes to this project will be documented here.

## 0.7.0 - 2026-07-01
## 0.7.0 - 2026-07-02

### Added

Expand All @@ -16,6 +16,14 @@ All notable changes to this project will be documented here.
- Added dependency-free Mermaid `stateDiagram-v2` export with
`to_mermaid(machine)`.

### Changed

- Hardened the GitHub Release publish workflow so the release tag must match the
package version, point at `origin/master`, and have a configured PyPI token
before upload.
- Updated PyPI-facing installation docs to use `pip install xstate` for the
released package.

## 0.6.0 - 2026-06-28

### Added
Expand Down
25 changes: 11 additions & 14 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,27 @@ the niche of native XState JSON compatibility.
```
src/xstate/
__init__.py Public API: `from xstate import Machine`
machine.py Machine class — entry point and pure transition API
machine.py Core Machine class and transition entry point
config_parser.py Two-pass XState config parser and normalizer
schema.py TypedDict boundary for raw XState config data
schema.py TypedDict schemas for Machine, StateNode, Transition, and Invoke configs
state_node.py Resolved state hierarchy model
transition.py Resolved transition model
state.py Public State / MachineSnapshot snapshots
algorithm.py SCXML execution engine (microstep/macrostep, entry/exit sets)
action.py Action constructors and higher-order action helpers
transition.py Resolved transition model
context.py ContextAdapter policies, including dataclass contexts
event.py Event wrapper and conversion helpers
exceptions.py Custom exception classes
handlers.py HandlerArgs and HandlerAdapter callable adaptation
guards.py Composable guards and state_in/stateIn helpers
snapshot.py Snapshot serialization and restoration helpers
mermaid.py Dependency-free Mermaid diagram export
context.py ContextAdapter policies, including dataclass contexts
interpreter.py Synchronous runtime, queue, subscriptions, timers
async_interpreter.py Asyncio runtime and awaitable action execution
actor.py Actor model, create_actor, ActorSystem, actor logic helpers
snapshot.py Snapshot serialization and restoration helpers
scheduler.py Clock abstractions
mermaid.py Dependency-free Mermaid diagram export
scxml.py SCXML XML → Machine config converter with safe Boolean conds
setup_api.py setup(...).create_machine(...) strict API
machine.py Core Machine class and transition entry point
interpreter.py Synchronous runtime, queue, subscriptions, timers
async_interpreter.py Asyncio runtime and awaitable action execution
config_parser.py Parser for StateNode configurations
schema.py TypedDict schemas for Machine, StateNode, Transition, and Invoke configs
exceptions.py Custom exception classes
```

`algorithm.py` is the heart of the library. It implements the W3C SCXML algorithm:
Expand All @@ -49,7 +46,7 @@ The critical execution order is: `main_event_loop` → `microstep` → `main_eve

---

## Current state (0.7.0 release-ready on master)
## Current state (0.7.0 on master)

**Working:**
- Hierarchical (compound) states
Expand Down Expand Up @@ -228,7 +225,7 @@ poetry run python -m pytest tests/test_scxml.py -k cond-js
poetry run mypy src/xstate/

# Format + lint
poetry run ruff format src/ tests/
poetry run ruff format --check src/ tests/
poetry run ruff check src/ tests/
```

Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ functions, delay values, and actor logic.

## Installation

The `0.7.0` package metadata is ready for release. Until the GitHub release
publishes to PyPI, install from source:
Install the released package from PyPI:

```bash
pip install xstate
```

For an unreleased checkout, install from source:

```bash
git clone https://github.com/JovaniPink/xstate-python.git
Expand Down
Loading