diff --git a/resources/test/fixtures/pydocstyle/D.py b/resources/test/fixtures/pydocstyle/D.py index 113018fcf3..30c63e8360 100644 --- a/resources/test/fixtures/pydocstyle/D.py +++ b/resources/test/fixtures/pydocstyle/D.py @@ -571,3 +571,11 @@ def multiline_trailing_and_leading_space(): """ pass + + +@expect('D210: No whitespaces allowed surrounding docstring text') +@expect("D400: First line should end with a period (not '\"')") +@expect("D415: First line should end with a period, question mark, " + "or exclamation point (not '\"')") +def endswith_quote(): + """Whitespace at the end, but also a quote" """ diff --git a/src/pydocstyle/plugins.rs b/src/pydocstyle/plugins.rs index 6eb4a9d81c..394a05f774 100644 --- a/src/pydocstyle/plugins.rs +++ b/src/pydocstyle/plugins.rs @@ -633,17 +633,25 @@ pub fn no_surrounding_whitespace(checker: &mut Checker, definition: &Definition) .chain(constants::SINGLE_QUOTE_PREFIXES) { if first_line.starts_with(pattern) { - check.amend(Fix::replacement( - trimmed.to_string(), - Location::new( - docstring.location.row(), - docstring.location.column() + pattern.len(), - ), - Location::new( - docstring.location.row(), - docstring.location.column() + pattern.len() + line.chars().count(), - ), - )); + if let Some(quote) = pattern.chars().last() { + // If removing whitespace would lead to an invalid string of quote + // characters, avoid applying the fix. + if !trimmed.ends_with(quote) { + check.amend(Fix::replacement( + trimmed.to_string(), + Location::new( + docstring.location.row(), + docstring.location.column() + pattern.len(), + ), + Location::new( + docstring.location.row(), + docstring.location.column() + + pattern.len() + + line.chars().count(), + ), + )); + } + } break; } } diff --git a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D210_D.py.snap b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D210_D.py.snap index c451b9cd79..bef21772fe 100644 --- a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D210_D.py.snap +++ b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D210_D.py.snap @@ -47,4 +47,12 @@ expression: checks end_location: row: 299 column: 36 +- kind: NoSurroundingWhitespace + location: + row: 581 + column: 4 + end_location: + row: 581 + column: 51 + fix: ~ diff --git a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D400_D.py.snap b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D400_D.py.snap index b4c7f9f41d..af29dfeb26 100644 --- a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D400_D.py.snap +++ b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D400_D.py.snap @@ -106,4 +106,12 @@ expression: checks row: 520 column: 32 fix: ~ +- kind: EndsInPeriod + location: + row: 581 + column: 4 + end_location: + row: 581 + column: 51 + fix: ~ diff --git a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D415_D.py.snap b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D415_D.py.snap index c8c3d95e90..ff70dcc778 100644 --- a/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D415_D.py.snap +++ b/src/pydocstyle/snapshots/ruff__pydocstyle__tests__D415_D.py.snap @@ -98,4 +98,12 @@ expression: checks row: 520 column: 32 fix: ~ +- kind: EndsInPunctuation + location: + row: 581 + column: 4 + end_location: + row: 581 + column: 51 + fix: ~