Skip to content

Avoid stringified type annotations in units - #18329

Merged
mhvk merged 1 commit into
astropy:mainfrom
eerovaher:runtime-type-imports-units
Aug 25, 2025
Merged

mhvk merged 1 commit into
astropy:mainfrom
eerovaher:runtime-type-imports-units

Conversation

@eerovaher

Copy link
Copy Markdown
Member

Description

Sphinx is known to have problems resolving stringified annotations, so it's best to avoid them whenever possible. In units it is not possible to avoid stringified annotations entirely because of circular imports, but it was nonetheless possible to remove if TYPE_CHECKING: blocks from all but two modules. Moving the definitions of UnitBase and PhysicalType was necessary for minimizing the number of forward references, but that makes the diff look huge. I recommend the reviewers first move UnitBase and PhysicalType definitions in their local repositories and then compare the resulting working tree with the branch here. That way the amount of code changes should be quite manageable.

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

@eerovaher eerovaher added this to the v7.1.1 milestone Jun 20, 2025
@eerovaher
eerovaher requested review from mhvk and nstarman June 20, 2025 21:52
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

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

I rearranged stuff as suggested, and the diff looks good.
PEP 649 is going to clean up all the stringified annotations in py 3.13+ but overall there are actually now fewer such annotations because of the removal of from __future__ import annotations.

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

Yes, looks good. It slightly breaks having required functions defined before their use, but on balance for UnitBase it is also nice that it gets defined earlier.

For PhysicalType, though, perhaps still after the definitions? (see in-line)

Also, one question just to be sure: currently, inside the UnitBase definition, for typing still "UnitBase" is used. Is it really necessary to even stringify the name of the class being defined? It seems in this case it is not a forward reference, so should be OK. (Though perhaps the class needs to actually have been completely defined.) Anyway, just in case -- you probably checked this already!

Comment thread astropy/units/physical.py Outdated
__array__: Final = None


_units_and_physical_types: Final[list[tuple[core.UnitBase, str | set[str]]]] = [

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.

I'd have a slight preference for keeping this list on top, since it is the thing one needs to edit if a new physical type is added. Since it doesn't include PhysicalType anywhere, presumably that should not affect anything.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It would be best if the physical types definitions and machinery were in separate modules and I even have a pull request to make that change, but it's stuck because I can't figure out how to make the API docs build without warnings. I don't see much value in moving these definitions within this module unless we entirely give up the idea of having separate modules.

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.

It would be best if the physical types definitions and machinery were in separate modules

Agreed.

I even have a pull request to make that change

🎉

but it's stuck because I can't figure out how to make the API docs build without warnings

Sounds familiar.

I don't see much value in moving these definitions within this module unless we entirely give up the idea of having separate modules.

I think it's about keeping aspects of the current pre-PR layout.

@eerovaher

Copy link
Copy Markdown
Member Author

Also, one question just to be sure: currently, inside the UnitBase definition, for typing still "UnitBase" is used. Is it really necessary to even stringify the name of the class being defined? It seems in this case it is not a forward reference, so should be OK. (Though perhaps the class needs to actually have been completely defined.) Anyway, just in case -- you probably checked this already!

It is necessary and it is not specific to annotations:

Python 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:
...     a = A
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in A
NameError: name 'A' is not defined

@nstarman

Copy link
Copy Markdown
Member

@eerovaher if you rebase, let's get this in.

Sphinx is known to have problems resolving stringified annotations, so
it's best to avoid them whenever possible. In `units` it is not possible
to avoid stringified annotations entirely because of circular imports,
but it was nonetheless possible to remove `if TYPE_CHECKING:` blocks
from all but two modules. Moving the definitions of `UnitBase` and
`PhysicalType` was necessary for minimizing the number of forward
references.
@eerovaher
eerovaher force-pushed the runtime-type-imports-units branch from e73f3b3 to 983beb3 Compare August 25, 2025 13:34
@mhvk mhvk modified the milestones: v7.1.1, v7.2.0 Aug 25, 2025
@mhvk

mhvk commented Aug 25, 2025

Copy link
Copy Markdown
Contributor

OK, thanks, let's get it in! Note, though, that to me this change seems to invasive for backporting (even if functionally nothing changes), so I removed that. If we decide that was wrong, we could still backport manually.

@mhvk
mhvk merged commit 6b9d2f7 into astropy:main Aug 25, 2025
@eerovaher
eerovaher deleted the runtime-type-imports-units branch August 25, 2025 16:29
@eerovaher

Copy link
Copy Markdown
Member Author

Downstream has already reported documentation build failures caused by stringified annotations (#18221), so not backporting is irresponsible.

@mhvk

mhvk commented Aug 25, 2025

Copy link
Copy Markdown
Contributor

OK, fair enough. Fine to backport with a fixes #18221 line.

@pllim pllim modified the milestones: v7.2.0, v7.1.1 Aug 25, 2025
@pllim

pllim commented Aug 25, 2025

Copy link
Copy Markdown
Member

@meeseeksdev backport to v7.1.x

@lumberbot-app

lumberbot-app Bot commented Aug 25, 2025

Copy link
Copy Markdown

Owee, I'm MrMeeseeks, Look at me.

There seem to be a conflict, please backport manually. Here are approximate instructions:

  1. Checkout backport branch and update it.
git checkout v7.1.x
git pull
  1. Cherry pick the first parent branch of the this PR on top of the older branch:
git cherry-pick -x -m1 6b9d2f7b7b91efaa65a94348c33c6d0ef8a02f3a
  1. You will likely have some merge/cherry-pick conflict here, fix them and commit:
git commit -am 'Backport PR #18329: Avoid stringified type annotations in `units`'
  1. Push to a named branch:
git push YOURFORK v7.1.x:auto-backport-of-pr-18329-on-v7.1.x
  1. Create a PR against branch v7.1.x, I would have named this PR:

"Backport PR #18329 on branch v7.1.x (Avoid stringified type annotations in units)"

And apply the correct labels and milestones.

Congratulations — you did some good work! Hopefully your backport PR will be tested by the continuous integration and merged soon!

Remember to remove the Still Needs Manual Backport label once the PR gets merged.

If these instructions are inaccurate, feel free to suggest an improvement.

@pllim

pllim commented Aug 25, 2025

Copy link
Copy Markdown
Member

Re: #18329 (comment)

  1. Please manually backport (auto backport failed)
  2. Add fixes #18221 in PR description as @mhvk suggested above
  3. Add @rosteen as reviewer of that backport PR you will open to ensure that the backport really would fix the issue mentioned in Step 2

Thank you!

eerovaher pushed a commit to eerovaher/astropy that referenced this pull request Aug 26, 2025
The backport is required to prevent/solve problems analogous to those
reported in astropy#18221.
mhvk added a commit that referenced this pull request Aug 26, 2025
Backport PR #18329 on branch v7.1.x (Avoid stringified type annotations in units)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants