mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add RUF rules
This commit is contained in:
parent
a2dfac593b
commit
3e5432db47
@ -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",
|
||||||
|
@ -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:
|
||||||
|
@ -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.
|
||||||
|
@ -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:
|
||||||
|
@ -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.
|
||||||
|
@ -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')
|
||||||
|
@ -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:
|
||||||
|
@ -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'}),
|
||||||
)
|
)
|
||||||
|
@ -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:
|
||||||
|
@ -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."""
|
||||||
|
@ -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."""
|
||||||
|
@ -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):
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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,
|
||||||
):
|
):
|
||||||
|
@ -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.
|
||||||
|
@ -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:
|
||||||
|
@ -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({
|
||||||
|
@ -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,
|
||||||
):
|
):
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
3
tasks.py
3
tasks.py
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user