diff --git a/Cargo.toml b/Cargo.toml index 4394506..a058a0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ passthrough = [ "PYAPP_PIP_EXTRA_ARGS", "PYAPP_PIP_VERSION", "PYAPP_PROJECT_DEPENDENCY_FILE", + "PYAPP_PROJECT_FEATURES", "PYAPP_PROJECT_NAME", "PYAPP_PROJECT_PATH", "PYAPP_PROJECT_VERSION", diff --git a/build.rs b/build.rs index fa84c61..eab88b0 100644 --- a/build.rs +++ b/build.rs @@ -819,6 +819,11 @@ fn set_pip_version() { set_runtime_variable(variable, env::var(variable).unwrap_or("latest".to_string())); } +fn set_pip_project_features() { + let variable = "PYAPP_PROJECT_FEATURES"; + set_runtime_variable(variable, env::var(variable).unwrap_or_default()); +} + fn set_pip_extra_args() { let variable = "PYAPP_PIP_EXTRA_ARGS"; set_runtime_variable(variable, env::var(variable).unwrap_or_default()); @@ -919,6 +924,7 @@ fn main() { set_upgrade_virtualenv(); set_pip_external(); set_pip_version(); + set_pip_project_features(); set_pip_extra_args(); set_pip_allow_config(); set_skip_install(); diff --git a/docs/config.md b/docs/config.md index 8fa2b77..0244d61 100644 --- a/docs/config.md +++ b/docs/config.md @@ -31,6 +31,12 @@ You may embed the project with the `PYAPP_PROJECT_PATH` option which should be a !!! note The project name and version is automatically derived from the metadata files inside. +## Features (extras) ## {: #project-features } + +You may set the `PYAPP_PROJECT_FEATURES` option to select [optional dependency groups](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#extras) that would usually be passed to installers within square brackets after the package name e.g. `pkg[foo,bar]`. In that example, you would set `PYAPP_PROJECT_FEATURES` to `foo,bar`. + +This also works when [embedding the project](#project-embedding). + ## Execution mode The following options are mutually exclusive: diff --git a/src/app.rs b/src/app.rs index 05aba57..0815ba4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -160,6 +160,10 @@ pub fn exec_notebook_path() -> PathBuf { .join(env!("PYAPP__EXEC_NOTEBOOK_NAME")) } +pub fn pip_project_features() -> String { + env!("PYAPP_PROJECT_FEATURES").into() +} + pub fn pip_extra_args() -> String { env!("PYAPP_PIP_EXTRA_ARGS").into() } diff --git a/src/distribution.rs b/src/distribution.rs index e45d134..f28b9f4 100644 --- a/src/distribution.rs +++ b/src/distribution.rs @@ -259,7 +259,9 @@ fn install_project() -> Result<()> { ) })?; - command.arg(temp_path.to_string_lossy().as_ref()); + command.arg(apply_project_features( + temp_path.to_string_lossy().as_ref().to_string(), + )); let wait_message = if binary_only && file_name.ends_with(".whl") { format!("Unpacking {}", install_target) @@ -276,7 +278,11 @@ fn install_project() -> Result<()> { let dependency_file = app::project_dependency_file(); if dependency_file.is_empty() { - command.arg(format!("{}=={}", app::project_name(), app::project_version()).as_str()); + command.arg(format!( + "{}=={}", + apply_project_features(app::project_name()), + app::project_version() + )); pip_install(command, wait_message) } else { pip_install_dependency_file(&dependency_file, command, wait_message) @@ -391,3 +397,11 @@ fn check_setup_status(status: ExitStatus, output: String) -> Result<()> { Ok(()) } + +fn apply_project_features(install_target: String) -> String { + if app::pip_project_features().is_empty() { + install_target + } else { + format!("{install_target}[{}]", app::pip_project_features()) + } +}