Ian George committed 34424db

test updates, attempting to add dynamic choices to admin

  • Participants
  • Parent commits e2410b8

Comments (0)

Files changed (3)

File statemachine/

 class FSM_Exception(Exception): pass
 class FSM_TransitionNotAllowed(FSM_Exception): pass
 class FSM_StateDoesNotExist(FSM_Exception): pass
-class FSM_VerificationError(FSM_Exception): pass
+class FSM_VerificationError(FSM_Exception):
+    def __init__(self, message, states=None):
+        self.message = message
+        self.states = states
+    def __str__(self):
+        if self.states:
+            return "%s %s" % (self.message, self.states)
+        else:
+            return self.message
 class FSM_State(object):
     def verify(self):
-        Best only called on fully formed machines, checks for unreachable states
+        Best only called on fully formed machines, checks for exit states that don't exist
         bad_states = []
         state_names = set(self.states.keys())
             bad_states.extend(set(state.exit_states) - state_names)
         if len(bad_states):
-            raise FSM_VerificationError(bad_states)
+            raise FSM_VerificationError("Invalid exit state(s)", bad_states)
+    def get_django_choices(self):
+        return tuple([(name,name) for name in self.states.keys()])
     def add(self, fsm_state):
         Transitions the machine to its new state.
-         if self.verify_on_execute:
+        if self.verify_on_execute:
-       if not new_state in self.states:
+        if not new_state in self.states:
             raise FSM_StateDoesNotExist(new_state)
         exiting_state = self.states[self.state]

File statemachine/

 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
 from django.contrib.auth.models import User
+from django.utils.functional import lazy
 from django.conf import settings
 from fsm import FSM_Exception, FSM
         # if we don't have a machine to work with, raise an exception
         if self.__machine_class__:
             self.__machine__ = deepcopy(self.__machine_class__)
-            self.__machine__.state = self.state
-            raise StateMachineMissing("Instance of fsm.FSM required for this model to function")
+            raise StateMachineMissing("Instance of fsm.FSM required for this model to function (set __machine_class__ on the model)")
+        self.__machine__.state = self.state
         self._current_state = self.state
+        self._meta.get_field_by_name("state")[0]._choices = self.__machine__.get_django_choices()
+        super(StateMachineBase, self).__init__(*args, **kwargs)
     def save(self, *args, **kwargs):
         if self.state == self._current_state:
             super(StateMachineBase, self).save(*args, **kwargs)

File statemachine/

     if state_to == "end" and state_from == "step3":
         return True
-testfsm = FSM(FSM_State("start" ,["step1", "step1a", "step1b", "step1c"]))
+testfsm = FSM(FSM_State("start" ,["step1a", "step1b", "step1c"]))
 testfsm.add(FSM_State("step1a", ["step2",]))
 testfsm.add(FSM_State("step1b", ["step2",]))
 testfsm.add(FSM_State("step1c", ["step2",]))
         self.fsm.__machine__.add(FSM_State("random", ["doesntexist", "alsodoesnexist"]))
         with self.assertRaises(FSM_VerificationError):
     def test_save_fail(self):
         """Should raise a StateMachineNotAllowed, messing with the state outside of the machine."""
         self.fsm.transition("step2", None , "Some notes!")
         self.fsm.transition("end", None)
+        #reload so we get everything from the db
+        fsm_id =
+        self.fsm = TestStateMachine.objects.get(pk=fsm_id)
         self.assertEqual(self.fsm.state_history.count(), 3)
         self.assertEqual(self.fsm.state_history.all()[1].notes, "Some notes!")
     def test_entry_action(self):