diff --git a/crates/ruff/tests/lint.rs b/crates/ruff/tests/lint.rs index b53f219351736..ff6a913ac4806 100644 --- a/crates/ruff/tests/lint.rs +++ b/crates/ruff/tests/lint.rs @@ -1804,3 +1804,127 @@ select = ["UP006"] Ok(()) } + +#[test] +fn checks_notebooks_in_preview_mode() -> anyhow::Result<()> { + let tempdir = TempDir::new()?; + std::fs::write( + tempdir.path().join("main.ipynb"), + r#" +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "ad6f36d9-4b7d-4562-8d00-f15a0f1fbb6d", + "metadata": {}, + "outputs": [], + "source": [ + "import random" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} +"#, + )?; + + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(STDIN_BASE_OPTIONS) + .arg("--select") + .arg("F401") + .arg("--preview") + .current_dir(&tempdir) + , @r###" + success: false + exit_code: 1 + ----- stdout ----- + main.ipynb:cell 1:1:8: F401 [*] `random` imported but unused + Found 1 error. + [*] 1 fixable with the `--fix` option. + + ----- stderr ----- + "###); + Ok(()) +} + +#[test] +fn ignores_notebooks_in_stable() -> anyhow::Result<()> { + let tempdir = TempDir::new()?; + std::fs::write( + tempdir.path().join("main.ipynb"), + r#" +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "ad6f36d9-4b7d-4562-8d00-f15a0f1fbb6d", + "metadata": {}, + "outputs": [], + "source": [ + "import random" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} +"#, + )?; + + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .args(STDIN_BASE_OPTIONS) + .arg("--select") + .arg("F401") + .current_dir(&tempdir) + , @r###" + success: true + exit_code: 0 + ----- stdout ----- + All checks passed! + + ----- stderr ----- + warning: No Python files found under the given path(s) + "###); + Ok(()) +} diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index e4d16310639c2..5f08d054cdbbb 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -230,9 +230,15 @@ impl Configuration { extend_exclude: FilePatternSet::try_from_iter(self.extend_exclude)?, extend_include: FilePatternSet::try_from_iter(self.extend_include)?, force_exclude: self.force_exclude.unwrap_or(false), - include: FilePatternSet::try_from_iter( - self.include.unwrap_or_else(|| INCLUDE.to_vec()), - )?, + include: FilePatternSet::try_from_iter(self.include.unwrap_or_else(|| { + let mut include = INCLUDE.to_vec(); + + if global_preview.is_enabled() { + include.push(FilePattern::Builtin("*.ipynb")); + } + + include + }))?, respect_gitignore: self.respect_gitignore.unwrap_or(true), project_root: project_root.to_path_buf(), }, diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 30ba34612b545..b0dbdd99f325c 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -241,6 +241,10 @@ pub struct Options { /// included here not for configuration but because we lint whether e.g. the /// `[project]` matches the schema. /// + /// If [preview](https://docs.astral.sh/ruff/preview/) is enabled, the default + /// includes notebook files (`.ipynb` extension). You can exclude them by adding + /// `*.ipynb` to [`extend-exclude`](#extend-exclude). + /// /// For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax). #[option( default = r#"["*.py", "*.pyi", "**/pyproject.toml"]"#, diff --git a/docs/configuration.md b/docs/configuration.md index 23acfdede9558..04acc43173024 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -380,6 +380,10 @@ You can also change the default selection using the [`include`](settings.md#incl Ruff has built-in support for [Jupyter Notebooks](https://jupyter.org/). +!!! info + Notebooks are linted and formatted by default when using [preview mode](preview). + You can opt-out of notebook linting and formatting by adding `*.ipynb` to [`extend-exclude`](settings.md#extend-exclude). + To opt in to linting and formatting Jupyter Notebook (`.ipynb`) files, add the `*.ipynb` pattern to your [`extend-include`](settings.md#extend-include) setting, like so: diff --git a/ruff.schema.json b/ruff.schema.json index daf012bc8f759..dca601da07fe5 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -444,7 +444,7 @@ ] }, "include": { - "description": "A list of file patterns to include when linting.\n\nInclusion are based on globs, and should be single-path patterns, like `*.pyw`, to include any file with the `.pyw` extension. `pyproject.toml` is included here not for configuration but because we lint whether e.g. the `[project]` matches the schema.\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).", + "description": "A list of file patterns to include when linting.\n\nInclusion are based on globs, and should be single-path patterns, like `*.pyw`, to include any file with the `.pyw` extension. `pyproject.toml` is included here not for configuration but because we lint whether e.g. the `[project]` matches the schema.\n\nIf [preview](https://docs.astral.sh/ruff/preview/) is enabled, the default includes notebook files (`.ipynb` extension). You can exclude them by adding `*.ipynb` to [`extend-exclude`](#extend-exclude).\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).", "type": [ "array", "null"