python-statemachine 2.1.2__py3-none-any.whl → 2.3.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.
- {python_statemachine-2.1.2.dist-info → python_statemachine-2.3.0.dist-info}/METADATA +86 -25
- python_statemachine-2.3.0.dist-info/RECORD +28 -0
- statemachine/__init__.py +1 -1
- statemachine/callbacks.py +106 -76
- statemachine/contrib/diagram.py +20 -6
- statemachine/dispatcher.py +72 -37
- statemachine/event.py +21 -20
- statemachine/exceptions.py +9 -3
- statemachine/factory.py +72 -9
- statemachine/graph.py +6 -0
- statemachine/locale/en/LC_MESSAGES/statemachine.po +40 -26
- statemachine/locale/pt_BR/LC_MESSAGES/statemachine.po +60 -39
- statemachine/mixins.py +1 -3
- statemachine/signature.py +15 -8
- statemachine/state.py +22 -25
- statemachine/statemachine.py +125 -97
- statemachine/states.py +6 -4
- statemachine/transition.py +35 -26
- statemachine/utils.py +19 -0
- python_statemachine-2.1.2.dist-info/RECORD +0 -30
- statemachine/locale/en/LC_MESSAGES/statemachine.mo +0 -0
- statemachine/locale/pt_BR/LC_MESSAGES/statemachine.mo +0 -0
- {python_statemachine-2.1.2.dist-info → python_statemachine-2.3.0.dist-info}/LICENSE +0 -0
- {python_statemachine-2.1.2.dist-info → python_statemachine-2.3.0.dist-info}/WHEEL +0 -0
statemachine/dispatcher.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from collections import namedtuple
|
|
2
2
|
from operator import attrgetter
|
|
3
3
|
from typing import Any
|
|
4
|
+
from typing import Generator
|
|
5
|
+
from typing import Tuple
|
|
4
6
|
|
|
5
7
|
from .signature import SignatureAdapter
|
|
6
8
|
|
|
@@ -14,21 +16,14 @@ class ObjectConfig(namedtuple("ObjectConfig", "obj skip_attrs resolver_id")):
|
|
|
14
16
|
"""
|
|
15
17
|
|
|
16
18
|
@classmethod
|
|
17
|
-
def from_obj(cls, obj, skip_attrs=None):
|
|
19
|
+
def from_obj(cls, obj, skip_attrs=None) -> "ObjectConfig":
|
|
18
20
|
if isinstance(obj, ObjectConfig):
|
|
19
21
|
return obj
|
|
20
22
|
else:
|
|
21
|
-
return cls(obj,
|
|
22
|
-
|
|
23
|
-
def getattr(self, attr):
|
|
24
|
-
if attr in self.skip_attrs:
|
|
25
|
-
return
|
|
26
|
-
return getattr(self.obj, attr, None)
|
|
23
|
+
return cls(obj, skip_attrs or set(), str(id(obj)))
|
|
27
24
|
|
|
28
25
|
|
|
29
26
|
class WrapSearchResult:
|
|
30
|
-
is_empty = False
|
|
31
|
-
|
|
32
27
|
def __init__(self, attribute, resolver_id) -> None:
|
|
33
28
|
self.attribute = attribute
|
|
34
29
|
self.resolver_id = resolver_id
|
|
@@ -41,15 +36,11 @@ class WrapSearchResult:
|
|
|
41
36
|
def wrap(self): # pragma: no cover
|
|
42
37
|
pass
|
|
43
38
|
|
|
44
|
-
def __call__(self, *args: Any, **kwds: Any) -> Any:
|
|
39
|
+
async def __call__(self, *args: Any, **kwds: Any) -> Any:
|
|
45
40
|
if self._cache is None:
|
|
46
41
|
self._cache = self.wrap()
|
|
47
42
|
assert self._cache
|
|
48
|
-
return self._cache(*args, **kwds)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class EmptyWrapSearchResult(WrapSearchResult):
|
|
52
|
-
is_empty = True
|
|
43
|
+
return await self._cache(*args, **kwds)
|
|
53
44
|
|
|
54
45
|
|
|
55
46
|
class CallableSearchResult(WrapSearchResult):
|
|
@@ -72,7 +63,7 @@ class AttributeCallableSearchResult(WrapSearchResult):
|
|
|
72
63
|
# we'll build a method that get's the fresh value for each call
|
|
73
64
|
getter = attrgetter(self.attribute)
|
|
74
65
|
|
|
75
|
-
def wrapper(*args, **kwargs):
|
|
66
|
+
async def wrapper(*args, **kwargs):
|
|
76
67
|
return getter(self.obj)
|
|
77
68
|
|
|
78
69
|
return wrapper
|
|
@@ -86,39 +77,83 @@ class EventSearchResult(WrapSearchResult):
|
|
|
86
77
|
def wrap(self):
|
|
87
78
|
"Events already have the 'machine' parameter defined."
|
|
88
79
|
|
|
89
|
-
def wrapper(*args, **kwargs):
|
|
80
|
+
async def wrapper(*args, **kwargs):
|
|
90
81
|
kwargs.pop("machine", None)
|
|
91
|
-
return self.func(*args, **kwargs)
|
|
82
|
+
return await self.func(*args, **kwargs)
|
|
92
83
|
|
|
93
84
|
return wrapper
|
|
94
85
|
|
|
95
86
|
|
|
96
|
-
def
|
|
97
|
-
|
|
98
|
-
|
|
87
|
+
def _search_callable_attr_is_property(
|
|
88
|
+
attr, configs: Tuple[ObjectConfig, ...]
|
|
89
|
+
) -> "WrapSearchResult | None":
|
|
90
|
+
# if the attr is a property, we'll try to find the object that has the
|
|
91
|
+
# property on the configs
|
|
92
|
+
attr_name = attr.fget.__name__
|
|
93
|
+
for obj, _skip_attrs, resolver_id in configs:
|
|
94
|
+
func = getattr(type(obj), attr_name, None)
|
|
95
|
+
if func is not None and func is attr:
|
|
96
|
+
return AttributeCallableSearchResult(attr_name, obj, resolver_id)
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _search_callable_attr_is_callable(attr, configs: Tuple[ObjectConfig, ...]) -> WrapSearchResult:
|
|
101
|
+
# if the attr is an unbounded method, we'll try to find the bounded method
|
|
102
|
+
# on the configs
|
|
103
|
+
if not hasattr(attr, "__self__"):
|
|
104
|
+
for obj, _skip_attrs, resolver_id in configs:
|
|
105
|
+
func = getattr(obj, attr.__name__, None)
|
|
106
|
+
if func is not None and func.__func__ is attr:
|
|
107
|
+
return CallableSearchResult(attr.__name__, func, resolver_id)
|
|
108
|
+
|
|
109
|
+
return CallableSearchResult(attr, attr, None)
|
|
99
110
|
|
|
100
|
-
for config in configs:
|
|
101
|
-
func = config.getattr(attr)
|
|
102
|
-
if func is not None:
|
|
103
|
-
if not callable(func):
|
|
104
|
-
return AttributeCallableSearchResult(
|
|
105
|
-
attr, config.obj, config.resolver_id
|
|
106
|
-
)
|
|
107
111
|
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
def _search_callable_in_configs(
|
|
113
|
+
attr, configs: Tuple[ObjectConfig, ...]
|
|
114
|
+
) -> Generator[WrapSearchResult, None, None]:
|
|
115
|
+
for obj, skip_attrs, resolver_id in configs:
|
|
116
|
+
if attr in skip_attrs:
|
|
117
|
+
continue
|
|
110
118
|
|
|
111
|
-
|
|
119
|
+
if not hasattr(obj, attr):
|
|
120
|
+
continue
|
|
112
121
|
|
|
113
|
-
|
|
122
|
+
func = getattr(obj, attr)
|
|
123
|
+
if not callable(func):
|
|
124
|
+
yield AttributeCallableSearchResult(attr, obj, resolver_id)
|
|
114
125
|
|
|
126
|
+
if getattr(func, "_is_sm_event", False):
|
|
127
|
+
yield EventSearchResult(attr, func, resolver_id)
|
|
115
128
|
|
|
116
|
-
|
|
129
|
+
yield CallableSearchResult(attr, func, resolver_id)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def search_callable(
|
|
133
|
+
attr, configs: Tuple[ObjectConfig, ...]
|
|
134
|
+
) -> Generator[WrapSearchResult, None, None]: # noqa: C901
|
|
135
|
+
if isinstance(attr, property):
|
|
136
|
+
result = _search_callable_attr_is_property(attr, configs)
|
|
137
|
+
if result is not None:
|
|
138
|
+
yield result
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
if callable(attr):
|
|
142
|
+
yield _search_callable_attr_is_callable(attr, configs)
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
yield from _search_callable_in_configs(attr, configs)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def resolver_factory(objects: Tuple[ObjectConfig, ...]):
|
|
117
149
|
"""Factory that returns a configured resolver."""
|
|
118
150
|
|
|
119
|
-
|
|
151
|
+
def resolver(attr) -> Generator[WrapSearchResult, None, None]:
|
|
152
|
+
yield from search_callable(attr, objects)
|
|
153
|
+
|
|
154
|
+
return resolver
|
|
120
155
|
|
|
121
|
-
def wrapper(attr):
|
|
122
|
-
return search_callable(attr, *objects)
|
|
123
156
|
|
|
124
|
-
|
|
157
|
+
def resolver_factory_from_objects(*objects: Tuple[Any, ...]):
|
|
158
|
+
configs: Tuple[ObjectConfig, ...] = tuple(ObjectConfig.from_obj(o) for o in objects)
|
|
159
|
+
return resolver_factory(configs)
|
statemachine/event.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
from functools import partial
|
|
1
2
|
from typing import TYPE_CHECKING
|
|
2
3
|
|
|
4
|
+
from statemachine.utils import run_async_from_sync
|
|
5
|
+
|
|
3
6
|
from .event_data import EventData
|
|
4
7
|
from .event_data import TriggerData
|
|
5
8
|
from .exceptions import TransitionNotAllowed
|
|
@@ -15,28 +18,28 @@ class Event:
|
|
|
15
18
|
def __repr__(self):
|
|
16
19
|
return f"{type(self).__name__}({self.name!r})"
|
|
17
20
|
|
|
18
|
-
def trigger(self, machine: "StateMachine", *args, **kwargs):
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
return self._trigger(trigger_data)
|
|
21
|
+
async def trigger(self, machine: "StateMachine", *args, **kwargs):
|
|
22
|
+
trigger_data = TriggerData(
|
|
23
|
+
machine=machine,
|
|
24
|
+
event=self.name,
|
|
25
|
+
args=args,
|
|
26
|
+
kwargs=kwargs,
|
|
27
|
+
)
|
|
28
|
+
trigger_wrapper = partial(self._trigger, trigger_data=trigger_data)
|
|
28
29
|
|
|
29
|
-
return machine._process(trigger_wrapper)
|
|
30
|
+
return await machine._process(trigger_wrapper)
|
|
30
31
|
|
|
31
|
-
def _trigger(self, trigger_data: TriggerData):
|
|
32
|
+
async def _trigger(self, trigger_data: TriggerData):
|
|
32
33
|
event_data = None
|
|
34
|
+
await trigger_data.machine._ensure_is_initialized()
|
|
35
|
+
|
|
33
36
|
state = trigger_data.machine.current_state
|
|
34
37
|
for transition in state.transitions:
|
|
35
38
|
if not transition.match(trigger_data.event):
|
|
36
39
|
continue
|
|
37
40
|
|
|
38
41
|
event_data = EventData(trigger_data=trigger_data, transition=transition)
|
|
39
|
-
if transition.execute(event_data):
|
|
42
|
+
if await transition.execute(event_data):
|
|
40
43
|
event_data.executed = True
|
|
41
44
|
break
|
|
42
45
|
else:
|
|
@@ -46,17 +49,15 @@ class Event:
|
|
|
46
49
|
return event_data.result if event_data else None
|
|
47
50
|
|
|
48
51
|
|
|
49
|
-
def trigger_event_factory(
|
|
52
|
+
def trigger_event_factory(event_instance: Event):
|
|
50
53
|
"""Build a method that sends specific `event` to the machine"""
|
|
51
|
-
event_instance = Event(event)
|
|
52
54
|
|
|
53
55
|
def trigger_event(self, *args, **kwargs):
|
|
54
|
-
return event_instance.trigger(self, *args, **kwargs)
|
|
55
|
-
|
|
56
|
-
trigger_event.name = event
|
|
57
|
-
trigger_event.identifier = event
|
|
58
|
-
trigger_event._is_sm_event = True
|
|
56
|
+
return run_async_from_sync(event_instance.trigger(self, *args, **kwargs))
|
|
59
57
|
|
|
58
|
+
trigger_event.name = event_instance.name # type: ignore[attr-defined]
|
|
59
|
+
trigger_event.identifier = event_instance.name # type: ignore[attr-defined]
|
|
60
|
+
trigger_event._is_sm_event = True # type: ignore[attr-defined]
|
|
60
61
|
return trigger_event
|
|
61
62
|
|
|
62
63
|
|
statemachine/exceptions.py
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
1
3
|
from .i18n import _
|
|
2
4
|
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .state import State
|
|
7
|
+
|
|
3
8
|
|
|
4
9
|
class StateMachineError(Exception):
|
|
5
10
|
"Base exception for this project, all exceptions that can be raised inherit from this class."
|
|
@@ -12,9 +17,10 @@ class InvalidDefinition(StateMachineError):
|
|
|
12
17
|
class InvalidStateValue(InvalidDefinition):
|
|
13
18
|
"The current model state value is not mapped to a state definition."
|
|
14
19
|
|
|
15
|
-
def __init__(self, value):
|
|
20
|
+
def __init__(self, value, msg=None):
|
|
16
21
|
self.value = value
|
|
17
|
-
msg
|
|
22
|
+
if msg is None:
|
|
23
|
+
msg = _("{!r} is not a valid state value.").format(value)
|
|
18
24
|
super().__init__(msg)
|
|
19
25
|
|
|
20
26
|
|
|
@@ -25,7 +31,7 @@ class AttrNotFound(InvalidDefinition):
|
|
|
25
31
|
class TransitionNotAllowed(StateMachineError):
|
|
26
32
|
"Raised when there's no transition that can run from the current :ref:`state`."
|
|
27
33
|
|
|
28
|
-
def __init__(self, event, state):
|
|
34
|
+
def __init__(self, event: str, state: "State"):
|
|
29
35
|
self.event = event
|
|
30
36
|
self.state = state
|
|
31
37
|
msg = _("Can't {} when in {}.").format(self.event, self.state.name)
|
statemachine/factory.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import warnings
|
|
1
2
|
from typing import TYPE_CHECKING
|
|
2
3
|
from typing import Any
|
|
3
4
|
from typing import Dict
|
|
@@ -9,6 +10,7 @@ from . import registry
|
|
|
9
10
|
from .event import Event
|
|
10
11
|
from .event import trigger_event_factory
|
|
11
12
|
from .exceptions import InvalidDefinition
|
|
13
|
+
from .graph import iterate_states_and_transitions
|
|
12
14
|
from .graph import visit_connected_states
|
|
13
15
|
from .i18n import _
|
|
14
16
|
from .state import State
|
|
@@ -18,7 +20,15 @@ from .transition_list import TransitionList
|
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
class StateMachineMetaclass(type):
|
|
21
|
-
|
|
23
|
+
"Metaclass for constructing StateMachine classes"
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
cls,
|
|
27
|
+
name: str,
|
|
28
|
+
bases: Tuple[type],
|
|
29
|
+
attrs: Dict[str, Any],
|
|
30
|
+
strict_states: bool = False,
|
|
31
|
+
) -> None:
|
|
22
32
|
super().__init__(name, bases, attrs)
|
|
23
33
|
registry.register(cls)
|
|
24
34
|
cls.name = cls.__name__
|
|
@@ -27,7 +37,9 @@ class StateMachineMetaclass(type):
|
|
|
27
37
|
"""Map of ``state.value`` to the corresponding :ref:`state`."""
|
|
28
38
|
|
|
29
39
|
cls._abstract = True
|
|
40
|
+
cls._strict_states = strict_states
|
|
30
41
|
cls._events: Dict[str, Event] = {}
|
|
42
|
+
cls._protected_attrs: set = set()
|
|
31
43
|
|
|
32
44
|
cls.add_inherited(bases)
|
|
33
45
|
cls.add_from_attributes(attrs)
|
|
@@ -40,12 +52,12 @@ class StateMachineMetaclass(type):
|
|
|
40
52
|
cls.final_states: List[State] = [state for state in cls.states if state.final]
|
|
41
53
|
|
|
42
54
|
cls._check()
|
|
55
|
+
cls._setup()
|
|
43
56
|
|
|
44
57
|
if TYPE_CHECKING:
|
|
45
58
|
"""Makes mypy happy with dynamic created attributes"""
|
|
46
59
|
|
|
47
|
-
def __getattr__(self, attribute: str) -> Any:
|
|
48
|
-
...
|
|
60
|
+
def __getattr__(self, attribute: str) -> Any: ...
|
|
49
61
|
|
|
50
62
|
def _check(cls):
|
|
51
63
|
has_states = bool(cls.states)
|
|
@@ -66,6 +78,8 @@ class StateMachineMetaclass(type):
|
|
|
66
78
|
cls._check_initial_state()
|
|
67
79
|
cls._check_final_states()
|
|
68
80
|
cls._check_disconnected_state()
|
|
81
|
+
cls._check_trap_states()
|
|
82
|
+
cls._check_reachable_final_states()
|
|
69
83
|
|
|
70
84
|
def _check_initial_state(cls):
|
|
71
85
|
initials = [s for s in cls.states if s.initial]
|
|
@@ -73,7 +87,7 @@ class StateMachineMetaclass(type):
|
|
|
73
87
|
raise InvalidDefinition(
|
|
74
88
|
_(
|
|
75
89
|
"There should be one and only one initial state. "
|
|
76
|
-
"
|
|
90
|
+
"You currently have these: {!r}"
|
|
77
91
|
).format([s.id for s in initials])
|
|
78
92
|
)
|
|
79
93
|
|
|
@@ -84,11 +98,44 @@ class StateMachineMetaclass(type):
|
|
|
84
98
|
|
|
85
99
|
if final_state_with_invalid_transitions:
|
|
86
100
|
raise InvalidDefinition(
|
|
87
|
-
_(
|
|
88
|
-
|
|
89
|
-
)
|
|
101
|
+
_("Cannot declare transitions from final state. Invalid state(s): {}").format(
|
|
102
|
+
[s.id for s in final_state_with_invalid_transitions]
|
|
103
|
+
)
|
|
90
104
|
)
|
|
91
105
|
|
|
106
|
+
def _check_trap_states(cls):
|
|
107
|
+
trap_states = [s for s in cls.states if not s.final and not s.transitions]
|
|
108
|
+
if trap_states:
|
|
109
|
+
message = _(
|
|
110
|
+
"All non-final states should have at least one outgoing transition. "
|
|
111
|
+
"These states have no outgoing transition: {!r}"
|
|
112
|
+
).format([s.id for s in trap_states])
|
|
113
|
+
if cls._strict_states:
|
|
114
|
+
raise InvalidDefinition(message)
|
|
115
|
+
else:
|
|
116
|
+
warnings.warn(message, UserWarning, stacklevel=4)
|
|
117
|
+
|
|
118
|
+
def _check_reachable_final_states(cls):
|
|
119
|
+
if not any(s.final for s in cls.states):
|
|
120
|
+
return # No need to check final reachability
|
|
121
|
+
disconnected_states = cls._states_without_path_to_final_states()
|
|
122
|
+
if disconnected_states:
|
|
123
|
+
message = _(
|
|
124
|
+
"All non-final states should have at least one path to a final state. "
|
|
125
|
+
"These states have no path to a final state: {!r}"
|
|
126
|
+
).format([s.id for s in disconnected_states])
|
|
127
|
+
if cls._strict_states:
|
|
128
|
+
raise InvalidDefinition(message)
|
|
129
|
+
else:
|
|
130
|
+
warnings.warn(message, UserWarning, stacklevel=1)
|
|
131
|
+
|
|
132
|
+
def _states_without_path_to_final_states(cls):
|
|
133
|
+
return [
|
|
134
|
+
state
|
|
135
|
+
for state in cls.states
|
|
136
|
+
if not state.final and not any(s.final for s in visit_connected_states(state))
|
|
137
|
+
]
|
|
138
|
+
|
|
92
139
|
def _disconnected_states(cls, starting_state):
|
|
93
140
|
visitable_states = set(visit_connected_states(starting_state))
|
|
94
141
|
return set(cls.states) - visitable_states
|
|
@@ -104,6 +151,23 @@ class StateMachineMetaclass(type):
|
|
|
104
151
|
).format([s.id for s in disconnected_states])
|
|
105
152
|
)
|
|
106
153
|
|
|
154
|
+
def _setup(cls):
|
|
155
|
+
for visited in iterate_states_and_transitions(cls.states):
|
|
156
|
+
visited._setup()
|
|
157
|
+
|
|
158
|
+
cls._protected_attrs = {
|
|
159
|
+
"_abstract",
|
|
160
|
+
"model",
|
|
161
|
+
"state_field",
|
|
162
|
+
"start_value",
|
|
163
|
+
"initial_state",
|
|
164
|
+
"final_states",
|
|
165
|
+
"states",
|
|
166
|
+
"_events",
|
|
167
|
+
"states_map",
|
|
168
|
+
"send",
|
|
169
|
+
} | {s.id for s in cls.states}
|
|
170
|
+
|
|
107
171
|
def add_inherited(cls, bases):
|
|
108
172
|
for base in bases:
|
|
109
173
|
for state in getattr(base, "states", []):
|
|
@@ -158,8 +222,7 @@ class StateMachineMetaclass(type):
|
|
|
158
222
|
if event not in cls._events:
|
|
159
223
|
event_instance = Event(event)
|
|
160
224
|
cls._events[event] = event_instance
|
|
161
|
-
|
|
162
|
-
setattr(cls, event, event_trigger)
|
|
225
|
+
setattr(cls, event, trigger_event_factory(event_instance))
|
|
163
226
|
|
|
164
227
|
return cls._events[event]
|
|
165
228
|
|
statemachine/graph.py
CHANGED
|
@@ -1,66 +1,80 @@
|
|
|
1
1
|
# This file is distributed under the same license as the PROJECT project.
|
|
2
|
-
# Fernando Macedo <fgmacedo@gmail.com>,
|
|
2
|
+
# Fernando Macedo <fgmacedo@gmail.com>, 2024.
|
|
3
3
|
#
|
|
4
4
|
msgid ""
|
|
5
5
|
msgstr ""
|
|
6
|
-
"Project-Id-Version: 2.
|
|
6
|
+
"Project-Id-Version: 2.3.0\n"
|
|
7
7
|
"Report-Msgid-Bugs-To: fgmacedo@gmail.com\n"
|
|
8
8
|
"POT-Creation-Date: 2023-03-04 16:10-0300\n"
|
|
9
|
-
"PO-Revision-Date:
|
|
9
|
+
"PO-Revision-Date: 2024-06-07 17:41-0300\n"
|
|
10
10
|
"Last-Translator: Fernando Macedo <fgmacedo@gmail.com>\n"
|
|
11
11
|
"MIME-Version: 1.0\n"
|
|
12
12
|
"Content-Type: text/plain; charset=utf-8\n"
|
|
13
13
|
"Content-Transfer-Encoding: 8bit\n"
|
|
14
14
|
"Generated-By: Babel 2.12.1\n"
|
|
15
15
|
|
|
16
|
-
#: statemachine/callbacks.py:
|
|
17
|
-
msgid "Callback {!r} not property configured."
|
|
18
|
-
msgstr ""
|
|
19
|
-
|
|
20
|
-
#: statemachine/dispatcher.py:35
|
|
16
|
+
#: statemachine/callbacks.py:289
|
|
21
17
|
msgid "Did not found name '{}' from model or statemachine"
|
|
22
18
|
msgstr ""
|
|
23
19
|
|
|
24
|
-
#: statemachine/exceptions.py:
|
|
20
|
+
#: statemachine/exceptions.py:23
|
|
25
21
|
msgid "{!r} is not a valid state value."
|
|
26
22
|
msgstr ""
|
|
27
23
|
|
|
28
|
-
#: statemachine/exceptions.py:
|
|
24
|
+
#: statemachine/exceptions.py:37
|
|
29
25
|
msgid "Can't {} when in {}."
|
|
30
26
|
msgstr ""
|
|
31
27
|
|
|
32
|
-
#: statemachine/factory.py:
|
|
33
|
-
msgid ""
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
#: statemachine/factory.py:73
|
|
29
|
+
msgid "There are no states."
|
|
30
|
+
msgstr ""
|
|
31
|
+
|
|
32
|
+
#: statemachine/factory.py:76
|
|
33
|
+
msgid "There are no events."
|
|
36
34
|
msgstr ""
|
|
37
35
|
|
|
38
|
-
#: statemachine/factory.py:
|
|
36
|
+
#: statemachine/factory.py:88
|
|
39
37
|
msgid ""
|
|
40
|
-
"There
|
|
41
|
-
"
|
|
38
|
+
"There should be one and only one initial state. You currently have these:"
|
|
39
|
+
" {!r}"
|
|
42
40
|
msgstr ""
|
|
43
41
|
|
|
44
|
-
#: statemachine/factory.py:
|
|
45
|
-
msgid "
|
|
42
|
+
#: statemachine/factory.py:101
|
|
43
|
+
msgid "Cannot declare transitions from final state. Invalid state(s): {}"
|
|
46
44
|
msgstr ""
|
|
47
45
|
|
|
48
|
-
#: statemachine/factory.py:
|
|
49
|
-
msgid "
|
|
46
|
+
#: statemachine/factory.py:109
|
|
47
|
+
msgid ""
|
|
48
|
+
"All non-final states should have at least one outgoing transition. These "
|
|
49
|
+
"states have no outgoing transition: {!r}"
|
|
50
50
|
msgstr ""
|
|
51
51
|
|
|
52
|
-
#: statemachine/factory.py:
|
|
53
|
-
msgid "
|
|
52
|
+
#: statemachine/factory.py:123
|
|
53
|
+
msgid ""
|
|
54
|
+
"All non-final states should have at least one path to a final state. "
|
|
55
|
+
"These states have no path to a final state: {!r}"
|
|
54
56
|
msgstr ""
|
|
55
57
|
|
|
56
|
-
#: statemachine/
|
|
58
|
+
#: statemachine/factory.py:147
|
|
59
|
+
msgid ""
|
|
60
|
+
"There are unreachable states. The statemachine graph should have a single"
|
|
61
|
+
" component. Disconnected states: {}"
|
|
62
|
+
msgstr ""
|
|
63
|
+
|
|
64
|
+
#: statemachine/mixins.py:23
|
|
57
65
|
msgid "{!r} is not a valid state machine name."
|
|
58
66
|
msgstr ""
|
|
59
67
|
|
|
60
|
-
#: statemachine/state.py:
|
|
68
|
+
#: statemachine/state.py:152
|
|
61
69
|
msgid "State overriding is not allowed. Trying to add '{}' to {}"
|
|
62
70
|
msgstr ""
|
|
63
71
|
|
|
64
|
-
#: statemachine/statemachine.py:
|
|
72
|
+
#: statemachine/statemachine.py:86
|
|
65
73
|
msgid "There are no states or transitions."
|
|
66
74
|
msgstr ""
|
|
75
|
+
|
|
76
|
+
#: statemachine/statemachine.py:249
|
|
77
|
+
msgid ""
|
|
78
|
+
"There's no current state set. In async code, did you activate the initial"
|
|
79
|
+
" state? (e.g., `await sm.activate_initial_state()`)"
|
|
80
|
+
msgstr ""
|
|
@@ -1,70 +1,91 @@
|
|
|
1
|
-
# This file is distributed under the same license as the
|
|
2
|
-
# Fernando Macedo <fgmacedo@gmail.com>,
|
|
1
|
+
# This file is distributed under the same license as the project.
|
|
2
|
+
# Fernando Macedo <fgmacedo@gmail.com>, 2024.
|
|
3
3
|
#
|
|
4
4
|
msgid ""
|
|
5
5
|
msgstr ""
|
|
6
|
-
"Project-Id-Version:
|
|
6
|
+
"Project-Id-Version: 2.3.0\n"
|
|
7
7
|
"Report-Msgid-Bugs-To: fgmacedo@gmail.com\n"
|
|
8
8
|
"POT-Creation-Date: 2023-03-04 16:10-0300\n"
|
|
9
|
-
"PO-Revision-Date:
|
|
9
|
+
"PO-Revision-Date: 2024-06-07 17:41-0300\n"
|
|
10
10
|
"Last-Translator: Fernando Macedo <fgmacedo@gmail.com>\n"
|
|
11
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
11
12
|
"MIME-Version: 1.0\n"
|
|
12
13
|
"Content-Type: text/plain; charset=utf-8\n"
|
|
13
14
|
"Content-Transfer-Encoding: 8bit\n"
|
|
14
|
-
"Generated-By: Babel 2.
|
|
15
|
+
"Generated-By: Babel 2.14.0\n"
|
|
15
16
|
|
|
16
|
-
#: statemachine/callbacks.py:
|
|
17
|
-
msgid "Callback {!r} not property configured."
|
|
18
|
-
msgstr "Callback {!r} não está configurado corretamente."
|
|
19
|
-
|
|
20
|
-
#: statemachine/dispatcher.py:35
|
|
17
|
+
#: statemachine/callbacks.py:289
|
|
21
18
|
msgid "Did not found name '{}' from model or statemachine"
|
|
22
|
-
msgstr "Não
|
|
19
|
+
msgstr "Não encontrou o nome '{}' no modelo ou na máquina de estados"
|
|
23
20
|
|
|
24
|
-
#: statemachine/exceptions.py:
|
|
21
|
+
#: statemachine/exceptions.py:23
|
|
25
22
|
msgid "{!r} is not a valid state value."
|
|
26
23
|
msgstr "{!r} não é um valor de estado válido."
|
|
27
24
|
|
|
28
|
-
#: statemachine/exceptions.py:
|
|
25
|
+
#: statemachine/exceptions.py:37
|
|
29
26
|
msgid "Can't {} when in {}."
|
|
30
|
-
msgstr "Não é possível {} quando em {}."
|
|
31
|
-
|
|
32
|
-
#: statemachine/factory.py:35
|
|
33
|
-
msgid ""
|
|
34
|
-
"There should be one and only one initial state. Your currently have "
|
|
35
|
-
"these: {!r}"
|
|
36
|
-
msgstr ""
|
|
37
|
-
"Deve haver um e apenas um estado inicial. Atualmente, você tem "
|
|
38
|
-
"os seguintes: {!r}"
|
|
27
|
+
msgstr "Não é possível {} quando está em {}."
|
|
39
28
|
|
|
40
|
-
#: statemachine/factory.py:
|
|
41
|
-
msgid ""
|
|
42
|
-
"There are unreachable states. The statemachine graph should have a single"
|
|
43
|
-
" component. Disconnected states: {}"
|
|
44
|
-
msgstr ""
|
|
45
|
-
"Há estados inalcançáveis. O grafo da máquina de estados deve ter apenas um"
|
|
46
|
-
" componente. Estados desconectados: {}"
|
|
47
|
-
|
|
48
|
-
#: statemachine/factory.py:69
|
|
29
|
+
#: statemachine/factory.py:73
|
|
49
30
|
msgid "There are no states."
|
|
50
31
|
msgstr "Não há estados."
|
|
51
32
|
|
|
52
|
-
#: statemachine/factory.py:
|
|
33
|
+
#: statemachine/factory.py:76
|
|
53
34
|
msgid "There are no events."
|
|
54
35
|
msgstr "Não há eventos."
|
|
55
36
|
|
|
56
|
-
#: statemachine/factory.py:
|
|
37
|
+
#: statemachine/factory.py:88
|
|
38
|
+
msgid ""
|
|
39
|
+
"There should be one and only one initial state. You currently have these:"
|
|
40
|
+
" {!r}"
|
|
41
|
+
msgstr "Deve haver um e apenas um estado inicial. Você atualmente tem estes: {!r}"
|
|
42
|
+
|
|
43
|
+
#: statemachine/factory.py:101
|
|
57
44
|
msgid "Cannot declare transitions from final state. Invalid state(s): {}"
|
|
58
|
-
msgstr "
|
|
45
|
+
msgstr ""
|
|
46
|
+
"Não é possível declarar transições a partir do estado final. Estado(s) "
|
|
47
|
+
"inválido(s): {}"
|
|
48
|
+
|
|
49
|
+
#: statemachine/factory.py:109
|
|
50
|
+
msgid ""
|
|
51
|
+
"All non-final states should have at least one outgoing transition. These "
|
|
52
|
+
"states have no outgoing transition: {!r}"
|
|
53
|
+
msgstr ""
|
|
54
|
+
"Todos os estados não finais devem ter pelo menos uma transição de saída. "
|
|
55
|
+
"Esses estados não têm transição de saída: {!r}"
|
|
59
56
|
|
|
60
|
-
#: statemachine/
|
|
57
|
+
#: statemachine/factory.py:123
|
|
58
|
+
msgid ""
|
|
59
|
+
"All non-final states should have at least one path to a final state. "
|
|
60
|
+
"These states have no path to a final state: {!r}"
|
|
61
|
+
msgstr ""
|
|
62
|
+
"Todos os estados não finais devem ter pelo menos um caminho para um "
|
|
63
|
+
"estado final. Esses estados não têm caminho para um estado final: {!r}"
|
|
64
|
+
|
|
65
|
+
#: statemachine/factory.py:147
|
|
66
|
+
msgid ""
|
|
67
|
+
"There are unreachable states. The statemachine graph should have a single"
|
|
68
|
+
" component. Disconnected states: {}"
|
|
69
|
+
msgstr ""
|
|
70
|
+
"Há estados inacessíveis. O gráfico da máquina de estados deve ter um "
|
|
71
|
+
"único componente. Estados desconectados: {}"
|
|
72
|
+
|
|
73
|
+
#: statemachine/mixins.py:23
|
|
61
74
|
msgid "{!r} is not a valid state machine name."
|
|
62
|
-
msgstr "{!r} não é um nome válido para
|
|
75
|
+
msgstr "{!r} não é um nome válido para uma máquina de estados."
|
|
63
76
|
|
|
64
|
-
#: statemachine/state.py:
|
|
77
|
+
#: statemachine/state.py:152
|
|
65
78
|
msgid "State overriding is not allowed. Trying to add '{}' to {}"
|
|
66
|
-
msgstr "
|
|
79
|
+
msgstr "Sobrescrever estados não é permitido. Tentando adicionar '{}' a {}"
|
|
67
80
|
|
|
68
|
-
#: statemachine/statemachine.py:
|
|
81
|
+
#: statemachine/statemachine.py:86
|
|
69
82
|
msgid "There are no states or transitions."
|
|
70
83
|
msgstr "Não há estados ou transições."
|
|
84
|
+
|
|
85
|
+
#: statemachine/statemachine.py:249
|
|
86
|
+
msgid ""
|
|
87
|
+
"There's no current state set. In async code, did you activate the initial"
|
|
88
|
+
" state? (e.g., `await sm.activate_initial_state()`)"
|
|
89
|
+
msgstr ""
|
|
90
|
+
"Não há estado atual definido. No código assíncrono, você ativou o estado"
|
|
91
|
+
" inicial? (por exemplo, `await sm.activate_initial_state()`)"
|