Skip to content

Commit

Permalink
Setup pre-commit
Browse files Browse the repository at this point in the history
  • Loading branch information
pfouque committed Oct 26, 2023
1 parent 9aa5f60 commit 6aea58b
Show file tree
Hide file tree
Showing 20 changed files with 112 additions and 93 deletions.
2 changes: 1 addition & 1 deletion .checkignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
tests/*
django_fsm/tests/*
django_fsm/tests/*
38 changes: 38 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
default_language_version:
python: python3.8
python_venv: python3.8 # Optional

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
args: ["--maxkb=700"]
- id: check-case-conflict
- id: check-json
- id: check-merge-conflict
- id: check-symlinks
- id: check-toml
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace

- repo: https://github.com/asottile/pyupgrade
rev: v3.15.0
hooks:
- id: pyupgrade
args:
- "--py38-plus"

- repo: https://github.com/adamchainz/django-upgrade
rev: 1.15.0
hooks:
- id: django-upgrade
args: [--target-version, "3.2"]

# - repo: https://github.com/astral-sh/ruff-pre-commit
# rev: v0.0.291
# hooks:
# - id: ruff-format
# - id: ruff
3 changes: 1 addition & 2 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
persistent=yes

[MESSAGES CONTROL]
# C0111 = Missing docstring
# C0111 = Missing docstring
# I0011 = # Warning locally suppressed using disable-msg
# I0012 = # Warning locally suppressed using disable-msg
disable=I0011,I0012
Expand Down Expand Up @@ -60,4 +60,3 @@ max-parents=7
max-attributes=7
min-public-methods=0
max-public-methods=20

4 changes: 3 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
copyright (c) 2010 Mikhail Podgurskiy
The MIT License (MIT)

Copyright (c) 2010 Mikhail Podgurskiy

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ on a model instance with a protected FSMField will cause an exception.

``source`` parameter accepts a list of states, or an individual state or ``django_fsm.State`` implementation.

You can use ``*`` for ``source`` to allow switching to ``target`` from any state.
You can use ``*`` for ``source`` to allow switching to ``target`` from any state.

You can use ``+`` for ``source`` to allow switching to ``target`` from any state excluding ``target`` state.

Expand All @@ -163,7 +163,7 @@ You can use ``+`` for ``source`` to allow switching to ``target`` from any state
``target`` state parameter could point to a specific state or ``django_fsm.State`` implementation

.. code:: python
from django_fsm import FSMField, transition, RETURN_VALUE, GET_STATE
@transition(field=state,
source='*',
Expand Down
59 changes: 29 additions & 30 deletions django_fsm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
State tracking functionality for django models
"""
Expand Down Expand Up @@ -82,7 +81,7 @@ class TransitionNotAllowed(Exception):
def __init__(self, *args, **kwargs):
self.object = kwargs.pop("object", None)
self.method = kwargs.pop("method", None)
super(TransitionNotAllowed, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)


class InvalidResultState(Exception):
Expand All @@ -97,7 +96,7 @@ class ConcurrentTransition(Exception):
"""


class Transition(object):
class Transition:
def __init__(self, method, source, target, on_error, conditions, permission, custom):
self.method = method
self.source = source
Expand Down Expand Up @@ -155,7 +154,7 @@ def get_available_user_FIELD_transitions(instance, user, field):
yield transition


class FSMMeta(object):
class FSMMeta:
"""
Models methods transitions meta information
"""
Expand All @@ -174,7 +173,7 @@ def get_transition(self, source):

def add_transition(self, method, source, target, on_error=None, conditions=[], permission=None, custom={}):
if source in self.transitions:
raise AssertionError("Duplicate transition for {0} state".format(source))
raise AssertionError(f"Duplicate transition for {source} state")

self.transitions[source] = Transition(
method=method,
Expand Down Expand Up @@ -226,20 +225,20 @@ def next_state(self, current_state):
transition = self.get_transition(current_state)

if transition is None:
raise TransitionNotAllowed("No transition from {0}".format(current_state))
raise TransitionNotAllowed(f"No transition from {current_state}")

return transition.target

def exception_state(self, current_state):
transition = self.get_transition(current_state)

if transition is None:
raise TransitionNotAllowed("No transition from {0}".format(current_state))
raise TransitionNotAllowed(f"No transition from {current_state}")

return transition.on_error


class FSMFieldDescriptor(object):
class FSMFieldDescriptor:
def __init__(self, field):
self.field = field

Expand All @@ -250,14 +249,14 @@ def __get__(self, instance, type=None):

def __set__(self, instance, value):
if self.field.protected and self.field.name in instance.__dict__:
raise AttributeError("Direct {0} modification is not allowed".format(self.field.name))
raise AttributeError(f"Direct {self.field.name} modification is not allowed")

# Update state
self.field.set_proxy(instance, value)
self.field.set_state(instance, value)


class FSMFieldMixin(object):
class FSMFieldMixin:
descriptor_class = FSMFieldDescriptor

def __init__(self, *args, **kwargs):
Expand All @@ -277,10 +276,10 @@ def __init__(self, *args, **kwargs):
self.state_proxy[state] = proxy_cls_ref
kwargs["choices"] = choices

super(FSMFieldMixin, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)

def deconstruct(self):
name, path, args, kwargs = super(FSMFieldMixin, self).deconstruct()
name, path, args, kwargs = super().deconstruct()
if self.protected:
kwargs["protected"] = self.protected
return name, path, args, kwargs
Expand Down Expand Up @@ -326,7 +325,7 @@ def set_proxy(self, instance, state):

model = get_model(app_label, model_name)
if model is None:
raise ValueError("No model found {0}".format(state_proxy))
raise ValueError(f"No model found {state_proxy}")

instance.__class__ = model

Expand All @@ -337,13 +336,13 @@ def change_state(self, instance, method, *args, **kwargs):

if not meta.has_transition(current_state):
raise TransitionNotAllowed(
"Can't switch from state '{0}' using method '{1}'".format(current_state, method_name),
f"Can't switch from state '{current_state}' using method '{method_name}'",
object=instance,
method=method,
)
if not meta.conditions_met(instance, current_state):
raise TransitionNotAllowed(
"Transition conditions have not been met for method '{0}'".format(method_name), object=instance, method=method
f"Transition conditions have not been met for method '{method_name}'", object=instance, method=method
)

next_state = meta.next_state(current_state)
Expand Down Expand Up @@ -398,15 +397,15 @@ def get_all_transitions(self, instance_cls):
def contribute_to_class(self, cls, name, **kwargs):
self.base_cls = cls

super(FSMFieldMixin, self).contribute_to_class(cls, name, **kwargs)
super().contribute_to_class(cls, name, **kwargs)
setattr(cls, self.name, self.descriptor_class(self))
setattr(cls, "get_all_{0}_transitions".format(self.name), partialmethod(get_all_FIELD_transitions, field=self))
setattr(cls, f"get_all_{self.name}_transitions", partialmethod(get_all_FIELD_transitions, field=self))
setattr(
cls, "get_available_{0}_transitions".format(self.name), partialmethod(get_available_FIELD_transitions, field=self)
cls, f"get_available_{self.name}_transitions", partialmethod(get_available_FIELD_transitions, field=self)
)
setattr(
cls,
"get_available_user_{0}_transitions".format(self.name),
f"get_available_user_{self.name}_transitions",
partialmethod(get_available_user_FIELD_transitions, field=self),
)

Expand Down Expand Up @@ -448,7 +447,7 @@ class FSMField(FSMFieldMixin, models.CharField):

def __init__(self, *args, **kwargs):
kwargs.setdefault("max_length", 50)
super(FSMField, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)


class FSMIntegerField(FSMFieldMixin, models.IntegerField):
Expand All @@ -471,7 +470,7 @@ def set_state(self, instance, state):
instance.__dict__[self.attname] = self.to_python(state)


class ConcurrentTransitionMixin(object):
class ConcurrentTransitionMixin:
"""
Protects a Model from undesirable effects caused by concurrently executed transitions,
e.g. running the same transition multiple times at the same time, or running different
Expand All @@ -498,7 +497,7 @@ class ConcurrentTransitionMixin(object):
"""

def __init__(self, *args, **kwargs):
super(ConcurrentTransitionMixin, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self._update_initial_state()

@property
Expand All @@ -513,9 +512,9 @@ def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_updat
filter_on = filter(lambda field: field.model == base_qs.model, self.state_fields)

# state filter will be used to narrow down the standard filter checking only PK
state_filter = dict((field.attname, self.__initial_states[field.attname]) for field in filter_on)
state_filter = {field.attname: self.__initial_states[field.attname] for field in filter_on}

updated = super(ConcurrentTransitionMixin, self)._do_update(
updated = super()._do_update(
base_qs=base_qs.filter(**state_filter),
using=using,
pk_val=pk_val,
Expand All @@ -536,14 +535,14 @@ def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_updat
return updated

def _update_initial_state(self):
self.__initial_states = dict((field.attname, field.value_from_object(self)) for field in self.state_fields)
self.__initial_states = {field.attname: field.value_from_object(self) for field in self.state_fields}

def refresh_from_db(self, *args, **kwargs):
super(ConcurrentTransitionMixin, self).refresh_from_db(*args, **kwargs)
super().refresh_from_db(*args, **kwargs)
self._update_initial_state()

def save(self, *args, **kwargs):
super(ConcurrentTransitionMixin, self).save(*args, **kwargs)
super().save(*args, **kwargs)
self._update_initial_state()


Expand Down Expand Up @@ -617,7 +616,7 @@ def has_transition_perm(bound_method, user):
)


class State(object):
class State:
def get_state(self, model, transition, result, args=[], kwargs={}):
raise NotImplementedError

Expand All @@ -629,7 +628,7 @@ def __init__(self, *allowed_states):
def get_state(self, model, transition, result, args=[], kwargs={}):
if self.allowed_states is not None:
if result not in self.allowed_states:
raise InvalidResultState("{} is not in list of allowed states\n{}".format(result, self.allowed_states))
raise InvalidResultState(f"{result} is not in list of allowed states\n{self.allowed_states}")
return result


Expand All @@ -642,5 +641,5 @@ def get_state(self, model, transition, result, args=[], kwargs={}):
result_state = self.func(model, *args, **kwargs)
if self.allowed_states is not None:
if result_state not in self.allowed_states:
raise InvalidResultState("{} is not in list of allowed states\n{}".format(result, self.allowed_states))
raise InvalidResultState(f"{result} is not in list of allowed states\n{self.allowed_states}")
return result_state
15 changes: 7 additions & 8 deletions django_fsm/management/commands/graph_transitions.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# -*- coding: utf-8; mode: django -*-
import graphviz
from optparse import make_option
from itertools import chain

from django.core.management.base import BaseCommand
try:
from django.utils.encoding import force_text
from django.utils.encoding import force_str
_requires_system_checks = True
except ImportError: # Django >= 4.0
from django.utils.encoding import force_str as force_text
Expand Down Expand Up @@ -37,12 +36,12 @@ def all_fsm_fields_data(model):

def node_name(field, state):
opts = field.model._meta
return "%s.%s.%s.%s" % (opts.app_label, opts.verbose_name.replace(" ", "_"), field.name, state)
return "{}.{}.{}.{}".format(opts.app_label, opts.verbose_name.replace(" ", "_"), field.name, state)


def node_label(field, state):
if type(state) == int or (type(state) == bool and hasattr(field, "choices")):
return force_text(dict(field.choices).get(state))
return force_str(dict(field.choices).get(state))
else:
return state

Expand Down Expand Up @@ -79,7 +78,7 @@ def generate_dot(fields_data):
add_transition(source, target, transition.name, source_name, field, sources, targets, edges)

targets.update(
set((node_name(field, target), node_label(field, target)) for target, _ in chain(any_targets, any_except_targets))
{(node_name(field, target), node_label(field, target)) for target, _ in chain(any_targets, any_except_targets)}
)
for target, name in any_targets:
target_name = node_name(field, target)
Expand All @@ -91,16 +90,16 @@ def generate_dot(fields_data):
for target, name in any_except_targets:
target_name = node_name(field, target)
all_nodes = sources | targets
all_nodes.remove(((target_name, node_label(field, target))))
all_nodes.remove((target_name, node_label(field, target)))
for source_name, label in all_nodes:
sources.add((source_name, label))
edges.add((source_name, target_name, (("label", name),)))

# construct subgraph
opts = field.model._meta
subgraph = graphviz.Digraph(
name="cluster_%s_%s_%s" % (opts.app_label, opts.object_name, field.name),
graph_attr={"label": "%s.%s.%s" % (opts.app_label, opts.object_name, field.name)},
name=f"cluster_{opts.app_label}_{opts.object_name}_{field.name}",
graph_attr={"label": f"{opts.app_label}.{opts.object_name}.{field.name}"},
)

final_states = targets - sources
Expand Down
1 change: 0 additions & 1 deletion django_fsm/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Empty file to mark package as valid django application.
"""
1 change: 0 additions & 1 deletion django_fsm/signals.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from django.dispatch import Signal

pre_transition = Signal()
Expand Down
2 changes: 1 addition & 1 deletion django_fsm/tests/test_abstract_inheritance.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ def test_field_available_transitions_works(self):
def test_field_all_transitions_works(self):
transitions = self.model.get_all_state_transitions()
self.assertEqual(
set([("new", "published"), ("published", "sticked")]), set((data.source, data.target) for data in transitions)
{("new", "published"), ("published", "sticked")}, {(data.source, data.target) for data in transitions}
)
Loading

0 comments on commit 6aea58b

Please sign in to comment.