Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

132 changes: 132 additions & 0 deletions crates/ty/tests/file_watching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,138 @@ fn changed_file() -> anyhow::Result<()> {
Ok(())
}

#[test]
fn scripts_to_synchronize_after_file_and_directory_changes() -> anyhow::Result<()> {
let script = dedent(
r"
# /// script
# dependencies = []
# ///
",
);
let mut case = setup(|context: &mut SetupContext| {
context.write_project_file("existing.py", &script)?;
context.write_project_file("edited.py", "")?;
context.write_file("new/script.py", &script)
})?;
let edited = case.project_path("edited.py");
assert_eq!(
case.db().project().script_files(case.db()).iter().count(),
1
);

update_file(&edited, &script)?;

let changes = case.take_watch_changes(event_for_file("edited.py"));
let changes = case.apply_changes(&changes);
assert_eq!(
changes.scripts_to_synchronize(case.db()),
vec![case.system_file(&edited)?]
);

std::fs::rename(
case.root_path().join("new").as_std_path(),
case.project_path("new").as_std_path(),
)?;
let mut changes = case.take_watch_changes(event_for_file("new"));
update_file(&edited, "")?;
changes.extend(case.stop_watch(event_for_file("edited.py")));

// Directory discovery also includes unchanged scripts, but `edited.py` no longer
// contains a PEP 723 script metadata block.
let changes = case.apply_changes(&changes);
assert_eq!(
changes
.scripts_to_synchronize(case.db())
.into_iter()
.collect::<HashSet<_>>(),
HashSet::from([
case.system_file(case.project_path("existing.py"))?,
case.system_file(case.project_path("new/script.py"))?,
])
);

Ok(())
}

#[test]
fn script_exclusion_tracks_file_creation_and_metadata_edits() -> anyhow::Result<()> {
let mut case = setup([(
"ty.toml",
r"
[src]
exclude-scripts = true
",
)])?;
let path = case.project_path("script.py");
let script = r"
# /// script
# dependencies = []
# ///
missing
";
assert!(case.db().check().is_empty());

std::fs::write(path.as_std_path(), dedent(script).as_ref())?;
let changes = case.take_watch_changes(event_for_file("script.py"));
let changes = case.apply_changes(&changes);
assert!(changes.scripts_to_synchronize(case.db()).is_empty());
let file = case.system_file(&path)?;
assert!(case.db().check().is_empty());
assert!(case.db().check_file(file).is_empty());

update_file(&path, "missing\n")?;
let changes = case.take_watch_changes(event_for_file("script.py"));
case.apply_changes(&changes);
assert_eq!(case.db().check().len(), 1);
assert_eq!(case.db().check_file(file).len(), 1);

update_file(&path, script)?;
let changes = case.take_watch_changes(event_for_file("script.py"));
case.apply_changes(&changes);
assert!(case.db().check().is_empty());
assert!(case.db().check_file(file).is_empty());

Ok(())
}

#[test]
fn explicitly_included_file_remains_checked_when_becoming_a_script() -> anyhow::Result<()> {
let mut case = setup([
(
"ty.toml",
r"
[src]
exclude-scripts = true
",
),
("script.py", "missing\n"),
])?;
let path = case.project_path("script.py");
let file = case.system_file(&path)?;
case.db
.project()
.set_included_paths(&mut case.db, vec![path.clone()]);
assert_eq!(case.db().check().len(), 1);
assert_eq!(case.db().check_file(file).len(), 1);

update_file(
&path,
r"
# /// script
# dependencies = []
# ///
missing
",
)?;
let changes = case.take_watch_changes(event_for_file("script.py"));
case.apply_changes(&changes);
assert_eq!(case.db().check().len(), 1);
assert_eq!(case.db().check_file(file).len(), 1);

Ok(())
}

#[test]
fn deleted_file() -> anyhow::Result<()> {
let foo_source = "print('Hello, world!')";
Expand Down
6 changes: 1 addition & 5 deletions crates/ty_ide/src/call_hierarchy/incoming_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,7 @@ pub fn incoming_calls(db: &dyn Db, file: ProgramFile<'_>, offset: TextSize) -> V
if is_externally_visible {
let program = model.program();
let files = db.project().files(db);
let files: Vec<_> = files
.iter()
.copied()
.filter(|other| *other != source_file)
.collect();
let files: Vec<_> = files.iter().filter(|other| *other != source_file).collect();
let minimum_job_len = minimum_parallel_job_len(files.len(), MAX_MIN_FILES_PER_PARALLEL_JOB);
// The byte-level text prefilter still pays off as a coarse gate:
// files that don't contain the target name (or an import of it)
Expand Down
1 change: 0 additions & 1 deletion crates/ty_ide/src/goto_implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ pub fn goto_implementation(
.project()
.files(db)
.iter()
.copied()
.filter(|candidate| *candidate != source_file)
.collect();
candidate_files.push(source_file);
Expand Down
6 changes: 1 addition & 5 deletions crates/ty_ide/src/references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,7 @@ pub(crate) fn references(
if search_across_files && (is_parameter || is_externally_visible_symbol) {
let program = model.program();
let files = db.project().files(db);
let files: Vec<_> = files
.iter()
.copied()
.filter(|other| *other != source_file)
.collect();
let files: Vec<_> = files.iter().filter(|other| *other != source_file).collect();
let minimum_job_len = minimum_parallel_job_len(files.len(), MAX_MIN_FILES_PER_PARALLEL_JOB);
let other_references = files
.into_par_iter()
Expand Down
2 changes: 1 addition & 1 deletion crates/ty_ide/src/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub fn rename(

/// Helper function to check if a file is included in the project.
fn is_file_in_project(db: &dyn Db, file: File) -> bool {
file.path(db).is_system_virtual_path() || db.project().files(db).contains(&file)
file.path(db).is_system_virtual_path() || db.project().files(db).contains(file)
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion crates/ty_ide/src/workspace_symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn workspace_symbols(db: &dyn Db, query: &str) -> Vec<WorkspaceSymbolInfo> {
let project = db.project();
let query = QueryPattern::fuzzy(query);
let files = project.files(db);
let files: Vec<_> = files.iter().copied().collect();
let files: Vec<_> = files.iter().collect();

files
.into_par_iter()
Expand Down
1 change: 1 addition & 0 deletions crates/ty_project/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ tracing = { workspace = true }

[dev-dependencies]
ruff_db = { workspace = true, features = ["os", "testing"] }
ruff_python_trivia = { workspace = true }

insta = { workspace = true, features = ["redactions", "ron"] }
tempfile = { workspace = true }
Expand Down
Loading