From 1b938fd48420ceedf1e9886bd95ea738374680f7 Mon Sep 17 00:00:00 2001 From: Tom Fleet Date: Mon, 2 May 2022 17:44:01 +0100 Subject: [PATCH] feat(package): Extract package version from PEP 621 compliant pyproject.toml (#3950) * feat(package): Extract package version from PEP621 pyproject.toml * Update docs explaining PEP 621 package version * Only read pyproject.toml once * Simplify get_pep621_version * Handle version formatting in get_pyproject_version --- docs/config/README.md | 4 +- src/modules/package.rs | 86 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/docs/config/README.md b/docs/config/README.md index a3251cbe..1cc73c80 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -2503,7 +2503,7 @@ symbol = "☁️ " The `package` module is shown when the current directory is the repository for a package, and shows its current version. The module currently supports `npm`, `nimble`, `cargo`, -`poetry`, `composer`, `gradle`, `julia`, `mix`, `helm`, `shards` and `dart` packages. +`poetry`, `python`, `composer`, `gradle`, `julia`, `mix`, `helm`, `shards` and `dart` packages. - [**npm**](https://docs.npmjs.com/cli/commands/npm) – The `npm` package version is extracted from the `package.json` present in the current directory @@ -2511,7 +2511,7 @@ package, and shows its current version. The module currently supports `npm`, `ni - [**Nimble**](https://github.com/nim-lang/nimble) - The `nimble` package version is extracted from the `*.nimble` file present in the current directory with the `nimble dump` command - [**Poetry**](https://python-poetry.org/) – The `poetry` package version is extracted from the `pyproject.toml` present in the current directory -- [**Python**](https://www.python.org) - The `python` package version is extracted from the `setup.cfg` present in the current directory +- [**Python**](https://www.python.org) - The `python` package version is extracted from a [PEP 621](https://peps.python.org/pep-0621/) compliant `pyproject.toml` or a `setup.cfg` present in the current directory - [**Composer**](https://getcomposer.org/) – The `composer` package version is extracted from the `composer.json` present in the current directory - [**Gradle**](https://gradle.org/) – The `gradle` package version is extracted from the `build.gradle` present diff --git a/src/modules/package.rs b/src/modules/package.rs index d8de5468..29ad7aa4 100644 --- a/src/modules/package.rs +++ b/src/modules/package.rs @@ -66,16 +66,25 @@ fn get_node_package_version(context: &Context, config: &PackageConfig) -> Option Some(formatted_version) } -fn get_poetry_version(context: &Context, config: &PackageConfig) -> Option { - let file_contents = context.read_file_from_pwd("pyproject.toml")?; - let poetry_toml: toml::Value = toml::from_str(&file_contents).ok()?; - let raw_version = poetry_toml +fn get_poetry_version(pyproject: &toml::Value) -> Option<&str> { + pyproject .get("tool")? .get("poetry")? .get("version")? - .as_str()?; + .as_str() +} - format_version(raw_version, config.version_format) +fn get_pep621_version(pyproject: &toml::Value) -> Option<&str> { + pyproject.get("project")?.get("version")?.as_str() +} + +fn get_pyproject_version(context: &Context, config: &PackageConfig) -> Option { + let file_contents = context.read_file_from_pwd("pyproject.toml")?; + let pyproject_toml: toml::Value = toml::from_str(&file_contents).ok()?; + + get_pep621_version(&pyproject_toml) + .or_else(|| get_poetry_version(&pyproject_toml)) + .and_then(|raw_version| format_version(raw_version, config.version_format)) } fn get_setup_cfg_version(context: &Context, config: &PackageConfig) -> Option { @@ -252,7 +261,7 @@ fn get_version(context: &Context, config: &PackageConfig) -> Option { get_cargo_version, get_nimble_version, get_node_package_version, - get_poetry_version, + get_pyproject_version, get_setup_cfg_version, get_composer_version, get_gradle_version, @@ -632,6 +641,69 @@ license = "MIT" project_dir.close() } + #[test] + fn test_extract_pep621_version() -> io::Result<()> { + let config_name = "pyproject.toml"; + let config_content = toml::toml! { + [project] + name = "starship" + version = "0.1.0" + } + .to_string(); + + let project_dir = create_project_dir()?; + fill_config(&project_dir, config_name, Some(&config_content))?; + expect_output(&project_dir, Some("v0.1.0"), None); + project_dir.close() + } + + #[test] + fn test_extract_pep621_version_without_version() -> io::Result<()> { + let config_name = "pyproject.toml"; + let config_content = toml::toml! { + [project] + name = "starship" + } + .to_string(); + + let project_dir = create_project_dir()?; + fill_config(&project_dir, config_name, Some(&config_content))?; + expect_output(&project_dir, None, None); + project_dir.close() + } + + #[test] + fn test_extract_pep621_version_attr_directive() -> io::Result<()> { + let config_name = "pyproject.toml"; + let config_content = toml::toml! { + [project] + name = "starship" + version = {attr = "starship.__version__"} + } + .to_string(); + + let project_dir = create_project_dir()?; + fill_config(&project_dir, config_name, Some(&config_content))?; + expect_output(&project_dir, None, None); + project_dir.close() + } + + #[test] + fn test_extract_pep621_version_file_directive() -> io::Result<()> { + let config_name = "pyproject.toml"; + let config_content = toml::toml! { + [project] + name = "starship" + version = {file = "VERSION.txt"} + } + .to_string(); + + let project_dir = create_project_dir()?; + fill_config(&project_dir, config_name, Some(&config_content))?; + expect_output(&project_dir, None, None); + project_dir.close() + } + #[test] fn test_extract_setup_cfg_version() -> io::Result<()> { let config_name = "setup.cfg";