Skip to content

Commit 9a70f5e

Browse files
authored
Discover markdown files by default in preview mode (#23434)
Adds `*.md` to the list of default globs in preview mode. Adds a simple filter to the `check` CLI command to exclude file types that aren't supported for linting before checking if the set of resolved paths is empty, preserving existing behavior of warning "No Python files found under the given path(s)" even if there are markdown files present and preview mode is enabled. Fixes #3792
1 parent 3dc78b0 commit 9a70f5e

File tree

14 files changed

+98
-87
lines changed

14 files changed

+98
-87
lines changed

crates/ruff/src/commands/add_noqa.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use ruff_linter::source_kind::SourceKind;
1111
use ruff_linter::warn_user_once;
1212
use ruff_python_ast::{PySourceType, SourceType};
1313
use ruff_workspace::resolver::{
14-
PyprojectConfig, ResolvedFile, match_exclusion, python_files_in_path,
14+
PyprojectConfig, ResolvedFile, match_exclusion, project_files_in_path,
1515
};
1616

1717
use crate::args::ConfigArguments;
@@ -25,10 +25,22 @@ pub(crate) fn add_noqa(
2525
) -> Result<usize> {
2626
// Collect all the files to check.
2727
let start = Instant::now();
28-
let (paths, resolver) = python_files_in_path(files, pyproject_config, config_arguments)?;
28+
let (mut paths, resolver) = project_files_in_path(files, pyproject_config, config_arguments)?;
2929
let duration = start.elapsed();
3030
debug!("Identified files to lint in: {duration:?}");
3131

32+
// Filter out paths for file types not supported for linting
33+
paths.retain(|path| {
34+
if let Ok(ResolvedFile::Root(path) | ResolvedFile::Nested(path)) = path {
35+
matches!(
36+
SourceType::from(path),
37+
SourceType::Python(PySourceType::Python | PySourceType::Stub)
38+
)
39+
} else {
40+
true
41+
}
42+
});
43+
3244
if paths.is_empty() {
3345
warn_user_once!("No Python files found under the given path(s)");
3446
return Ok(0);
@@ -48,11 +60,7 @@ pub(crate) fn add_noqa(
4860
.par_iter()
4961
.flatten()
5062
.filter_map(|resolved_file| {
51-
let SourceType::Python(source_type @ (PySourceType::Python | PySourceType::Stub)) =
52-
SourceType::from(resolved_file.path())
53-
else {
54-
return None;
55-
};
63+
let source_type = SourceType::from(resolved_file.path());
5664
let path = resolved_file.path();
5765
let package = resolved_file
5866
.path()
@@ -69,7 +77,7 @@ pub(crate) fn add_noqa(
6977
{
7078
return None;
7179
}
72-
let source_kind = match SourceKind::from_path(path, SourceType::Python(source_type)) {
80+
let source_kind = match SourceKind::from_path(path, source_type) {
7381
Ok(Some(source_kind)) => source_kind,
7482
Ok(None) => return None,
7583
Err(e) => {
@@ -81,7 +89,7 @@ pub(crate) fn add_noqa(
8189
path,
8290
package,
8391
&source_kind,
84-
source_type,
92+
source_type.expect_python(),
8593
&settings.linter,
8694
reason,
8795
) {

crates/ruff/src/commands/analyze_graph.rs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use ruff_linter::package::PackageRoot;
1111
use ruff_linter::source_kind::SourceKind;
1212
use ruff_linter::{warn_user, warn_user_once};
1313
use ruff_python_ast::SourceType;
14-
use ruff_workspace::resolver::{ResolvedFile, match_exclusion, python_files_in_path};
14+
use ruff_workspace::resolver::{ResolvedFile, match_exclusion, project_files_in_path};
1515
use rustc_hash::{FxBuildHasher, FxHashMap};
1616
use std::io::Write;
1717
use std::path::{Path, PathBuf};
@@ -35,7 +35,16 @@ pub(crate) fn analyze_graph(
3535

3636
// Find all Python files.
3737
let files = resolve_default_files(args.files, false);
38-
let (paths, resolver) = python_files_in_path(&files, &pyproject_config, config_arguments)?;
38+
let (mut paths, resolver) = project_files_in_path(&files, &pyproject_config, config_arguments)?;
39+
40+
// Filter to only Python files
41+
paths.retain(|path| {
42+
if let Ok(ResolvedFile::Root(path) | ResolvedFile::Nested(path)) = path {
43+
matches!(SourceType::from(path), SourceType::Python(_))
44+
} else {
45+
true
46+
}
47+
});
3948

4049
if paths.is_empty() {
4150
warn_user_once!("No Python files found under the given path(s)");
@@ -124,6 +133,7 @@ pub(crate) fn analyze_graph(
124133
let string_imports = settings.analyze.string_imports;
125134
let include_dependencies = settings.analyze.include_dependencies.get(path).cloned();
126135
let type_checking_imports = settings.analyze.type_checking_imports;
136+
let source_type = settings.analyze.extension.get_source_type(path);
127137

128138
// Skip excluded files.
129139
if (settings.file_resolver.force_exclude || !resolved_file.is_root())
@@ -136,19 +146,6 @@ pub(crate) fn analyze_graph(
136146
continue;
137147
}
138148

139-
// Ignore non-Python files.
140-
let source_type = match settings.analyze.extension.get_source_type(path) {
141-
SourceType::Python(source_type) => source_type,
142-
SourceType::Toml(_) => {
143-
debug!("Ignoring TOML file: {}", path.display());
144-
continue;
145-
}
146-
SourceType::Markdown => {
147-
debug!("Ignoring Markdown file: {}", path.display());
148-
continue;
149-
}
150-
};
151-
152149
// Convert to system paths.
153150
let Ok(package) = package.map(SystemPathBuf::from_path_buf).transpose() else {
154151
warn!("Failed to convert package to system path");
@@ -165,10 +162,7 @@ pub(crate) fn analyze_graph(
165162
let result = inner_result.clone();
166163
scope.spawn(move |_| {
167164
// Extract source code (handles both .py and .ipynb files)
168-
let source_kind = match SourceKind::from_path(
169-
path.as_std_path(),
170-
SourceType::Python(source_type),
171-
) {
165+
let source_kind = match SourceKind::from_path(path.as_std_path(), source_type) {
172166
Ok(Some(source_kind)) => source_kind,
173167
Ok(None) => {
174168
debug!("Skipping non-Python notebook: {path}");
@@ -186,7 +180,7 @@ pub(crate) fn analyze_graph(
186180
let mut imports = ModuleImports::detect(
187181
&db,
188182
source_code,
189-
source_type,
183+
source_type.expect_python(),
190184
&path,
191185
package.as_deref(),
192186
string_imports,

crates/ruff/src/commands/check.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use log::{debug, warn};
1010
#[cfg(not(target_family = "wasm"))]
1111
use rayon::prelude::*;
1212
use ruff_linter::message::create_panic_diagnostic;
13+
use ruff_python_ast::{SourceType, TomlSourceType};
1314
use rustc_hash::FxHashMap;
1415

1516
use ruff_db::diagnostic::Diagnostic;
@@ -22,7 +23,7 @@ use ruff_linter::{IOError, Violation, fs, warn_user_once};
2223
use ruff_source_file::SourceFileBuilder;
2324
use ruff_text_size::TextRange;
2425
use ruff_workspace::resolver::{
25-
PyprojectConfig, ResolvedFile, match_exclusion, python_files_in_path,
26+
PyprojectConfig, ResolvedFile, match_exclusion, project_files_in_path,
2627
};
2728

2829
use crate::args::ConfigArguments;
@@ -41,9 +42,21 @@ pub(crate) fn check(
4142
) -> Result<Diagnostics> {
4243
// Collect all the Python files to check.
4344
let start = Instant::now();
44-
let (paths, resolver) = python_files_in_path(files, pyproject_config, config_arguments)?;
45+
let (mut paths, resolver) = project_files_in_path(files, pyproject_config, config_arguments)?;
4546
debug!("Identified files to lint in: {:?}", start.elapsed());
4647

48+
// Filter out paths for file types not supported for linting
49+
paths.retain(|path| {
50+
if let Ok(ResolvedFile::Root(path) | ResolvedFile::Nested(path)) = path {
51+
matches!(
52+
SourceType::from(path),
53+
SourceType::Python(_) | SourceType::Toml(TomlSourceType::Pyproject)
54+
)
55+
} else {
56+
true
57+
}
58+
});
59+
4760
if paths.is_empty() {
4861
warn_user_once!("No Python files found under the given path(s)");
4962
return Ok(Diagnostics::default());

crates/ruff/src/commands/check_stdin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use ruff_db::diagnostic::Diagnostic;
55
use ruff_linter::package::PackageRoot;
66
use ruff_linter::packaging;
77
use ruff_linter::settings::flags;
8-
use ruff_workspace::resolver::{PyprojectConfig, Resolver, match_exclusion, python_file_at_path};
8+
use ruff_workspace::resolver::{PyprojectConfig, Resolver, match_exclusion, project_file_at_path};
99

1010
use crate::args::ConfigArguments;
1111
use crate::diagnostics::{Diagnostics, lint_stdin};
@@ -23,7 +23,7 @@ pub(crate) fn check_stdin(
2323

2424
if resolver.force_exclude() {
2525
if let Some(filename) = filename {
26-
if !python_file_at_path(filename, &mut resolver, overrides)? {
26+
if !project_file_at_path(filename, &mut resolver, overrides)? {
2727
if fix_mode.is_apply() {
2828
parrot_stdin()?;
2929
}

crates/ruff/src/commands/format.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use ruff_source_file::{LineIndex, LineRanges, OneIndexed, SourceFileBuilder};
3838
use ruff_text_size::{TextLen, TextRange, TextSize};
3939
use ruff_workspace::FormatterSettings;
4040
use ruff_workspace::resolver::{
41-
PyprojectConfig, ResolvedFile, Resolver, match_exclusion, python_files_in_path,
41+
PyprojectConfig, ResolvedFile, Resolver, match_exclusion, project_files_in_path,
4242
};
4343

4444
use crate::args::{ConfigArguments, FormatArguments, FormatRange};
@@ -75,7 +75,7 @@ pub(crate) fn format(
7575
) -> Result<ExitStatus> {
7676
let mode = FormatMode::from_cli(&cli);
7777
let files = resolve_default_files(cli.files, false);
78-
let (paths, resolver) = python_files_in_path(&files, pyproject_config, config_arguments)?;
78+
let (paths, resolver) = project_files_in_path(&files, pyproject_config, config_arguments)?;
7979

8080
let output_format = pyproject_config.settings.output_format;
8181
let preview = pyproject_config.settings.formatter.preview;

crates/ruff/src/commands/format_stdin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use log::error;
77
use ruff_linter::source_kind::{SourceError, SourceKind};
88
use ruff_python_ast::SourceType;
99
use ruff_workspace::FormatterSettings;
10-
use ruff_workspace::resolver::{PyprojectConfig, Resolver, match_exclusion, python_file_at_path};
10+
use ruff_workspace::resolver::{PyprojectConfig, Resolver, match_exclusion, project_file_at_path};
1111

1212
use crate::ExitStatus;
1313
use crate::args::{ConfigArguments, FormatArguments, FormatRange};
@@ -30,7 +30,7 @@ pub(crate) fn format_stdin(
3030

3131
if resolver.force_exclude() {
3232
if let Some(filename) = cli.stdin_filename.as_deref() {
33-
if !python_file_at_path(filename, &mut resolver, config_arguments)? {
33+
if !project_file_at_path(filename, &mut resolver, config_arguments)? {
3434
if mode.is_write() {
3535
parrot_stdin()?;
3636
}

crates/ruff/src/commands/show_files.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use anyhow::Result;
55
use itertools::Itertools;
66

77
use ruff_linter::warn_user_once;
8-
use ruff_workspace::resolver::{PyprojectConfig, ResolvedFile, python_files_in_path};
8+
use ruff_python_ast::{SourceType, TomlSourceType};
9+
use ruff_workspace::resolver::{PyprojectConfig, ResolvedFile, project_files_in_path};
910

1011
use crate::args::ConfigArguments;
1112

@@ -17,7 +18,19 @@ pub(crate) fn show_files(
1718
writer: &mut impl Write,
1819
) -> Result<()> {
1920
// Collect all files in the hierarchy.
20-
let (paths, _resolver) = python_files_in_path(files, pyproject_config, config_arguments)?;
21+
let (mut paths, _resolver) = project_files_in_path(files, pyproject_config, config_arguments)?;
22+
23+
// Filter out paths for file types not supported for linting
24+
paths.retain(|path| {
25+
if let Ok(ResolvedFile::Root(path) | ResolvedFile::Nested(path)) = path {
26+
matches!(
27+
SourceType::from(path),
28+
SourceType::Python(_) | SourceType::Toml(TomlSourceType::Pyproject)
29+
)
30+
} else {
31+
true
32+
}
33+
});
2134

2235
if paths.is_empty() {
2336
warn_user_once!("No Python files found under the given path(s)");

crates/ruff/src/commands/show_settings.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::path::PathBuf;
44
use anyhow::{Result, bail};
55
use itertools::Itertools;
66

7-
use ruff_workspace::resolver::{PyprojectConfig, ResolvedFile, python_files_in_path};
7+
use ruff_workspace::resolver::{PyprojectConfig, ResolvedFile, project_files_in_path};
88

99
use crate::args::ConfigArguments;
1010

@@ -16,7 +16,7 @@ pub(crate) fn show_settings(
1616
writer: &mut impl Write,
1717
) -> Result<()> {
1818
// Collect all files in the hierarchy.
19-
let (paths, resolver) = python_files_in_path(files, pyproject_config, config_arguments)?;
19+
let (paths, resolver) = project_files_in_path(files, pyproject_config, config_arguments)?;
2020

2121
// Print the list of files.
2222
let Some(path) = paths

crates/ruff/tests/cli/snapshots/cli__lint__requires_python_no_tool_preview_enabled.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ file_resolver.include = [
6363
"*.pyw",
6464
"*.ipynb",
6565
"**/pyproject.toml",
66+
"*.md",
6667
]
6768
file_resolver.extend_include = []
6869
file_resolver.respect_gitignore = true

crates/ruff_dev/src/format_dev.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use ruff_python_formatter::{
3636
FormatModuleError, MagicTrailingComma, PreviewMode, PyFormatOptions, format_module_source,
3737
};
3838
use ruff_python_parser::ParseError;
39-
use ruff_workspace::resolver::{PyprojectConfig, ResolvedFile, Resolver, python_files_in_path};
39+
use ruff_workspace::resolver::{PyprojectConfig, ResolvedFile, Resolver, project_files_in_path};
4040

4141
fn parse_cli(dirs: &[PathBuf]) -> anyhow::Result<(FormatArguments, ConfigArguments)> {
4242
let args_matches = FormatCommand::command()
@@ -68,7 +68,7 @@ fn ruff_check_paths<'a>(
6868
cli: &FormatArguments,
6969
config_arguments: &ConfigArguments,
7070
) -> anyhow::Result<(Vec<Result<ResolvedFile, ignore::Error>>, Resolver<'a>)> {
71-
let (paths, resolver) = python_files_in_path(&cli.files, pyproject_config, config_arguments)?;
71+
let (paths, resolver) = project_files_in_path(&cli.files, pyproject_config, config_arguments)?;
7272
Ok((paths, resolver))
7373
}
7474

0 commit comments

Comments
 (0)