flake8_to_ruff: support `isort` options (#2082)

See: https://github.com/charliermarsh/ruff/issues/1749.
This commit is contained in:
Shannon Rothe 2023-01-23 05:18:01 +11:00 committed by GitHub
parent e11cf1bf65
commit 36fb8f7a63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 38 deletions

View File

@ -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(())

View File

@ -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))
}

View File

@ -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 {

View File

@ -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>,
}

View File

@ -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>>,
}

View File

@ -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;

View File

@ -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)
}