From bf9e670838e92768dc6866423bfe20f7c02b38cc Mon Sep 17 00:00:00 2001 From: Amethyst Reese Date: Tue, 17 Feb 2026 14:20:49 -0800 Subject: [PATCH 1/5] Add extension mapping to configuration file options Issue #23204 --- crates/ruff_workspace/src/configuration.rs | 12 +++++------- crates/ruff_workspace/src/options.rs | 16 +++++++++++++++- ruff.schema.json | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index 5c204b3a0078ce..ca1e881448b902 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -7,6 +7,7 @@ use std::collections::BTreeMap; use std::env::VarError; use std::num::{NonZeroU8, NonZeroU16}; use std::path::{Path, PathBuf}; +use std::str::FromStr; use anyhow::{Context, Result, anyhow}; use glob::{GlobError, Paths, PatternError, glob}; @@ -28,9 +29,9 @@ use ruff_linter::rules::{flake8_import_conventions, isort, pycodestyle}; use ruff_linter::settings::fix_safety_table::FixSafetyTable; use ruff_linter::settings::rule_table::RuleTable; use ruff_linter::settings::types::{ - CompiledPerFileIgnoreList, CompiledPerFileTargetVersionList, ExtensionMapping, FilePattern, - FilePatternSet, GlobPath, OutputFormat, PerFileIgnore, PerFileTargetVersion, PreviewMode, - RequiredVersion, UnsafeFixes, + CompiledPerFileIgnoreList, CompiledPerFileTargetVersionList, ExtensionMapping, ExtensionPair, + FilePattern, FilePatternSet, GlobPath, Language, OutputFormat, PerFileIgnore, + PerFileTargetVersion, PreviewMode, RequiredVersion, UnsafeFixes, }; use ruff_linter::settings::{ DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX, LinterSettings, TASK_TAGS, TargetVersion, @@ -564,10 +565,7 @@ impl Configuration { }) .collect() }), - // `--extension` is a hidden command-line argument that isn't supported in configuration - // files at present. - extension: None, - + extension: options.extension.map(ExtensionMapping::from), lint: LintConfiguration::from_options(lint, project_root)?, format: FormatConfiguration::from_options( options.format.unwrap_or_default(), diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 07011ad66026c4..9746b4d34d962e 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -32,7 +32,7 @@ use ruff_linter::rules::{ pycodestyle, pydoclint, pydocstyle, pyflakes, pylint, pyupgrade, ruff, }; use ruff_linter::settings::types::{ - IdentifierPattern, OutputFormat, PythonVersion, RequiredVersion, + IdentifierPattern, Language, OutputFormat, PythonVersion, RequiredVersion, }; use ruff_linter::{RuleSelector, warn_user_once}; use ruff_macros::{CombineOptions, OptionsMetadata}; @@ -282,6 +282,20 @@ pub struct Options { )] pub respect_gitignore: Option, + /// A mapping of custom file extensions to known file types (overridden + /// by the `--extension` command-line flag). + /// + /// Supported file types include `python`, `pyi`, `ipynb`, and `markdown`. + #[option( + default = "{}", + value_type = "dict[str, str]", + example = r#" + # Add a custom file extension mapped to Python + extension = {"rpy"="python"} + "# + )] + pub extension: Option>, + // Generic python options /// A list of builtins to treat as defined references, in addition to the /// system builtins. diff --git a/ruff.schema.json b/ruff.schema.json index 1de42c71a9ba7e..bf49bd3520ad17 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -177,6 +177,16 @@ "$ref": "#/definitions/RuleSelector" } }, + "extension-mapping": { + "description": "A mapping of custom file extensions to known file extensions", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "$ref": "#/definitions/Language" + } + }, "external": { "description": "A list of rule codes or prefixes that are unsupported by Ruff, but should be\npreserved when (e.g.) validating `# noqa` directives. Useful for\nretaining `# noqa` directives that cover plugins not yet implemented\nby Ruff.", "type": [ @@ -1976,6 +1986,15 @@ }, "additionalProperties": false }, + "Language": { + "type": "string", + "enum": [ + "python", + "pyi", + "ipynb", + "markdown" + ] + }, "LineEnding": { "oneOf": [ { From 5d5c35ad4672fc5eb5055a4aaaa0db803ea1c439 Mon Sep 17 00:00:00 2001 From: Amethyst Reese Date: Tue, 17 Feb 2026 16:57:01 -0800 Subject: [PATCH 2/5] clippy --- crates/ruff_workspace/src/configuration.rs | 7 +++---- ruff.schema.json | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index ca1e881448b902..59c9be0efe760e 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -7,7 +7,6 @@ use std::collections::BTreeMap; use std::env::VarError; use std::num::{NonZeroU8, NonZeroU16}; use std::path::{Path, PathBuf}; -use std::str::FromStr; use anyhow::{Context, Result, anyhow}; use glob::{GlobError, Paths, PatternError, glob}; @@ -29,9 +28,9 @@ use ruff_linter::rules::{flake8_import_conventions, isort, pycodestyle}; use ruff_linter::settings::fix_safety_table::FixSafetyTable; use ruff_linter::settings::rule_table::RuleTable; use ruff_linter::settings::types::{ - CompiledPerFileIgnoreList, CompiledPerFileTargetVersionList, ExtensionMapping, ExtensionPair, - FilePattern, FilePatternSet, GlobPath, Language, OutputFormat, PerFileIgnore, - PerFileTargetVersion, PreviewMode, RequiredVersion, UnsafeFixes, + CompiledPerFileIgnoreList, CompiledPerFileTargetVersionList, ExtensionMapping, FilePattern, + FilePatternSet, GlobPath, OutputFormat, PerFileIgnore, PerFileTargetVersion, PreviewMode, + RequiredVersion, UnsafeFixes, }; use ruff_linter::settings::{ DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX, LinterSettings, TASK_TAGS, TargetVersion, diff --git a/ruff.schema.json b/ruff.schema.json index bf49bd3520ad17..8d95d780644f4b 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -177,8 +177,8 @@ "$ref": "#/definitions/RuleSelector" } }, - "extension-mapping": { - "description": "A mapping of custom file extensions to known file extensions", + "extension": { + "description": "A mapping of custom file extensions to known file types (overridden\nby the `--extension` command-line flag).\n\nSupported file types include `python`, `pyi`, `ipynb`, and `markdown`.", "type": [ "object", "null" From cb2aeefc3a3023c4f9ff06694f1e21a58824c65e Mon Sep 17 00:00:00 2001 From: Amethyst Reese Date: Tue, 17 Feb 2026 17:21:51 -0800 Subject: [PATCH 3/5] better doc type info --- crates/ruff_workspace/src/options.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 9746b4d34d962e..9a5e507ea50e46 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -288,7 +288,7 @@ pub struct Options { /// Supported file types include `python`, `pyi`, `ipynb`, and `markdown`. #[option( default = "{}", - value_type = "dict[str, str]", + value_type = "dict[str, Language]", example = r#" # Add a custom file extension mapped to Python extension = {"rpy"="python"} From 3dcf4347e8086a04b779f02656f324207ff141ac Mon Sep 17 00:00:00 2001 From: Amethyst Reese Date: Tue, 17 Feb 2026 17:22:01 -0800 Subject: [PATCH 4/5] integration test --- crates/ruff/tests/integration_test.rs | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/crates/ruff/tests/integration_test.rs b/crates/ruff/tests/integration_test.rs index 81490045657706..36ea362eebdaff 100644 --- a/crates/ruff/tests/integration_test.rs +++ b/crates/ruff/tests/integration_test.rs @@ -629,6 +629,42 @@ fn stdin_override_parser_py() { "); } +#[test] +fn stdin_override_parser_py_config() -> Result<()> { + let tempdir = TempDir::new()?; + let pyproject_toml = tempdir.path().join("pyproject.toml"); + fs::write( + &pyproject_toml, + r#" +[tool.ruff] +extension = {"ipynb"="python"} +"#, + )?; + let mut cmd = RuffCheck::default() + .config(&pyproject_toml) + .args(["--stdin-filename", "F401.ipynb"]) + .build(); + assert_cmd_snapshot!(cmd + .pass_stdin("import os\n"), @" + success: false + exit_code: 1 + ----- stdout ----- + F401 [*] `os` imported but unused + --> F401.ipynb:1:8 + | + 1 | import os + | ^^ + | + help: Remove unused import: `os` + + Found 1 error. + [*] 1 fixable with the `--fix` option. + + ----- stderr ----- + "); + Ok(()) +} + #[test] fn stdin_fix_when_not_fixable_should_still_print_contents() { let mut cmd = RuffCheck::default().args(["--fix"]).build(); From 9e195ff2a6ff82758f57e99e842edc39fd8dc729 Mon Sep 17 00:00:00 2001 From: Amethyst Reese Date: Wed, 18 Feb 2026 10:11:02 -0800 Subject: [PATCH 5/5] toml style --- crates/ruff/tests/integration_test.rs | 2 +- crates/ruff_workspace/src/options.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ruff/tests/integration_test.rs b/crates/ruff/tests/integration_test.rs index 36ea362eebdaff..380974918f70e4 100644 --- a/crates/ruff/tests/integration_test.rs +++ b/crates/ruff/tests/integration_test.rs @@ -637,7 +637,7 @@ fn stdin_override_parser_py_config() -> Result<()> { &pyproject_toml, r#" [tool.ruff] -extension = {"ipynb"="python"} +extension = {ipynb="python"} "#, )?; let mut cmd = RuffCheck::default() diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 9a5e507ea50e46..78e35073a1d043 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -291,7 +291,7 @@ pub struct Options { value_type = "dict[str, Language]", example = r#" # Add a custom file extension mapped to Python - extension = {"rpy"="python"} + extension = {rpy="python"} "# )] pub extension: Option>,