Skip to content

Commit 73160dc

Browse files
dhruvmanilaAlexWaygood
authored andcommitted
Stabilize support for Jupyter Notebooks (#12878)
Co-authored-by: Alex Waygood <[email protected]> Closes: #12456 Closes: astral-sh/ruff-vscode#546
1 parent 15aa5a6 commit 73160dc

File tree

13 files changed

+68
-160
lines changed

13 files changed

+68
-160
lines changed

crates/ruff/src/commands/check.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,7 @@ mod test {
268268

269269
// Run
270270
let diagnostics = check(
271-
// Notebooks are not included by default
272-
&[tempdir.path().to_path_buf(), notebook],
271+
&[tempdir.path().to_path_buf()],
273272
&pyproject_config,
274273
&ConfigArguments::default(),
275274
flags::Cache::Disabled,

crates/ruff/tests/lint.rs

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,7 +1806,7 @@ select = ["UP006"]
18061806
}
18071807

18081808
#[test]
1809-
fn checks_notebooks_in_preview_mode() -> anyhow::Result<()> {
1809+
fn checks_notebooks_in_stable() -> anyhow::Result<()> {
18101810
let tempdir = TempDir::new()?;
18111811
std::fs::write(
18121812
tempdir.path().join("main.ipynb"),
@@ -1853,7 +1853,6 @@ fn checks_notebooks_in_preview_mode() -> anyhow::Result<()> {
18531853
.args(STDIN_BASE_OPTIONS)
18541854
.arg("--select")
18551855
.arg("F401")
1856-
.arg("--preview")
18571856
.current_dir(&tempdir)
18581857
, @r###"
18591858
success: false
@@ -1867,64 +1866,3 @@ fn checks_notebooks_in_preview_mode() -> anyhow::Result<()> {
18671866
"###);
18681867
Ok(())
18691868
}
1870-
1871-
#[test]
1872-
fn ignores_notebooks_in_stable() -> anyhow::Result<()> {
1873-
let tempdir = TempDir::new()?;
1874-
std::fs::write(
1875-
tempdir.path().join("main.ipynb"),
1876-
r#"
1877-
{
1878-
"cells": [
1879-
{
1880-
"cell_type": "code",
1881-
"execution_count": null,
1882-
"id": "ad6f36d9-4b7d-4562-8d00-f15a0f1fbb6d",
1883-
"metadata": {},
1884-
"outputs": [],
1885-
"source": [
1886-
"import random"
1887-
]
1888-
}
1889-
],
1890-
"metadata": {
1891-
"kernelspec": {
1892-
"display_name": "Python 3 (ipykernel)",
1893-
"language": "python",
1894-
"name": "python3"
1895-
},
1896-
"language_info": {
1897-
"codemirror_mode": {
1898-
"name": "ipython",
1899-
"version": 3
1900-
},
1901-
"file_extension": ".py",
1902-
"mimetype": "text/x-python",
1903-
"name": "python",
1904-
"nbconvert_exporter": "python",
1905-
"pygments_lexer": "ipython3",
1906-
"version": "3.12.0"
1907-
}
1908-
},
1909-
"nbformat": 4,
1910-
"nbformat_minor": 5
1911-
}
1912-
"#,
1913-
)?;
1914-
1915-
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
1916-
.args(STDIN_BASE_OPTIONS)
1917-
.arg("--select")
1918-
.arg("F401")
1919-
.current_dir(&tempdir)
1920-
, @r###"
1921-
success: true
1922-
exit_code: 0
1923-
----- stdout -----
1924-
All checks passed!
1925-
1926-
----- stderr -----
1927-
warning: No Python files found under the given path(s)
1928-
"###);
1929-
Ok(())
1930-
}

crates/ruff/tests/snapshots/show_settings__display_default_settings.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ file_resolver.force_exclude = false
6060
file_resolver.include = [
6161
"*.py",
6262
"*.pyi",
63+
"*.ipynb",
6364
"**/pyproject.toml",
6465
]
6566
file_resolver.extend_include = []

crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_comparison.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ use super::super::helpers::at_last_top_level_expression_in_cell;
2525
/// assert foo == bar, "`foo` and `bar` should be equal."
2626
/// ```
2727
///
28+
/// ## Notebook behavior
29+
/// For Jupyter Notebooks, this rule is not applied to the last top-level expression in a cell.
30+
/// This is because it's common to have a notebook cell that ends with an expression,
31+
/// which will result in the `repr` of the evaluated expression being printed as the cell's output.
32+
///
2833
/// ## References
2934
/// - [Python documentation: `assert` statement](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement)
3035
#[violation]
@@ -43,9 +48,6 @@ impl Violation for UselessComparison {
4348
/// B015
4449
pub(crate) fn useless_comparison(checker: &mut Checker, expr: &Expr) {
4550
if expr.is_compare_expr() {
46-
// For Jupyter Notebooks, ignore the last top-level expression for each cell.
47-
// This is because it's common to have a cell that ends with an expression
48-
// to display it's value.
4951
if checker.source_type.is_ipynb()
5052
&& at_last_top_level_expression_in_cell(
5153
checker.semantic(),

crates/ruff_linter/src/rules/flake8_bugbear/rules/useless_expression.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ use super::super::helpers::at_last_top_level_expression_in_cell;
2626
/// foo = 1 + 1
2727
/// ```
2828
///
29+
/// ## Notebook behavior
30+
/// For Jupyter Notebooks, this rule is not applied to the last top-level expression in a cell.
31+
/// This is because it's common to have a notebook cell that ends with an expression,
32+
/// which will result in the `repr` of the evaluated expression being printed as the cell's output.
33+
///
2934
/// ## Known problems
3035
/// This rule ignores expression types that are commonly used for their side
3136
/// effects, such as function calls.
@@ -81,9 +86,6 @@ pub(crate) fn useless_expression(checker: &mut Checker, value: &Expr) {
8186
return;
8287
}
8388

84-
// For Jupyter Notebooks, ignore the last top-level expression for each cell.
85-
// This is because it's common to have a cell that ends with an expression
86-
// to display it's value.
8789
if checker.source_type.is_ipynb()
8890
&& at_last_top_level_expression_in_cell(
8991
checker.semantic(),

crates/ruff_linter/src/rules/pycodestyle/rules/module_import_not_at_top_of_file.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ use ruff_text_size::Ranged;
66
use crate::checkers::ast::Checker;
77

88
/// ## What it does
9-
/// Checks for imports that are not at the top of the file. For Jupyter notebooks, this
10-
/// checks for imports that are not at the top of the cell.
9+
/// Checks for imports that are not at the top of the file.
1110
///
1211
/// ## Why is this bad?
1312
/// According to [PEP 8], "imports are always put at the top of the file, just after any
@@ -36,6 +35,9 @@ use crate::checkers::ast::Checker;
3635
/// a = 1
3736
/// ```
3837
///
38+
/// ## Notebook behavior
39+
/// For Jupyter notebooks, this rule checks for imports that are not at the top of a *cell*.
40+
///
3941
/// [PEP 8]: https://peps.python.org/pep-0008/#imports
4042
#[violation]
4143
pub struct ModuleImportNotAtTopOfFile {

crates/ruff_linter/src/rules/pydocstyle/rules/not_missing.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ use crate::registry::Rule;
5353
/// def calculate_speed(distance: float, time: float) -> float: ...
5454
/// ```
5555
///
56+
/// ## Notebook behavior
57+
/// This rule is ignored for Jupyter Notebooks.
58+
///
5659
/// ## References
5760
/// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/)
5861
/// - [PEP 287 – reStructuredText Docstring Format](https://peps.python.org/pep-0287/)

crates/ruff_workspace/src/configuration.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,9 @@ impl Configuration {
230230
extend_exclude: FilePatternSet::try_from_iter(self.extend_exclude)?,
231231
extend_include: FilePatternSet::try_from_iter(self.extend_include)?,
232232
force_exclude: self.force_exclude.unwrap_or(false),
233-
include: FilePatternSet::try_from_iter(self.include.unwrap_or_else(|| {
234-
let mut include = INCLUDE.to_vec();
235-
236-
if global_preview.is_enabled() {
237-
include.push(FilePattern::Builtin("*.ipynb"));
238-
}
239-
240-
include
241-
}))?,
233+
include: FilePatternSet::try_from_iter(
234+
self.include.unwrap_or_else(|| INCLUDE.to_vec()),
235+
)?,
242236
respect_gitignore: self.respect_gitignore.unwrap_or(true),
243237
project_root: project_root.to_path_buf(),
244238
},

crates/ruff_workspace/src/options.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,11 @@ pub struct Options {
241241
/// included here not for configuration but because we lint whether e.g. the
242242
/// `[project]` matches the schema.
243243
///
244-
/// If [preview](https://docs.astral.sh/ruff/preview/) is enabled, the default
245-
/// includes notebook files (`.ipynb` extension). You can exclude them by adding
246-
/// `*.ipynb` to [`extend-exclude`](#extend-exclude).
244+
/// Notebook files (`.ipynb` extension) are included by default on Ruff 0.6.0+.
247245
///
248246
/// For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).
249247
#[option(
250-
default = r#"["*.py", "*.pyi", "**/pyproject.toml"]"#,
248+
default = r#"["*.py", "*.pyi", "*.ipynb", "**/pyproject.toml"]"#,
251249
value_type = "list[str]",
252250
example = r#"
253251
include = ["*.py"]

crates/ruff_workspace/src/settings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ pub(crate) static EXCLUDE: &[FilePattern] = &[
137137
pub(crate) static INCLUDE: &[FilePattern] = &[
138138
FilePattern::Builtin("*.py"),
139139
FilePattern::Builtin("*.pyi"),
140+
FilePattern::Builtin("*.ipynb"),
140141
FilePattern::Builtin("**/pyproject.toml"),
141142
];
142143

0 commit comments

Comments
 (0)