Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ruff #3

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ jobs:
lint: ${{steps.changes.outputs.lint }}
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4
- id: changes
name: Check for file changes
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3
with:
base: ${{ github.ref }}
token: ${{ github.token }}
Expand All @@ -47,16 +47,19 @@ jobs:
if: needs.changes.outputs.lint
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.12
architecture: 'x64'
- uses: yezz123/setup-uv@v4
with:
version: "latest"
- name: lint
if: needs.changes.outputs.lint
run: |
uv run isort src/ --check-only
uv run flake8 src/
pip install ruff
ruff check -e
ruff format --check
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ jobs:
lint: ${{steps.changes.outputs.lint }}
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4
- id: changes
name: Check for file changes
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3
with:
base: ${{ github.ref }}
token: ${{ github.token }}
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:
strategy:
max-parallel: 1
matrix:
python-version: [ "3.11", "3.12" ]
python-version: [ "3.11", "3.12", "3.13" ]
django-version: [ "4.2", "5.1" ]
fail-fast: true
needs: [ changes ]
Expand All @@ -74,7 +74,7 @@ jobs:
DB_PASSWORD: "postgres"
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
Expand Down Expand Up @@ -119,7 +119,7 @@ jobs:
if: ${{ always() }}

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
if: matrix.python-version == 3.12
continue-on-error: true
with:
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies = [
"django-admin-extra-buttons>=1.5.8",
"django-concurrency>=2.6",
"django>=4",
"sentry-sdk",
]

[project.optional-dependencies]
Expand Down
3 changes: 2 additions & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ addopts =
-rs
--tb=short
--capture=sys
--maxfail=5
--echo-version django
--cov-config=tests/.coveragerc
--cov-report html
--cov-report xml:coverage.xml

--cov=django_celery_boost

markers =
admin
Expand Down
81 changes: 81 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
target-version = "py313"
line-length = 120

[lint.isort]
case-sensitive = true

[lint]
select = [
"A", # prevent using keywords that clobber python builtins
# "ANN", # flake8 annotations
"B", # bugbear: security warnings
"BLE", # blind exceptions
"C4", # flake8-comprehensions
"C90", # McCabe complexity
"COM", # flake8-commas
"D", # pydocstyle
"DJ", # flake8-django
"E", # pycodestylex
"E4", "E7", "E9",
"ERA", # eradicate
"F", # pyflakes
"FLY", # flynt
"FURB", # refurb
"I", # isort
"ICN", # flake8-import-conventions
"ISC", # implicit string concatenation
"N", # Pep* naming
"PERF", # perflint
"PIE", # flake8-pie
"PL", # PyLint
# "PT", # flake8-pytest-style
"Q", # flake8-quotes
"R", # PyLint Refactor
"RET", # flake8-return
"S", # bandit,
"SIM", # flake8-simplify
"T10", # flake8-debugger
"T20", # flake8-print
"TC", # flake8-type-checking
"UP", # pyupgrade
"W", # pycodestyle warnings
"YTT", # flake8 2020
]
extend-select = ["UP", ]
ignore = [
"ANN401",
"B904", # raise-without-from-inside-except: syntax not compatible with py2
"COM812",
"D100", # Missing docstring in public module
"D101", # Missing docstring in public class
"D102", # Missing docstring in public method
"D103", # Missing docstring in public function
"D104", # Missing docstring in public package
"D105", # Missing docstring in magic method
"D106", # Missing docstring in public nested class
"D107", # Missing docstring in `__init__`
"D203", # one-blank-line-before-class
# "D212", # multi-line-summary-first-line
"D213", # multi-line-summary-second-line
"E731", # lambda-assignment: lambdas are substential in maintenance of py2/3 codebase
"ISC001", # conflicts with ruff format command
"RUF005", # collection-literal-concatenation: syntax not compatible with py2
"RUF012", # mutable-class-default: typing is not available for py2
"I001", # unsorted imports https://docs.astral.sh/ruff/rules/unsorted-imports/#unsorted-imports-i001
"UP037", # [*] Remove quotes from type annotation
"UP035", # Import from `collections.abc` instead: `Sequence`
"UP031", # Use format specifiers instead of percent format
"SIM108", # Use ternary operator instead of...
"PLR2004", # Magic value used in comparison
"DJ001", # Avoid using `null=True` on string-based fields such as `CharField`
]

[format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"

[lint.per-file-ignores]
"tests/**.py" = ["S101", "PLR2004", "S", "SIM117", "D", "UP", "PLR0913", "ANN", "N999"]
"src/**/versioning/**.py" = ["N999", ]
85 changes: 27 additions & 58 deletions src/django_celery_boost/admin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Optional, Sequence
from typing import Any, Sequence

from admin_extra_buttons.decorators import button
from admin_extra_buttons.mixins import ExtraButtonsMixin, confirm_action
Expand All @@ -19,9 +19,7 @@ class CeleryTaskModelAdmin(ExtraButtonsMixin, admin.ModelAdmin):
inspect_template = None
queue_template = None

def get_readonly_fields(
self, request: HttpRequest, obj: "Optional[Model]" = None
) -> Sequence[str]:
def get_readonly_fields(self, request: HttpRequest, obj: Model | None = None) -> Sequence[str]:
ret = list(super().get_readonly_fields(request, obj))
ret.append("curr_async_result_id")
return ret
Expand All @@ -37,34 +35,25 @@ def check_status(self, request: HttpRequest) -> "HttpResponse": # type: ignore
obj.curr_async_result_id = None
obj.save()

def get_common_context(
self, request: HttpRequest, pk: str = None, **kwargs: Any
) -> dict[str, Any]:
def get_common_context(self, request: HttpRequest, pk: str = None, **kwargs: Any) -> dict[str, Any]:
kwargs["flower_addr"] = getattr(settings, "CELERY_FLOW_ADDRESS", "")
return super().get_common_context(request, pk, **kwargs)

@button(
permission=lambda r, o, handler: handler.model_admin.has_queue_permission(
"inspect", r, o
)
)
@button(permission=lambda r, o, handler: handler.model_admin.has_queue_permission("inspect", r, o))
def celery_inspect(self, request: HttpRequest, pk: str) -> HttpResponse:
ctx = self.get_common_context(request, pk, title="Inspect Task")
return render(
request,
self.inspect_template
or [
"%s/%s/%s/inspect.html"
% (self.admin_site.name, self.opts.app_label, self.opts.model_name),
"%s/%s/%s/inspect.html" % (self.admin_site.name, self.opts.app_label, self.opts.model_name),
"%s/%s/inspect.html" % (self.admin_site.name, self.opts.app_label),
"%s/celery_boost/inspect.html" % self.admin_site.name,
],
ctx,
)

def has_queue_permission(
self, perm, request: HttpRequest, o: Optional[CeleryTaskModel]
) -> bool:
def has_queue_permission(self, perm, request: HttpRequest, o: CeleryTaskModel | None) -> bool:
perm = "%s.%s_%s" % (
self.model._meta.app_label,
perm,
Expand All @@ -74,58 +63,47 @@ def has_queue_permission(

@button(
label="Queue",
permission=lambda r, o, handler: handler.model_admin.has_queue_permission(
"queue", r, o
),
permission=lambda r, o, handler: handler.model_admin.has_queue_permission("queue", r, o),
)
def celery_queue(self, request: "HttpRequest", pk: str) -> "HttpResponse": # type: ignore
return self._celery_queue(request, pk)

@button(
label="Revoke",
permission=lambda r, o, handler: handler.model_admin.has_queue_permission(
"revoke", r, o
),
permission=lambda r, o, handler: handler.model_admin.has_queue_permission("revoke", r, o),
)
def celery_revoke(self, request: "HttpRequest", pk: str) -> "HttpResponse": # type: ignore
return self._celery_revoke(request, pk)

@button(
label="Terminate",
permission=lambda r, o, handler: handler.model_admin.has_queue_permission(
"terminate", r, o
),
permission=lambda r, o, handler: handler.model_admin.has_queue_permission("terminate", r, o),
)
def celery_terminate(self, request: "HttpRequest", pk: str) -> "HttpResponse": # type: ignore
return self._celery_terminate(request, pk)

def _celery_queue(self, request: "HttpRequest", pk: str) -> "HttpResponse": # type: ignore
obj: Optional[CeleryTaskModel]
obj: CeleryTaskModel | None
obj = self.get_object(request, pk)

ctx = self.get_common_context(
request, pk, title=f"Confirm queue action for {obj}"
)
ctx = self.get_common_context(request, pk, title=f"Confirm queue action for {obj}")

def doit(request: "HttpRequest") -> HttpResponseRedirect:
if obj.queue() is None:
self.message_user(request, "Task already queued", level=messages.INFO)
redirect_url = reverse(
"%s:%s_%s_change"
% (self.admin_site.name, obj._meta.app_label, obj._meta.model_name),
"%s:%s_%s_change" % (self.admin_site.name, obj._meta.app_label, obj._meta.model_name),
args=(obj.pk,),
current_app=self.admin_site.name,
)
return HttpResponseRedirect(redirect_url)

if obj.is_queued():
self.message_user(
request, "Task has already been queued.", messages.WARNING
)
return
self.message_user(request, "Task has already been queued.", messages.WARNING)
return None
if obj.is_terminated() and not obj.repeatable:
self.message_user(request, "Task is already terminated.", messages.WARNING)
return
return None

return confirm_action(
self,
Expand All @@ -137,32 +115,28 @@ def doit(request: "HttpRequest") -> HttpResponseRedirect:
description="",
template=self.queue_template
or [
"%s/%s/%s/queue.html"
% (self.admin_site.name, self.opts.app_label, self.opts.model_name),
"%s/%s/%s/queue.html" % (self.admin_site.name, self.opts.app_label, self.opts.model_name),
"%s/%s/queue.html" % (self.admin_site.name, self.opts.app_label),
"%s/celery_boost/queue.html" % self.admin_site.name,
],
)

def _celery_revoke(self, request: "HttpRequest", pk: str) -> "HttpResponse": # type: ignore
obj: Optional[CeleryTaskModel]
obj: CeleryTaskModel | None
obj = self.get_object(request, pk)

if not obj.is_queued():
self.message_user(request, "Task not queued.", messages.WARNING)
return
return None
if obj.is_terminated():
self.message_user(request, "Task is already terminated.", messages.WARNING)
return
ctx = self.get_common_context(
request, pk, title=f"Confirm revoking action for {obj}"
)
return None
ctx = self.get_common_context(request, pk, title=f"Confirm revoking action for {obj}")

def doit(request: "HttpRequest") -> HttpResponseRedirect:
obj.revoke()
redirect_url = reverse(
"%s:%s_%s_change"
% (self.admin_site.name, obj._meta.app_label, obj._meta.model_name),
"%s:%s_%s_change" % (self.admin_site.name, obj._meta.app_label, obj._meta.model_name),
args=(obj.pk,),
current_app=self.admin_site.name,
)
Expand All @@ -177,8 +151,7 @@ def doit(request: "HttpRequest") -> HttpResponseRedirect:
extra_context=ctx,
description="",
template=[
"%s/%s/%s/queue.html"
% (self.admin_site.name, self.opts.app_label, self.opts.model_name),
"%s/%s/%s/queue.html" % (self.admin_site.name, self.opts.app_label, self.opts.model_name),
"%s/%s/queue.html" % (self.admin_site.name, self.opts.app_label),
"%s/celery_boost/queue.html" % self.admin_site.name,
],
Expand All @@ -188,19 +161,16 @@ def _celery_terminate(self, request: HttpRequest, pk: str) -> "HttpResponse": #
obj: CeleryTaskModel = self.get_object(request, pk)
if not obj.is_queued():
self.message_user(request, "Task not queued.", messages.WARNING)
return
return None
if obj.is_terminated():
self.message_user(request, "Task is already terminated.", messages.WARNING)
return
ctx = self.get_common_context(
request, pk, title=f"Confirm termination request for {obj}"
)
return None
ctx = self.get_common_context(request, pk, title=f"Confirm termination request for {obj}")

def doit(request: "HttpRequest") -> HttpResponseRedirect:
result = obj.terminate()
redirect_url = reverse(
"%s:%s_%s_change"
% (self.admin_site.name, obj._meta.app_label, obj._meta.model_name),
"%s:%s_%s_change" % (self.admin_site.name, obj._meta.app_label, obj._meta.model_name),
args=(obj.pk,),
current_app=self.admin_site.name,
)
Expand All @@ -218,8 +188,7 @@ def doit(request: "HttpRequest") -> HttpResponseRedirect:
description="",
template=self.terminate_template
or [
"%s/%s/%s/terminate.html"
% (self.admin_site.name, self.opts.app_label, self.opts.model_name),
"%s/%s/%s/terminate.html" % (self.admin_site.name, self.opts.app_label, self.opts.model_name),
"%s/%s/terminate.html" % (self.admin_site.name, self.opts.app_label),
"%s/celery_boost/terminate.html" % self.admin_site.name,
],
Expand Down
Loading
Loading