Skip to content

Commit

Permalink
Rename custom-typeshed-dir, target-version and `current-directory…
Browse files Browse the repository at this point in the history
…` CLI options (#14930)

## Summary

This PR renames the `--custom-typeshed-dir`, `target-version`, and
`--current-directory` cli options to `--typeshed`,
`--python-version`, and `--project` as discussed in the CLI proposal
document.
I added aliases for `--target-version` (for Ruff compat) and
`--custom-typeshed-dir` (for Alex)

## Test Plan

Long help

```
An extremely fast Python type checker.

Usage: red_knot [OPTIONS] [COMMAND]

Commands:
  server  Start the language server
  help    Print this message or the help of the given subcommand(s)

Options:
      --project <PROJECT>
          Run the command within the given project directory.
          
          All `pyproject.toml` files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (`.venv`).
          
          Other command-line arguments (such as relative paths) will be resolved relative to the current working directory."#,

      --venv-path <PATH>
          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.

      --typeshed-path <PATH>
          Custom directory to use for stdlib typeshed stubs

      --extra-search-path <PATH>
          Additional path to use as a module-resolution source (can be passed multiple times)

      --python-version <VERSION>
          Python version to assume when resolving types
          
          [possible values: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13]

  -v, --verbose...
          Use verbose output (or `-vv` and `-vvv` for more verbose output)

  -W, --watch
          Run in watch mode by re-running whenever files change

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version
```

Short help 

```
An extremely fast Python type checker.

Usage: red_knot [OPTIONS] [COMMAND]

Commands:
  server  Start the language server
  help    Print this message or the help of the given subcommand(s)

Options:
      --project <PROJECT>         Run the command within the given project directory
      --venv-path <PATH>          Path to the virtual environment the project uses
      --typeshed-path <PATH>      Custom directory to use for stdlib typeshed stubs
      --extra-search-path <PATH>  Additional path to use as a module-resolution source (can be passed multiple times)
      --python-version <VERSION>  Python version to assume when resolving types [possible values: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13]
  -v, --verbose...                Use verbose output (or `-vv` and `-vvv` for more verbose output)
  -W, --watch                     Run in watch mode by re-running whenever files change
  -h, --help                      Print help (see more with '--help')
  -V, --version                   Print version

```

---------

Co-authored-by: Alex Waygood <[email protected]>
  • Loading branch information
MichaReiser and AlexWaygood authored Dec 13, 2024
1 parent d7ce548 commit c1837e4
Show file tree
Hide file tree
Showing 33 changed files with 282 additions and 299 deletions.
84 changes: 33 additions & 51 deletions crates/red_knot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use anyhow::{anyhow, Context};
use clap::Parser;
use colored::Colorize;
use crossbeam::channel as crossbeam_channel;
use python_version::PythonVersion;
use red_knot_python_semantic::SitePackages;
use red_knot_server::run_server;
use red_knot_workspace::db::RootDatabase;
Expand All @@ -15,12 +16,11 @@ use red_knot_workspace::workspace::WorkspaceMetadata;
use ruff_db::diagnostic::Diagnostic;
use ruff_db::system::{OsSystem, System, SystemPath, SystemPathBuf};
use salsa::plumbing::ZalsaDatabase;
use target_version::TargetVersion;

use crate::logging::{setup_tracing, Verbosity};

mod logging;
mod target_version;
mod python_version;
mod verbosity;

#[derive(Debug, Parser)]
Expand All @@ -34,63 +34,48 @@ struct Args {
#[command(subcommand)]
pub(crate) command: Option<Command>,

#[arg(
long,
help = "Changes the current working directory.",
long_help = "Changes the current working directory before any specified operations. This affects the workspace and configuration discovery.",
value_name = "PATH"
)]
current_directory: Option<SystemPathBuf>,

#[arg(
long,
help = "Path to the virtual environment the project uses",
long_help = "\
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.",
value_name = "PATH"
)]
/// 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")]
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")]
venv_path: Option<SystemPathBuf>,

#[arg(
long,
value_name = "DIRECTORY",
help = "Custom directory to use for stdlib typeshed stubs"
)]
custom_typeshed_dir: Option<SystemPathBuf>,

#[arg(
long,
value_name = "PATH",
help = "Additional path to use as a module-resolution source (can be passed multiple times)"
)]
/// Custom directory to use for stdlib typeshed stubs.
#[arg(long, value_name = "PATH", alias = "custom-typeshed-dir")]
typeshed: Option<SystemPathBuf>,

/// Additional path to use as a module-resolution source (can be passed multiple times).
#[arg(long, value_name = "PATH")]
extra_search_path: Option<Vec<SystemPathBuf>>,

#[arg(
long,
help = "Python version to assume when resolving types",
value_name = "VERSION"
)]
target_version: Option<TargetVersion>,
/// Python version to assume when resolving types.
#[arg(long, value_name = "VERSION", alias = "target-version")]
python_version: Option<PythonVersion>,

#[clap(flatten)]
verbosity: Verbosity,

#[arg(
long,
help = "Run in watch mode by re-running whenever files change",
short = 'W'
)]
/// Run in watch mode by re-running whenever files change.
#[arg(long, short = 'W')]
watch: bool,
}

impl Args {
fn to_configuration(&self, cli_cwd: &SystemPath) -> Configuration {
let mut configuration = Configuration::default();

if let Some(target_version) = self.target_version {
configuration.target_version = Some(target_version.into());
if let Some(python_version) = self.python_version {
configuration.python_version = Some(python_version.into());
}

if let Some(venv_path) = &self.venv_path {
Expand All @@ -99,9 +84,8 @@ impl Args {
});
}

if let Some(custom_typeshed_dir) = &self.custom_typeshed_dir {
configuration.search_paths.custom_typeshed =
Some(SystemPath::absolute(custom_typeshed_dir, cli_cwd));
if let Some(typeshed) = &self.typeshed {
configuration.search_paths.typeshed = Some(SystemPath::absolute(typeshed, cli_cwd));
}

if let Some(extra_search_paths) = &self.extra_search_path {
Expand Down Expand Up @@ -167,15 +151,13 @@ fn run() -> anyhow::Result<ExitStatus> {
};

let cwd = args
.current_directory
.project
.as_ref()
.map(|cwd| {
if cwd.as_std_path().is_dir() {
Ok(SystemPath::absolute(cwd, &cli_base_path))
} else {
Err(anyhow!(
"Provided current-directory path `{cwd}` is not a directory"
))
Err(anyhow!("Provided project path `{cwd}` is not a directory"))
}
})
.transpose()?
Expand Down
68 changes: 68 additions & 0 deletions crates/red_knot/src/python_version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/// Enumeration of all supported Python versions
///
/// TODO: unify with the `PythonVersion` enum in the linter/formatter crates?
#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, Default, clap::ValueEnum)]
pub enum PythonVersion {
#[value(name = "3.7")]
Py37,
#[value(name = "3.8")]
Py38,
#[default]
#[value(name = "3.9")]
Py39,
#[value(name = "3.10")]
Py310,
#[value(name = "3.11")]
Py311,
#[value(name = "3.12")]
Py312,
#[value(name = "3.13")]
Py313,
}

impl PythonVersion {
const fn as_str(self) -> &'static str {
match self {
Self::Py37 => "3.7",
Self::Py38 => "3.8",
Self::Py39 => "3.9",
Self::Py310 => "3.10",
Self::Py311 => "3.11",
Self::Py312 => "3.12",
Self::Py313 => "3.13",
}
}
}

impl std::fmt::Display for PythonVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}

impl From<PythonVersion> for red_knot_python_semantic::PythonVersion {
fn from(value: PythonVersion) -> Self {
match value {
PythonVersion::Py37 => Self::PY37,
PythonVersion::Py38 => Self::PY38,
PythonVersion::Py39 => Self::PY39,
PythonVersion::Py310 => Self::PY310,
PythonVersion::Py311 => Self::PY311,
PythonVersion::Py312 => Self::PY312,
PythonVersion::Py313 => Self::PY313,
}
}
}

#[cfg(test)]
mod tests {
use crate::python_version::PythonVersion;

#[test]
fn same_default_as_python_version() {
assert_eq!(
red_knot_python_semantic::PythonVersion::from(PythonVersion::default()),
red_knot_python_semantic::PythonVersion::default()
);
}
}
62 changes: 0 additions & 62 deletions crates/red_knot/src/target_version.rs

This file was deleted.

6 changes: 3 additions & 3 deletions crates/red_knot/tests/file_watching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ where
.extra_paths
.iter()
.flatten()
.chain(search_paths.custom_typeshed.iter())
.chain(search_paths.typeshed.iter())
.chain(search_paths.site_packages.iter().flat_map(|site_packages| {
if let SitePackages::Known(path) = site_packages {
path.as_slice()
Expand All @@ -296,7 +296,7 @@ where
}

let configuration = Configuration {
target_version: Some(PythonVersion::PY312),
python_version: Some(PythonVersion::PY312),
search_paths,
};

Expand Down Expand Up @@ -888,7 +888,7 @@ fn changed_versions_file() -> anyhow::Result<()> {
Ok(())
},
|root_path, _workspace_path| SearchPathConfiguration {
custom_typeshed: Some(root_path.join("typeshed")),
typeshed: Some(root_path.join("typeshed")),
..SearchPathConfiguration::default()
},
)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ if "" < lorem == "ipsum":

```toml
[environment]
target-version = "3.11"
python-version = "3.11"
```

```py
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def f():

```toml
[environment]
target-version = "3.11"
python-version = "3.11"
```

```py
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The following configuration will be attached to the *root* section (without any

```toml
[environment]
target-version = "3.10"
python-version = "3.10"
```

# Basic
Expand Down Expand Up @@ -34,7 +34,7 @@ Here, we make sure that we can overwrite the global configuration in a child sec

```toml
[environment]
target-version = "3.11"
python-version = "3.11"
```

```py
Expand All @@ -55,7 +55,7 @@ Children in this section should all use the section configuration:

```toml
[environment]
target-version = "3.12"
python-version = "3.12"
```

## Child
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _(m: int, n: int):

```toml
[environment]
target-version = "3.9"
python-version = "3.9"
```

```py
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

```toml
[environment]
target-version = "3.9"
python-version = "3.9"
```

## The type of `sys.version_info`
Expand Down
4 changes: 2 additions & 2 deletions crates/red_knot_python_semantic/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,12 @@ pub(crate) mod tests {
.context("Failed to write test files")?;

let mut search_paths = SearchPathSettings::new(src_root);
search_paths.custom_typeshed = self.custom_typeshed;
search_paths.typeshed = self.custom_typeshed;

Program::from_settings(
&db,
&ProgramSettings {
target_version: self.python_version,
python_version: self.python_version,
search_paths,
},
)
Expand Down
Loading

0 comments on commit c1837e4

Please sign in to comment.