Skip to content

Add WPS484: forbid strings that document nothing - #3810

Merged
sobolevn merged 6 commits into
wemake-services:masterfrom
vyhuholl:issue-3808
Sep 12, 2026
Merged

Add WPS484: forbid strings that document nothing#3810
sobolevn merged 6 commits into
wemake-services:masterfrom
vyhuholl:issue-3808

Conversation

@vyhuholl

Copy link
Copy Markdown
Contributor

I have made things!

Adds WPS484, the rule from #3808. It flags a string statement placed where it cannot document anything:

some.first = 1
"""Documents nothing, `first` belongs to `some`."""


def some(arg):
    """Function docs."""
    if arg:
        """Neither does this."""
        return arg
    return 0

A string documents something in exactly four places:

  • opening a module, class or function body
  • after an assignment to a plain name in a module or a class
  • after self.some = ... inside a method
  • after a type Some = ... alias on python3.12+

The check itself is a single condition, because WPS226 already had to answer this same question in order to skip docstrings:

def _check_doc_string_place(self, node: ast.Expr) -> None:
    if strings.is_doc_string(node) and not strings.is_doc_string_value(
        node.value,
    ):
        self.add_violation(WrongDocStringPlacementViolation(node))

That reuse is the point of the rule, not a shortcut. Both rules now read one definition of a documenting position, so refining it later moves them together instead of letting two copies drift.

The violation sits in best_practices.py next to WPS428, the old "statement has no effect" rule that was retired to ruff's B015/B018 in 1.0.0. Neither of those flags a string, which is how these slip through today.

wemake-python-styleguide itself is clean under the new rule.

Open to review

I picked these three without asking, so say if any is wrong:

  • the name, WrongDocStringPlacementViolation
  • the code, WPS484
  • counting type Some = int docstrings as a valid position, given they're still only a proposal upstream

AI Policy

  • I have read and agree to the AI Policy, removed any "Co-Authored-By" lines attributing coding agents, and manually reviewed the final result

Checklist

  • I have double checked that there are no unrelated changes in this pull request (old patches, accidental config files, etc)
  • I have created at least one test case for the changes I have made
  • I have updated the documentation for the changes I have made
  • I have added my changes to the CHANGELOG.md

Related issues

Closes #3808

🙏 Please, if you or your company is finding wemake-python-styleguide valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/wemake-python-styleguide. As a thank you, your profile/company logo will be added to our main README which receives hundreds of unique visitors per day.

A string statement only documents something when it opens a module,
class or function body, follows a module or class attribute, follows
`self.some = ...` in a method, or follows a `type` alias. Anywhere else
it does nothing at runtime while still reading like documentation.

The check reuses `is_doc_string_value()`, the predicate WPS226 already
uses to skip docstrings, so both rules share one definition of a
documenting position instead of keeping two that can drift apart.

Closes wemake-services#3808
@codecov

codecov Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (336341c) to head (663120a).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #3810   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          374       375    +1     
  Lines        12708     12763   +55     
  Branches       879       880    +1     
=========================================
+ Hits         12708     12763   +55     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sobolevn sobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first correction:

after self.some = ... inside a constructor

Not in every other method

:)

`self.some = 1` in a regular method assigns to an instance that already
exists, so a string after it documents nothing. Only `__init__` defines
the attributes, which is what PEP 258 and Sphinx read.

This narrows the shared predicate, so it moves `WPS226` as well: the
same string after `self.some = 1` outside a constructor is counted
again. That is the point of the two rules sharing one definition.

Refs wemake-services#3808

@sobolevn sobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment thread tests/test_visitors/test_ast/test_statements/test_doc_string_placement.py Outdated
Comment thread wemake_python_styleguide/logic/tree/strings.py Outdated
Comment thread wemake_python_styleguide/violations/best_practices.py
Comment thread wemake_python_styleguide/violations/best_practices.py Outdated
Comment thread CHANGELOG.md
vyhuholl and others added 2 commits September 12, 2026 10:56
Co-authored-by: sobolevn <mail@sobolevn.me>
Four review points plus the build:

- The applied suggestion dropped the escaping on one example but kept
  `"""`, which closed the class docstring early and broke the parse.
  Both examples now use `'''`, which is what the suggestion asked for.
- `__new__` defines attributes too, so both constructors are accepted.
- The placement tests now run over `"Doc"`, `'Doc'`, `"""Doc"""` and
  `'''Doc'''`, and cover a `__new__` constructor.
- Master released 1.8.1 while this branch was open, so the merge swept
  the entry into a released patch section. A new violation cannot ship
  in a patch anyway, so it starts a fresh WIP section.

Refs wemake-services#3808

@sobolevn sobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Last fixes:

  • please test dataclass-style attrs explicitly, with and without default values
  • there's a common error that people use """Docstring""" before the attribute, not after. we should also explicitly test and report this case

Both already behaved correctly, so this is coverage plus docs, no
change to the check itself.

Dataclass fields are plain annotated class attributes, with or without
a default, so they were already allowed. Now they say so explicitly.

A string placed before an attribute is already reported, since the
statement above it is not an assignment. Three shapes are covered: at
module level, in a class body, and between two attributes. The example
in the violation now shows this, as it is the common way to get it
wrong.

Refs wemake-services#3808
@vyhuholl

Copy link
Copy Markdown
Contributor Author

Added tests for dataclass-style attrs and for attribute docstring placement. Both cases already behaved correctly, so no code change was needed.

@sobolevn sobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@sobolevn
sobolevn merged commit f5e435a into wemake-services:master Sep 12, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Forbid strings that look like docstrings but are not

2 participants