-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Error instead of panic! when running Ruff from a deleted directory (#16903)
#17054
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
to reflect function behavior.
otherwise ruff panics if the working directory does not exist.
This test works when executed with nexttest but has interactions with other `resolve_files` tests when executed.
ntBre
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! I took a look at this earlier in the week, and I was wondering how to go about testing it too.
I think if you move the new integration test to its own file, it will be built and run separately by cargo test and avoid the parallelization issues you ran into. Then you can also skip saving the original_dir and restoring it since the test should be run on its own.
Alternatively, we could possibly skip testing this to avoid changing the cwd at all, which feels a little scary. What do you think @MichaReiser?
crates/ruff/src/resolve.rs
Outdated
| ) -> Result<PyprojectConfig> { | ||
| // Ensure directory exists before proceeding | ||
| if std::env::current_dir().is_err() { | ||
| return Err(anyhow!("Working directory does not exist")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could use bail! here instead of Err(anyhow!(...)).
I also think we might as well do something like this:
let Ok(cwd) = std::env::current_dir() else {
bail!("Working directory does not exist");
};instead of using path_dedot::CWD below, which is just a LazyLock around std::env::current_dir. That makes it a bit more clear what this check is for, I think.
We may also want to move this check into the if config_arguments.isolated check if that's the only place CWD is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree on your proposal for rewriting. It makes the intentions of the check clear and we can get rid of the comment.
path_dedot::CWD is used a couple of times throughout the function so I will keep it outside of the if clause.
crates/ruff/tests/resolve_files.rs
Outdated
| let temp_path = temp_dir.path().to_path_buf(); | ||
| let original_dir = std::env::current_dir().unwrap(); | ||
| std::env::set_current_dir(&temp_path).unwrap(); | ||
| std::mem::drop(temp_dir); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I would just use drop directly without qualifying it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that it reads nicer.
I will also just import from std::env so we can use directory operations without qualifiers.
crates/ruff/tests/resolve_files.rs
Outdated
| insta::with_settings!({ | ||
| filters => TEST_FILTERS.to_vec() | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you actually need these filters and could leave them out. Paths only cause problems when they appear in the snapshot output.
|
to have the test binary is built and run seperately. This is necessary as changing the working directory within the tests likely breaks other tests executed in parallel by changing the working directory. Also trim down the test logic a bit. "--no-cache" is redundant. Use imports instead of qualifiers for readability.
This is already achieved by having the test in a dedicated file.
Use bail! and let else since it communicates the intent more clearly.
|
Having the test in a dedicated file now works for both |
crates/ruff/src/resolve.rs
Outdated
| config_arguments: &ConfigArguments, | ||
| stdin_filename: Option<&Path>, | ||
| ) -> Result<PyprojectConfig> { | ||
| let Ok(_cwd) = std::env::current_dir() else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels off that the path isn't used here. I think we should change the code to call cwd.parse_dot() and use it instead of &path_dedot::CWD below
Edit: This is the same as what @ntBre was proposing
| set_current_dir(&temp_path).unwrap(); | ||
| drop(temp_dir); | ||
|
|
||
| assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)).arg("check"), @r###" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @ntBre that changing the working directory is problematic. Let's only override the current working directory for the spanned CLI command.
| assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)).arg("check"), @r###" | |
| assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)).arg("check").current_dir(&temp_path), @r###" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I tried current_dir when I looked at this, and it caused a different panic in the Command invocation, separate from the one we're trying to test. But it would be good to double check, and maybe I missed something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the assert_cmd_snapshot or current_dir calls an unwrap() somewhere. The test fails with:
[...] called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory"There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I see. Let's add some module level documentation (or at least test level) explaining why this test has to be its own module.
Instead of path_dedot::CWD where appropriate
crates/ruff/src/resolve.rs
Outdated
| .unwrap_or(&path_dedot::CWD.as_path()), | ||
| )? { | ||
| if let Some(pyproject) = | ||
| pyproject::find_settings_toml(stdin_filename.as_ref().unwrap_or(&cwd.as_path()))? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intentional that you're only using parse_dot in some paths?
I think I'd change the method to
let Ok(cwd) = std::env::current_dir() else {
bail!("Working directory does not exist")
};
let cwd = cwd.parse_dot()?;There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was born out of me wrestling with the typechecker, using the previous implementation as reference.
I agree that a more consistent, less verbose usage is preferable.
Is the change in 27a8964 what you had in mind? I'm a bit out of my depth with Cow and the path handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks right to me. I think we could skip calling parse_dot at all since path_dedot::CWD doesn't:
but I think Micha's point was that we should be consistent one way or the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ntBre
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for following up on this, it's looking good. Just one more nit to avoid as_ref calls and an idea for fixing Windows CI.
I'll defer to Micha for the final approval, but this looks good to me once CI passes.
crates/ruff/src/resolve.rs
Outdated
| .unwrap_or(&path_dedot::CWD.as_path()), | ||
| )? { | ||
| if let Some(pyproject) = | ||
| pyproject::find_settings_toml(stdin_filename.as_ref().unwrap_or(&cwd.as_ref()))? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: You do need as_ref currently, but stdin_filename is already an Option<&Path>, so you can actually simplify both of these cases (here and below on line 137) to this:
| pyproject::find_settings_toml(stdin_filename.as_ref().unwrap_or(&cwd.as_ref()))? | |
| pyproject::find_settings_toml(stdin_filename.unwrap_or(&cwd))? |
crates/ruff/tests/direxist_guard.rs
Outdated
| //! Tests in the same module become flaky under `cargo test`s parallel execution | ||
| //! due to in-test working directory manipulation. | ||
| #![cfg(not(target_family = "wasm"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the Windows CI failure is real. I think Windows will keep the directory around as long as a process is using it. Maybe we need to exclude both wasm and windows targets? I always forget the syntax for this, but I think it's something like this:
| #![cfg(not(target_family = "wasm"))] | |
| #![cfg(not(any(target_family = "wasm", target_family = "windows")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave the Windows CI failures to you, if that's fine... I don't have access to a Windows machine.
* main: [red-knot] Add property tests for callable types (#17006) [red-knot] Disjointness for callable types (#17094) [red-knot] Flatten `Type::Callable` into four `Type` variants (#17126) mdtest.py: do a full mdtest run immediately when the script is executed (#17128) [red-knot] Fix callable subtyping for standard parameters (#17125) [red-knot] Fix more `redundant-cast` false positives (#17119) Sync vendored typeshed stubs (#17106) [red-knot] support Any as a class in typeshed (#17107) Visit `Identifier` node as part of the `SourceOrderVisitor` (#17110) [red-knot] Don't infer Todo for quite so many tuple type expressions (#17116) CI: Run pre-commit on depot machine (#17120) Error instead of `panic!` when running Ruff from a deleted directory (#16903) (#17054) Control flow graph: setup (#17064) [red-knot] Playground improvements (#17109) [red-knot] IDE crate (#17045) Update dependency vite to v6.2.4 (#17104) [red-knot] Add redundant-cast error (#17100) [red-knot] Narrowing on `in tuple[...]` and `in str` (#17059)
Closes #16903
Summary
Check if the current working directory exist. If not, provide an error instead of panicking.
Fixed a stale comment in
resolve_default_files.Test Plan
I added a test to the
resolve_files.rs.Manual testing follows steps of #16903 :
mkdir tmp cd tmpOpen Issues / Questions to Reviewer
All tests pass when executed with
cargo nextest run.However, with
cargo testthe parallelization makes the other tests fail as we change thepwd.Serial execution with
cargo testseems to require another dependency or some workarounds.Do you think an additional dependency or test complexity is worth testing this small edge case, do you have another implementation idea, or should i rather remove the test?
P.S.: I'm currently participating in a batch at the Recurse Center and would love to contribute more for the next six weeks to improve my Rust. Let me know if you're open to mentoring/reviewing and/or if you have specific areas where help would be most valued.