Skip to content

fix: ruff c408 in astropy/units - #15664

Merged
mhvk merged 3 commits into
astropy:mainfrom
paverett:fix/ruff_c408_units
Jan 30, 2024
Merged

mhvk merged 3 commits into
astropy:mainfrom
paverett:fix/ruff_c408_units

Conversation

@paverett

@paverett paverett commented Dec 1, 2023

Copy link
Copy Markdown
Contributor

Description

This pull request is to address violations to Ruff's rule C408, which is listed explicitly in issue #14818. Only the units sub module is addressed in this PR.

Solves part of #14818.

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

@github-actions

github-actions Bot commented Dec 1, 2023

Copy link
Copy Markdown
Contributor

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.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • Is a milestone set? Milestone must be set but we cannot check for it on Actions; do not let the green checkmark fool you.
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@eerovaher

Copy link
Copy Markdown
Member

Hi, @paverett

One of the purposes of #14818 is to suggest very simple tasks to new contributors so that they can familiarize themselves with the basic workflow and tools that we use to develop astropy. Based on your pull requests I think you should be capable of addressing more challenging rules now. I encourage you to work on PT012, but if you would like to address some other rule not explicitly listed in #14818 then feel free to do so.

@paverett

paverett commented Dec 1, 2023

Copy link
Copy Markdown
Contributor Author

Hi, @paverett

One of the purposes of #14818 is to suggest very simple tasks to new contributors so that they can familiarize themselves with the basic workflow and tools that we use to develop astropy. Based on your pull requests I think you should be capable of addressing more challenging rules now. I encourage you to work on PT012, but if you would like to address some other rule not explicitly listed in #14818 then feel free to do so.

I understand, sorry about that @eerovaher. Yeah I can take a look at PT012! I looked and didn't find an issue regarding PT012. Should I create one or did I miss one that has already been created?

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looking at this, I actually rather dislike the changes, in particular for the usage of dict - when used to set kwargs, I find it rather nice that it looks like passing on arguments to a function call.

So, I'd suggest to keep ignoring this particular ruff rule, and only change the cases where it is an empty tuple, list, or dict (where not parametrized). I marked the cases I think are fine to change.

neginf = x._to_own_unit(neginf)
return (
(x.view(np.ndarray),),
dict(copy=True, nan=nan, posinf=posinf, neginf=neginf),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I do not like this: Here, kwargs is set and I find it much clearer if it looks like arguments to a function.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a helper function for a numpy operation so speed is very important.
Given that, this is a good improvement.

@mhvk mhvk Dec 1, 2023 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The speed advantage is completely negligible compared to the overhead of even this function itself. I made a conscious decision to write it as it is here, and I don't think this change is good.

But if you want to speed it up further and keep the intent clear, I'm fine with changing the code to

return (x.view(np.ndarray), copy, nan, posinf, neginf), {}, x.unit, None

(I guess that would continue the now common practice to rewrite code just to avoid black formatting...)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder what the speed of constructing a NamedTuple is.

usemask=usemask,
asrecarray=asrecarray,
),
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same, please exclude this one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a helper function for a numpy operation so speed is very important.
Given that, this is a good improvement.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As above. Can "solve" the same way too if we really want to follow ruff gospel.

self.data = equiv_list
self.name = [name]
self.kwargs = [kwargs] if kwargs is not None else [dict()]
self.kwargs = [kwargs] if kwargs is not None else [{}]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This one is fine.

Comment thread astropy/units/quantity.py

except (TypeError, ValueError, AttributeError) as e:
out_normalized = kwargs.get("out", tuple())
out_normalized = kwargs.get("out", ())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Definitely better

assert e1.name == ["pixel_scale", "temperature_energy"]
assert isinstance(e1.kwargs, list)
assert e1.kwargs == [{"pixscale": 10 * u.arcsec / u.pix}, dict()]
assert e1.kwargs == [{"pixscale": 10 * u.arcsec / u.pix}, {}]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OK



@pytest.mark.parametrize("multiplicand", [list(), 42, 0, -1])
@pytest.mark.parametrize("multiplicand", [[], 42, 0, -1])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Definitely better

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed.

@mhvk mhvk mentioned this pull request Dec 1, 2023
3 of 6 tasks
@nstarman

nstarman commented Dec 1, 2023

Copy link
Copy Markdown
Member

@mhvk, there are 2 good reasons why using the built-in dict constructor {} is better than the dict callable:

  1. Speed. It's like 2x faster to use the dict constructor. Applying Ruff C408 is an easy speedup wherever it's fixed.
Details

CleanShot 2023-12-01 at 16 36 37@2x

  1. Safety. Python does not protect dict as a symbol so it can be re-assigned. Because of how Python scopes namespaces the following thing can happpen:
Details

CleanShot 2023-12-01 at 16 43 12@2x

In sum, {} is 100% equivalent but 2x faster and safer.

@nstarman nstarman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

As I note in a comment this PR changes the dict callable for the built-in dict constructor, which is 2x faster and not susceptible to namespace trickery. Thanks @paverett for contributing. IMO this is a good PR to merge.

usemask=usemask,
asrecarray=asrecarray,
),
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a helper function for a numpy operation so speed is very important.
Given that, this is a good improvement.



@pytest.mark.parametrize("multiplicand", [list(), 42, 0, -1])
@pytest.mark.parametrize("multiplicand", [[], 42, 0, -1])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Agreed.

@pytest.mark.parametrize(
"kwargs",
(
dict(return_index=True, return_inverse=True),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All these test cases are very specifically written this way to make them look like arguments to functions. I really see no reason to decrease readability because of some ruff "rule".

@eerovaher

Copy link
Copy Markdown
Member

When I added C408 to the list of suggested rules I didn't expect it to be controversial, and it has been applied in quite a few sub-packages without provoking discussion. But if the sub-package maintainers don't want the rule to be enforced in all cases then for now it's best to just apply it where they are happy with it.

@paverett asked:

I looked and didn't find an issue regarding PT012. Should I create one or did I miss one that has already been created?

I don't see any value in opening issues for that rule. You can open pull requests without having to refer to any specific issue.

@paverett

Copy link
Copy Markdown
Contributor Author

@nstarman @mhvk I am unsure how i should continue with this PR, should I continue to implement the changes requested in this PR? Or should I close it? It does not seem like a change that is wanted.

@eerovaher

Copy link
Copy Markdown
Member

@mhvk, would you be interested in turning on Ruff's allow-dict-calls-with-keyword-arguments setting?

@mhvk

mhvk commented Jan 19, 2024

Copy link
Copy Markdown
Contributor

@mhvk, would you be interested in turning on Ruff's allow-dict-calls-with-keyword-arguments setting?

Yes, that would make sense, so that means for dict C408 just enforces empty dict() should be {}, right? (and still does empty tuples and lists, etc.

@nstarman

Copy link
Copy Markdown
Member

I'm fine with that. We can return to the question of dicts later / never. Some refactoring might make the question moot.
It would be nice if the allow-dict-calls-with-keyword-arguments could be done in a file-specific way, e.g. to ignore the test files & select unit files, but that's not a show-stopper.

@eerovaher

Copy link
Copy Markdown
Member

@paverett, when #15915 is merged then you can address the remaining violations in units.

@paverett
paverett force-pushed the fix/ruff_c408_units branch from 8b7c3af to f390995 Compare January 26, 2024 02:33

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry to be a bit slow - this one is now all OK. Thanks!

@mhvk

mhvk commented Jan 30, 2024

Copy link
Copy Markdown
Contributor

Failure unrelated, so merging. Thanks again!

@mhvk
mhvk merged commit 95c510a into astropy:main Jan 30, 2024
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.

6 participants