semantic-state-machine-graphable 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Richard West
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.4
2
+ Name: semantic-state-machine-graphable
3
+ Version: 0.1.4
4
+ Summary: A library for visualizing semantic-state-machine structures and AuditContext execution paths as graphs using graphable.
5
+ Keywords: state-machine,graphable,visualization,audit,type-safety
6
+ Author: Richard West
7
+ Author-email: Richard West <dopplereffect.us@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: Topic :: Scientific/Engineering :: Visualization
15
+ Requires-Dist: graphable>=0.6.1
16
+ Requires-Dist: semantic-state-machine>=0.1.0
17
+ Requires-Python: >=3.13
18
+ Project-URL: Homepage, https://github.com/TheTrueSCU/semantic-state-machine-graphable
19
+ Project-URL: Repository, https://github.com/TheTrueSCU/semantic-state-machine-graphable
20
+ Project-URL: Issues, https://github.com/TheTrueSCU/semantic-state-machine-graphable/issues
21
+ Description-Content-Type: text/markdown
22
+
23
+ # semantic-state-machine-graphable
24
+
25
+ A library for visualizing `semantic-state-machine` structures and `AuditContext` execution paths as graphs using `graphable`.
26
+
27
+ ## Features
28
+ - **StateMachineGraph**: Visualize the static structure of a `semantic-state-machine.StateMachine`.
29
+ - **AuditContextGraph**: Visualize the execution history of an `AuditContext` as a graph, with edges annotated by transition indices.
30
+
31
+ ## Installation
32
+
33
+ ### For Development
34
+ The project is managed with `uv`. To install dependencies:
35
+ ```bash
36
+ uv sync
37
+ ```
38
+
39
+ ### From PyPI
40
+ ```bash
41
+ pip install semantic-state-machine-graphable
42
+ ```
43
+
44
+ ## Testing
45
+ The project uses `pytest` for testing. Run the test suite with coverage reporting:
46
+ ```bash
47
+ PYTHONPATH=src uv run pytest --cov=semantic_state_machine_graphable --cov-report=term-missing
48
+ ```
49
+
50
+ ## Usage
51
+
52
+ ### State Machine Visualization
53
+ ```python
54
+ from semantic_state_machine import StateMachine
55
+ from semantic_state_machine_graphable.graph import StateMachineGraph
56
+
57
+ sm = StateMachine(...)
58
+ sm.add_transition(...)
59
+
60
+ graph = StateMachineGraph(sm)
61
+ # Now visualize or export the graph
62
+ ```
63
+
64
+ ### Execution Path Visualization
65
+ ```python
66
+ from semantic_state_machine import AuditedStateMachine, AuditContext
67
+ from semantic_state_machine_graphable.graph import AuditContextGraph
68
+
69
+ sm = AuditedStateMachine(...)
70
+ ctx = AuditContext(...)
71
+ # ... execute transitions ...
72
+
73
+ graph = AuditContextGraph(ctx, sm)
74
+ # Now visualize or export the execution path graph
75
+ ```
76
+
77
+ ## License
78
+ This project is licensed under the MIT License.
@@ -0,0 +1,56 @@
1
+ # semantic-state-machine-graphable
2
+
3
+ A library for visualizing `semantic-state-machine` structures and `AuditContext` execution paths as graphs using `graphable`.
4
+
5
+ ## Features
6
+ - **StateMachineGraph**: Visualize the static structure of a `semantic-state-machine.StateMachine`.
7
+ - **AuditContextGraph**: Visualize the execution history of an `AuditContext` as a graph, with edges annotated by transition indices.
8
+
9
+ ## Installation
10
+
11
+ ### For Development
12
+ The project is managed with `uv`. To install dependencies:
13
+ ```bash
14
+ uv sync
15
+ ```
16
+
17
+ ### From PyPI
18
+ ```bash
19
+ pip install semantic-state-machine-graphable
20
+ ```
21
+
22
+ ## Testing
23
+ The project uses `pytest` for testing. Run the test suite with coverage reporting:
24
+ ```bash
25
+ PYTHONPATH=src uv run pytest --cov=semantic_state_machine_graphable --cov-report=term-missing
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ### State Machine Visualization
31
+ ```python
32
+ from semantic_state_machine import StateMachine
33
+ from semantic_state_machine_graphable.graph import StateMachineGraph
34
+
35
+ sm = StateMachine(...)
36
+ sm.add_transition(...)
37
+
38
+ graph = StateMachineGraph(sm)
39
+ # Now visualize or export the graph
40
+ ```
41
+
42
+ ### Execution Path Visualization
43
+ ```python
44
+ from semantic_state_machine import AuditedStateMachine, AuditContext
45
+ from semantic_state_machine_graphable.graph import AuditContextGraph
46
+
47
+ sm = AuditedStateMachine(...)
48
+ ctx = AuditContext(...)
49
+ # ... execute transitions ...
50
+
51
+ graph = AuditContextGraph(ctx, sm)
52
+ # Now visualize or export the execution path graph
53
+ ```
54
+
55
+ ## License
56
+ This project is licensed under the MIT License.
@@ -0,0 +1,46 @@
1
+ [project]
2
+ name = "semantic-state-machine-graphable"
3
+ version = "0.1.4"
4
+ description = "A library for visualizing semantic-state-machine structures and AuditContext execution paths as graphs using graphable."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Richard West", email = "dopplereffect.us@gmail.com" }
8
+ ]
9
+ license = "MIT"
10
+ license-files = ["LICENSE"]
11
+ keywords = ["state-machine", "graphable", "visualization", "audit", "type-safety"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "Programming Language :: Python :: 3.13",
16
+ "Topic :: Software Development :: Libraries :: Python Modules",
17
+ "Topic :: Scientific/Engineering :: Visualization",
18
+ ]
19
+ requires-python = ">=3.13"
20
+ dependencies = [
21
+ "graphable>=0.6.1",
22
+ "semantic-state-machine>=0.1.0",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/TheTrueSCU/semantic-state-machine-graphable"
27
+ Repository = "https://github.com/TheTrueSCU/semantic-state-machine-graphable"
28
+ Issues = "https://github.com/TheTrueSCU/semantic-state-machine-graphable/issues"
29
+
30
+ [build-system]
31
+ requires = ["uv-build>=0.11.0"]
32
+ build-backend = "uv_build"
33
+
34
+ [dependency-groups]
35
+ dev = [
36
+ "pytest>=9.0.3",
37
+ "pytest-cov>=7.1.0",
38
+ "pytest-gitignore>=1.3",
39
+ "pytest-html-plus>=0.5.2",
40
+ "pytest-isort>=4.0.0",
41
+ "pytest-randomly>=4.0.1",
42
+ "pytest-timeout>=2.4.0",
43
+ "pytest-xdist>=3.8.0",
44
+ "ruff>=0.15.10",
45
+ "ty>=0.0.29",
46
+ ]
@@ -0,0 +1,134 @@
1
+ from enum import Enum
2
+ from typing import TypeVar
3
+ from semantic_state_machine import StateMachine, AuditContext
4
+ from graphable import Graph, Graphable
5
+
6
+ S = TypeVar("S", bound=Enum)
7
+ E = TypeVar("E", bound=Enum)
8
+ C = TypeVar("C")
9
+
10
+
11
+ class StateNode[S: Enum](Graphable[S]):
12
+ """A node in the graph representing a state.
13
+
14
+ Args:
15
+ state: The Enum value representing the state.
16
+ """
17
+
18
+ def __init__(self, state: S):
19
+ super().__init__(state)
20
+
21
+
22
+ class StateMachineGraph[S: Enum, E: Enum, C](Graph[StateNode[S]]):
23
+ """A graph representation of a StateMachine's structure.
24
+
25
+ Args:
26
+ sm: The StateMachine instance to visualize.
27
+
28
+ Notes:
29
+ Architectural Intent: Provides a static view of all possible
30
+ transitions defined in the state machine.
31
+ """
32
+
33
+ def __init__(self, sm: StateMachine[S, E, C]):
34
+ super().__init__()
35
+ self._sm = sm
36
+ self._sync()
37
+
38
+ def _get_or_create_node(self, state: S) -> StateNode[S]:
39
+ """Retrieves an existing node for a state or creates a new one."""
40
+ try:
41
+ return self[state]
42
+ except KeyError:
43
+ node = StateNode(state)
44
+ self.add_node(node)
45
+ return node
46
+
47
+ def _sync(self):
48
+ """Builds the Graph from the StateMachine's transitions."""
49
+ for (from_state, event), (to_state, _) in self._sm._transitions.items():
50
+ u = self._get_or_create_node(from_state)
51
+ v = self._get_or_create_node(to_state)
52
+
53
+ if v in u.dependents:
54
+ attrs = u.edge_attributes(v)
55
+ events = attrs.get("events", [])
56
+ if event not in events:
57
+ events.append(event)
58
+ u.set_edge_attribute(v, "events", events)
59
+ u.set_edge_attribute(v, "label", ", ".join(e.name for e in events))
60
+ else:
61
+ u.add_dependent(v, events=[event], label=event.name)
62
+
63
+
64
+ class AuditContextGraph[S: Enum, E: Enum, C](Graph[StateNode[S]]):
65
+ """A graph representation of the execution path recorded in an AuditContext.
66
+
67
+ Args:
68
+ ctx: The AuditContext instance to visualize.
69
+ sm: Optional StateMachine instance to resolve target states.
70
+ If not provided, target states are inferred from the next entry
71
+ in the audit log, meaning the final transition's target state
72
+ cannot be determined.
73
+
74
+ Notes:
75
+ Architectural Intent: Visualizes the actual sequence of states
76
+ visited. Edges are annotated with the sequence of 1-based indices
77
+ from the audit log.
78
+ """
79
+
80
+ def __init__(
81
+ self, ctx: AuditContext[S, E], sm: StateMachine[S, E, C] | None = None
82
+ ):
83
+ super().__init__()
84
+ self._ctx = ctx
85
+ self._sm = sm
86
+ self._sync()
87
+
88
+ def _get_or_create_node(self, state: S) -> StateNode[S]:
89
+ """Retrieves an existing node for a state or creates a new one."""
90
+ try:
91
+ return self[state]
92
+ except KeyError:
93
+ node = StateNode(state)
94
+ self.add_node(node)
95
+ return node
96
+
97
+ def _sync(self):
98
+ """Builds the Graph from the AuditContext's history."""
99
+ audit_data = self._ctx._audit
100
+ for i in range(len(audit_data)):
101
+ from_state, event = audit_data[i]
102
+
103
+ to_state = None
104
+ if self._sm:
105
+ # Use StateMachine to find to_state
106
+ try:
107
+ to_state, _ = self._sm._next_transition(from_state, event)
108
+ except Exception:
109
+ # If SM doesn't have it, try fallback to inference
110
+ pass
111
+
112
+ if to_state is None and i + 1 < len(audit_data):
113
+ # Fallback to inference from next state
114
+ to_state = audit_data[i + 1][0]
115
+
116
+ if to_state is None:
117
+ continue
118
+
119
+ u = self._get_or_create_node(from_state)
120
+ v = self._get_or_create_node(to_state)
121
+
122
+ # The user requested "index (plus one)" which matches 1-based indexing.
123
+ index = i + 1
124
+
125
+ if v in u.dependents:
126
+ attrs = u.edge_attributes(v)
127
+ indices = attrs.get("indices", [])
128
+ indices.append(index)
129
+ u.set_edge_attribute(v, "indices", indices)
130
+ u.set_edge_attribute(
131
+ v, "label", f"{event.name} ({', '.join(map(str, indices))})"
132
+ )
133
+ else:
134
+ u.add_dependent(v, indices=[index], label=f"{event.name} ({index})")