Skip to content

Commit

Permalink
docs: improved usage docs
Browse files Browse the repository at this point in the history
  • Loading branch information
woile committed Aug 29, 2018
1 parent 0ce7a25 commit 0cb109b
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 17 deletions.
45 changes: 28 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,6 @@ Minimal state machine

* Free software: BSD license

.. contents::
:depth: 2

Usage
=====

.. code-block:: python
Expand Down Expand Up @@ -90,7 +85,10 @@ Usage
I'm going to a pending state
Out[5]: 'pending'

In [6]: m.change_state('failed')

::

In [6]: m.change_state('failed') # Let's try to transition to an invalid state
---------------------------------------------------------------------------
InvalidTransition Traceback (most recent call last)
<ipython-input-6-71d2461eee74> in <module>()
Expand All @@ -105,30 +103,43 @@ Usage

InvalidTransition: The transition from pending to failed is not valid

.. contents::
:depth: 2

There are hooks that can be included before a state transition happens and after.

fsm will look for these functions
Installation
============

::

pre_<state_name>
post_<state_name>
pip install fsmpy

And will give them any extra argument given to :code:`change_state`

E.g:
Usage
======

Running :code:`m.change_state('pending', name='john')` will trigger :code:`pre_pending(name='john')`
1. Define in a class the :code:`state_machine`
2. Initialize :code:`state`, either with a value, using :code:`__init__` or as a django field
3. Add hooks:

+------------------------+-------------------------------------------------------------------------------------------------------------+
| Method | Description |
+------------------------+-------------------------------------------------------------------------------------------------------------+
| on_before_change_state | Before transitioning to the state |
+------------------------+-------------------------------------------------------------------------------------------------------------+
| on_change_state | After transitioning to the state, if no failure, runs for every state |
+------------------------+-------------------------------------------------------------------------------------------------------------+
| pre_<state_name> | Runs before a particular state, where :code:`state_name` is the specified name in the :code:`state_machine` |
+------------------------+-------------------------------------------------------------------------------------------------------------+
| post_<state_name> | Runs after a particular state, where :code:`state_name` is the specified name in the :code:`state_machine` |
+------------------------+-------------------------------------------------------------------------------------------------------------+

Installation
============
This hooks will receive any extra argument given to :code:`change_state`

::

pip install fsmpy
E.g:

Running :code:`m.change_state('pending', name='john')` will trigger :code:`pre_pending(name='john')`

Django integration
==================
Expand Down
57 changes: 57 additions & 0 deletions docs/django.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Django integration
==================

.. code-block:: python
import fsm
from django.db import models
class MyModel(models.Model, fsm.FiniteStateMachineMixin):
"""An example to test the state machine.
Contains transitions to everywhere, nowhere and specific states.
"""
CHOICES = (
('created', 'CREATED'),
('pending', 'PENDING'),
('running', 'RUNNING'),
('success', 'SUCCESS'),
('failed', 'FAILED'),
('retry', 'RETRY'),
)
state_machine = {
'created': '__all__',
'pending': ('running',),
'running': ('success', 'failed'),
'success': None,
'failed': ('retry',),
'retry': ('pending', 'retry'),
}
state = models.CharField(max_length=30, choices=CHOICES, default='created')
def on_change_state(self, previous_state, next_state, **kwargs):
self.save()
Django Rest Framework
---------------------

If you are using :code:`serializers`, they usually perform the :code:`save`, so saving inside :code:`on_change_state` is not necessary.

One simple solution is to do this:

.. code-block:: python
class MySerializer(serializers.ModelSerializer):
def update(self, instance, validated_data):
instance = super().update(instance, validated_data)
new_state = validated_data.get('state', instance.state)
try:
instance.change_state(new_state)
except fsm.InvalidTransition:
raise serializers.ValidationError("Invalid transition")
return instance
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Contents
readme
installation
usage
django
reference/index
contributing
authors
Expand Down
27 changes: 27 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@
Usage
=====

1. Define in a class the :code:`state_machine`
2. Initialize :code:`state`, either with a value, using :code:`__init__` or as a django field
3. Add hooks:

+------------------------+-------------------------------------------------------------------------------------------------------------+
| Method | Description |
+------------------------+-------------------------------------------------------------------------------------------------------------+
| on_before_change_state | Before transitioning to the state |
+------------------------+-------------------------------------------------------------------------------------------------------------+
| on_change_state | After transitioning to the state, if no failure, runs for every state |
+------------------------+-------------------------------------------------------------------------------------------------------------+
| pre_<state_name> | Runs before a particular state, where :code:`state_name` is the specified name in the :code:`state_machine` |
+------------------------+-------------------------------------------------------------------------------------------------------------+
| post_<state_name> | Runs after a particular state, where :code:`state_name` is the specified name in the :code:`state_machine` |
+------------------------+-------------------------------------------------------------------------------------------------------------+

This hooks will receive any extra argument given to :code:`change_state`


E.g:

Running :code:`m.change_state('pending', name='john')` will trigger :code:`pre_pending(name='john')`

In your code
------------


To use Python Finite State Machine in a project::

import fsm
Expand Down

0 comments on commit 0cb109b

Please sign in to comment.