Skip to content

Handling of attrs and dataclass constructors #656

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

Open
wants to merge 76 commits into
base: master
Choose a base branch
from

Conversation

tristanlatr
Copy link
Contributor

@tristanlatr tristanlatr commented Oct 17, 2022

This PR drastically improve our understanding of attrs and dataclass generated classes.

It will infer the __init__ signature and present fields docstrings in the parameter table.
It understand combinations of auto_attribs, auto_detect, kw_only and init arguments to the attr.s() function. As well as the new APIs attrs.define(). For attr.ib(), it checks the converter, factory, default, type, kw_only and init arguments to infer each constructor param.

It only handles the creation of the __init__ method, it’s does not create __eq__ and other attrs methods. Since these methods all have the same signature, it’s probably not worth it to actually create Function instance to represent them. One thing we could do it to add a note at the end of the docstring listing implemented methods. Another thing to do would be to show the class decorators so the reader can determine whether all compare methods are implemented.

See documentation here: https://pydoctor--656.org.readthedocs.build/en/656/codedoc.html#using-attrs

Partial Fix for #305, handles the dataclass and attrs case.
Fixes #890

Currently, It will sometimes generate a wrong constructor arguments order for dataclasses and classic attrs based classes that have multiple inheritance and attribute collisions. This is because there are two manner of linearizing the parameters and I only implemented the “collect by MRO” order.

@codecov
Copy link

codecov bot commented Oct 31, 2022

Codecov Report

Attention: Patch coverage is 92.89617% with 26 lines in your changes missing coverage. Please review.

Project coverage is 93.15%. Comparing base (97fc788) to head (faed763).

Files with missing lines Patch % Lines
pydoctor/extensions/attrs.py 91.80% 13 Missing and 11 partials ⚠️
pydoctor/astutils.py 97.14% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #656      +/-   ##
==========================================
- Coverage   93.18%   93.15%   -0.04%     
==========================================
  Files          47       49       +2     
  Lines        8736     9024     +288     
  Branches     1601     1667      +66     
==========================================
+ Hits         8141     8406     +265     
- Misses        336      349      +13     
- Partials      259      269      +10     

☔ View full report in Codecov by Sentry.
📢 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tristanlatr tristanlatr marked this pull request as draft January 18, 2023 17:59
@tristanlatr tristanlatr changed the title 305 handling of constructors Handling of constructors Feb 22, 2023
@tristanlatr tristanlatr mentioned this pull request Feb 23, 2023
@tristanlatr tristanlatr changed the title Handling of constructors Handling of attrs constructors Apr 6, 2023
@tristanlatr tristanlatr changed the title Handling of attrs/dataclass/pydantic/namedtuple constructors Handling of attrs and dataclass constructors Jun 28, 2025

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

@tristanlatr tristanlatr requested a review from glyph June 29, 2025 15:53
@tristanlatr tristanlatr marked this pull request as ready for review June 29, 2025 15:54
Uses a converter
"""

Pydoctor also supports the newer APIs (``attrs.define``/``attrs.field``).
Copy link
Contributor Author

@tristanlatr tristanlatr Jun 29, 2025

Choose a reason for hiding this comment

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

Suggested change
Pydoctor also supports the newer APIs (``attrs.define``/``attrs.field``).
Pydoctor also supports the newer APIs (``attrs.define``/``attrs.field``); as well as ``dataclasses.dataclass`` generated classes.

@tristanlatr tristanlatr requested a review from a team July 1, 2025 17:40

This comment has been minimized.

This comment has been minimized.

Copy link

Diff from pydoctor_primer, showing the effect of this PR on open source code:

sdk-python (https://github.com/temporalio/sdk-python): typechecking got 1.12x slower (200.4s -> 224.2s)
(Performance measurements are based on a single noisy sample)
+ /projects/sdk-python/temporalio/client.py:2967: ambiguous ref to typed_search_attributes, could be temporalio.client.WorkflowExecution.typed_search_attributes, temporalio.client.ScheduleActionStartWorkflow.typed_search_attributes, temporalio.client.ScheduleDescription.typed_search_attributes, temporalio.client.ScheduleListDescription.typed_search_attributes
+ /projects/sdk-python/temporalio/client.py:2967: Cannot find link target for "typed_search_attributes"
+ /projects/sdk-python/temporalio/worker/_tuning.py:67: Cannot find link target for "CompositeTuner"

Copy link
Member

@glyph glyph left a comment

Choose a reason for hiding this comment

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

I think the generated docstring could be a bit better, but otherwise this seems great. No need to think super hard about it though, if you can think of a slightly better boilerplate we can improve it more later.

list_of_numbers: List[int] = list(),
converted_paths: List[str] = list()):
"""
attrs generated method
Copy link
Member

Choose a reason for hiding this comment

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

Could this be a note like @note:, with a title line "Initialize a SomeClass"? In the summary, I think seeing "attrs generated method" on every __init__ is even less helpful than that.

@tristanlatr
Copy link
Contributor Author

tristanlatr commented Jul 11, 2025

Hi @glyph and many thanks for your review as always.

I will move the words saying whether it’s a attrs or dataclass generated method in a @note field. And use the title you suggested :)

I’ll try to improve one or two aspect still, namely

  • how the dataclasse (and classic attrs without the argument collect_by_mro=True) inherited attributes are ordered. It’s currently not quite right in case of colliding names.
  • Support InitVar annotation.
  • follow up issues should be opened to address (or at least document) the following missing features:
    • decorator based factory and converters feature in attrs
    • show the class decorators
    • make private (hidden by default) function and classes decorators that are private or inside a private namespace

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants