diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5185cbac91..af4fab920c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - id: check-yaml - id: mixed-line-ending - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.3 + rev: v0.9.2 hooks: - id: ruff-format args: [--preview] @@ -28,7 +28,7 @@ repos: --preview ] - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.5.1 + rev: 0.5.20 hooks: - id: pip-compile name: pip-compile requirements-dev.in @@ -51,7 +51,7 @@ repos: args: [contrib/container/requirements.in, -o, contrib/container/requirements.txt, --python-version=3.11, --no-strip-extras, --generate-hashes] files: contrib/container/requirements\.(in|txt)$ - repo: https://github.com/Riverside-Healthcare/djLint - rev: v1.36.1 + rev: v1.36.4 hooks: - id: djlint-django - repo: https://github.com/codespell-project/codespell @@ -70,13 +70,13 @@ repos: src/frontend/vite.config.ts | )$ - repo: https://github.com/biomejs/pre-commit - rev: "v0.5.0" + rev: "v0.6.1" hooks: - id: biome-check additional_dependencies: ["@biomejs/biome@1.9.4"] files: ^src/frontend/.*\.(js|ts|tsx)$ - repo: https://github.com/gitleaks/gitleaks - rev: v8.21.2 + rev: v8.23.1 hooks: - id: gitleaks #- repo: https://github.com/jumanjihouse/pre-commit-hooks diff --git a/contrib/container/gunicorn.conf.py b/contrib/container/gunicorn.conf.py index 6d36a74269..564423ef10 100644 --- a/contrib/container/gunicorn.conf.py +++ b/contrib/container/gunicorn.conf.py @@ -19,7 +19,7 @@ threads = 4 # Worker timeout (default = 90 seconds) -timeout = os.environ.get('INVENTREE_GUNICORN_TIMEOUT', 90) +timeout = os.environ.get('INVENTREE_GUNICORN_TIMEOUT', '90') # Number of worker processes workers = os.environ.get('INVENTREE_GUNICORN_WORKERS', None) diff --git a/docs/docs/hooks.py b/docs/docs/hooks.py index 27af45ae7a..574cafdfb0 100644 --- a/docs/docs/hooks.py +++ b/docs/docs/hooks.py @@ -150,7 +150,7 @@ def on_config(config, *args, **kwargs): We can use these to determine (at run time) where we are hosting """ - rtd = os.environ.get('READTHEDOCS', False) + rtd = os.environ.get('READTHEDOCS', 'False') # Note: version selection is handled by RTD internally # Check for 'versions.json' file diff --git a/pyproject.toml b/pyproject.toml index 6f37c4efaa..d596e0f0b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,8 @@ ignore = [ # - RUF015 - Prefer next({iterable}) over single element slice "RUF012", # - RUF012 - Mutable class attributes should be annotated with typing.ClassVar + "RUF052", + # - RUF052 - Local dummy variable is accessed "SIM117", # - SIM117 - Use a single with statement with multiple contexts instead of nested with statements "SIM102", diff --git a/src/backend/InvenTree/InvenTree/helpers.py b/src/backend/InvenTree/InvenTree/helpers.py index 11110c30ce..b0f9b6aa84 100644 --- a/src/backend/InvenTree/InvenTree/helpers.py +++ b/src/backend/InvenTree/InvenTree/helpers.py @@ -11,6 +11,7 @@ from decimal import Decimal, InvalidOperation from pathlib import Path from typing import Optional, TypeVar, Union from wsgiref.util import FileWrapper +from zoneinfo import ZoneInfo, ZoneInfoNotFoundError from django.conf import settings from django.contrib.staticfiles.storage import StaticFilesStorage @@ -25,7 +26,6 @@ import structlog from bleach import clean from djmoney.money import Money from PIL import Image -from zoneinfo import ZoneInfo, ZoneInfoNotFoundError from common.currency import currency_code_default diff --git a/src/backend/InvenTree/InvenTree/models.py b/src/backend/InvenTree/InvenTree/models.py index 75bd4200c1..3840075712 100644 --- a/src/backend/InvenTree/InvenTree/models.py +++ b/src/backend/InvenTree/InvenTree/models.py @@ -762,8 +762,7 @@ class InvenTreeTree(MetadataMixin, PluginValidationMixin, MPTTModel): pathstring = self.construct_pathstring() if pathstring != self.pathstring: - if 'force_insert' in kwargs: - del kwargs['force_insert'] + kwargs.pop('force_insert', None) kwargs['force_update'] = True diff --git a/src/backend/InvenTree/InvenTree/settings.py b/src/backend/InvenTree/InvenTree/settings.py index e578dca4be..a591c4948b 100644 --- a/src/backend/InvenTree/InvenTree/settings.py +++ b/src/backend/InvenTree/InvenTree/settings.py @@ -13,6 +13,7 @@ import logging import os import sys from pathlib import Path +from zoneinfo import ZoneInfo, ZoneInfoNotFoundError import django.conf.locale import django.core.exceptions @@ -21,7 +22,6 @@ from django.http import Http404 import structlog from dotenv import load_dotenv -from zoneinfo import ZoneInfo, ZoneInfoNotFoundError from InvenTree.cache import get_cache_config, is_global_cache_enabled from InvenTree.config import get_boolean_setting, get_custom_file, get_setting diff --git a/src/backend/InvenTree/InvenTree/tests.py b/src/backend/InvenTree/InvenTree/tests.py index 355a8d8122..8a8dedd6c1 100644 --- a/src/backend/InvenTree/InvenTree/tests.py +++ b/src/backend/InvenTree/InvenTree/tests.py @@ -5,6 +5,7 @@ import time from datetime import datetime, timedelta from decimal import Decimal from unittest import mock +from zoneinfo import ZoneInfo import django.core.exceptions as django_exceptions from django.conf import settings @@ -21,7 +22,6 @@ from djmoney.contrib.exchange.models import Rate, convert_money from djmoney.money import Money from maintenance_mode.core import get_maintenance_mode, set_maintenance_mode from sesame.utils import get_user -from zoneinfo import ZoneInfo import InvenTree.conversion import InvenTree.format diff --git a/src/backend/InvenTree/common/api.py b/src/backend/InvenTree/common/api.py index ca33b208b6..aa6af12662 100644 --- a/src/backend/InvenTree/common/api.py +++ b/src/backend/InvenTree/common/api.py @@ -1,7 +1,6 @@ """Provides a JSON API for common components.""" import json -from typing import Type from django.conf import settings from django.contrib.contenttypes.models import ContentType @@ -557,7 +556,7 @@ class AllUnitList(ListAPI): """Parse a unit from the registry.""" if not hasattr(reg, k): return None - unit: Type[UnitLike] = getattr(reg, k) + unit: type[UnitLike] = getattr(reg, k) return { 'name': k, 'is_alias': reg.get_name(k) == k, diff --git a/src/backend/InvenTree/common/setting/system.py b/src/backend/InvenTree/common/setting/system.py index a27ebe88cc..7a1c7349f9 100644 --- a/src/backend/InvenTree/common/setting/system.py +++ b/src/backend/InvenTree/common/setting/system.py @@ -29,8 +29,8 @@ def validate_part_name_format(value): # Make sure that the field_name exists in Part model from part.models import Part - jinja_template_regex = re.compile('{{.*?}}') - field_name_regex = re.compile('(?<=part\\.)[A-z]+') + jinja_template_regex = re.compile(r'{{.*?}}') + field_name_regex = re.compile(r'(?<=part\.)[A-z]+') for jinja_template in jinja_template_regex.findall(str(value)): # make sure at least one and only one field is present inside the parser diff --git a/src/backend/InvenTree/generic/states/fields.py b/src/backend/InvenTree/generic/states/fields.py index 19d23b028e..fe3425f242 100644 --- a/src/backend/InvenTree/generic/states/fields.py +++ b/src/backend/InvenTree/generic/states/fields.py @@ -1,6 +1,7 @@ """Custom model/serializer fields for InvenTree models that support custom states.""" -from typing import Any, Iterable, Optional +from collections.abc import Iterable +from typing import Any, Optional from django.core.exceptions import ObjectDoesNotExist from django.db import models diff --git a/src/backend/InvenTree/machine/machine_types/label_printer.py b/src/backend/InvenTree/machine/machine_types/label_printer.py index 119da641af..9ad74d3ba0 100644 --- a/src/backend/InvenTree/machine/machine_types/label_printer.py +++ b/src/backend/InvenTree/machine/machine_types/label_printer.py @@ -59,7 +59,7 @@ class LabelPrinterBaseDriver(BaseDriver): label: LabelTemplate, items: QuerySet[models.Model], **kwargs, - ) -> Union[None, JsonResponse]: + ) -> Union[JsonResponse, None]: """Print one or more labels with the provided template and items. Arguments: diff --git a/src/backend/InvenTree/plugin/base/barcodes/helper.py b/src/backend/InvenTree/plugin/base/barcodes/helper.py index d8814534ce..fcddfcf327 100644 --- a/src/backend/InvenTree/plugin/base/barcodes/helper.py +++ b/src/backend/InvenTree/plugin/base/barcodes/helper.py @@ -1,6 +1,6 @@ """Helper functions for barcode generation.""" -from typing import Type, cast +from typing import cast import structlog @@ -44,7 +44,7 @@ def generate_barcode(model_instance: InvenTreeBarcodeMixin): @cache -def get_supported_barcode_models() -> list[Type[InvenTreeBarcodeMixin]]: +def get_supported_barcode_models() -> list[type[InvenTreeBarcodeMixin]]: """Returns a list of database models which support barcode functionality.""" return InvenTree.helpers_model.getModelsWithMixin(InvenTreeBarcodeMixin) diff --git a/src/backend/InvenTree/report/templatetags/report.py b/src/backend/InvenTree/report/templatetags/report.py index 935a47578e..9c84d20732 100644 --- a/src/backend/InvenTree/report/templatetags/report.py +++ b/src/backend/InvenTree/report/templatetags/report.py @@ -426,10 +426,10 @@ def render_html_text(text: str, **kwargs): """ tags = [] - if kwargs.get('bold', False): + if kwargs.get('bold'): tags.append('strong') - if kwargs.get('italic', False): + if kwargs.get('italic'): tags.append('em') if heading := kwargs.get('heading', ''): diff --git a/src/backend/InvenTree/report/tests.py b/src/backend/InvenTree/report/tests.py index f410da2aec..3b22b37abb 100644 --- a/src/backend/InvenTree/report/tests.py +++ b/src/backend/InvenTree/report/tests.py @@ -1,6 +1,7 @@ """Unit testing for the various report models.""" from io import StringIO +from zoneinfo import ZoneInfo from django.apps import apps from django.conf import settings @@ -11,7 +12,6 @@ from django.utils import timezone from django.utils.safestring import SafeString from PIL import Image -from zoneinfo import ZoneInfo import report.models as report_models from build.models import Build diff --git a/src/backend/InvenTree/stock/models.py b/src/backend/InvenTree/stock/models.py index 6f000a1b0b..b781176096 100644 --- a/src/backend/InvenTree/stock/models.py +++ b/src/backend/InvenTree/stock/models.py @@ -472,7 +472,7 @@ class StockItem( Returns: QuerySet: The created StockItem objects - raises: + Raises: ValidationError: If any of the provided serial numbers are invalid This method uses bulk_create to create multiple StockItem objects in a single query, diff --git a/tasks.py b/tasks.py index 326104d682..08e097f2fd 100644 --- a/tasks.py +++ b/tasks.py @@ -614,7 +614,7 @@ def update( # If: # - INVENTREE_DOCKER is set (by the docker image eg.) and not overridden by `--frontend` flag # - `--no-frontend` flag is set - if (os.environ.get('INVENTREE_DOCKER', False) and not frontend) or no_frontend: + if (os.environ.get('INVENTREE_DOCKER', 'False') and not frontend) or no_frontend: if no_frontend: info('Skipping frontend update (no_frontend flag set)') else: @@ -1041,7 +1041,7 @@ def test( pty = not disable_pty - _apps = ' '.join(apps()) + tested_apps = ' '.join(apps()) cmd = 'test' @@ -1050,7 +1050,7 @@ def test( cmd += f' {runtest}' else: # Run all tests - cmd += f' {_apps}' + cmd += f' {tested_apps}' if report: cmd += ' --slowreport' @@ -1351,9 +1351,12 @@ def frontend_download( def handle_download(url): # download frontend-build.zip to temporary file - with requests.get( - url, headers=default_headers, stream=True, allow_redirects=True - ) as response, NamedTemporaryFile(suffix='.zip') as dst: + with ( + requests.get( + url, headers=default_headers, stream=True, allow_redirects=True + ) as response, + NamedTemporaryFile(suffix='.zip') as dst, + ): response.raise_for_status() # auto decode the gzipped raw data