1- # -*- coding: utf-8 -*-
21"""
32State tracking functionality for django models
43"""
54import inspect
6- import sys
7- from functools import wraps
5+ from functools import partialmethod , wraps
86
97import django
108from django .db import models
1311from django .db .models .signals import class_prepared
1412from django_fsm .signals import pre_transition , post_transition
1513
16- try :
17- from functools import partialmethod
18- except ImportError :
19- # python 2.7, so we are on django<=1.11
20- from django .utils .functional import curry as partialmethod
21-
2214try :
2315 from django .apps import apps as django_apps
2416
@@ -46,25 +38,6 @@ def get_model(app_label, model_name):
4638 "RETURN_VALUE" ,
4739]
4840
49- if sys .version_info [:2 ] == (2 , 6 ):
50- # Backport of Python 2.7 inspect.getmembers,
51- # since Python 2.6 ships buggy implementation
52- def __getmembers (object , predicate = None ):
53- """Return all members of an object as (name, value) pairs sorted by name.
54- Optionally, only return members that satisfy a given predicate."""
55- results = []
56- for key in dir (object ):
57- try :
58- value = getattr (object , key )
59- except AttributeError :
60- continue
61- if not predicate or predicate (value ):
62- results .append ((key , value ))
63- results .sort ()
64- return results
65-
66- inspect .getmembers = __getmembers
67-
6841# South support; see http://south.aeracode.org/docs/tutorial/part4.html#simple-inheritance
6942try :
7043 from south .modelsinspector import add_introspection_rules
@@ -82,7 +55,7 @@ class TransitionNotAllowed(Exception):
8255 def __init__ (self , * args , ** kwargs ):
8356 self .object = kwargs .pop ("object" , None )
8457 self .method = kwargs .pop ("method" , None )
85- super (TransitionNotAllowed , self ).__init__ (* args , ** kwargs )
58+ super ().__init__ (* args , ** kwargs )
8659
8760
8861class InvalidResultState (Exception ):
@@ -97,7 +70,7 @@ class ConcurrentTransition(Exception):
9770 """
9871
9972
100- class Transition ( object ) :
73+ class Transition :
10174 def __init__ (self , method , source , target , on_error , conditions , permission , custom ):
10275 self .method = method
10376 self .source = source
@@ -155,7 +128,7 @@ def get_available_user_FIELD_transitions(instance, user, field):
155128 yield transition
156129
157130
158- class FSMMeta ( object ) :
131+ class FSMMeta :
159132 """
160133 Models methods transitions meta information
161134 """
@@ -174,7 +147,7 @@ def get_transition(self, source):
174147
175148 def add_transition (self , method , source , target , on_error = None , conditions = [], permission = None , custom = {}):
176149 if source in self .transitions :
177- raise AssertionError ("Duplicate transition for {0 } state" . format ( source ) )
150+ raise AssertionError (f "Duplicate transition for { source } state" )
178151
179152 self .transitions [source ] = Transition (
180153 method = method ,
@@ -226,20 +199,20 @@ def next_state(self, current_state):
226199 transition = self .get_transition (current_state )
227200
228201 if transition is None :
229- raise TransitionNotAllowed ("No transition from {0}" . format ( current_state ) )
202+ raise TransitionNotAllowed (f "No transition from { current_state } " )
230203
231204 return transition .target
232205
233206 def exception_state (self , current_state ):
234207 transition = self .get_transition (current_state )
235208
236209 if transition is None :
237- raise TransitionNotAllowed ("No transition from {0}" . format ( current_state ) )
210+ raise TransitionNotAllowed (f "No transition from { current_state } " )
238211
239212 return transition .on_error
240213
241214
242- class FSMFieldDescriptor ( object ) :
215+ class FSMFieldDescriptor :
243216 def __init__ (self , field ):
244217 self .field = field
245218
@@ -250,14 +223,14 @@ def __get__(self, instance, type=None):
250223
251224 def __set__ (self , instance , value ):
252225 if self .field .protected and self .field .name in instance .__dict__ :
253- raise AttributeError ("Direct {0 } modification is not allowed" . format ( self . field . name ) )
226+ raise AttributeError (f "Direct { self . field . name } modification is not allowed" )
254227
255228 # Update state
256229 self .field .set_proxy (instance , value )
257230 self .field .set_state (instance , value )
258231
259232
260- class FSMFieldMixin ( object ) :
233+ class FSMFieldMixin :
261234 descriptor_class = FSMFieldDescriptor
262235
263236 def __init__ (self , * args , ** kwargs ):
@@ -277,10 +250,10 @@ def __init__(self, *args, **kwargs):
277250 self .state_proxy [state ] = proxy_cls_ref
278251 kwargs ["choices" ] = choices
279252
280- super (FSMFieldMixin , self ).__init__ (* args , ** kwargs )
253+ super ().__init__ (* args , ** kwargs )
281254
282255 def deconstruct (self ):
283- name , path , args , kwargs = super (FSMFieldMixin , self ).deconstruct ()
256+ name , path , args , kwargs = super ().deconstruct ()
284257 if self .protected :
285258 kwargs ["protected" ] = self .protected
286259 return name , path , args , kwargs
@@ -326,7 +299,7 @@ def set_proxy(self, instance, state):
326299
327300 model = get_model (app_label , model_name )
328301 if model is None :
329- raise ValueError ("No model found {0}" . format ( state_proxy ) )
302+ raise ValueError (f "No model found { state_proxy } " )
330303
331304 instance .__class__ = model
332305
@@ -337,13 +310,13 @@ def change_state(self, instance, method, *args, **kwargs):
337310
338311 if not meta .has_transition (current_state ):
339312 raise TransitionNotAllowed (
340- "Can't switch from state '{0 }' using method '{1 }'" . format ( current_state , method_name ) ,
313+ f "Can't switch from state '{ current_state } ' using method '{ method_name } '" ,
341314 object = instance ,
342315 method = method ,
343316 )
344317 if not meta .conditions_met (instance , current_state ):
345318 raise TransitionNotAllowed (
346- "Transition conditions have not been met for method '{0 }'" . format ( method_name ) , object = instance , method = method
319+ f "Transition conditions have not been met for method '{ method_name } '" , object = instance , method = method
347320 )
348321
349322 next_state = meta .next_state (current_state )
@@ -398,15 +371,15 @@ def get_all_transitions(self, instance_cls):
398371 def contribute_to_class (self , cls , name , ** kwargs ):
399372 self .base_cls = cls
400373
401- super (FSMFieldMixin , self ).contribute_to_class (cls , name , ** kwargs )
374+ super ().contribute_to_class (cls , name , ** kwargs )
402375 setattr (cls , self .name , self .descriptor_class (self ))
403- setattr (cls , "get_all_{0}_transitions" . format ( self .name ) , partialmethod (get_all_FIELD_transitions , field = self ))
376+ setattr (cls , f "get_all_{ self .name } _transitions" , partialmethod (get_all_FIELD_transitions , field = self ))
404377 setattr (
405- cls , "get_available_{0}_transitions" . format ( self .name ) , partialmethod (get_available_FIELD_transitions , field = self )
378+ cls , f "get_available_{ self .name } _transitions" , partialmethod (get_available_FIELD_transitions , field = self )
406379 )
407380 setattr (
408381 cls ,
409- "get_available_user_{0}_transitions" . format ( self .name ) ,
382+ f "get_available_user_{ self .name } _transitions" ,
410383 partialmethod (get_available_user_FIELD_transitions , field = self ),
411384 )
412385
@@ -448,7 +421,7 @@ class FSMField(FSMFieldMixin, models.CharField):
448421
449422 def __init__ (self , * args , ** kwargs ):
450423 kwargs .setdefault ("max_length" , 50 )
451- super (FSMField , self ).__init__ (* args , ** kwargs )
424+ super ().__init__ (* args , ** kwargs )
452425
453426
454427class FSMIntegerField (FSMFieldMixin , models .IntegerField ):
@@ -471,7 +444,7 @@ def set_state(self, instance, state):
471444 instance .__dict__ [self .attname ] = self .to_python (state )
472445
473446
474- class ConcurrentTransitionMixin ( object ) :
447+ class ConcurrentTransitionMixin :
475448 """
476449 Protects a Model from undesirable effects caused by concurrently executed transitions,
477450 e.g. running the same transition multiple times at the same time, or running different
@@ -498,7 +471,7 @@ class ConcurrentTransitionMixin(object):
498471 """
499472
500473 def __init__ (self , * args , ** kwargs ):
501- super (ConcurrentTransitionMixin , self ).__init__ (* args , ** kwargs )
474+ super ().__init__ (* args , ** kwargs )
502475 self ._update_initial_state ()
503476
504477 @property
@@ -513,9 +486,9 @@ def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_updat
513486 filter_on = filter (lambda field : field .model == base_qs .model , self .state_fields )
514487
515488 # state filter will be used to narrow down the standard filter checking only PK
516- state_filter = dict (( field .attname , self .__initial_states [field .attname ]) for field in filter_on )
489+ state_filter = { field .attname : self .__initial_states [field .attname ] for field in filter_on }
517490
518- updated = super (ConcurrentTransitionMixin , self )._do_update (
491+ updated = super ()._do_update (
519492 base_qs = base_qs .filter (** state_filter ),
520493 using = using ,
521494 pk_val = pk_val ,
@@ -536,14 +509,14 @@ def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_updat
536509 return updated
537510
538511 def _update_initial_state (self ):
539- self .__initial_states = dict (( field .attname , field .value_from_object (self )) for field in self .state_fields )
512+ self .__initial_states = { field .attname : field .value_from_object (self ) for field in self .state_fields }
540513
541514 def refresh_from_db (self , * args , ** kwargs ):
542- super (ConcurrentTransitionMixin , self ).refresh_from_db (* args , ** kwargs )
515+ super ().refresh_from_db (* args , ** kwargs )
543516 self ._update_initial_state ()
544517
545518 def save (self , * args , ** kwargs ):
546- super (ConcurrentTransitionMixin , self ).save (* args , ** kwargs )
519+ super ().save (* args , ** kwargs )
547520 self ._update_initial_state ()
548521
549522
@@ -588,36 +561,34 @@ def can_proceed(bound_method, check_conditions=True):
588561 conditions.
589562 """
590563 if not hasattr (bound_method , "_django_fsm" ):
591- im_func = getattr (bound_method , "im_func" , getattr (bound_method , "__func__" ))
592- raise TypeError ("%s method is not transition" % im_func .__name__ )
564+ raise TypeError ("%s method is not transition" % bound_method .__func__ .__name__ )
593565
594566 meta = bound_method ._django_fsm
595- im_self = getattr ( bound_method , "im_self" , getattr ( bound_method , " __self__" ))
596- current_state = meta .field .get_state (im_self )
567+ self = bound_method . __self__
568+ current_state = meta .field .get_state (self )
597569
598- return meta .has_transition (current_state ) and (not check_conditions or meta .conditions_met (im_self , current_state ))
570+ return meta .has_transition (current_state ) and (not check_conditions or meta .conditions_met (self , current_state ))
599571
600572
601573def has_transition_perm (bound_method , user ):
602574 """
603575 Returns True if model in state allows to call bound_method and user have rights on it
604576 """
605577 if not hasattr (bound_method , "_django_fsm" ):
606- im_func = getattr (bound_method , "im_func" , getattr (bound_method , "__func__" ))
607- raise TypeError ("%s method is not transition" % im_func .__name__ )
578+ raise TypeError ("%s method is not transition" % bound_method .__func__ .__name__ )
608579
609580 meta = bound_method ._django_fsm
610- im_self = getattr ( bound_method , "im_self" , getattr ( bound_method , " __self__" ))
611- current_state = meta .field .get_state (im_self )
581+ self = bound_method . __self__
582+ current_state = meta .field .get_state (self )
612583
613584 return (
614585 meta .has_transition (current_state )
615- and meta .conditions_met (im_self , current_state )
616- and meta .has_transition_perm (im_self , current_state , user )
586+ and meta .conditions_met (self , current_state )
587+ and meta .has_transition_perm (self , current_state , user )
617588 )
618589
619590
620- class State ( object ) :
591+ class State :
621592 def get_state (self , model , transition , result , args = [], kwargs = {}):
622593 raise NotImplementedError
623594
@@ -629,7 +600,7 @@ def __init__(self, *allowed_states):
629600 def get_state (self , model , transition , result , args = [], kwargs = {}):
630601 if self .allowed_states is not None :
631602 if result not in self .allowed_states :
632- raise InvalidResultState ("{ } is not in list of allowed states\n {}" . format ( result , self .allowed_states ) )
603+ raise InvalidResultState (f" { result } is not in list of allowed states\n { self .allowed_states } " )
633604 return result
634605
635606
@@ -642,5 +613,5 @@ def get_state(self, model, transition, result, args=[], kwargs={}):
642613 result_state = self .func (model , * args , ** kwargs )
643614 if self .allowed_states is not None :
644615 if result_state not in self .allowed_states :
645- raise InvalidResultState ("{ } is not in list of allowed states\n {}" . format ( result , self .allowed_states ) )
616+ raise InvalidResultState (f" { result } is not in list of allowed states\n { self .allowed_states } " )
646617 return result_state
0 commit comments