Skip to content

Add config option and logic to allow the use of PEP257-style inline class attribute documentation#278

Open
mpyuglgwkxcmodyrpo wants to merge 12 commits intojsh9:mainfrom
mpyuglgwkxcmodyrpo:pep257-inline-class-attribute-docs
Open

Add config option and logic to allow the use of PEP257-style inline class attribute documentation#278
mpyuglgwkxcmodyrpo wants to merge 12 commits intojsh9:mainfrom
mpyuglgwkxcmodyrpo:pep257-inline-class-attribute-docs

Conversation

@mpyuglgwkxcmodyrpo
Copy link
Copy Markdown

@mpyuglgwkxcmodyrpo mpyuglgwkxcmodyrpo commented Nov 29, 2025

PEP-257 is kind of vague when it comes to class vs. instance variable docs:

String literals occurring elsewhere in Python code may also act as documentation. They are not recognized by the Python bytecode compiler and are not accessible as runtime object attributes (i.e. not assigned to doc), but two types of extra docstrings may be extracted by software tools:

  1. String literals occurring immediately after a simple assignment at the top level of a module, class, or init method are called “attribute docstrings”.
  2. String literals occurring immediately after another docstring are called “additional docstrings”.

Please see PEP 258, “Docutils Design Specification”, for a detailed description of attribute and additional docstrings.

The way I interpret it is that it does allow a string after both class attributes AND instance attributes, especially since a class attribute is "a simple assignment". Additionally, but less relevant, the reference to PEP 258 seems strange because it was rejected entirely.

This PR adds support for inline class variable documentation.

The logic uses the class visitor to walk the class AST and check for constant exprs (ast.Expr -> ast.Constant) after ast.AnnAssign or ast.Assign directives. It will insert the attribute at the correct index in the documented args list so that it does not throw an out of order error. If attributes are declared in the class, they supersede the one declared inline.

I have additionally included tests, command line options, and docs in this PR. Let me know what you think of the overall idea and if the parameter name makes sense. I am also not confident that the added logic is in the correct function, but it does function properly where it is. I can also split it out into another helper, if you think that would make the code cleaner.

Thanks for the awesome project, it has already caught a number of doc inconsistencies with our code base.

Comment thread pydoclint/utils/visitor_helper.py Outdated
@mpyuglgwkxcmodyrpo
Copy link
Copy Markdown
Author

mpyuglgwkxcmodyrpo commented Nov 29, 2025

Fixing lints, will push again in a few.

fixed, will work on your other comments.

Comment thread docs/config_options.md Outdated
@mpyuglgwkxcmodyrpo mpyuglgwkxcmodyrpo force-pushed the pep257-inline-class-attribute-docs branch from 403da31 to 5915074 Compare November 29, 2025 03:10
Comment thread docs/config_options.md Outdated
Comment thread tests/utils/test_visitor_helper.py Outdated
Comment thread tests/utils/test_visitor_helper.py
Comment thread docs/config_options.md Outdated
@jsh9
Copy link
Copy Markdown
Owner

jsh9 commented Nov 29, 2025

Hi @mpyuglgwkxcmodyrpo , thanks for contributing to pydoclint!

I wasn't familiar with this type of style before, but recently I did see such styles being produced by various AI coding assistants I used. I think pydoclint should accommodate for such style.

Small note: when you push new commits, this PR's Github workflow doesn't run unless I click "approve" on my end. (I don't know now to configure this.) Therefore, you can run tox in your machine's pydoclint py env to make sure the Github workflow passes (at least for your OS and your py version).

@mpyuglgwkxcmodyrpo
Copy link
Copy Markdown
Author

mpyuglgwkxcmodyrpo commented Dec 1, 2025

Pushed changes. I think the concept of "inline docstrings" is really only present in sphinx... but autodoc supports it for all three styles... see example numpy documentation and example google documentation on the sphinx website. The examples include BOTH the post-definition constant string AND #: either on the line before the attribute declaration or even on the same line as it.

One last thing I have to do is pull the documented type from the inline docstring, because apparently its valid to specify the type as the first thing in the comment and then follow it with a colon. I'll need to update the tests for that.
Done.

I'm thinking of changing the option from allow-inline-classvar-docs to allow-inline-class-attribute-docs. I am also wondering if we should throw a doc mismatch error IF arg-type-hints-in-docstring and allow-inline-classvar-docs are both True, the attribute type is specified in both the class header docstring and the inline docstring, AND they mismatch. Right now the inline docstring type is ignored entirely if they are both specified and both options are True. Thoughts?

I didn't implement the dedent bit because I needed the sources in multiple places. I could do an itertools.product, but unless you feel strongly about it I will not.

Also, I separated out the code that gathers the documented and actual attributes from the ast.ClassDef node, as I would have needed to gather them anyway to test the inline docs function. I can split it differently if you'd like.

Let me know if you want more changes.

@jsh9
Copy link
Copy Markdown
Owner

jsh9 commented Dec 10, 2025

Hi @mpyuglgwkxcmodyrpo , I've been a bit busy these past few days. Let me try to get to it this weekend.

@mpyuglgwkxcmodyrpo mpyuglgwkxcmodyrpo force-pushed the pep257-inline-class-attribute-docs branch from 96a1196 to 178db4a Compare December 10, 2025 19:10
@mpyuglgwkxcmodyrpo
Copy link
Copy Markdown
Author

No worries at all! I fixed the markdown formatting just now.

Comment thread pydoclint/utils/arg.py
) -> None:
"""Insert an Arg at a specific index."""
self.infoList.insert(index, arg)
self.lookup[arg.name] = arg.typeHint
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Are there any safeguards when arg already exists in self.infoList and self.lookup?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I added a check and exception. Thoughts? It should be an edge case.

Comment thread pydoclint/utils/visitor_helper.py Outdated
Comment thread pydoclint/utils/visitor_helper.py Outdated
Comment thread pydoclint/utils/visitor_helper.py Outdated
Comment thread pydoclint/utils/visitor_helper.py Outdated
Comment thread docs/checking_class_attributes.md Outdated
Comment thread docs/checking_class_attributes.md Outdated
Comment thread docs/config_options.md Outdated
Comment thread tests/test_main.py Outdated
Comment thread pydoclint/utils/visitor_helper.py
Comment thread pydoclint/utils/visitor_helper.py
@mpyuglgwkxcmodyrpo
Copy link
Copy Markdown
Author

I will have time to work on this tomorrow, I think. Thanks for the feedback I look forward to implementing it so we can get this merged.

@mpyuglgwkxcmodyrpo
Copy link
Copy Markdown
Author

Sorry this got away from me with the holidays and some work deadlines. Still on my radar.

@mpyuglgwkxcmodyrpo mpyuglgwkxcmodyrpo force-pushed the pep257-inline-class-attribute-docs branch from 478231d to 512daf6 Compare March 8, 2026 21:16
@mpyuglgwkxcmodyrpo
Copy link
Copy Markdown
Author

I thought my tox checks were passing and then I must have changed something. All good now!

@mpyuglgwkxcmodyrpo
Copy link
Copy Markdown
Author

mpyuglgwkxcmodyrpo commented Mar 17, 2026

Not sure what is going on here, I cannot reproduce the reformatting changes locally (muff format is failing in tox pre-commit step). tox is passing on everything locally.

$ uv run muff format --config muff.toml
47 files left unchanged
$ uv run muff --version
muff 0.14.5

The version matches the one in the pre-commit config.

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.

2 participants