feat(python): add option to use the parent directory as venv name

This commit is contained in:
RFCreate 2025-01-26 16:54:34 -06:00
parent beff0a1988
commit a9b2816b74
4 changed files with 67 additions and 20 deletions

View File

@ -1450,6 +1450,10 @@
"python3",
"python2"
],
"override_venv_names": [
".venv",
"venv"
],
"style": "yellow bold",
"symbol": "🐍 ",
"version_format": "v${raw}"
@ -5361,6 +5365,15 @@
"items": {
"type": "string"
}
},
"override_venv_names": {
"default": [
""
],
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false

View File

@ -3700,19 +3700,20 @@ By default, the module will be shown if any of the following conditions are met:
### Options
| Option | Default | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `format` | `'via [${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'` | The format for the module. |
| `version_format` | `'v${raw}'` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
| `symbol` | `'🐍 '` | A format string representing the symbol of Python |
| `style` | `'yellow bold'` | The style for the module. |
| `pyenv_version_name` | `false` | Use pyenv to get Python version |
| `pyenv_prefix` | `'pyenv'` | Prefix before pyenv version display, only used if pyenv is used |
| `python_binary` | `['python', 'python3', 'python2']` | Configures the python binaries that Starship should executes when getting the version. |
| `detect_extensions` | `['py', 'ipynb']` | Which extensions should trigger this module |
| `detect_files` | `['.python-version', 'Pipfile', '__init__.py', 'pyproject.toml', 'requirements.txt', 'setup.py', 'tox.ini', 'pixi.toml']` | Which filenames should trigger this module |
| `detect_folders` | `[]` | Which folders should trigger this module |
| `disabled` | `false` | Disables the `python` module. |
| Option | Default | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `format` | `'via [${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'` | The format for the module. |
| `version_format` | `'v${raw}'` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` |
| `symbol` | `'🐍 '` | A format string representing the symbol of Python |
| `style` | `'yellow bold'` | The style for the module. |
| `pyenv_version_name` | `false` | Use pyenv to get Python version |
| `pyenv_prefix` | `'pyenv'` | Prefix before pyenv version display, only used if pyenv is used |
| `python_binary` | `['python', 'python3', 'python2']` | Configures the python binaries that Starship should executes when getting the version. |
| `detect_extensions` | `['py', 'ipynb']` | Which extensions should trigger this module |
| `detect_files` | `['.python-version', 'Pipfile', '__init__.py', 'pyproject.toml', 'requirements.txt', 'setup.py', 'tox.ini', 'pixi.toml']` | Which filenames should trigger this module |
| `detect_folders` | `[]` | Which folders should trigger this module |
| `override_venv_names` | `['.venv', 'venv']` | Which venv names should be replaced with the parent directory name. |
| `disabled` | `false` | Disables the `python` module. |
::: tip

View File

@ -22,6 +22,7 @@ pub struct PythonConfig<'a> {
pub detect_files: Vec<&'a str>,
pub detect_folders: Vec<&'a str>,
pub detect_env_vars: Vec<&'a str>,
pub override_venv_names: Vec<&'a str>,
}
impl Default for PythonConfig<'_> {
@ -48,6 +49,7 @@ impl Default for PythonConfig<'_> {
],
detect_folders: vec![],
detect_env_vars: vec!["VIRTUAL_ENV"],
override_venv_names: vec![".venv", "venv"],
}
}
}

View File

@ -56,7 +56,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
.map(Ok)
}
"virtualenv" => {
let virtual_env = get_python_virtual_env(context);
let virtual_env = get_python_virtual_env(context, &config);
virtual_env.as_ref().map(|e| Ok(e.trim().to_string()))
}
"pyenv_prefix" => Some(Ok(pyenv_prefix.to_string())),
@ -113,13 +113,9 @@ fn parse_python_version(python_version_string: &str) -> Option<String> {
Some(version.to_string())
}
fn get_python_virtual_env(context: &Context) -> Option<String> {
fn get_python_virtual_env(context: &Context, config: &PythonConfig) -> Option<String> {
context.get_env("VIRTUAL_ENV").and_then(|venv| {
get_prompt_from_venv(Path::new(&venv)).or_else(|| {
Path::new(&venv)
.file_name()
.map(|filename| String::from(filename.to_str().unwrap_or("")))
})
get_prompt_from_venv(Path::new(&venv)).or_else(|| get_venv_name(Path::new(&venv), config))
})
}
@ -131,6 +127,19 @@ fn get_prompt_from_venv(venv_path: &Path) -> Option<String> {
.map(|prompt| String::from(prompt.trim_matches(&['(', ')'] as &[_])))
}
fn get_venv_name(venv_path: &Path, config: &PythonConfig) -> Option<String> {
let mut venv_name = venv_path
.file_name()
.map(|filename| filename.to_str().unwrap_or(""));
if venv_name.map(|name| config.override_venv_names.contains(&name))? {
venv_name = venv_path
.parent()
.and_then(|parent| parent.file_name())
.map(|filename| filename.to_str().unwrap_or(""));
}
venv_name.map(|name| name.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
@ -396,6 +405,28 @@ Python 3.7.9 (7e6e2bb30ac5fbdbd443619cae28c51d5c162a02, Nov 24 2020, 10:03:59)
dir.close()
}
#[test]
fn with_active_venv_and_override_venv_names() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let actual = ModuleRenderer::new("python")
.path(dir.path())
.env("VIRTUAL_ENV", "/foo/bar/my_venv")
.config(toml::toml! {
[python]
override_venv_names = [".venv", "venv", "my_venv"]
})
.collect();
let expected = Some(format!(
"via {}",
Color::Yellow.bold().paint("🐍 v3.8.0 (bar) ")
));
assert_eq!(actual, expected);
dir.close()
}
#[test]
fn with_different_env_var() -> io::Result<()> {
let dir = tempfile::tempdir()?;