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"] "__init__.py" = ["D104"]
[tool.ruff.lint] [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: # Things that should be enabled in the future:
# - LOG # - LOG
# - DJ # for Django stuff # - DJ # for Django stuff
# - S # for security stuff (bandit) # - S # for security stuff (bandit)
ignore = [ ignore = [
"RUF015",
# - RUF015 - Prefer next({iterable}) over single element slice
"RUF012",
# - RUF012 - Mutable class attributes should be annotated with typing.ClassVar
"SIM117", "SIM117",
# - SIM117 - Use a single with statement with multiple contexts instead of nested with statements # - SIM117 - Use a single with statement with multiple contexts instead of nested with statements
"SIM102", "SIM102",

View File

@ -2,6 +2,7 @@
import logging import logging
import re import re
from typing import Optional
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -133,7 +134,7 @@ def convert_value(value, unit):
return value 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. """Validate that the provided value is a valid physical quantity.
Arguments: Arguments:

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@ import time
import warnings import warnings
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Callable from typing import Callable, Optional
from django.conf import settings from django.conf import settings
from django.core.exceptions import AppRegistryNotReady from django.core.exceptions import AppRegistryNotReady
@ -291,7 +291,7 @@ class TaskRegister:
task_list: list[ScheduledTask] = [] 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.""" """Register a task with the que."""
self.task_list.append(ScheduledTask(task, schedule, minutes)) self.task_list.append(ScheduledTask(task, schedule, minutes))
@ -299,7 +299,9 @@ class TaskRegister:
tasks = 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. """Register the given task as a scheduled task.
Example: Example:

View File

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

View File

@ -2,6 +2,7 @@
import json import json
import logging import logging
from typing import Optional
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ValidationError as DjangoValidationError
@ -537,7 +538,10 @@ class DataImportRow(models.Model):
return overrides return overrides
def extract_data( 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.""" """Extract row data from the provided data dictionary."""
if not field_mapping: if not field_mapping:

View File

@ -139,7 +139,7 @@ class BaseDriver(
Arguments: Arguments:
error: Exception or string error: Exception or string
""" """
self.set_shared_state('errors', self.errors + [error]) self.set_shared_state('errors', [*self.errors, error])
# --- state getters/setters # --- state getters/setters
@property @property
@ -317,7 +317,7 @@ class BaseMachineType(
Arguments: Arguments:
error: Exception or string error: Exception or string
""" """
self.set_shared_state('errors', self.errors + [error]) self.set_shared_state('errors', [*self.errors, error])
def reset_errors(self): def reset_errors(self):
"""Helper function for resetting the error list for a machine.""" """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]): def handle_error(self, error: Union[Exception, str]):
"""Helper function for capturing errors with the machine registry.""" """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): def initialize(self, main: bool = False):
"""Initialize the machine registry.""" """Initialize the machine registry."""

View File

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

View File

@ -4,6 +4,7 @@ Primarily BOM upload tools.
""" """
from collections import OrderedDict from collections import OrderedDict
from typing import Optional
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
@ -40,7 +41,11 @@ def MakeBomTemplate(fmt):
def ExportBom( 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. """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 return orders_intersection if orders_intersection else orders_union
@staticmethod @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.""" """Get a supplier part from SKU or by supplier and MPN."""
if not (sku or supplier or mpn): if not (sku or supplier or mpn):
return SupplierPart.objects.none() return SupplierPart.objects.none()
@ -420,10 +422,10 @@ class SupplierBarcodeMixin(BarcodeMixin):
def receive_purchase_order_item( def receive_purchase_order_item(
supplier_part: SupplierPart, supplier_part: SupplierPart,
user: User, user: User,
quantity: Decimal | str = None, quantity: Decimal | str | None = None,
purchase_order: PurchaseOrder = None, purchase_order: PurchaseOrder = None,
location: StockLocation = None, location: StockLocation = None,
barcode: str = None, barcode: str | None = None,
) -> dict: ) -> dict:
"""Try to receive a purchase order item. """Try to receive a purchase order item.

View File

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

View File

@ -1,5 +1,7 @@
"""Validation mixin class definition.""" """Validation mixin class definition."""
from typing import Optional
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Model from django.db.models import Model
@ -67,7 +69,9 @@ class ValidationMixin:
""" """
return None 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. """Run custom validation on a database model instance.
This method is called when a model instance is being validated. 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 distutils.sysconfig import get_python_lib
from importlib.metadata import PackageNotFoundError, metadata from importlib.metadata import PackageNotFoundError, metadata
from pathlib import Path from pathlib import Path
from typing import Optional
from django.conf import settings from django.conf import settings
from django.urls.base import reverse from django.urls.base import reverse
@ -27,7 +28,7 @@ class MetaBase:
SLUG = None SLUG = None
TITLE = 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. """Reference a meta item with a key.
Args: Args:

View File

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

View File

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

View File

@ -1519,7 +1519,7 @@ def stock_item_adjust_status_options():
In particular, include a Null option for the status field. 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): class StockAdjustmentItemSerializer(serializers.Serializer):

View File

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

View File

@ -9,6 +9,7 @@ import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
from platform import python_version from platform import python_version
from typing import Optional
from invoke import task from invoke import task
@ -135,7 +136,7 @@ def managePyPath():
return managePyDir().joinpath('manage.py') 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. """Runs a given command a given path.
Args: Args: