Skip to content
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

Detect imports in src layouts by default #12848

Merged
merged 1 commit into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 2 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -911,9 +911,5 @@ There are three ways in which an import can be categorized as "first-party":
the `src` setting and, for each directory, check for the existence of a subdirectory `foo` or a
file `foo.py`.
By default, `src` is set to the project root. In the above example, we'd want to set
`src = ["./src"]` to ensure that we locate `./my_project/src/foo` and thus categorize `import foo`
as first-party in `baz.py`. In practice, for this limited example, setting `src = ["./src"]` is
unnecessary, as all imports within `./my_project/src/foo` would be categorized as first-party via
the same-package heuristic; but if your project contains multiple packages, you'll want to set `src`
explicitly.
By default, `src` is set to the project root, along with `"src"` subdirectory in the project root.
This ensures that Ruff supports both flat and "src" layouts out of the box.
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ linter.logger_objects = []
linter.namespace_packages = []
linter.src = [
"[BASEPATH]",
"[BASEPATH]/src",
]
linter.tab_size = 4
linter.line_length = 88
Expand Down
2 changes: 1 addition & 1 deletion crates/ruff_linter/src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ impl LinterSettings {
per_file_ignores: CompiledPerFileIgnoreList::default(),
fix_safety: FixSafetyTable::default(),

src: vec![path_dedot::CWD.clone()],
src: vec![path_dedot::CWD.clone(), path_dedot::CWD.join("src")],
// Needs duplicating
tab_size: IndentWidth::default(),
line_length: LineLength::default(),
Expand Down
6 changes: 3 additions & 3 deletions crates/ruff_workspace/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ impl Configuration {
.chain(lint.extend_per_file_ignores)
.collect(),
)?,

fix_safety: FixSafetyTable::from_rule_selectors(
&lint.extend_safe_fixes,
&lint.extend_unsafe_fixes,
Expand All @@ -280,8 +279,9 @@ impl Configuration {
require_explicit: false,
},
),

src: self.src.unwrap_or_else(|| vec![project_root.to_path_buf()]),
src: self
.src
.unwrap_or_else(|| vec![project_root.to_path_buf(), project_root.join("src")]),
explicit_preview_rules: lint.explicit_preview_rules.unwrap_or_default(),

task_tags: lint
Expand Down
30 changes: 17 additions & 13 deletions crates/ruff_workspace/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,33 +323,37 @@ pub struct Options {
/// The directories to consider when resolving first- vs. third-party
/// imports.
///
/// As an example: given a Python package structure like:
/// When omitted, the `src` directory will typically default to including both:
///
/// 1. The directory containing the nearest `pyproject.toml`, `ruff.toml`, or `.ruff.toml` file (the "project root").
/// 2. The `"src"` subdirectory of the project root.
///
/// These defaults ensure that uv supports both flat layouts and `src` layouts out-of-the-box.
/// (If a configuration file is explicitly provided (e.g., via the `--config` command-line
/// flag), the current working directory will be considered the project root.)
///
/// As an example, consider an alternative project structure, like:
///
/// ```text
/// my_project
/// ├── pyproject.toml
/// └── src
/// └── lib
/// └── my_package
/// ├── __init__.py
/// ├── foo.py
/// └── bar.py
/// ```
///
/// The `./src` directory should be included in the `src` option
/// (e.g., `src = ["src"]`), such that when resolving imports,
/// `my_package.foo` is considered a first-party import.
///
/// When omitted, the `src` directory will typically default to the
/// directory containing the nearest `pyproject.toml`, `ruff.toml`, or
/// `.ruff.toml` file (the "project root"), unless a configuration file
/// is explicitly provided (e.g., via the `--config` command-line flag).
/// In this case, the `./lib` directory should be included in the `src` option
/// (e.g., `src = ["lib"]`), such that when resolving imports, `my_package.foo`
/// is considered first-party.
///
/// This field supports globs. For example, if you have a series of Python
/// packages in a `python_modules` directory, `src = ["python_modules/*"]`
/// would expand to incorporate all of the packages in that directory. User
/// home directory and environment variables will also be expanded.
/// would expand to incorporate all packages in that directory. User home
/// directory and environment variables will also be expanded.
#[option(
default = r#"["."]"#,
default = r#"[".", "src"]"#,
value_type = "list[str]",
example = r#"
# Allow imports relative to the "src" and "test" directories.
Expand Down
15 changes: 8 additions & 7 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,14 @@ When Ruff sees an import like `import foo`, it will then iterate over the `src`
looking for a corresponding Python module (in reality, a directory named `foo` or a file named
`foo.py`).

If the `src` field is omitted, Ruff will default to using the "project root" as the only
first-party source. The "project root" is typically the directory containing your `pyproject.toml`,
`ruff.toml`, or `.ruff.toml` file, unless a configuration file is provided on the command-line via
the `--config` option, in which case, the current working directory is used as the project root.

In this case, Ruff would only check the top-level directory. Instead, we can configure Ruff to
consider `src` as a first-party source like so:
If the `src` field is omitted, Ruff will default to using the "project root", along with a `"src"`
subdirectory, as the first-party sources, to support both flat and nested project layouts.
The "project root" is typically the directory containing your `pyproject.toml`, `ruff.toml`, or
`.ruff.toml` file, unless a configuration file is provided on the command-line via the `--config`
option, in which case, the current working directory is used as the project root.

In this case, Ruff would check the `"src"` directory by default, but we can configure it as an
explicit, exclusive first-party source like so:

=== "pyproject.toml"

Expand Down
2 changes: 1 addition & 1 deletion docs/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Alternatively, you can include `ruff-action` as a step in any other workflow fil

- `version`: The Ruff version to install (default: latest).
- `args`: The command-line arguments to pass to Ruff (default: `"check"`).
- `src`: The source paths to pass to Ruff (default: `"."`).
- `src`: The source paths to pass to Ruff (default: `[".", "src"]`).

For example, to run `ruff check --select B ./src` using Ruff version `0.0.259`:

Expand Down
2 changes: 1 addition & 1 deletion ruff.schema.json

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

Loading