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

Sort imports for more consistent diff (ruff/isort) #4392

Merged
merged 2 commits into from
Aug 12, 2024

Conversation

Avasam
Copy link
Contributor

@Avasam Avasam commented May 23, 2024

Summary of changes

As title says.
I've made sure that _distutils_hack should be sorted before _distutils, and that setuptools gets sorted before distutils in tests as long as the hack is supported (ref: #4137 )

Pull Request Checklist

@Avasam Avasam force-pushed the ruff-isort branch 2 times, most recently from 913eedb to 6287b8d Compare June 14, 2024 20:29
@Avasam Avasam force-pushed the ruff-isort branch 2 times, most recently from 2f2f68a to d8c8dcc Compare July 1, 2024 16:17
@Avasam Avasam changed the title Sort imports for more consistent diff Sort imports for more consistent diff (ruff/isort) Jul 1, 2024
Comment on lines +81 to +84
from os import open as os_open, utime # isort: skip
from os.path import isdir, split # isort: skip
Copy link
Contributor Author

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
Copy link
Contributor Author

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
Copy link
Contributor Author

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
Copy link
Contributor Author

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)

Copy link
Contributor

@abravalheri abravalheri left a 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
Comment on lines 66 to 67
known-third-party = ["setuptools"]
known-first-party = ["distutils"]
Copy link
Contributor

@abravalheri abravalheri Aug 9, 2024

Choose a reason for hiding this comment

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

Would this make sense?

Suggested change
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

Copy link
Contributor Author

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 !

@Avasam
Copy link
Contributor Author

Avasam commented Aug 9, 2024

I think in the case of this PR it would be interesting in separating 2 commits

Certainly, now that I have confirmation this is indeed wanted, I'll be cautious about keeping it into 2 clean commits.

implies in more coordination with the other PRs for the best moment/order to merge, but I think we can do that.

Hence I've been lazily merging conflicts until now ^^ (with an occasional soft reset)

Copy link
Contributor

@abravalheri abravalheri left a 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"]
Copy link
Contributor

@abravalheri abravalheri Aug 12, 2024

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.

Suggested change
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

Copy link
Contributor Author

@Avasam Avasam Aug 12, 2024

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:

image
image
(overly zealous prints but I'm trying to remove assumptions from my proof)

It was also already that way for most imports.

Copy link
Contributor

@abravalheri abravalheri Aug 12, 2024

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.

Copy link
Contributor Author

@Avasam Avasam Aug 12, 2024

Choose a reason for hiding this comment

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

As long as eager is before first-party, local-folder and delayed yeah

Just to be clear, I think swapping the order of "local-folder" and "delayed" works in both cases. I'm arguing for keeping the expectation and habit of putting relative imports last.
(prefering left side in this image)
image

Copy link
Contributor

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

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 setuptools2.

Footnotes

  1. For example to solve cycles, Python import machinery may start evaluating the parent module, then interrupt this evaluation in favour of children module, then proceed to finish the evaluation of the parent module.

  2. Unless we verify an unintended consequence and we need to revert.

Copy link
Contributor

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.

Copy link
Contributor Author

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
Copy link
Contributor Author

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 ?

Copy link
Contributor

@abravalheri abravalheri Aug 12, 2024

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.

Copy link
Contributor Author

@Avasam Avasam Aug 12, 2024

Choose a reason for hiding this comment

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

@abravalheri abravalheri merged commit fa10e36 into pypa:main Aug 12, 2024
21 checks passed
@abravalheri
Copy link
Contributor

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.

@Avasam
Copy link
Contributor Author

Avasam commented Aug 12, 2024

some extra work for the currently opened PRs

The good news is it shouldn't be much: accept both on merge conflict concerning imports, then let Ruff do the rest.

@Avasam Avasam deleted the ruff-isort branch August 12, 2024 16:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants