mycorrhizal 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl
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.
- mycorrhizal/_version.py +1 -0
- mycorrhizal/common/__init__.py +15 -3
- mycorrhizal/common/cache.py +114 -0
- mycorrhizal/common/compilation.py +263 -0
- mycorrhizal/common/interface_detection.py +159 -0
- mycorrhizal/common/interfaces.py +3 -50
- mycorrhizal/common/mermaid.py +124 -0
- mycorrhizal/common/wrappers.py +1 -1
- mycorrhizal/hypha/core/builder.py +56 -8
- mycorrhizal/hypha/core/runtime.py +242 -107
- mycorrhizal/hypha/core/specs.py +19 -3
- mycorrhizal/mycelium/__init__.py +174 -0
- mycorrhizal/mycelium/core.py +619 -0
- mycorrhizal/mycelium/exceptions.py +30 -0
- mycorrhizal/mycelium/hypha_bridge.py +1143 -0
- mycorrhizal/mycelium/instance.py +440 -0
- mycorrhizal/mycelium/pn_context.py +276 -0
- mycorrhizal/mycelium/runner.py +165 -0
- mycorrhizal/mycelium/spores_integration.py +655 -0
- mycorrhizal/mycelium/tree_builder.py +102 -0
- mycorrhizal/mycelium/tree_spec.py +197 -0
- mycorrhizal/rhizomorph/README.md +82 -33
- mycorrhizal/rhizomorph/core.py +308 -82
- mycorrhizal/septum/TRANSITION_REFERENCE.md +385 -0
- mycorrhizal/{enoki → septum}/core.py +326 -100
- mycorrhizal/{enoki → septum}/testing_utils.py +7 -7
- mycorrhizal/{enoki → septum}/util.py +44 -21
- mycorrhizal/spores/__init__.py +72 -19
- mycorrhizal/spores/core.py +907 -75
- mycorrhizal/spores/dsl/__init__.py +8 -8
- mycorrhizal/spores/dsl/hypha.py +3 -15
- mycorrhizal/spores/dsl/rhizomorph.py +3 -11
- mycorrhizal/spores/dsl/{enoki.py → septum.py} +26 -77
- mycorrhizal/spores/encoder/json.py +21 -12
- mycorrhizal/spores/extraction.py +14 -11
- mycorrhizal/spores/models.py +75 -20
- mycorrhizal/spores/transport/__init__.py +9 -2
- mycorrhizal/spores/transport/base.py +36 -17
- mycorrhizal/spores/transport/file.py +126 -0
- mycorrhizal-0.2.0.dist-info/METADATA +335 -0
- mycorrhizal-0.2.0.dist-info/RECORD +54 -0
- mycorrhizal-0.1.0.dist-info/METADATA +0 -198
- mycorrhizal-0.1.0.dist-info/RECORD +0 -37
- /mycorrhizal/{enoki → septum}/__init__.py +0 -0
- {mycorrhizal-0.1.0.dist-info → mycorrhizal-0.2.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Shared Mermaid diagram formatting utilities.
|
|
4
|
+
|
|
5
|
+
This module provides common formatting functions for generating Mermaid diagrams
|
|
6
|
+
across Mycorrhizal systems (Septum, Mycelium, etc.). Using these utilities ensures:
|
|
7
|
+
- Consistent visual styling across all systems
|
|
8
|
+
- Single source of truth for formatting logic
|
|
9
|
+
- Bug fixes apply to all systems
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
from mycorrhizal.common.mermaid import format_state_node, format_transition
|
|
13
|
+
|
|
14
|
+
node = format_state_node("state1", "IdleState", is_initial=True)
|
|
15
|
+
edge = format_transition("state1", "state2", "START")
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Optional
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def format_state_node(node_id: str, state_name: str, is_initial: bool = False) -> str:
|
|
24
|
+
"""
|
|
25
|
+
Format a state node for Mermaid diagrams.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
node_id: The unique identifier for this node (e.g., "fsm1_IdleState")
|
|
29
|
+
state_name: The display name for the state (e.g., "IdleState")
|
|
30
|
+
is_initial: Whether this is the initial/entry state
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Mermaid node definition as a string
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
>>> format_state_node("state1", "IdleState", is_initial=True)
|
|
37
|
+
' state1(["IdleState (initial)"])'
|
|
38
|
+
>>> format_state_node("state2", "Running", is_initial=False)
|
|
39
|
+
' state2(["Running"])'
|
|
40
|
+
"""
|
|
41
|
+
display_name = state_name
|
|
42
|
+
if is_initial:
|
|
43
|
+
display_name = f"{state_name} (initial)"
|
|
44
|
+
|
|
45
|
+
# Use stadium shape (rounded rectangle) for states: node_id(["label"])
|
|
46
|
+
return f' {node_id}(["[{display_name}]"])'
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def format_transition(
|
|
50
|
+
from_id: str,
|
|
51
|
+
to_id: str,
|
|
52
|
+
label: Optional[str] = None,
|
|
53
|
+
style: Optional[str] = None
|
|
54
|
+
) -> str:
|
|
55
|
+
"""
|
|
56
|
+
Format a transition edge for Mermaid diagrams.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
from_id: Source node ID
|
|
60
|
+
to_id: Target node ID
|
|
61
|
+
label: Optional transition label (e.g., event name)
|
|
62
|
+
style: Optional edge style (e.g., ".thick" for thick lines)
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Mermaid edge definition as a string
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
>>> format_transition("state1", "state2", "START")
|
|
69
|
+
' state1 -->|START| state2'
|
|
70
|
+
>>> format_transition("state1", "state2")
|
|
71
|
+
' state1 --> state2'
|
|
72
|
+
"""
|
|
73
|
+
edge = f" {from_id} -->"
|
|
74
|
+
if label:
|
|
75
|
+
edge = f"{edge}|{label}|"
|
|
76
|
+
edge = f"{edge} {to_id}"
|
|
77
|
+
|
|
78
|
+
if style:
|
|
79
|
+
edge = f"{edge}{style}"
|
|
80
|
+
|
|
81
|
+
return edge
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def format_subgraph(subgraph_id: str, title: str, content: list[str]) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Format a subgraph for grouping related nodes.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
subgraph_id: Unique identifier for the subgraph
|
|
90
|
+
title: Display title for the subgraph
|
|
91
|
+
content: List of lines containing the subgraph content
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Mermaid subgraph definition as a string
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
>>> content = [
|
|
98
|
+
... ' state1(["Idle"])',
|
|
99
|
+
... ' state2(["Running"])'
|
|
100
|
+
... ]
|
|
101
|
+
>>> format_subgraph("FSM1", "My FSM", content)
|
|
102
|
+
' subgraph FSM1 ["My FSM"]\\n state1(["Idle"])\\n state2(["Running"])\\n end'
|
|
103
|
+
"""
|
|
104
|
+
lines = [f' subgraph {subgraph_id} ["{title}"]']
|
|
105
|
+
lines.extend(content)
|
|
106
|
+
lines.append(" end")
|
|
107
|
+
return "\n".join(lines)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def format_comment(text: str) -> str:
|
|
111
|
+
"""
|
|
112
|
+
Format a comment for Mermaid diagrams.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
text: Comment text
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Mermaid comment as a string
|
|
119
|
+
|
|
120
|
+
Example:
|
|
121
|
+
>>> format_comment("This is a comment")
|
|
122
|
+
' %% This is a comment'
|
|
123
|
+
"""
|
|
124
|
+
return f" %% {text}"
|
mycorrhizal/common/wrappers.py
CHANGED
|
@@ -6,7 +6,7 @@ NetBuilder provides the API for declaratively constructing Petri net specificati
|
|
|
6
6
|
Used within @pn.net decorated functions.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from typing import Optional, Callable, List, Dict, Type, Any
|
|
9
|
+
from typing import Optional, Callable, List, Dict, Type, Any, Union
|
|
10
10
|
from .specs import (
|
|
11
11
|
NetSpec,
|
|
12
12
|
PlaceSpec,
|
|
@@ -54,14 +54,52 @@ class NetBuilder:
|
|
|
54
54
|
|
|
55
55
|
def place(
|
|
56
56
|
self,
|
|
57
|
-
|
|
57
|
+
name_or_func: Union[str, Callable, None] = None,
|
|
58
58
|
type: PlaceType = PlaceType.BAG,
|
|
59
59
|
state_factory: Optional[Callable] = None,
|
|
60
|
-
) -> PlaceRef:
|
|
61
|
-
"""Declare a regular place
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
) -> Union[PlaceRef, Callable]:
|
|
61
|
+
"""Declare a regular place.
|
|
62
|
+
|
|
63
|
+
Can be used in three ways:
|
|
64
|
+
|
|
65
|
+
1. As a method call (returns PlaceRef for use in arcs):
|
|
66
|
+
queue = builder.place("queue", type=PlaceType.QUEUE)
|
|
67
|
+
|
|
68
|
+
2. As a decorator without parens (infers name from function):
|
|
69
|
+
@builder.place
|
|
70
|
+
def queue(bb):
|
|
71
|
+
return bb.tokens
|
|
72
|
+
|
|
73
|
+
3. As a decorator with custom name:
|
|
74
|
+
@builder.place("custom_name")
|
|
75
|
+
def my_func(bb):
|
|
76
|
+
return bb.tokens
|
|
77
|
+
"""
|
|
78
|
+
# Case 1: Used as decorator without parens - first arg is the function
|
|
79
|
+
if callable(name_or_func):
|
|
80
|
+
func = name_or_func
|
|
81
|
+
place_name = func.__name__
|
|
82
|
+
place_spec = PlaceSpec(place_name, type, handler=func, state_factory=state_factory)
|
|
83
|
+
self.spec.places[place_name] = place_spec
|
|
84
|
+
return PlaceRef(place_name, self.spec)
|
|
85
|
+
|
|
86
|
+
# Case 2 & 3: Used with explicit name (as method call or decorator with args)
|
|
87
|
+
# or called without any args (need to return decorator)
|
|
88
|
+
if isinstance(name_or_func, str):
|
|
89
|
+
name = name_or_func
|
|
90
|
+
place_spec = PlaceSpec(name, type, state_factory=state_factory)
|
|
91
|
+
self.spec.places[name] = place_spec
|
|
92
|
+
# Return PlaceRef - it's callable via __call__ for decorator use
|
|
93
|
+
return PlaceRef(name, self.spec)
|
|
94
|
+
|
|
95
|
+
# Case 4: Called without any args - shouldn't happen but handle gracefully
|
|
96
|
+
# This would be like @builder.place() with empty parens
|
|
97
|
+
def decorator(func: Callable) -> PlaceRef:
|
|
98
|
+
place_name = func.__name__
|
|
99
|
+
place_spec = PlaceSpec(place_name, type, handler=func, state_factory=state_factory)
|
|
100
|
+
self.spec.places[place_name] = place_spec
|
|
101
|
+
return PlaceRef(place_name, self.spec)
|
|
102
|
+
return decorator
|
|
65
103
|
|
|
66
104
|
def io_input_place(self):
|
|
67
105
|
"""Decorator for IOInputPlace with async generator"""
|
|
@@ -98,7 +136,17 @@ class NetBuilder:
|
|
|
98
136
|
guard: Optional[GuardSpec] = None,
|
|
99
137
|
state_factory: Optional[Callable] = None,
|
|
100
138
|
):
|
|
101
|
-
"""Decorator for transition function
|
|
139
|
+
"""Decorator for transition function.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
guard: Optional guard specification
|
|
143
|
+
state_factory: Optional state factory for transition state
|
|
144
|
+
|
|
145
|
+
Usage:
|
|
146
|
+
@builder.transition()
|
|
147
|
+
async def my_transition(consumed, bb, timebase):
|
|
148
|
+
yield {output: token}
|
|
149
|
+
"""
|
|
102
150
|
|
|
103
151
|
def decorator(func: Callable) -> TransitionRef:
|
|
104
152
|
name = func.__name__
|