Repository navigation
ci: mypy config - #16312
ci: mypy config#16312nstarman wants to merge 4 commits into
Conversation
|
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.
|
|
|
||
|
|
||
| [tool.mypy] | ||
| python_version = "3.10" |
There was a problem hiding this comment.
Is the leading whitespace necessary? I don't see that in the other sections.
| python_version = "3.10" | |
| python_version = "3.10" |
There was a problem hiding this comment.
hm. good point. I think @WilliamJamieson had a PR about improving our pyproject.toml layout... The leading space allows for section folding in IDEs.
There was a problem hiding this comment.
We definitely don't have any formal style for our pyproject.toml file. E.g.
[tool.coverage]
[tool.coverage.run]
is different than our ruff config, where the subsection-that's-actually-a-section isn't indented.
There was a problem hiding this comment.
Not that I'm advocating for style anarchy. Actually it would be better to have a linter integrated with pre-commit that takes care of all these concerns for us...
There was a problem hiding this comment.
Why does that sound so familiar? I am surprised it has not been done already by now.
There was a problem hiding this comment.
@namurphy, given PlasmaPy/PlasmaPy#1868, do you have any suggestions?
There was a problem hiding this comment.
I've had good experiences with pyproject-fmt, so much so that I forgot we'd added that hook! I'd suggest using a linter specific to pyproject.toml because checks against standard schemas for different configurations are likely to be either present already or added in the future, and these checks could potentially find configuration problems.
There was a problem hiding this comment.
Have you found a way to prevent pyproject-fmt from alphabetizing your toml? Or since the TOML is so rarely looked at, do you just let it alphabetize?
There was a problem hiding this comment.
Correction: it appears PlasmaPy doesn't use pyproject-fmt anymore. I just tried adding it back to PlasmaPy's pre-commit configuration, and in addition to the sorting, it also removed comment-only lines (tox-dev/pyproject-fmt#16). Since there are times when it really helps to have comment-only lines, we won't be able to use it until it's resolved...
There was a problem hiding this comment.
Thanks @namurphy for the info!
FYI for readers of this thread, I've resolved the whitespace inconsistencies manually. So this thread is resolved, even if the discussion for future improvements is ongoing!
eerovaher
left a comment
There was a problem hiding this comment.
units is a major bottleneck for type checking astropy, so I would rather not introduce any project level type checker configuration until units has been decently annotated. Adding annotations (anywhere, not just in units) to help with IDE tab-completion can be useful already, but that does not require configuring a type checker.
| [[tool.mypy.overrides]] | ||
| module = [ | ||
| "astropy/logger", | ||
| "astropy/_erfa/*", | ||
| "astropy/config/*", | ||
| "astropy/conftest", | ||
| "astropy/constants/*", | ||
| "astropy/convolution/*", | ||
| "astropy/coordinates/*", | ||
| "astropy/cosmology/*", | ||
| "astropy/extern/*", | ||
| "astropy/io/*", | ||
| "astropy/modeling/*", | ||
| "astropy/nddata/*", | ||
| "astropy/samp/*", | ||
| "astropy/stats/*", | ||
| "astropy/table/*", | ||
| "astropy/tests/*", | ||
| "astropy/time/*", | ||
| "astropy/timeseries/*", | ||
| "astropy/uncertainty/*", | ||
| "astropy/units/*", | ||
| "astropy/utils/*", | ||
| "astropy/version", | ||
| "astropy/visualization/*", | ||
| "astropy/wcs/*", | ||
| ] | ||
| ignore_errors = true |
There was a problem hiding this comment.
Very few maintainers have expressed any interest in adding type annotations and the number of people that have expressed interest in type checking astropy is even lower. It seems better to require sub-packages to explicitly opt in to type checking instead of setting files = ["astropy/**/*.py"] and then explicitly opting sub-packages out.
There was a problem hiding this comment.
A consideration here is whether we want subpackages that get added to Astropy in the future to be type checked with mypy by default. Because adding type hints is significantly easier when writing code for the first time, my inclination would be to set it so that new subpackages do get type checked by default. But, this consideration would only matter if any subpackages might be added in the next few years.
There was a problem hiding this comment.
A consideration here is whether we want subpackages that get added to Astropy in the future to be type checked with mypy by default.
Unlikely we will have a new subpackage anytime soon (but never say never). When we do though, it is usually already an existing code/package. To require typing right off the bat would be a deal breaker. So 👎 from me.
There was a problem hiding this comment.
Because adding type hints is significantly easier when writing code for the first time, my inclination would be to set it so that new subpackages do get type checked by default.
It is true that type checking is simpler if it is done from the very beginning, but we can't demand that from new sub-packages without an APE.
There was a problem hiding this comment.
Agreed that new sub-packages in principle new sub packages can be more easily typed, but in practice are unlikely to be given their origins from other sources.
Very few maintainers have expressed any interest in adding type annotations and the number of people that have expressed interest in type checking astropy is even lower. It seems better to require sub-packages to explicitly opt in to type checking ...
I think the picture is more complicated. It's true that few maintainers have wanted to add type annotations and fewer have started, but what's also true is that many users want it. (I have plenty of colleagues that have told me that they struggle to use Astropy for a few reasons and for many of them a significant one is because they aren't overly interested in programming and just want to get the job done and have justifiably gotten really used to the way that modern IDEs can surface information from type annotations and help do argument-by-argument completion of functions and classes. It just works. I know that I'm super used to it and am less-than-thrilled when I use a library that makes me dig around for the information. I'm looking at you jax.experimental.array_api with your lack of type annotations and docstrings). The bar for good, helpful user-facing code has been raised. So while it's true that few maintainers are doing anything, I think that reflects a failing on our part, not a reason to structure Astropy's config.
That being said, in its current form this PR is exactly equivalent to not opting in for any sub-package. And it will basically remain so for a while. The crucial difference between adding an opt-in list versus an opt-out list is that an opt-out list is a visible reminder of what remains to be done for Astropy to be more performant, have fewer bugs, and be more user friendly. I'm hoping that utils and cosmology and units will be some of the first libraries to remove themself from the opt-out list. I know users will appreciate it.
@eerovaher you are doing an excellent job adding type hints and other than my thanks right now, it's probably a mostly thankless task. Thank you for your work on utils.
There was a problem hiding this comment.
We should indeed add type annotations that are helpful for IDE tab-completion, but that does not require configuring a type checker.
Ideally type checking would be helpful for developers, but in practice whenever I try to use mypy in astropy I immediately get overwhelmed by warnings from units and that is not helpful.
There was a problem hiding this comment.
We should indeed add type annotations that are helpful for IDE tab-completion, but that does not require configuring a type checker.
We do need to test the type annotations. RN the ones we are adding are completely untested. They look right...
There was a problem hiding this comment.
The complexity and rigor of annotations that are required to satisfy type checkers is much higher than what can be useful for IDE tab-completion. I know that some of the annotations I've written are oversimplified so that a type checker will (rightfully) complain about them, but I still wrote them that way because having good return type annotations is helpful for IDEs even if some of the parameter annotations are sloppy. Furthermore, my expectation is that it will be simpler to start using a type checker when the fraction of annotated code is larger because then the checker should be able to point out more precisely what needs to be changed to make it happy.
I don't want us to end up in a situation where the few people that are adding annotations have to spend more time adding exceptions to the type checker configuration than they would spend on adding annotations themselves. And if early on our approach is to ignore (almost) every type violation then we can do that without writing anything down.
There was a problem hiding this comment.
I feel like type hints too often take 100% of our focus in these discussions, when in fact they're not the only reason to use a type checker, so let me give a different perspective. Personally, the main reason I'd want to see astropy starting to use a type checker is that it'd enable using constructs from the typing module that are essentially declarations of intention which don't have any effect at runtime, like final, Final, override, overload, assert_never1, Protocol or ReadOnly (new in Python 3.13). To me, these are the real game changers and they are the part the typing language that actually allows me to detect and fix defects through a type checker, but of course type hints play a big part in enabling this too. I'm not saying that type hints don't help finding bugs too (they do !), but in my experience they're higher cost, lower rewards in that area.
Footnotes
-
this one is not a no-op at runtime ↩
There was a problem hiding this comment.
@neutrinoceros, a good point! I use Protocol all the time, and TypedDict, and other useful runtime-features. override is also such a nice addition to typing.
|
I very much like this PR! Thank you for doing it, and to everyone else for their feedback and work towards adding type hints! The approach taken here is a much better idea than the prototype I experimented with in #15794... 😮💨 The mypy docs contain a guide on using mypy with an existing codebase, which I've found to be incredibly helpful for PlasmaPy. This PR implements two of the recommendations from this guide:
[The guide also recommends adding mypy to CI as soon as possible, which made the process of adding type hints to PlasmaPy significantly easier! But that's out-of-scope here and may be best discussed in https://github.com/astropy/astropy-APEs/pull/94, which I'm hoping to get back to one of these megaseconds... ⌚] |
|
@eerovaher, you wrote a good post about the levels of typing we want to do as a package. |
|
It's not clear to me who is supposed to maintain type checker configuration and how. Adding exceptions to every type checking error or warning doesn't sound very helpful, even if it is done on per-file and per-error basis. It is much simpler to ignore type checking by not running a type checker at all. An alternative that could be useful would be to try to address type checking errors as they are revealed, but no one has done that so far. Is anyone planning to start doing that? Maybe they should start by opening a pull request where they could post the type checker configuration that they used, and then we could evaluate if the improvements this enables are worth the effort.
A pull request that adds annotations to some set of functions that are useful for IDE tab-completion has no effect on the tab-completion of any other functions. This means that functions can be annotated independently from each other and project-level coordination is not required. Type checking is very different because adding annotations to one function could cause new type checking warnings in other functions, modules or even sub-packages, especially early on when the amount of annotated code is still very small. It seems to me type checking needs project-level commitment, or at least commitment from the key sub-packages such as
Addressing a Ruff rule violation does not cause brand new violations to appear in unedited code, but editing type annotations can cause brand new type checking violations in unedited code. So the ignores in |
|
Is type-checking on the list of topics to be discussed at the Coordination Meeting yet ? it sounds more and more like it should be. |
|
Does this count? astropy/astropy-project#349 (comment) |
|
Thanks ! I missed it ! |
|
We should probably make sure that at least the big picture aspect of typing is discussed as a plenary just to make sure everyone is on the same page. |
8f6ce05 to
b85a9f5
Compare
mhvk
left a comment
There was a problem hiding this comment.
Saw this again as it had changed. I think it would be good to have some basic setup ready, so that people who want to run mypy to check things can do so. Since we're not actually using it ourselves properly yet, is it an idea to work a bit like ruff, where we use the "standard" location mypy.ini (or maybe .mypy.ini to keep it hidden by default) and move things over to pyproject.toml as they mature?
eerovaher
left a comment
There was a problem hiding this comment.
If we adopt follow_imports = "skip" and start adding annotations one file at time then this configuration could indeed be useful. But I agree with @mhvk that the configuration should not be in pyproject.toml yet, not until we are actually type checking in CI, and I would also prefer if type checking would be opt-in (by adding entries to files) instead of opt-out (by adding entries to mypy.overrides). The fraction of annotated code will remain very small in the foreseeable future.
SGTM.
True, but IMO that's not the rationale for having an opt-out list rather than an opt-in one. The reasons are:
|
|
If the opt-out approach is more popular then I can accept it. There's a few files that we could start type checking already (with these settings, and locally, not in a CI job). Should we discuss that here? |
Seems appropriate! We should get the mypy settings correct. |
|
In addition to what @neutrinoceros already said it should also be pointed out that normally Mypy should be configured to check at least one file. There are two reasons for this. The first is that it would provide an example how to unignore files. The second is that type checking anything in |
| show_error_codes = true | ||
| # TODO: temporary | ||
| ignore_missing_imports = true | ||
| follow_imports = skip |
There was a problem hiding this comment.
I've found silent to be more useful than skip. From what I can tell silent helps ensure that the annotations are self-consistent (although it cannot check if the annotations are consistent with unannotated code), but skip does not check self-consistency.
|
Sorry to be a bummer but I'm having second thoughts about the choice of mypy as our base type-checker; specifically, with the launch of numpy 2.2, which made great strides in the typing area, it became clear to me that relying solely on mypy to type check numpy-based code is problematic:
but perhaps a more convincing point is that mypy is explicitely called out as buggy in numpy 2.2's release notes, where we also find that their recommended type checker is actually |
|
To a non-typing type like me, the advantage of mypy has always been the speed-up promised by mypyc... |
|
I don't think I ever heard of any project leveraging both mypyc and numpy together, so I'm skeptical about the existence of that possibility as far as astropy is concerned (but happy to be proven wrong !). |
|
@nstarman and I have been thinking that for the units machinery it might be quite useful - that of course is pure python right now (i.e., calculating the conversion functions, etc.). |
|
This doesn't exclude basedpyright, which is stricter than mypy and corrects a few mistakes/ambiguties. For most cases, what passes one passes the other. Areas we want to target with mypyc must pass mypy and should pass basedpyright. If we want to start with basedpyright, which SGTM, why don't you open a PR to get it started. Then we can change this PR to target only specific modules / files. |
Sounds interesting, I'm curious to see the outcome !
True, though it seems hard enough for us to start using one typechecker, I'm worried we might never get a second chance.
yes, but I'd like to highlight that it doesn't take much to run into some correct numpy code that mypy will choke on (either by incorrectly reporting an error or by not applying type narrowing even when it's possible), but pyright will thrive.
I'd be happy to, but don't have plans for doing this at the moment, and I'm not sure I can commit to it for the time being so please do not wait on this bit. I realize that I'm being a bit more negative than constructive here. The point I want to get across is: mypy might not work for our needs, and the sooner we acknowledge this possibility, the less painful it'll be if we eventually need to switch to something else. |
|
I am not at all worried about potential incompatibilities between Mypy and NumPy. The difficulties I am encountering when trying to make the code (mostly |
|
So far, mostly we've added code annotations, which are useful even if they may contain (minor, hopefully) typing errors. But #17902 proposes to add ~100KiB worth of automatically generated stub files for |
|
Agreed. This PR has gotten a bit away from me, in part because when mypy errors, it sometimes just catastrophically crashes, which is what is happening here. Debugging has proven onerous. |
|
I've personally found mypy to be challenging to configure (see PlasmaPy's The documentation page on using mypy with an existing codebase contains a lot of general advice that has made my life significantly easier whilst enabling static type checking. |
|
I've been using (based)pyright for a couple months now, I can look into setting it up for astropy.units tomorrow. |
|
update: #17918 👀 |
|
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. |
|
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. |
A redo of #12971 now that we have
typing!This PR provides a
mypyconfiguration where all folders are ignored.As a sub-package adds type hints the module may be removed from the top
[[tool.mypy.overrides]]that ignores all errors and sub-package specific settings added in a new[[tool.mypy.overrides]], below.e.g.
Non-goals
decide where type hints will be stored: in the code, or as type stubs in a separate directory.This is resolved.Goals
have a quality setup that:
works for either type hint location.This is resolvedWith this PR, @namurphy's PRs for tox and CI can proceed.