Skip to content

TYP: add typing information - #8

Draft
nstarman wants to merge 1 commit into
astropy:mainfrom
nstarman:typing
Draft

TYP: add typing information#8
nstarman wants to merge 1 commit into
astropy:mainfrom
nstarman:typing

Conversation

@nstarman

Copy link
Copy Markdown
Member

No description provided.

@nstarman nstarman changed the title WIP TYP: add typing information Nov 27, 2024

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

Looks quite good! Some suggestions in-line. I can push some of those, but before doing so, an idea may be to set up pre-commit in a separate PR (without mypy), just to keep review easier.

Comment thread quantity/core.py Outdated
array_api_compat.array_namespace(arg)
except TypeError:
return False
else:

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.

Can we turn off the rule that removes this else - it is more readable to keep it!

Comment thread quantity/_quantity_api.py


@runtime_checkable
class ArrayQuantity(Quantity, Array, Protocol):

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.

QuantityArray may be better?

More relevantly, for my own understanding, an isinstance will check that something has the value and unit atttributes, that those are of the right type, and adds to Quantity that it will also check that the something itself is array-like (i.e., has __array_namespace__), right?

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.

that those are of the right type

I don't think that's included in "runtime checkable" protocols.

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.

Yeah, unfortunately not.

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.

Well, at some level that makes things easy, in that basic Quantity operations will just work with float values.

Comment thread quantity/core.py

def _make_comp(comp):
def __comp__(self, other):
def _make_comp(comp: str) -> Callable[[Quantity, Any], Array]:

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.

Should be Union[Array | NotImplementedType], no?

Comment thread quantity/core.py
def _make_comp(comp):
def __comp__(self, other):
def _make_comp(comp: str) -> Callable[[Quantity, Any], Array]:
def _comp_(self: Quantity, other: Any) -> Array | NotImplementedType:

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.

Don't mind changing it at all, but if we do, probably nicer to change __op__ above too.

Comment thread quantity/core.py
else:
try:
exp = exp.__complex__()
out = complex(exp)

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.

This is not the same! E.g., complex("1+1j") works, but we don't want to support 2**"1+1j"

Comment thread quantity/core.py

def __array_namespace__(self, *, api_version: str | None = None) -> Any:
# TODO: make our own?
del api_version

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.

Why is this needed? Can one not add something like Unused[str | None] ... checking, I see that this was suggested at python/typing#1499 but not liked; instead a relevant noqa to get the linter happy was suggested. That does seem nicer.

Comment thread quantity/core.py

def _operate(self, other, op, units_helper):
def _operate(
self, other: Any, op: Any, units_helper: Any

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 think op and units_helper can be

op: str, units_helper: Callable[[Unit, Unit], tuple[list[Callable | None, Callable | None], Unit | None]]

Not sure I did the second one right, but it takes 2 units and returns a list of two converters or None and a final unit or None. Maybe worth defining separately? The general helper could have arbitrary number of units, with the output having the same number of converters.

Comment thread quantity/core.py
exp = _check_pow_args(exp, mod)
if exp is NotImplemented:
def __pow__(self, exp: Any, mod: Any = None) -> Self | NotImplementedType:
if (mod := _parse_pow_mod(mod)) is NotImplemented:

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 like the symmetry of the parsing, but maybe we should just go for

if mod is not None:
    return NotImplemented

(and then perhaps overload __pow__ itself??)

Comment thread quantity/core.py
if (mod := _parse_pow_mod(mod)) is NotImplemented:
return NotImplemented

if (exp := _check_pow_exp(exp)) is NotImplemented:

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.

This is a nice improvement.

Comment thread quantity/core.py
def __ipow__(self, exp, mod=None):
exp = _check_pow_args(exp, mod)
if exp is NotImplemented:
if (mod := _parse_pow_mod(mod)) is NotImplemented:

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.

As above.

@nstarman
nstarman force-pushed the typing branch 2 times, most recently from 60f06ed to 79d4f22 Compare December 3, 2024 16:51
Comment thread pyproject.toml
warn_unused_configs = true

[[tool.mypy.overrides]]
module = ["quantity._dev.*", "quantity.tests.*"]

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.

Just a bit of a flyby - cool to see the mypy setup! But this is out of date - test has moved now (and another reason why that is good!)

@nstarman

nstarman commented Dec 8, 2024

Copy link
Copy Markdown
Member Author

Agreed! I think this PR will serve only as reference for a few equivalent PRs.

Signed-off-by: nstarman <nstarman@users.noreply.github.com>
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.

3 participants