Skip to content

Commit deef21f

Browse files
committed
Leverage Ruff
1 parent 40c6d39 commit deef21f

22 files changed

+152
-133
lines changed

CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
Changelog
22
=========
33

4+
Unreleased
5+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6+
7+
- Add support for Django 5.2
8+
- Add support for python 3.13
9+
10+
411
django-fsm-2 4.0.0 2024-09-02
512
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
613

django_fsm/__init__.py

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,22 @@
1818
from django_fsm.signals import pre_transition
1919

2020
__all__ = [
21-
"TransitionNotAllowed",
21+
"GET_STATE",
22+
"RETURN_VALUE",
2223
"ConcurrentTransition",
23-
"FSMFieldMixin",
24+
"ConcurrentTransitionMixin",
2425
"FSMField",
26+
"FSMFieldMixin",
2527
"FSMIntegerField",
2628
"FSMKeyField",
27-
"ConcurrentTransitionMixin",
28-
"transition",
29+
"TransitionNotAllowed",
2930
"can_proceed",
3031
"has_transition_perm",
31-
"GET_STATE",
32-
"RETURN_VALUE",
32+
"transition",
3333
]
3434

3535

36-
class TransitionNotAllowed(Exception):
36+
class TransitionNotAllowed(Exception): # noqa: N818
3737
"""Raised when a transition is not allowed"""
3838

3939
def __init__(self, *args, **kwargs):
@@ -42,11 +42,11 @@ def __init__(self, *args, **kwargs):
4242
super().__init__(*args, **kwargs)
4343

4444

45-
class InvalidResultState(Exception):
45+
class InvalidResultState(Exception): # noqa: N818
4646
"""Raised when we got invalid result state"""
4747

4848

49-
class ConcurrentTransition(Exception):
49+
class ConcurrentTransition(Exception): # noqa: N818
5050
"""
5151
Raised when the transition cannot be executed because the
5252
object has become stale (state has been changed since it
@@ -91,7 +91,7 @@ def __eq__(self, other):
9191
return False
9292

9393

94-
def get_available_FIELD_transitions(instance, field):
94+
def get_available_FIELD_transitions(instance, field): # noqa: N802
9595
"""
9696
List of transitions available in current model state
9797
with all conditions met
@@ -105,14 +105,14 @@ def get_available_FIELD_transitions(instance, field):
105105
yield meta.get_transition(curr_state)
106106

107107

108-
def get_all_FIELD_transitions(instance, field):
108+
def get_all_FIELD_transitions(instance, field): # noqa: N802
109109
"""
110110
List of all transitions available in current model state
111111
"""
112112
return field.get_all_transitions(instance.__class__)
113113

114114

115-
def get_available_user_FIELD_transitions(instance, user, field):
115+
def get_available_user_FIELD_transitions(instance, user, field): # noqa: N802
116116
"""
117117
List of transitions available in current model state
118118
with all conditions met and user have rights on it
@@ -211,7 +211,7 @@ class FSMFieldDescriptor:
211211
def __init__(self, field):
212212
self.field = field
213213

214-
def __get__(self, instance, type=None):
214+
def __get__(self, instance, instance_type=None):
215215
if instance is None:
216216
return self
217217
return self.field.get_state(instance)
@@ -234,7 +234,9 @@ def __init__(self, *args, **kwargs):
234234
self.state_proxy = {} # state -> ProxyClsRef
235235

236236
state_choices = kwargs.pop("state_choices", None)
237-
choices = kwargs.get("choices", None)
237+
choices = kwargs.get(
238+
"choices",
239+
)
238240
if state_choices is not None and choices is not None:
239241
raise ValueError("Use one of choices or state_choices value")
240242

@@ -295,7 +297,9 @@ def change_state(self, instance, method, *args, **kwargs):
295297
)
296298
if not meta.conditions_met(instance, current_state):
297299
raise TransitionNotAllowed(
298-
f"Transition conditions have not been met for method '{method_name}'", object=instance, method=method
300+
f"Transition conditions have not been met for method '{method_name}'",
301+
object=instance,
302+
method=method,
299303
)
300304

301305
next_state = meta.next_state(current_state)
@@ -344,8 +348,7 @@ def get_all_transitions(self, instance_cls):
344348
for transition in transitions.values():
345349
meta = transition._django_fsm
346350

347-
for transition in meta.transitions.values():
348-
yield transition
351+
yield from meta.transitions.values()
349352

350353
def contribute_to_class(self, cls, name, **kwargs):
351354
self.base_cls = cls
@@ -406,8 +409,6 @@ class FSMIntegerField(FSMFieldMixin, models.IntegerField):
406409
Same as FSMField, but stores the state value in an IntegerField.
407410
"""
408411

409-
pass
410-
411412

412413
class FSMKeyField(FSMFieldMixin, models.ForeignKey):
413414
"""
@@ -557,7 +558,7 @@ def _change_state(instance, *args, **kwargs):
557558
return inner_transition
558559

559560

560-
def can_proceed(bound_method, check_conditions=True):
561+
def can_proceed(bound_method, check_conditions=True): # noqa: FBT002
561562
"""
562563
Returns True if model in state allows to call bound_method
563564
@@ -597,25 +598,23 @@ def get_state(self, model, transition, result, args=[], kwargs={}):
597598
raise NotImplementedError
598599

599600

600-
class RETURN_VALUE(State):
601+
class RETURN_VALUE(State): # noqa: N801
601602
def __init__(self, *allowed_states):
602603
self.allowed_states = allowed_states if allowed_states else None
603604

604605
def get_state(self, model, transition, result, args=[], kwargs={}):
605-
if self.allowed_states is not None:
606-
if result not in self.allowed_states:
607-
raise InvalidResultState(f"{result} is not in list of allowed states\n{self.allowed_states}")
606+
if self.allowed_states is not None and result not in self.allowed_states:
607+
raise InvalidResultState(f"{result} is not in list of allowed states\n{self.allowed_states}")
608608
return result
609609

610610

611-
class GET_STATE(State):
611+
class GET_STATE(State): # noqa: N801
612612
def __init__(self, func, states=None):
613613
self.func = func
614614
self.allowed_states = states
615615

616616
def get_state(self, model, transition, result, args=[], kwargs={}):
617617
result_state = self.func(model, *args, **kwargs)
618-
if self.allowed_states is not None:
619-
if result_state not in self.allowed_states:
620-
raise InvalidResultState(f"{result_state} is not in list of allowed states\n{self.allowed_states}")
618+
if self.allowed_states is not None and result_state not in self.allowed_states:
619+
raise InvalidResultState(f"{result_state} is not in list of allowed states\n{self.allowed_states}")
621620
return result_state

django_fsm/management/commands/graph_transitions.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def node_label(field, state):
2727
return state
2828

2929

30-
def generate_dot(fields_data): # noqa: C901
30+
def generate_dot(fields_data): # noqa: C901, PLR0912
3131
result = graphviz.Digraph()
3232

3333
for field, model in fields_data:
@@ -88,11 +88,11 @@ def generate_dot(fields_data): # noqa: C901
8888
subgraph.node(name, label=label, shape="doublecircle")
8989
for name, label in (sources | targets) - final_states:
9090
subgraph.node(name, label=label, shape="circle")
91-
if field.default: # Adding initial state notation
92-
if label == field.default:
93-
initial_name = node_name(field, "_initial")
94-
subgraph.node(name=initial_name, label="", shape="point")
95-
subgraph.edge(initial_name, name)
91+
# Adding initial state notation
92+
if field.default and label == field.default:
93+
initial_name = node_name(field, "_initial")
94+
subgraph.node(name=initial_name, label="", shape="point")
95+
subgraph.edge(initial_name, name)
9696
for source_name, target_name, attrs in edges:
9797
subgraph.edge(source_name, target_name, **dict(attrs))
9898

@@ -111,10 +111,10 @@ def add_transition(transition_source, transition_target, transition_name, source
111111
def get_graphviz_layouts():
112112
try:
113113
import graphviz
114-
115-
return graphviz.backend.ENGINES
116-
except Exception:
114+
except ModuleNotFoundError:
117115
return {"sfdp", "circo", "twopi", "dot", "neato", "fdp", "osage", "patchwork"}
116+
else:
117+
return graphviz.backend.ENGINES
118118

119119

120120
class Command(BaseCommand):
@@ -139,10 +139,10 @@ def add_arguments(self, parser):
139139
parser.add_argument("args", nargs="*", help=("[appname[.model[.field]]]"))
140140

141141
def render_output(self, graph, **options):
142-
filename, format = options["outputfile"].rsplit(".", 1)
142+
filename, graph_format = options["outputfile"].rsplit(".", 1)
143143

144144
graph.engine = options["layout"]
145-
graph.format = format
145+
graph.format = graph_format
146146
graph.render(filename)
147147

148148
def handle(self, *args, **options):
@@ -156,10 +156,10 @@ def handle(self, *args, **options):
156156
models = apps.get_models(app)
157157
for model in models:
158158
fields_data += all_fsm_fields_data(model)
159-
elif len(field_spec) == 2:
159+
if len(field_spec) == 2: # noqa: PLR2004
160160
model = apps.get_model(field_spec[0], field_spec[1])
161161
fields_data += all_fsm_fields_data(model)
162-
elif len(field_spec) == 3:
162+
if len(field_spec) == 3: # noqa: PLR2004
163163
model = apps.get_model(field_spec[0], field_spec[1])
164164
fields_data += all_fsm_fields_data(model)
165165
else:
@@ -170,4 +170,4 @@ def handle(self, *args, **options):
170170
if options["outputfile"]:
171171
self.render_output(dotdata, **options)
172172
else:
173-
print(dotdata)
173+
print(dotdata) # noqa: T201

django_fsm/tests/test_key_field.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,19 @@ class DBState(models.Model):
2323

2424
label = models.CharField(max_length=255)
2525

26-
def __unicode__(self):
27-
return self.label
28-
2926
class Meta:
3027
app_label = "django_fsm"
3128

29+
def __unicode__(self):
30+
return self.label
31+
3232

3333
class FKBlogPost(models.Model):
3434
state = FSMKeyField(DBState, default="new", protected=True, on_delete=models.CASCADE)
3535

36+
class Meta:
37+
app_label = "django_fsm"
38+
3639
@transition(field=state, source="new", target="published")
3740
def publish(self):
3841
pass
@@ -57,9 +60,6 @@ def steal(self):
5760
def moderate(self):
5861
pass
5962

60-
class Meta:
61-
app_label = "django_fsm"
62-
6363

6464
class FSMKeyFieldTest(TestCase):
6565
def setUp(self):
@@ -119,7 +119,7 @@ def test_star_shortcut_succeed(self):
119119

120120

121121
"""
122-
TODO FIX it
122+
# TODO: FIX it
123123
class BlogPostStatus(models.Model):
124124
name = models.CharField(max_length=10, unique=True)
125125
objects = models.Manager()

django_fsm/tests/test_protected_field.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
class ProtectedAccessModel(models.Model):
1111
status = FSMField(default="new", protected=True)
1212

13+
class Meta:
14+
app_label = "django_fsm"
15+
1316
@transition(field=status, source="new", target="published")
1417
def publish(self):
1518
pass
1619

17-
class Meta:
18-
app_label = "django_fsm"
19-
2020

2121
class MultiProtectedAccessModel(models.Model):
2222
status1 = FSMField(default="new", protected=True)

django_fsm/tests/test_protected_fields.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
class RefreshableProtectedAccessModel(models.Model):
1212
status = FSMField(default="new", protected=True)
1313

14+
class Meta:
15+
app_label = "django_fsm"
16+
1417
@transition(field=status, source="new", target="published")
1518
def publish(self):
1619
pass
1720

18-
class Meta:
19-
app_label = "django_fsm"
20-
2121

2222
class RefreshableModel(FSMModelMixin, RefreshableProtectedAccessModel):
2323
pass

django_fsm/tests/test_proxy_inheritance.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ def publish(self):
1717

1818

1919
class InheritedModel(BaseModel):
20+
class Meta:
21+
proxy = True
22+
2023
@transition(field="state", source="published", target="sticked")
2124
def stick(self):
2225
pass
2326

24-
class Meta:
25-
proxy = True
26-
2727

2828
class TestinheritedModel(TestCase):
2929
def setUp(self):

pyproject.toml

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,31 @@ target-version = "py38"
5858
fix = true
5959

6060
[tool.ruff.lint]
61-
# select = ["ALL"]
62-
extend-select = [
63-
"F", # Pyflakes
64-
"E", # pycodestyle
65-
"W", # pycodestyle
66-
"UP", # pyupgrade
61+
select = ["ALL"]
62+
extend-ignore = [
63+
"COM812", # This rule may cause conflicts when used with the formatter
64+
"D", # pydocstyle
65+
"DOC", # pydoclint
66+
"B",
67+
"PTH",
68+
"ANN", # Missing type annotation
69+
"RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
70+
"PT", # Use a regular `assert` instead of unittest-style
71+
"DJ008", # Model does not define `__str__` method
72+
"ARG001", # Unused function argument
73+
"ARG002", # Unused method argument
74+
"TRY002", # Create your own exception
75+
"TRY003", # Avoid specifying long messages outside the exception class
76+
"EM101", # Exception must not use a string literal, assign to variable first
77+
"EM102", # Exception must not use an f-string literal, assign to variable first
78+
"SLF001", # Private member accessed
79+
"SIM103", # Return the condition directly
80+
"PLR0913", # Too many arguments in function definition
81+
]
82+
fixable = [
6783
"I", # isort
68-
"PERF",
69-
"RET",
70-
"C",
71-
# "B",
84+
"RUF100", # Unused `noqa` directive
7285
]
73-
fixable = ["I"]
7486

7587

7688
[tool.ruff.lint.isort]

tests/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
)
2121

2222
DATABASE_ENGINE = "sqlite3"
23-
SECRET_KEY = "nokey"
23+
SECRET_KEY = "nokey" # noqa: S105
2424
MIDDLEWARE_CLASSES = ()
2525
DATABASES = {
2626
"default": {

0 commit comments

Comments
 (0)