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, Seed};
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 #[error("Virtual environment path is not valid UTF-8: {}", path.user_display())]
36 NonUtf8Path {
37 path: PathBuf,
39 },
40}
41
42impl uv_errors::Hint for Error {
43 fn hints(&self) -> uv_errors::Hints<'_> {
44 match self {
45 Self::Exists { name, .. } => uv_errors::Hints::from(format!(
46 "Use the `--clear` flag or set `UV_VENV_CLEAR=1` to replace the existing {name}",
47 )),
48 Self::ClearNonVirtualenv { .. } => uv_errors::Hints::from(
49 "Use the `--force` flag to remove the existing directory anyway",
50 ),
51 _ => uv_errors::Hints::none(),
52 }
53 }
54}
55
56#[derive(Debug)]
58pub enum Prompt {
59 CurrentDirectoryName,
61 Static(String),
63 None,
66}
67
68impl Prompt {
69 pub fn from_args(prompt: Option<String>) -> Self {
71 match prompt {
72 Some(prompt) if prompt == "." => Self::CurrentDirectoryName,
73 Some(prompt) => Self::Static(prompt),
74 None => Self::None,
75 }
76 }
77}
78
79pub fn create_venv(
81 location: &Path,
82 interpreter: Interpreter,
83 prompt: Prompt,
84 system_site_packages: bool,
85 on_existing: OnExisting,
86 relocatable: bool,
87 seed: Seed,
88 upgradeable: bool,
89) -> Result<PythonEnvironment, Error> {
90 let virtualenv = virtualenv::create(
92 location,
93 &interpreter,
94 prompt,
95 system_site_packages,
96 on_existing,
97 relocatable,
98 seed,
99 upgradeable,
100 )?;
101
102 let interpreter = interpreter.with_virtualenv(virtualenv);
104 Ok(PythonEnvironment::from_interpreter(interpreter))
105}