-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[red-knot] Add
--ignore
, --warn
, and --error
CLI arguments
- Loading branch information
1 parent
43160b4
commit 5dd905d
Showing
5 changed files
with
325 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,7 @@ tracing-flamechart.svg | |
tracing-flamegraph.svg | ||
|
||
# insta | ||
.rs.pending-snap | ||
*.rs.pending-snap | ||
|
||
|
||
### | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
use crate::logging::Verbosity; | ||
use crate::python_version::PythonVersion; | ||
use crate::Command; | ||
use clap::{ArgAction, ArgMatches, Error, Parser}; | ||
use red_knot_project::metadata::options::{EnvironmentOptions, Options}; | ||
use red_knot_project::metadata::value::{RangedValue, RelativePathBuf}; | ||
use red_knot_python_semantic::lint; | ||
use ruff_db::system::SystemPathBuf; | ||
|
||
#[derive(Debug, Parser)] | ||
#[command( | ||
author, | ||
name = "red-knot", | ||
about = "An extremely fast Python type checker." | ||
)] | ||
#[command(version)] | ||
pub(crate) struct Args { | ||
#[command(subcommand)] | ||
pub(crate) command: Option<Command>, | ||
|
||
/// Run the command within the given project directory. | ||
/// | ||
/// All `pyproject.toml` files will be discovered by walking up the directory tree from the given project directory, | ||
/// as will the project's virtual environment (`.venv`) unless the `venv-path` option is set. | ||
/// | ||
/// Other command-line arguments (such as relative paths) will be resolved relative to the current working directory. | ||
#[arg(long, value_name = "PROJECT")] | ||
pub(crate) project: Option<SystemPathBuf>, | ||
|
||
/// Path to the virtual environment the project uses. | ||
/// | ||
/// If provided, red-knot will use the `site-packages` directory of this virtual environment | ||
/// to resolve type information for the project's third-party dependencies. | ||
#[arg(long, value_name = "PATH")] | ||
pub(crate) venv_path: Option<SystemPathBuf>, | ||
|
||
/// Custom directory to use for stdlib typeshed stubs. | ||
#[arg(long, value_name = "PATH", alias = "custom-typeshed-dir")] | ||
pub(crate) typeshed: Option<SystemPathBuf>, | ||
|
||
/// Additional path to use as a module-resolution source (can be passed multiple times). | ||
#[arg(long, value_name = "PATH")] | ||
pub(crate) extra_search_path: Option<Vec<SystemPathBuf>>, | ||
|
||
/// Python version to assume when resolving types. | ||
#[arg(long, value_name = "VERSION", alias = "target-version")] | ||
pub(crate) python_version: Option<PythonVersion>, | ||
|
||
#[clap(flatten)] | ||
pub(crate) verbosity: Verbosity, | ||
|
||
#[clap(flatten)] | ||
pub(crate) rules: RulesArg, | ||
|
||
/// Run in watch mode by re-running whenever files change. | ||
#[arg(long, short = 'W')] | ||
pub(crate) watch: bool, | ||
} | ||
|
||
impl Args { | ||
pub(crate) fn to_options(&self) -> Options { | ||
let rules = if self.rules.is_empty() { | ||
None | ||
} else { | ||
Some( | ||
self.rules | ||
.iter() | ||
.map(|(rule, level)| { | ||
(RangedValue::cli(rule.to_string()), RangedValue::cli(level)) | ||
}) | ||
.collect(), | ||
) | ||
}; | ||
|
||
Options { | ||
environment: Some(EnvironmentOptions { | ||
python_version: self | ||
.python_version | ||
.map(|version| RangedValue::cli(version.into())), | ||
venv_path: self.venv_path.as_ref().map(RelativePathBuf::cli), | ||
typeshed: self.typeshed.as_ref().map(RelativePathBuf::cli), | ||
extra_paths: self.extra_search_path.as_ref().map(|extra_search_paths| { | ||
extra_search_paths | ||
.iter() | ||
.map(RelativePathBuf::cli) | ||
.collect() | ||
}), | ||
..EnvironmentOptions::default() | ||
}), | ||
rules, | ||
..Default::default() | ||
} | ||
} | ||
} | ||
|
||
/// A list of rules to enable or disable with a given severity. | ||
/// | ||
/// This type is used to parse the `--error`, `--warn`, and `--ignore` arguments | ||
/// while preserving the order in which they were specified (arguments last override previous severities). | ||
#[derive(Debug)] | ||
pub(crate) struct RulesArg(Vec<(String, lint::Level)>); | ||
|
||
impl RulesArg { | ||
fn is_empty(&self) -> bool { | ||
self.0.is_empty() | ||
} | ||
|
||
fn iter(&self) -> impl Iterator<Item = (&str, lint::Level)> { | ||
self.0.iter().map(|(rule, level)| (rule.as_str(), *level)) | ||
} | ||
} | ||
|
||
impl clap::FromArgMatches for RulesArg { | ||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> { | ||
let mut rules = Vec::new(); | ||
|
||
for (level, arg_id) in [ | ||
(lint::Level::Ignore, "ignore"), | ||
(lint::Level::Warn, "warn"), | ||
(lint::Level::Error, "error"), | ||
] { | ||
rules.extend( | ||
matches | ||
.indices_of(arg_id) | ||
.into_iter() | ||
.flatten() | ||
.zip(matches.get_many::<String>(arg_id).into_iter().flatten()) | ||
.map(|(index, rule)| (index, rule, level)), | ||
) | ||
} | ||
|
||
// Sorty by their index so that values specified later override earlier ones. | ||
rules.sort_by_key(|(index, _, _)| *index); | ||
|
||
Ok(Self( | ||
rules | ||
.into_iter() | ||
.map(|(_, rule, level)| (rule.to_owned(), level)) | ||
.collect(), | ||
)) | ||
} | ||
|
||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> { | ||
self.0 = Self::from_arg_matches(matches)?.0; | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl clap::Args for RulesArg { | ||
fn augment_args(cmd: clap::Command) -> clap::Command { | ||
const HELP_HEADING: &'static str = "Enabling / disabling rules"; | ||
|
||
cmd.arg( | ||
clap::Arg::new("error") | ||
.long("error") | ||
.action(ArgAction::Append) | ||
.help("List of rules to enable with an error severity") | ||
.value_name("RULE") | ||
.help_heading(HELP_HEADING), | ||
) | ||
.arg( | ||
clap::Arg::new("warn") | ||
.long("warn") | ||
.action(ArgAction::Append) | ||
.help("List of rules to enable with a warning severity") | ||
.value_name("RULE") | ||
.help_heading(HELP_HEADING), | ||
) | ||
.arg( | ||
clap::Arg::new("ignore") | ||
.long("ignore") | ||
.action(ArgAction::Append) | ||
.help("List of rule codes to disable") | ||
.value_name("RULE") | ||
.help_heading(HELP_HEADING), | ||
) | ||
} | ||
|
||
fn augment_args_for_update(cmd: clap::Command) -> clap::Command { | ||
Self::augment_args(cmd) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.