Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add option to put docstrings on model attributes #1190

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

eli-bl
Copy link
Collaborator

@eli-bl eli-bl commented Jan 7, 2025

Adds a docstrings_on_attributes option that causes property descriptions to appear in docstrings on the attributes, instead of in the class docstring. This is a desirable behavior when using documentation generators like Sphinx.

This is a non-breaking change; if the option is not set, code generation is exactly the same as before (evidence: the existing golden-record directories have no changes).

Clarification about how docstrings on attributes work

Python does not treat all docstrings the same, in terms of availability at runtime. A docstring on a class or method is available as a __doc__ attribute— but a docstring on an attribute is not; such a string is just thrown away by the interpreter. If class A has attribute b, then A.b.__doc__ will never be a thing— you would have to define b as a property getter method instead.

However, docstrings on attributes are still valid as per PEP 257 as a thing that can be surfaced by other tools. Sphinx will use them when generating documentation, and VS Code will show them as a description in the popup if you hover over an attribute.


from typer.testing import CliRunner

from openapi_python_client.cli import app


def regen_golden_record():
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This file had a large amount of copy-paste; most of the regenerate methods are the same except for the file/path names. I've refactored them to use a common method, clarifying what the differences really are.

I verified that this doesn't change the output for the existing end-to-end tests by deleting all the golden record directories, running pdm regen, and seeing that the new files exactly match what's in source control.

@eli-bl eli-bl requested a review from dbanty January 7, 2025 18:14
Copy link
Collaborator

@dbanty dbanty left a comment

Choose a reason for hiding this comment

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

Could you use a smaller OpenAPI document for the snapshots on this one so there will be fewer changes in the future as we tweak things?

Probably just a single endpoint & model would be enough to demonstrate it

@eli-bl eli-bl force-pushed the model-attr-docstrings branch from ec3a812 to 0c73307 Compare January 7, 2025 20:36

# Make `config` available in custom templates

The configuration options object is now exposed as a variable called `config` in Jinja2 templates.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This change isn't really specific to the new feature, but I figured it was useful enough to be worth mentioning.

@eli-bl eli-bl requested a review from dbanty January 7, 2025 22:05
@eli-bl
Copy link
Collaborator Author

eli-bl commented Jan 9, 2025

@dbanty FYI, this was motivated partly by trying to build some HTML docs from a generated client with Sphinx, and finding that Sphinx really does not like how the current class docstrings are formatted. The format only really works if you view the strings as plain text; if it's interpreted either as Sphinx's default .rst format, or as Markdown, it becomes very garbled. That's the case even if the class & property descriptions are just plain text with no special markup - it's just a consequence of how indents & line breaks are being used in the template. Regardless of what kind of markup is supported by any particular tool, they are all likely to have opinions about those things, so it's kind of asking for trouble to try to create structured text like this out of multiple pieces of data. By contrast, the Python code structure, and the idea of class docstrings vs. attribute docstrings, is already something doc generators and IDEs understand.

@eli-bl
Copy link
Collaborator Author

eli-bl commented Jan 10, 2025

@dbanty Btw, I updated the PR description to clarify the behavior of attribute docstrings in Python.

{# This macro returns the provided content as a docstring, set to a raw string if it contains a backslash #}
{% if (not omit_if_empty) or (content | trim) %}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The reason I added the omit_if_empty parameter here is to avoid inserting an empty """ """ for the class docstring if the model class doesn't have any description. That wasn't really an issue with the previous behavior, because model classes almost always have properties so there was always a class docstring that included the property descriptions. I am not setting omit_if_empty in the template unless the new docstrings_on_attributes option is enabled, so that I can guarantee that the behavior is 100% unchanged if you don't set the option.



Attributes:
raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a
Copy link
Collaborator

Choose a reason for hiding this comment

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

@eli-bl do you think it's worth modifying the client classes as well? Do you end up wanting these documented with Sphinx?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah yeah, I hadn't thought of that. I guess it may as well be consistent - will do.

@@ -0,0 +1,15 @@
class_overrides:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Most of this config is probably not needed with the smaller test case

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, will remove copypasta

@eli-bl eli-bl force-pushed the model-attr-docstrings branch from 80c799d to e980228 Compare January 13, 2025 19:55
@eli-bl eli-bl force-pushed the model-attr-docstrings branch from e980228 to 7c3427e Compare January 13, 2025 19:59
raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a
status code that was not documented in the source OpenAPI document. Can also be provided as a keyword
argument to the constructor.
{{ attr_in_class_docstring("raise_on_unexpected_status") | wordwrap(101) | indent(12) }}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The word wrap parameter here looks arbitrary, but that happens to be the value that results in exactly the same formatting for this text as before.

@eli-bl eli-bl requested a review from dbanty January 13, 2025 20:02
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