-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Attempt to use Ruff formatter on this project #1103
Comments
This PR replaces flake8, flake8-docstrings, flake8-builtins, isort, autopep8, pep8-naming, pyproject-flake8, and two test_infra unit tests with ruff for linting. Formatting remains unchanged (to be addressed in #1103). Notes: 1. Ruff does not yet implement all of the pycodestyle rules, which we checked/fixed with autopep8, see: astral-sh/ruff#2402 2. Ruff implements all Flake8 rules (the "F" rules). 3. flake8-docstrings is not listed in the Ruff re-implementation list by pydocstyle is there, which flake8-docstrings is based on 4. Ruff reimplements flake8-builtins (but picks up much more than we were previously, which is odd). 5. Ruff's isort is "profile='black'". 6. With flake8 we had "R" rules enabled, but I can't figure out what those were, or what provided them. Where the linter picks up issues that the old tools did not, handle in one of these ways: * Ignore with a `noqa:` directive if it's a false positive or should otherwise be permanently ignored in that specific case * Ignore for a file or group of files (the docs and tests have several of these) where it's something we want to pick up in the core code but not everywhere * Ignore with a note to review later when it's likely that there would be too much additional noise in this PR * Make the recommended change, when it's small and seems reasonable #1104 will continue on from this with a few more changes that are minimal and reasonable, and enabling additional rule sets (since they are bundled with ruff, and since ruff is so fast, they are basically free) that I agree with/like the most. A few outdated `noqa:` directives have been removed (ruff detects these as well). Fixes #1102.
Currently, running `tox -e fmt` leaves the code in a state that `tox -e lint` complains about, for two reasons: * Wrapping a line in ops/charm - I'm not sure why this difference exists since autopep8 and ruff have the same max line length (or why it wasn't picked up before we used ruff), but ruff is ok with the wrapped version, so it seems like the simple fix here is to just have it wrapped. * "from x import a,b,c" style imports and wrapping. For the import issue, if we adjust isort to use the "vertical hanging indent" mode (weirdly called "3") that gets most of the way there, but even though the docs show a trailing comma, one isn't included. However, if we use the `--split-on-trailing-comma` mode as well that does lead to a compatible format. We're not using the "force wrapping via trailing comma" trick anywhere, but it seems harmless enough to have it enabled. I've put the options in tox.ini rather than pyproject.toml because we're intending to move to `ruff` for formatting soon (#1103) and this ensures that these options go away, rather than getting missed in pyproject.toml. I can change that if we'd rather keep all the options in one place. Also bumped the isort version, which isn't required but I did while investigating, and since I've tested it and it's ok, seems reasonable. Also passed the line length to isort, which isn't needed at the moment but is more consistent.
We'd like to pair on this in person in Madrid: one of us can do a quick first pass, then we can go over style concerns together and try to nut it out in a morning. |
A couple of thoughts after looking at @IronCore864's preview of model.py:
# Old: 3 lines, easy to read
self._data.update({
self.relation.app: RelationDataContent(self.relation, self.relation.app, backend),
})
# New: 7 lines! harder to read
self._data.update(
{
self.relation.app: RelationDataContent(
self.relation, self.relation.app, backend
),
}
) Maybe we'll just have to get over that. Or maybe we can rewrite the ones that expand crazily to avoid the crazy 7-line wrapping: data = {self.relation.app: RelationDataContent(self.relation, self.relation.app, backend)}
self._data.update(data) |
My NZ$0.02: Firstly some disclaimers: before Black existed, the style guide I used (and had my teams use) was very similar, I adopted Black quite early (partly because there were so few changes), and I've been using it for most of my code ever since, so I'm very accustomed to it (and therefore Ruff's black-equivalent style). So even though Stockholm Syndrome may not be a real thing, I might have it in this case 😆.
# Old:
stop: Tuple[str, ...] = tuple(s.name for s in self.get_services(
*service_names).values() if s.is_running())
# New:
stop: Tuple[str, ...] = tuple(
s.name for s in self.get_services(*service_names).values() if s.is_running()
)
- f"key {key!r} is invalid: must be similar to 'key', 'some-key2', "
- f"or 'some.key'")
+ f"key {key!r} is invalid: must be similar to 'key', 'some-key2', " f"or 'some.key'"
+ )
|
iPhone v.s. Android: which one do you like? Many has a preference, but to me (and maybe more), they are the same: they do exactly the same thing, and they even look the same more and more nowadays. I only choose iPhone because I couldn't be bothered to spend hours deciding which Android phone to buy. That doesn't mean iPhone is better than Android. Many choose Android because of some reason but that doesn't mean Android is better than iPhone either. There is no "best", if there was, everybody would go for the best choice, and other choices wouldn't exist any more. Where do you want to live the most on the earth? Tokyo? Shanghai? New York? The list goes on. Everybody has a preference but there is no "best city" to live. Same logic: if there was, everybody would be moving there, rendering all the other cities empty. It's all personal preferences and priorities. This brings me to the discussion on black V ruff (might as well throw in autopep8). None is perfect, there is no "best" option. If there was, everybody would switch to the best, and the other options wouldn't exist. I do not have a strong preference regarding ruff V black. They both are fine. Autopep8 is Okay, too. No matter which you choose, there will be corner cases that make you doubt your choice. That said, I still did a comparison between black and ruff and here are some examples where they differ: Sample 1: _AddressDict = TypedDict(
"_AddressDict",
<<<<<<< ruff
{
"address": str, # Juju < 2.9
"value": str, # Juju >= 2.9
"cidr": str,
},
=======
{"address": str, "value": str, "cidr": str}, # Juju < 2.9 # Juju >= 2.9
>>>>>>> black
) Here I prefer ruff. Sample 2: self._relations = RelationMapping(
<<<<<<< ruff
relations, self.unit, self._backend, self._cache, broken_relation_id=broken_relation_id
=======
relations,
self.unit,
self._backend,
self._cache,
broken_relation_id=broken_relation_id,
>>>>>>> black
) Still ruff. Sample 3: def __init__(
<<<<<<< ruff
self, name: str, meta: "ops.charm.CharmMeta", backend: "_ModelBackend", cache: _ModelCache
=======
self,
name: str,
meta: "ops.charm.CharmMeta",
backend: "_ModelBackend",
cache: _ModelCache,
>>>>>>> black
): Black here since the line starts to become too long to be read efficiently. As you can see, even for the same person, it's not easy to decide which is best. If this was Sophie's choice, that movie would be 5 hours long instead of just 2h30m. If I have to make a choice here, I choose ruff, not because of the style differences, but because ruff is written in Rust and that makes me think it's probably faster than black (which might not always hold true in real world). I don't think we should make a decision based on personal preferences because by definition, personal preferences differ. How about a vote? |
Ah, sorry, I didn't mean to imply that we should choose between black and ruff. Ruff's formatter is more-or-less Black, and we should definitely use Ruff if we change, not consider using Black. I was just meaning to provide context in that I have been using the "Black style" for a long time, so am probably biased because of that. The choice here is really between
I don't think we need to vote, we can just talk it over in person and come to a consensus. |
I believe this is complete and we just missed closing the issue, likely because there were multiple PRs. |
I think it's time to use automatic code formatting. We could use Black, but because we want to use Ruff for linting, we should also probably use Ruff's code formatter. It fixes several minor consistency issues with Black, and also adds a single-quote knob (yay! :-).
We should keep in mind that this project has tried to switch to Black twice in the past:
We should consider those comments seriously, and see if there are fixes / workarounds for those issues, either by increasing the line length, adding/removing trailing commas to guide the tool, or manually reformatting the few places where the tool makes things significantly worse.
That said, the pros of using an automatic code formatter is high.
The text was updated successfully, but these errors were encountered: