Make typing_extensions an (optional?) astropy dependency #10689
Description
Question
How should Astropy implement typing?
What is the timeline?
What Infrastructure needs to be built to enable this? e.g. mypy checker in test suite or submissions to python's type-shed.
OLD Description
See #10662
The python typing library is under active development and new and useful features are not available for py3.6-3.8. The typing_extensions library is now the official backport for all these types and is even developed within the main body of python (though offered as a separate install) — see https://github.com/python/typing/tree/master/typing_extensions.
As astropy moves to add static typing, the extended types options, in addition to the guaranteed stability and long-term support, would make this a useful and safe dependency.
I'm making this an issue, not PR, because I know how contentious adding new dependencies can be.
Edit: this would probably not be a permanent additional dependency since the features in typing_extension all become core python. When new features stop being added regularly and our python minveraion catches up, this can be dropped.
Edit: Now suggesting as an OPTIONAL dependency
Activity
[-]Make `typing_extensions` an astropy dependency[/-][+]Make [typing_extensions](https://pypi.org/project/typing-extensions) an astropy dependency[/+][-]Make [typing_extensions](https://pypi.org/project/typing-extensions) an astropy dependency[/-][+]Make `typing_extensions` an astropy dependency[/+]dhomeier commentedon Aug 29, 2020
Could you clarify which (especially non-experimental) features it would actually add for newer Python versions? The project page primarily discusses 3.4-3.6, and those alone might weaken the case a bit, since the schedule for dropping 3.6 support is already under discussion.
nstarman commentedon Aug 29, 2020
What I meant was that there are a number of types which are py3.7+ or py3.8+ or even py3.9+. Until our minimum version is 3.9, then not all the static type will be available.
To me personally, the most useful are:
Annotatedtype (py3.9+ intyping) which allows for metadata to be associated with static types. This would have immediate use in add unit-aware quantity annotations. #10662 and also be applicable to the annotations in the Modeling module.Literal(py3.8+) which indicates a value equivalent to the literal, for instancemeans
x=a or b.get_args(py3.8+) for breaking apartUnionandAnnotatedtypesAlso useful are:
@runtime_checkable(py3.8+) for a custom class to be used withisinstanceand as a static type check.Protocoltype (py3.8+) enables structural subtyping.OrderedDictfor annotating all the ordered descriptors in astropyTypedDict(py3.8+) for dictionaries that must contain a certain set of keys, like howBaseCoordinateFramesare implemented.Final(py3.8+) to prevent subclasses from changing a value. This will be useful all over the place, to annotate protected attributes without having to make them private with single or double underscores.There are also PEPs for adding other types, like 603 for frozen maps, and 604 for the pipe operator to create union types. These will be implemented in the
typing_extensionsbackport long before astropy's minimum version catches up.It would be amazing, though perhaps a pipe dream, to be able to fully static type astropy and compile into fast C.Edit: also numpy's
ArrayLikeandDTypeLikerely ontyping_extensionsuntil py3.8+pllim commentedon Aug 29, 2020
This adds maintenance burden for the core maintainers, especially given that our minversion for Python has not caught up to your needs yet. Some cost-benefit discussions are needed.
dhomeier commentedon Aug 29, 2020
Isn't that part of
collectionssince 3.5?nstarman commentedon Aug 29, 2020
Beyond ensuring that a package has consistent and equivalent functionality across all supported python versions, I'm not that familiar with the cost aspect of adding dependencies. Could you highlight a couple so I can look into them and how they relate to the
typing_extensionspackage?nstarman commentedon Aug 29, 2020
Not the dedicated static type. This one is actually more flexible since its a
Generic, so any ordered mapping falls under its purview.dhomeier commentedon Aug 29, 2020
I think the only package beyond
numpythat has ever (just) been accepted as a required dependency ispyerfa#10329. Arguablytyping_extensionsseems a much lower hurdle to install...nstarman commentedon Aug 29, 2020
I've been reading the discussion around
pyerfaand it seems one of the main points under consideration was pinning versions of dependencies.typing_extensionspromises LTS for py3.5+, so there's no problem for minimum versions, I think all that would need to be done is set the minimum required version to the version of the latest-used feature. I think the only problem that could happen is if some other package set a conflicting version requirement; but honestly, given the backport nature of the package, I don't see why that would ever happen.nstarman commentedon Sep 1, 2020
@mhvk I know we've loosely discussed the
Annotatedtype in #10655. What do you think about a run-time dependency for that and the other static types?saimn commentedon Sep 4, 2020
Numpy's next major release will have types information, and they are using
typing_extensionsbut as an optional dependency: https://github.com/numpy/numpy/search?q=typing_extensions&unscoped_q=typing_extensionshttps://github.com/numpy/numpy/blob/5b5a74043985b5cf577cd14b9a326b8eeb13c11a/numpy/typing/__init__.py#L8-L23
nstarman commentedon Sep 4, 2020
Thanks for pointing this out! I'm looking at the code, if
typing_extensionsis not present thanArrayLikeandDTypeLikebecome the generic typeAny.9 remaining items
implement typing_extensions as optional dependency
[-]Make `typing_extensions` an optional astropy dependency[/-][+]Make `typing_extensions` an (optional?) astropy dependency[/+]nstarman commentedon Oct 10, 2020
@embray discussion points about the
requestspackage seem relevant to this discussion as well. To paraphrase and inserttyping_extensionsforrequestsWhile having
typing_extensionsas an optional rather than required dependency is fine, it introduces a bit of non-astro, "technical" code (see python version checks and codecov issues in #10662).nstarman commentedon Apr 29, 2021
I'm revisiting #10662 and re-encountering the problems related to not having an
Annotatedannotation fromtyping. While first applicable to the units package, theQuantity[unit]would also be of benefit to the modeling package, which can use unit annotation in custom model definitions.typing_extensionsis the backward-compatible library for accessing py3.9+ features likeAnnotated. Just a resummary oftyping_extensions, it is:pipand python 2.7+.There a larger conversation to be had on how Astropy wants to implement typing, but ``typing_extensions``` will certainly be one of the dependencies required to do this in a way compatible with python 3.7 and even 3.8. While NumPy is making this an optional dependency, my hope is that it doesn't seem far fetched to make it a dependency here... 🤞
embray commentedon May 17, 2021
Just to add my $0.02, based on my experience with my own recent forays into static typing with Python, having
typing_extensionsis absolutely crucial.I just wasn't aware that there was any concerted effort yet to make Astropy fully type-aware (though it seems like it would be a good thing to do incrementally.
nstarman commentedon May 18, 2021
Agreed. Probably preaching to the choir here, but Mypy has incremental typing both in package scope and strictness. The easiest way to do typing would probably be to choose a subpackage (maybe a module in utils) that doesn't work with Units or Coordinates or anything that needs custom Astropy type hints and start building from there: get the
Mypy.ini; see ifmypyccan transpile the code, etc.taldcroft commentedon May 18, 2021
I'd be interested in hearing any applicable case stories to show how spending (possibly considerable) time and effort to make astropy fully type aware would benefit. I'm not necessarily against working toward this goal, but I do think we need to have some justification for the effort and consider the costs.
We do have to remember that many contributors to the core are not likely to be up to speed on writing typed code, so making the entry barrier for contributions even higher is a real concern.
mhvk commentedon May 18, 2021
I share @taldcroft's fear, although I guess in a way it is just provides an easier-to-parse (computationally at least) method to express what we now do in the
Parameterssection. But I do wonder how it would work in practice for initializers for classes likeSkyCoordorTime....That said, I still like very much the implementation for
quantity_inputin #10662, where one can decorate arguments with things likeQuantity[u.m].p.s. numpy has gone the route of having a separate set of files (in
numpy.typing) - a benefit of that is that those who like to use typing can, but it is not enforced on those who'd rather not.taldcroft commentedon May 18, 2021
I will say that I've become a pretty big fan of VS code + Pylance, and so I am beginning to see the benefit in my own workflow of type inference to allow for improve autocompletion and docs. I've actually been pretty amazed sometimes that it figures out some variable is a Table or whatever and gives me the right method auto-complete.
From that perspective I'd be happy if there was a type annotation that said
table.hstackreturns aTable. Except that if you stackQTablesit returns aQTable. So I have no idea how that works, though saying it isTableseems better than nothing at all.nstarman commentedon May 18, 2021
@taldcroft
IMO there are a number of pros. Hopefully they outweigh the cons:
Agreed. This could be problematic. OTOH, in my experimentation with typed code, I've generally found that mypy and other static code analyzers have helped me a) improve my docstrings to be more accurate about function parameters and output and b) actually write clearer, more atomic code, since fancy tricks and Frankenstein functions make mypy unhappy. Some well-typed code may be easier to contribute to, while other functions will be harder. I think one of many arguments for mypy is that gradual typing will enable us to choose, at a pretty granular level, what to type hint. Code in active development we can leave untyped, if we so choose. Very mature code that really only gets occasional bug fixes can be fully typed.
@mhvk
That is certainly one option. I personally am not a huge fan of all the file duplication. But it's presumably is easier for other packages to find / build a typeshd.
mhvk commentedon May 18, 2021
Slightly more on-topic, I actually do not have much of a problem with making
typing_extensionsa dependency, since it is part of the standard library in more recent pythons.embray commentedon May 20, 2021
I would also be +1 to having a separate hierarchy of type stubs. It's a bit of a pain to have to maintain two separate source hierarchies but it also would keep it out of the main codebase. One thing I don't like about typing and that kept me away from it a long time is having type hints everywhere really clutters the code up, especially if you're not used to reading python with type hints.
@taldcroft
There's quite a number of facilities behind exactly this sort of use case. For the case of hstack for example, very schematically you might have something like:
Running mypy on this gives:
It finds an error on the last line because
'asdf'is not aTable. The variableTcan represent anyTablesubclass, and this expresses that if you hstack twoTableit will return aTable(or subclass thereof) based on the types of the inputs. I admit I'm not sure what happens with the realhstackif you combine aTablewith aQTable. If it returns aQTablein this case I'm not exactly sure how to capture that in type hints, but it does know it at least returns aTable.nstarman commentedon Sep 30, 2021
I think this specific issue will be resolved by #10662, which adds
typing_extensionsas an optional dependency.So perhaps the discussion of that could move there.
I feel pretty comfortable adding it as an optional dependency for the simple reason that it's maintained as part of the main python code by the core python developers.
I think the related discussion on how to implement typing in astropy is well worth having and here might be the place.
I'll change the issue title and put a PSA in the top comment.
@embray. I'm very far from an expert in typing, so I'm trying to determine if type stubs can be mixed with integrated type hints. The questions I'm trying to figure out are: can each subpackage make a separate decision and everything play nice, or can mypy etc only understand one format? Can the same be applied within a subpackage?
I tentatively think the answer to both questions is yes... but any insight would be appreciated.
nstarman commentedon Nov 9, 2021
typing_extensionswas added as an optional dependency in #10662.