1
- # -*- coding: utf-8 -*-
2
1
"""
3
2
State tracking functionality for django models
4
3
"""
5
4
import inspect
6
- import sys
7
- from functools import wraps
5
+ from functools import partialmethod , wraps
8
6
9
7
import django
10
8
from django .db import models
13
11
from django .db .models .signals import class_prepared
14
12
from django_fsm .signals import pre_transition , post_transition
15
13
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
-
22
14
try :
23
15
from django .apps import apps as django_apps
24
16
@@ -46,25 +38,6 @@ def get_model(app_label, model_name):
46
38
"RETURN_VALUE" ,
47
39
]
48
40
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
-
68
41
# South support; see http://south.aeracode.org/docs/tutorial/part4.html#simple-inheritance
69
42
try :
70
43
from south .modelsinspector import add_introspection_rules
@@ -82,7 +55,7 @@ class TransitionNotAllowed(Exception):
82
55
def __init__ (self , * args , ** kwargs ):
83
56
self .object = kwargs .pop ("object" , None )
84
57
self .method = kwargs .pop ("method" , None )
85
- super (TransitionNotAllowed , self ).__init__ (* args , ** kwargs )
58
+ super ().__init__ (* args , ** kwargs )
86
59
87
60
88
61
class InvalidResultState (Exception ):
@@ -97,7 +70,7 @@ class ConcurrentTransition(Exception):
97
70
"""
98
71
99
72
100
- class Transition ( object ) :
73
+ class Transition :
101
74
def __init__ (self , method , source , target , on_error , conditions , permission , custom ):
102
75
self .method = method
103
76
self .source = source
@@ -166,7 +139,7 @@ def get_available_user_FIELD_transitions(instance, user, field):
166
139
yield transition
167
140
168
141
169
- class FSMMeta ( object ) :
142
+ class FSMMeta :
170
143
"""
171
144
Models methods transitions meta information
172
145
"""
@@ -185,7 +158,7 @@ def get_transition(self, source):
185
158
186
159
def add_transition (self , method , source , target , on_error = None , conditions = [], permission = None , custom = {}):
187
160
if source in self .transitions :
188
- raise AssertionError ("Duplicate transition for {0 } state" . format ( source ) )
161
+ raise AssertionError (f "Duplicate transition for { source } state" )
189
162
190
163
self .transitions [source ] = Transition (
191
164
method = method ,
@@ -237,20 +210,20 @@ def next_state(self, current_state):
237
210
transition = self .get_transition (current_state )
238
211
239
212
if transition is None :
240
- raise TransitionNotAllowed ("No transition from {0}" . format ( current_state ) )
213
+ raise TransitionNotAllowed (f "No transition from { current_state } " )
241
214
242
215
return transition .target
243
216
244
217
def exception_state (self , current_state ):
245
218
transition = self .get_transition (current_state )
246
219
247
220
if transition is None :
248
- raise TransitionNotAllowed ("No transition from {0}" . format ( current_state ) )
221
+ raise TransitionNotAllowed (f "No transition from { current_state } " )
249
222
250
223
return transition .on_error
251
224
252
225
253
- class FSMFieldDescriptor ( object ) :
226
+ class FSMFieldDescriptor :
254
227
def __init__ (self , field ):
255
228
self .field = field
256
229
@@ -261,14 +234,14 @@ def __get__(self, instance, type=None):
261
234
262
235
def __set__ (self , instance , value ):
263
236
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" )
265
238
266
239
# Update state
267
240
self .field .set_proxy (instance , value )
268
241
self .field .set_state (instance , value )
269
242
270
243
271
- class FSMFieldMixin ( object ) :
244
+ class FSMFieldMixin :
272
245
descriptor_class = FSMFieldDescriptor
273
246
274
247
def __init__ (self , * args , ** kwargs ):
@@ -288,10 +261,10 @@ def __init__(self, *args, **kwargs):
288
261
self .state_proxy [state ] = proxy_cls_ref
289
262
kwargs ["choices" ] = choices
290
263
291
- super (FSMFieldMixin , self ).__init__ (* args , ** kwargs )
264
+ super ().__init__ (* args , ** kwargs )
292
265
293
266
def deconstruct (self ):
294
- name , path , args , kwargs = super (FSMFieldMixin , self ).deconstruct ()
267
+ name , path , args , kwargs = super ().deconstruct ()
295
268
if self .protected :
296
269
kwargs ["protected" ] = self .protected
297
270
return name , path , args , kwargs
@@ -337,7 +310,7 @@ def set_proxy(self, instance, state):
337
310
338
311
model = get_model (app_label , model_name )
339
312
if model is None :
340
- raise ValueError ("No model found {0}" . format ( state_proxy ) )
313
+ raise ValueError (f "No model found { state_proxy } " )
341
314
342
315
instance .__class__ = model
343
316
@@ -348,13 +321,13 @@ def change_state(self, instance, method, *args, **kwargs):
348
321
349
322
if not meta .has_transition (current_state ):
350
323
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 } '" ,
352
325
object = instance ,
353
326
method = method ,
354
327
)
355
328
if not meta .conditions_met (instance , current_state ):
356
329
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
358
331
)
359
332
360
333
next_state = meta .next_state (current_state )
@@ -409,15 +382,15 @@ def get_all_transitions(self, instance_cls):
409
382
def contribute_to_class (self , cls , name , ** kwargs ):
410
383
self .base_cls = cls
411
384
412
- super (FSMFieldMixin , self ).contribute_to_class (cls , name , ** kwargs )
385
+ super ().contribute_to_class (cls , name , ** kwargs )
413
386
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 ))
415
388
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 )
417
390
)
418
391
setattr (
419
392
cls ,
420
- "get_available_user_{0}_transitions" . format ( self .name ) ,
393
+ f "get_available_user_{ self .name } _transitions" ,
421
394
partialmethod (get_available_user_FIELD_transitions , field = self ),
422
395
)
423
396
@@ -459,7 +432,7 @@ class FSMField(FSMFieldMixin, models.CharField):
459
432
460
433
def __init__ (self , * args , ** kwargs ):
461
434
kwargs .setdefault ("max_length" , 50 )
462
- super (FSMField , self ).__init__ (* args , ** kwargs )
435
+ super ().__init__ (* args , ** kwargs )
463
436
464
437
465
438
class FSMIntegerField (FSMFieldMixin , models .IntegerField ):
@@ -535,7 +508,7 @@ class ConcurrentTransitionMixin(object):
535
508
"""
536
509
537
510
def __init__ (self , * args , ** kwargs ):
538
- super (ConcurrentTransitionMixin , self ).__init__ (* args , ** kwargs )
511
+ super ().__init__ (* args , ** kwargs )
539
512
self ._update_initial_state ()
540
513
541
514
@property
@@ -550,9 +523,9 @@ def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_updat
550
523
filter_on = filter (lambda field : field .model == base_qs .model , self .state_fields )
551
524
552
525
# 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 }
554
527
555
- updated = super (ConcurrentTransitionMixin , self )._do_update (
528
+ updated = super ()._do_update (
556
529
base_qs = base_qs .filter (** state_filter ),
557
530
using = using ,
558
531
pk_val = pk_val ,
@@ -573,14 +546,14 @@ def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_updat
573
546
return updated
574
547
575
548
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 }
577
550
578
551
def refresh_from_db (self , * args , ** kwargs ):
579
- super (ConcurrentTransitionMixin , self ).refresh_from_db (* args , ** kwargs )
552
+ super ().refresh_from_db (* args , ** kwargs )
580
553
self ._update_initial_state ()
581
554
582
555
def save (self , * args , ** kwargs ):
583
- super (ConcurrentTransitionMixin , self ).save (* args , ** kwargs )
556
+ super ().save (* args , ** kwargs )
584
557
self ._update_initial_state ()
585
558
586
559
@@ -625,36 +598,34 @@ def can_proceed(bound_method, check_conditions=True):
625
598
conditions.
626
599
"""
627
600
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__ )
630
602
631
603
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 )
634
606
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 ))
636
608
637
609
638
610
def has_transition_perm (bound_method , user ):
639
611
"""
640
612
Returns True if model in state allows to call bound_method and user have rights on it
641
613
"""
642
614
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__ )
645
616
646
617
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 )
649
620
650
621
return (
651
622
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 )
654
625
)
655
626
656
627
657
- class State ( object ) :
628
+ class State :
658
629
def get_state (self , model , transition , result , args = [], kwargs = {}):
659
630
raise NotImplementedError
660
631
@@ -666,7 +637,7 @@ def __init__(self, *allowed_states):
666
637
def get_state (self , model , transition , result , args = [], kwargs = {}):
667
638
if self .allowed_states is not None :
668
639
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 } " )
670
641
return result
671
642
672
643
@@ -679,5 +650,5 @@ def get_state(self, model, transition, result, args=[], kwargs={}):
679
650
result_state = self .func (model , * args , ** kwargs )
680
651
if self .allowed_states is not None :
681
652
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 } " )
683
654
return result_state
0 commit comments