mirror of https://github.com/astral-sh/ruff
Ignore any `pyproject.toml` without a `[tool.ruff]` section (#1243)
This commit is contained in:
parent
d814ebd21f
commit
549ea2f85f
17
README.md
17
README.md
|
|
@ -343,15 +343,18 @@ directory hierarchy is used for every individual file, with all paths in the `py
|
|||
|
||||
There are a few exceptions to these rules:
|
||||
|
||||
1. If a configuration file is passed directly via `--config`, those settings are used for across
|
||||
1. In locating the "closest" `pyproject.toml` file for a given path, Ruff ignore any
|
||||
`pyproject.toml` files that lack a `[tool.ruff]` section.
|
||||
2. If a configuration file is passed directly via `--config`, those settings are used for across
|
||||
files. Any relative paths in that configuration file (like `exclude` globs or `src` paths) are
|
||||
resolved relative to the _current working directory_.
|
||||
2. If no `pyproject.toml` file is found in the filesystem hierarchy, Ruff will fall back to using
|
||||
a default configuration. If a user-specific configuration file exists at `${config_dir}/ruff/pyproject.toml`,
|
||||
that file will be used instead of the default configuration, with `${config_dir}` being determined
|
||||
via the [`dirs](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) crate, and all relative paths
|
||||
being again resolved relative to the _current working directory_.
|
||||
3. Any `pyproject.toml`-supported settings that are provided on the command-line (e.g., via
|
||||
3. If no `pyproject.toml` file is found in the filesystem hierarchy, Ruff will fall back to using
|
||||
a default configuration. If a user-specific configuration file exists
|
||||
at `${config_dir}/ruff/pyproject.toml`,
|
||||
that file will be used instead of the default configuration, with `${config_dir}` being
|
||||
determined via the [`dirs](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) crate, and all
|
||||
relative paths being again resolved relative to the _current working directory_.
|
||||
4. Any `pyproject.toml`-supported settings that are provided on the command-line (e.g., via
|
||||
`--select`) will override the settings in _every_ resolved configuration file.
|
||||
|
||||
Unlike [ESLint](https://eslint.org/docs/latest/user-guide/configuring/configuration-files#cascading-and-hierarchy),
|
||||
|
|
|
|||
|
|
@ -9,30 +9,32 @@ Running from the repo root should pick up and enforce the appropriate settings f
|
|||
|
||||
```
|
||||
∴ cargo run resources/test/project/
|
||||
Found 7 error(s).
|
||||
resources/test/project/examples/.dotfiles/script.py:1:8: F401 `os` imported but unused
|
||||
resources/test/project/examples/.dotfiles/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
Found 8 error(s).
|
||||
resources/test/project/examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
resources/test/project/examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
resources/test/project/src/file.py:1:8: F401 `os` imported but unused
|
||||
resources/test/project/src/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
resources/test/project/src/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
4 potentially fixable with the --fix option.
|
||||
6 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from the project directory itself should exhibit the same behavior:
|
||||
|
||||
```
|
||||
∴ (cd resources/test/project/ && cargo run .)
|
||||
Found 7 error(s).
|
||||
examples/.dotfiles/script.py:1:8: F401 `os` imported but unused
|
||||
examples/.dotfiles/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
Found 8 error(s).
|
||||
examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
src/file.py:1:8: F401 `os` imported but unused
|
||||
src/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
src/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
4 potentially fixable with the --fix option.
|
||||
6 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from the sub-package directory should exhibit the same behavior, but omit the top-level
|
||||
|
|
@ -51,19 +53,22 @@ file paths from the current working directory:
|
|||
|
||||
```
|
||||
∴ (cargo run -- --config=resources/test/project/pyproject.toml resources/test/project/)
|
||||
Found 11 error(s).
|
||||
resources/test/project/examples/.dotfiles/script.py:1:8: F401 `os` imported but unused
|
||||
resources/test/project/examples/.dotfiles/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
Found 14 error(s).
|
||||
resources/test/project/examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 `os` imported but unused
|
||||
resources/test/project/examples/docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
resources/test/project/examples/docs/docs/file.py:1:8: F401 `os` imported but unused
|
||||
resources/test/project/examples/docs/docs/file.py:3:8: F401 `numpy` imported but unused
|
||||
resources/test/project/examples/docs/docs/file.py:4:27: F401 `docs.concepts.file` imported but unused
|
||||
resources/test/project/examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
|
||||
resources/test/project/examples/excluded/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
resources/test/project/src/file.py:1:8: F401 `os` imported but unused
|
||||
resources/test/project/src/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
resources/test/project/src/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
7 potentially fixable with the --fix option.
|
||||
10 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from a parent directory should this "ignore" the `exclude` (hence, `concepts/file.py` gets
|
||||
|
|
@ -72,10 +77,10 @@ included in the output):
|
|||
```
|
||||
∴ (cd resources/test/project/examples && cargo run -- --config=docs/pyproject.toml .)
|
||||
Found 4 error(s).
|
||||
.dotfiles/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
excluded/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
1 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,2 @@
|
|||
import os
|
||||
|
||||
|
||||
def f():
|
||||
x = 1
|
||||
import numpy as np
|
||||
from app import app_file
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ pub mod visibility;
|
|||
|
||||
/// Load the relevant `Settings` for a given `Path`.
|
||||
fn resolve(path: &Path) -> Result<Settings> {
|
||||
if let Some(pyproject) = pyproject::find_pyproject_toml(path) {
|
||||
if let Some(pyproject) = pyproject::find_pyproject_toml(path)? {
|
||||
// First priority: `pyproject.toml` in the current `Path`.
|
||||
resolver::resolve_settings(&pyproject, &Relativity::Parent, None)
|
||||
} else if let Some(pyproject) = pyproject::find_user_pyproject_toml() {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ fn resolve(config: Option<PathBuf>, overrides: &Overrides) -> Result<PyprojectDi
|
|||
// current working directory. (This matches ESLint's behavior.)
|
||||
let settings = resolve_settings(&pyproject, &Relativity::Cwd, Some(overrides))?;
|
||||
Ok(PyprojectDiscovery::Fixed(settings))
|
||||
} else if let Some(pyproject) = pyproject::find_pyproject_toml(path_dedot::CWD.as_path()) {
|
||||
} else if let Some(pyproject) = pyproject::find_pyproject_toml(path_dedot::CWD.as_path())? {
|
||||
// Second priority: find a `pyproject.toml` file in the current working path,
|
||||
// and resolve all paths relative to that directory. (With
|
||||
// `Strategy::Hierarchical`, we'll end up finding the "closest" `pyproject.toml`
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use rustc_hash::FxHashSet;
|
|||
use crate::cli::Overrides;
|
||||
use crate::fs;
|
||||
use crate::settings::configuration::Configuration;
|
||||
use crate::settings::pyproject::has_ruff_section;
|
||||
use crate::settings::{pyproject, Settings};
|
||||
|
||||
/// The strategy used to discover Python files in the filesystem..
|
||||
|
|
@ -201,9 +202,11 @@ pub fn python_files_in_path(
|
|||
for ancestor in path.ancestors() {
|
||||
let pyproject = ancestor.join("pyproject.toml");
|
||||
if pyproject.is_file() {
|
||||
let (root, settings) =
|
||||
resolve_scoped_settings(&pyproject, &Relativity::Parent, Some(overrides))?;
|
||||
resolver.add(root, settings);
|
||||
if has_ruff_section(&pyproject)? {
|
||||
let (root, settings) =
|
||||
resolve_scoped_settings(&pyproject, &Relativity::Parent, Some(overrides))?;
|
||||
resolver.add(root, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -237,12 +240,23 @@ pub fn python_files_in_path(
|
|||
{
|
||||
let pyproject = entry.path().join("pyproject.toml");
|
||||
if pyproject.is_file() {
|
||||
match resolve_scoped_settings(
|
||||
&pyproject,
|
||||
&Relativity::Parent,
|
||||
Some(overrides),
|
||||
) {
|
||||
Ok((root, settings)) => resolver.write().unwrap().add(root, settings),
|
||||
match has_ruff_section(&pyproject) {
|
||||
Ok(false) => {}
|
||||
Ok(true) => {
|
||||
match resolve_scoped_settings(
|
||||
&pyproject,
|
||||
&Relativity::Parent,
|
||||
Some(overrides),
|
||||
) {
|
||||
Ok((root, settings)) => {
|
||||
resolver.write().unwrap().add(root, settings);
|
||||
}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
|
|
@ -272,8 +286,8 @@ pub fn python_files_in_path(
|
|||
return WalkState::Skip;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("Ignored path due to error in parsing: {:?}: {}", path, e);
|
||||
Err(err) => {
|
||||
debug!("Ignored path due to error in parsing: {:?}: {}", path, err);
|
||||
return WalkState::Skip;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,17 +33,24 @@ fn parse_pyproject_toml(path: &Path) -> Result<Pyproject> {
|
|||
toml::from_str(&contents).map_err(std::convert::Into::into)
|
||||
}
|
||||
|
||||
/// Find the nearest `pyproject.toml` file.
|
||||
pub fn find_pyproject_toml(path: &Path) -> Option<PathBuf> {
|
||||
for directory in path.ancestors() {
|
||||
let pyproject = directory.join("pyproject.toml");
|
||||
if pyproject.is_file() {
|
||||
return Some(pyproject);
|
||||
}
|
||||
}
|
||||
None
|
||||
/// Return `true` if a `pyproject.toml` contains a `[tool.ruff]` section.
|
||||
pub fn has_ruff_section(path: &Path) -> Result<bool> {
|
||||
let pyproject = parse_pyproject_toml(path)?;
|
||||
Ok(pyproject.tool.and_then(|tool| tool.ruff).is_some())
|
||||
}
|
||||
|
||||
/// Find the path to the `pyproject.toml` file, if such a file exists.
|
||||
pub fn find_pyproject_toml(path: &Path) -> Result<Option<PathBuf>> {
|
||||
for directory in path.ancestors() {
|
||||
let pyproject = directory.join("pyproject.toml");
|
||||
if pyproject.is_file() && has_ruff_section(&pyproject)? {
|
||||
return Ok(Some(pyproject));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Find the path to the user-specific `pyproject.toml`, if it exists.
|
||||
pub fn find_user_pyproject_toml() -> Option<PathBuf> {
|
||||
let mut path = dirs::config_dir()?;
|
||||
path.push("ruff");
|
||||
|
|
@ -55,6 +62,7 @@ pub fn find_user_pyproject_toml() -> Option<PathBuf> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Load `Options` from a `pyproject.toml`.
|
||||
pub fn load_options(pyproject: &Path) -> Result<Options> {
|
||||
Ok(parse_pyproject_toml(pyproject)
|
||||
.map_err(|err| anyhow!("Failed to parse `{}`: {}", pyproject.to_string_lossy(), err))?
|
||||
|
|
@ -355,7 +363,7 @@ other-attribute = 1
|
|||
fn find_and_parse_pyproject_toml() -> Result<()> {
|
||||
let cwd = current_dir()?;
|
||||
let pyproject =
|
||||
find_pyproject_toml(&cwd.join("resources/test/fixtures/__init__.py")).unwrap();
|
||||
find_pyproject_toml(&cwd.join("resources/test/fixtures/__init__.py"))?.unwrap();
|
||||
assert_eq!(
|
||||
pyproject,
|
||||
cwd.join("resources/test/fixtures/pyproject.toml")
|
||||
|
|
|
|||
Loading…
Reference in New Issue