Skip to content

Commit

Permalink
Add Ruff linting (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
Viicos authored Jul 1, 2024
1 parent e06af9a commit 3c9c7bd
Show file tree
Hide file tree
Showing 16 changed files with 160 additions and 122 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ jobs:
matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Unreleased

* Add typing support
* Deprecate `solo.models.get_cache`
* Switch to `pyproject.toml`
* Switch to Ruff for formatting and linting

django-solo-2.2.0
=================
Expand Down
4 changes: 1 addition & 3 deletions examples/config/admin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from django.contrib import admin

from solo.admin import SingletonModelAdmin

from config.models import SiteConfiguration

from solo.admin import SingletonModelAdmin

admin.site.register(SiteConfiguration, SingletonModelAdmin)
4 changes: 2 additions & 2 deletions examples/config/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@


class SiteConfiguration(SingletonModel):
site_name = models.CharField(max_length=255, default='Site Name')
site_name = models.CharField(max_length=255, default="Site Name")
maintenance_mode = models.BooleanField(default=False)

def __str__(self):
return u"Site Configuration"
return "Site Configuration"

class Meta:
verbose_name = "Site Configuration"
Expand Down
5 changes: 3 additions & 2 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
Note: For django-solo, this file is used simply to launch the test suite.
"""

import os
import sys


def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test_project.settings')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
Expand All @@ -21,5 +22,5 @@ def main():
execute_from_command_line(sys.argv)


if __name__ == '__main__':
if __name__ == "__main__":
main()
23 changes: 23 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,26 @@ Changelog = "https://github.com/lazybird/django-solo/blob/master/CHANGES"
ignore_missing_imports = true
strict = true
exclude = "solo/tests"

[tool.ruff]
line-length = 100
target-version = "py38"

[tool.ruff.lint]
select = [
"F", # pyflakes
"E", # pycodestyle
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"RUF", # ruff
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"PTH", # flake8-use-pathlib
"SIM", # flake8-simplify
"TID", # flake8-tidy-imports
]

ignore = [
"B904",
]
10 changes: 6 additions & 4 deletions solo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""django-solo helps working with singletons: things like global settings that you want to edit from the admin site.
"""
import django
django-solo helps working with singletons:
things like global settings that you want to edit from the admin site.
"""

import django

__version__ = '2.2.0'
__version__ = "2.2.0"

if django.VERSION < (3, 2):
default_app_config = 'solo.apps.SoloAppConfig'
default_app_config = "solo.apps.SoloAppConfig"
61 changes: 34 additions & 27 deletions solo/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

from typing import Any

from django.db.models import Model
from django.urls import URLPattern, re_path
from django.contrib import admin
from django.db.models import Model
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.urls import URLPattern, re_path
from django.utils.encoding import force_str
from django.utils.translation import gettext as _

from solo.models import DEFAULT_SINGLETON_INSTANCE_ID
from solo import settings as solo_settings
from solo.models import DEFAULT_SINGLETON_INSTANCE_ID


class SingletonModelAdmin(admin.ModelAdmin): # type: ignore[type-arg]
Expand All @@ -37,42 +37,47 @@ def get_urls(self) -> list[URLPattern]:
model_name = self.model._meta.module_name.lower()

self.model._meta.verbose_name_plural = self.model._meta.verbose_name
url_name_prefix = '%(app_name)s_%(model_name)s' % {
'app_name': self.model._meta.app_label,
'model_name': model_name,
}
url_name_prefix = f"{self.model._meta.app_label}_{model_name}"
custom_urls = [
re_path(r'^history/$',
self.admin_site.admin_view(self.history_view),
{'object_id': str(self.singleton_instance_id)},
name='%s_history' % url_name_prefix),
re_path(r'^$',
self.admin_site.admin_view(self.change_view),
{'object_id': str(self.singleton_instance_id)},
name='%s_change' % url_name_prefix),
re_path(
r"^history/$",
self.admin_site.admin_view(self.history_view),
{"object_id": str(self.singleton_instance_id)},
name=f"{url_name_prefix}_history",
),
re_path(
r"^$",
self.admin_site.admin_view(self.change_view),
{"object_id": str(self.singleton_instance_id)},
name=f"{url_name_prefix}_change",
),
]

# By inserting the custom URLs first, we overwrite the standard URLs.
return custom_urls + urls

def response_change(self, request: HttpRequest, obj: Model) -> HttpResponseRedirect:
msg = _('%(obj)s was changed successfully.') % {
'obj': force_str(obj)}
if '_continue' in request.POST:
self.message_user(request, msg + ' ' +
_('You may edit it again below.'))
msg = _("{obj} was changed successfully.").format(obj=force_str(obj))
if "_continue" in request.POST:
self.message_user(request, msg + " " + _("You may edit it again below."))
return HttpResponseRedirect(request.path)
else:
self.message_user(request, msg)
return HttpResponseRedirect("../../")

def change_view(self, request: HttpRequest, object_id: str, form_url: str = '', extra_context: dict[str, Any] | None = None) -> HttpResponse:
def change_view(
self,
request: HttpRequest,
object_id: str,
form_url: str = "",
extra_context: dict[str, Any] | None = None,
) -> HttpResponse:
if object_id == str(self.singleton_instance_id):
self.model.objects.get_or_create(pk=self.singleton_instance_id)

if not extra_context:
extra_context = dict()
extra_context['skip_object_list_page'] = solo_settings.SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE
extra_context = {}
extra_context["skip_object_list_page"] = solo_settings.SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE

return super().change_view(
request,
Expand All @@ -81,10 +86,12 @@ def change_view(self, request: HttpRequest, object_id: str, form_url: str = '',
extra_context=extra_context,
)

def history_view(self, request: HttpRequest, object_id: str, extra_context: dict[str, Any] | None = None) -> HttpResponse:
def history_view(
self, request: HttpRequest, object_id: str, extra_context: dict[str, Any] | None = None
) -> HttpResponse:
if not extra_context:
extra_context = dict()
extra_context['skip_object_list_page'] = solo_settings.SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE
extra_context = {}
extra_context["skip_object_list_page"] = solo_settings.SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE

return super().history_view(
request,
Expand All @@ -94,4 +101,4 @@ def history_view(self, request: HttpRequest, object_id: str, extra_context: dict

@property
def singleton_instance_id(self) -> int:
return getattr(self.model, 'singleton_instance_id', DEFAULT_SINGLETON_INSTANCE_ID)
return getattr(self.model, "singleton_instance_id", DEFAULT_SINGLETON_INSTANCE_ID)
2 changes: 1 addition & 1 deletion solo/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@


class SoloAppConfig(AppConfig):
name = 'solo'
name = "solo"
verbose_name = "solo"
12 changes: 6 additions & 6 deletions solo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,29 @@ def delete(self, *args: Any, **kwargs: Any) -> tuple[int, dict[str, int]]:

@classmethod
def clear_cache(cls) -> None:
cache_name = getattr(settings, 'SOLO_CACHE', solo_settings.SOLO_CACHE)
cache_name = getattr(settings, "SOLO_CACHE", solo_settings.SOLO_CACHE)
if cache_name:
cache = caches[cache_name]
cache_key = cls.get_cache_key()
cache.delete(cache_key)

def set_to_cache(self) -> None:
cache_name = getattr(settings, 'SOLO_CACHE', solo_settings.SOLO_CACHE)
cache_name = getattr(settings, "SOLO_CACHE", solo_settings.SOLO_CACHE)
if not cache_name:
return None
cache = caches[cache_name]
cache_key = self.get_cache_key()
timeout = getattr(settings, 'SOLO_CACHE_TIMEOUT', solo_settings.SOLO_CACHE_TIMEOUT)
timeout = getattr(settings, "SOLO_CACHE_TIMEOUT", solo_settings.SOLO_CACHE_TIMEOUT)
cache.set(cache_key, self, timeout)

@classmethod
def get_cache_key(cls) -> str:
prefix = getattr(settings, 'SOLO_CACHE_PREFIX', solo_settings.SOLO_CACHE_PREFIX)
return '%s:%s' % (prefix, cls.__name__.lower())
prefix = getattr(settings, "SOLO_CACHE_PREFIX", solo_settings.SOLO_CACHE_PREFIX)
return f"{prefix}:{cls.__name__.lower()}"

@classmethod
def get_solo(cls) -> Self:
cache_name = getattr(settings, 'SOLO_CACHE', solo_settings.SOLO_CACHE)
cache_name = getattr(settings, "SOLO_CACHE", solo_settings.SOLO_CACHE)
if not cache_name:
obj, _ = cls.objects.get_or_create(pk=cls.singleton_instance_id)
return obj # type: ignore[return-value]
Expand Down
12 changes: 4 additions & 8 deletions solo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
from django.conf import settings

# template parameters
GET_SOLO_TEMPLATE_TAG_NAME: str = getattr(
settings, 'GET_SOLO_TEMPLATE_TAG_NAME', 'get_solo'
)
GET_SOLO_TEMPLATE_TAG_NAME: str = getattr(settings, "GET_SOLO_TEMPLATE_TAG_NAME", "get_solo")

SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE: bool = getattr(
settings, 'SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE', True
)
SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE: bool = getattr(settings, "SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE", True)

# The cache that should be used, e.g. 'default'. Refers to Django CACHES setting.
# Set to None to disable caching.
SOLO_CACHE: str | None = None

SOLO_CACHE_TIMEOUT = 60 * 5

SOLO_CACHE_PREFIX = 'solo'
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
SOLO_CACHE_PREFIX = "solo"
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
24 changes: 12 additions & 12 deletions solo/templatetags/solo_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@
@register.simple_tag(name=solo_settings.GET_SOLO_TEMPLATE_TAG_NAME)
def get_solo(model_path: str) -> SingletonModel:
try:
app_label, model_name = model_path.rsplit('.', 1)
app_label, model_name = model_path.rsplit(".", 1)
except ValueError:
raise template.TemplateSyntaxError(_(
"Templatetag requires the model dotted path: 'app_label.ModelName'. "
"Received '%s'." % model_path
))
raise template.TemplateSyntaxError(
_(
"Templatetag requires the model dotted path: 'app_label.ModelName'. "
"Received '{model_path}'."
).format(model_path=model_path)
)
model_class: type[SingletonModel] = apps.get_model(app_label, model_name)
if not model_class:
raise template.TemplateSyntaxError(_(
"Could not get the model name '%(model)s' from the application "
"named '%(app)s'" % {
'model': model_name,
'app': app_label,
}
))
raise template.TemplateSyntaxError(
_("Could not get the model name '{model}' from the application named '{app}'").format(
model=model_name, app=app_label
)
)
return model_class.get_solo()
6 changes: 3 additions & 3 deletions solo/tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@


class SiteConfiguration(SingletonModel):
site_name = models.CharField(max_length=255, default='Default Config')
file = models.FileField(upload_to='files', default=SimpleUploadedFile("default-file.pdf", None))
site_name = models.CharField(max_length=255, default="Default Config")
file = models.FileField(upload_to="files", default=SimpleUploadedFile("default-file.pdf", None))

def __str__(self):
return "Site Configuration"
Expand All @@ -17,7 +17,7 @@ class Meta:

class SiteConfigurationWithExplicitlyGivenId(SingletonModel):
singleton_instance_id = 24
site_name = models.CharField(max_length=255, default='Default Config')
site_name = models.CharField(max_length=255, default="Default Config")

def __str__(self):
return "Site Configuration"
Expand Down
38 changes: 19 additions & 19 deletions solo/tests/settings.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
)

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'solo-tests.db',
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "solo-tests.db",
}
}

INSTALLED_APPS = (
'solo',
'solo.tests',
"solo",
"solo.tests",
)

SECRET_KEY = 'any-key'
SECRET_KEY = "any-key"

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': '127.0.0.1:11211',
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"LOCATION": "127.0.0.1:11211",
},
}

SOLO_CACHE = 'default'
SOLO_CACHE = "default"

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
},
]
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
Loading

0 comments on commit 3c9c7bd

Please sign in to comment.