feat(python): Add option to change the python binary (#1297)
* Add option to change the python binary We are going to start to have problems with the python binary as python2 is removed and replaced with python3. To make the transition easier I have added an option to the python module to allow the user to pick a particular binary, e.g `python3`, for the module to use when selecting the version of python. I have also refactored the python tests moving almost all of them into the module and removing the dependency on the version of python that is installed on the system. * Add advanced config section to python module docs Have added an advanced config section to the python module docs and moved the `python_binary` option into that section.
This commit is contained in:
parent
b563d841c7
commit
055986e2b1
|
@ -1225,6 +1225,25 @@ The module will be shown if any of the following conditions are met:
|
|||
| `style` | `"bold yellow"` | The style for the module. |
|
||||
| `disabled` | `false` | Disables the `python` module. |
|
||||
|
||||
<details>
|
||||
<summary>This module has some advanced configuration options.</summary>
|
||||
|
||||
| Variable | Default | Description |
|
||||
| --------------- | -------- | ---------------------------------------------------------------------------- |
|
||||
| `python_binary` | `python` | Confgures the python binary that Starship executes when getting the version. |
|
||||
|
||||
The `python_binary` variable changes the binary that Starship executes to get
|
||||
the version of Python, it doesn't change the arguments that are used.
|
||||
|
||||
```toml
|
||||
# ~/.config/starship.toml
|
||||
|
||||
[python]
|
||||
python_binary = "python3"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Example
|
||||
|
||||
```toml
|
||||
|
@ -1480,7 +1499,7 @@ will simply show all custom modules in the order they were defined.
|
|||
If unset, it will fallback to STARSHIP_SHELL and then to "sh" on Linux, and "cmd /C" on Windows.
|
||||
|
||||
If `shell` is not given or only contains one element and Starship detects PowerShell will be used,
|
||||
the following arguments will automatically be added: `-NoProfile -Command -`.
|
||||
the following arguments will automatically be added: `-NoProfile -Command -`.
|
||||
This behavior can be avoided by explicitly passing arguments to the shell, e.g.
|
||||
|
||||
```toml
|
||||
|
|
|
@ -9,6 +9,7 @@ pub struct PythonConfig<'a> {
|
|||
pub version: SegmentConfig<'a>,
|
||||
pub pyenv_prefix: SegmentConfig<'a>,
|
||||
pub pyenv_version_name: bool,
|
||||
pub python_binary: &'a str,
|
||||
pub scan_for_pyfiles: bool,
|
||||
pub style: Style,
|
||||
pub disabled: bool,
|
||||
|
@ -21,6 +22,7 @@ impl<'a> RootModuleConfig<'a> for PythonConfig<'a> {
|
|||
version: SegmentConfig::default(),
|
||||
pyenv_prefix: SegmentConfig::new("pyenv "),
|
||||
pyenv_version_name: false,
|
||||
python_binary: "python",
|
||||
scan_for_pyfiles: true,
|
||||
style: Color::Yellow.bold(),
|
||||
disabled: false,
|
||||
|
|
|
@ -49,7 +49,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||
module.create_segment("pyenv_prefix", &config.pyenv_prefix);
|
||||
module.create_segment("version", &SegmentConfig::new(&python_version.trim()));
|
||||
} else {
|
||||
let python_version = get_python_version()?;
|
||||
let python_version = get_python_version(&config.python_binary)?;
|
||||
let formatted_version = format_python_version(&python_version);
|
||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
||||
};
|
||||
|
@ -64,8 +64,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||
Some(module)
|
||||
}
|
||||
|
||||
fn get_python_version() -> Option<String> {
|
||||
match utils::exec_cmd("python", &["--version"]) {
|
||||
fn get_python_version(python_binary: &str) -> Option<String> {
|
||||
match utils::exec_cmd(python_binary, &["--version"]) {
|
||||
Some(output) => {
|
||||
if output.stdout.is_empty() {
|
||||
Some(output.stderr)
|
||||
|
@ -98,6 +98,10 @@ fn get_python_virtual_env() -> Option<String> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::modules::utils::test::render_module;
|
||||
use ansi_term::Color;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
|
||||
#[test]
|
||||
fn test_format_python_version() {
|
||||
|
@ -110,4 +114,149 @@ mod tests {
|
|||
let input = "Python 3.6.10 :: Anaconda, Inc.";
|
||||
assert_eq!(format_python_version(input), "v3.6.10");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_without_python_files() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
let actual = render_module("python", dir.path(), None);
|
||||
let expected = None;
|
||||
assert_eq!(expected, actual);
|
||||
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_with_python_version() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join(".python-version"))?.sync_all()?;
|
||||
|
||||
check_python2_renders(&dir, None);
|
||||
check_python3_renders(&dir, None);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_with_requirements_txt() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("requirements.txt"))?.sync_all()?;
|
||||
|
||||
check_python2_renders(&dir, None);
|
||||
check_python3_renders(&dir, None);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_with_pyproject_toml() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("pyproject.toml"))?.sync_all()?;
|
||||
|
||||
check_python2_renders(&dir, None);
|
||||
check_python3_renders(&dir, None);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_with_pipfile() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("Pipfile"))?.sync_all()?;
|
||||
|
||||
check_python2_renders(&dir, None);
|
||||
check_python3_renders(&dir, None);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_with_tox() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("tox.ini"))?.sync_all()?;
|
||||
|
||||
check_python2_renders(&dir, None);
|
||||
check_python3_renders(&dir, None);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_with_setup_py() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("setup.py"))?.sync_all()?;
|
||||
|
||||
check_python2_renders(&dir, None);
|
||||
check_python3_renders(&dir, None);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_with_init_py() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("__init__.py"))?.sync_all()?;
|
||||
|
||||
check_python2_renders(&dir, None);
|
||||
check_python3_renders(&dir, None);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn folder_with_py_file() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("main.py"))?.sync_all()?;
|
||||
|
||||
check_python2_renders(&dir, None);
|
||||
check_python3_renders(&dir, None);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disabled_scan_for_pyfiles_and_folder_with_ignored_py_file() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("foo.py"))?.sync_all()?;
|
||||
|
||||
let expected = None;
|
||||
let config = toml::toml! {
|
||||
[python]
|
||||
scan_for_pyfiles = false
|
||||
};
|
||||
let actual = render_module("python", dir.path(), Some(config));
|
||||
assert_eq!(expected, actual);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disabled_scan_for_pyfiles_and_folder_with_setup_py() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("setup.py"))?.sync_all()?;
|
||||
|
||||
let config = toml::toml! {
|
||||
[python]
|
||||
scan_for_pyfiles = false
|
||||
};
|
||||
|
||||
check_python2_renders(&dir, Some(config));
|
||||
|
||||
let config_python3 = toml::toml! {
|
||||
[python]
|
||||
python_binary = "python3"
|
||||
scan_for_pyfiles = false
|
||||
};
|
||||
|
||||
check_python3_renders(&dir, Some(config_python3));
|
||||
|
||||
dir.close()
|
||||
}
|
||||
|
||||
fn check_python2_renders(dir: &tempfile::TempDir, starship_config: Option<toml::Value>) {
|
||||
let actual = render_module("python", dir.path(), starship_config);
|
||||
let expected = Some(format!("via {} ", Color::Yellow.bold().paint("🐍 v2.7.17")));
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
fn check_python3_renders(dir: &tempfile::TempDir, starship_config: Option<toml::Value>) {
|
||||
let config = Some(starship_config.unwrap_or(toml::toml! {
|
||||
[python]
|
||||
python_binary = "python3"
|
||||
}));
|
||||
|
||||
let actual = render_module("python", dir.path(), config);
|
||||
let expected = Some(format!("via {} ", Color::Yellow.bold().paint("🐍 v3.8.0")));
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,14 @@ active boot switches: -d:release\n",
|
|||
stdout: String::from("0.13.5"),
|
||||
stderr: String::default(),
|
||||
}),
|
||||
"python --version" => Some(CommandOutput {
|
||||
stdout: String::from("Python 2.7.17"),
|
||||
stderr: String::default(),
|
||||
}),
|
||||
"python3 --version" => Some(CommandOutput {
|
||||
stdout: String::from("Python 3.8.0"),
|
||||
stderr: String::default(),
|
||||
}),
|
||||
"ruby -v" => Some(CommandOutput {
|
||||
stdout: String::from("ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-gnu]"),
|
||||
stderr: String::default(),
|
||||
|
|
|
@ -1,163 +1,12 @@
|
|||
use std::fs::File;
|
||||
use std::io;
|
||||
|
||||
use ansi_term::Color;
|
||||
use crate::common;
|
||||
|
||||
use crate::common::{self, TestCommand};
|
||||
// TODO - These tests should be moved into the python module when we have sorted out mocking of env
|
||||
// vars.
|
||||
|
||||
#[test]
|
||||
fn show_nothing_on_empty_dir() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = "";
|
||||
assert_eq!(expected, actual);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn folder_with_python_version() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join(".python-version"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn folder_with_requirements_txt() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("requirements.txt"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn folder_with_pyproject_toml() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("pyproject.toml"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn folder_with_pipfile() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("Pipfile"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn folder_with_tox() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("tox.ini"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn folder_with_setup_py() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("setup.py"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn folder_with_init_py() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("__init__.py"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn folder_with_py_file() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("main.py"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn with_virtual_env() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("main.py"))?.sync_all()?;
|
||||
|
@ -168,13 +17,11 @@ fn with_virtual_env() -> io::Result<()> {
|
|||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7 (my_venv)"));
|
||||
assert_eq!(expected, actual);
|
||||
assert!(actual.contains("my_venv"));
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn with_active_venv() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
|
||||
|
@ -185,48 +32,6 @@ fn with_active_venv() -> io::Result<()> {
|
|||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7 (my_venv)"));
|
||||
assert_eq!(expected, actual);
|
||||
assert!(actual.contains("my_venv"));
|
||||
dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disabled_scan_for_pyfiles_and_folder_with_ignored_py_file() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("foo.py"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.use_config(toml::toml! {
|
||||
[python]
|
||||
scan_for_pyfiles = false
|
||||
})
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = "";
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn disabled_scan_for_pyfiles_and_folder_with_setup_py() -> io::Result<()> {
|
||||
let dir = tempfile::tempdir()?;
|
||||
File::create(dir.path().join("setup.py"))?.sync_all()?;
|
||||
|
||||
let output = common::render_module("python")
|
||||
.use_config(toml::toml! {
|
||||
[python]
|
||||
scan_for_pyfiles = false
|
||||
})
|
||||
.arg("--path")
|
||||
.arg(dir.path())
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.7.7"));
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue