Add type hints to EpochsArray
constructor and BaseRaw.get_data()
#12740
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is WIP and I'm trying out some things while also simultaneously attempting not to go insane.
Whether we like it or not, as you know, most IDEs these days rely on static code analysis to assist writing code and offering tab completions etc.
So to provide a better UX, I started experimenting with type annotations in MNE-Python.
Now there are several design patterns we have in our code that make me pull out my hair – not because I necessarily think they're inherently bad, not all of them; but because some are extremely difficult or impossible to properly annotate such that static analysis tools will be able to infer the correct types and we don't have to bend over backwards
One of such recurring patterns, for example, is changing the type of a return value depending on a function parameter.
Let's look at the following code:
raw.get_data()
has a switch,return_times
, which will turn the return value fromNDArray
into atuple[NDArray, NDArray]
.This means that which type will actually be returned can only be determined at runtime, except if one uses
@overload
s, which we figured are a bit … heavy? Let's call it heavy :)But without adding an overload to
get_data()
to handle the two cases –return_times=False -> NDArray
,return_times=True -> tuple
, the user is forced to perform a runtime type check. Without theassert
in my MWE above,mne.io.RawArray(data=data, …)
would (correctly!) get red squiggly lines, because Pyright cannot know whether it's dealing with an array or a tuple of arrays here, while the constructor clearly demands an array.The only solution to that problem that wouldn't require a change or amendment to our API is adding overloads to
get_data()
.But since previous consensus was that we're not super happy about this approach, I'm right now a little bit lost and demotivated on how to best proceed. I want to provide an improved UX but I fully understand the reservations towards overloads.
That said … This PR includes some improvements to
EpochsArray
andBaseRaw.get_data()
that already improve the UX a bit but I'm not happy about the unclear return type ofget_data()
. Sigh…