Skip to content

Merge constructor docstrings into class docstrings - #1622

Open
felix-windsor wants to merge 1 commit into
collective:mainfrom
felix-windsor:docs/merge-constructor-docstrings
Open

Merge constructor docstrings into class docstrings#1622
felix-windsor wants to merge 1 commit into
collective:mainfrom
felix-windsor:docs/merge-constructor-docstrings

Conversation

@felix-windsor

Copy link
Copy Markdown

Linked issue

Description

Moves every __init__ and __new__ docstring in the package into its containing class docstring so API documentation has a single source of class-level content.

This also:

  • configures Sphinx with autoclass_content = "class";
  • preserves and organizes existing parameter, example, and exception documentation;
  • adds an AST regression test that reports any constructor docstrings added later;
  • adds the required documentation news fragment.

Responsible AI disclosure: I used OpenAI Codex (GPT-5) to inventory and migrate the docstrings, draft the AST regression test, update the Sphinx configuration and news entry, and review validation output. I reviewed the complete diff and validated the changes locally.

Checklist

  • I added a change log entry, following the instructions in Change log entry format.
  • I followed icalendar project guidelines for Artificial intelligence policy and disclosed my Responsible AI use in my commit messages, if applicable.
  • I added or updated tests, if applicable.
  • I ran and ensured all tests pass locally by following Run tests.
  • I added or edited documentation as necessary, both as docstrings to be rendered in the API documentation and narrative documentation, following the Style guide.

Additional information

Local validation:

  • uv run pytest -q: 17,888 passed, 28 skipped, 529 xfailed.
  • make test: CPython 3.10, 3.11, 3.12, 3.13, and 3.14 passed; the nopytz environment passed.
  • CARGO_NET_GIT_FETCH_WITH_CLI=true uv run tox -e pypy3: passed with 97% coverage.
  • Strict make html Sphinx build: passed with warnings treated as errors.
  • uv run ruff format --check, uv run ruff check, and git diff --check: passed.

The combined docs tox run completed HTML, doctest, and Vale successfully; its link-check phase only reported two pre-existing external-site responses unrelated to this change: a 404 from the sphinx-reredirects documentation URL and a 403 from a Stack Overflow timezone link.

AI disclosure: I used OpenAI Codex (GPT-5) to inventory all __init__ and __new__ docstrings, migrate and merge their content into class docstrings, add the AST regression test, update the Sphinx configuration and news entry, and review local test and documentation results. I reviewed and validated the changes.
@github-actions github-actions Bot added the ai-suspicion This contribution is possibly created with lots of AI help without enough human understanding. label Aug 1, 2026
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

This pull request did not pass quality checks and AI use is suspected. Please review Contribute and make any necessary amendments.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Profile summary:

GitHub user: felix-windsor
🟢 No concerns found with user's profile.
🟢 No concerns found with recent PR activity.
🟢 No concerns found with recent issue activity.

For a more detailed report, run `gh-profiler felix-windsor`.
Full profile
GitHub user: felix-windsor
🟢 No concerns found with user's profile.
   🟢 Account age: 2 years
   🟢 Profile information:
        name: Felix Wang
        company: University of Sydney
        blog: shengxi.xyz
        email: felixwindsor3344@gmail.com
        bio: You must realize a grand world awaits your exploration, far beyond the known.
      Empty fields: location

🟢 No concerns found with recent PR activity.
   3 PRs opened in the last 21 days.
      0 opened against repos the user owns.
      0 opened against repos in publicly associated orgs.
      3 opened against external repos.

   🟢 0 of 3 external PRs merged in the last 21 days.
   🟢 0 of 3 external PRs closed without merging in the last 21 days.

🟢 No concerns found with recent issue activity.
   🟢 No new issues opened in the last 21 days.

@angatha

angatha commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

@krrishapatel please dont paste AI generated output like this. Keep the important parts.

Did you verify that the AI did its job correct?

I prefer not to do the suggestion since an __init__ method should only be within a class.

Comment thread docs/conf.py
@stevepiercy

Copy link
Copy Markdown
Member

I'm in the middle of a thorough review while in transit. Please don't merge until I have the chance to complete it.

@stevepiercy stevepiercy 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.

This is fantastic work. Thank you for your effort. Would you please review my suggestions, and take care? Thank you!

Comment on lines 70 to 71
Component is the base object for calendar, Event and the other
components defined in :rfc:`5545`. Normally you will not use this class

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.

Suggested change
Component is the base object for calendar, Event and the other
components defined in :rfc:`5545`. Normally you will not use this class
Component is the base object for calendar, Event, and the other
components defined in :rfc:`5545`. Normally you won't use this class

Comment thread src/icalendar/cal/lazy.py

All properties of the calendar component are parsed immediately.
Subcomponents and their properties are parsed lazily.
A new calendar starts with no subcomponents.

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.

This is a strange statement, and I don't think it's true in this context. The lazy module is special, in that it lazily parses subcomponents upon initialization. Perhaps @SashankBhamidi or @niccokunzmann can provide a more accurate description of what initialization actually does? Or maybe just remove this statement, as I think the existing description is accurate enough? My Python vocabulary is less proficient than theirs.

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.

Yes, it's true, but it's equally true of a plain Calendar(). The __init__ sets InitialSubcomponentsStrategy, which transitions to LazySubcomponentsStrategy when super().__init__() sets subcomponents = []. The existing description already says what matters. I'd drop the sentence.

Comment on lines +25 to +28
component_factory: Required. The factory to use for creating components.
data: Required. The raw iCalendar data to parse, either as bytes or a
list of content lines.
types_factory: Required. The factory to use for creating property values.

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.

Nice! Thanks for watching the latest update about sorting parameters and adding "Required."

One minor correction from the original.

Suggested change
component_factory: Required. The factory to use for creating components.
data: Required. The raw iCalendar data to parse, either as bytes or a
list of content lines.
types_factory: Required. The factory to use for creating property values.
component_factory: Required. The factory to use for creating components.
data: Required. The raw iCalendar data to parse, either as bytes, string,
or a list of content lines.
types_factory: Required. The factory to use for creating property values.

Comment on lines +96 to +98
Parameters:
name: Required. The name of the subcomponent.
parser: Required. The parser that holds the raw subcomponent data.

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.

Another good improvement. ❤️

Comment thread docs/conf.py
Comment thread src/icalendar/alarms.py
computation.

Examples:
This example uses RFC 9074. One alarm is 30 minutes before the event and

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.

Suggested change
This example uses RFC 9074. One alarm is 30 minutes before the event and
This example uses :rfc:`9074`. One alarm is 30 minutes before the event and

Comment thread src/icalendar/alarms.py
>>> alarms.active[0].trigger # this alarm triggers 15 minutes before 10:30
datetime.datetime(2021, 3, 2, 10, 15, tzinfo=ZoneInfo(key='America/New_York'))

RFC 9074 specifies that alarms can also be triggered by proximity.

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.

Suggested change
RFC 9074 specifies that alarms can also be triggered by proximity.
:rfc:`9074` specifies that alarms can also be triggered by proximity.

Comment thread src/icalendar/alarms.py
Comment on lines +147 to +148
component: An alarm, event, or to-do component with which to start the
computation.

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.

Let's link these to the component class, and rewrap for ruff.

Suggested change
component: An alarm, event, or to-do component with which to start the
computation.
component: An :class:`~icalendar.cal.alarm.Alarm`, :class:`~icalendar.cal.event.Event`, or :class:`~icalendar.cal.todo.Todo` component with which to start the computation.

**kwargs: Keyword arguments passed to :class:`~collections.OrderedDict`.

Example:
Examples:

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.

I see only one example.

Suggested change
Examples:
Example:

Comment thread src/icalendar/error.py
Comment on lines +120 to +121
path: The location in the jCal structure where the error occurred.
parser: The parser class or its name where the error occurred.

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.

Sort. path doesn't look required to me.

Suggested change
path: The location in the jCal structure where the error occurred.
parser: The parser class or its name where the error occurred.
parser: The parser class or its name where the error occurred.
path: The location in the jCal structure where the error occurred.

@Solaris-star Solaris-star left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed — this covers the same ground as my now-closed #1623, and does it more completely. A few observations:

  1. autoclass_content = "class" in docs/conf.py — good catch, I missed this in my version. Without it Sphinx would still try to render __init__ docstrings if any slipped through.

  2. Test placement: putting the AST check in the existing test_docstrings.py is better than a standalone file — keeps all docstring policy tests together.

  3. Required. prefix: consistent with the convention @stevepiercy established in #1603. Nice.

  4. One minor note: the test uses Path(icalendar.__file__).parent which resolves correctly for installed packages, but if someone runs tests from a source checkout without installing, the path still works since icalendar.__file__ points to the source tree. No issue, just confirming I checked.

  5. The news fragment is present — my #1623 was missing that. Lesson learned.

Happy to help with any follow-up on this if needed.

@SashankBhamidi SashankBhamidi 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 Felix. I ran the new test against main and confirmed it fails there.

Steve's suggestions are all still open. One more thing inline.

Procedural note: if any part of this was AI-assisted, please follow the Responsible AI use policy. Standard reminder.

Comment thread src/icalendar/alarms.py
Comment on lines +51 to +52
parent: The parent component to which the alarm refers.
snoozed_until: A datetime in UTC until which the alarm has been snoozed.

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 parameter order in the docstring doesn't match the signature. The __init__ signature (line 60) has snoozed_until before parent, but the docstring has them reversed. Parameters should follow signature order.

Suggested change
parent: The parent component to which the alarm refers.
snoozed_until: A datetime in UTC until which the alarm has been snoozed.
snoozed_until: A datetime in UTC until which the alarm has been snoozed.
parent: The parent component to which the alarm refers.

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.

Actually, we changed this in https://icalendar.readthedocs.io/en/latest/contribute/documentation/style-guide.html#docstring-structure. Alphabetically sorted within each group of required and optional parameters is correct.

Comment thread src/icalendar/cal/lazy.py

All properties of the calendar component are parsed immediately.
Subcomponents and their properties are parsed lazily.
A new calendar starts with no subcomponents.

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.

Yes, it's true, but it's equally true of a plain Calendar(). The __init__ sets InitialSubcomponentsStrategy, which transitions to LazySubcomponentsStrategy when super().__init__() sets subcomponents = []. The existing description already says what matters. I'd drop the sentence.

@SashankBhamidi

Copy link
Copy Markdown
Member

Hi @felix-windsor, could you take care of the conflicts please? Let us know if you need any support from our side.

@niccokunzmann

Copy link
Copy Markdown
Member

Uh. Yes, that is a problem when creating a big PR on an active repository. @felix-windsor Your contribution is welcome and I hope to see it go through. If you like, create smaller PRs for the changes and they have less merge work in them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-suspicion This contribution is possibly created with lots of AI help without enough human understanding. doc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Merge __init__ or __new__ docstrings into their class's docstring

6 participants