diff --git a/crates/ruff_linter/resources/test/fixtures/pydoclint/DOC501.py b/crates/ruff_linter/resources/test/fixtures/pydoclint/DOC501.py index fd3a371080..721ca6a6b1 100644 --- a/crates/ruff_linter/resources/test/fixtures/pydoclint/DOC501.py +++ b/crates/ruff_linter/resources/test/fixtures/pydoclint/DOC501.py @@ -6,3 +6,15 @@ def parse_bool(x, default=_parse_bool_sentinel): `ValueError` ê>>> all(parse_bool(x) for x in [True, "yes", "Yes", "true", "True", "on", "ON", "1", 1]) """ + + +# https://github.com/astral-sh/ruff/issues/12647 +def get_bar(self) -> str: + """Print and return bar. + + Raises: + ValueError: bar is not bar. + + Returns: + str: bar value. + """ diff --git a/crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs b/crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs index 5e85018b76..a3f8c14dec 100644 --- a/crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs +++ b/crates/ruff_linter/src/rules/pydoclint/rules/check_docstring.rs @@ -377,7 +377,7 @@ impl Ranged for RaisesSection<'_> { impl<'a> RaisesSection<'a> { /// Return the raised exceptions for the docstring, or `None` if the docstring does not contain /// a `Raises` section. - fn from_section(section: &SectionContext<'a>, style: SectionStyle) -> Self { + fn from_section(section: &SectionContext<'a>, style: Option) -> Self { Self { raised_exceptions: parse_entries(section.following_lines_str(), style), range: section.range(), @@ -393,7 +393,7 @@ struct DocstringSections<'a> { } impl<'a> DocstringSections<'a> { - fn from_sections(sections: &'a SectionContexts, style: SectionStyle) -> Self { + fn from_sections(sections: &'a SectionContexts, style: Option) -> Self { let mut docstring_sections = Self::default(); for section in sections { match section.kind() { @@ -414,10 +414,21 @@ impl<'a> DocstringSections<'a> { } /// Parse the entries in a `Raises` section of a docstring. -fn parse_entries(content: &str, style: SectionStyle) -> Vec { +/// +/// Attempts to parse using the specified [`SectionStyle`], falling back to the other style if no +/// entries are found. +fn parse_entries(content: &str, style: Option) -> Vec { match style { - SectionStyle::Google => parse_entries_google(content), - SectionStyle::Numpy => parse_entries_numpy(content), + Some(SectionStyle::Google) => parse_entries_google(content), + Some(SectionStyle::Numpy) => parse_entries_numpy(content), + None => { + let entries = parse_entries_google(content); + if entries.is_empty() { + parse_entries_numpy(content) + } else { + entries + } + } } } @@ -660,12 +671,12 @@ pub(crate) fn check_docstring( // Prioritize the specified convention over the determined style. let docstring_sections = match convention { Some(Convention::Google) => { - DocstringSections::from_sections(section_contexts, SectionStyle::Google) + DocstringSections::from_sections(section_contexts, Some(SectionStyle::Google)) } Some(Convention::Numpy) => { - DocstringSections::from_sections(section_contexts, SectionStyle::Numpy) + DocstringSections::from_sections(section_contexts, Some(SectionStyle::Numpy)) } - _ => DocstringSections::from_sections(section_contexts, section_contexts.style()), + Some(Convention::Pep257) | None => DocstringSections::from_sections(section_contexts, None), }; let body_entries = {