mirror of https://github.com/astral-sh/uv
Reject non-PEP 751 TOML files in install commands (#13120)
If you pass a TOML file to `uv pip install` that isn't recognized, we should just reject it instead of assuming `requirements.txt`. I just don't see a real case where it's better to let the command proceed.
This commit is contained in:
parent
3ace372158
commit
11d00d21f7
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
@ -5,7 +6,6 @@ use console::Term;
|
||||||
|
|
||||||
use uv_fs::{Simplified, CWD};
|
use uv_fs::{Simplified, CWD};
|
||||||
use uv_requirements_txt::RequirementsTxtRequirement;
|
use uv_requirements_txt::RequirementsTxtRequirement;
|
||||||
use uv_warnings::warn_user;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum RequirementsSource {
|
pub enum RequirementsSource {
|
||||||
|
|
@ -32,89 +32,127 @@ pub enum RequirementsSource {
|
||||||
impl RequirementsSource {
|
impl RequirementsSource {
|
||||||
/// Parse a [`RequirementsSource`] from a [`PathBuf`]. The file type is determined by the file
|
/// Parse a [`RequirementsSource`] from a [`PathBuf`]. The file type is determined by the file
|
||||||
/// extension.
|
/// extension.
|
||||||
pub fn from_requirements_file(path: PathBuf) -> Self {
|
pub fn from_requirements_file(path: PathBuf) -> Result<Self> {
|
||||||
if path.ends_with("pyproject.toml") {
|
if path.ends_with("pyproject.toml") {
|
||||||
Self::PyprojectToml(path)
|
Ok(Self::PyprojectToml(path))
|
||||||
} else if path.ends_with("setup.py") {
|
} else if path.ends_with("setup.py") {
|
||||||
Self::SetupPy(path)
|
Ok(Self::SetupPy(path))
|
||||||
} else if path.ends_with("setup.cfg") {
|
} else if path.ends_with("setup.cfg") {
|
||||||
Self::SetupCfg(path)
|
Ok(Self::SetupCfg(path))
|
||||||
} else if path.ends_with("environment.yml") {
|
} else if path.ends_with("environment.yml") {
|
||||||
Self::EnvironmentYml(path)
|
Ok(Self::EnvironmentYml(path))
|
||||||
} else if path
|
} else if path
|
||||||
.file_name()
|
.file_name()
|
||||||
.is_some_and(|file_name| file_name.to_str().is_some_and(is_pylock_toml))
|
.is_some_and(|file_name| file_name.to_str().is_some_and(is_pylock_toml))
|
||||||
{
|
{
|
||||||
Self::PylockToml(path)
|
Ok(Self::PylockToml(path))
|
||||||
|
} else if path
|
||||||
|
.extension()
|
||||||
|
.is_some_and(|ext| ext.eq_ignore_ascii_case("toml"))
|
||||||
|
{
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"`{}` is not a valid PEP 751 filename: expected TOML file to start with `pylock.` and end with `.toml` (e.g., `pylock.toml`, `pylock.dev.toml`)",
|
||||||
|
path.user_display(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Self::RequirementsTxt(path)
|
Ok(Self::RequirementsTxt(path))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a [`RequirementsSource`] from a `requirements.txt` file.
|
/// Parse a [`RequirementsSource`] from a `requirements.txt` file.
|
||||||
pub fn from_requirements_txt(path: PathBuf) -> Self {
|
pub fn from_requirements_txt(path: PathBuf) -> Result<Self> {
|
||||||
for file_name in ["pyproject.toml", "setup.py", "setup.cfg"] {
|
for file_name in ["pyproject.toml", "setup.py", "setup.cfg"] {
|
||||||
if path.ends_with(file_name) {
|
if path.ends_with(file_name) {
|
||||||
warn_user!(
|
return Err(anyhow::anyhow!(
|
||||||
"The file `{}` appears to be a `{}` file, but requirements must be specified in `requirements.txt` format.",
|
"The file `{}` appears to be a `{}` file, but requirements must be specified in `requirements.txt` format",
|
||||||
path.user_display(),
|
path.user_display(),
|
||||||
file_name
|
file_name
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(file_name) = path.file_name() {
|
if path
|
||||||
if file_name.to_str().is_some_and(is_pylock_toml) {
|
.file_name()
|
||||||
warn_user!(
|
.and_then(OsStr::to_str)
|
||||||
"The file `{}` appears to be a `pylock.toml` file, but requirements must be specified in `requirements.txt` format.",
|
.is_some_and(is_pylock_toml)
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"The file `{}` appears to be a `pylock.toml` file, but requirements must be specified in `requirements.txt` format",
|
||||||
path.user_display(),
|
path.user_display(),
|
||||||
);
|
));
|
||||||
|
} else if path
|
||||||
|
.extension()
|
||||||
|
.is_some_and(|ext| ext.eq_ignore_ascii_case("toml"))
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"The file `{}` appears to be a TOML file, but requirements must be specified in `requirements.txt` format",
|
||||||
|
path.user_display(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
Ok(Self::RequirementsTxt(path))
|
||||||
Self::RequirementsTxt(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a [`RequirementsSource`] from a `constraints.txt` file.
|
/// Parse a [`RequirementsSource`] from a `constraints.txt` file.
|
||||||
pub fn from_constraints_txt(path: PathBuf) -> Self {
|
pub fn from_constraints_txt(path: PathBuf) -> Result<Self> {
|
||||||
for file_name in ["pyproject.toml", "setup.py", "setup.cfg"] {
|
for file_name in ["pyproject.toml", "setup.py", "setup.cfg"] {
|
||||||
if path.ends_with(file_name) {
|
if path.ends_with(file_name) {
|
||||||
warn_user!(
|
return Err(anyhow::anyhow!(
|
||||||
"The file `{}` appears to be a `{}` file, but constraints must be specified in `requirements.txt` format.",
|
"The file `{}` appears to be a `{}` file, but constraints must be specified in `requirements.txt` format",
|
||||||
path.user_display(),
|
path.user_display(),
|
||||||
file_name
|
file_name
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(file_name) = path.file_name() {
|
if path
|
||||||
if file_name.to_str().is_some_and(is_pylock_toml) {
|
.file_name()
|
||||||
warn_user!(
|
.and_then(OsStr::to_str)
|
||||||
"The file `{}` appears to be a `pylock.toml` file, but constraints must be specified in `requirements.txt` format.",
|
.is_some_and(is_pylock_toml)
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"The file `{}` appears to be a `pylock.toml` file, but constraints must be specified in `requirements.txt` format",
|
||||||
path.user_display(),
|
path.user_display(),
|
||||||
);
|
));
|
||||||
|
} else if path
|
||||||
|
.extension()
|
||||||
|
.is_some_and(|ext| ext.eq_ignore_ascii_case("toml"))
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"The file `{}` appears to be a TOML file, but constraints must be specified in `requirements.txt` format",
|
||||||
|
path.user_display(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
Ok(Self::RequirementsTxt(path))
|
||||||
Self::RequirementsTxt(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a [`RequirementsSource`] from an `overrides.txt` file.
|
/// Parse a [`RequirementsSource`] from an `overrides.txt` file.
|
||||||
pub fn from_overrides_txt(path: PathBuf) -> Self {
|
pub fn from_overrides_txt(path: PathBuf) -> Result<Self> {
|
||||||
for file_name in ["pyproject.toml", "setup.py", "setup.cfg"] {
|
for file_name in ["pyproject.toml", "setup.py", "setup.cfg"] {
|
||||||
if path.ends_with(file_name) {
|
if path.ends_with(file_name) {
|
||||||
warn_user!(
|
return Err(anyhow::anyhow!(
|
||||||
"The file `{}` appears to be a `{}` file, but overrides must be specified in `requirements.txt` format.",
|
"The file `{}` appears to be a `{}` file, but overrides must be specified in `requirements.txt` format",
|
||||||
path.user_display(),
|
path.user_display(),
|
||||||
file_name
|
file_name
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(file_name) = path.file_name() {
|
if path
|
||||||
if file_name.to_str().is_some_and(is_pylock_toml) {
|
.file_name()
|
||||||
warn_user!(
|
.and_then(OsStr::to_str)
|
||||||
"The file `{}` appears to be a `pylock.toml` file, but overrides must be specified in `requirements.txt` format.",
|
.is_some_and(is_pylock_toml)
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"The file `{}` appears to be a `pylock.toml` file, but overrides must be specified in `requirements.txt` format",
|
||||||
path.user_display(),
|
path.user_display(),
|
||||||
);
|
));
|
||||||
|
} else if path
|
||||||
|
.extension()
|
||||||
|
.is_some_and(|ext| ext.eq_ignore_ascii_case("toml"))
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"The file `{}` appears to be a TOML file, but overrides must be specified in `requirements.txt` format",
|
||||||
|
path.user_display(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
Ok(Self::RequirementsTxt(path))
|
||||||
Self::RequirementsTxt(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a [`RequirementsSource`] from a user-provided string, assumed to be a positional
|
/// Parse a [`RequirementsSource`] from a user-provided string, assumed to be a positional
|
||||||
|
|
@ -134,7 +172,7 @@ impl RequirementsSource {
|
||||||
);
|
);
|
||||||
let confirmation = uv_console::confirm(&prompt, &term, true)?;
|
let confirmation = uv_console::confirm(&prompt, &term, true)?;
|
||||||
if confirmation {
|
if confirmation {
|
||||||
return Ok(Self::from_requirements_file(name.into()));
|
return Self::from_requirements_file(name.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +192,7 @@ impl RequirementsSource {
|
||||||
);
|
);
|
||||||
let confirmation = uv_console::confirm(&prompt, &term, true)?;
|
let confirmation = uv_console::confirm(&prompt, &term, true)?;
|
||||||
if confirmation {
|
if confirmation {
|
||||||
return Ok(Self::from_requirements_file(name.into()));
|
return Self::from_requirements_file(name.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -182,7 +220,7 @@ impl RequirementsSource {
|
||||||
);
|
);
|
||||||
let confirmation = uv_console::confirm(&prompt, &term, true)?;
|
let confirmation = uv_console::confirm(&prompt, &term, true)?;
|
||||||
if confirmation {
|
if confirmation {
|
||||||
return Ok(Self::from_requirements_file(name.into()));
|
return Self::from_requirements_file(name.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +240,7 @@ impl RequirementsSource {
|
||||||
);
|
);
|
||||||
let confirmation = uv_console::confirm(&prompt, &term, true)?;
|
let confirmation = uv_console::confirm(&prompt, &term, true)?;
|
||||||
if confirmation {
|
if confirmation {
|
||||||
return Ok(Self::from_requirements_file(name.into()));
|
return Self::from_requirements_file(name.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -407,22 +407,22 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
.src_file
|
.src_file
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_requirements_file)
|
.map(RequirementsSource::from_requirements_file)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let constraints = args
|
let constraints = args
|
||||||
.constraints
|
.constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let overrides = args
|
let overrides = args
|
||||||
.overrides
|
.overrides
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_overrides_txt)
|
.map(RequirementsSource::from_overrides_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let build_constraints = args
|
let build_constraints = args
|
||||||
.build_constraints
|
.build_constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let mut groups = BTreeMap::new();
|
let mut groups = BTreeMap::new();
|
||||||
for group in args.settings.groups {
|
for group in args.settings.groups {
|
||||||
|
|
@ -516,17 +516,17 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
.src_file
|
.src_file
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_requirements_file)
|
.map(RequirementsSource::from_requirements_file)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let constraints = args
|
let constraints = args
|
||||||
.constraints
|
.constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let build_constraints = args
|
let build_constraints = args
|
||||||
.build_constraints
|
.build_constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
commands::pip_sync(
|
commands::pip_sync(
|
||||||
&requirements,
|
&requirements,
|
||||||
|
|
@ -588,23 +588,24 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
requirements.extend(
|
requirements.extend(
|
||||||
args.requirements
|
args.requirements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_requirements_file),
|
.map(RequirementsSource::from_requirements_file)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
);
|
);
|
||||||
let constraints = args
|
let constraints = args
|
||||||
.constraints
|
.constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let overrides = args
|
let overrides = args
|
||||||
.overrides
|
.overrides
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_overrides_txt)
|
.map(RequirementsSource::from_overrides_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let build_constraints = args
|
let build_constraints = args
|
||||||
.build_constraints
|
.build_constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_overrides_txt)
|
.map(RequirementsSource::from_overrides_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let mut groups = BTreeMap::new();
|
let mut groups = BTreeMap::new();
|
||||||
for group in args.settings.groups {
|
for group in args.settings.groups {
|
||||||
|
|
@ -735,7 +736,8 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
sources.extend(
|
sources.extend(
|
||||||
args.requirements
|
args.requirements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_requirements_file),
|
.map(RequirementsSource::from_requirements_file)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
);
|
);
|
||||||
commands::pip_uninstall(
|
commands::pip_uninstall(
|
||||||
&sources,
|
&sources,
|
||||||
|
|
@ -908,7 +910,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
.build_constraints
|
.build_constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
commands::build_frontend(
|
commands::build_frontend(
|
||||||
&project_dir,
|
&project_dir,
|
||||||
|
|
@ -1121,7 +1123,8 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
requirements.extend(
|
requirements.extend(
|
||||||
args.with_requirements
|
args.with_requirements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_requirements_file),
|
.map(RequirementsSource::from_requirements_file)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
);
|
);
|
||||||
requirements
|
requirements
|
||||||
};
|
};
|
||||||
|
|
@ -1129,18 +1132,18 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
.constraints
|
.constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let overrides = args
|
let overrides = args
|
||||||
.overrides
|
.overrides
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_overrides_txt)
|
.map(RequirementsSource::from_overrides_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let build_constraints = args
|
let build_constraints = args
|
||||||
.build_constraints
|
.build_constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
Box::pin(commands::tool_run(
|
Box::pin(commands::tool_run(
|
||||||
args.command,
|
args.command,
|
||||||
|
|
@ -1195,24 +1198,25 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
requirements.extend(
|
requirements.extend(
|
||||||
args.with_requirements
|
args.with_requirements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_requirements_file),
|
.map(RequirementsSource::from_requirements_file)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
);
|
);
|
||||||
|
|
||||||
let constraints = args
|
let constraints = args
|
||||||
.constraints
|
.constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let overrides = args
|
let overrides = args
|
||||||
.overrides
|
.overrides
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_overrides_txt)
|
.map(RequirementsSource::from_overrides_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let build_constraints = args
|
let build_constraints = args
|
||||||
.build_constraints
|
.build_constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
Box::pin(commands::tool_install(
|
Box::pin(commands::tool_install(
|
||||||
args.package,
|
args.package,
|
||||||
|
|
@ -1639,7 +1643,8 @@ async fn run_project(
|
||||||
requirements.extend(
|
requirements.extend(
|
||||||
args.with_requirements
|
args.with_requirements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_requirements_file),
|
.map(RequirementsSource::from_requirements_file)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Box::pin(commands::run(
|
Box::pin(commands::run(
|
||||||
|
|
@ -1803,15 +1808,14 @@ async fn run_project(
|
||||||
.chain(
|
.chain(
|
||||||
args.requirements
|
args.requirements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_requirements_file)
|
.map(RequirementsSource::from_requirements_file),
|
||||||
.map(Ok),
|
|
||||||
)
|
)
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
let constraints = args
|
let constraints = args
|
||||||
.constraints
|
.constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(RequirementsSource::from_constraints_txt)
|
.map(RequirementsSource::from_constraints_txt)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
Box::pin(commands::add(
|
Box::pin(commands::add(
|
||||||
project_dir,
|
project_dir,
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,27 @@ fn invalid_pyproject_toml_option_unknown_field() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_toml_filename() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
let test_toml = context.temp_dir.child("test.toml");
|
||||||
|
test_toml.touch()?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.pip_install()
|
||||||
|
.arg("-r")
|
||||||
|
.arg("test.toml"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: `test.toml` is not a valid PEP 751 filename: expected TOML file to start with `pylock.` and end with `.toml` (e.g., `pylock.toml`, `pylock.dev.toml`)
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_uv_toml_option_disallowed() -> Result<()> {
|
fn invalid_uv_toml_option_disallowed() -> Result<()> {
|
||||||
let context = TestContext::new("3.12");
|
let context = TestContext::new("3.12");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue