mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 05:45:24 +00:00
[pydocstyle-D405
] Allow using parameters
as a sub-section header (#9894)
## Summary This review contains a fix for [D405](https://docs.astral.sh/ruff/rules/capitalize-section-name/) (capitalize-section-name) The problem is that Ruff considers the sub-section header as a normal section if it has the same name as some section name. For instance, a function/method has an argument named "parameters". This only applies if you use Numpy style docstring. See: [ISSUE](https://github.com/astral-sh/ruff/issues/9806) The following will not raise D405 after the fix: ```python def some_function(parameters: list[str]): """A function with a parameters parameter Parameters ---------- parameters: A list of string parameters """ ... ``` ## Test Plan ```bash cargo test ``` --------- Co-authored-by: Mikko Leppänen <mikko.leppanen@vaisala.com> Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
parent
49fe1b85f2
commit
b4f2882b72
7 changed files with 235 additions and 4 deletions
|
@ -562,3 +562,46 @@ def titlecase_sub_section_header():
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_method_should_be_correctly_capitalized(parameters: list[str], other_parameters: dict[str, str]): # noqa: D213
|
||||||
|
"""Test parameters and attributes sections are capitalized correctly.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
parameters:
|
||||||
|
A list of string parameters
|
||||||
|
other_parameters:
|
||||||
|
A dictionary of string attributes
|
||||||
|
|
||||||
|
Other Parameters
|
||||||
|
----------
|
||||||
|
other_parameters:
|
||||||
|
A dictionary of string attributes
|
||||||
|
parameters:
|
||||||
|
A list of string parameters
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_lowercase_sub_section_header_should_be_valid(parameters: list[str], value: int): # noqa: D213
|
||||||
|
"""Test that lower case subsection header is valid even if it has the same name as section kind.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
----------
|
||||||
|
parameters:
|
||||||
|
A list of string parameters
|
||||||
|
value:
|
||||||
|
Some value
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_lowercase_sub_section_header_different_kind(returns: int):
|
||||||
|
"""Test that lower case subsection header is valid even if it is of a different kind.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-‐-----------------
|
||||||
|
returns:
|
||||||
|
some value
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
|
@ -130,6 +130,34 @@ impl SectionKind {
|
||||||
Self::Yields => "Yields",
|
Self::Yields => "Yields",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if a section can contain subsections, as in:
|
||||||
|
/// ```python
|
||||||
|
/// Yields
|
||||||
|
/// ------
|
||||||
|
/// int
|
||||||
|
/// Description of the anonymous integer return value.
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// For NumPy, see: <https://numpydoc.readthedocs.io/en/latest/format.html>
|
||||||
|
///
|
||||||
|
/// For Google, see: <https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings>
|
||||||
|
pub(crate) fn has_subsections(self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
Self::Args
|
||||||
|
| Self::Arguments
|
||||||
|
| Self::OtherArgs
|
||||||
|
| Self::OtherParameters
|
||||||
|
| Self::OtherParams
|
||||||
|
| Self::Parameters
|
||||||
|
| Self::Raises
|
||||||
|
| Self::Returns
|
||||||
|
| Self::SeeAlso
|
||||||
|
| Self::Warns
|
||||||
|
| Self::Yields
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct SectionContexts<'a> {
|
pub(crate) struct SectionContexts<'a> {
|
||||||
|
@ -462,13 +490,54 @@ fn is_docstring_section(
|
||||||
// args: The arguments to the function.
|
// args: The arguments to the function.
|
||||||
// """
|
// """
|
||||||
// ```
|
// ```
|
||||||
|
// Or `parameters` in:
|
||||||
|
// ```python
|
||||||
|
// def func(parameters: tuple[int]):
|
||||||
|
// """Toggle the gizmo.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// -----
|
||||||
|
// parameters:
|
||||||
|
// The arguments to the function.
|
||||||
|
// """
|
||||||
|
// ```
|
||||||
// However, if the header is an _exact_ match (like `Returns:`, as opposed to `returns:`), then
|
// However, if the header is an _exact_ match (like `Returns:`, as opposed to `returns:`), then
|
||||||
// continue to treat it as a section header.
|
// continue to treat it as a section header.
|
||||||
if let Some(previous_section) = previous_section {
|
if section_kind.has_subsections() {
|
||||||
if previous_section.indent_size < indent_size {
|
if let Some(previous_section) = previous_section {
|
||||||
let verbatim = &line[TextRange::at(indent_size, section_name_size)];
|
let verbatim = &line[TextRange::at(indent_size, section_name_size)];
|
||||||
if section_kind.as_str() != verbatim {
|
|
||||||
return false;
|
// If the section is more deeply indented, assume it's a subsection, as in:
|
||||||
|
// ```python
|
||||||
|
// def func(args: tuple[int]):
|
||||||
|
// """Toggle the gizmo.
|
||||||
|
//
|
||||||
|
// Args:
|
||||||
|
// args: The arguments to the function.
|
||||||
|
// """
|
||||||
|
// ```
|
||||||
|
if previous_section.indent_size < indent_size {
|
||||||
|
if section_kind.as_str() != verbatim {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the section isn't underlined, and isn't title-cased, assume it's a subsection,
|
||||||
|
// as in:
|
||||||
|
// ```python
|
||||||
|
// def func(parameters: tuple[int]):
|
||||||
|
// """Toggle the gizmo.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// -----
|
||||||
|
// parameters:
|
||||||
|
// The arguments to the function.
|
||||||
|
// """
|
||||||
|
// ```
|
||||||
|
if !next_line_is_underline && verbatim.chars().next().is_some_and(char::is_lowercase) {
|
||||||
|
if section_kind.as_str() != verbatim {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,5 +49,7 @@ sections.py:558:5: D214 [*] Section is over-indented ("Returns")
|
||||||
563 |- Returns:
|
563 |- Returns:
|
||||||
563 |+ Returns:
|
563 |+ Returns:
|
||||||
564 564 | """
|
564 564 | """
|
||||||
|
565 565 |
|
||||||
|
566 566 |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,4 +61,31 @@ sections.py:216:5: D406 [*] Section name should end with a newline ("Raises")
|
||||||
229 229 |
|
229 229 |
|
||||||
230 230 | """
|
230 230 | """
|
||||||
|
|
||||||
|
sections.py:588:5: D406 [*] Section name should end with a newline ("Parameters")
|
||||||
|
|
|
||||||
|
587 | def test_lowercase_sub_section_header_should_be_valid(parameters: list[str], value: int): # noqa: D213
|
||||||
|
588 | """Test that lower case subsection header is valid even if it has the same name as section kind.
|
||||||
|
| _____^
|
||||||
|
589 | |
|
||||||
|
590 | | Parameters:
|
||||||
|
591 | | ----------
|
||||||
|
592 | | parameters:
|
||||||
|
593 | | A list of string parameters
|
||||||
|
594 | | value:
|
||||||
|
595 | | Some value
|
||||||
|
596 | | """
|
||||||
|
| |_______^ D406
|
||||||
|
|
|
||||||
|
= help: Add newline after "Parameters"
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
587 587 | def test_lowercase_sub_section_header_should_be_valid(parameters: list[str], value: int): # noqa: D213
|
||||||
|
588 588 | """Test that lower case subsection header is valid even if it has the same name as section kind.
|
||||||
|
589 589 |
|
||||||
|
590 |- Parameters:
|
||||||
|
590 |+ Parameters
|
||||||
|
591 591 | ----------
|
||||||
|
592 592 | parameters:
|
||||||
|
593 593 | A list of string parameters
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -567,5 +567,32 @@ sections.py:558:5: D407 [*] Missing dashed underline after section ("Returns")
|
||||||
563 563 | Returns:
|
563 563 | Returns:
|
||||||
564 |+ -------
|
564 |+ -------
|
||||||
564 565 | """
|
564 565 | """
|
||||||
|
565 566 |
|
||||||
|
566 567 |
|
||||||
|
|
||||||
|
sections.py:600:4: D407 [*] Missing dashed underline after section ("Parameters")
|
||||||
|
|
|
||||||
|
599 | def test_lowercase_sub_section_header_different_kind(returns: int):
|
||||||
|
600 | """Test that lower case subsection header is valid even if it is of a different kind.
|
||||||
|
| ____^
|
||||||
|
601 | |
|
||||||
|
602 | | Parameters
|
||||||
|
603 | | -‐-----------------
|
||||||
|
604 | | returns:
|
||||||
|
605 | | some value
|
||||||
|
606 | |
|
||||||
|
607 | | """
|
||||||
|
| |______^ D407
|
||||||
|
|
|
||||||
|
= help: Add dashed line under "Parameters"
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
600 600 | """Test that lower case subsection header is valid even if it is of a different kind.
|
||||||
|
601 601 |
|
||||||
|
602 602 | Parameters
|
||||||
|
603 |+ ----------
|
||||||
|
603 604 | -‐-----------------
|
||||||
|
604 605 | returns:
|
||||||
|
605 606 | some value
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,4 +61,39 @@ sections.py:216:5: D409 [*] Section underline should match the length of its nam
|
||||||
227 227 | Raises:
|
227 227 | Raises:
|
||||||
228 228 | My attention.
|
228 228 | My attention.
|
||||||
|
|
||||||
|
sections.py:568:5: D409 [*] Section underline should match the length of its name ("Other Parameters")
|
||||||
|
|
|
||||||
|
567 | def test_method_should_be_correctly_capitalized(parameters: list[str], other_parameters: dict[str, str]): # noqa: D213
|
||||||
|
568 | """Test parameters and attributes sections are capitalized correctly.
|
||||||
|
| _____^
|
||||||
|
569 | |
|
||||||
|
570 | | Parameters
|
||||||
|
571 | | ----------
|
||||||
|
572 | | parameters:
|
||||||
|
573 | | A list of string parameters
|
||||||
|
574 | | other_parameters:
|
||||||
|
575 | | A dictionary of string attributes
|
||||||
|
576 | |
|
||||||
|
577 | | Other Parameters
|
||||||
|
578 | | ----------
|
||||||
|
579 | | other_parameters:
|
||||||
|
580 | | A dictionary of string attributes
|
||||||
|
581 | | parameters:
|
||||||
|
582 | | A list of string parameters
|
||||||
|
583 | |
|
||||||
|
584 | | """
|
||||||
|
| |_______^ D409
|
||||||
|
|
|
||||||
|
= help: Adjust underline length to match "Other Parameters"
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
575 575 | A dictionary of string attributes
|
||||||
|
576 576 |
|
||||||
|
577 577 | Other Parameters
|
||||||
|
578 |- ----------
|
||||||
|
578 |+ ----------------
|
||||||
|
579 579 | other_parameters:
|
||||||
|
580 580 | A dictionary of string attributes
|
||||||
|
581 581 | parameters:
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -161,5 +161,33 @@ sections.py:558:5: D413 [*] Missing blank line after last section ("Returns")
|
||||||
563 563 | Returns:
|
563 563 | Returns:
|
||||||
564 |+
|
564 |+
|
||||||
564 565 | """
|
564 565 | """
|
||||||
|
565 566 |
|
||||||
|
566 567 |
|
||||||
|
|
||||||
|
sections.py:588:5: D413 [*] Missing blank line after last section ("Parameters")
|
||||||
|
|
|
||||||
|
587 | def test_lowercase_sub_section_header_should_be_valid(parameters: list[str], value: int): # noqa: D213
|
||||||
|
588 | """Test that lower case subsection header is valid even if it has the same name as section kind.
|
||||||
|
| _____^
|
||||||
|
589 | |
|
||||||
|
590 | | Parameters:
|
||||||
|
591 | | ----------
|
||||||
|
592 | | parameters:
|
||||||
|
593 | | A list of string parameters
|
||||||
|
594 | | value:
|
||||||
|
595 | | Some value
|
||||||
|
596 | | """
|
||||||
|
| |_______^ D413
|
||||||
|
|
|
||||||
|
= help: Add blank line after "Parameters"
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
593 593 | A list of string parameters
|
||||||
|
594 594 | value:
|
||||||
|
595 595 | Some value
|
||||||
|
596 |+
|
||||||
|
596 597 | """
|
||||||
|
597 598 |
|
||||||
|
598 599 |
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue