Skip to content

Commit bd426ea

Browse files
committed
Harmonise methods for distinguishing different Python source types
1 parent fc661e1 commit bd426ea

File tree

11 files changed

+33
-60
lines changed

11 files changed

+33
-60
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/red_knot_server/src/session/index.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
33
use std::sync::Arc;
44

55
use lsp_types::Url;
6+
use ruff_python_ast::PySourceType;
67
use rustc_hash::FxHashMap;
78

89
use crate::{
@@ -72,10 +73,7 @@ impl Index {
7273
pub(crate) fn key_from_url(&self, url: Url) -> DocumentKey {
7374
if self.notebook_cells.contains_key(&url) {
7475
DocumentKey::NotebookCell(url)
75-
} else if Path::new(url.path())
76-
.extension()
77-
.map_or(false, |ext| ext.eq_ignore_ascii_case("ipynb"))
78-
{
76+
} else if PySourceType::from(url.path()).is_ipynb() {
7977
DocumentKey::Notebook(url)
8078
} else {
8179
DocumentKey::Text(url)

crates/ruff_dev/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ ruff_python_ast = { workspace = true }
2020
ruff_python_codegen = { workspace = true }
2121
ruff_python_formatter = { workspace = true }
2222
ruff_python_parser = { workspace = true }
23-
ruff_python_stdlib = { workspace = true }
2423
ruff_python_trivia = { workspace = true }
2524
ruff_workspace = { workspace = true, features = ["schemars"] }
2625

crates/ruff_dev/src/round_trip.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::path::PathBuf;
77
use anyhow::Result;
88

99
use ruff_python_codegen::round_trip;
10-
use ruff_python_stdlib::path::is_jupyter_notebook;
10+
use ruff_python_ast::PySourceType;
1111

1212
#[derive(clap::Args)]
1313
pub(crate) struct Args {
@@ -18,7 +18,7 @@ pub(crate) struct Args {
1818

1919
pub(crate) fn main(args: &Args) -> Result<()> {
2020
let path = args.file.as_path();
21-
if is_jupyter_notebook(path) {
21+
if PySourceType::from(path).is_ipynb() {
2222
println!("{}", ruff_notebook::round_trip(path)?);
2323
} else {
2424
let contents = fs::read_to_string(&args.file)?;

crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_module_shadowing.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::path::Path;
22

33
use ruff_diagnostics::{Diagnostic, Violation};
44
use ruff_macros::{derive_message_formats, violation};
5+
use ruff_python_ast::PySourceType;
56
use ruff_python_stdlib::path::is_module_file;
67
use ruff_python_stdlib::sys::is_known_standard_library;
78
use ruff_text_size::TextRange;
@@ -42,10 +43,10 @@ pub(crate) fn builtin_module_shadowing(
4243
allowed_modules: &[String],
4344
target_version: PythonVersion,
4445
) -> Option<Diagnostic> {
45-
if !path
46-
.extension()
47-
.is_some_and(|ext| ext == "py" || ext == "pyi")
48-
{
46+
if !matches!(
47+
PySourceType::try_from_path(path),
48+
Some(PySourceType::Python | PySourceType::Stub)
49+
) {
4950
return None;
5051
}
5152

crates/ruff_linter/src/rules/flake8_no_pep420/rules/implicit_namespace_package.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::path::{Path, PathBuf};
22

33
use ruff_diagnostics::{Diagnostic, Violation};
44
use ruff_macros::{derive_message_formats, violation};
5+
use ruff_python_ast::PySourceType;
56
use ruff_python_trivia::CommentRanges;
67
use ruff_source_file::Locator;
78
use ruff_text_size::{TextRange, TextSize};
@@ -51,7 +52,7 @@ pub(crate) fn implicit_namespace_package(
5152
) -> Option<Diagnostic> {
5253
if package.is_none()
5354
// Ignore non-`.py` files, which don't require an `__init__.py`.
54-
&& path.extension().is_some_and( |ext| ext == "py")
55+
&& PySourceType::try_from_path(path).is_some_and(|source_type|source_type.is_python())
5556
// Ignore any files that are direct children of the project root.
5657
&& !path
5758
.parent()

crates/ruff_linter/src/rules/pep8_naming/rules/invalid_module_name.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::path::Path;
33

44
use ruff_diagnostics::{Diagnostic, Violation};
55
use ruff_macros::{derive_message_formats, violation};
6+
use ruff_python_ast::PySourceType;
67
use ruff_python_stdlib::identifiers::{is_migration_name, is_module_name};
78
use ruff_python_stdlib::path::is_module_file;
89
use ruff_text_size::TextRange;
@@ -53,10 +54,10 @@ pub(crate) fn invalid_module_name(
5354
package: Option<&Path>,
5455
ignore_names: &IgnoreNames,
5556
) -> Option<Diagnostic> {
56-
if !path
57-
.extension()
58-
.is_some_and(|ext| ext == "py" || ext == "pyi")
59-
{
57+
if !matches!(
58+
PySourceType::try_from_path(path),
59+
Some(PySourceType::Python | PySourceType::Stub)
60+
) {
6061
return None;
6162
}
6263

crates/ruff_python_ast/src/lib.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,17 @@ impl PySourceType {
9999

100100
Some(ty)
101101
}
102-
}
103102

104-
impl<P: AsRef<Path>> From<P> for PySourceType {
105-
fn from(path: P) -> Self {
103+
pub fn try_from_path(path: impl AsRef<Path>) -> Option<Self> {
106104
path.as_ref()
107105
.extension()
108106
.and_then(OsStr::to_str)
109-
.map_or(Self::Python, Self::from_extension)
107+
.and_then(Self::try_from_extension)
108+
}
109+
}
110+
111+
impl<P: AsRef<Path>> From<P> for PySourceType {
112+
fn from(path: P) -> Self {
113+
Self::try_from_path(path).unwrap_or_default()
110114
}
111115
}

crates/ruff_python_semantic/src/model.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ use rustc_hash::FxHashMap;
55

66
use ruff_python_ast::helpers::from_relative_import;
77
use ruff_python_ast::name::{QualifiedName, UnqualifiedName};
8-
use ruff_python_ast::{self as ast, Expr, ExprContext, Operator, Stmt};
9-
use ruff_python_stdlib::path::is_python_stub_file;
8+
use ruff_python_ast::{self as ast, Expr, ExprContext, Operator, PySourceType, Stmt};
109
use ruff_text_size::{Ranged, TextRange, TextSize};
1110

1211
use crate::binding::{
@@ -2246,7 +2245,7 @@ bitflags! {
22462245

22472246
impl SemanticModelFlags {
22482247
pub fn new(path: &Path) -> Self {
2249-
if is_python_stub_file(path) {
2248+
if PySourceType::from(path).is_stub() {
22502249
Self::STUB_FILE
22512250
} else {
22522251
Self::default()
Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::ffi::OsStr;
12
use std::path::Path;
23

34
/// Return `true` if the [`Path`] is named `pyproject.toml`.
@@ -6,38 +7,10 @@ pub fn is_pyproject_toml(path: &Path) -> bool {
67
.is_some_and(|name| name == "pyproject.toml")
78
}
89

9-
/// Return `true` if the [`Path`] appears to be that of a Python interface definition file (`.pyi`).
10-
pub fn is_python_stub_file(path: &Path) -> bool {
11-
path.extension().is_some_and(|ext| ext == "pyi")
12-
}
13-
14-
/// Return `true` if the [`Path`] appears to be that of a Jupyter notebook (`.ipynb`).
15-
pub fn is_jupyter_notebook(path: &Path) -> bool {
16-
path.extension().is_some_and(|ext| ext == "ipynb")
17-
}
18-
1910
/// Return `true` if a [`Path`] should use the name of its parent directory as its module name.
2011
pub fn is_module_file(path: &Path) -> bool {
21-
path.file_name().is_some_and(|file_name| {
22-
file_name == "__init__.py"
23-
|| file_name == "__init__.pyi"
24-
|| file_name == "__main__.py"
25-
|| file_name == "__main__.pyi"
26-
})
27-
}
28-
29-
#[cfg(test)]
30-
mod tests {
31-
use std::path::Path;
32-
33-
use crate::path::is_jupyter_notebook;
34-
35-
#[test]
36-
fn test_is_jupyter_notebook() {
37-
let path = Path::new("foo/bar/baz.ipynb");
38-
assert!(is_jupyter_notebook(path));
39-
40-
let path = Path::new("foo/bar/baz.py");
41-
assert!(!is_jupyter_notebook(path));
42-
}
12+
matches!(
13+
path.file_name().and_then(OsStr::to_str),
14+
Some("__init__.py" | "__init__.pyi" | "__main__.py" | "__main__.pyi")
15+
)
4316
}

0 commit comments

Comments
 (0)