sm

state_machine

Python State Machine for humans

Showing:

Popularity

Downloads/wk

0

GitHub Stars

369

Maintenance

Last Commit

4yrs ago

Contributors

9

Package

Dependencies

0

License

MIT

Categories

Readme

state_machine

state machine for humans

|Build Status|

There are two types of developers in this world: those who love state machines and those who will eventually.

I fall in the first camp. I think it is really important to have a declarative way to define the states of an object. That’s why I developed state_machine.

Install

.. code:: bash

pip install state_machine

.. |Build Status| image:: https://travis-ci.org/jtushman/state_machine.svg?branch=master :target: https://travis-ci.org/jtushman/state_machine

Basic Usage

.. code:: python

@acts_as_state_machine
class Person():
    name = 'Billy'

    sleeping = State(initial=True)
    running = State()
    cleaning = State()

    run = Event(from_states=sleeping, to_state=running)
    cleanup = Event(from_states=running, to_state=cleaning)
    sleep = Event(from_states=(running, cleaning), to_state=sleeping)

    @before('sleep')
    def do_one_thing(self):
        print "{} is sleepy".format(self.name)

    @before('sleep')
    def do_another_thing(self):
        print "{} is REALLY sleepy".format(self.name)

    @after('sleep')
    def snore(self):
        print "Zzzzzzzzzzzz"

    @after('sleep')
    def big_snore(self):
        print "Zzzzzzzzzzzzzzzzzzzzzz"

person = Person()
print person.current_state == Person.sleeping       # True
print person.is_sleeping                            # True
print person.is_running                             # False
person.run()
print person.is_running                             # True
person.sleep()

# Billy is sleepy
# Billy is REALLY sleepy
# Zzzzzzzzzzzz
# Zzzzzzzzzzzzzzzzzzzzzz

print person.is_sleeping                            # True

Features

Before / After Callback Decorators


You can add callback hooks that get executed before or after an event
(see example above).

*Important:* if the *before* event causes an exception or returns
``False``, the state will not change (transition is blocked) and the
*after* event will not be executed.

Blocks invalid state transitions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

An *InvalidStateTransition Exception* will be thrown if you try to move
into an invalid state.

ORM support
-----------

We have basic support for `mongoengine`_, and `sqlalchemy`_.

Mongoengine
~~~~~~~~~~~

Just have your object inherit from ``mongoengine.Document`` and
state\_machine will add a StringField for state.

*Note:* You must explicitly call #save to persist the document to the
datastore.

.. code:: python

        @acts_as_state_machine
        class Person(mongoengine.Document):
            name = mongoengine.StringField(default='Billy')

            sleeping = State(initial=True)
            running = State()
            cleaning = State()

            run = Event(from_states=sleeping, to_state=running)
            cleanup = Event(from_states=running, to_state=cleaning)
            sleep = Event(from_states=(running, cleaning), to_state=sleeping)

            @before('sleep')
            def do_one_thing(self):
                print "{} is sleepy".format(self.name)

            @before('sleep')
            def do_another_thing(self):
                print "{} is REALLY sleepy".format(self.name)

            @after('sleep')
            def snore(self):
                print "Zzzzzzzzzzzz"

            @after('sleep')
            def snore(self):
                print "Zzzzzzzzzzzzzzzzzzzzzz"


        person = Person()
        person.save()
        eq_(person.current_state, Person.sleeping)
        assert person.is_sleeping
        assert not person.is_running
        person.run()
        assert person.is_running
        person.sleep()
        assert person.is_sleeping
        person.run()
        person.save()

        person2 = Person.objects(id=person.id).first()
        assert person2.is_running

.. _mongoengine: http://mongoengine.org/
.. _sqlalchemy: http://www.sqlalchemy.org/

Sqlalchemy
~~~~~~~~~~

All you need to do is have sqlalchemy manage your object. For example:

.. code:: python

        from sqlalchemy.ext.declarative import declarative_base
        Base = declarative_base()
        @acts_as_state_machine
        class Puppy(Base):
           ...

Issues / Roadmap:
-----------------

-  Allow multiple state\_machines per object
-  Be able to configure the state field

Questions / Issues
------------------

Feel free to ping me on twitter: `@tushman`_
or add issues or PRs at https://github.com/jtushman/state_machine

.. _@tushman: http://twitter.com/tushman

Thank you
---------

to `aasm`_ and ruby’s `state\_machine`_ and all other state machines
that I loved before

.. _aasm: https://github.com/aasm/aasm
.. _state\_machine: https://github.com/pluginaweek/state_machine

Rate & Review

Great Documentation0
Easy to Use0
Performant0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Slow0
Buggy0
Abandoned0
Unwelcoming Community0
100