Skip to content

Commit

Permalink
feat: Support abstract SM classes. Closes #350
Browse files Browse the repository at this point in the history
  • Loading branch information
fgmacedo committed Feb 22, 2023
1 parent 0a54b24 commit f304aa2
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 12 deletions.
16 changes: 8 additions & 8 deletions statemachine/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from .state import State
from .transition import Transition
from .transition_list import TransitionList
from .utils import qualname
from .utils import ugettext as _


Expand Down Expand Up @@ -57,18 +56,19 @@ def _check_disconnected_state(cls):
)

def _check(cls):
has_states = bool(cls.states)
has_events = bool(cls._events)

# do not validate the base class
name = qualname(cls)
if name == "statemachine.statemachine.StateMachine":
return
cls._abstract = not has_states and not has_events

cls._abstract = False
# do not validate the base abstract classes
if cls._abstract:
return

if not cls.states:
if not has_states:
raise InvalidDefinition(_("There are no states."))

if not cls._events:
if not has_events:
raise InvalidDefinition(_("There are no events."))

cls._check_disconnected_state()
Expand Down
5 changes: 5 additions & 0 deletions statemachine/statemachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
from .event import Event
from .event_data import EventData
from .exceptions import InvalidStateValue
from .exceptions import InvalidDefinition
from .exceptions import TransitionNotAllowed
from .factory import StateMachineMetaclass
from .model import Model
from .transition import Transition
from .utils import ugettext as _


if TYPE_CHECKING:
Expand All @@ -28,6 +30,9 @@ def __init__(self, model=None, state_field="state", start_value=None):
self.state_field = state_field
self.start_value = start_value

if self._abstract:
raise InvalidDefinition(_("There are no states or transitions."))

initial_transition = Transition(
None, self._get_initial_state(), event="__initial__"
)
Expand Down
16 changes: 12 additions & 4 deletions tests/test_statemachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,13 +296,21 @@ def test_state_machine_with_a_invalid_start_value(
machine_cls(model, start_value=start_value)


def test_should_not_create_instance_of_machine_without_states():
def test_should_not_create_instance_of_abstract_machine():
class EmptyMachine(StateMachine):
"An empty machine"
pass

with pytest.raises(exceptions.InvalidDefinition):
EmptyMachine()


def test_should_not_create_instance_of_machine_without_states():
s1 = State("X")
with pytest.raises(exceptions.InvalidDefinition):

class EmptyMachine(StateMachine):
"An empty machine"
pass
class OnlyTransitionMachine(StateMachine):
t1 = s1.to.itself()


def test_should_not_create_instance_of_machine_without_transitions():
Expand Down

0 comments on commit f304aa2

Please sign in to comment.