mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 15:15:33 +00:00
Implement D404 and D418 for pydocstyle (#409)
This commit is contained in:
parent
e08e1caf71
commit
77055faab6
8 changed files with 176 additions and 41 deletions
|
@ -217,7 +217,7 @@ ruff also implements some of the most popular Flake8 plugins natively, including
|
||||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||||
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/) (12/16)
|
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/) (12/16)
|
||||||
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (3/32)
|
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (3/32)
|
||||||
- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) (25/48)
|
- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) (27/48)
|
||||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (8/34)
|
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (8/34)
|
||||||
|
|
||||||
Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis Flake8:
|
Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis Flake8:
|
||||||
|
@ -323,7 +323,9 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||||
| D400 | EndsInPeriod | First line should end with a period | | |
|
| D400 | EndsInPeriod | First line should end with a period | | |
|
||||||
| D402 | NoSignature | First line should not be the function's 'signature' | | |
|
| D402 | NoSignature | First line should not be the function's 'signature' | | |
|
||||||
| D403 | FirstLineCapitalized | First word of the first line should be properly capitalized | | |
|
| D403 | FirstLineCapitalized | First word of the first line should be properly capitalized | | |
|
||||||
|
| D404 | NoThisPrefix | First word of the docstring should not be `This` | | |
|
||||||
| D415 | EndsInPunctuation | First line should end with a period, question mark, or exclamation point | | |
|
| D415 | EndsInPunctuation | First line should end with a period, question mark, or exclamation point | | |
|
||||||
|
| D418 | SkipDocstring | Function decorated with @overload shouldn't contain a docstring | | |
|
||||||
| D419 | NonEmpty | Docstring is empty | | |
|
| D419 | NonEmpty | Docstring is empty | | |
|
||||||
| D201 | NoBlankLineBeforeFunction | No blank lines allowed before function docstring (found 1) | | |
|
| D201 | NoBlankLineBeforeFunction | No blank lines allowed before function docstring (found 1) | | |
|
||||||
| D202 | NoBlankLineAfterFunction | No blank lines allowed after function docstring (found 1) | | |
|
| D202 | NoBlankLineAfterFunction | No blank lines allowed after function docstring (found 1) | | |
|
||||||
|
|
|
@ -1955,9 +1955,15 @@ impl<'a> Checker<'a> {
|
||||||
if self.settings.enabled.contains(&CheckCode::D403) {
|
if self.settings.enabled.contains(&CheckCode::D403) {
|
||||||
docstrings::capitalized(self, &docstring);
|
docstrings::capitalized(self, &docstring);
|
||||||
}
|
}
|
||||||
|
if self.settings.enabled.contains(&CheckCode::D404) {
|
||||||
|
docstrings::starts_with_this(self, &docstring);
|
||||||
|
}
|
||||||
if self.settings.enabled.contains(&CheckCode::D415) {
|
if self.settings.enabled.contains(&CheckCode::D415) {
|
||||||
docstrings::ends_with_punctuation(self, &docstring);
|
docstrings::ends_with_punctuation(self, &docstring);
|
||||||
}
|
}
|
||||||
|
if self.settings.enabled.contains(&CheckCode::D418) {
|
||||||
|
docstrings::if_needed(self, &docstring);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,9 @@ pub enum CheckCode {
|
||||||
D400,
|
D400,
|
||||||
D402,
|
D402,
|
||||||
D403,
|
D403,
|
||||||
|
D404,
|
||||||
D415,
|
D415,
|
||||||
|
D418,
|
||||||
D419,
|
D419,
|
||||||
D201,
|
D201,
|
||||||
D202,
|
D202,
|
||||||
|
@ -279,27 +281,29 @@ pub enum CheckKind {
|
||||||
EndsInPunctuation,
|
EndsInPunctuation,
|
||||||
FirstLineCapitalized,
|
FirstLineCapitalized,
|
||||||
FitsOnOneLine,
|
FitsOnOneLine,
|
||||||
|
MagicMethod,
|
||||||
MultiLineSummaryFirstLine,
|
MultiLineSummaryFirstLine,
|
||||||
MultiLineSummarySecondLine,
|
MultiLineSummarySecondLine,
|
||||||
NewLineAfterLastParagraph,
|
NewLineAfterLastParagraph,
|
||||||
NoBlankLineAfterSummary,
|
|
||||||
NoSurroundingWhitespace,
|
|
||||||
NonEmpty,
|
|
||||||
UsesTripleQuotes,
|
|
||||||
NoSignature,
|
|
||||||
NoBlankLineBeforeFunction(usize),
|
|
||||||
NoBlankLineAfterFunction(usize),
|
NoBlankLineAfterFunction(usize),
|
||||||
|
NoBlankLineAfterSummary,
|
||||||
NoBlankLineBeforeClass(usize),
|
NoBlankLineBeforeClass(usize),
|
||||||
OneBlankLineBeforeClass(usize),
|
NoBlankLineBeforeFunction(usize),
|
||||||
|
NoSignature,
|
||||||
|
NoSurroundingWhitespace,
|
||||||
|
NoThisPrefix,
|
||||||
|
NonEmpty,
|
||||||
OneBlankLineAfterClass(usize),
|
OneBlankLineAfterClass(usize),
|
||||||
PublicModule,
|
OneBlankLineBeforeClass(usize),
|
||||||
PublicClass,
|
PublicClass,
|
||||||
PublicMethod,
|
|
||||||
PublicFunction,
|
PublicFunction,
|
||||||
PublicPackage,
|
|
||||||
MagicMethod,
|
|
||||||
PublicNestedClass,
|
|
||||||
PublicInit,
|
PublicInit,
|
||||||
|
PublicMethod,
|
||||||
|
PublicModule,
|
||||||
|
PublicNestedClass,
|
||||||
|
PublicPackage,
|
||||||
|
SkipDocstring,
|
||||||
|
UsesTripleQuotes,
|
||||||
// Meta
|
// Meta
|
||||||
UnusedNOQA(Option<Vec<String>>),
|
UnusedNOQA(Option<Vec<String>>),
|
||||||
}
|
}
|
||||||
|
@ -422,22 +426,24 @@ impl CheckCode {
|
||||||
CheckCode::D106 => CheckKind::PublicNestedClass,
|
CheckCode::D106 => CheckKind::PublicNestedClass,
|
||||||
CheckCode::D107 => CheckKind::PublicInit,
|
CheckCode::D107 => CheckKind::PublicInit,
|
||||||
CheckCode::D200 => CheckKind::FitsOnOneLine,
|
CheckCode::D200 => CheckKind::FitsOnOneLine,
|
||||||
|
CheckCode::D201 => CheckKind::NoBlankLineBeforeFunction(1),
|
||||||
|
CheckCode::D202 => CheckKind::NoBlankLineAfterFunction(1),
|
||||||
|
CheckCode::D203 => CheckKind::OneBlankLineBeforeClass(0),
|
||||||
|
CheckCode::D204 => CheckKind::OneBlankLineAfterClass(0),
|
||||||
CheckCode::D205 => CheckKind::NoBlankLineAfterSummary,
|
CheckCode::D205 => CheckKind::NoBlankLineAfterSummary,
|
||||||
CheckCode::D209 => CheckKind::NewLineAfterLastParagraph,
|
CheckCode::D209 => CheckKind::NewLineAfterLastParagraph,
|
||||||
CheckCode::D210 => CheckKind::NoSurroundingWhitespace,
|
CheckCode::D210 => CheckKind::NoSurroundingWhitespace,
|
||||||
CheckCode::D400 => CheckKind::EndsInPeriod,
|
CheckCode::D211 => CheckKind::NoBlankLineBeforeClass(1),
|
||||||
CheckCode::D419 => CheckKind::NonEmpty,
|
|
||||||
CheckCode::D212 => CheckKind::MultiLineSummaryFirstLine,
|
CheckCode::D212 => CheckKind::MultiLineSummaryFirstLine,
|
||||||
CheckCode::D213 => CheckKind::MultiLineSummarySecondLine,
|
CheckCode::D213 => CheckKind::MultiLineSummarySecondLine,
|
||||||
CheckCode::D300 => CheckKind::UsesTripleQuotes,
|
CheckCode::D300 => CheckKind::UsesTripleQuotes,
|
||||||
|
CheckCode::D400 => CheckKind::EndsInPeriod,
|
||||||
CheckCode::D402 => CheckKind::NoSignature,
|
CheckCode::D402 => CheckKind::NoSignature,
|
||||||
CheckCode::D403 => CheckKind::FirstLineCapitalized,
|
CheckCode::D403 => CheckKind::FirstLineCapitalized,
|
||||||
|
CheckCode::D404 => CheckKind::NoThisPrefix,
|
||||||
CheckCode::D415 => CheckKind::EndsInPunctuation,
|
CheckCode::D415 => CheckKind::EndsInPunctuation,
|
||||||
CheckCode::D201 => CheckKind::NoBlankLineBeforeFunction(1),
|
CheckCode::D418 => CheckKind::SkipDocstring,
|
||||||
CheckCode::D202 => CheckKind::NoBlankLineAfterFunction(1),
|
CheckCode::D419 => CheckKind::NonEmpty,
|
||||||
CheckCode::D211 => CheckKind::NoBlankLineBeforeClass(1),
|
|
||||||
CheckCode::D203 => CheckKind::OneBlankLineBeforeClass(0),
|
|
||||||
CheckCode::D204 => CheckKind::OneBlankLineAfterClass(0),
|
|
||||||
// Meta
|
// Meta
|
||||||
CheckCode::M001 => CheckKind::UnusedNOQA(None),
|
CheckCode::M001 => CheckKind::UnusedNOQA(None),
|
||||||
}
|
}
|
||||||
|
@ -527,31 +533,33 @@ impl CheckKind {
|
||||||
CheckKind::UselessObjectInheritance(_) => &CheckCode::U004,
|
CheckKind::UselessObjectInheritance(_) => &CheckCode::U004,
|
||||||
CheckKind::SuperCallWithParameters => &CheckCode::U008,
|
CheckKind::SuperCallWithParameters => &CheckCode::U008,
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
CheckKind::PublicModule => &CheckCode::D100,
|
|
||||||
CheckKind::PublicClass => &CheckCode::D101,
|
|
||||||
CheckKind::PublicMethod => &CheckCode::D102,
|
|
||||||
CheckKind::PublicFunction => &CheckCode::D103,
|
|
||||||
CheckKind::PublicPackage => &CheckCode::D104,
|
|
||||||
CheckKind::MagicMethod => &CheckCode::D105,
|
|
||||||
CheckKind::PublicNestedClass => &CheckCode::D106,
|
|
||||||
CheckKind::PublicInit => &CheckCode::D107,
|
|
||||||
CheckKind::FitsOnOneLine => &CheckCode::D200,
|
|
||||||
CheckKind::NoBlankLineAfterSummary => &CheckCode::D205,
|
|
||||||
CheckKind::NewLineAfterLastParagraph => &CheckCode::D209,
|
|
||||||
CheckKind::NoSurroundingWhitespace => &CheckCode::D210,
|
|
||||||
CheckKind::EndsInPeriod => &CheckCode::D400,
|
CheckKind::EndsInPeriod => &CheckCode::D400,
|
||||||
CheckKind::NonEmpty => &CheckCode::D419,
|
CheckKind::EndsInPunctuation => &CheckCode::D415,
|
||||||
|
CheckKind::FirstLineCapitalized => &CheckCode::D403,
|
||||||
|
CheckKind::FitsOnOneLine => &CheckCode::D200,
|
||||||
|
CheckKind::MagicMethod => &CheckCode::D105,
|
||||||
CheckKind::MultiLineSummaryFirstLine => &CheckCode::D212,
|
CheckKind::MultiLineSummaryFirstLine => &CheckCode::D212,
|
||||||
CheckKind::MultiLineSummarySecondLine => &CheckCode::D213,
|
CheckKind::MultiLineSummarySecondLine => &CheckCode::D213,
|
||||||
CheckKind::UsesTripleQuotes => &CheckCode::D300,
|
CheckKind::NewLineAfterLastParagraph => &CheckCode::D209,
|
||||||
CheckKind::NoSignature => &CheckCode::D402,
|
|
||||||
CheckKind::FirstLineCapitalized => &CheckCode::D403,
|
|
||||||
CheckKind::EndsInPunctuation => &CheckCode::D415,
|
|
||||||
CheckKind::NoBlankLineBeforeFunction(_) => &CheckCode::D201,
|
|
||||||
CheckKind::NoBlankLineAfterFunction(_) => &CheckCode::D202,
|
CheckKind::NoBlankLineAfterFunction(_) => &CheckCode::D202,
|
||||||
|
CheckKind::NoBlankLineAfterSummary => &CheckCode::D205,
|
||||||
CheckKind::NoBlankLineBeforeClass(_) => &CheckCode::D211,
|
CheckKind::NoBlankLineBeforeClass(_) => &CheckCode::D211,
|
||||||
CheckKind::OneBlankLineBeforeClass(_) => &CheckCode::D203,
|
CheckKind::NoBlankLineBeforeFunction(_) => &CheckCode::D201,
|
||||||
|
CheckKind::NoSignature => &CheckCode::D402,
|
||||||
|
CheckKind::NoSurroundingWhitespace => &CheckCode::D210,
|
||||||
|
CheckKind::NoThisPrefix => &CheckCode::D404,
|
||||||
|
CheckKind::NonEmpty => &CheckCode::D419,
|
||||||
CheckKind::OneBlankLineAfterClass(_) => &CheckCode::D204,
|
CheckKind::OneBlankLineAfterClass(_) => &CheckCode::D204,
|
||||||
|
CheckKind::OneBlankLineBeforeClass(_) => &CheckCode::D203,
|
||||||
|
CheckKind::PublicClass => &CheckCode::D101,
|
||||||
|
CheckKind::PublicFunction => &CheckCode::D103,
|
||||||
|
CheckKind::PublicInit => &CheckCode::D107,
|
||||||
|
CheckKind::PublicMethod => &CheckCode::D102,
|
||||||
|
CheckKind::PublicModule => &CheckCode::D100,
|
||||||
|
CheckKind::PublicNestedClass => &CheckCode::D106,
|
||||||
|
CheckKind::PublicPackage => &CheckCode::D104,
|
||||||
|
CheckKind::SkipDocstring => &CheckCode::D418,
|
||||||
|
CheckKind::UsesTripleQuotes => &CheckCode::D300,
|
||||||
// Meta
|
// Meta
|
||||||
CheckKind::UnusedNOQA(_) => &CheckCode::M001,
|
CheckKind::UnusedNOQA(_) => &CheckCode::M001,
|
||||||
}
|
}
|
||||||
|
@ -851,6 +859,12 @@ impl CheckKind {
|
||||||
CheckKind::MagicMethod => "Missing docstring in magic method".to_string(),
|
CheckKind::MagicMethod => "Missing docstring in magic method".to_string(),
|
||||||
CheckKind::PublicNestedClass => "Missing docstring in public nested class".to_string(),
|
CheckKind::PublicNestedClass => "Missing docstring in public nested class".to_string(),
|
||||||
CheckKind::PublicInit => "Missing docstring in __init__".to_string(),
|
CheckKind::PublicInit => "Missing docstring in __init__".to_string(),
|
||||||
|
CheckKind::NoThisPrefix => {
|
||||||
|
"First word of the docstring should not be `This`".to_string()
|
||||||
|
}
|
||||||
|
CheckKind::SkipDocstring => {
|
||||||
|
"Function decorated with @overload shouldn't contain a docstring".to_string()
|
||||||
|
}
|
||||||
// Meta
|
// Meta
|
||||||
CheckKind::UnusedNOQA(codes) => match codes {
|
CheckKind::UnusedNOQA(codes) => match codes {
|
||||||
None => "Unused `noqa` directive".to_string(),
|
None => "Unused `noqa` directive".to_string(),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Abstractions for tracking and validationg docstrings in Python code.
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rustpython_ast::{Constant, Expr, ExprKind, Location, Stmt, StmtKind};
|
use rustpython_ast::{Constant, Expr, ExprKind, Location, Stmt, StmtKind};
|
||||||
|
@ -593,6 +595,32 @@ pub fn capitalized(checker: &mut Checker, definition: &Definition) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// D404
|
||||||
|
pub fn starts_with_this(checker: &mut Checker, definition: &Definition) {
|
||||||
|
if let Some(docstring) = definition.docstring {
|
||||||
|
if let ExprKind::Constant {
|
||||||
|
value: Constant::Str(string),
|
||||||
|
..
|
||||||
|
} = &docstring.node
|
||||||
|
{
|
||||||
|
let trimmed = string.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(first_word) = string.split(' ').next() {
|
||||||
|
if first_word
|
||||||
|
.replace(|c: char| !c.is_alphanumeric(), "")
|
||||||
|
.to_lowercase()
|
||||||
|
== "this"
|
||||||
|
{
|
||||||
|
checker.add_check(Check::new(CheckKind::NoThisPrefix, range_for(docstring)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// D415
|
/// D415
|
||||||
pub fn ends_with_punctuation(checker: &mut Checker, definition: &Definition) {
|
pub fn ends_with_punctuation(checker: &mut Checker, definition: &Definition) {
|
||||||
if let Some(docstring) = definition.docstring {
|
if let Some(docstring) = definition.docstring {
|
||||||
|
@ -613,6 +641,23 @@ pub fn ends_with_punctuation(checker: &mut Checker, definition: &Definition) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// D418
|
||||||
|
pub fn if_needed(checker: &mut Checker, definition: &Definition) {
|
||||||
|
if definition.docstring.is_some() {
|
||||||
|
if let DefinitionKind::Function(stmt)
|
||||||
|
| DefinitionKind::NestedFunction(stmt)
|
||||||
|
| DefinitionKind::Method(stmt) = definition.kind
|
||||||
|
{
|
||||||
|
if is_overload(stmt) {
|
||||||
|
checker.add_check(Check::new(
|
||||||
|
CheckKind::SkipDocstring,
|
||||||
|
Range::from_located(stmt),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// D419
|
/// D419
|
||||||
pub fn not_empty(checker: &mut Checker, definition: &Definition) -> bool {
|
pub fn not_empty(checker: &mut Checker, definition: &Definition) -> bool {
|
||||||
if let Some(docstring) = definition.docstring {
|
if let Some(docstring) = definition.docstring {
|
||||||
|
|
|
@ -1284,6 +1284,18 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn d404() -> Result<()> {
|
||||||
|
let mut checks = check_path(
|
||||||
|
Path::new("./resources/test/fixtures/D.py"),
|
||||||
|
&settings::Settings::for_rule(CheckCode::D404),
|
||||||
|
&fixer::Mode::Generate,
|
||||||
|
)?;
|
||||||
|
checks.sort_by_key(|check| check.location);
|
||||||
|
insta::assert_yaml_snapshot!(checks);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn d415() -> Result<()> {
|
fn d415() -> Result<()> {
|
||||||
let mut checks = check_path(
|
let mut checks = check_path(
|
||||||
|
@ -1296,6 +1308,18 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn d418() -> Result<()> {
|
||||||
|
let mut checks = check_path(
|
||||||
|
Path::new("./resources/test/fixtures/D.py"),
|
||||||
|
&settings::Settings::for_rule(CheckCode::D418),
|
||||||
|
&fixer::Mode::Generate,
|
||||||
|
)?;
|
||||||
|
checks.sort_by_key(|check| check.location);
|
||||||
|
insta::assert_yaml_snapshot!(checks);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn d419() -> Result<()> {
|
fn d419() -> Result<()> {
|
||||||
let mut checks = check_path(
|
let mut checks = check_path(
|
||||||
|
|
6
src/snapshots/ruff__linter__tests__d404.snap
Normal file
6
src/snapshots/ruff__linter__tests__d404.snap
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
source: src/linter.rs
|
||||||
|
expression: checks
|
||||||
|
---
|
||||||
|
[]
|
||||||
|
|
29
src/snapshots/ruff__linter__tests__d418.snap
Normal file
29
src/snapshots/ruff__linter__tests__d418.snap
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
source: src/linter.rs
|
||||||
|
expression: checks
|
||||||
|
---
|
||||||
|
- kind: SkipDocstring
|
||||||
|
location:
|
||||||
|
row: 33
|
||||||
|
column: 5
|
||||||
|
end_location:
|
||||||
|
row: 37
|
||||||
|
column: 5
|
||||||
|
fix: ~
|
||||||
|
- kind: SkipDocstring
|
||||||
|
location:
|
||||||
|
row: 85
|
||||||
|
column: 5
|
||||||
|
end_location:
|
||||||
|
row: 89
|
||||||
|
column: 5
|
||||||
|
fix: ~
|
||||||
|
- kind: SkipDocstring
|
||||||
|
location:
|
||||||
|
row: 105
|
||||||
|
column: 1
|
||||||
|
end_location:
|
||||||
|
row: 110
|
||||||
|
column: 1
|
||||||
|
fix: ~
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Abstractions for tracking public and private visibility across modules, classes, and functions.
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::ast::helpers::match_name_or_attr;
|
use crate::ast::helpers::match_name_or_attr;
|
||||||
|
@ -24,6 +26,7 @@ pub struct VisibleScope {
|
||||||
pub visibility: Visibility,
|
pub visibility: Visibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if a function definition is an `@overload`.
|
||||||
pub fn is_overload(stmt: &Stmt) -> bool {
|
pub fn is_overload(stmt: &Stmt) -> bool {
|
||||||
match &stmt.node {
|
match &stmt.node {
|
||||||
StmtKind::FunctionDef { decorator_list, .. }
|
StmtKind::FunctionDef { decorator_list, .. }
|
||||||
|
@ -34,6 +37,7 @@ pub fn is_overload(stmt: &Stmt) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if a function is a "magic method".
|
||||||
pub fn is_magic(stmt: &Stmt) -> bool {
|
pub fn is_magic(stmt: &Stmt) -> bool {
|
||||||
match &stmt.node {
|
match &stmt.node {
|
||||||
StmtKind::FunctionDef { name, .. } | StmtKind::AsyncFunctionDef { name, .. } => {
|
StmtKind::FunctionDef { name, .. } | StmtKind::AsyncFunctionDef { name, .. } => {
|
||||||
|
@ -47,6 +51,7 @@ pub fn is_magic(stmt: &Stmt) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if a function is an `__init__`.
|
||||||
pub fn is_init(stmt: &Stmt) -> bool {
|
pub fn is_init(stmt: &Stmt) -> bool {
|
||||||
match &stmt.node {
|
match &stmt.node {
|
||||||
StmtKind::FunctionDef { name, .. } | StmtKind::AsyncFunctionDef { name, .. } => {
|
StmtKind::FunctionDef { name, .. } | StmtKind::AsyncFunctionDef { name, .. } => {
|
||||||
|
@ -56,13 +61,14 @@ pub fn is_init(stmt: &Stmt) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_private_name(module_name: &str) -> bool {
|
/// Returns `true` if a module name indicates private visibility.
|
||||||
|
fn is_private_module(module_name: &str) -> bool {
|
||||||
module_name.starts_with('_') || (module_name.starts_with("__") && module_name.ends_with("__"))
|
module_name.starts_with('_') || (module_name.starts_with("__") && module_name.ends_with("__"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module_visibility(path: &Path) -> Visibility {
|
pub fn module_visibility(path: &Path) -> Visibility {
|
||||||
for component in path.iter().rev() {
|
for component in path.iter().rev() {
|
||||||
if is_private_name(&component.to_string_lossy()) {
|
if is_private_module(&component.to_string_lossy()) {
|
||||||
return Visibility::Private;
|
return Visibility::Private;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,6 +121,9 @@ fn class_visibility(stmt: &Stmt) -> Visibility {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transition a `VisibleScope` based on a new `Documentable` definition.
|
/// Transition a `VisibleScope` based on a new `Documentable` definition.
|
||||||
|
///
|
||||||
|
/// `scope` is the current `VisibleScope`, while `Documentable` and `Stmt` describe the current
|
||||||
|
/// node used to modify visibility.
|
||||||
pub fn transition_scope(scope: &VisibleScope, stmt: &Stmt, kind: &Documentable) -> VisibleScope {
|
pub fn transition_scope(scope: &VisibleScope, stmt: &Stmt, kind: &Documentable) -> VisibleScope {
|
||||||
match kind {
|
match kind {
|
||||||
Documentable::Function => VisibleScope {
|
Documentable::Function => VisibleScope {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue