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
@@ -166,7 +139,7 @@ def get_available_user_FIELD_transitions(instance, user, field):
166139 yield transition
167140
168141
169- class FSMMeta ( object ) :
142+ class FSMMeta :
170143 """
171144 Models methods transitions meta information
172145 """
@@ -185,7 +158,7 @@ def get_transition(self, source):
185158
186159 def add_transition (self , method , source , target , on_error = None , conditions = [], permission = None , custom = {}):
187160 if source in self .transitions :
188- raise AssertionError ("Duplicate transition for {0 } state" . format ( source ) )
161+ raise AssertionError (f "Duplicate transition for { source } state" )
189162
190163 self .transitions [source ] = Transition (
191164 method = method ,
@@ -237,20 +210,20 @@ def next_state(self, current_state):
237210 transition = self .get_transition (current_state )
238211
239212 if transition is None :
240- raise TransitionNotAllowed ("No transition from {0}" . format ( current_state ) )
213+ raise TransitionNotAllowed (f "No transition from { current_state } " )
241214
242215 return transition .target
243216
244217 def exception_state (self , current_state ):
245218 transition = self .get_transition (current_state )
246219
247220 if transition is None :
248- raise TransitionNotAllowed ("No transition from {0}" . format ( current_state ) )
221+ raise TransitionNotAllowed (f "No transition from { current_state } " )
249222
250223 return transition .on_error
251224
252225
253- class FSMFieldDescriptor ( object ) :
226+ class FSMFieldDescriptor :
254227 def __init__ (self , field ):
255228 self .field = field
256229
@@ -261,14 +234,14 @@ def __get__(self, instance, type=None):
261234
262235 def __set__ (self , instance , value ):
263236 if self .field .protected and self .field .name in instance .__dict__ :
264- raise AttributeError ("Direct {0 } modification is not allowed" . format ( self . field . name ) )
237+ raise AttributeError (f "Direct { self . field . name } modification is not allowed" )
265238
266239 # Update state
267240 self .field .set_proxy (instance , value )
268241 self .field .set_state (instance , value )
269242
270243
271- class FSMFieldMixin ( object ) :
244+ class FSMFieldMixin :
272245 descriptor_class = FSMFieldDescriptor
273246
274247 def __init__ (self , * args , ** kwargs ):
@@ -288,10 +261,10 @@ def __init__(self, *args, **kwargs):
288261 self .state_proxy [state ] = proxy_cls_ref
289262 kwargs ["choices" ] = choices
290263
291- super (FSMFieldMixin , self ).__init__ (* args , ** kwargs )
264+ super ().__init__ (* args , ** kwargs )
292265
293266 def deconstruct (self ):
294- name , path , args , kwargs = super (FSMFieldMixin , self ).deconstruct ()
267+ name , path , args , kwargs = super ().deconstruct ()
295268 if self .protected :
296269 kwargs ["protected" ] = self .protected
297270 return name , path , args , kwargs
@@ -337,7 +310,7 @@ def set_proxy(self, instance, state):
337310
338311 model = get_model (app_label , model_name )
339312 if model is None :
340- raise ValueError ("No model found {0}" . format ( state_proxy ) )
313+ raise ValueError (f "No model found { state_proxy } " )
341314
342315 instance .__class__ = model
343316
@@ -348,13 +321,13 @@ def change_state(self, instance, method, *args, **kwargs):
348321
349322 if not meta .has_transition (current_state ):
350323 raise TransitionNotAllowed (
351- "Can't switch from state '{0 }' using method '{1 }'" . format ( current_state , method_name ) ,
324+ f "Can't switch from state '{ current_state } ' using method '{ method_name } '" ,
352325 object = instance ,
353326 method = method ,
354327 )
355328 if not meta .conditions_met (instance , current_state ):
356329 raise TransitionNotAllowed (
357- "Transition conditions have not been met for method '{0 }'" . format ( method_name ) , object = instance , method = method
330+ f "Transition conditions have not been met for method '{ method_name } '" , object = instance , method = method
358331 )
359332
360333 next_state = meta .next_state (current_state )
@@ -409,15 +382,15 @@ def get_all_transitions(self, instance_cls):
409382 def contribute_to_class (self , cls , name , ** kwargs ):
410383 self .base_cls = cls
411384
412- super (FSMFieldMixin , self ).contribute_to_class (cls , name , ** kwargs )
385+ super ().contribute_to_class (cls , name , ** kwargs )
413386 setattr (cls , self .name , self .descriptor_class (self ))
414- setattr (cls , "get_all_{0}_transitions" . format ( self .name ) , partialmethod (get_all_FIELD_transitions , field = self ))
387+ setattr (cls , f "get_all_{ self .name } _transitions" , partialmethod (get_all_FIELD_transitions , field = self ))
415388 setattr (
416- cls , "get_available_{0}_transitions" . format ( self .name ) , partialmethod (get_available_FIELD_transitions , field = self )
389+ cls , f "get_available_{ self .name } _transitions" , partialmethod (get_available_FIELD_transitions , field = self )
417390 )
418391 setattr (
419392 cls ,
420- "get_available_user_{0}_transitions" . format ( self .name ) ,
393+ f "get_available_user_{ self .name } _transitions" ,
421394 partialmethod (get_available_user_FIELD_transitions , field = self ),
422395 )
423396
@@ -459,7 +432,7 @@ class FSMField(FSMFieldMixin, models.CharField):
459432
460433 def __init__ (self , * args , ** kwargs ):
461434 kwargs .setdefault ("max_length" , 50 )
462- super (FSMField , self ).__init__ (* args , ** kwargs )
435+ super ().__init__ (* args , ** kwargs )
463436
464437
465438class FSMIntegerField (FSMFieldMixin , models .IntegerField ):
@@ -535,7 +508,7 @@ class ConcurrentTransitionMixin(object):
535508 """
536509
537510 def __init__ (self , * args , ** kwargs ):
538- super (ConcurrentTransitionMixin , self ).__init__ (* args , ** kwargs )
511+ super ().__init__ (* args , ** kwargs )
539512 self ._update_initial_state ()
540513
541514 @property
@@ -550,9 +523,9 @@ def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_updat
550523 filter_on = filter (lambda field : field .model == base_qs .model , self .state_fields )
551524
552525 # state filter will be used to narrow down the standard filter checking only PK
553- state_filter = dict (( field .attname , self .__initial_states [field .attname ]) for field in filter_on )
526+ state_filter = { field .attname : self .__initial_states [field .attname ] for field in filter_on }
554527
555- updated = super (ConcurrentTransitionMixin , self )._do_update (
528+ updated = super ()._do_update (
556529 base_qs = base_qs .filter (** state_filter ),
557530 using = using ,
558531 pk_val = pk_val ,
@@ -573,14 +546,14 @@ def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_updat
573546 return updated
574547
575548 def _update_initial_state (self ):
576- self .__initial_states = dict (( field .attname , field .value_from_object (self )) for field in self .state_fields )
549+ self .__initial_states = { field .attname : field .value_from_object (self ) for field in self .state_fields }
577550
578551 def refresh_from_db (self , * args , ** kwargs ):
579- super (ConcurrentTransitionMixin , self ).refresh_from_db (* args , ** kwargs )
552+ super ().refresh_from_db (* args , ** kwargs )
580553 self ._update_initial_state ()
581554
582555 def save (self , * args , ** kwargs ):
583- super (ConcurrentTransitionMixin , self ).save (* args , ** kwargs )
556+ super ().save (* args , ** kwargs )
584557 self ._update_initial_state ()
585558
586559
@@ -625,36 +598,34 @@ def can_proceed(bound_method, check_conditions=True):
625598 conditions.
626599 """
627600 if not hasattr (bound_method , "_django_fsm" ):
628- im_func = getattr (bound_method , "im_func" , getattr (bound_method , "__func__" ))
629- raise TypeError ("%s method is not transition" % im_func .__name__ )
601+ raise TypeError ("%s method is not transition" % bound_method .__func__ .__name__ )
630602
631603 meta = bound_method ._django_fsm
632- im_self = getattr ( bound_method , "im_self" , getattr ( bound_method , " __self__" ))
633- current_state = meta .field .get_state (im_self )
604+ self = bound_method . __self__
605+ current_state = meta .field .get_state (self )
634606
635- return meta .has_transition (current_state ) and (not check_conditions or meta .conditions_met (im_self , current_state ))
607+ return meta .has_transition (current_state ) and (not check_conditions or meta .conditions_met (self , current_state ))
636608
637609
638610def has_transition_perm (bound_method , user ):
639611 """
640612 Returns True if model in state allows to call bound_method and user have rights on it
641613 """
642614 if not hasattr (bound_method , "_django_fsm" ):
643- im_func = getattr (bound_method , "im_func" , getattr (bound_method , "__func__" ))
644- raise TypeError ("%s method is not transition" % im_func .__name__ )
615+ raise TypeError ("%s method is not transition" % bound_method .__func__ .__name__ )
645616
646617 meta = bound_method ._django_fsm
647- im_self = getattr ( bound_method , "im_self" , getattr ( bound_method , " __self__" ))
648- current_state = meta .field .get_state (im_self )
618+ self = bound_method . __self__
619+ current_state = meta .field .get_state (self )
649620
650621 return (
651622 meta .has_transition (current_state )
652- and meta .conditions_met (im_self , current_state )
653- and meta .has_transition_perm (im_self , current_state , user )
623+ and meta .conditions_met (self , current_state )
624+ and meta .has_transition_perm (self , current_state , user )
654625 )
655626
656627
657- class State ( object ) :
628+ class State :
658629 def get_state (self , model , transition , result , args = [], kwargs = {}):
659630 raise NotImplementedError
660631
@@ -666,7 +637,7 @@ def __init__(self, *allowed_states):
666637 def get_state (self , model , transition , result , args = [], kwargs = {}):
667638 if self .allowed_states is not None :
668639 if result not in self .allowed_states :
669- raise InvalidResultState ("{ } is not in list of allowed states\n {}" . format ( result , self .allowed_states ) )
640+ raise InvalidResultState (f" { result } is not in list of allowed states\n { self .allowed_states } " )
670641 return result
671642
672643
@@ -679,5 +650,5 @@ def get_state(self, model, transition, result, args=[], kwargs={}):
679650 result_state = self .func (model , * args , ** kwargs )
680651 if self .allowed_states is not None :
681652 if result_state not in self .allowed_states :
682- raise InvalidResultState ("{ } is not in list of allowed states\n {}" . format ( result_state , self .allowed_states ) )
653+ raise InvalidResultState (f" { result_state } is not in list of allowed states\n { self .allowed_states } " )
683654 return result_state
0 commit comments