8000 Add type hint annotations to `astropy.units.physical` by namurphy · Pull Request #15914 · astropy/astropy · GitHub
[go: up one dir, main page]

Skip to content

Add type hint annotations to astropy.units.physical#15914

Closed
namurphy wants to merge 1 commit intoastropy:mainfrom
namurphy:units-physical-types-annotations
Closed

Add type hint annotations to astropy.units.physical#15914
namurphy wants to merge 1 commit intoastropy:mainfrom
namurphy:units-physical-types-annotations

Conversation

@namurphy
Copy link
Contributor
@namurphy namurphy commented Jan 18, 2024

Description

This pull request adds type hint annotations to astropy.units.physical.

It's only a first draft so far since I haven't checked it with mypy at all. I may add some type hints to the corresponding tests too while I'm at it.

It'd be fine to squash this PR.

@github-actions github-actions bot added the units label Jan 18, 2024
@github-actions
Copy link
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?
  • Is a milestone set? Milestone must be set but we cannot check for it on Actions; do not let the green checkmark fool you.
  • 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.

@github-actions
Copy link
Contributor

👋 Thank you for your draft pull request! Do you know that you can use [ci skip] or [skip ci] in your commit messages to skip running continuous integration tests until you are ready?

Copy link
Member
@nstarman nstarman left a comment

Choose a reason for hiding this comment

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

👍

__all__ = ["def_physical_type", "get_physical_type", "PhysicalType"]

_units_and_physical_types = [
_units_and_physical_types : list[tuple(u.UnitBase, str | set(str))] = [
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
_units_and_physical_types : list[tuple(u.UnitBase, str | set(str))] = [
_units_and_physical_types : list[tuple[u.UnitBase, str | set[str]]] = [


@staticmethod
def _dimensionally_compatible_unit(obj):
def _dimensionally_compatible_unit(obj: object) -> u.UnitBase | NotImplemented: # ???
Copy link
Member

Choose a reason for hiding this comment

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

this is a good place for typing.overload.

Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as for __eq__ - I think we'd want the type information to tell what gives success, not what gives failure, where for this function failure means getting NotImplemented.

Note that I really worry about "this is a good place for typing.overload - if we are adding more than annotations, suddenly files can become like this

    # Builtin types
    @overload
    def __new__(cls, dtype: type[builtins.bool], align: builtins.bool = ..., copy: builtins.bool = ..., metadata: dict[builtins.str, Any] = ...) -> dtype[np.bool]: ...
    @overload
    def __new__(cls, dtype: type[int], align: builtins.bool = ..., copy: builtins.bool = ..., metadata: dict[builtins.str, Any] = ...) -> dtype[int_]: ...
    @overload
    def __new__(cls, dtype: None | type[float], align: builtins.bool = ..., copy: builtins.bool = ..., metadata: dict[builtins.str, Any] = ...) -> dtype[float64]: ...
    @overload
    def __new__(cls, dtype: type[complex], align: builtins.bool = ..., copy: builtins.bool = ..., metadata: dict[builtins.str, Any] = ...) -> dtype[complex128]: ...
    @overload
    def __new__(cls, dtype: type[builtins.str], align: builtins.bool = ..., copy: builtins.bool = ..., metadata: dict[builtins.str, Any] = ...) -> dtype[str_]: ...
    @overload
    def __new__(cls, dtype: type[bytes], align: builtins.bool = ..., copy: builtins.bool = ..., metadata: dict[builtins.str, Any] = ...) -> dtype[bytes_]: ...

Can we pretty please agree that overload has no place in regular python code files?

return new_unit.physical_type

def __mul__(self, other):
def __mul__(self, other: object) -> Self | NotImplemented:
Copy link
Member

Choose a reason for hiding this comment

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

The standard is actually to not put NotImplemented into the type hint of dunder methods.

Copy link
Contributor

Choose a reason for hiding this comment

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

Bit of a flyby, as I was just looking how the typing "looks": these ones seem rather superfluous; are there not some standard defaults for dunder operations like these?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mhvk — that is a great question that I do not know the answer to! I think that static type checkers like mypy still need type hints in order to check dunder methods, but I'm not sure.

When adding type hints to plasmapy.particles, I was able to use autotyping to automatically add type hints for dunder methods, which was pretty straightforward.

Copy link
Contributor

Choose a reason for hiding this comment

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

See comment about __eq__ - it seems much more logical to me to put here things that allow __mul__ to succeed.

yield from self._physical_type_list

def __eq__(self, other):
def __eq__(self, other: object) -> bool:
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be

Suggested change
def __eq__(self, other: object) -> bool:
def __eq__(self, other: PhysicalType | str) -> bool:

Copy link
Member

Choose a reason for hiding this comment

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

It's valid to do PhysicalType() == 4, which will return False after trying 4.__req__().

Copy link
Contributor

Choose a reason for hiding this comment

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

Unresolving this, since I think @eerovaher's comment is actually relevant: isn't typing supposed to tell what is needed to make this function succeed? With PhysicalType|str, that is clear, with object you get zero information.

I guess for these dunder methods, it depends on what you mean by "succeed" - I'd argue that returning NotImplemented is a form of not succeeding, since if the reverse also does it, you get a TypeError. More generally, that the reverse is called is irrelevant for thinking about success of this function.

Copy link
Member
@nstarman nstarman Jan 24, 2024

Choose a reason for hiding this comment

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

See https://discuss.python.org/t/make-type-hints-for-eq-of-primitives-less-strict/34240/10 for a discussion where people are advocating for making typing dunder methods less strict. The typing of most dunder methods is limited by inheritance from "object". Currently the correct annotation for equality is __eq__(self, other: object) -> bool. Not annotating the return type of NotImplemented is problematic but baked into Python ATM. Accepting any input is correct since evaluating an equality to False is a valid output, even if it happens from a double NotImplemented behind-the-scenes.

Copy link
Member
@nstarman nstarman Jan 24, 2024

Choose a reason for hiding this comment

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

Having other be restricted only makes sense if the method errors or doesn't work on that input. __eq__ et al work, returning NotImplemented / False.

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand the logic, but it is not a useful one to humans or much in the spirit of what NotImplemented means - I'd say we don't annotate these until the discussion has concluded.

# standard physical types defined here.
if __doc__ is not None:
doclines = [
doclines: list[str] = [
Copy link
Member

Choose a reason for hiding this comment

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

Why does this need an annotation?



def get_physical_type(obj):
def get_physical_type(obj: object) -> PhysicalType:
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems good to have QuantityLike and PhysicalTypeLike defined, use it here.

Copy link
Member

Choose a reason for hiding this comment

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

👍 on using a type alias PhysicalTypeLike. This is again driven by use of type annotations as developer docs, not trying to please mypy. Whether PhysicalTypeLike tries to enumerate all the possibilities or if it is just an empty type alias makes no difference to me, but seeing that while developing code is very useful.

Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed, and I like that those can be stored in a types.py file, so one can fiddle with those definitions without having to change how the code itself looks.

@astrofrog astrofrog modified the milestones: v6.1.0, v7.0.0 Apr 4, 2024
@mhvk mhvk added the typing related to type annotations label May 30, 2024
@github-actions github-actions bot added the Close? Tell stale bot that this issue/PR is stale label Jun 17, 2024
@github-actions
Copy link
Contributor

Hi humans 👋 - this pull request hasn't had any new commits for approximately 4 months. I plan to close this in 30 days if the pull request doesn't have any new commits by then.

In lieu of a stalled pull request, please consider closing this and open an issue instead if a reminder is needed to revisit in the future. Maintainers may also choose to add keep-open label to keep this PR open but it is discouraged unless absolutely necessary.

If this PR still needs to be reviewed, as an author, you can rebase it to reset the clock.

If you believe I commented on this pull request incorrectly, please report this here.

@github-actions github-actions bot added the closed-by-bot Closed by stale bot label Jul 18, 2024
@github-actions
Copy link
Contributor

I'm going to close this pull request as per my previous message. If you think what is being added/fixed here is still important, please remember to open an issue to keep track of it. Thanks!

If this is the first time I am commenting on this issue, or if you believe I closed this issue incorrectly, please report this here.

@github-actions github-actions bot closed this Jul 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Close? Tell stale bot that this issue/PR is stale closed-by-bot Closed by stale bot no-changelog-entry-needed typing related to type annotations units

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

0