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

Run automated formatting and linters #187

Merged

Conversation

WilliamJamieson
Copy link
Collaborator

This PR adds automated linters and code formatters to stcal.

Checklist

  • added entry in CHANGES.rst (either in Bug Fixes or Changes to API)
  • updated relevant tests
  • updated relevant documentation
  • updated relevant milestone(s)
  • added relevant label(s)

@codecov
Copy link

codecov bot commented Aug 11, 2023

Codecov Report

Attention: 238 lines in your changes are missing coverage. Please review.

Files Coverage Δ
src/stcal/__init__.py 100.00% <100.00%> (ø)
src/stcal/alignment/resample_utils.py 100.00% <100.00%> (ø)
src/stcal/linearity/linearity.py 100.00% <100.00%> (ø)
src/stcal/ramp_fitting/ols_cas22/__init__.py 100.00% <100.00%> (ø)
src/stcal/ramp_fitting/ramp_fit_class.py 55.91% <100.00%> (ø)
src/stcal/saturation/saturation.py 98.33% <100.00%> (-0.03%) ⬇️
tests/test_alignment.py 100.00% <100.00%> (ø)
tests/test_dark_current.py 100.00% <100.00%> (ø)
tests/test_dq.py 92.30% <100.00%> (ø)
tests/test_jump.py 95.02% <100.00%> (ø)
... and 22 more

📢 Thoughts on this report? Let us know!

@WilliamJamieson WilliamJamieson force-pushed the feature/code_formatting branch from 23bfff3 to afe58c1 Compare August 11, 2023 18:38
Copy link
Collaborator

@zacharyburnett zacharyburnett left a comment

Choose a reason for hiding this comment

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

LGTM, we can also activate pre-commit.ci for this repo to automatically lint / format PRs, pending maintainer approval

@WilliamJamieson
Copy link
Collaborator Author

@WilliamJamieson WilliamJamieson marked this pull request as ready for review November 11, 2023 14:36
@WilliamJamieson WilliamJamieson requested a review from a team as a code owner November 11, 2023 14:36
Copy link
Collaborator

@kmacdonald-stsci kmacdonald-stsci left a comment

Choose a reason for hiding this comment

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

All in all it looks fine. I'm confused by some of the choices made and some of the syntax. Also, the PR should list what automated tools were used for formatting and linting. That way any future PR's can use those same tools to ensure all future changes conform to the current formatting and syntax.

rotation: float = None,
transform=None,
):
pscale_ratio: int | None = None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should the = None be removed from these?

Copy link
Collaborator Author

@WilliamJamieson WilliamJamieson Nov 14, 2023

Choose a reason for hiding this comment

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

This is correct. The | is notation introduced officially by Python 3.10 but available in Python 3.9 via from __future__ import annotations; is equivalent to using a typing.Union (e.g. a | b is equivalent to typing.Union[a, b]). Note that the typing.Union[a, b] annotation is saying for Python that the type is either a or b. It is not the equivalent of a C union type, that is more akin to the Python tuple, e.g. annotated by tuple[a, b].

As for the addition of the | None = None, the annotation/assignment foo: int=None is technically incorrect and will fail static type checkers, both built into IDEs for syntax highlighting and completion and strong checkers like MyPy. Instead it needs to be turned into an optional, foo: typing.Optional[int] = None which is short for foo: typing.Union[int, None] = None which as stated above can be reduced to the | symbol.

Essentially, what has happened here is that ruff noted the lack of the optional note in those annotations which clearly are optional and swapped that to using the optional annotation. Then the pyupgrade tool shortened it to using | None, which is the preferred way of writing optional annotations now according to the majority of style guides.

Copy link
Collaborator

@zacharyburnett zacharyburnett Nov 14, 2023

Choose a reason for hiding this comment

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

I like this new style, much more explicit but less characters at the same time

fiducial: Union[tuple, np.ndarray],
disp_axis: int = None,
pscale_ratio: float = None,
fiducial: tuple | np.ndarray,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This was originally listed as a Union, now is not. Is that correct?

disp_axis: int = None,
pscale_ratio: float = None,
fiducial: tuple | np.ndarray,
disp_axis: int | None = None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should the = None b here?

def _reproject(
x: Union[float, np.ndarray], y: Union[float, np.ndarray]
) -> tuple:
def _reproject(x: float | np.ndarray, y: float | np.ndarray) -> tuple:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it appropriate to remove Union here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think Python 3.10 changed Union to |; can this run on 3.9 with a future import?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

from __future__ import annotations makes this work in Python 3.9 as this syntax was "trialed" in Python 3.9 before becoming official in Python 3.10.

@@ -86,24 +86,28 @@ def do_correction_data(science_data, dark_data, dark_output=None):
drk_groupgap = dark_data.exp_groupgap

log.info(
'Science data nints=%d, ngroups=%d, nframes=%d, groupgap=%d',
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this was better in the old format. Also, why not use f-strings?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the fault of the auto-formatter (both black and ruff will do the same thing), which can be turned off locally if one wants to, but I didn't review the outputs for when it did strange things.

As for the f-string, this is due to a quirk in how python.logging actually functions under the hood.

When you log a message say log.debug(msg) whatever is in msg will be computed no matter what (e.g. if its an f-string or str.format string), meaning that even if the logging level is turned down so that in this case debug messages are not logged, there is still overhead from logging due to it still computing msg. However, fprintf string formatting can be written in a way that avoids this because python.logging passes all the arguments after the message string to the string using %, i.e. log.debug("my message with %s and %s", "this", "that)
will ultimately be rendered as "my message %s and %s" % ("this", "that") if the debug level logging is set, otherwise no rendering will occur.

There are other reasons why fprintf style string formatting is preferred by python.logging in addition to this. However, in any case the documentation for python.logging specifically says that the fprintf style strings should be preferred https://docs.python.org/3.12/howto/logging.html#logging-variable-data. This unfortunately is unlikely to change due to backwards compatiblity issues.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The why is this bad? section of https://docs.astral.sh/ruff/rules/logging-string-format/#why-is-this-bad goes into further details.

@@ -105,22 +105,31 @@ def gls_ramp_fit(ramp_data, buffsize, save_opt, readnoise_2d, gain_2d, max_cores
num_available_cores = cpu_count()
number_slices = utils.compute_num_slices(max_cores, nrows, num_available_cores)

log.info(f"Number of data slices: {number_slices}")
log.info("Number of data slices: %s", number_slices)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why does this remove the use of f-strings?

@@ -159,10 +155,10 @@ def ols_ramp_fit_multiprocessing(
opt_info: tuple
The tuple of computed optional results arrays for fitting.
"""
log.info(f"Number of processors used for multiprocessing: {number_slices}")
log.info("Number of processors used for multiprocessing: %s", number_slices)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why the removal of f-string?

@WilliamJamieson WilliamJamieson merged commit 36d9d14 into spacetelescope:main Nov 14, 2023
22 of 23 checks passed
@WilliamJamieson WilliamJamieson deleted the feature/code_formatting branch November 14, 2023 15:10
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.

3 participants