1use std::io;
2use std::path::{Path, PathBuf};
3
4use thiserror::Error;
5
6use uv_fs::Simplified;
7use uv_python::{Interpreter, PythonEnvironment};
8
9pub use virtualenv::{ClearNonVirtualenv, OnExisting, RemovalReason};
10
11mod virtualenv;
12
13#[derive(Debug, Error)]
14pub enum Error {
15 #[error(transparent)]
16 Io(#[from] io::Error),
17 #[error(
18 "Could not find a suitable Python executable for the virtual environment based on the interpreter: {0}"
19 )]
20 NotFound(String),
21 #[error(transparent)]
22 Python(#[from] uv_python::managed::Error),
23 #[error("A {name} already exists at: {}", path.user_display())]
24 Exists {
25 name: &'static str,
27 path: PathBuf,
29 },
30 #[error("uv will not clear a directory that is not a virtual environment")]
31 ClearNonVirtualenv {
32 path: PathBuf,
34 },
35}
36
37impl uv_errors::Hint for Error {
38 fn hints(&self) -> uv_errors::Hints<'_> {
39 match self {
40 Self::Exists { name, .. } => uv_errors::Hints::from(format!(
41 "Use the `--clear` flag or set `UV_VENV_CLEAR=1` to replace the existing {name}",
42 )),
43 Self::ClearNonVirtualenv { .. } => uv_errors::Hints::from(
44 "Use the `--force` flag to remove the existing directory anyway",
45 ),
46 _ => uv_errors::Hints::none(),
47 }
48 }
49}
50
51#[derive(Debug)]
53pub enum Prompt {
54 CurrentDirectoryName,
56 Static(String),
58 None,
61}
62
63impl Prompt {
64 pub fn from_args(prompt: Option<String>) -> Self {
66 match prompt {
67 Some(prompt) if prompt == "." => Self::CurrentDirectoryName,
68 Some(prompt) => Self::Static(prompt),
69 None => Self::None,
70 }
71 }
72}
73
74#[expect(clippy::fn_params_excessive_bools)]
76pub fn create_venv(
77 location: &Path,
78 interpreter: Interpreter,
79 prompt: Prompt,
80 system_site_packages: bool,
81 on_existing: OnExisting,
82 relocatable: bool,
83 seed: bool,
84 upgradeable: bool,
85) -> Result<PythonEnvironment, Error> {
86 let virtualenv = virtualenv::create(
88 location,
89 &interpreter,
90 prompt,
91 system_site_packages,
92 on_existing,
93 relocatable,
94 seed,
95 upgradeable,
96 )?;
97
98 let interpreter = interpreter.with_virtualenv(virtualenv);
100 Ok(PythonEnvironment::from_interpreter(interpreter))
101}