-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Sort imports for more consistent diff (ruff/isort) #4392
Conversation
913eedb
to
6287b8d
Compare
2f2f68a
to
d8c8dcc
Compare
from os import open as os_open, utime # isort: skip | ||
from os.path import isdir, split # isort: skip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is not automated
from . import ( | ||
_entry_points, | ||
_reqs, | ||
command as _, # noqa: F401 # imported for side-effects |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is not automated (made the noqa more specific)
@@ -4,21 +4,19 @@ | |||
|
|||
import jaraco.path | |||
import pytest | |||
import setuptools # noqa: F401 # force distutils.core to be patched |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is not automated (more precise noqa)
@@ -3,18 +3,17 @@ | |||
from configparser import ConfigParser | |||
from itertools import product | |||
|
|||
import jaraco.path | |||
import pytest | |||
import setuptools # noqa: F401 # force distutils.core to be patched |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is not automated (more precise noqa)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much @Avasam.
I think in the case of this PR it would be interesting in separating 2 commits: 1 for the configuration changes (like ruff.toml
and .pre-commit-config.yaml
) and another one for the bulk of the automated changes. If necessary git commit --no-verify
can be used to allow the first commit to be made without changing the rest of the codebase.
Because squashing is not viable if we want to keep the 2 commits separated, it would make more sense to use rebase
instead of merging
if it is necessary to update the codebase. This also implies in more coordination with the other PRs for the best moment/order to merge, but I think we can do that.
ruff.toml
Outdated
known-third-party = ["setuptools"] | ||
known-first-party = ["distutils"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this make sense?
known-third-party = ["setuptools"] | |
known-first-party = ["distutils"] | |
section-order = ["future", "standard-library", "eager", "third-party", "first-party", "local-folder", "delayed"] | |
sections.eager = ["_distutils_hack"] | |
sections.delayed = ["distutils"] |
It is more verbose, but also more compatible with what isort would do by default, special-casing only distutils
and _distutils_hack
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize I could create custom sections. That is so much better yes !
Certainly, now that I have confirmation this is indeed wanted, I'll be cautious about keeping it into 2 clean commits.
Hence I've been lazily merging conflicts until now ^^ (with an occasional soft reset) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much @Avasam for putting so much work on this.
I am interested in merging this one before anything else, to get it out of the way and rip off the metaphorical band-aid. Unless you have a different suggestion.
ruff.toml
Outdated
# Force Ruff/isort to always import setuptools before distutils in tests as long as distutils_hack is supported | ||
# This also ensures _distutils_hack is imported before distutils | ||
# https://github.com/pypa/setuptools/issues/4137 | ||
section-order = ["future", "standard-library", "eager", "third-party", "first-party", "delayed", "local-folder"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose we leave "delayed"
as the last item in this array.
section-order = ["future", "standard-library", "eager", "third-party", "first-party", "delayed", "local-folder"] | |
section-order = ["future", "standard-library", "eager", "third-party", "first-party", "local-folder", "delayed"] |
The reasoning is the following:
Relative import statements like from . import ..
seem to be considered "local-folder", but they still refer to setuptools
. This means that the configuration ... "delayed", "local-folder"]
will place distutils
imports before setuptools
imports, but that is what we are trying to avoid. So my recommendation is to write ..., "local-folder", "delayed"]
.
For example ... "delayed", "local-folder"]
change setuptools/command/bdist_wheel.py
to:
from packaging import tags, version as _packaging_version
from wheel.metadata import pkginfo_to_metadata
from wheel.wheelfile import WheelFile
from distutils import log
from .. import Command, __version__
from .egg_info import egg_info as egg_info_cls
But we would like:
from packaging import tags, version as _packaging_version
from wheel.metadata import pkginfo_to_metadata
from wheel.wheelfile import WheelFile
from .. import Command, __version__
from .egg_info import egg_info as egg_info_cls
from distutils import log
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's my reasoning:
For non-setuptools folders, like tools and tests, it doesn't change anything and it's closer to what a user of setuptools would have.
For setuptools itself: AFAIK, to import a submodule, the top module/package gets imported too. So _distutils_hack
should still always run first. Unless I'm missing something:
(overly zealous prints but I'm trying to remove assumptions from my proof)
It was also already that way for most imports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_distutils_hack
will not be affected by putting delayed
last, right? (Because _distutils_hack
goes to its own group: eager
, which always comes first).
So if that is the concern, "local-folder", "delayed"]
should be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thank you very much for clarifying!
We currently have a recommendation that distutils
should be imported after setuptools
expressed in
setuptools/_distutils_hack/__init__.py
Lines 17 to 24 in a6f7484
warnings.warn( | |
"Distutils was imported before Setuptools, but importing Setuptools " | |
"also replaces the `distutils` module in `sys.modules`. This may lead " | |
"to undesirable behaviors or errors. To avoid these issues, avoid " | |
"using distutils directly, ensure that setuptools is installed in the " | |
"traditional way (e.g. not an editable install), and/or make sure " | |
"that setuptools is always imported before distutils." | |
) |
So I think that honouring that is more important than the traditional approach.
I understand that indirectly we can verify that both approaches work. But the implicit approach might be fragile in the future1. So in principle, I am in favour of directly ensuring that any import of distutils
always come explicitly after the imports to setuptools
2.
Footnotes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can change that once SETUPTOOLS_USE_DISTUTILS=stdlib
is fully removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll follow your decision! I think my case was clear and understood so I'm satisfied. I've rebased the config and autofix changes separately to keep that nice 2 commits separation.
@@ -93,20 +91,16 @@ | |||
# no write support, probably under GAE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question that doesn't affect this PR: What's GAE ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Google App Engine? I don't know... the change is from 2009, before setuptools moved to Github and unfortunatelly all references to issues/PR have been messed up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much. This might add some extra work for the currently opened PRs, but I think it is good in the long term. |
The good news is it shouldn't be much: accept both on merge conflict concerning imports, then let Ruff do the rest. |
Summary of changes
As title says.
I've made sure that
_distutils_hack
should be sorted before_distutils
, and thatsetuptools
gets sorted beforedistutils
in tests as long as the hack is supported (ref: #4137 )Pull Request Checklist
newsfragments/
. (no user-facing changes)(See documentation for details)