Add RUF rules

This commit is contained in:
Matthias Mair 2024-08-20 00:03:39 +02:00
parent a2dfac593b
commit 3e5432db47
No known key found for this signature in database
GPG Key ID: A593429DDA23B66A
22 changed files with 63 additions and 35 deletions

View File

@ -20,13 +20,17 @@ src = ["src/backend/InvenTree"]
"__init__.py" = ["D104"]
[tool.ruff.lint]
select = ["A", "B", "C", "C4", "D", "F", "I", "N", "SIM", "PIE", "UP", "W"]
select = ["A", "B", "C", "C4", "D", "F", "I", "N", "SIM", "PIE", "RUF", "UP", "W"]
# Things that should be enabled in the future:
# - LOG
# - DJ # for Django stuff
# - S # for security stuff (bandit)
ignore = [
"RUF015",
# - RUF015 - Prefer next({iterable}) over single element slice
"RUF012",
# - RUF012 - Mutable class attributes should be annotated with typing.ClassVar
"SIM117",
# - SIM117 - Use a single with statement with multiple contexts instead of nested with statements
"SIM102",

View File

@ -2,6 +2,7 @@
import logging
import re
from typing import Optional
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
@ -133,7 +134,7 @@ def convert_value(value, unit):
return value
def convert_physical_value(value: str, unit: str = None, strip_units=True):
def convert_physical_value(value: str, unit: Optional[str] = None, strip_units=True):
"""Validate that the provided value is a valid physical quantity.
Arguments:

View File

@ -2,6 +2,7 @@
import re
import string
from typing import Optional
from django.conf import settings
from django.utils import translation
@ -179,8 +180,8 @@ def extract_named_group(name: str, value: str, fmt_string: str) -> str:
def format_money(
money: Money,
decimal_places: int = None,
format: str = None,
decimal_places: Optional[int] = None,
format: Optional[str] = None,
include_symbol: bool = True,
) -> str:
"""Format money object according to the currently set local.

View File

@ -9,7 +9,7 @@ import os.path
import re
from decimal import Decimal, InvalidOperation
from pathlib import Path
from typing import TypeVar, Union
from typing import Optional, TypeVar, Union
from wsgiref.util import FileWrapper
from django.conf import settings
@ -859,7 +859,7 @@ def server_timezone() -> str:
return settings.TIME_ZONE
def to_local_time(time, target_tz: str = None):
def to_local_time(time, target_tz: Optional[str] = None):
"""Convert the provided time object to the local timezone.
Arguments:

View File

@ -856,7 +856,7 @@ class InvenTreeTree(MetadataMixin, PluginValidationMixin, MPTTModel):
Returns:
List of category names from the top level to this category
"""
return self.parentpath + [self]
return [*self.parentpath, self]
def get_path(self):
"""Return a list of element in the item tree.

View File

@ -89,7 +89,7 @@ class InvenTreeCurrencySerializer(serializers.ChoiceField):
)
if allow_blank:
choices = [('', '---------')] + choices
choices = [('', '---------'), *choices]
kwargs['choices'] = choices
@ -424,14 +424,15 @@ class ExendedUserSerializer(UserSerializer):
class Meta(UserSerializer.Meta):
"""Metaclass defines serializer fields."""
fields = UserSerializer.Meta.fields + [
fields = [
*UserSerializer.Meta.fields,
'groups',
'is_staff',
'is_superuser',
'is_active',
]
read_only_fields = UserSerializer.Meta.read_only_fields + ['groups']
read_only_fields = [*UserSerializer.Meta.read_only_fields, 'groups']
is_staff = serializers.BooleanField(
label=_('Staff'), help_text=_('Does this user have staff permissions')

View File

@ -9,7 +9,7 @@ import time
import warnings
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Callable
from typing import Callable, Optional
from django.conf import settings
from django.core.exceptions import AppRegistryNotReady
@ -291,7 +291,7 @@ class TaskRegister:
task_list: list[ScheduledTask] = []
def register(self, task, schedule, minutes: int = None):
def register(self, task, schedule, minutes: Optional[int] = None):
"""Register a task with the que."""
self.task_list.append(ScheduledTask(task, schedule, minutes))
@ -299,7 +299,9 @@ class TaskRegister:
tasks = TaskRegister()
def scheduled_task(interval: str, minutes: int = None, tasklist: TaskRegister = None):
def scheduled_task(
interval: str, minutes: Optional[int] = None, tasklist: TaskRegister = None
):
"""Register the given task as a scheduled task.
Example:

View File

@ -65,7 +65,7 @@ class MatchFieldForm(forms.Form):
for col in columns:
field_name = col['name']
self.fields[field_name] = forms.ChoiceField(
choices=[('', '-' * 10)] + headers_choices,
choices=[('', '-' * 10), *headers_choices],
required=False,
widget=forms.Select(attrs={'class': 'select fieldselect'}),
)
@ -131,7 +131,7 @@ class MatchItemForm(forms.Form):
item_match = row['match_' + col_guess]
# Set field select box
self.fields[field_name] = forms.ChoiceField(
choices=[('', '-' * 10)] + item_options,
choices=[('', '-' * 10), *item_options],
required=False,
widget=forms.Select(attrs={'class': 'select bomselect'}),
)
@ -151,7 +151,7 @@ class MatchItemForm(forms.Form):
field_name = 'item_select-' + str(row['index'])
# Set field select box
self.fields[field_name] = forms.ChoiceField(
choices=[('', '-' * 10)] + item_options,
choices=[('', '-' * 10), *item_options],
required=False,
widget=forms.Select(attrs={'class': 'select bomselect'}),
)

View File

@ -2,6 +2,7 @@
import json
import logging
from typing import Optional
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError as DjangoValidationError
@ -537,7 +538,10 @@ class DataImportRow(models.Model):
return overrides
def extract_data(
self, available_fields: dict = None, field_mapping: dict = None, commit=True
self,
available_fields: Optional[dict] = None,
field_mapping: Optional[dict] = None,
commit=True,
):
"""Extract row data from the provided data dictionary."""
if not field_mapping:

View File

@ -139,7 +139,7 @@ class BaseDriver(
Arguments:
error: Exception or string
"""
self.set_shared_state('errors', self.errors + [error])
self.set_shared_state('errors', [*self.errors, error])
# --- state getters/setters
@property
@ -317,7 +317,7 @@ class BaseMachineType(
Arguments:
error: Exception or string
"""
self.set_shared_state('errors', self.errors + [error])
self.set_shared_state('errors', [*self.errors, error])
def reset_errors(self):
"""Helper function for resetting the error list for a machine."""

View File

@ -38,7 +38,7 @@ class MachineRegistry(
def handle_error(self, error: Union[Exception, str]):
"""Helper function for capturing errors with the machine registry."""
self.set_shared_state('errors', self.errors + [error])
self.set_shared_state('errors', [*self.errors, error])
def initialize(self, main: bool = False):
"""Initialize the machine registry."""

View File

@ -164,7 +164,8 @@ class AbstractOrderSerializer(DataImportExportSerializerMixin, serializers.Seria
'notes',
'barcode_hash',
'overdue',
] + extra_fields
*extra_fields,
]
class AbstractLineItemSerializer:
@ -433,7 +434,7 @@ class PurchaseOrderLineItemSerializer(
def skip_create_fields(self):
"""Return a list of fields to skip when creating a new object."""
return ['auto_pricing', 'merge_items'] + super().skip_create_fields()
return ['auto_pricing', 'merge_items', *super().skip_create_fields()]
@staticmethod
def annotate_queryset(queryset):

View File

@ -4,6 +4,7 @@ Primarily BOM upload tools.
"""
from collections import OrderedDict
from typing import Optional
from django.utils.translation import gettext as _
@ -40,7 +41,11 @@ def MakeBomTemplate(fmt):
def ExportBom(
part: Part, fmt='csv', cascade: bool = False, max_levels: int = None, **kwargs
part: Part,
fmt='csv',
cascade: bool = False,
max_levels: Optional[int] = None,
**kwargs,
):
"""Export a BOM (Bill of Materials) for a given part.

View File

@ -384,7 +384,9 @@ class SupplierBarcodeMixin(BarcodeMixin):
return orders_intersection if orders_intersection else orders_union
@staticmethod
def get_supplier_parts(sku: str = None, supplier: Company = None, mpn: str = None):
def get_supplier_parts(
sku: str | None = None, supplier: Company = None, mpn: str | None = None
):
"""Get a supplier part from SKU or by supplier and MPN."""
if not (sku or supplier or mpn):
return SupplierPart.objects.none()
@ -420,10 +422,10 @@ class SupplierBarcodeMixin(BarcodeMixin):
def receive_purchase_order_item(
supplier_part: SupplierPart,
user: User,
quantity: Decimal | str = None,
quantity: Decimal | str | None = None,
purchase_order: PurchaseOrder = None,
location: StockLocation = None,
barcode: str = None,
barcode: str | None = None,
) -> dict:
"""Try to receive a purchase order item.

View File

@ -3,6 +3,7 @@
import json as json_pkg
import logging
from collections.abc import Iterable
from typing import Optional
import requests
@ -117,10 +118,10 @@ class APICallMixin:
self,
endpoint: str,
method: str = 'GET',
url_args: dict = None,
url_args: Optional[dict] = None,
data=None,
json=None,
headers: dict = None,
headers: Optional[dict] = None,
simple_response: bool = True,
endpoint_is_url: bool = False,
):

View File

@ -1,5 +1,7 @@
"""Validation mixin class definition."""
from typing import Optional
from django.core.exceptions import ValidationError
from django.db.models import Model
@ -67,7 +69,9 @@ class ValidationMixin:
"""
return None
def validate_model_instance(self, instance: Model, deltas: dict = None) -> None:
def validate_model_instance(
self, instance: Model, deltas: Optional[dict] = None
) -> None:
"""Run custom validation on a database model instance.
This method is called when a model instance is being validated.

View File

@ -7,6 +7,7 @@ from datetime import datetime
from distutils.sysconfig import get_python_lib
from importlib.metadata import PackageNotFoundError, metadata
from pathlib import Path
from typing import Optional
from django.conf import settings
from django.urls.base import reverse
@ -27,7 +28,7 @@ class MetaBase:
SLUG = None
TITLE = None
def get_meta_value(self, key: str, old_key: str = None, __default=None):
def get_meta_value(self, key: str, old_key: Optional[str] = None, __default=None):
"""Reference a meta item with a key.
Args:

View File

@ -1025,7 +1025,7 @@ class StockList(DataExportViewMixin, ListCreateDestroyAPIView):
msg += ' : '
msg += ','.join([str(e) for e in invalid])
raise ValidationError({'serial_numbers': errors + [msg]})
raise ValidationError({'serial_numbers': [*errors, msg]})
except DjangoValidationError as e:
raise ValidationError({

View File

@ -1432,7 +1432,7 @@ class StockItem(
self,
entry_type: int,
user: User,
deltas: dict = None,
deltas: dict | None = None,
notes: str = '',
**kwargs,
):

View File

@ -1519,7 +1519,7 @@ def stock_item_adjust_status_options():
In particular, include a Null option for the status field.
"""
return [(None, _('No Change'))] + stock.status_codes.StockStatus.items()
return [(None, _('No Change')), *stock.status_codes.StockStatus.items()]
class StockAdjustmentItemSerializer(serializers.Serializer):

View File

@ -63,7 +63,7 @@ class RuleSetInline(admin.TabularInline):
can_delete = False
verbose_name = 'Ruleset'
verbose_plural_name = 'Rulesets'
fields = ['name'] + list(RuleSet.RULE_OPTIONS)
fields = ['name', *list(RuleSet.RULE_OPTIONS)]
readonly_fields = ['name']
max_num = len(RuleSet.RULESET_CHOICES)
min_num = 1

View File

@ -9,6 +9,7 @@ import subprocess
import sys
from pathlib import Path
from platform import python_version
from typing import Optional
from invoke import task
@ -135,7 +136,7 @@ def managePyPath():
return managePyDir().joinpath('manage.py')
def run(c, cmd, path: Path = None, pty=False, env=None):
def run(c, cmd, path: Optional[Path] = None, pty=False, env=None):
"""Runs a given command a given path.
Args: