Skip to content

Commit 8c1cc3d

Browse files
committed
Leverage Ruff
1 parent 40c6d39 commit 8c1cc3d

24 files changed

+150
-135
lines changed

.github/workflows/coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
pull_request:
55
push:
66
branches:
7-
- master
7+
- main
88

99
jobs:
1010
coverage:

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

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ class DbState(models.Model):
292292
id = models.CharField(primary_key=True, max_length=50)
293293
label = models.CharField(max_length=255)
294294

295-
def __unicode__(self):
295+
def __str__(self):
296296
return self.label
297297

298298

django_fsm/__init__.py

Lines changed: 22 additions & 27 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,7 @@ 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("choices")
238238
if state_choices is not None and choices is not None:
239239
raise ValueError("Use one of choices or state_choices value")
240240

@@ -344,8 +344,7 @@ def get_all_transitions(self, instance_cls):
344344
for transition in transitions.values():
345345
meta = transition._django_fsm
346346

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

350349
def contribute_to_class(self, cls, name, **kwargs):
351350
self.base_cls = cls
@@ -406,8 +405,6 @@ class FSMIntegerField(FSMFieldMixin, models.IntegerField):
406405
Same as FSMField, but stores the state value in an IntegerField.
407406
"""
408407

409-
pass
410-
411408

412409
class FSMKeyField(FSMFieldMixin, models.ForeignKey):
413410
"""
@@ -557,7 +554,7 @@ def _change_state(instance, *args, **kwargs):
557554
return inner_transition
558555

559556

560-
def can_proceed(bound_method, check_conditions=True):
557+
def can_proceed(bound_method, check_conditions=True): # noqa: FBT002
561558
"""
562559
Returns True if model in state allows to call bound_method
563560
@@ -597,25 +594,23 @@ def get_state(self, model, transition, result, args=[], kwargs={}):
597594
raise NotImplementedError
598595

599596

600-
class RETURN_VALUE(State):
597+
class RETURN_VALUE(State): # noqa: N801
601598
def __init__(self, *allowed_states):
602599
self.allowed_states = allowed_states if allowed_states else None
603600

604601
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}")
602+
if self.allowed_states is not None and result not in self.allowed_states:
603+
raise InvalidResultState(f"{result} is not in list of allowed states\n{self.allowed_states}")
608604
return result
609605

610606

611-
class GET_STATE(State):
607+
class GET_STATE(State): # noqa: N801
612608
def __init__(self, func, states=None):
613609
self.func = func
614610
self.allowed_states = states
615611

616612
def get_state(self, model, transition, result, args=[], kwargs={}):
617613
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}")
614+
if self.allowed_states is not None and result_state not in self.allowed_states:
615+
raise InvalidResultState(f"{result_state} is not in list of allowed states\n{self.allowed_states}")
621616
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 __str__(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)