Use locked ty versions in uv check

This commit is contained in:
Zsolt Dollenstein
2026-06-16 17:14:38 +01:00
parent a032056d2d
commit 24d6472e66
5 changed files with 769 additions and 5 deletions
+3 -1
View File
@@ -5384,7 +5384,9 @@ pub struct CheckArgs {
/// Accepts either a version (e.g., `0.0.1`) which will be treated as an exact pin,
/// a version specifier (e.g., `>=0.0.1`), or `latest` to use the latest available version.
///
/// By default, a constrained version range of ty will be used (e.g., `>=0.0,<0.1`).
/// By default, the exact version resolved in `uv.lock` will be used when the project has an
/// active `ty` development dependency. Otherwise, a constrained version range of ty will be
/// used (e.g., `>=0.0,<0.1`).
#[arg(long, value_hint = ValueHint::Other)]
pub ty_version: Option<String>,
+58
View File
@@ -775,6 +775,64 @@ impl Lock {
&self.manifest.dependency_groups
}
/// Returns the package selected by a direct dependency in a dependency group.
///
/// If `project_name` is provided, the dependency group attached to that package is used.
/// Otherwise, the dependency group attached directly to the lock manifest is used.
pub fn find_dependency_group_package(
&self,
project_name: Option<&PackageName>,
group: &GroupName,
dependency_name: &PackageName,
marker_environment: &MarkerEnvironment,
) -> Result<Option<&Package>, String> {
let Some(project_name) = project_name else {
let Some(requirements) = self.manifest.dependency_groups.get(group) else {
return Ok(None);
};
if !requirements.iter().any(|requirement| {
&requirement.name == dependency_name
&& requirement.marker.evaluate(marker_environment, &[])
}) {
return Ok(None);
}
return self.find_by_markers(dependency_name, marker_environment);
};
let Some(project) = self.find_by_name(project_name)? else {
return Ok(None);
};
let Some(dependencies) = project.resolved_dependency_groups().get(group) else {
return Ok(None);
};
let mut selected = None;
for dependency in dependencies {
if &dependency.package_id.name != dependency_name
|| !dependency.complexified_marker.evaluate(
marker_environment,
std::iter::empty::<&PackageName>(),
dependency
.extra
.iter()
.map(|extra| (&dependency.package_id.name, extra)),
std::iter::once((project_name, group)),
)
{
continue;
}
let package = self.find_by_id(&dependency.package_id);
if selected.is_some_and(|selected: &Package| selected.id != package.id) {
return Err(format!(
"found multiple packages matching `{dependency_name}` in dependency group `{group}` for `{project_name}`"
));
}
selected = Some(package);
}
Ok(selected)
}
/// Returns the build constraints that were used to generate this lock.
pub fn build_constraints(&self, root: &Path) -> Constraints {
Constraints::from_requirements(
+28 -2
View File
@@ -204,6 +204,7 @@ pub(crate) async fn check(
// Select an environment and, if we found a project, sync it before running checks.
let mut workspace_metadata = None;
let mut locked_ty_version = None;
let venv_path = if let Some(project) = &project {
let extras = extras.with_defaults(DefaultExtras::default());
@@ -229,18 +230,34 @@ pub(crate) async fn check(
.into_environment()?
};
let ty_declaration = if ty_path.is_none() && ty_version.is_none() {
ty::active_declaration(project, venv.interpreter(), &settings.resolver.sources)?
} else {
None
};
let state = UniversalState::default();
let _environment_lock;
let lock = if no_sync {
debug!("Skipping environment synchronization due to `--no-sync`");
match LockTarget::Workspace(project.workspace()).read().await {
let lock = match LockTarget::Workspace(project.workspace()).read().await {
Ok(lock) => lock,
Err(err) if ty_declaration.is_some() => return Err(err.into()),
Err(err) => {
debug!("Failed to read lockfile; skipping workspace metadata: {err}");
None
}
};
if let Some(declaration) = ty_declaration.as_ref() {
let Some(lock) = lock.as_ref() else {
anyhow::bail!(
"The active `ty` development dependency requires an existing lockfile when `--no-sync` is used; update `uv.lock`, remove `--no-sync`, or use `--ty-version` or the `TY` environment variable"
);
};
locked_ty_version = Some(ty::version_from_lock(declaration, project, lock, &venv)?);
}
lock
} else {
// Keep the environment locked through synchronization and metadata collection.
_environment_lock = venv
@@ -291,6 +308,15 @@ pub(crate) async fn check(
Err(err) => return Err(err.into()),
};
if let Some(declaration) = ty_declaration.as_ref() {
locked_ty_version = Some(ty::version_from_lock(
declaration,
project,
result.lock(),
&venv,
)?);
}
let target = match project {
VirtualProject::Project(project) => InstallTarget::Project {
workspace: project.workspace(),
@@ -381,7 +407,7 @@ pub(crate) async fn check(
.map(|value| value.timestamp());
ty::run(
ty_version,
ty_version.or(locked_ty_version),
ty_path,
&target_dir,
venv_path.as_deref(),
+131 -1
View File
@@ -3,7 +3,7 @@ use std::process::Stdio;
use std::str::FromStr;
use std::time::Duration;
use anyhow::{Context, Result};
use anyhow::{Context, Result, bail};
use tokio::io::AsyncWriteExt;
use tokio::process::{ChildStdin, Command};
use tracing::debug;
@@ -11,6 +11,13 @@ use tracing::debug;
use uv_bin_install::{BinVersion, Binary, ResolvedVersion, bin_install, find_matching_version};
use uv_cache::Cache;
use uv_client::BaseClientBuilder;
use uv_configuration::NoSources;
use uv_normalize::{DEV_DEPENDENCIES, PackageName};
use uv_python::{Interpreter, PythonEnvironment};
use uv_resolver::Lock;
use uv_workspace::VirtualProject;
use uv_workspace::dependency_groups::FlatDependencyGroups;
use uv_workspace::pyproject::{Source, ToolUvSources};
use crate::child::run_to_completion;
use crate::commands::ExitStatus;
@@ -20,6 +27,129 @@ use crate::printer::Printer;
/// Limit how long uv can block if a version of ty does not consume metadata from stdin.
const WORKSPACE_METADATA_WRITE_TIMEOUT: Duration = Duration::from_mins(1);
/// An active `ty` declaration in the current project's development dependencies.
pub(super) struct ActiveDeclaration {
package_name: PackageName,
}
/// Find and validate an active `ty` declaration for the selected interpreter.
pub(super) fn active_declaration(
project: &VirtualProject,
interpreter: &Interpreter,
no_sources: &NoSources,
) -> Result<Option<ActiveDeclaration>> {
let package_name = PackageName::from_str("ty")?;
let dependency_groups =
FlatDependencyGroups::from_pyproject_toml(project.root(), project.pyproject_toml())?;
let Some(dev_dependencies) = dependency_groups.get(&DEV_DEPENDENCIES) else {
return Ok(None);
};
let active_requirements = dev_dependencies
.requirements
.iter()
.filter(|requirement| {
requirement.name == package_name
&& requirement.evaluate_markers(interpreter.markers(), &[])
})
.collect::<Vec<_>>();
if active_requirements.is_empty() {
return Ok(None);
}
let source = if no_sources.for_package(&package_name) {
None
} else {
project
.pyproject_toml()
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.sources.as_ref())
.map(ToolUvSources::inner)
.and_then(|sources| sources.get(&package_name))
.or_else(|| project.workspace().sources().get(&package_name))
.and_then(|sources| {
sources.iter().find(|source| {
source.extra().is_none()
&& source
.group()
.is_none_or(|group| group == &*DEV_DEPENDENCIES)
&& source.marker().evaluate(interpreter.markers(), &[])
})
})
};
match source {
Some(Source::Registry { .. }) => {}
Some(source) => {
bail!(
"The active `ty` development dependency uses the non-registry source `{}`, but `uv check` can only install standalone `ty` releases by version; use a registry source, `--ty-version`, or the `TY` environment variable",
source_reference(source)
);
}
None if let Some(url) = active_requirements.iter().find_map(|requirement| {
let Some(uv_pep508::VersionOrUrl::Url(url)) = requirement.version_or_url.as_ref()
else {
return None;
};
Some(url)
}) =>
{
bail!(
"The active `ty` development dependency uses the direct URL `{url}`, but `uv check` can only install standalone `ty` releases by version; use a registry requirement, `--ty-version`, or the `TY` environment variable"
);
}
None => {}
}
Ok(Some(ActiveDeclaration { package_name }))
}
fn source_reference(source: &Source) -> String {
match source {
Source::Git { git, .. } => git.to_string(),
Source::Url { url, .. } => url.to_string(),
Source::Path { path, .. } => path.to_string(),
Source::Registry { index, .. } => index.to_string(),
Source::Workspace { workspace, .. } => format!("workspace = {workspace}"),
}
}
/// Select the exact registry version of `ty` reachable from the current project in the lockfile.
pub(super) fn version_from_lock(
declaration: &ActiveDeclaration,
project: &VirtualProject,
lock: &Lock,
environment: &PythonEnvironment,
) -> Result<String> {
let marker_environment = environment.interpreter().resolver_marker_environment();
let package = lock
.find_dependency_group_package(
project.project_name(),
&DEV_DEPENDENCIES,
&declaration.package_name,
marker_environment.markers(),
)
.map_err(anyhow::Error::msg)?;
let Some(package) = package else {
bail!(
"The active `ty` development dependency is not present in the lockfile for the selected Python environment; update `uv.lock`, or use `--ty-version` or the `TY` environment variable"
);
};
if package.index(project.workspace().install_path())?.is_none() {
bail!(
"The locked `ty` package uses a non-registry source, but `uv check` can only install standalone `ty` releases by version; use a registry source, `--ty-version`, or the `TY` environment variable"
);
}
let Some(version) = package.version() else {
bail!(
"The locked `ty` package has no version, but `uv check` can only install standalone `ty` releases by version; use a registry source, `--ty-version`, or the `TY` environment variable"
);
};
Ok(version.to_string())
}
async fn write_workspace_metadata(mut stdin: ChildStdin, workspace_metadata: String) -> Result<()> {
match tokio::time::timeout(
WORKSPACE_METADATA_WRITE_TIMEOUT,
+549 -1
View File
@@ -38,6 +38,536 @@ fn check_project() -> Result<()> {
Ok(())
}
#[test]
#[cfg(feature = "test-pypi")]
fn check_uses_exact_ty_version_from_lock() -> Result<()> {
let context = uv_test::test_context!("3.12");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
typing = ["ty>=0.0.1"]
dev = [{ include-group = "typing" }]
[tool.uv]
constraint-dependencies = ["ty==0.0.17"]
[tool.uv.sources]
ty = { path = "does-not-exist" }
"#})?;
context
.lock()
.arg("--no-sources")
.env(EnvVars::UV_EXCLUDE_NEWER, "2026-02-15T00:00:00Z")
.assert()
.success();
context.temp_dir.child("main.py").write_str("x = 1")?;
uv_snapshot!(
context.filters(),
context
.check()
.arg("--no-sources")
.arg("--no-sync")
.arg("--no-dev")
.arg("--no-build-package")
.arg("ty")
.arg("--no-binary-package")
.arg("ty")
.arg("--verbose")
.env(EnvVars::RUST_LOG, "uv::commands::project::check::ty=debug"),
@"
success: true
exit_code: 0
----- stdout -----
All checks passed!
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
DEBUG `--exclude-newer` is ignored for pinned version `0.0.17`
DEBUG Using `ty==0.0.17`
DEBUG Passing workspace metadata to `ty check` via stdin
"
);
Ok(())
}
#[test]
#[cfg(feature = "test-pypi")]
fn check_uses_exact_ty_version_from_legacy_dev_dependencies() -> Result<()> {
let context = uv_test::test_context!("3.12");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty<0.0.18"]
[tool.uv]
dev-dependencies = ["ty>=0.0.17"]
"#})?;
context.temp_dir.child("main.py").write_str("x = 1")?;
uv_snapshot!(
context.filters(),
context
.check()
.arg("--no-dev")
.arg("--exclude-newer")
.arg("2026-02-15T00:00:00Z")
.arg("--verbose")
.env(EnvVars::RUST_LOG, "uv::commands::project::check::ty=debug"),
@"
success: true
exit_code: 0
----- stdout -----
All checks passed!
----- stderr -----
warning: The `tool.uv.dev-dependencies` field (used in `pyproject.toml`) is deprecated and will be removed in a future release; use `dependency-groups.dev` instead
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
DEBUG `--exclude-newer` is ignored for pinned version `0.0.17`
DEBUG Using `ty==0.0.17`
DEBUG Passing workspace metadata to `ty check` via stdin
"
);
Ok(())
}
#[test]
#[cfg(feature = "test-pypi")]
fn check_uses_applicable_ty_version_from_forked_lock() -> Result<()> {
let context = uv_test::test_context!("3.12");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = []
[dependency-groups]
dev = [
"ty==0.0.16 ; python_version < '3.12'",
"ty==0.0.17 ; python_version >= '3.12'",
]
"#})?;
context.temp_dir.child("main.py").write_str("x = 1")?;
uv_snapshot!(
context.filters(),
context
.check()
.arg("--no-dev")
.arg("--verbose")
.env(EnvVars::RUST_LOG, "uv::commands::project::check::ty=debug"),
@"
success: true
exit_code: 0
----- stdout -----
All checks passed!
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
DEBUG `--exclude-newer` is ignored for pinned version `0.0.17`
DEBUG Using `ty==0.0.17`
DEBUG Passing workspace metadata to `ty check` via stdin
"
);
Ok(())
}
#[test]
fn check_ignores_inactive_ty_declaration() -> Result<()> {
let context = uv_test::test_context!("3.12");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty>=999 ; python_version < '3.12'"]
"#})?;
context.temp_dir.child("main.py").write_str("x = 1")?;
uv_snapshot!(
context.filters(),
context
.check()
.arg("--verbose")
.env(EnvVars::RUST_LOG, "uv::commands::project::check::ty=debug"),
@"
success: true
exit_code: 0
----- stdout -----
All checks passed!
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
DEBUG Resolved `ty@>=0.0, <0.1` to `ty==0.0.17`
DEBUG Passing workspace metadata to `ty check` via stdin
"
);
Ok(())
}
#[test]
fn check_rejects_non_registry_ty_source() -> Result<()> {
let context = uv_test::test_context!("3.12");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty"]
[tool.uv.sources]
ty = { path = "does-not-exist" }
"#})?;
uv_snapshot!(context.filters(), context.check(), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
error: The active `ty` development dependency uses the non-registry source `does-not-exist`, but `uv check` can only install standalone `ty` releases by version; use a registry source, `--ty-version`, or the `TY` environment variable
");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty @ https://example.com/ty.whl"]
"#})?;
uv_snapshot!(context.filters(), context.check(), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
error: The active `ty` development dependency uses the direct URL `https://example.com/ty.whl`, but `uv check` can only install standalone `ty` releases by version; use a registry requirement, `--ty-version`, or the `TY` environment variable
");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty @ https://example.com/ty.whl"]
[tool.uv.sources]
ty = { index = "test" }
[[tool.uv.index]]
name = "test"
url = "https://example.com/simple"
explicit = true
"#})?;
// The registry override makes the inline URL registry-backed, so selection proceeds to the
// missing-lock error instead of rejecting the declaration as a direct URL.
uv_snapshot!(context.filters(), context.check().arg("--no-sync"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
error: The active `ty` development dependency requires an existing lockfile when `--no-sync` is used; update `uv.lock`, remove `--no-sync`, or use `--ty-version` or the `TY` environment variable
");
Ok(())
}
#[test]
fn check_active_ty_requires_lock_with_no_sync() -> Result<()> {
let context = uv_test::test_context!("3.12");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty==0.0.17"]
"#})?;
uv_snapshot!(context.filters(), context.check().arg("--no-sync"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
error: The active `ty` development dependency requires an existing lockfile when `--no-sync` is used; update `uv.lock`, remove `--no-sync`, or use `--ty-version` or the `TY` environment variable
");
Ok(())
}
#[test]
fn check_active_ty_rejects_stale_frozen_lock() -> Result<()> {
let context = uv_test::test_context!("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
"#})?;
context.lock().assert().success();
pyproject_toml.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty==0.0.17"]
"#})?;
uv_snapshot!(context.filters(), context.check().arg("--frozen"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
error: The active `ty` development dependency is not present in the lockfile for the selected Python environment; update `uv.lock`, or use `--ty-version` or the `TY` environment variable
");
Ok(())
}
#[test]
#[cfg(feature = "test-pypi")]
fn check_virtual_root_does_not_use_member_ty() -> Result<()> {
let context = uv_test::test_context!("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(indoc! {r#"
[tool.uv.workspace]
members = ["member"]
"#})?;
let member = context.temp_dir.child("member");
member.create_dir_all()?;
member.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "member"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty==0.0.17"]
"#})?;
context
.lock()
.arg("--exclude-newer")
.arg("2026-02-15T00:00:00Z")
.assert()
.success();
pyproject_toml.write_str(indoc! {r#"
[dependency-groups]
dev = ["ty==0.0.17"]
[tool.uv.workspace]
members = ["member"]
"#})?;
uv_snapshot!(context.filters(), context.check().arg("--frozen"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
error: The active `ty` development dependency is not present in the lockfile for the selected Python environment; update `uv.lock`, or use `--ty-version` or the `TY` environment variable
");
Ok(())
}
#[test]
#[cfg(feature = "test-pypi")]
fn check_virtual_root_uses_exact_ty_version_from_lock() -> Result<()> {
let context = uv_test::test_context!("3.12");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[dependency-groups]
dev = ["ty==0.0.17"]
[tool.uv.workspace]
members = ["member"]
"#})?;
let member = context.temp_dir.child("member");
member.create_dir_all()?;
member.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "member"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
"#})?;
context.temp_dir.child("main.py").write_str("x = 1")?;
context
.lock()
.arg("--exclude-newer")
.arg("2026-02-15T00:00:00Z")
.assert()
.success();
uv_snapshot!(
context.filters(),
context
.check()
.arg("--no-sync")
.arg("--verbose")
.env(EnvVars::RUST_LOG, "uv::commands::project::check::ty=debug"),
@r###"
success: true
exit_code: 0
----- stdout -----
All checks passed!
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
DEBUG `--exclude-newer` is ignored for pinned version `0.0.17`
DEBUG Using `ty==0.0.17`
DEBUG Passing workspace metadata to `ty check` via stdin
"###
);
Ok(())
}
#[test]
#[cfg(feature = "test-pypi")]
fn check_member_ty_ignores_virtual_root_dev_dependencies() -> Result<()> {
let context = uv_test::test_context!("3.12");
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[dependency-groups]
dev = ["iniconfig==2.0.0"]
[tool.uv.workspace]
members = ["member"]
"#})?;
let member = context.temp_dir.child("member");
member.create_dir_all()?;
member.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "member"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty==0.0.17"]
"#})?;
member.child("main.py").write_str("x = 1")?;
context
.lock()
.arg("--exclude-newer")
.arg("2026-02-15T00:00:00Z")
.assert()
.success();
// These mutually exclusive build settings would make the workspace root's development
// dependency unusable if it leaked into the member-only version extraction.
uv_snapshot!(
context.filters(),
context
.check()
.current_dir(member.path())
.arg("--no-sync")
.arg("--no-build-package")
.arg("iniconfig")
.arg("--no-binary-package")
.arg("iniconfig")
.arg("--verbose")
.env(EnvVars::RUST_LOG, "uv::commands::project::check::ty=debug"),
@"
success: true
exit_code: 0
----- stdout -----
All checks passed!
----- stderr -----
warning: `uv check` is experimental and may change without warning. Pass `--preview-features check-command` to disable this warning.
DEBUG `--exclude-newer` is ignored for pinned version `0.0.17`
DEBUG Using `ty==0.0.17`
DEBUG Passing workspace metadata to `ty check` via stdin
"
);
Ok(())
}
#[test]
#[cfg(feature = "test-pypi")]
fn check_uses_ty_from_environment() -> Result<()> {
@@ -56,13 +586,27 @@ fn check_uses_ty_from_environment() -> Result<()> {
.success();
let ty = bin_dir.child(format!("ty{}", std::env::consts::EXE_SUFFIX));
// `TY` takes precedence over both an explicit version and an unsupported project source.
context
.temp_dir
.child("pyproject.toml")
.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty @ https://example.com/ty.whl"]
"#})?;
context.temp_dir.child("main.py").write_str("x = 1")?;
uv_snapshot!(
context.filters(),
context
.check()
.arg("--no-project")
.arg("--no-sync")
.arg("--ty-version")
.arg(">=999.0.0")
.arg("--verbose")
@@ -130,6 +674,7 @@ fn check_passes_workspace_metadata_to_ty() -> Result<()> {
fn check_no_sync_ignores_invalid_lockfile() -> Result<()> {
let context = uv_test::test_context!("3.12");
// An explicit version bypasses both project-source validation and lockfile parsing.
context
.temp_dir
.child("pyproject.toml")
@@ -139,6 +684,9 @@ fn check_no_sync_ignores_invalid_lockfile() -> Result<()> {
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[dependency-groups]
dev = ["ty @ https://example.com/ty.whl"]
"#})?;
context.temp_dir.child("uv.lock").write_str("invalid")?;
context.temp_dir.child("main.py").write_str(indoc! {r"