mirror of https://github.com/astral-sh/ruff
flake8_to_ruff: support `isort` options (#2082)
See: https://github.com/charliermarsh/ruff/issues/1749.
This commit is contained in:
parent
e11cf1bf65
commit
36fb8f7a63
|
|
@ -18,7 +18,7 @@ use std::path::PathBuf;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use configparser::ini::Ini;
|
use configparser::ini::Ini;
|
||||||
use ruff::flake8_to_ruff;
|
use ruff::flake8_to_ruff::{self, ExternalConfig};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(
|
#[command(
|
||||||
|
|
@ -48,14 +48,18 @@ fn main() -> Result<()> {
|
||||||
let config = ini.load(cli.file).map_err(|msg| anyhow::anyhow!(msg))?;
|
let config = ini.load(cli.file).map_err(|msg| anyhow::anyhow!(msg))?;
|
||||||
|
|
||||||
// Read the pyproject.toml file.
|
// Read the pyproject.toml file.
|
||||||
let black = cli
|
let pyproject = cli.pyproject.map(flake8_to_ruff::parse).transpose()?;
|
||||||
.pyproject
|
let external_config = pyproject
|
||||||
.map(flake8_to_ruff::parse_black_options)
|
.as_ref()
|
||||||
.transpose()?
|
.and_then(|pyproject| pyproject.tool.as_ref())
|
||||||
.flatten();
|
.map(|tool| ExternalConfig {
|
||||||
|
black: tool.black.as_ref(),
|
||||||
|
isort: tool.isort.as_ref(),
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
// Create Ruff's pyproject.toml section.
|
// Create Ruff's pyproject.toml section.
|
||||||
let pyproject = flake8_to_ruff::convert(&config, black.as_ref(), cli.plugin)?;
|
let pyproject = flake8_to_ruff::convert(&config, &external_config, cli.plugin)?;
|
||||||
println!("{}", toml_edit::easy::to_string_pretty(&pyproject)?);
|
println!("{}", toml_edit::easy::to_string_pretty(&pyproject)?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
//! Extract Black configuration settings from a pyproject.toml.
|
//! Extract Black configuration settings from a pyproject.toml.
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::settings::types::PythonVersion;
|
use crate::settings::types::PythonVersion;
|
||||||
|
|
@ -14,20 +11,3 @@ pub struct Black {
|
||||||
#[serde(alias = "target-version", alias = "target_version")]
|
#[serde(alias = "target-version", alias = "target_version")]
|
||||||
pub target_version: Option<Vec<PythonVersion>>,
|
pub target_version: Option<Vec<PythonVersion>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
struct Tools {
|
|
||||||
black: Option<Black>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
struct Pyproject {
|
|
||||||
tool: Option<Tools>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_black_options<P: AsRef<Path>>(path: P) -> Result<Option<Black>> {
|
|
||||||
let contents = std::fs::read_to_string(path)?;
|
|
||||||
Ok(toml_edit::easy::from_str::<Pyproject>(&contents)?
|
|
||||||
.tool
|
|
||||||
.and_then(|tool| tool.black))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::collections::{BTreeSet, HashMap};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
|
||||||
use super::black::Black;
|
use super::external_config::ExternalConfig;
|
||||||
use super::plugin::Plugin;
|
use super::plugin::Plugin;
|
||||||
use super::{parser, plugin};
|
use super::{parser, plugin};
|
||||||
use crate::registry::RuleSelector;
|
use crate::registry::RuleSelector;
|
||||||
|
|
@ -23,7 +23,7 @@ use crate::warn_user;
|
||||||
|
|
||||||
pub fn convert(
|
pub fn convert(
|
||||||
config: &HashMap<String, HashMap<String, Option<String>>>,
|
config: &HashMap<String, HashMap<String, Option<String>>>,
|
||||||
black: Option<&Black>,
|
external_config: &ExternalConfig,
|
||||||
plugins: Option<Vec<Plugin>>,
|
plugins: Option<Vec<Plugin>>,
|
||||||
) -> Result<Pyproject> {
|
) -> Result<Pyproject> {
|
||||||
// Extract the Flake8 section.
|
// Extract the Flake8 section.
|
||||||
|
|
@ -377,7 +377,7 @@ pub fn convert(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract any settings from the existing `pyproject.toml`.
|
// Extract any settings from the existing `pyproject.toml`.
|
||||||
if let Some(black) = black {
|
if let Some(black) = &external_config.black {
|
||||||
if let Some(line_length) = &black.line_length {
|
if let Some(line_length) = &black.line_length {
|
||||||
options.line_length = Some(*line_length);
|
options.line_length = Some(*line_length);
|
||||||
}
|
}
|
||||||
|
|
@ -389,6 +389,19 @@ pub fn convert(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(isort) = &external_config.isort {
|
||||||
|
if let Some(src_paths) = &isort.src_paths {
|
||||||
|
match options.src.as_mut() {
|
||||||
|
Some(src) => {
|
||||||
|
src.extend(src_paths.clone());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
options.src = Some(src_paths.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the pyproject.toml.
|
// Create the pyproject.toml.
|
||||||
Ok(Pyproject::new(options))
|
Ok(Pyproject::new(options))
|
||||||
}
|
}
|
||||||
|
|
@ -401,6 +414,7 @@ mod tests {
|
||||||
|
|
||||||
use super::super::plugin::Plugin;
|
use super::super::plugin::Plugin;
|
||||||
use super::convert;
|
use super::convert;
|
||||||
|
use crate::flake8_to_ruff::ExternalConfig;
|
||||||
use crate::registry::RuleSelector;
|
use crate::registry::RuleSelector;
|
||||||
use crate::rules::pydocstyle::settings::Convention;
|
use crate::rules::pydocstyle::settings::Convention;
|
||||||
use crate::rules::{flake8_quotes, pydocstyle};
|
use crate::rules::{flake8_quotes, pydocstyle};
|
||||||
|
|
@ -411,7 +425,7 @@ mod tests {
|
||||||
fn it_converts_empty() -> Result<()> {
|
fn it_converts_empty() -> Result<()> {
|
||||||
let actual = convert(
|
let actual = convert(
|
||||||
&HashMap::from([("flake8".to_string(), HashMap::default())]),
|
&HashMap::from([("flake8".to_string(), HashMap::default())]),
|
||||||
None,
|
&ExternalConfig::default(),
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
let expected = Pyproject::new(Options {
|
let expected = Pyproject::new(Options {
|
||||||
|
|
@ -475,7 +489,7 @@ mod tests {
|
||||||
"flake8".to_string(),
|
"flake8".to_string(),
|
||||||
HashMap::from([("max-line-length".to_string(), Some("100".to_string()))]),
|
HashMap::from([("max-line-length".to_string(), Some("100".to_string()))]),
|
||||||
)]),
|
)]),
|
||||||
None,
|
&ExternalConfig::default(),
|
||||||
Some(vec![]),
|
Some(vec![]),
|
||||||
)?;
|
)?;
|
||||||
let expected = Pyproject::new(Options {
|
let expected = Pyproject::new(Options {
|
||||||
|
|
@ -539,7 +553,7 @@ mod tests {
|
||||||
"flake8".to_string(),
|
"flake8".to_string(),
|
||||||
HashMap::from([("max_line_length".to_string(), Some("100".to_string()))]),
|
HashMap::from([("max_line_length".to_string(), Some("100".to_string()))]),
|
||||||
)]),
|
)]),
|
||||||
None,
|
&ExternalConfig::default(),
|
||||||
Some(vec![]),
|
Some(vec![]),
|
||||||
)?;
|
)?;
|
||||||
let expected = Pyproject::new(Options {
|
let expected = Pyproject::new(Options {
|
||||||
|
|
@ -603,7 +617,7 @@ mod tests {
|
||||||
"flake8".to_string(),
|
"flake8".to_string(),
|
||||||
HashMap::from([("max_line_length".to_string(), Some("abc".to_string()))]),
|
HashMap::from([("max_line_length".to_string(), Some("abc".to_string()))]),
|
||||||
)]),
|
)]),
|
||||||
None,
|
&ExternalConfig::default(),
|
||||||
Some(vec![]),
|
Some(vec![]),
|
||||||
)?;
|
)?;
|
||||||
let expected = Pyproject::new(Options {
|
let expected = Pyproject::new(Options {
|
||||||
|
|
@ -667,7 +681,7 @@ mod tests {
|
||||||
"flake8".to_string(),
|
"flake8".to_string(),
|
||||||
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
||||||
)]),
|
)]),
|
||||||
None,
|
&ExternalConfig::default(),
|
||||||
Some(vec![]),
|
Some(vec![]),
|
||||||
)?;
|
)?;
|
||||||
let expected = Pyproject::new(Options {
|
let expected = Pyproject::new(Options {
|
||||||
|
|
@ -739,7 +753,7 @@ mod tests {
|
||||||
Some("numpy".to_string()),
|
Some("numpy".to_string()),
|
||||||
)]),
|
)]),
|
||||||
)]),
|
)]),
|
||||||
None,
|
&ExternalConfig::default(),
|
||||||
Some(vec![Plugin::Flake8Docstrings]),
|
Some(vec![Plugin::Flake8Docstrings]),
|
||||||
)?;
|
)?;
|
||||||
let expected = Pyproject::new(Options {
|
let expected = Pyproject::new(Options {
|
||||||
|
|
@ -810,7 +824,7 @@ mod tests {
|
||||||
"flake8".to_string(),
|
"flake8".to_string(),
|
||||||
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
||||||
)]),
|
)]),
|
||||||
None,
|
&ExternalConfig::default(),
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
let expected = Pyproject::new(Options {
|
let expected = Pyproject::new(Options {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
use super::black::Black;
|
||||||
|
use super::isort::Isort;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ExternalConfig<'a> {
|
||||||
|
pub black: Option<&'a Black>,
|
||||||
|
pub isort: Option<&'a Isort>,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
//! Extract isort configuration settings from a pyproject.toml.
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// The [isort configuration](https://pycqa.github.io/isort/docs/configuration/config_files.html).
|
||||||
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||||
|
pub struct Isort {
|
||||||
|
#[serde(alias = "src-paths", alias = "src_paths")]
|
||||||
|
pub src_paths: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
mod black;
|
mod black;
|
||||||
mod converter;
|
mod converter;
|
||||||
|
mod external_config;
|
||||||
|
mod isort;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod plugin;
|
mod plugin;
|
||||||
|
mod pyproject;
|
||||||
|
|
||||||
pub use black::parse_black_options;
|
|
||||||
pub use converter::convert;
|
pub use converter::convert;
|
||||||
|
pub use external_config::ExternalConfig;
|
||||||
pub use plugin::Plugin;
|
pub use plugin::Plugin;
|
||||||
|
pub use pyproject::parse;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::black::Black;
|
||||||
|
use super::isort::Isort;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct Tools {
|
||||||
|
pub black: Option<Black>,
|
||||||
|
pub isort: Option<Isort>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct Pyproject {
|
||||||
|
pub tool: Option<Tools>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse<P: AsRef<Path>>(path: P) -> Result<Pyproject> {
|
||||||
|
let contents = std::fs::read_to_string(path)?;
|
||||||
|
let pyproject = toml_edit::easy::from_str::<Pyproject>(&contents)?;
|
||||||
|
Ok(pyproject)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue