Open DimitriPapadopoulos opened 8 months ago
Thanks for sharing and distilling the results. I'll go through them one by one.
GH102
: Auto-cancel on repeated PRs At least one workflow should auto-cancel.
On this one, I'm at -0. If it's best practice to have this config, perhaps GitHub should make it the default. I see setuptools has adopted it, but with an additional ref_type
factor, added in pypa/setuptools#3116. That issue does look generally relevant. Given that code has been stable since, my guess is the Setuptools approach would be suitable to apply here.
I've had other users propose to disable fail-fast, which is kind-of the opposite of this change.
I find it a little frustrating that the authors of GH102 don't explain why I should override the presumably sensible defaults that GitHub provides. I'd really like to see GH102 rewritten to include the motivation (what's the value in tweaking the configuration) and either a feature request or guidance from GitHub that this setting is preferred. It should probably be updated too to recommend a tweak that doesn't break releases.
PC100: Has pre-commit-hooks
I've previously explored enabling pre-commit, but I've found it adds too much toil and noise to a project. The project is insistent on pinning and frequently updating the config, which at the very least results in lots of nuisance PRs and commits in the history. I've stumbled on a few projects that are using pre-commit, and especially for the stable ones, the commits in the repo are littered with pre-commit bumps. I absolutely don't want to adopt a process that's unwilling to go with the flow and work at head.
See also #109.
RF101: Bugbear must be selected RF102: isort must be selected RF103: pyupgrade must be selected
These sound good. I was tempted to enable isort when migrating from flake8/black, but I wanted to wait for the projects to stabilize, which they basically are now (little risk of having to roll back the migration). There are still probably many projects that haven't yet been updated to support the code style tweaks in ruff, but that's fine. Enabling these settings will cause a lot of toil on the downstream projects, but I'm willing to do it, especially if we can devise a routine to apply ruff --fix
after rolling out the setting to downstream projects.
I'm not fond of pre-commit myself :smile:
Do you have a complete list of downstream projects that use this skeleton? I have already started applying B and UP rules in some of them. Not all rules can be enforced with ruff check --fix
or even --unsafe-fix
automatically.
About GH102, I must admit I don't understand the gory details of GitHub jobs. Yet, I think concurrency groups could be enabled and fast-fail disabled at the same time:
I experimented adding "I", "B", and "UP" to ruff.toml in the keyring project. It revealed 73 errors of which all but 17 could be mechanically fixed (all but 33 safely):
After applying the fixes, there were new failures in the tests, including "needs formatting" and mypy failures... so that's annoying. It doesn't appear there's a way to --fix
and format
in the same invocation (https://github.com/astral-sh/ruff/issues/8232). It does seem that the unfixable issues are all bugbear, so maybe that's an indication to skip bugbear for now. Skipping bugbear, the check + format results in this diff, causing mypy failure:
diff --git a/keyring/_compat.py b/keyring/_compat.py
index 46868a8..7d7c8fa 100644
--- a/keyring/_compat.py
+++ b/keyring/_compat.py
@@ -4,4 +4,6 @@ __all__ = ['properties']
try:
from jaraco.classes import properties # pragma: no-cover
except ImportError:
- from . import _properties_compat as properties # type: ignore[no-redef] # pragma: no-cover
+ from . import (
+ _properties_compat as properties, # type: ignore[no-redef] # pragma: no-cover
+ )
That's a little discouraging, suggesting there's a lot of toil ahead.
Do you have a complete list of downstream projects that use this skeleton?
I have a list of projects I contribute to, but that's a superset of projects I maintain and only a subset of projects utilizing skeleton. The Coherent OSS page has a curated list of projects. That's probably a pretty good representation of projects dependent on skeleton that I (and others in Coherent OSS) maintain. For projects others maintain, probably the best way to find those would be to search GitHub for non-fork projects containing the badge (note that the year changes, so you'd want to search without the year). @bswck do you have any other advice on how to find skeleton-based projects (based on the work you've done)?
Yet B are often the most interesting rules. For example, they detect tests that contain a = b
instead of assert a == b
. This error happens more frequently than I would have thought.
I've filed https://github.com/astral-sh/ruff/issues/10516 to track ruff isort fixes breaking mypy tests.
Do you have a complete list of downstream projects that use this skeleton?
I have a list of projects I contribute to, but that's a superset of projects I maintain and only a subset of projects utilizing skeleton. The Coherent OSS page has a curated list of projects. That's probably a pretty good representation of projects dependent on skeleton that I (and others in Coherent OSS) maintain. For projects others maintain, probably the best way to find those would be to search GitHub for non-fork projects containing the badge (note that the year changes, so you'd want to search without the year). @bswck do you have any other advice on how to find skeleton-based projects (based on the work you've done)?
I'll provide a script for it. We could include it in your article later.
I did some work this evening to make jaraco.develop.projects-run
more flexible, and was able to run this command:
@ env PROJECTS_LIST_URL=https://raw.githubusercontent.com/jaraco/dotfiles/main/projects.txt pip-run 'jaraco.develop>=8.9.1' -- -m jaraco.develop.projects-run -t 'not fork' -- ruff check --select I,B,UP 2>1 | gist
https://gist.github.com/jaraco/066032d456c816caef90ed2563cce1ec
Only ~3300 lints to clean up.
Next, I'll see if I can use this routine to enact some of the automatic fixes.
I've spent some time cleaning up those projects so at least they're building at HEAD. I've also spent some time fixing some of these checks in the projects and learned a few things:
as err
and from err
, but it's annoying to fix. It seems to me that the proper fix should be to make this behavior the default in Python.(prior to an edit, I had B904 and B028 swapped above)
If we're going to adopt bugbear checks, I'd suggest to disable B028 and B904 to start.
- B015 caught a couple of bugs \o/.
Indeed, I have caught many missing assert
in tests with this one.
- B018 had a lot of false positives, especially in keyring libraries that use the side effect of attribute access to detect behavior.
That's especially true of tests. Perhaps disable in tests?
- B028 is a nuisance and found everywhere. Usually the solution is to add
as err
andfrom err
, but it's annoying to fix. It seems to me that the proper fix should be to make this behavior the default in Python.
Adding from err
changes the wording from:
During handling of the above exception, another exception occurred:
to:
The above exception was the direct cause of the following exception:
I doubt the default behaviour will ever change in Python now that that distinction has been introduced. Is doing the "right thing" such a nuisance? On the other hand, is the difference in wording that important and useful?
I doubt the default behaviour will ever change in Python now that that distinction has been introduced. Is doing the "right thing" such a nuisance? On the other hand, is the difference in wording that important and useful?
It's four elements to two lines, so no, it's not horrible, but it does start to litter the codebase. Especially when by my estimation 99% of the time, if one is explicitly raising an exception in except
block, it's a direct cause (compare that with a coding error that raises an exception).
If Python had the intention for every piece of code everywhere to choose between from None
and from err
, it really would have been nice for the most common form to be streamlined syntactically.
Oh, but I see now, there are in fact three different modes: no indication, from err
, and from None
... as the latter resets the exception stack.
I still contend, if Python recommends for everyone to write from err
, they should make that the default behavior, and instead make another syntax from Any
or similar, so that a programmer types nothing for the preferred behavior and types an option for the uncommon case.
I realize bugbear doesn't speak for the whole community, but it's annoying to be adding all of these changes and persistent noise to all the code bases for such little value.
Here's what B028 looks like, and here's what B904 looks like across the projects.
With UP
, you might want to disable UP038
though https://github.com/astral-sh/ruff/issues/7871
As a sidenote, for projects relying on both setuptools and distutils, (like setuptools itself) you can add them to https://docs.astral.sh/ruff/settings/#lint_isort_extra-standard-library, https://docs.astral.sh/ruff/settings/#lint_isort_known-third-party, https://docs.astral.sh/ruff/settings/#lint_isort_known-first-party, or https://docs.astral.sh/ruff/settings/#lint_isort_known-local-folder such that setuptools is grouped to always be imported before distutils. (not necessarily something to add in skeleton, but a consideration you can have whenever you hit that issue of import order mattering across a codebase)
Apply those rules that make sense: https://learn.scientific-python.org/development/guides/repo-review/?repo=jaraco%2Fskeleton&branch=main
Suggestions:
GH102
: Auto-cancel on repeated PRs At least one workflow should auto-cancel.PC100: Has pre-commit-hooks Must have
https://github.com/pre-commit/pre-commit-hooks
repo in.pre-commit-config.yaml
PC901: Custom pre-commit CI message Should have something like this in .pre-commit-config.yaml:
RF101: Bugbear must be selected Must select the flake8-bugbear B checks. Recommended:
RF102: isort must be selected Must select the isort I checks. Recommended:
RF103: pyupgrade must be selected Must select the pyupgrade UP checks. Recommended: