diff --git a/doc/reference.rst b/doc/reference.rst index 596b1ea..015ae0d 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -169,6 +169,21 @@ to a plain attribute: from typos in the code (:exc:`AttributeError` would be raised), whereas raw strings provide no such guarantee. + - Easily setting the current value:: + + >>> obj.state = MyWorkflow.states.ready + >>> obj.state.is_ready + True + + >>> # Setting from a state name is also possible + >>> obj.state = 'ready' + >>> obj.state.is_ready + True + + .. note:: Setting the state without going through transitions defeats the goal of + xworkflows; this feature should only be used for faster testing or when + saving/restoring objects from external storage. + Using transitions ----------------- diff --git a/tests/test_base.py b/tests/test_base.py index 5e5a15a..71c59cc 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -141,6 +141,53 @@ def test_representation(self): self.assertEqual(hash(self.foo.name), hash(self.sf)) +class WorkflowEnabledTestCase(unittest.TestCase): + def setUp(self): + super(WorkflowEnabledTestCase, self).setUp() + + class MyWorkflow(base.Workflow): + states = ( + ('foo', "Foo"), + ('bar', "Bar"), + ('baz', "Baz"), + ) + transitions = ( + ('foobar', 'foo', 'bar'), + ('gobaz', ('foo', 'bar'), 'baz'), + ('bazbar', 'baz', 'bar'), + ) + initial_state = 'foo' + + class MyWorkflowEnabled(base.WorkflowEnabled): + state = MyWorkflow() + + self.foo = MyWorkflow.states.foo + self.bar = MyWorkflow.states.bar + self.wf = MyWorkflow + self.wfe = MyWorkflowEnabled + + def test_access_state(self): + obj = self.wfe() + self.assertEqual(self.foo, obj.state) + self.assertTrue(obj.state.is_foo) + self.assertFalse(obj.state.is_bar) + + obj.state = self.bar + + self.assertEqual(self.bar, obj.state) + self.assertTrue(obj.state.is_bar) + self.assertFalse(obj.state.is_foo) + + def test_compare_state_text(self): + obj = self.wfe() + + obj.state = 'bar' + + self.assertEqual(self.bar, obj.state) + self.assertTrue(obj.state.is_bar) + self.assertFalse(obj.state.is_foo) + + class ImplementationPropertyTestCase(unittest.TestCase): def setUp(self): diff --git a/xworkflows/base.py b/xworkflows/base.py index 87ceb69..673f77a 100644 --- a/xworkflows/base.py +++ b/xworkflows/base.py @@ -67,8 +67,11 @@ def __getattr__(self, name): def __len__(self): return len(self._states) - def __getitem__(self, name): - return self._states[name] + def __getitem__(self, name_or_state): + if isinstance(name_or_state, State): + return self._states[name_or_state.name] + else: + return self._states[name_or_state] def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self._states) @@ -883,7 +886,7 @@ def __init__(self, state, workflow): def __eq__(self, other): if isinstance(other, self.__class__): return self.state == other.state - if isinstance(other, State): + elif isinstance(other, State): return self.state == other elif is_string(other): return self.state.name == other @@ -941,10 +944,12 @@ def __get__(self, instance, owner): def __set__(self, instance, value): """Set the current state of the 'instance' object.""" - if not value in self.workflow.states: + try: + state = self.workflow.states[value] + except KeyError: raise ValueError("Value %s is not a valid state for workflow %s." % (value, self.workflow)) - instance.__dict__[self.field_name] = value + instance.__dict__[self.field_name] = state def __str__(self): return 'StateProperty(%s, %s)' % (self.workflow, self.field_name)