Compare commits
2 Commits
zb/virtual
...
zb/ignore-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a90f33781 | ||
|
|
1f8b187aa1 |
@@ -175,6 +175,13 @@ pub(crate) struct CheckCommand {
|
||||
/// For example, spinners or progress bars.
|
||||
#[arg(global = true, long, value_parser = clap::builder::BoolishValueParser::new(), help_heading = "Global options")]
|
||||
pub no_progress: bool,
|
||||
|
||||
/// Ignore the `VIRTUAL_ENV` environment variable when discovering the Python environment.
|
||||
///
|
||||
/// This is useful when a tool wrapping ty activates a virtual environment but you would
|
||||
/// prefer to discover the `.venv` in the working directory.
|
||||
#[arg(long, hide = true)]
|
||||
pub(crate) ignore_active_virtual_env: bool,
|
||||
}
|
||||
|
||||
impl CheckCommand {
|
||||
|
||||
@@ -114,6 +114,7 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
|
||||
let system = OsSystem::new(&cwd);
|
||||
let watch = args.watch;
|
||||
let exit_zero = args.exit_zero;
|
||||
let ignore_active_virtual_env = args.ignore_active_virtual_env;
|
||||
let config_file = args
|
||||
.config_file
|
||||
.as_ref()
|
||||
@@ -125,6 +126,7 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
|
||||
};
|
||||
|
||||
project_metadata.apply_configuration_files(&system)?;
|
||||
project_metadata.set_ignore_active_virtual_env(ignore_active_virtual_env);
|
||||
|
||||
let project_options_overrides = ProjectOptionsOverrides::new(config_file, args.into_options());
|
||||
project_metadata.apply_overrides(&project_options_overrides);
|
||||
|
||||
@@ -2703,3 +2703,123 @@ fn pythonpath_multiple_dirs_is_respected() -> anyhow::Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// When `--ignore-active-virtual-env` is passed, ty should ignore the `VIRTUAL_ENV`
|
||||
/// environment variable and fall back to other discovery mechanisms.
|
||||
#[test]
|
||||
fn ignore_active_virtual_env() -> anyhow::Result<()> {
|
||||
let active_venv_package1_path = if cfg!(windows) {
|
||||
"myvenv/Lib/site-packages/package1/__init__.py"
|
||||
} else {
|
||||
"myvenv/lib/python3.13/site-packages/package1/__init__.py"
|
||||
};
|
||||
|
||||
let working_venv_package1_path = if cfg!(windows) {
|
||||
"project/.venv/Lib/site-packages/package1/__init__.py"
|
||||
} else {
|
||||
"project/.venv/lib/python3.13/site-packages/package1/__init__.py"
|
||||
};
|
||||
|
||||
let case = CliTest::with_files([
|
||||
(
|
||||
"project/test.py",
|
||||
r#"
|
||||
from package1 import ActiveVenv
|
||||
from package1 import WorkingVenv
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"project/.venv/pyvenv.cfg",
|
||||
r#"
|
||||
home = ./
|
||||
|
||||
"#,
|
||||
),
|
||||
(
|
||||
"myvenv/pyvenv.cfg",
|
||||
r#"
|
||||
home = ./
|
||||
|
||||
"#,
|
||||
),
|
||||
(
|
||||
active_venv_package1_path,
|
||||
r#"
|
||||
class WorkingVenv: ...
|
||||
"#,
|
||||
),
|
||||
(
|
||||
working_venv_package1_path,
|
||||
r#"
|
||||
class ActiveVenv: ...
|
||||
"#,
|
||||
),
|
||||
])?;
|
||||
|
||||
// With `VIRTUAL_ENV` set, the active environment is found
|
||||
assert_cmd_snapshot!(case.command()
|
||||
.current_dir(case.root().join("project"))
|
||||
.env("VIRTUAL_ENV", case.root().join("myvenv")), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
error[unresolved-import]: Module `package1` has no member `ActiveVenv`
|
||||
--> test.py:2:22
|
||||
|
|
||||
2 | from package1 import ActiveVenv
|
||||
| ^^^^^^^^^^
|
||||
3 | from package1 import WorkingVenv
|
||||
|
|
||||
info: rule `unresolved-import` is enabled by default
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// With `--ignore-active-virtual-env`, we ignore `VIRTUAL_ENV` and find the `.venv` instead
|
||||
assert_cmd_snapshot!(case.command()
|
||||
.current_dir(case.root().join("project"))
|
||||
.env("VIRTUAL_ENV", case.root().join("myvenv"))
|
||||
.arg("--ignore-active-virtual-env"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
error[unresolved-import]: Module `package1` has no member `WorkingVenv`
|
||||
--> test.py:3:22
|
||||
|
|
||||
2 | from package1 import ActiveVenv
|
||||
3 | from package1 import WorkingVenv
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
info: rule `unresolved-import` is enabled by default
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// We still find `.venv` when activated and `--ignore-active-virtual-env` is passed
|
||||
assert_cmd_snapshot!(case.command()
|
||||
.current_dir(case.root().join("project"))
|
||||
.env("VIRTUAL_ENV", case.root().join(".venv"))
|
||||
.arg("--ignore-active-virtual-env"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
error[unresolved-import]: Module `package1` has no member `WorkingVenv`
|
||||
--> test.py:3:22
|
||||
|
|
||||
2 | from package1 import ActiveVenv
|
||||
3 | from package1 import WorkingVenv
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
info: rule `unresolved-import` is enabled by default
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -37,6 +37,11 @@ pub struct ProjectMetadata {
|
||||
/// The path ordering doesn't imply precedence.
|
||||
#[cfg_attr(test, serde(skip_serializing_if = "Vec::is_empty"))]
|
||||
pub(super) extra_configuration_paths: Vec<SystemPathBuf>,
|
||||
|
||||
/// If true, ignore the `VIRTUAL_ENV` environment variable when discovering
|
||||
/// the Python environment.
|
||||
#[cfg_attr(test, serde(skip_serializing_if = "std::ops::Not::not"))]
|
||||
pub(super) ignore_active_virtual_env: bool,
|
||||
}
|
||||
|
||||
impl ProjectMetadata {
|
||||
@@ -47,6 +52,7 @@ impl ProjectMetadata {
|
||||
root,
|
||||
extra_configuration_paths: Vec::default(),
|
||||
options: Options::default(),
|
||||
ignore_active_virtual_env: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +76,7 @@ impl ProjectMetadata {
|
||||
root: system.current_directory().to_path_buf(),
|
||||
options,
|
||||
extra_configuration_paths: vec![path],
|
||||
ignore_active_virtual_env: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -117,6 +124,7 @@ impl ProjectMetadata {
|
||||
root,
|
||||
options,
|
||||
extra_configuration_paths: Vec::new(),
|
||||
ignore_active_virtual_env: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -268,13 +276,22 @@ impl ProjectMetadata {
|
||||
&self.extra_configuration_paths
|
||||
}
|
||||
|
||||
pub fn set_ignore_active_virtual_env(&mut self, ignore: bool) {
|
||||
self.ignore_active_virtual_env = ignore;
|
||||
}
|
||||
|
||||
pub fn to_program_settings(
|
||||
&self,
|
||||
system: &dyn System,
|
||||
vendored: &VendoredFileSystem,
|
||||
) -> anyhow::Result<ProgramSettings> {
|
||||
self.options
|
||||
.to_program_settings(self.root(), self.name(), system, vendored)
|
||||
self.options.to_program_settings(
|
||||
self.root(),
|
||||
self.name(),
|
||||
system,
|
||||
vendored,
|
||||
self.ignore_active_virtual_env,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn apply_overrides(&mut self, overrides: &ProjectOptionsOverrides) {
|
||||
|
||||
@@ -117,6 +117,7 @@ impl Options {
|
||||
project_name: &str,
|
||||
system: &dyn System,
|
||||
vendored: &VendoredFileSystem,
|
||||
ignore_active_virtual_env: bool,
|
||||
) -> anyhow::Result<ProgramSettings> {
|
||||
let environment = self.environment.or_default();
|
||||
|
||||
@@ -160,7 +161,7 @@ impl Options {
|
||||
system,
|
||||
)?)
|
||||
} else {
|
||||
PythonEnvironment::discover(project_root, system)
|
||||
PythonEnvironment::discover(project_root, system, ignore_active_virtual_env)
|
||||
.context("Failed to discover local Python environment")?
|
||||
};
|
||||
|
||||
|
||||
@@ -163,6 +163,7 @@ impl PythonEnvironment {
|
||||
pub fn discover(
|
||||
project_root: &SystemPath,
|
||||
system: &dyn System,
|
||||
ignore_active_virtual_env: bool,
|
||||
) -> Result<Option<Self>, SitePackagesDiscoveryError> {
|
||||
fn resolve_environment(
|
||||
system: &dyn System,
|
||||
@@ -173,13 +174,9 @@ impl PythonEnvironment {
|
||||
PythonEnvironment::new(path, origin, system)
|
||||
}
|
||||
|
||||
if let Ok(virtual_env) = system.env_var(EnvVars::VIRTUAL_ENV) {
|
||||
return resolve_environment(
|
||||
system,
|
||||
SystemPath::new(&virtual_env),
|
||||
SysPrefixPathOrigin::VirtualEnvVar,
|
||||
)
|
||||
.map(Some);
|
||||
if let Some(virtual_env) = virtual_environment_from_env(system, ignore_active_virtual_env) {
|
||||
return resolve_environment(system, &virtual_env, SysPrefixPathOrigin::VirtualEnvVar)
|
||||
.map(Some);
|
||||
}
|
||||
|
||||
if let Some(conda_env) = conda_environment_from_env(system, CondaEnvironmentKind::Child) {
|
||||
@@ -696,6 +693,24 @@ pub(crate) fn conda_environment_from_env(
|
||||
Some(path)
|
||||
}
|
||||
|
||||
/// Read `VIRTUAL_ENV`.
|
||||
///
|
||||
/// Returns `None` if `ignore` is `true`.
|
||||
pub(crate) fn virtual_environment_from_env(
|
||||
system: &dyn System,
|
||||
ignore: bool,
|
||||
) -> Option<SystemPathBuf> {
|
||||
if ignore {
|
||||
tracing::debug!(
|
||||
"Ignoring active virtual environment (from `VIRTUAL_ENV`) due to `--ignore-active-virtual-env`"
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
let dir = system.env_var(EnvVars::VIRTUAL_ENV).ok()?;
|
||||
Some(SystemPathBuf::from(dir))
|
||||
}
|
||||
|
||||
/// A parser for `pyvenv.cfg` files: metadata files for virtual environments.
|
||||
///
|
||||
/// Note that a `pyvenv.cfg` file *looks* like a `.ini` file, but actually isn't valid `.ini` syntax!
|
||||
|
||||
Reference in New Issue
Block a user