-
-
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
[BUG] DistutilsMetaFinder breaks distutils submodule imports when old setuptools is higher on path #3073
Comments
Thanks for your patience. I'm getting ramped up on this issue today and I'd like to come up with a robust fix. Thanks for your investigation and linking to prior issues. I'll continue to explore this issue here. |
I'm starting to get a grasp of the underlying behavior here. At first, I was surprised that the technique as currently implemented wouldn't have the intended behavior. I could replicate the reported failure, but when I looked at the importer code, I would have expected the exceptional condition to take place and thus allow a fallback to the traditional behavior. But then I realized that I don't yet understand Python's import internals enough to understand why that results in a distutils module without its submodule attributes. I might have expected the importer to crash, but I guess the importer has to be robust to lots of circular dependencies. My only instinct here is that the act of |
I put together this patch:
It does have the desired effect of working around the issue, but it has the undesirable effect that it breaks pip upgrades of setuptools from source (because the directory with the .pth file is different from the source directory, so the distutils hack doesn't load, and setuptools assertion to ensure_local_distutils fails). In other words, some workflows are actually depending on the behavior that distutils is loaded from a setuptools where the hack is not. I considered perhaps making this exception only when imported from .pth but not when installed as part of Other options I'm considering:
I don't have any good solutions yet. The problem landscape is already very complicated (also by things like pip exclusions), so I'm not confident that the problem space is well understood or even has a viable solution. |
(original reporter of this issue here): Yeah, we're also still hitting different permutations of this with current setuptools where the "wrong distutils" assert is firing in mixed situations where it shouldn't (usually when a system-site-packages venv with ancient setuptools is involved)- we're doing the envvar hack disable to limp along, but we really need to figure out a broader solution before this gets bigger (and it likely will). Still willing to pitch in more on that if needed... |
I explored the environment where this is issue is occurring and I think I have an understanding on the problem. The root of the issue is that A breakdown of the process is:
The key take away is that importing Reverting the changes to diff --git a/_distutils_hack/__init__.py b/_distutils_hack/__init__.py
index 605a6edc..547dcbfd 100644
--- a/_distutils_hack/__init__.py
+++ b/_distutils_hack/__init__.py
@@ -98,8 +98,10 @@ class DistutilsMetaFinder:
import importlib.util
try:
+ sys_modules_before_import = sys.modules.copy()
mod = importlib.import_module('setuptools._distutils')
except Exception:
+ sys.modules = sys_modules_before_import
# There are a couple of cases where setuptools._distutils
# may not be present:
# - An older Setuptools without a local distutils is Another option is to call I'd be happy to submit a PR with either change. I found the following toy example helpful while exploring this behavior
This script replicates the behavior: class Finder:
def find_spec(self, fullname, path, target=None):
if fullname == "b":
import a
return
import sys
sys.meta_path.insert(0, Finder())
import b.x
print(b.x) |
setuptools version
setuptools====60.7.0
Python version
Python 3.7
OS
macOS
Additional environment information
Similar to #2957, this occurs when an old setuptools is on path but a newer setuptools (with a distutils shimming .pth file) is installed.
Description
This is a followup to #2957 where the .pth shim broke distutils imports when an older setuptools is higher on path. The fix in #2962 allows distutils to be imported as well as submodules, but those submodules are not usable.
I'm running into this issue when running a PEX which contains an older version of setuptools but the Python interpreter has a newer version of setuptools. In the bootstrap phase pex removes the new setuptools from sys.path and adds the older setuptools. DistutilsMetaFinder is not removed from sys.meta_path during this phase and causes distutils submodules to fail.
Expected behavior
The presence of a new-but-not-loadable setuptools on sys.path doesn't break distutils submodules.
How to Reproduce
As in #2957 a reproducer is:
Output
The text was updated successfully, but these errors were encountered: