mirror of https://github.com/astral-sh/ruff
[`pydoclint`] Implement `docstring-extraneous-parameter` (`DOC102`) (#20376)
## Summary Implement `docstring-extraneous-parameter` (`DOC102`). This rule checks that all parameters present in a functions docstring are also present in its signature. Split from #13280, per this [comment](https://github.com/astral-sh/ruff/pull/13280#issuecomment-3280575506). Part of #12434. ## Test Plan Test cases added. --------- Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
This commit is contained in:
parent
058fc37542
commit
03696687ea
|
|
@ -0,0 +1,264 @@
|
||||||
|
# DOC102
|
||||||
|
def add_numbers(b):
|
||||||
|
"""
|
||||||
|
Adds two numbers and returns the result.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
a (int): The first number to add.
|
||||||
|
b (int): The second number to add.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The sum of the two numbers.
|
||||||
|
"""
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def multiply_list_elements(lst):
|
||||||
|
"""
|
||||||
|
Multiplies each element in a list by a given multiplier.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lst (list of int): A list of integers.
|
||||||
|
multiplier (int): The multiplier for each element in the list.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list of int: A new list with each element multiplied.
|
||||||
|
"""
|
||||||
|
return [x * multiplier for x in lst]
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def find_max_value():
|
||||||
|
"""
|
||||||
|
Finds the maximum value in a list of numbers.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
numbers (list of int): A list of integers to search through.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The maximum value found in the list.
|
||||||
|
"""
|
||||||
|
return max(numbers)
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def create_user_profile(location="here"):
|
||||||
|
"""
|
||||||
|
Creates a user profile with basic information.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): The name of the user.
|
||||||
|
age (int): The age of the user.
|
||||||
|
email (str): The user's email address.
|
||||||
|
location (str): The location of the user.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary containing the user's profile.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'age': age,
|
||||||
|
'email': email,
|
||||||
|
'location': location
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def calculate_total_price(item_prices, discount):
|
||||||
|
"""
|
||||||
|
Calculates the total price after applying tax and a discount.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
item_prices (list of float): A list of prices for each item.
|
||||||
|
tax_rate (float): The tax rate to apply.
|
||||||
|
discount (float): The discount to subtract from the total.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: The final total price after tax and discount.
|
||||||
|
"""
|
||||||
|
total = sum(item_prices)
|
||||||
|
total_with_tax = total + (total * tax_rate)
|
||||||
|
final_total = total_with_tax - discount
|
||||||
|
return final_total
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def send_email(subject, body, bcc_address=None):
|
||||||
|
"""
|
||||||
|
Sends an email to the specified recipients.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subject (str): The subject of the email.
|
||||||
|
body (str): The content of the email.
|
||||||
|
to_address (str): The recipient's email address.
|
||||||
|
cc_address (str, optional): The email address for CC. Defaults to None.
|
||||||
|
bcc_address (str, optional): The email address for BCC. Defaults to None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the email was sent successfully, False otherwise.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def concatenate_strings(*args):
|
||||||
|
"""
|
||||||
|
Concatenates multiple strings with a specified separator.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
separator (str): The separator to use between strings.
|
||||||
|
*args (str): Variable length argument list of strings to concatenate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: A single concatenated string.
|
||||||
|
"""
|
||||||
|
return separator.join(args)
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def process_order(order_id):
|
||||||
|
"""
|
||||||
|
Processes an order with a list of items and optional order details.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
order_id (int): The unique identifier for the order.
|
||||||
|
*items (str): Variable length argument list of items in the order.
|
||||||
|
**details (dict): Additional details such as shipping method and address.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary containing the order summary.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'order_id': order_id,
|
||||||
|
'items': items,
|
||||||
|
'details': details
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Calculator:
|
||||||
|
"""
|
||||||
|
A simple calculator class that can perform basic arithmetic operations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Initializes the calculator with an initial value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (int, optional): The initial value of the calculator. Defaults to 0.
|
||||||
|
"""
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def add(self, number2):
|
||||||
|
"""
|
||||||
|
Adds a number to the current value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
number (int or float): The number to add to the current value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int or float: The updated value after addition.
|
||||||
|
"""
|
||||||
|
self.value += number + number2
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
@classmethod
|
||||||
|
def from_string(cls):
|
||||||
|
"""
|
||||||
|
Creates a Calculator instance from a string representation of a number.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value_str (str): The string representing the initial value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Calculator: A new instance of Calculator initialized with the value from the string.
|
||||||
|
"""
|
||||||
|
value = float(value_str)
|
||||||
|
return cls(value)
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
@staticmethod
|
||||||
|
def is_valid_number():
|
||||||
|
"""
|
||||||
|
Checks if a given number is valid (int or float).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
number (any): The value to check.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the number is valid, False otherwise.
|
||||||
|
"""
|
||||||
|
return isinstance(number, (int, float))
|
||||||
|
|
||||||
|
# OK
|
||||||
|
def foo(param1, param2, *args, **kwargs):
|
||||||
|
"""Foo.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
param1 (int): The first parameter.
|
||||||
|
param2 (:obj:`str`, optional): The second parameter. Defaults to None.
|
||||||
|
Second line of description: should be indented.
|
||||||
|
*args: Variable length argument list.
|
||||||
|
**kwargs: Arbitrary keyword arguments.
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
# OK
|
||||||
|
def on_server_unloaded(self, server_context: ServerContext) -> None:
|
||||||
|
''' Execute ``on_server_unloaded`` from ``server_lifecycle.py`` (if
|
||||||
|
it is defined) when the server cleanly exits. (Before stopping the
|
||||||
|
server's ``IOLoop``.)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
server_context (ServerContext) :
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
In practice this code may not run, since servers are often killed
|
||||||
|
by a signal.
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
return self._lifecycle_handler.on_server_unloaded(server_context)
|
||||||
|
|
||||||
|
# OK
|
||||||
|
def function_with_kwargs(param1, param2, **kwargs):
|
||||||
|
"""Function with **kwargs parameter.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
param1 (int): The first parameter.
|
||||||
|
param2 (str): The second parameter.
|
||||||
|
extra_param (str): An extra parameter that may be passed via **kwargs.
|
||||||
|
another_extra (int): Another extra parameter.
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
# OK
|
||||||
|
def add_numbers(b):
|
||||||
|
"""
|
||||||
|
Adds two numbers and returns the result.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
b: The second number to add.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The sum of the two numbers.
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def add_numbers(b):
|
||||||
|
"""
|
||||||
|
Adds two numbers and returns the result.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
a: The first number to add.
|
||||||
|
b: The second number to add.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The sum of the two numbers.
|
||||||
|
"""
|
||||||
|
return a + b
|
||||||
|
|
@ -0,0 +1,372 @@
|
||||||
|
# DOC102
|
||||||
|
def add_numbers(b):
|
||||||
|
"""
|
||||||
|
Adds two numbers and returns the result.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
a : int
|
||||||
|
The first number to add.
|
||||||
|
b : int
|
||||||
|
The second number to add.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int
|
||||||
|
The sum of the two numbers.
|
||||||
|
"""
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def multiply_list_elements(lst):
|
||||||
|
"""
|
||||||
|
Multiplies each element in a list by a given multiplier.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
lst : list of int
|
||||||
|
A list of integers.
|
||||||
|
multiplier : int
|
||||||
|
The multiplier for each element in the list.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list of int
|
||||||
|
A new list with each element multiplied.
|
||||||
|
"""
|
||||||
|
return [x * multiplier for x in lst]
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def find_max_value():
|
||||||
|
"""
|
||||||
|
Finds the maximum value in a list of numbers.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
numbers : list of int
|
||||||
|
A list of integers to search through.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int
|
||||||
|
The maximum value found in the list.
|
||||||
|
"""
|
||||||
|
return max(numbers)
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def create_user_profile(location="here"):
|
||||||
|
"""
|
||||||
|
Creates a user profile with basic information.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
name : str
|
||||||
|
The name of the user.
|
||||||
|
age : int
|
||||||
|
The age of the user.
|
||||||
|
email : str
|
||||||
|
The user's email address.
|
||||||
|
location : str, optional
|
||||||
|
The location of the user, by default "here".
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
A dictionary containing the user's profile.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'age': age,
|
||||||
|
'email': email,
|
||||||
|
'location': location
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def calculate_total_price(item_prices, discount):
|
||||||
|
"""
|
||||||
|
Calculates the total price after applying tax and a discount.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
item_prices : list of float
|
||||||
|
A list of prices for each item.
|
||||||
|
tax_rate : float
|
||||||
|
The tax rate to apply.
|
||||||
|
discount : float
|
||||||
|
The discount to subtract from the total.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float
|
||||||
|
The final total price after tax and discount.
|
||||||
|
"""
|
||||||
|
total = sum(item_prices)
|
||||||
|
total_with_tax = total + (total * tax_rate)
|
||||||
|
final_total = total_with_tax - discount
|
||||||
|
return final_total
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def send_email(subject, body, bcc_address=None):
|
||||||
|
"""
|
||||||
|
Sends an email to the specified recipients.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
subject : str
|
||||||
|
The subject of the email.
|
||||||
|
body : str
|
||||||
|
The content of the email.
|
||||||
|
to_address : str
|
||||||
|
The recipient's email address.
|
||||||
|
cc_address : str, optional
|
||||||
|
The email address for CC, by default None.
|
||||||
|
bcc_address : str, optional
|
||||||
|
The email address for BCC, by default None.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if the email was sent successfully, False otherwise.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def concatenate_strings(*args):
|
||||||
|
"""
|
||||||
|
Concatenates multiple strings with a specified separator.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
separator : str
|
||||||
|
The separator to use between strings.
|
||||||
|
*args : str
|
||||||
|
Variable length argument list of strings to concatenate.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
A single concatenated string.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def process_order(order_id):
|
||||||
|
"""
|
||||||
|
Processes an order with a list of items and optional order details.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
order_id : int
|
||||||
|
The unique identifier for the order.
|
||||||
|
*items : str
|
||||||
|
Variable length argument list of items in the order.
|
||||||
|
**details : dict
|
||||||
|
Additional details such as shipping method and address.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
A dictionary containing the order summary.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'order_id': order_id,
|
||||||
|
'items': items,
|
||||||
|
'details': details
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Calculator:
|
||||||
|
"""
|
||||||
|
A simple calculator class that can perform basic arithmetic operations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Initializes the calculator with an initial value.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
value : int, optional
|
||||||
|
The initial value of the calculator, by default 0.
|
||||||
|
"""
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def add(self, number2):
|
||||||
|
"""
|
||||||
|
Adds two numbers to the current value.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
number : int or float
|
||||||
|
The first number to add.
|
||||||
|
number2 : int or float
|
||||||
|
The second number to add.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int or float
|
||||||
|
The updated value after addition.
|
||||||
|
"""
|
||||||
|
self.value += number + number2
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
@classmethod
|
||||||
|
def from_string(cls):
|
||||||
|
"""
|
||||||
|
Creates a Calculator instance from a string representation of a number.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
value_str : str
|
||||||
|
The string representing the initial value.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Calculator
|
||||||
|
A new instance of Calculator initialized with the value from the string.
|
||||||
|
"""
|
||||||
|
value = float(value_str)
|
||||||
|
return cls(value)
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
@staticmethod
|
||||||
|
def is_valid_number():
|
||||||
|
"""
|
||||||
|
Checks if a given number is valid (int or float).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
number : any
|
||||||
|
The value to check.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if the number is valid, False otherwise.
|
||||||
|
"""
|
||||||
|
return isinstance(number, (int, float))
|
||||||
|
|
||||||
|
# OK
|
||||||
|
def function_with_kwargs(param1, param2, **kwargs):
|
||||||
|
"""Function with **kwargs parameter.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
param1 : int
|
||||||
|
The first parameter.
|
||||||
|
param2 : str
|
||||||
|
The second parameter.
|
||||||
|
extra_param : str
|
||||||
|
An extra parameter that may be passed via **kwargs.
|
||||||
|
another_extra : int
|
||||||
|
Another extra parameter.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
# OK
|
||||||
|
def add_numbers(b):
|
||||||
|
"""
|
||||||
|
Adds two numbers and returns the result.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
b
|
||||||
|
The second number to add.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int
|
||||||
|
The sum of the two numbers.
|
||||||
|
"""
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
# DOC102
|
||||||
|
def add_numbers(b):
|
||||||
|
"""
|
||||||
|
Adds two numbers and returns the result.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
a
|
||||||
|
The first number to add.
|
||||||
|
b
|
||||||
|
The second number to add.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int
|
||||||
|
The sum of the two numbers.
|
||||||
|
"""
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
# OK
|
||||||
|
def send_help(self, *args: Any) -> Any:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Shows the help command for the specified entity if given.
|
||||||
|
The entity can be a command or a cog.
|
||||||
|
|
||||||
|
If no entity is given, then it'll show help for the
|
||||||
|
entire bot.
|
||||||
|
|
||||||
|
If the entity is a string, then it looks up whether it's a
|
||||||
|
:class:`Cog` or a :class:`Command`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Due to the way this function works, instead of returning
|
||||||
|
something similar to :meth:`~.commands.HelpCommand.command_not_found`
|
||||||
|
this returns :class:`None` on bad input or no help command.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
entity: Optional[Union[:class:`Command`, :class:`Cog`, :class:`str`]]
|
||||||
|
The entity to show help for.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Any
|
||||||
|
The result of the help command, if any.
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
# OK
|
||||||
|
@classmethod
|
||||||
|
async def convert(cls, ctx: Context, argument: str) -> Self:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
The method that actually converters an argument to the flag mapping.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
cls: Type[:class:`FlagConverter`]
|
||||||
|
The flag converter class.
|
||||||
|
ctx: :class:`Context`
|
||||||
|
The invocation context.
|
||||||
|
argument: :class:`str`
|
||||||
|
The argument to convert from.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
FlagError
|
||||||
|
A flag related parsing error.
|
||||||
|
CommandError
|
||||||
|
A command related error.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
:class:`FlagConverter`
|
||||||
|
The flag converter instance with all flags parsed.
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
@ -81,6 +81,7 @@ pub(crate) fn definitions(checker: &mut Checker) {
|
||||||
Rule::UndocumentedPublicPackage,
|
Rule::UndocumentedPublicPackage,
|
||||||
]);
|
]);
|
||||||
let enforce_pydoclint = checker.any_rule_enabled(&[
|
let enforce_pydoclint = checker.any_rule_enabled(&[
|
||||||
|
Rule::DocstringExtraneousParameter,
|
||||||
Rule::DocstringMissingReturns,
|
Rule::DocstringMissingReturns,
|
||||||
Rule::DocstringExtraneousReturns,
|
Rule::DocstringExtraneousReturns,
|
||||||
Rule::DocstringMissingYields,
|
Rule::DocstringMissingYields,
|
||||||
|
|
|
||||||
|
|
@ -988,6 +988,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||||
(FastApi, "003") => (RuleGroup::Stable, rules::fastapi::rules::FastApiUnusedPathParameter),
|
(FastApi, "003") => (RuleGroup::Stable, rules::fastapi::rules::FastApiUnusedPathParameter),
|
||||||
|
|
||||||
// pydoclint
|
// pydoclint
|
||||||
|
(Pydoclint, "102") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringExtraneousParameter),
|
||||||
(Pydoclint, "201") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringMissingReturns),
|
(Pydoclint, "201") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringMissingReturns),
|
||||||
(Pydoclint, "202") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringExtraneousReturns),
|
(Pydoclint, "202") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringExtraneousReturns),
|
||||||
(Pydoclint, "402") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringMissingYields),
|
(Pydoclint, "402") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringMissingYields),
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(Rule::DocstringExtraneousParameter, Path::new("DOC102_google.py"))]
|
||||||
#[test_case(Rule::DocstringMissingReturns, Path::new("DOC201_google.py"))]
|
#[test_case(Rule::DocstringMissingReturns, Path::new("DOC201_google.py"))]
|
||||||
#[test_case(Rule::DocstringExtraneousReturns, Path::new("DOC202_google.py"))]
|
#[test_case(Rule::DocstringExtraneousReturns, Path::new("DOC202_google.py"))]
|
||||||
#[test_case(Rule::DocstringMissingYields, Path::new("DOC402_google.py"))]
|
#[test_case(Rule::DocstringMissingYields, Path::new("DOC402_google.py"))]
|
||||||
|
|
@ -50,6 +51,7 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(Rule::DocstringExtraneousParameter, Path::new("DOC102_numpy.py"))]
|
||||||
#[test_case(Rule::DocstringMissingReturns, Path::new("DOC201_numpy.py"))]
|
#[test_case(Rule::DocstringMissingReturns, Path::new("DOC201_numpy.py"))]
|
||||||
#[test_case(Rule::DocstringExtraneousReturns, Path::new("DOC202_numpy.py"))]
|
#[test_case(Rule::DocstringExtraneousReturns, Path::new("DOC202_numpy.py"))]
|
||||||
#[test_case(Rule::DocstringMissingYields, Path::new("DOC402_numpy.py"))]
|
#[test_case(Rule::DocstringMissingYields, Path::new("DOC402_numpy.py"))]
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::helpers::map_callable;
|
use ruff_python_ast::helpers::{map_callable, map_subscript};
|
||||||
use ruff_python_ast::helpers::map_subscript;
|
|
||||||
use ruff_python_ast::name::QualifiedName;
|
use ruff_python_ast::name::QualifiedName;
|
||||||
use ruff_python_ast::visitor::Visitor;
|
use ruff_python_ast::visitor::Visitor;
|
||||||
use ruff_python_ast::{self as ast, Expr, Stmt, visitor};
|
use ruff_python_ast::{self as ast, Expr, Stmt, visitor};
|
||||||
use ruff_python_semantic::analyze::{function_type, visibility};
|
use ruff_python_semantic::analyze::{function_type, visibility};
|
||||||
use ruff_python_semantic::{Definition, SemanticModel};
|
use ruff_python_semantic::{Definition, SemanticModel};
|
||||||
use ruff_source_file::NewlineWithTrailingNewline;
|
use ruff_python_stdlib::identifiers::is_identifier;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_source_file::{LineRanges, NewlineWithTrailingNewline};
|
||||||
|
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::Violation;
|
use crate::Violation;
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
@ -18,6 +18,62 @@ use crate::docstrings::styles::SectionStyle;
|
||||||
use crate::registry::Rule;
|
use crate::registry::Rule;
|
||||||
use crate::rules::pydocstyle::settings::Convention;
|
use crate::rules::pydocstyle::settings::Convention;
|
||||||
|
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for function docstrings that include parameters which are not
|
||||||
|
/// in the function signature.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// If a docstring documents a parameter which is not in the function signature,
|
||||||
|
/// it can be misleading to users and/or a sign of incomplete documentation or
|
||||||
|
/// refactors.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```python
|
||||||
|
/// def calculate_speed(distance: float, time: float) -> float:
|
||||||
|
/// """Calculate speed as distance divided by time.
|
||||||
|
///
|
||||||
|
/// Args:
|
||||||
|
/// distance: Distance traveled.
|
||||||
|
/// time: Time spent traveling.
|
||||||
|
/// acceleration: Rate of change of speed.
|
||||||
|
///
|
||||||
|
/// Returns:
|
||||||
|
/// Speed as distance divided by time.
|
||||||
|
/// """
|
||||||
|
/// return distance / time
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// def calculate_speed(distance: float, time: float) -> float:
|
||||||
|
/// """Calculate speed as distance divided by time.
|
||||||
|
///
|
||||||
|
/// Args:
|
||||||
|
/// distance: Distance traveled.
|
||||||
|
/// time: Time spent traveling.
|
||||||
|
///
|
||||||
|
/// Returns:
|
||||||
|
/// Speed as distance divided by time.
|
||||||
|
/// """
|
||||||
|
/// return distance / time
|
||||||
|
/// ```
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct DocstringExtraneousParameter {
|
||||||
|
id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Violation for DocstringExtraneousParameter {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let DocstringExtraneousParameter { id } = self;
|
||||||
|
format!("Documented parameter `{id}` is not in the function's signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fix_title(&self) -> Option<String> {
|
||||||
|
Some("Remove the extraneous parameter from the docstring".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for functions with `return` statements that do not have "Returns"
|
/// Checks for functions with `return` statements that do not have "Returns"
|
||||||
/// sections in their docstrings.
|
/// sections in their docstrings.
|
||||||
|
|
@ -396,6 +452,19 @@ impl GenericSection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A parameter in a docstring with its text range.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct ParameterEntry<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
range: TextRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ranged for ParameterEntry<'_> {
|
||||||
|
fn range(&self) -> TextRange {
|
||||||
|
self.range
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A "Raises" section in a docstring.
|
/// A "Raises" section in a docstring.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct RaisesSection<'a> {
|
struct RaisesSection<'a> {
|
||||||
|
|
@ -414,17 +483,46 @@ impl<'a> RaisesSection<'a> {
|
||||||
/// a "Raises" section.
|
/// a "Raises" section.
|
||||||
fn from_section(section: &SectionContext<'a>, style: Option<SectionStyle>) -> Self {
|
fn from_section(section: &SectionContext<'a>, style: Option<SectionStyle>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
raised_exceptions: parse_entries(section.following_lines_str(), style),
|
raised_exceptions: parse_raises(section.following_lines_str(), style),
|
||||||
range: section.range(),
|
range: section.range(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An "Args" or "Parameters" section in a docstring.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ParametersSection<'a> {
|
||||||
|
parameters: Vec<ParameterEntry<'a>>,
|
||||||
|
range: TextRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ranged for ParametersSection<'_> {
|
||||||
|
fn range(&self) -> TextRange {
|
||||||
|
self.range
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ParametersSection<'a> {
|
||||||
|
/// Return the parameters for the docstring, or `None` if the docstring does not contain
|
||||||
|
/// an "Args" or "Parameters" section.
|
||||||
|
fn from_section(section: &SectionContext<'a>, style: Option<SectionStyle>) -> Self {
|
||||||
|
Self {
|
||||||
|
parameters: parse_parameters(
|
||||||
|
section.following_lines_str(),
|
||||||
|
section.following_range().start(),
|
||||||
|
style,
|
||||||
|
),
|
||||||
|
range: section.section_name_range(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct DocstringSections<'a> {
|
struct DocstringSections<'a> {
|
||||||
returns: Option<GenericSection>,
|
returns: Option<GenericSection>,
|
||||||
yields: Option<GenericSection>,
|
yields: Option<GenericSection>,
|
||||||
raises: Option<RaisesSection<'a>>,
|
raises: Option<RaisesSection<'a>>,
|
||||||
|
parameters: Option<ParametersSection<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DocstringSections<'a> {
|
impl<'a> DocstringSections<'a> {
|
||||||
|
|
@ -432,6 +530,10 @@ impl<'a> DocstringSections<'a> {
|
||||||
let mut docstring_sections = Self::default();
|
let mut docstring_sections = Self::default();
|
||||||
for section in sections {
|
for section in sections {
|
||||||
match section.kind() {
|
match section.kind() {
|
||||||
|
SectionKind::Args | SectionKind::Arguments | SectionKind::Parameters => {
|
||||||
|
docstring_sections.parameters =
|
||||||
|
Some(ParametersSection::from_section(§ion, style));
|
||||||
|
}
|
||||||
SectionKind::Raises => {
|
SectionKind::Raises => {
|
||||||
docstring_sections.raises = Some(RaisesSection::from_section(§ion, style));
|
docstring_sections.raises = Some(RaisesSection::from_section(§ion, style));
|
||||||
}
|
}
|
||||||
|
|
@ -448,18 +550,22 @@ impl<'a> DocstringSections<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the entries in a "Raises" section of a docstring.
|
/// Parse the entries in a "Parameters" section of a docstring.
|
||||||
///
|
///
|
||||||
/// Attempts to parse using the specified [`SectionStyle`], falling back to the other style if no
|
/// Attempts to parse using the specified [`SectionStyle`], falling back to the other style if no
|
||||||
/// entries are found.
|
/// entries are found.
|
||||||
fn parse_entries(content: &str, style: Option<SectionStyle>) -> Vec<QualifiedName<'_>> {
|
fn parse_parameters(
|
||||||
|
content: &str,
|
||||||
|
content_start: TextSize,
|
||||||
|
style: Option<SectionStyle>,
|
||||||
|
) -> Vec<ParameterEntry<'_>> {
|
||||||
match style {
|
match style {
|
||||||
Some(SectionStyle::Google) => parse_entries_google(content),
|
Some(SectionStyle::Google) => parse_parameters_google(content, content_start),
|
||||||
Some(SectionStyle::Numpy) => parse_entries_numpy(content),
|
Some(SectionStyle::Numpy) => parse_parameters_numpy(content, content_start),
|
||||||
None => {
|
None => {
|
||||||
let entries = parse_entries_google(content);
|
let entries = parse_parameters_google(content, content_start);
|
||||||
if entries.is_empty() {
|
if entries.is_empty() {
|
||||||
parse_entries_numpy(content)
|
parse_parameters_numpy(content, content_start)
|
||||||
} else {
|
} else {
|
||||||
entries
|
entries
|
||||||
}
|
}
|
||||||
|
|
@ -467,14 +573,134 @@ fn parse_entries(content: &str, style: Option<SectionStyle>) -> Vec<QualifiedNam
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses Google-style docstring sections of the form:
|
/// Parses Google-style "Args" sections of the form:
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// Args:
|
||||||
|
/// a (int): The first number to add.
|
||||||
|
/// b (int): The second number to add.
|
||||||
|
/// ```
|
||||||
|
fn parse_parameters_google(content: &str, content_start: TextSize) -> Vec<ParameterEntry<'_>> {
|
||||||
|
let mut entries: Vec<ParameterEntry> = Vec::new();
|
||||||
|
// Find first entry to determine indentation
|
||||||
|
let Some(first_arg) = content.lines().next() else {
|
||||||
|
return entries;
|
||||||
|
};
|
||||||
|
let indentation = &first_arg[..first_arg.len() - first_arg.trim_start().len()];
|
||||||
|
|
||||||
|
let mut current_pos = TextSize::ZERO;
|
||||||
|
for line in content.lines() {
|
||||||
|
let line_start = current_pos;
|
||||||
|
current_pos = content.full_line_end(line_start);
|
||||||
|
|
||||||
|
if let Some(entry) = line.strip_prefix(indentation) {
|
||||||
|
if entry
|
||||||
|
.chars()
|
||||||
|
.next()
|
||||||
|
.is_some_and(|first_char| !first_char.is_whitespace())
|
||||||
|
{
|
||||||
|
let Some((before_colon, _)) = entry.split_once(':') else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if let Some(param) = before_colon.split_whitespace().next() {
|
||||||
|
let param_name = param.trim_start_matches('*');
|
||||||
|
if is_identifier(param_name) {
|
||||||
|
let param_start = line_start + indentation.text_len();
|
||||||
|
let param_end = param_start + param.text_len();
|
||||||
|
|
||||||
|
entries.push(ParameterEntry {
|
||||||
|
name: param_name,
|
||||||
|
range: TextRange::new(
|
||||||
|
content_start + param_start,
|
||||||
|
content_start + param_end,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entries
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses NumPy-style "Parameters" sections of the form:
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// Parameters
|
||||||
|
/// ----------
|
||||||
|
/// a : int
|
||||||
|
/// The first number to add.
|
||||||
|
/// b : int
|
||||||
|
/// The second number to add.
|
||||||
|
/// ```
|
||||||
|
fn parse_parameters_numpy(content: &str, content_start: TextSize) -> Vec<ParameterEntry<'_>> {
|
||||||
|
let mut entries: Vec<ParameterEntry> = Vec::new();
|
||||||
|
let mut lines = content.lines();
|
||||||
|
let Some(dashes) = lines.next() else {
|
||||||
|
return entries;
|
||||||
|
};
|
||||||
|
let indentation = &dashes[..dashes.len() - dashes.trim_start().len()];
|
||||||
|
|
||||||
|
let mut current_pos = content.full_line_end(dashes.text_len());
|
||||||
|
for potential in lines {
|
||||||
|
let line_start = current_pos;
|
||||||
|
current_pos = content.full_line_end(line_start);
|
||||||
|
|
||||||
|
if let Some(entry) = potential.strip_prefix(indentation) {
|
||||||
|
if entry
|
||||||
|
.chars()
|
||||||
|
.next()
|
||||||
|
.is_some_and(|first_char| !first_char.is_whitespace())
|
||||||
|
{
|
||||||
|
if let Some(before_colon) = entry.split(':').next() {
|
||||||
|
let param = before_colon.trim_end();
|
||||||
|
let param_name = param.trim_start_matches('*');
|
||||||
|
if is_identifier(param_name) {
|
||||||
|
let param_start = line_start + indentation.text_len();
|
||||||
|
let param_end = param_start + param.text_len();
|
||||||
|
|
||||||
|
entries.push(ParameterEntry {
|
||||||
|
name: param_name,
|
||||||
|
range: TextRange::new(
|
||||||
|
content_start + param_start,
|
||||||
|
content_start + param_end,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entries
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the entries in a "Raises" section of a docstring.
|
||||||
|
///
|
||||||
|
/// Attempts to parse using the specified [`SectionStyle`], falling back to the other style if no
|
||||||
|
/// entries are found.
|
||||||
|
fn parse_raises(content: &str, style: Option<SectionStyle>) -> Vec<QualifiedName<'_>> {
|
||||||
|
match style {
|
||||||
|
Some(SectionStyle::Google) => parse_raises_google(content),
|
||||||
|
Some(SectionStyle::Numpy) => parse_raises_numpy(content),
|
||||||
|
None => {
|
||||||
|
let entries = parse_raises_google(content);
|
||||||
|
if entries.is_empty() {
|
||||||
|
parse_raises_numpy(content)
|
||||||
|
} else {
|
||||||
|
entries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses Google-style "Raises" section of the form:
|
||||||
///
|
///
|
||||||
/// ```python
|
/// ```python
|
||||||
/// Raises:
|
/// Raises:
|
||||||
/// FasterThanLightError: If speed is greater than the speed of light.
|
/// FasterThanLightError: If speed is greater than the speed of light.
|
||||||
/// DivisionByZero: If attempting to divide by zero.
|
/// DivisionByZero: If attempting to divide by zero.
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_entries_google(content: &str) -> Vec<QualifiedName<'_>> {
|
fn parse_raises_google(content: &str) -> Vec<QualifiedName<'_>> {
|
||||||
let mut entries: Vec<QualifiedName> = Vec::new();
|
let mut entries: Vec<QualifiedName> = Vec::new();
|
||||||
for potential in content.lines() {
|
for potential in content.lines() {
|
||||||
let Some(colon_idx) = potential.find(':') else {
|
let Some(colon_idx) = potential.find(':') else {
|
||||||
|
|
@ -486,7 +712,7 @@ fn parse_entries_google(content: &str) -> Vec<QualifiedName<'_>> {
|
||||||
entries
|
entries
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses NumPy-style docstring sections of the form:
|
/// Parses NumPy-style "Raises" section of the form:
|
||||||
///
|
///
|
||||||
/// ```python
|
/// ```python
|
||||||
/// Raises
|
/// Raises
|
||||||
|
|
@ -496,7 +722,7 @@ fn parse_entries_google(content: &str) -> Vec<QualifiedName<'_>> {
|
||||||
/// DivisionByZero
|
/// DivisionByZero
|
||||||
/// If attempting to divide by zero.
|
/// If attempting to divide by zero.
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_entries_numpy(content: &str) -> Vec<QualifiedName<'_>> {
|
fn parse_raises_numpy(content: &str) -> Vec<QualifiedName<'_>> {
|
||||||
let mut entries: Vec<QualifiedName> = Vec::new();
|
let mut entries: Vec<QualifiedName> = Vec::new();
|
||||||
let mut lines = content.lines();
|
let mut lines = content.lines();
|
||||||
let Some(dashes) = lines.next() else {
|
let Some(dashes) = lines.next() else {
|
||||||
|
|
@ -867,6 +1093,17 @@ fn is_generator_function_annotated_as_returning_none(
|
||||||
.is_some_and(GeneratorOrIteratorArguments::indicates_none_returned)
|
.is_some_and(GeneratorOrIteratorArguments::indicates_none_returned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parameters_from_signature<'a>(docstring: &'a Docstring) -> Vec<&'a str> {
|
||||||
|
let mut parameters = Vec::new();
|
||||||
|
let Some(function) = docstring.definition.as_function_def() else {
|
||||||
|
return parameters;
|
||||||
|
};
|
||||||
|
for param in &function.parameters {
|
||||||
|
parameters.push(param.name());
|
||||||
|
}
|
||||||
|
parameters
|
||||||
|
}
|
||||||
|
|
||||||
fn is_one_line(docstring: &Docstring) -> bool {
|
fn is_one_line(docstring: &Docstring) -> bool {
|
||||||
let mut non_empty_line_count = 0;
|
let mut non_empty_line_count = 0;
|
||||||
for line in NewlineWithTrailingNewline::from(docstring.body().as_str()) {
|
for line in NewlineWithTrailingNewline::from(docstring.body().as_str()) {
|
||||||
|
|
@ -880,7 +1117,7 @@ fn is_one_line(docstring: &Docstring) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DOC201, DOC202, DOC402, DOC403, DOC501, DOC502
|
/// DOC102, DOC201, DOC202, DOC402, DOC403, DOC501, DOC502
|
||||||
pub(crate) fn check_docstring(
|
pub(crate) fn check_docstring(
|
||||||
checker: &Checker,
|
checker: &Checker,
|
||||||
definition: &Definition,
|
definition: &Definition,
|
||||||
|
|
@ -920,6 +1157,8 @@ pub(crate) fn check_docstring(
|
||||||
visitor.finish()
|
visitor.finish()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let signature_parameters = parameters_from_signature(docstring);
|
||||||
|
|
||||||
// DOC201
|
// DOC201
|
||||||
if checker.is_rule_enabled(Rule::DocstringMissingReturns) {
|
if checker.is_rule_enabled(Rule::DocstringMissingReturns) {
|
||||||
if should_document_returns(function_def)
|
if should_document_returns(function_def)
|
||||||
|
|
@ -1008,6 +1247,25 @@ pub(crate) fn check_docstring(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DOC102
|
||||||
|
if checker.is_rule_enabled(Rule::DocstringExtraneousParameter) {
|
||||||
|
// Don't report extraneous parameters if the signature defines *args or **kwargs
|
||||||
|
if function_def.parameters.vararg.is_none() && function_def.parameters.kwarg.is_none() {
|
||||||
|
if let Some(docstring_params) = docstring_sections.parameters {
|
||||||
|
for docstring_param in &docstring_params.parameters {
|
||||||
|
if !signature_parameters.contains(&docstring_param.name) {
|
||||||
|
checker.report_diagnostic(
|
||||||
|
DocstringExtraneousParameter {
|
||||||
|
id: docstring_param.name.to_string(),
|
||||||
|
},
|
||||||
|
docstring_param.range(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid applying "extraneous" rules to abstract methods. An abstract method's docstring _could_
|
// Avoid applying "extraneous" rules to abstract methods. An abstract method's docstring _could_
|
||||||
// document that it raises an exception without including the exception in the implementation.
|
// document that it raises an exception without including the exception in the implementation.
|
||||||
if !visibility::is_abstract(&function_def.decorator_list, semantic) {
|
if !visibility::is_abstract(&function_def.decorator_list, semantic) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pydoclint/mod.rs
|
||||||
|
---
|
||||||
|
DOC102 Documented parameter `a` is not in the function's signature
|
||||||
|
--> DOC102_google.py:7:9
|
||||||
|
|
|
||||||
|
6 | Args:
|
||||||
|
7 | a (int): The first number to add.
|
||||||
|
| ^
|
||||||
|
8 | b (int): The second number to add.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `multiplier` is not in the function's signature
|
||||||
|
--> DOC102_google.py:23:9
|
||||||
|
|
|
||||||
|
21 | Args:
|
||||||
|
22 | lst (list of int): A list of integers.
|
||||||
|
23 | multiplier (int): The multiplier for each element in the list.
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
24 |
|
||||||
|
25 | Returns:
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `numbers` is not in the function's signature
|
||||||
|
--> DOC102_google.py:37:9
|
||||||
|
|
|
||||||
|
36 | Args:
|
||||||
|
37 | numbers (list of int): A list of integers to search through.
|
||||||
|
| ^^^^^^^
|
||||||
|
38 |
|
||||||
|
39 | Returns:
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `name` is not in the function's signature
|
||||||
|
--> DOC102_google.py:51:9
|
||||||
|
|
|
||||||
|
50 | Args:
|
||||||
|
51 | name (str): The name of the user.
|
||||||
|
| ^^^^
|
||||||
|
52 | age (int): The age of the user.
|
||||||
|
53 | email (str): The user's email address.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `age` is not in the function's signature
|
||||||
|
--> DOC102_google.py:52:9
|
||||||
|
|
|
||||||
|
50 | Args:
|
||||||
|
51 | name (str): The name of the user.
|
||||||
|
52 | age (int): The age of the user.
|
||||||
|
| ^^^
|
||||||
|
53 | email (str): The user's email address.
|
||||||
|
54 | location (str): The location of the user.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `email` is not in the function's signature
|
||||||
|
--> DOC102_google.py:53:9
|
||||||
|
|
|
||||||
|
51 | name (str): The name of the user.
|
||||||
|
52 | age (int): The age of the user.
|
||||||
|
53 | email (str): The user's email address.
|
||||||
|
| ^^^^^
|
||||||
|
54 | location (str): The location of the user.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `tax_rate` is not in the function's signature
|
||||||
|
--> DOC102_google.py:74:9
|
||||||
|
|
|
||||||
|
72 | Args:
|
||||||
|
73 | item_prices (list of float): A list of prices for each item.
|
||||||
|
74 | tax_rate (float): The tax rate to apply.
|
||||||
|
| ^^^^^^^^
|
||||||
|
75 | discount (float): The discount to subtract from the total.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `to_address` is not in the function's signature
|
||||||
|
--> DOC102_google.py:94:9
|
||||||
|
|
|
||||||
|
92 | subject (str): The subject of the email.
|
||||||
|
93 | body (str): The content of the email.
|
||||||
|
94 | to_address (str): The recipient's email address.
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
95 | cc_address (str, optional): The email address for CC. Defaults to None.
|
||||||
|
96 | bcc_address (str, optional): The email address for BCC. Defaults to None.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `cc_address` is not in the function's signature
|
||||||
|
--> DOC102_google.py:95:9
|
||||||
|
|
|
||||||
|
93 | body (str): The content of the email.
|
||||||
|
94 | to_address (str): The recipient's email address.
|
||||||
|
95 | cc_address (str, optional): The email address for CC. Defaults to None.
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
96 | bcc_address (str, optional): The email address for BCC. Defaults to None.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `items` is not in the function's signature
|
||||||
|
--> DOC102_google.py:126:9
|
||||||
|
|
|
||||||
|
124 | Args:
|
||||||
|
125 | order_id (int): The unique identifier for the order.
|
||||||
|
126 | *items (str): Variable length argument list of items in the order.
|
||||||
|
| ^^^^^^
|
||||||
|
127 | **details (dict): Additional details such as shipping method and address.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `details` is not in the function's signature
|
||||||
|
--> DOC102_google.py:127:9
|
||||||
|
|
|
||||||
|
125 | order_id (int): The unique identifier for the order.
|
||||||
|
126 | *items (str): Variable length argument list of items in the order.
|
||||||
|
127 | **details (dict): Additional details such as shipping method and address.
|
||||||
|
| ^^^^^^^^^
|
||||||
|
128 |
|
||||||
|
129 | Returns:
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `value` is not in the function's signature
|
||||||
|
--> DOC102_google.py:150:13
|
||||||
|
|
|
||||||
|
149 | Args:
|
||||||
|
150 | value (int, optional): The initial value of the calculator. Defaults to 0.
|
||||||
|
| ^^^^^
|
||||||
|
151 | """
|
||||||
|
152 | self.value = value
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `number` is not in the function's signature
|
||||||
|
--> DOC102_google.py:160:13
|
||||||
|
|
|
||||||
|
159 | Args:
|
||||||
|
160 | number (int or float): The number to add to the current value.
|
||||||
|
| ^^^^^^
|
||||||
|
161 |
|
||||||
|
162 | Returns:
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `value_str` is not in the function's signature
|
||||||
|
--> DOC102_google.py:175:13
|
||||||
|
|
|
||||||
|
174 | Args:
|
||||||
|
175 | value_str (str): The string representing the initial value.
|
||||||
|
| ^^^^^^^^^
|
||||||
|
176 |
|
||||||
|
177 | Returns:
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `number` is not in the function's signature
|
||||||
|
--> DOC102_google.py:190:13
|
||||||
|
|
|
||||||
|
189 | Args:
|
||||||
|
190 | number (any): The value to check.
|
||||||
|
| ^^^^^^
|
||||||
|
191 |
|
||||||
|
192 | Returns:
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `a` is not in the function's signature
|
||||||
|
--> DOC102_google.py:258:9
|
||||||
|
|
|
||||||
|
257 | Args:
|
||||||
|
258 | a: The first number to add.
|
||||||
|
| ^
|
||||||
|
259 | b: The second number to add.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pydoclint/mod.rs
|
||||||
|
---
|
||||||
|
DOC102 Documented parameter `a` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:8:5
|
||||||
|
|
|
||||||
|
6 | Parameters
|
||||||
|
7 | ----------
|
||||||
|
8 | a : int
|
||||||
|
| ^
|
||||||
|
9 | The first number to add.
|
||||||
|
10 | b : int
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `multiplier` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:30:5
|
||||||
|
|
|
||||||
|
28 | lst : list of int
|
||||||
|
29 | A list of integers.
|
||||||
|
30 | multiplier : int
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
31 | The multiplier for each element in the list.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `numbers` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:48:5
|
||||||
|
|
|
||||||
|
46 | Parameters
|
||||||
|
47 | ----------
|
||||||
|
48 | numbers : list of int
|
||||||
|
| ^^^^^^^
|
||||||
|
49 | A list of integers to search through.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `name` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:66:5
|
||||||
|
|
|
||||||
|
64 | Parameters
|
||||||
|
65 | ----------
|
||||||
|
66 | name : str
|
||||||
|
| ^^^^
|
||||||
|
67 | The name of the user.
|
||||||
|
68 | age : int
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `age` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:68:5
|
||||||
|
|
|
||||||
|
66 | name : str
|
||||||
|
67 | The name of the user.
|
||||||
|
68 | age : int
|
||||||
|
| ^^^
|
||||||
|
69 | The age of the user.
|
||||||
|
70 | email : str
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `email` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:70:5
|
||||||
|
|
|
||||||
|
68 | age : int
|
||||||
|
69 | The age of the user.
|
||||||
|
70 | email : str
|
||||||
|
| ^^^^^
|
||||||
|
71 | The user's email address.
|
||||||
|
72 | location : str, optional
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `tax_rate` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:97:5
|
||||||
|
|
|
||||||
|
95 | item_prices : list of float
|
||||||
|
96 | A list of prices for each item.
|
||||||
|
97 | tax_rate : float
|
||||||
|
| ^^^^^^^^
|
||||||
|
98 | The tax rate to apply.
|
||||||
|
99 | discount : float
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `to_address` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:124:5
|
||||||
|
|
|
||||||
|
122 | body : str
|
||||||
|
123 | The content of the email.
|
||||||
|
124 | to_address : str
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
125 | The recipient's email address.
|
||||||
|
126 | cc_address : str, optional
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `cc_address` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:126:5
|
||||||
|
|
|
||||||
|
124 | to_address : str
|
||||||
|
125 | The recipient's email address.
|
||||||
|
126 | cc_address : str, optional
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
127 | The email address for CC, by default None.
|
||||||
|
128 | bcc_address : str, optional
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `items` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:168:5
|
||||||
|
|
|
||||||
|
166 | order_id : int
|
||||||
|
167 | The unique identifier for the order.
|
||||||
|
168 | *items : str
|
||||||
|
| ^^^^^^
|
||||||
|
169 | Variable length argument list of items in the order.
|
||||||
|
170 | **details : dict
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `details` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:170:5
|
||||||
|
|
|
||||||
|
168 | *items : str
|
||||||
|
169 | Variable length argument list of items in the order.
|
||||||
|
170 | **details : dict
|
||||||
|
| ^^^^^^^^^
|
||||||
|
171 | Additional details such as shipping method and address.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `value` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:197:9
|
||||||
|
|
|
||||||
|
195 | Parameters
|
||||||
|
196 | ----------
|
||||||
|
197 | value : int, optional
|
||||||
|
| ^^^^^
|
||||||
|
198 | The initial value of the calculator, by default 0.
|
||||||
|
199 | """
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `number` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:209:9
|
||||||
|
|
|
||||||
|
207 | Parameters
|
||||||
|
208 | ----------
|
||||||
|
209 | number : int or float
|
||||||
|
| ^^^^^^
|
||||||
|
210 | The first number to add.
|
||||||
|
211 | number2 : int or float
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `value_str` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:230:9
|
||||||
|
|
|
||||||
|
228 | Parameters
|
||||||
|
229 | ----------
|
||||||
|
230 | value_str : str
|
||||||
|
| ^^^^^^^^^
|
||||||
|
231 | The string representing the initial value.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `number` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:249:9
|
||||||
|
|
|
||||||
|
247 | Parameters
|
||||||
|
248 | ----------
|
||||||
|
249 | number : any
|
||||||
|
| ^^^^^^
|
||||||
|
250 | The value to check.
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
||||||
|
DOC102 Documented parameter `a` is not in the function's signature
|
||||||
|
--> DOC102_numpy.py:300:5
|
||||||
|
|
|
||||||
|
298 | Parameters
|
||||||
|
299 | ----------
|
||||||
|
300 | a
|
||||||
|
| ^
|
||||||
|
301 | The first number to add.
|
||||||
|
302 | b
|
||||||
|
|
|
||||||
|
help: Remove the extraneous parameter from the docstring
|
||||||
|
|
@ -3186,6 +3186,9 @@
|
||||||
"DJ012",
|
"DJ012",
|
||||||
"DJ013",
|
"DJ013",
|
||||||
"DOC",
|
"DOC",
|
||||||
|
"DOC1",
|
||||||
|
"DOC10",
|
||||||
|
"DOC102",
|
||||||
"DOC2",
|
"DOC2",
|
||||||
"DOC20",
|
"DOC20",
|
||||||
"DOC201",
|
"DOC201",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue