mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-30 11:37:24 +00:00
Run interpreter discovery under -I mode (#2552)
## Summary
If you have a file `typing.py` in the current working directory, `python
-m` doesn't work in some Python versions:
```sh
❯ python -m foo
Could not import runpy module
Traceback (most recent call last):
File "/Users/crmarsh/.local/share/rtx/installs/python/3.9.18/lib/python3.9/runpy.py", line 15, in <module>
import importlib.util
File "/Users/crmarsh/.local/share/rtx/installs/python/3.9.18/lib/python3.9/importlib/util.py", line 2, in <module>
from . import abc
File "/Users/crmarsh/.local/share/rtx/installs/python/3.9.18/lib/python3.9/importlib/abc.py", line 17, in <module>
from typing import Protocol, runtime_checkable
ImportError: cannot import name 'Protocol' from 'typing' (/Users/crmarsh/workspace/uv/typing.py)
```
This did _not_ cause problems for us on Python 3.11 or later, because we
set `PYTHONSAFEPATH`, which avoids adding the current working directory
to `sys.path`. However, on earlier versions, we _were_ failing with the
above. (It's important that we run interpreter discovery in the current
working directory, since doing otherwise breaks pyenv shims.)
The fix implemented here uses `-I` to run Python in isolated mode, which
is even stricter. The downside of isolated mode is that we currently
rely on setting `PYTHONPATH` to find the "fake module" that we create on
disk, and `-I` means `PYTHONPATH` is totally ignored. So, instead, we
run a script directly, and that _script_ injects the path we care about
into `PYTHONSAFEPATH`.
Closes https://github.com/astral-sh/uv/issues/2547.
This commit is contained in:
parent
79fbac7af5
commit
c180fedbce
4 changed files with 63 additions and 38 deletions
|
|
@ -15,7 +15,7 @@ use platform_tags::Platform;
|
|||
use platform_tags::{Tags, TagsError};
|
||||
use pypi_types::Scheme;
|
||||
use uv_cache::{Cache, CacheBucket, CachedByTimestamp, Freshness, Timestamp};
|
||||
use uv_fs::{write_atomic_sync, Simplified};
|
||||
use uv_fs::{write_atomic_sync, PythonExt, Simplified};
|
||||
|
||||
use crate::Error;
|
||||
use crate::Virtualenv;
|
||||
|
|
@ -369,11 +369,17 @@ impl InterpreterInfo {
|
|||
let tempdir = tempfile::tempdir_in(cache.root())?;
|
||||
Self::setup_python_query_files(tempdir.path())?;
|
||||
|
||||
// Sanitize the path by (1) running under isolated mode (`-I`) to ignore any site packages
|
||||
// modifications, and then (2) adding the path containing our query script to the front of
|
||||
// `sys.path` so that we can import it.
|
||||
let script = format!(
|
||||
r#"import sys; sys.path = ["{}"] + sys.path; from python.get_interpreter_info import main; main()"#,
|
||||
tempdir.path().escape_for_python()
|
||||
);
|
||||
let output = Command::new(interpreter)
|
||||
.arg("-m")
|
||||
.arg("python.get_interpreter_info")
|
||||
.env("PYTHONPATH", tempdir.path())
|
||||
.env("PYTHONSAFEPATH", "1")
|
||||
.arg("-I")
|
||||
.arg("-c")
|
||||
.arg(script)
|
||||
.output()
|
||||
.map_err(|err| Error::PythonSubcommandLaunch {
|
||||
interpreter: interpreter.to_path_buf(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue