2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-26 18:46:44 +00:00

fix(backend): enforce docstring args (#9428)

* enforce docstring args

* add more rules that we could add later

* fix missing yields

* add a type

* make 3.9 compat
This commit is contained in:
Matthias Mair 2025-04-04 00:02:55 +02:00 committed by GitHub
parent b48ceb00f2
commit a2370dbe59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 98 additions and 47 deletions

View File

@ -126,17 +126,18 @@ def define_env(env):
"""Define custom environment variables for the documentation build process."""
@env.macro
def sourcedir(dirname, branch=None):
def sourcedir(dirname: str, branch=None):
"""Return a link to a directory within the source code repository.
Arguments:
- dirname: The name of the directory to link to (relative to the top-level directory)
dirname: The name of the directory to link to (relative to the top-level directory)
branch: The branch of the repository to link to (defaults to the current build environment)
Returns:
- A fully qualified URL to the source code directory on GitHub
A fully qualified URL to the source code directory on GitHub
Raises:
- FileNotFoundError: If the directory does not exist, or the generated URL is invalid
FileNotFoundError: If the directory does not exist, or the generated URL is invalid
"""
if branch == None:
branch = get_build_environment()
@ -169,13 +170,15 @@ def define_env(env):
"""Return a link to a file within the source code repository.
Arguments:
- filename: The name of the file to link to (relative to the top-level directory)
filename: The name of the file to link to (relative to the top-level directory)
branch: The branch of the repository to link to (defaults to the current build environment)
raw: If True, return the raw URL to the file (defaults to False)
Returns:
- A fully qualified URL to the source code file on GitHub
A fully qualified URL to the source code file on GitHub
Raises:
- FileNotFoundError: If the file does not exist, or the generated URL is invalid
FileNotFoundError: If the file does not exist, or the generated URL is invalid
"""
if branch == None:
branch = get_build_environment()
@ -247,9 +250,9 @@ def define_env(env):
"""Include a file in the documentation, in a 'collapse' block.
Arguments:
- filename: The name of the file to include (relative to the top-level directory)
- title:
- fmt:
filename: The name of the file to include (relative to the top-level directory)
title: The title of the collapse block in the documentation
fmt: The format of the included file (e.g., 'python', 'html', etc.)
"""
here = os.path.dirname(__file__)
path = os.path.join(here, '..', filename)
@ -299,7 +302,7 @@ def define_env(env):
"""Extract information on a particular global setting.
Arguments:
- key: The name of the global setting to extract information for.
key: The name of the global setting to extract information for.
"""
global GLOBAL_SETTINGS
setting = GLOBAL_SETTINGS[key]
@ -311,7 +314,7 @@ def define_env(env):
"""Extract information on a particular user setting.
Arguments:
- key: The name of the user setting to extract information for.
key: The name of the user setting to extract information for.
"""
global USER_SETTINGS
setting = USER_SETTINGS[key]

View File

@ -18,11 +18,16 @@ src = ["src/backend/InvenTree"]
"__init__.py" = ["D104"]
[tool.ruff.lint]
select = ["A", "B", "C", "C4", "D", "F", "I", "N", "SIM", "PIE", "PLE", "PLW", "RUF", "UP", "W"]
select = ["A", "B", "C", "C4", "D", "F", "I", "N", "SIM", "PIE", "PLE", "PLW", "RUF", "UP", "W",
#"DOC201", "DOC202", # enforce return docs
"DOC402","DOC403", # enforce yield docs
#"DOC501","DOC502", # enforce raise
]
# Things that should be enabled in the future:
# - LOG
# - DJ # for Django stuff
# - S # for security stuff (bandit)
# - D401 - Imperative docstrings
ignore = [
"PLE1205",
@ -51,8 +56,6 @@ ignore = [
"N806",
# - N812 - lowercase imported as non-lowercase
"N812",
# - D417 Missing argument descriptions in the docstring
"D417",
# - RUF032 - decimal-from-float-literal
"RUF032",
"RUF045",
@ -69,6 +72,7 @@ ignore = [
[tool.ruff.lint.pydocstyle]
convention = "google"
ignore-var-parameters = true
[tool.ruff.lint.isort]
split-on-trailing-comma = false

View File

@ -194,6 +194,7 @@ def format_money(
money (Money): The money object to format
decimal_places (int): Number of decimal places to use
fmt (str): Format pattern according LDML / the babel format pattern syntax (https://babel.pocoo.org/en/latest/numbers.html)
include_symbol (bool): Whether to include the currency symbol in the formatted output
Returns:
str: The formatted string

View File

@ -437,6 +437,7 @@ def increment_serial_number(serial, part=None):
Arguments:
serial: The serial number which should be incremented
part: Optional part object to provide additional context for incrementing the serial number
Returns:
incremented value, or None if incrementing could not be performed.
@ -491,6 +492,7 @@ def extract_serial_numbers(
input_string: Input string with specified serial numbers (string, or integer)
expected_quantity: The number of (unique) serial numbers we expect
starting_value: Provide a starting value for the sequence (or None)
part: Part that should be used as context
"""
if starting_value is None:
starting_value = increment_serial_number(None, part=part)

View File

@ -132,6 +132,7 @@ def get_shared_class_instance_state_mixin(get_state_key: Callable[[type], str]):
Arguments:
key: The key for the shared state
default: The default value to return if the key does not exist
"""
return cache.get(self._get_key(key)) or default

View File

@ -170,11 +170,11 @@ class InvenTreeMetadata(SimpleMetadata):
- model_value is callable, and field_value is not (this indicates that the model value is translated)
- model_value is not a string, and field_value is a string (this indicates that the model value is translated)
Arguments:
- field_name: The name of the field
- field_key: The property key to override
- field_value: The value of the field (if available)
- model_value: The equivalent value of the model (if available)
Args:
field_name (str): The name of the field.
field_key (str): The property key to override.
field_value: The value of the field (if available).
model_value: The equivalent value of the model (if available).
"""
if field_value is None and model_value is not None:
return model_value

View File

@ -39,6 +39,9 @@ def setup_tracing(
headers: The headers to send with the traces.
resources_input: The resources to send with the traces.
console: Whether to output the traces to the console.
auth: Dict with auth information
is_http: Whether to use HTTP or gRPC for the exporter.
append_http: Whether to append '/v1/traces' to the endpoint.
"""
if InvenTree.ready.isImportingData() or InvenTree.ready.isRunningMigrations():
return

View File

@ -1766,15 +1766,15 @@ def after_custom_unit_updated(sender, instance, **kwargs):
reload_unit_registry()
def rename_attachment(instance, filename):
def rename_attachment(instance, filename: str):
"""Callback function to rename an uploaded attachment file.
Arguments:
- instance: The Attachment instance
- filename: The original filename of the uploaded file
Args:
instance (Attachment): The Attachment instance for which the file is being renamed.
filename (str): The original filename of the uploaded file.
Returns:
- The new filename for the uploaded file, e.g. 'attachments/<model_type>/<model_id>/<filename>'
str: The new filename for the uploaded file, e.g. 'attachments/<model_type>/<model_id>/<filename>'.
"""
# Remove any illegal characters from the filename
illegal_chars = '\'"\\`~#|!@#$%^&*()[]{}<>?;:+=,'

View File

@ -2,6 +2,7 @@
import functools
import re
from datetime import datetime
from django.db.models import Count, F, Q
from django.urls import include, path
@ -567,15 +568,21 @@ class PartScheduling(RetrieveAPI):
schedule = []
def add_schedule_entry(date, quantity, title, instance, speculative_quantity=0):
def add_schedule_entry(
date: datetime,
quantity: float,
title: str,
instance,
speculative_quantity: float = 0,
):
"""Add a new entry to the schedule list.
Arguments:
- date: The date of the scheduled event
- quantity: The quantity of stock to be added or removed
- title: The title of the scheduled event
- instance: The associated model instance (e.g. SalesOrder object)
- speculative_quantity: A speculative quantity to be added or removed
Args:
date (datetime): The date of the scheduled event.
quantity (float): The quantity of stock to be added or removed.
title (str): The title of the scheduled event.
instance (Model): The associated model instance (e.g., SalesOrder object).
speculative_quantity (float, optional): A speculative quantity to be added or removed. Defaults to 0.
"""
schedule.append({
'date': date,

View File

@ -112,8 +112,8 @@ def annotate_total_stock(reference: str = '', filter: Q = None):
- Aggregates the 'quantity' of each relevant stock item
Args:
reference: The relationship reference of the part from the current model e.g. 'part'
stock_filter: Q object which defines how to filter the stock items
reference (str): The relationship reference of the part from the current model e.g. 'part'
filter (Q): Q object which defines how to filter the stock items
"""
# Stock filter only returns 'in stock' items
stock_filter = stock.models.StockItem.IN_STOCK_FILTER

View File

@ -753,6 +753,7 @@ class Part(
Arguments:
serial: The proposed serial number
stock_item: (optional) A StockItem instance which has this serial number assigned (e.g. testing for duplicates)
check_duplicates: If True, checks for duplicate serial numbers in the database.
raise_error: If False, and ValidationError(s) will be handled
Returns:
@ -2344,15 +2345,20 @@ class Part(
parameter.save()
def getTestTemplates(
self, required=None, include_parent=True, enabled=None
self, required=None, include_parent: bool = True, enabled=None
) -> QuerySet[PartTestTemplate]:
"""Return a list of all test templates associated with this Part.
These are used for validation of a StockItem.
Args:
required: Set to True or False to filter by "required" status
include_parent: Set to True to traverse upwards
required (bool, optional): Filter templates by whether they are required. Defaults to None.
include_parent (bool, optional): Include templates from parent parts. Defaults to True.
enabled (bool, optional): Filter templates by their enabled status. Defaults to None.
Returns:
QuerySet: A queryset of matching test templates.
"""
if include_parent:
tests = PartTestTemplate.objects.filter(

View File

@ -37,12 +37,13 @@ class BarcodeView(CreateAPIView):
# Default serializer class (can be overridden)
serializer_class = barcode_serializers.BarcodeSerializer
def log_scan(self, request, response=None, result=False):
def log_scan(self, request, response=None, result: bool = False):
"""Log a barcode scan to the database.
Arguments:
request: HTTP request object
response: Optional response data
result: Boolean indicating success or failure of the scan
"""
from common.models import BarcodeScanResult

View File

@ -73,7 +73,7 @@ class LabelPrintingMixin:
Arguments:
label: The LabelTemplate object to render against
item: The model instance to render
instance: The model instance to render
request: The HTTP request object which triggered this print job
Keyword Arguments:
pdf_data: The raw PDF data of the rendered label (if already rendered)

View File

@ -117,6 +117,7 @@ class UserInterfaceMixin:
Args:
request: HTTPRequest object (including user information)
context: Additional context data provided by the UI (query parameters)
Returns:
list: A list of custom panels to be injected into the UI
@ -131,6 +132,7 @@ class UserInterfaceMixin:
Args:
request: HTTPRequest object (including user information)
context: Additional context data provided by the UI (query parameters)
Returns:
list: A list of custom dashboard items to be injected into the UI
@ -145,6 +147,7 @@ class UserInterfaceMixin:
Args:
request: HTTPRequest object (including user information)
context: Additional context data provided by the UI (query parameters)
Returns:
list: A list of custom template editors to be injected into the UI
@ -159,6 +162,7 @@ class UserInterfaceMixin:
Args:
request: HTTPRequest object (including user information)
context: Additional context data provided by the UI (query parameters)
Returns:
list: A list of custom template previews to be injected into the UI

View File

@ -109,10 +109,13 @@ class PluginsRegistry:
def get_plugin(self, slug, active=None, with_mixin=None):
"""Lookup plugin by slug (unique key).
Arguments:
slug {str}: The slug (unique key) of the plugin
active {bool, None}: Filter by 'active' status of plugin. Defaults to None.
with_mixin {str, None}: Filter by mixin. Defaults to None.
Args:
slug (str): The slug of the plugin to look up.
active (bool, optional): Filter by 'active' status of the plugin. If None, no filtering is applied. Defaults to None.
with_mixin (str, optional): Filter by mixin name. If None, no filtering is applied. Defaults to None.
Returns:
InvenTreePlugin or None: The plugin instance if found, otherwise None.
"""
# Check if the registry needs to be reloaded
self.check_reload()

View File

@ -343,6 +343,7 @@ class RegistryTests(TestCase):
Arguments:
version: The version string to use for the plugin file
enabled: Whether the plugin should be enabled or not
reload: Whether to reload the plugin registry after creating the file
Returns:
str: The plugin registry hash

View File

@ -100,6 +100,7 @@ def barcode(data: str, barcode_class='code128', **kwargs) -> str:
Arguments:
data: Data to encode
barcode_class (str): The type of barcode to generate (default = 'code128')
Keyword Arguments:
format (str): Image format (default = 'PNG')

View File

@ -5,7 +5,7 @@ import logging
import os
from datetime import date, datetime
from decimal import Decimal
from typing import Any, Optional
from typing import Any, Optional, Union
from django import template
from django.apps.registry import apps
@ -451,7 +451,7 @@ def render_html_text(text: str, **kwargs):
@register.simple_tag
def format_number(
number,
number: Union[int, float, Decimal],
decimal_places: Optional[int] = None,
integer: bool = False,
leading: int = 0,
@ -460,6 +460,7 @@ def format_number(
"""Render a number with optional formatting options.
Arguments:
number: The number to be formatted
decimal_places: Number of decimal places to render
integer: Boolean, whether to render the number as an integer
leading: Number of leading zeros (default = 0)

View File

@ -1647,6 +1647,7 @@ class StockItem(
user (User): The user performing this action
deltas (dict, optional): A map of the changes made to the model. Defaults to None.
notes (str, optional): URL associated with this tracking entry. Defaults to ''.
commit (boolm optional): If True, save the entry to the database. Defaults to True.
Returns:
StockItemTracking: The created tracking entry

View File

@ -214,7 +214,15 @@ class RoleGroupAdmin(admin.ModelAdmin): # pragma: no cover
return self.get_rule_set(obj, 'return_order')
def get_formsets_with_inlines(self, request, obj=None):
"""Return all inline formsets."""
"""Retrieve all inline formsets for the given request and object.
Args:
request (HttpRequest): The HTTP request object.
obj (Model, optional): The model instance for which the formsets are being retrieved. Defaults to None.
Yields:
tuple: A tuple containing the formset and the corresponding inline instance.
"""
for inline in self.get_inline_instances(request, obj):
# Hide RuleSetInline in the 'Add role' view
if not isinstance(inline, RuleSetInline) or obj is not None:

View File

@ -172,6 +172,7 @@ def content_excludes(
"""Returns a list of content types to exclude from import / export.
Arguments:
allow_auth (bool): Allow user authentication data to be exported / imported
allow_tokens (bool): Allow tokens to be exported / imported
allow_plugins (bool): Allow plugin information to be exported / imported
allow_sso (bool): Allow SSO tokens to be exported / imported
@ -243,6 +244,7 @@ def run(c, cmd, path: Optional[Path] = None, pty=False, env=None):
cmd: Command to run.
path: Path to run the command in.
pty (bool, optional): Run an interactive session. Defaults to False.
env (dict, optional): Environment variables to pass to the command. Defaults to None.
"""
env = env or {}
path = path or localDir()
@ -1082,7 +1084,8 @@ def test(
):
"""Run unit-tests for InvenTree codebase.
Arguments:
Args:
c: Command line context.
disable_pty (bool): Disable PTY (default = False)
runtest (str): Specify which tests to run, in format <module>.<file>.<class>.<method> (default = '')
migrations (bool): Run migration unit tests (default = False)
@ -1394,6 +1397,7 @@ def frontend_trans(c, extract: bool = True):
Args:
c: Context variable
extract (bool): Whether to extract translations from source code. Defaults to True.
"""
info('Compiling frontend translations')
if extract: