mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-17 13:58:29 +00:00
Add support for uv run --all-packages
(#8741)
## Summary Closes https://github.com/astral-sh/uv/issues/8724.
This commit is contained in:
parent
3c9dd97fe9
commit
3808b61fc1
6 changed files with 198 additions and 3 deletions
|
@ -2740,10 +2740,20 @@ pub struct RunArgs {
|
|||
#[command(flatten)]
|
||||
pub refresh: RefreshArgs,
|
||||
|
||||
/// Run the command with all workspace members installed.
|
||||
///
|
||||
/// The workspace's environment (`.venv`) is updated to include all workspace
|
||||
/// members.
|
||||
///
|
||||
/// Any extras or groups specified via `--extra`, `--group`, or related options
|
||||
/// will be applied to all workspace members.
|
||||
#[arg(long, conflicts_with = "package")]
|
||||
pub all_packages: bool,
|
||||
|
||||
/// Run the command in a specific package in the workspace.
|
||||
///
|
||||
/// If the workspace member does not exist, uv will exit with an error.
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "all_packages")]
|
||||
pub package: Option<PackageName>,
|
||||
|
||||
/// Avoid discovering the project or workspace.
|
||||
|
|
|
@ -65,6 +65,7 @@ pub(crate) async fn run(
|
|||
frozen: bool,
|
||||
no_sync: bool,
|
||||
isolated: bool,
|
||||
all_packages: bool,
|
||||
package: Option<PackageName>,
|
||||
no_project: bool,
|
||||
no_config: bool,
|
||||
|
@ -346,6 +347,11 @@ pub(crate) async fn run(
|
|||
if let Some(flag) = dev.groups().and_then(GroupsSpecification::as_flag) {
|
||||
warn_user!("`{flag}` is not supported for Python scripts with inline metadata");
|
||||
}
|
||||
if all_packages {
|
||||
warn_user!(
|
||||
"`--all-packages` is a no-op for Python scripts with inline metadata, which always run in isolation"
|
||||
);
|
||||
}
|
||||
if package.is_some() {
|
||||
warn_user!(
|
||||
"`--package` is a no-op for Python scripts with inline metadata, which always run in isolation"
|
||||
|
@ -550,8 +556,14 @@ pub(crate) async fn run(
|
|||
.flatten();
|
||||
}
|
||||
} else {
|
||||
let target = if all_packages {
|
||||
InstallTarget::from_workspace(&project)
|
||||
} else {
|
||||
InstallTarget::from_project(&project)
|
||||
};
|
||||
|
||||
// Determine the default groups to include.
|
||||
validate_dependency_groups(InstallTarget::from_project(&project), &dev)?;
|
||||
validate_dependency_groups(target, &dev)?;
|
||||
let defaults = default_dependency_groups(project.pyproject_toml())?;
|
||||
|
||||
// Determine the lock mode.
|
||||
|
@ -607,7 +619,7 @@ pub(crate) async fn run(
|
|||
let install_options = InstallOptions::default();
|
||||
|
||||
project::sync::do_sync(
|
||||
InstallTarget::from_project(&project),
|
||||
target,
|
||||
&venv,
|
||||
result.lock(),
|
||||
&extras,
|
||||
|
|
|
@ -1293,6 +1293,7 @@ async fn run_project(
|
|||
args.frozen,
|
||||
args.no_sync,
|
||||
args.isolated,
|
||||
args.all_packages,
|
||||
args.package,
|
||||
args.no_project,
|
||||
no_config,
|
||||
|
|
|
@ -235,6 +235,7 @@ pub(crate) struct RunSettings {
|
|||
pub(crate) with_requirements: Vec<PathBuf>,
|
||||
pub(crate) isolated: bool,
|
||||
pub(crate) show_resolution: bool,
|
||||
pub(crate) all_packages: bool,
|
||||
pub(crate) package: Option<PackageName>,
|
||||
pub(crate) no_project: bool,
|
||||
pub(crate) no_sync: bool,
|
||||
|
@ -271,6 +272,7 @@ impl RunSettings {
|
|||
installer,
|
||||
build,
|
||||
refresh,
|
||||
all_packages,
|
||||
package,
|
||||
no_project,
|
||||
python,
|
||||
|
@ -296,6 +298,7 @@ impl RunSettings {
|
|||
.collect(),
|
||||
isolated,
|
||||
show_resolution,
|
||||
all_packages,
|
||||
package,
|
||||
no_project,
|
||||
no_sync,
|
||||
|
|
|
@ -806,6 +806,169 @@ fn run_with() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Sync all members in a workspace.
|
||||
#[test]
|
||||
fn run_in_workspace() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["anyio>3"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.uv.workspace]
|
||||
members = ["child1", "child2"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child1 = { workspace = true }
|
||||
child2 = { workspace = true }
|
||||
"#,
|
||||
)?;
|
||||
context
|
||||
.temp_dir
|
||||
.child("src")
|
||||
.child("project")
|
||||
.child("__init__.py")
|
||||
.touch()?;
|
||||
|
||||
let child1 = context.temp_dir.child("child1");
|
||||
child1.child("pyproject.toml").write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "child1"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig>1"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
"#,
|
||||
)?;
|
||||
child1
|
||||
.child("src")
|
||||
.child("child1")
|
||||
.child("__init__.py")
|
||||
.touch()?;
|
||||
|
||||
let child2 = context.temp_dir.child("child2");
|
||||
child2.child("pyproject.toml").write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "child2"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["typing-extensions>4"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
"#,
|
||||
)?;
|
||||
child2
|
||||
.child("src")
|
||||
.child("child2")
|
||||
.child("__init__.py")
|
||||
.touch()?;
|
||||
|
||||
let test_script = context.temp_dir.child("main.py");
|
||||
test_script.write_str(indoc! { r"
|
||||
import anyio
|
||||
"
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.run().arg("main.py"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Prepared 4 packages in [TIME]
|
||||
Installed 4 packages in [TIME]
|
||||
+ anyio==4.3.0
|
||||
+ idna==3.6
|
||||
+ project==0.1.0 (from file://[TEMP_DIR]/)
|
||||
+ sniffio==1.3.1
|
||||
"###);
|
||||
|
||||
let test_script = context.temp_dir.child("main.py");
|
||||
test_script.write_str(indoc! { r"
|
||||
import iniconfig
|
||||
"
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.run().arg("main.py"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Audited 4 packages in [TIME]
|
||||
Traceback (most recent call last):
|
||||
File "[TEMP_DIR]/main.py", line 1, in <module>
|
||||
import iniconfig
|
||||
ModuleNotFoundError: No module named 'iniconfig'
|
||||
"###);
|
||||
|
||||
uv_snapshot!(context.filters(), context.run().arg("--package").arg("child1").arg("main.py"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Prepared 2 packages in [TIME]
|
||||
Installed 2 packages in [TIME]
|
||||
+ child1==0.1.0 (from file://[TEMP_DIR]/child1)
|
||||
+ iniconfig==2.0.0
|
||||
"###);
|
||||
|
||||
let test_script = context.temp_dir.child("main.py");
|
||||
test_script.write_str(indoc! { r"
|
||||
import typing_extensions
|
||||
"
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.run().arg("main.py"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Audited 4 packages in [TIME]
|
||||
Traceback (most recent call last):
|
||||
File "[TEMP_DIR]/main.py", line 1, in <module>
|
||||
import typing_extensions
|
||||
ModuleNotFoundError: No module named 'typing_extensions'
|
||||
"###);
|
||||
|
||||
uv_snapshot!(context.filters(), context.run().arg("--all-packages").arg("main.py"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Prepared 2 packages in [TIME]
|
||||
Installed 2 packages in [TIME]
|
||||
+ child2==0.1.0 (from file://[TEMP_DIR]/child2)
|
||||
+ typing-extensions==4.10.0
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_with_editable() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
|
|
@ -78,6 +78,12 @@ uv run [OPTIONS] [COMMAND]
|
|||
|
||||
<p>This option is only available when running in a project.</p>
|
||||
|
||||
</dd><dt><code>--all-packages</code></dt><dd><p>Run the command with all workspace members installed.</p>
|
||||
|
||||
<p>The workspace’s environment (<code>.venv</code>) is updated to include all workspace members.</p>
|
||||
|
||||
<p>Any extras or groups specified via <code>--extra</code>, <code>--group</code>, or related options will be applied to all workspace members.</p>
|
||||
|
||||
</dd><dt><code>--allow-insecure-host</code> <i>allow-insecure-host</i></dt><dd><p>Allow insecure connections to a host.</p>
|
||||
|
||||
<p>Can be provided multiple times.</p>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue