[Python-modules-commits] [django-fsm] 04/10: Import django-fsm_2.3.0.orig.tar.gz
Michael Fladischer
fladi at moszumanska.debian.org
Fri Oct 16 09:55:54 UTC 2015
This is an automated email from the git hooks/post-receive script.
fladi pushed a commit to branch master
in repository django-fsm.
commit 4165236913c0855fec34700027328bf5021aeb56
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date: Fri Oct 16 11:14:12 2015 +0200
Import django-fsm_2.3.0.orig.tar.gz
---
.travis.yml | 1 +
README.md | 394 -----------------
README.rst | 484 +++++++++++++++++++++
django_fsm/__init__.py | 67 ++-
.../management/commands/graph_transitions.py | 81 +++-
django_fsm/tests/test_key_field.py | 12 +-
setup.py | 4 +-
tests/settings.py | 4 +-
.../{initial_data.json => test_states_data.json} | 0
tests/testapp/models.py | 8 +
tests/testapp/tests/test_custom_data.py | 3 +
tests/testapp/tests/test_exception_transitions.py | 5 +-
tests/testapp/tests/test_mixin_support.py | 31 ++
tests/testapp/tests/test_multidecorators.py | 34 ++
tests/testapp/tests/test_object_permissions.py | 44 ++
tests/testapp/tests/test_permissions.py | 5 +
.../tests/test_transition_all_except_target.py | 31 ++
tox.ini | 9 +-
18 files changed, 776 insertions(+), 441 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 53806c6..0f4a34f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,7 @@ env:
- $TOX_ENV=py26
- $TOX_ENV=py27
- $TOX_ENV=py33
+ - $TOX_ENV=py34
install:
- pip install tox
script:
diff --git a/README.md b/README.md
deleted file mode 100644
index 4ac8234..0000000
--- a/README.md
+++ /dev/null
@@ -1,394 +0,0 @@
-Django friendly finite state machine support
-============================================
-[![Build Status](https://travis-ci.org/kmmbvnr/django-fsm.svg?branch=master)](https://travis-ci.org/kmmbvnr/django-fsm)
-
-django-fsm adds declarative states management for django models.
-
-Instead of adding some state field to a django model, and managing its
-values by hand, you could use FSMState field and mark model methods
-with the `transition` decorator. Your method could contain the side-effects
-of the state change.
-
-Nice introduction is available here: https://gist.github.com/Nagyman/9502133
-
-You may also take a look at django-fsm-admin project
-containing a mixin and template tags to integrate django-fsm
-state transitions into the django admin.
-
-https://github.com/gadventures/django-fsm-admin
-
-Transition logging support could be achived with help of django-fsm-log package
-
-https://github.com/gizmag/django-fsm-log
-
-FSM really helps to structure the code, especially when a new
-developer comes to the project. FSM is most effective when you use it
-for some sequential steps.
-
-If you need parallel task execution, view and background task code reuse
-over different flows - check my new project django-viewflow
-
-https://github.com/kmmbvnr/django-viewflow
-
-Installation
-------------
-```bash
-$ pip install django-fsm
-```
-Or, for the latest git version
-```bash
-$ pip install -e git://github.com/kmmbvnr/django-fsm.git#egg=django-fsm
-```
-
-The library has full Python 3 support
-
-
-Usage
------
-
-Add FSMState field to your model
-```python
-from django_fsm import FSMField, transition
-
-class BlogPost(models.Model):
- state = FSMField(default='new')
-```
-
-Use the `transition` decorator to annotate model methods
-```python
- at transition(field=state, source='new', target='published')
-def publish(self):
- """
- This function may contain side-effects,
- like updating caches, notifying users, etc.
- The return value will be discarded.
- """
-```
-
-`source` parameter accepts a list of states, or an individual state.
-You can use `*` for source, to allow switching to `target` from any state.
-
-If calling publish() succeeds without raising an exception, the state field
-will be changed, but not written to the database.
-```python
-from django_fsm import can_proceed
-
-def publish_view(request, post_id):
- post = get_object__or_404(BlogPost, pk=post_id)
- if not can_proceed(post.publish):
- raise PermissionDenied
-
- post.publish()
- post.save()
- return redirect('/')
-```
-
-If some conditions are required to be met before changing the state, use the
-`conditions` argument to `transition`. `conditions` must be a list of functions
-taking one argument, the model instance. The function must return either
-`True` or `False` or a value that evaluates to `True` or `False`. If all functions
-return `True`, all conditions are considered to be met and the transition
-is allowed to happen. If one of the functions returns `False`, the transition
-will not happen. These functions should not have any side effects.
-
-You can use ordinary functions
-```python
-def can_publish(instance):
- # No publishing after 17 hours
- if datetime.datetime.now().hour > 17:
- return False
- return True
-```
-
-Or model methods
-```python
-def can_destroy(self):
- return self.is_under_investigation()
-```
-
-Use the conditions like this:
-```python
- at transition(field=state, source='new', target='published', conditions=[can_publish])
- def publish(self):
- """
- Side effects galore
- """
-
- at transition(field=state, source='*', target='destroyed', conditions=[can_destroy])
- def destroy(self):
- """
- Side effects galore
- """
-```
-
-You could instantiate a field with protected=True option, that prevents direct state field modification
-```python
-class BlogPost(models.Model):
- state = FSMField(default='new', protected=True)
-
-model = BlogPost()
-model.state = 'invalid' # Raises AttributeError
-```
-
-
-### `custom` properties
-Custom properties can be added by providing a dictionary to the `custom` keyword on the `transition` decorator.
-```python
- at transition(field=state,
- source='*',
- target='onhold',
- custom=dict(verbose='Hold for legal reasons'), transition_type='manual')
-def legal_hold(self):
- """
- Side effects galore
- """
-```
-
-### `on_error` state
-
-In case of transition method would raise exception, you can provide specific target state
-
-```python
- at transition(field=state, source='new', target='published', on_error='failed')
-def publish(self):
- """
- Some exceptio could happends here
- """
-```
-
-### `state_choices`
-Instead of passing two elements list `choices` you could use three elements `state_choices`,
-the last element states for string reference to model proxy class.
-
-Base class instance would be dynamically changed to corresponding Proxy class instance, depending on the state.
-Even for queryset results, you will get Proxy class instances, even if QuerySet executed on base class.
-
-Check the [test case](https://github.com/kmmbvnr/django-fsm/blob/master/tests/testapp/tests/test_state_transitions.py)
-for example usage. Or read about [implementation internals](http://schinckel.net/2013/06/13/django-proxy-model-state-machine/)
-
-### Permissions
-It is common to have permissions attached to each model transition. `django-fsm` handles this with
-`permission` keyword on the `transition` decorator. `permission` accepts a permission string, or
-callable that expects `user` argument and returns True if user can perform the transition
-
-```python
- at transition(field=state, source='*', target='publish',
- permission=lambda user: not user.has_perm('myapp.can_make_mistakes'))
-def publish(self):
- pass
-
- at transition(field=state, source='*', target='publish',
- permission='myapp.can_remove_post')
-def remove(self):
- pass
-```
-
-You can check permission with `has_transition_permission` method
-
-``` python
-from django_fsm import has_transition_perm
-def publish_view(request, post_id):
- post = get_object_or_404(BlogPost, pk=post_id)
- if not has_transition_perm(post.publish, request.user):
- raise PermissionDenied
-
- post.publish()
- post.save()
- return redirect('/')
-```
-
-### Model methods
-
-`get_all_FIELD_transitions`
-Enumerates all declared transitions
-
-`get_available_FIELD_transitions`
-Returns all transitions data available in current state
-
-`get_available_user_FIELD_transitions`
-Enumerates all transitions data available in current state for provided user
-
-### Foreign Key constraints support
-
-If you store the states in the db table you could use FSMKeyField to
-ensure Foreign Key database integrity.
-
-In your model :
-```python
-class DbState(models.Model):
- id = models.CharField(primary_key=True, max_length=50)
- label = models.CharField(max_length=255)
-
- def __unicode__(self):
- return self.label
-
-
-class BlogPost(models.Model):
- state = FSMKeyField(DbState, default='new')
-
- @transition(field=state, source='new', target='published')
- def publish(self):
- pass
-```
-
-In your fixtures/initial_data.json :
-```json
-[
- {
- "pk": "new",
- "model": "myapp.dbstate",
- "fields": {
- "label": "_NEW_"
- }
- },
- {
- "pk": "published",
- "model": "myapp.dbstate",
- "fields": {
- "label": "_PUBLISHED_"
- }
- }
-]
-```
-
-Note : source and target parameters in @transition decorator use pk values of DBState model
-as names, even if field "real" name is used, without _id postfix, as field parameter.
-
-
-### Integer Field support
-
-You can also use `FSMIntegerField`. This is handy when you want to use enum style constants.
-```python
-class BlogPostStateEnum(object):
- NEW = 10
- PUBLISHED = 20
- HIDDEN = 30
-
-class BlogPostWithIntegerField(models.Model):
- state = FSMIntegerField(default=BlogPostStateEnum.NEW)
-
- @transition(field=state, source=BlogPostStateEnum.NEW, target=BlogPostStateEnum.PUBLISHED)
- def publish(self):
- pass
-```
-
-### Signals
-
-`django_fsm.signals.pre_transition` and `django_fsm.signals.post_transition` are called before
-and after allowed transition. No signals on invalid transition are called.
-
-Arguments sent with these signals:
-
-**sender**
- The model class.
-
-**instance**
- The actual instance being procceed
-
-**name**
- Transition name
-
-**source**
- Source model state
-
-**target**
- Target model state
-
-## Optimistic locking
-
-`django-fsm` provides optimistic locking mixin, to avoid concurent model state changes.
-If model state was changed in database `django_fsm.ConcurrentTransition` exception would be raised
-on model.save()
-
-```python
-from django_fsm import FMSField, ConcurrentTransitionMixin
-
-class BlogPost(ConcurrentTransitionMixin, models.Model):
- state = FSMField(default='new')
-```
-
-For guaranteed protection against race conditions caused by concurrently executed transitions, make sure:
-* Your transitions do not have any side effects except for changes in the database,
-* You always run the save() method on the object within `django.db.transaction.atomic()` block.
-
-Following these recommendations, you can rely on ConcurrentTransitionMixin to cause a rollback of all the changes
-that have been executed in an inconsistent (out of sync) state, thus practically negating their effect.
-
-## Drawing transitions
-
-Renders a graphical overview of your models states transitions
-
-You need `pip install graphviz>=0.4` library
-
-```bash
-# Create a dot file
-$ ./manage.py graph_transitions > transitions.dot
-
-# Create a PNG image file only for specific model
-$ ./manage.py graph_transitions -o blog_transitions.png myapp.Blog
-```
-
-Changelog
----------
-
-<img src="https://f.cloud.github.com/assets/41479/2227946/a9e77760-9ad0-11e3-804f-301d075470fe.png" alt="django-fsm" width="100px"/>
-
-### django-fsm 2.2.1 2015-04-27
-* Improved exception message for unmet transition conditions.
-* Don't send post transiton signal in case of no state chnages on exception
-* Allow empty string as correct state value
-* Imporved graphviz fsm visualisation
-* Clean django 1.8 warnings
-
-
-### django-fsm 2.2.0 2014-09-03
-* Support for [class substitution](http://schinckel.net/2013/06/13/django-proxy-model-state-machine/) to proxy classes depending on the state
-* Added ConcurrentTransitionMixin with optimistic locking support
-* Default db_index=True for FSMIntegerField removed
-* Graph transition code migrated to new graphviz library with python 3 support
-* Ability to change state on transition exception
-
-### django-fsm 2.1.0 2014-05-15
-* Support for attaching permission checks on model transitions
-
-### django-fsm 2.0.0 2014-03-15
-* Backward incompatible release
-* All public code import moved directly to django_fsm package
-* Correct support for several @transitions decorator with different source states and conditions on same method
-* save parameter from transition decorator removed
-* get_available_FIELD_transitions return Transition data object instead of tuple
-* Models got get_available_FIELD_transitions, even if field specified as string reference
-* New get_all_FIELD_transitions method contributed to class
-
-### django-fsm 1.6.0 2014-03-15
-* FSMIntegerField and FSMKeyField support
-
-### django-fsm 1.5.1 2014-01-04
-
-* Ad-hoc support for state fields from proxy and inherited models
-
-### django-fsm 1.5.0 2013-09-17
-
-* Python 3 compatibility
-
-### django-fsm 1.4.0 2011-12-21
-
-* Add graph_transition command for drawing state transition picture
-
-### django-fsm 1.3.0 2011-07-28
-
-* Add direct field modification protection
-
-### django-fsm 1.2.0 2011-03-23
-
-* Add pre_transition and post_transition signals
-
-### django-fsm 1.1.0 2011-02-22
-
-* Add support for transition conditions
-* Allow multiple FSMField in one model
-* Contribute get_available_FIELD_transitions for model class
-
-### django-fsm 1.0.0 2010-10-12
-
-* Initial public release
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..7cbe137
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,484 @@
+Django friendly finite state machine support
+============================================
+
+|Build Status| |Downloads| |Gitter|
+
+django-fsm adds declarative states management for django models.
+
+Instead of adding some state field to a django model, and managing its
+values by hand, you could use FSMState field and mark model methods with
+the ``transition`` decorator. Your method could contain the side-effects
+of the state change.
+
+Nice introduction is available here:
+https://gist.github.com/Nagyman/9502133
+
+You may also take a look at django-fsm-admin project containing a mixin
+and template tags to integrate django-fsm state transitions into the
+django admin.
+
+https://github.com/gadventures/django-fsm-admin
+
+Transition logging support could be achived with help of django-fsm-log
+package
+
+https://github.com/gizmag/django-fsm-log
+
+FSM really helps to structure the code, especially when a new developer
+comes to the project. FSM is most effective when you use it for some
+sequential steps.
+
+If you need parallel task execution, view and background task code reuse
+over different flows - check my new project django-viewflow
+
+https://github.com/kmmbvnr/django-viewflow
+
+Installation
+------------
+
+.. code:: bash
+
+ $ pip install django-fsm
+
+Or, for the latest git version
+
+.. code:: bash
+
+ $ pip install -e git://github.com/kmmbvnr/django-fsm.git#egg=django-fsm
+
+The library has full Python 3 support
+
+Usage
+-----
+
+Add FSMState field to your model
+
+.. code:: python
+
+ from django_fsm import FSMField, transition
+
+ class BlogPost(models.Model):
+ state = FSMField(default='new')
+
+Use the ``transition`` decorator to annotate model methods
+
+.. code:: python
+
+ @transition(field=state, source='new', target='published')
+ def publish(self):
+ """
+ This function may contain side-effects,
+ like updating caches, notifying users, etc.
+ The return value will be discarded.
+ """
+
+``source`` parameter accepts a list of states, or an individual state.
+You can use ``*`` for source, to allow switching to ``target`` from any
+state.
+
+If calling publish() succeeds without raising an exception, the state
+field will be changed, but not written to the database.
+
+.. code:: python
+
+ from django_fsm import can_proceed
+
+ def publish_view(request, post_id):
+ post = get_object__or_404(BlogPost, pk=post_id)
+ if not can_proceed(post.publish):
+ raise PermissionDenied
+
+ post.publish()
+ post.save()
+ return redirect('/')
+
+If some conditions are required to be met before changing the state, use
+the ``conditions`` argument to ``transition``. ``conditions`` must be a
+list of functions taking one argument, the model instance. The function
+must return either ``True`` or ``False`` or a value that evaluates to
+``True`` or ``False``. If all functions return ``True``, all conditions
+are considered to be met and the transition is allowed to happen. If one
+of the functions returns ``False``, the transition will not happen.
+These functions should not have any side effects.
+
+You can use ordinary functions
+
+.. code:: python
+
+ def can_publish(instance):
+ # No publishing after 17 hours
+ if datetime.datetime.now().hour > 17:
+ return False
+ return True
+
+Or model methods
+
+.. code:: python
+
+ def can_destroy(self):
+ return self.is_under_investigation()
+
+Use the conditions like this:
+
+.. code:: python
+
+ @transition(field=state, source='new', target='published', conditions=[can_publish])
+ def publish(self):
+ """
+ Side effects galore
+ """
+
+ @transition(field=state, source='*', target='destroyed', conditions=[can_destroy])
+ def destroy(self):
+ """
+ Side effects galore
+ """
+
+You could instantiate a field with protected=True option, that prevents
+direct state field modification.
+
+.. code:: python
+
+ class BlogPost(models.Model):
+ state = FSMField(default='new', protected=True)
+
+ model = BlogPost()
+ model.state = 'invalid' # Raises AttributeError
+
+Note that calling
+```refresh_from_db`` <https://docs.djangoproject.com/en/1.8/ref/models/instances/#django.db.models.Model.refresh_from_db>`__
+on a model instance with a protected FSMField will cause an exception.
+
+``custom`` properties
+~~~~~~~~~~~~~~~~~~~~~
+
+Custom properties can be added by providing a dictionary to the
+``custom`` keyword on the ``transition`` decorator.
+
+.. code:: python
+
+ @transition(field=state,
+ source='*',
+ target='onhold',
+ custom=dict(verbose='Hold for legal reasons'))
+ def legal_hold(self):
+ """
+ Side effects galore
+ """
+
+``on_error`` state
+~~~~~~~~~~~~~~~~~~
+
+In case of transition method would raise exception, you can provide
+specific target state
+
+.. code:: python
+
+ @transition(field=state, source='new', target='published', on_error='failed')
+ def publish(self):
+ """
+ Some exceptio could happends here
+ """
+
+``state_choices``
+~~~~~~~~~~~~~~~~~
+
+Instead of passing two elements list ``choices`` you could use three
+elements ``state_choices``, the last element states for string reference
+to model proxy class.
+
+Base class instance would be dynamically changed to corresponding Proxy
+class instance, depending on the state. Even for queryset results, you
+will get Proxy class instances, even if QuerySet executed on base class.
+
+Check the `test
+case <https://github.com/kmmbvnr/django-fsm/blob/master/tests/testapp/tests/test_state_transitions.py>`__
+for example usage. Or read about `implementation
+internals <http://schinckel.net/2013/06/13/django-proxy-model-state-machine/>`__
+
+Permissions
+~~~~~~~~~~~
+
+It is common to have permissions attached to each model transition.
+``django-fsm`` handles this with ``permission`` keyword on the
+``transition`` decorator. ``permission`` accepts a permission string, or
+callable that expects ``user`` argument and returns True if user can
+perform the transition
+
+.. code:: python
+
+ @transition(field=state, source='*', target='publish',
+ permission=lambda user: not user.has_perm('myapp.can_make_mistakes'))
+ def publish(self):
+ pass
+
+ @transition(field=state, source='*', target='publish',
+ permission='myapp.can_remove_post')
+ def remove(self):
+ pass
+
+You can check permission with ``has_transition_permission`` method
+
+.. code:: python
+
+ from django_fsm import has_transition_perm
+ def publish_view(request, post_id):
+ post = get_object_or_404(BlogPost, pk=post_id)
+ if not has_transition_perm(post.publish, request.user):
+ raise PermissionDenied
+
+ post.publish()
+ post.save()
+ return redirect('/')
+
+Model methods
+~~~~~~~~~~~~~
+
+``get_all_FIELD_transitions`` Enumerates all declared transitions
+
+``get_available_FIELD_transitions`` Returns all transitions data
+available in current state
+
+``get_available_user_FIELD_transitions`` Enumerates all transitions data
+available in current state for provided user
+
+Foreign Key constraints support
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you store the states in the db table you could use FSMKeyField to
+ensure Foreign Key database integrity.
+
+In your model :
+
+.. code:: python
+
+ class DbState(models.Model):
+ id = models.CharField(primary_key=True, max_length=50)
+ label = models.CharField(max_length=255)
+
+ def __unicode__(self):
+ return self.label
+
+
+ class BlogPost(models.Model):
+ state = FSMKeyField(DbState, default='new')
+
+ @transition(field=state, source='new', target='published')
+ def publish(self):
+ pass
+
+In your fixtures/initial\_data.json :
+
+.. code:: json
+
+ [
+ {
+ "pk": "new",
+ "model": "myapp.dbstate",
+ "fields": {
+ "label": "_NEW_"
+ }
+ },
+ {
+ "pk": "published",
+ "model": "myapp.dbstate",
+ "fields": {
+ "label": "_PUBLISHED_"
+ }
+ }
+ ]
+
+Note : source and target parameters in @transition decorator use pk
+values of DBState model as names, even if field "real" name is used,
+without \_id postfix, as field parameter.
+
+Integer Field support
+~~~~~~~~~~~~~~~~~~~~~
+
+You can also use ``FSMIntegerField``. This is handy when you want to use
+enum style constants.
+
+.. code:: python
+
+ class BlogPostStateEnum(object):
+ NEW = 10
+ PUBLISHED = 20
+ HIDDEN = 30
+
+ class BlogPostWithIntegerField(models.Model):
+ state = FSMIntegerField(default=BlogPostStateEnum.NEW)
+
+ @transition(field=state, source=BlogPostStateEnum.NEW, target=BlogPostStateEnum.PUBLISHED)
+ def publish(self):
+ pass
+
+Signals
+~~~~~~~
+
+``django_fsm.signals.pre_transition`` and
+``django_fsm.signals.post_transition`` are called before and after
+allowed transition. No signals on invalid transition are called.
+
+Arguments sent with these signals:
+
+**sender** The model class.
+
+**instance** The actual instance being procceed
+
+**name** Transition name
+
+**source** Source model state
+
+**target** Target model state
+
+Optimistic locking
+------------------
+
+``django-fsm`` provides optimistic locking mixin, to avoid concurent
+model state changes. If model state was changed in database
+``django_fsm.ConcurrentTransition`` exception would be raised on
+model.save()
+
+.. code:: python
+
+ from django_fsm import FSMField, ConcurrentTransitionMixin
+
+ class BlogPost(ConcurrentTransitionMixin, models.Model):
+ state = FSMField(default='new')
+
+For guaranteed protection against race conditions caused by concurrently
+executed transitions, make sure: \* Your transitions do not have any
+side effects except for changes in the database, \* You always run the
+save() method on the object within ``django.db.transaction.atomic()``
+block.
+
+Following these recommendations, you can rely on
+ConcurrentTransitionMixin to cause a rollback of all the changes that
+have been executed in an inconsistent (out of sync) state, thus
+practically negating their effect.
+
+Drawing transitions
+-------------------
+
+Renders a graphical overview of your models states transitions
+
+You need ``pip install graphviz>=0.4`` library and add ``django_fsm`` to
+your ``INSTALLED_APPS``:
+
+.. code:: python
+
+ INSTALLED_APPS = (
+ ...
+ 'django_fsm',
+ ...
+ )
+
+.. code:: bash
+
+ # Create a dot file
+ $ ./manage.py graph_transitions > transitions.dot
+
+ # Create a PNG image file only for specific model
+ $ ./manage.py graph_transitions -o blog_transitions.png myapp.Blog
+
+Changelog
+---------
+
+django-fsm 2.3.0 2015-10-15
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Add source state shortcut '+' to specify transitions from all states except the target
+- Add object-level permission checks
+- Fix translated labels for graph of FSMIntegerField
+- Fix multiple signals for several transition decorators
+
+
+django-fsm 2.2.1 2015-04-27
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Improved exception message for unmet transition conditions.
+- Don't send post transiton signal in case of no state chnages on
+ exception
+- Allow empty string as correct state value
+- Imporved graphviz fsm visualisation
+- Clean django 1.8 warnings
+
+django-fsm 2.2.0 2014-09-03
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Support for `class
+ substitution <http://schinckel.net/2013/06/13/django-proxy-model-state-machine/>`__
+ to proxy classes depending on the state
+- Added ConcurrentTransitionMixin with optimistic locking support
+- Default db\_index=True for FSMIntegerField removed
+- Graph transition code migrated to new graphviz library with python 3
+ support
+- Ability to change state on transition exception
+
+django-fsm 2.1.0 2014-05-15
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Support for attaching permission checks on model transitions
+
+django-fsm 2.0.0 2014-03-15
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Backward incompatible release
+- All public code import moved directly to django\_fsm package
+- Correct support for several @transitions decorator with different
+ source states and conditions on same method
+- save parameter from transition decorator removed
+- get\_available\_FIELD\_transitions return Transition data object
+ instead of tuple
+- Models got get\_available\_FIELD\_transitions, even if field
+ specified as string reference
+- New get\_all\_FIELD\_transitions method contributed to class
+
+django-fsm 1.6.0 2014-03-15
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- FSMIntegerField and FSMKeyField support
+
+django-fsm 1.5.1 2014-01-04
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Ad-hoc support for state fields from proxy and inherited models
+
+django-fsm 1.5.0 2013-09-17
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Python 3 compatibility
+
+django-fsm 1.4.0 2011-12-21
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Add graph\_transition command for drawing state transition picture
+
+django-fsm 1.3.0 2011-07-28
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Add direct field modification protection
+
+django-fsm 1.2.0 2011-03-23
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Add pre\_transition and post\_transition signals
+
+django-fsm 1.1.0 2011-02-22
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Add support for transition conditions
+- Allow multiple FSMField in one model
+- Contribute get\_available\_FIELD\_transitions for model class
+
+django-fsm 1.0.0 2010-10-12
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Initial public release
+
+.. |Build Status| image:: https://travis-ci.org/kmmbvnr/django-fsm.svg?branch=master
+ :target: https://travis-ci.org/kmmbvnr/django-fsm
+.. |Downloads| image:: https://img.shields.io/pypi/dm/django-fsm.svg
+ :target: https://pypi.python.org/pypi/django-fsm
+.. |Gitter| image:: https://badges.gitter.im/Join%20Chat.svg
+ :target: https://gitter.im/kmmbvnr/django-fsm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
diff --git a/django_fsm/__init__.py b/django_fsm/__init__.py
index 373d795..56c8457 100644
--- a/django_fsm/__init__.py
+++ b/django_fsm/__init__.py
@@ -3,20 +3,23 @@
State tracking functionality for django models
"""
import inspect
-from functools import wraps
import sys
+import warnings
+from functools import wraps
from django.db import models
+from django.db.models.signals import class_prepared
+from django.utils.functional import curry
+from django_fsm.signals import pre_transition, post_transition
+
try:
from django.apps import apps as django_apps
+
def get_model(app_label, model_name):
app = django_apps.get_app_config(app_label)
return app.get_model(model_name)
except ImportError:
from django.db.models.loading import get_model
-from django.db.models.signals import class_prepared
-from django.utils.functional import curry
-from django_fsm.signals import pre_transition, post_transition
__all__ = ['TransitionNotAllowed', 'ConcurrentTransition',
@@ -56,6 +59,11 @@ else:
class TransitionNotAllowed(Exception):
"""Raised when a transition is not allowed"""
+ def __init__(self, *args, **kwargs):
+ self.object = kwargs.pop('object', None)
+ self.method = kwargs.pop('method', None)
+ super(TransitionNotAllowed, self).__init__(*args, **kwargs)
+
class ConcurrentTransition(Exception):
"""
@@ -79,10 +87,16 @@ class Transition(object):
def name(self):
return self.method.__name__
- def has_perm(self, user):
+ def has_perm(self, instance, user):
if not self.permission:
return True
- elif callable(self.permission) and self.permission(user):
+ elif callable(self.permission):
+ try:
+ return bool(self.permission(instance, user))
+ except TypeError:
+ warnings.warn('Callable permissions without instance parameter is depricated')
+ return bool(self.permission(user))
+ elif user.has_perm(self.permission, instance):
return True
elif user.has_perm(self.permission):
return True
@@ -101,7 +115,7 @@ def get_available_FIELD_transitions(instance, field):
for name, transition in transitions.items():
meta = transition._django_fsm
- for state in [curr_state, '*']:
+ for state in [curr_state, '*', '+']:
if state in meta.transitions:
transition = meta.transitions[state]
if all(map(lambda condition: condition(instance), transition.conditions)):
... 588 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-fsm.git
More information about the Python-modules-commits
mailing list