Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type hinting on user-facing methods #2986

Open
wants to merge 5 commits into
base: RELEASE_next_minor
Choose a base branch
from

Conversation

thomasaarholt
Copy link
Contributor

@thomasaarholt thomasaarholt commented Aug 12, 2022

Description of the change

  • Added type hinting on a few user-facing methods to make the experience better when using the pylance engine in VSCode.
  • So far only added basesignal hints to .mean() and .sum(). See note below about out.

I am using TYPE_CHECKING to solve circular import errors. See here for more info.

Progress of the PR

  • Change implemented (can be split into several points),
  • update docstring (if appropriate),
  • update user guide (if appropriate),
  • add an changelog entry in the upcoming_changes folder (see upcoming_changes/README.rst),
  • Check formatting changelog entry in the readthedocs doc build of this PR (link in github checks)
  • add tests,
  • ready for review.

Here is an example of how pylance recognizes the type of m, even before running the code.
image

Notes

I intentionally return BaseSignal from hs.load. Strictly, it should be Union[BaseSignal, List[BaseSignal]], since the function can return a list of signals. But since I'm not going for full mypy coverage and instead going for "help out the user", I think it is more friendly to stick to just the former.

I also return BaseSignal from methods that do have an out parameter, when it strictly should be Union[None, BaseSignal]. Again because of convenience: if you're using out then you won't be returning into an object so you don't care that there is a return type. When you are returning you don't want the output type to possibly be None (this raises warnings about None not having the e.g. .plot() methods.

These could be fixed by using function overloading, but there would be a huge amount of code bloat since many methods having out as an argument.

@codecov
Copy link

codecov bot commented Aug 12, 2022

Codecov Report

Merging #2986 (1b8419d) into RELEASE_next_minor (c868840) will decrease coverage by 0.03%.
The diff coverage is 57.50%.

@@                  Coverage Diff                   @@
##           RELEASE_next_minor    #2986      +/-   ##
======================================================
- Coverage               80.80%   80.77%   -0.04%     
======================================================
  Files                     209      209              
  Lines                   32709    32736      +27     
  Branches                 7325     7333       +8     
======================================================
+ Hits                    26432    26442      +10     
- Misses                   4514     4523       +9     
- Partials                 1763     1771       +8     
Impacted Files Coverage Δ
hyperspy/_signals/eds_sem.py 59.80% <33.33%> (-0.81%) ⬇️
hyperspy/_signals/eds_tem.py 83.21% <33.33%> (-0.52%) ⬇️
hyperspy/_signals/eels.py 77.23% <33.33%> (-0.20%) ⬇️
hyperspy/io.py 86.28% <33.33%> (-0.54%) ⬇️
hyperspy/_signals/signal1d.py 78.14% <50.00%> (-0.27%) ⬇️
hyperspy/_signals/signal2d.py 80.79% <50.00%> (-0.44%) ⬇️
hyperspy/component.py 88.19% <50.00%> (-0.26%) ⬇️
hyperspy/signal.py 76.84% <62.50%> (-0.10%) ⬇️
hyperspy/axes.py 91.18% <100.00%> (ø)
hyperspy/model.py 83.82% <100.00%> (+0.01%) ⬆️
... and 2 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@thomasaarholt
Copy link
Contributor Author

I intentionally return BaseSignal from hs.load. Strictly, it should be Union[BaseSignal, List[BaseSignal]], since the function can return a list of signals. But since I'm not going for full mypy coverage and instead going for "help out the user", I think it is more friendly to stick to just the former.

I also return BaseSignal from methods that do have an out parameter, when it strictly should be Union[None, BaseSignal]. Again because of convenience: if you're using out then you won't be returning into an object so you don't care that there is a return type. When you are returning you don't want the output type to possibly be None (this raises warnings about None not having the e.g. .plot() methods.

These could be fixed by using function overloading, but there would be a huge amount of code bloat since many methods having out as an argument.

@ericpre
Copy link
Member

ericpre commented Aug 20, 2022

I intentionally return BaseSignal from hs.load. Strictly, it should be Union[BaseSignal, List[BaseSignal]], since the function can return a list of signals. But since I'm not going for full mypy coverage and instead going for "help out the user", I think it is more friendly to stick to just the former.

I also return BaseSignal from methods that do have an out parameter, when it strictly should be Union[None, BaseSignal]. Again because of convenience: if you're using out then you won't be returning into an object so you don't care that there is a return type. When you are returning you don't want the output type to possibly be None (this raises warnings about None not having the e.g. .plot() methods.

If I understand correctly, you are saying that you prefer to providing type hints which are sometimes in favour of always correct at the cost of having a syntax slightly more complicated to read? If so, without any doubt, I prefer the "always correct" approach, because the other one is misleading! ;)

Would it be possible to add a test on CI to check that the imports in the TYPE_CHECKING if block are working, just to check for typos? I am concerned that we wouldn't notice typos and the typo hinting may fail silently.

Copy link
Member

@ericpre ericpre left a comment

Choose a reason for hiding this comment

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

It needs to be rebase to fix the failure of the test suite. Ideally, it would be better to rebase on RELEASE_next_major as this will not be a minor release before release 2.0 - we need to start using rosettasciio ASAP.

@@ -25,6 +26,8 @@
from hyperspy.ui_registry import add_gui_method, DISPLAY_DT, TOOLKIT_DT
from hyperspy.signal import BaseSetMetadataItems

if TYPE_CHECKING:
from hyperspy.models.edssemmodel import EDSSEMModel
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to test these imports on CI?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants