@@ -16,25 +16,31 @@ def all_fsm_fields_data(model):
16
16
return [(field , model ) for field in model ._meta .get_fields () if isinstance (field , FSMFieldMixin )]
17
17
18
18
19
- def node_name (field , state ):
19
+ def node_name (field , state ) -> str :
20
20
opts = field .model ._meta
21
21
return "{}.{}.{}.{}" .format (opts .app_label , opts .verbose_name .replace (" " , "_" ), field .name , state )
22
22
23
23
24
- def node_label (field , state ):
25
- if isinstance (state , int ) or (isinstance (state , bool ) and hasattr (field , "choices" )):
24
+ def node_label (field , state ) -> str :
25
+ if isinstance (state , int ):
26
+ return str (state )
27
+ if isinstance (state , bool ) and hasattr (field , "choices" ):
26
28
return force_str (dict (field .choices ).get (state ))
27
29
return state
28
30
29
31
30
- def generate_dot (fields_data ): # noqa: C901, PLR0912
32
+ def generate_dot (fields_data , ignore_transitions : list [str ] | None = None ): # noqa: C901, PLR0912
33
+ ignore_transitions = ignore_transitions or []
31
34
result = graphviz .Digraph ()
32
35
33
36
for field , model in fields_data :
34
37
sources , targets , edges , any_targets , any_except_targets = set (), set (), set (), set (), set ()
35
38
36
39
# dump nodes and edges
37
40
for transition in field .get_all_transitions (model ):
41
+ if transition .name in ignore_transitions :
42
+ continue
43
+
38
44
_targets = list (
39
45
(state for state in transition .target .allowed_states )
40
46
if isinstance (transition .target , (GET_STATE , RETURN_VALUE ))
@@ -127,7 +133,7 @@ def add_arguments(self, parser):
127
133
"-o" ,
128
134
action = "store" ,
129
135
dest = "outputfile" ,
130
- help = ( "Render output file. Type of output dependent on file extensions. Use png or jpg to render graph to image." ) ,
136
+ help = "Render output file. Type of output dependent on file extensions. Use png or jpg to render graph to image." ,
131
137
)
132
138
parser .add_argument (
133
139
"--layout" ,
@@ -137,6 +143,14 @@ def add_arguments(self, parser):
137
143
default = "dot" ,
138
144
help = f"Layout to be used by GraphViz for visualization. Layouts: { get_graphviz_layouts ()} ." ,
139
145
)
146
+ parser .add_argument (
147
+ "--exclude" ,
148
+ "-e" ,
149
+ action = "store" ,
150
+ dest = "exclude" ,
151
+ default = "" ,
152
+ help = "Ignore transitions with this name." ,
153
+ )
140
154
parser .add_argument ("args" , nargs = "*" , help = ("[appname[.model[.field]]]" ))
141
155
142
156
def render_output (self , graph , ** options ):
@@ -153,9 +167,8 @@ def handle(self, *args, **options):
153
167
field_spec = arg .split ("." )
154
168
155
169
if len (field_spec ) == 1 :
156
- app = apps .get_app (field_spec [0 ])
157
- models = apps .get_models (app )
158
- for model in models :
170
+ app = apps .get_app_config (field_spec [0 ])
171
+ for model in apps .get_models (app ):
159
172
fields_data += all_fsm_fields_data (model )
160
173
if len (field_spec ) == 2 : # noqa: PLR2004
161
174
model = apps .get_model (field_spec [0 ], field_spec [1 ])
@@ -166,7 +179,8 @@ def handle(self, *args, **options):
166
179
else :
167
180
for model in apps .get_models ():
168
181
fields_data += all_fsm_fields_data (model )
169
- dotdata = generate_dot (fields_data )
182
+
183
+ dotdata = generate_dot (fields_data , ignore_transitions = options ["exclude" ].split ("," ))
170
184
171
185
if options ["outputfile" ]:
172
186
self .render_output (dotdata , ** options )
0 commit comments