Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/uv-preview/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ bitflags::bitflags! {
const NATIVE_AUTH = 1 << 9;
const S3_ENDPOINT = 1 << 10;
const CACHE_SIZE = 1 << 11;
const INIT_PROJECT_FLAG = 1 << 12;
}
}

Expand All @@ -42,6 +43,7 @@ impl PreviewFeatures {
Self::NATIVE_AUTH => "native-auth",
Self::S3_ENDPOINT => "s3-endpoint",
Self::CACHE_SIZE => "cache-size",
Self::INIT_PROJECT_FLAG => "init-project-flag",
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
}
}
Expand Down Expand Up @@ -91,6 +93,7 @@ impl FromStr for PreviewFeatures {
"native-auth" => Self::NATIVE_AUTH,
"s3-endpoint" => Self::S3_ENDPOINT,
"cache-size" => Self::CACHE_SIZE,
"init-project-flag" => Self::INIT_PROJECT_FLAG,
_ => {
warn_user_once!("Unknown preview feature: `{part}`");
continue;
Expand Down
25 changes: 25 additions & 0 deletions crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use uv_fs::{CWD, Simplified};
#[cfg(feature = "self-update")]
use uv_pep440::release_specifiers_to_ranges;
use uv_pep508::VersionOrUrl;
use uv_preview::PreviewFeatures;
use uv_pypi_types::{ParsedDirectoryUrl, ParsedUrl};
use uv_python::PythonRequest;
use uv_requirements::{GroupsSpecification, RequirementsSource};
Expand Down Expand Up @@ -1805,6 +1806,30 @@ async fn run_project(
let args = settings::InitSettings::resolve(args, filesystem, environment);
show_settings!(args);

// The `--project` arg is being deprecated for `init` with a warning now and an error in preview.
if explicit_project {
if globals
.preview
.is_enabled(PreviewFeatures::INIT_PROJECT_FLAG)
{
bail!(
"The `--project` option cannot be used in `uv init`. Use `--directory` or `PATH` instead."
)
}
let message = {
match args.path {
Some(_) => {
" Since a positional path was provided, the `--project` option has no effect.\nConsider using `--directory` instead."
}
None => "\nConsider using `uv init <PATH>` instead.",
}
};
warn_user!(
"Use of the `--project` option in `uv init` is deprecated and will be removed in a future release.{}",
message
);
}

// Initialize the cache.
let cache = cache.init()?;

Expand Down
116 changes: 116 additions & 0 deletions crates/uv/tests/it/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4043,3 +4043,119 @@ fn git_states() {
");
assert!(!context.temp_dir.child("broken-git/.git").is_dir());
}

/// Using `uv init` with `--project` isn't allowed
#[test]
fn init_project_flag_is_not_allowed_under_preview() -> Result<()> {
let context = TestContext::new("3.12");

let child = context.temp_dir.child("foo");
child.create_dir_all()?;

// general `--preview` flag
uv_snapshot!(context.filters(), context.init().arg("--preview").arg("--project").arg("foo").arg("bar"), @r###"
success: false
exit_code: 2
----- stdout -----

----- stderr -----
error: The `--project` option cannot be used in `uv init`. Use `--directory` or `PATH` instead.
"###);

// feature-specific preview
uv_snapshot!(context.filters(), context.init().arg("--preview-features").arg("init-project-flag").arg("--project").arg("foo").arg("bar"), @r###"
success: false
exit_code: 2
----- stdout -----

----- stderr -----
error: The `--project` option cannot be used in `uv init`. Use `--directory` or `PATH` instead.
"###);

Ok(())
}

#[test]
fn init_project_flag_is_ignored_with_explicit_path() -> Result<()> {
let context = TestContext::new("3.12");

// with explicit path
uv_snapshot!(context.filters(), context.init().arg("--project").arg("bar").arg("foo"), @r###"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
warning: Use of the `--project` option in `uv init` is deprecated and will be removed in a future release. Since a positional path was provided, the `--project` option has no effect.
Consider using `--directory` instead.
Initialized project `foo` at `[TEMP_DIR]/foo`
"###);

let pyproject = context.read("foo/pyproject.toml");
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
pyproject, @r###"
[project]
name = "foo"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
"###
);
});

Ok(())
}

#[test]
fn init_project_flag_is_warned_without_path() -> Result<()> {
let context = TestContext::new("3.12");

// with explicit path
uv_snapshot!(context.filters(), context.init().arg("--project").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
warning: Use of the `--project` option in `uv init` is deprecated and will be removed in a future release.
Consider using `uv init <PATH>` instead.
Initialized project `bar`
"###);

context
.temp_dir
.child("bar/pyproject.toml")
.assert(predicate::path::is_file());

Ok(())
}

/// The `--directory` flag is used as the base for path
#[test]
fn init_working_directory_change() -> Result<()> {
let context = TestContext::new("3.12");

let child = context.temp_dir.child("bar");
child.create_dir_all()?;

uv_snapshot!(context.filters(), context.init().arg("--directory").arg("bar").arg("foo"), @r###"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Initialized project `foo` at `[TEMP_DIR]/bar/foo`
"###);

context
.temp_dir
.child("bar/foo/pyproject.toml")
.assert(predicate::path::is_file());

Ok(())
}
4 changes: 2 additions & 2 deletions crates/uv/tests/it/show_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7831,7 +7831,7 @@ fn preview_features() {
show_settings: true,
preview: Preview {
flags: PreviewFeatures(
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE,
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE | INIT_PROJECT_FLAG,
),
},
python_preference: Managed,
Expand Down Expand Up @@ -8059,7 +8059,7 @@ fn preview_features() {
show_settings: true,
preview: Preview {
flags: PreviewFeatures(
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE,
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE | INIT_PROJECT_FLAG,
),
},
python_preference: Managed,
Expand Down
6 changes: 4 additions & 2 deletions docs/concepts/projects/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ flag can be used to create a project for a library instead.
## Target directory

uv will create a project in the working directory, or, in a target directory by providing a name,
e.g., `uv init foo`. If there's already a project in the target directory, i.e., if there's a
`pyproject.toml`, uv will exit with an error.
e.g., `uv init foo`. The working directory can be modified with the `--directory` option, which will
cause the target directory path will be interpreted relative to the specified working directory. If
there's already a project in the target directory, i.e., if there's a `pyproject.toml`, uv will exit
with an error.

## Applications

Expand Down
Loading