Skip to content

Commit a81291e

Browse files
authored
[ty] Defer uv workspace discovery until after project configuration (#28525)
## Summary Today, we call uv metadata before we discover the ty project. This is fine for `uv check` where we always want to call uv metadata, but it's problematic for `ty check` because it prevents us from adding a configuration option to skip the metadata discovery (an opt out). This PR refactors the discovery to: 1. Find the ty project 2. Use the project to decide whether to call uv (for now, this is skipped because this PR doesn't add the setting) 3. Call uv metadata and if the uv discovered project is different from ty's, make that project the root instead ## Test Plan Testing: Project, CLI uv workspace, and language server tests pass; Clippy and hooks pass.
1 parent b6a74d2 commit a81291e

10 files changed

Lines changed: 386 additions & 363 deletions

File tree

‎crates/ruff_benchmark/benches/ty_script.rs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@ use divan::{Bencher, bench};
55
use rayon::ThreadPoolBuilder;
66
use ruff_db::system::{OsSystem, System, SystemPath, TestSystem};
77
use ty_project::{
8-
Db, ProjectDatabase, ProjectMetadata, ScriptEnvironmentAvailability, uv_test_env_vars,
8+
Db, ProjectDatabase, ProjectMetadata, ScriptEnvironmentAvailability, UseUv, uv_test_env_vars,
99
};
1010
use ty_static::EnvVars;
1111

1212
fn setup_iteration(root: &SystemPath, uv: &SystemPath) -> ProjectDatabase {
1313
let system = TestSystem::new(OsSystem::new(root));
1414
system.clear_env_vars();
1515
system.set_env_vars(uv_test_env_vars());
16-
system.set_env_var(EnvVars::TY_UV, "scripts");
1716
system.set_env_var(EnvVars::UV, uv.as_str());
1817

19-
let metadata = ProjectMetadata::discover(root, &system).unwrap();
18+
let metadata = ProjectMetadata::discover(root, &system)
19+
.unwrap()
20+
.with_use_uv(UseUv::Scripts);
2021
ProjectDatabase::fallible(metadata, system).unwrap()
2122
}
2223

‎crates/ty/src/lib.rs‎

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use ty_project::metadata::settings::TerminalSettings;
3131
use ty_project::watch::ProjectWatcher;
3232
use ty_project::{
3333
ChangeResult, CollectReporter, Db, Project, ScriptEnvironmentAvailability, UseUv,
34-
UvSyncProgress, watch,
34+
UvSyncProgress, UvWorkspace, watch,
3535
};
3636
use ty_project::{ProjectDatabase, ProjectMetadata, ProjectReloadResult};
3737
use ty_python_semantic::{fix_all_diagnostics, suppress_all_diagnostics};
@@ -148,8 +148,17 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
148148
.map(|path| SystemPath::absolute(path, &cwd));
149149
let force_exclude = args.force_exclude();
150150

151-
let use_uv = UseUv::from_system(&system);
152-
let use_uv = if use_uv == UseUv::On
151+
let mut project_metadata = match &config_file {
152+
Some(config_file) => {
153+
ProjectMetadata::from_config_file(config_file.clone(), &project_path, &system)?
154+
}
155+
None => ProjectMetadata::discover(&project_path, &system)?,
156+
};
157+
158+
project_metadata.apply_configuration_files(&system)?;
159+
160+
project_metadata.set_override_options(args.into_options());
161+
if project_metadata.use_uv() == UseUv::On
153162
&& let [path] = check_paths.as_slice()
154163
&& system.is_file(path)
155164
&& system
@@ -158,21 +167,13 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
158167
{
159168
// A single PEP 723 script uses its own uv environment, even with an explicit ty
160169
// configuration file. The other explicit paths still discover workspace metadata.
161-
UseUv::Scripts
162-
} else {
163-
use_uv
164-
};
165-
166-
let mut project_metadata = match &config_file {
167-
Some(config_file) => {
168-
ProjectMetadata::from_config_file(config_file.clone(), &project_path, &system, use_uv)?
169-
}
170-
None => ProjectMetadata::discover_with_uv(&project_path, &system, use_uv)?,
171-
};
172-
173-
project_metadata.apply_configuration_files(&system)?;
170+
project_metadata = project_metadata.with_use_uv(UseUv::Scripts);
171+
}
174172

175-
project_metadata.set_override_options(args.into_options());
173+
if project_metadata.use_uv().workspace_discovery_enabled() {
174+
let workspace = UvWorkspace::discover(&project_path, &system);
175+
project_metadata.apply_uv_workspace(&system, workspace)?;
176+
}
176177

177178
let mut db = ProjectDatabase::fallible(project_metadata, system)?;
178179
let project = db.project();

‎crates/ty/tests/file_watching.rs‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use ty_project::metadata::value::{RelativeGlobPattern, RelativePathBuf};
2727
#[cfg(unix)]
2828
use ty_project::watch::watch_paths;
2929
use ty_project::watch::{ChangeEvent, ProjectWatcher, directory_watcher};
30-
use ty_project::{ChangeResult, Db, ProjectDatabase, ProjectMetadata, UseUv};
30+
use ty_project::{ChangeResult, Db, ProjectDatabase, ProjectMetadata, UvWorkspace};
3131
use ty_python_core::platform::PythonPlatform;
3232
use ty_static::EnvVars;
3333

@@ -552,12 +552,7 @@ where
552552
}
553553

554554
let mut project = if let Some(config_file_override) = config_file_override {
555-
ProjectMetadata::from_config_file(
556-
config_file_override,
557-
&project_path,
558-
&system,
559-
UseUv::from_system(&system),
560-
)?
555+
ProjectMetadata::from_config_file(config_file_override, &project_path, &system)?
561556
} else {
562557
ProjectMetadata::discover(&project_path, &system)?
563558
};
@@ -568,6 +563,10 @@ where
568563
if let Some(override_options) = override_options {
569564
project.set_override_options(override_options);
570565
}
566+
if project.use_uv().workspace_discovery_enabled() {
567+
let workspace = UvWorkspace::discover(&project_path, &system);
568+
project.apply_uv_workspace(&system, workspace)?;
569+
}
571570

572571
// We need a chance to create the directories here.
573572
let merged_options = project.to_merged_options();

‎crates/ty_project/src/db/changes.rs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,9 @@ impl ProjectDatabase {
363363
if metadata.use_uv().workspace_discovery_enabled() {
364364
result.project_sync_path = Some(path.to_path_buf());
365365
} else {
366-
// We're not refreshing uv metadata, so use the existing environment.
367-
let environment = metadata.environment().clone();
368-
match project.rediscover(self, path, environment) {
366+
// We're not refreshing uv metadata, so use the existing workspace.
367+
let workspace = metadata.uv_workspace().clone();
368+
match project.rediscover(self, path, workspace) {
369369
Ok(ProjectReloadResult::Unchanged) => {}
370370
Ok(ProjectReloadResult::Changed { files_changed }) => {
371371
result.project_changed = true;
@@ -642,7 +642,7 @@ fn affects_uv_metadata(db: &dyn Db, change: &ChangeEvent) -> bool {
642642
let project = db.project();
643643
let workspace_root = project
644644
.metadata(db)
645-
.uv_workspace()
645+
.uv_workspace_metadata()
646646
.map_or(project.root(db), |workspace| workspace.workspace_root());
647647
let is_included_workspace_directory = path.starts_with(workspace_root)
648648
&& project

‎crates/ty_project/src/lib.rs‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ use ty_python_semantic::dependency::{DependencyMetadata, DependencyProjectKind};
3636
use ty_python_semantic::lint::RuleSelection;
3737
use uv::DependencyMetadataError;
3838
pub use uv::{
39-
ScriptEnvironmentAvailability, UseUv, UvEnvironments, UvSyncChanges, uv_test_env_vars,
39+
ScriptEnvironmentAvailability, UseUv, UvEnvironments, UvSyncChanges, UvWorkspace,
40+
uv_test_env_vars,
4041
};
4142

4243
mod db;
@@ -285,7 +286,7 @@ impl Project {
285286
db: &dyn Db,
286287
) -> Result<Option<Box<DependencyMetadata>>, DependencyMetadataError> {
287288
let metadata = self.metadata(db);
288-
let Some(workspace) = metadata.uv_workspace() else {
289+
let Some(workspace) = metadata.uv_workspace_metadata() else {
289290
tracing::debug!(
290291
"Skipping dependency checks for '{}': no uv workspace metadata is available",
291292
metadata.root(),
@@ -375,11 +376,9 @@ impl Project {
375376
self,
376377
db: &mut dyn Db,
377378
path: &SystemPath,
378-
environment: uv::ProjectEnvironment,
379+
workspace: uv::UvWorkspace,
379380
) -> Result<ProjectReloadResult, ProjectMetadataError> {
380-
let mut metadata = self
381-
.metadata(db)
382-
.rediscover(db.system(), path, environment)?;
381+
let mut metadata = self.metadata(db).rediscover(db.system(), path, workspace)?;
383382
if let Err(error) = metadata.apply_configuration_files(db.system()) {
384383
let error = anyhow::Error::new(error);
385384
tracing::error!(
@@ -802,7 +801,7 @@ impl Project {
802801
pub fn check_settings(&self, db: &dyn Db) -> Vec<Diagnostic> {
803802
let metadata = self.metadata(db);
804803
let uv_diagnostic = metadata.uv_diagnostic(db).or_else(|| {
805-
let workspace = metadata.uv_workspace()?;
804+
let workspace = metadata.uv_workspace_metadata()?;
806805
let error = self.dependency_metadata(db).as_ref().err()?;
807806
let mut diagnostic = error.to_diagnostic(DependencyProjectKind::Project);
808807
if let Ok(file) =

0 commit comments

Comments
 (0)