Skip to content

Commit

Permalink
Merge branch 'main' into dcreager/module-resolution
Browse files Browse the repository at this point in the history
* main:
  [red-knot] Display definition range in trace logs (#14955)
  [red-knot] Move the `ClassBase` enum to its own submodule (#14957)
  [red-knot] mdtest: python version requirements (#14954)
  [airflow]: Import modules that has been moved to airflow providers (AIR303) (#14764)
  [red-knot] Support `typing.TYPE_CHECKING` (#14952)
  Add tracing support to mdtest (#14935)
  Re-enable the fuzzer job on PRs (#14953)
  [red-knot] Improve `match` mdtests (#14951)
  Rename `custom-typeshed-dir`, `target-version` and `current-directory` CLI options (#14930)
  [red-knot] Add narrowing for 'while' loops (#14947)
  [`ruff`]  Skip SQLModel base classes for `mutable-class-default` (`RUF012`) (#14949)
  [red-knot] Tests for 'while' loop boundness (#14944)
  • Loading branch information
dcreager committed Dec 13, 2024
2 parents 9d4f731 + 3533d7f commit 80f65b7
Show file tree
Hide file tree
Showing 62 changed files with 1,111 additions and 548 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ jobs:
name: "cargo fuzz build"
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ github.ref == 'refs/heads/main' || needs.determine_changes.outputs.fuzz == 'true' }}
if: ${{ github.ref == 'refs/heads/main' || needs.determine_changes.outputs.fuzz == 'true' || needs.determine_changes.outputs.code == 'true' }}
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
Expand Down
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
4 changes: 4 additions & 0 deletions crates/red_knot_python_semantic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,9 @@ tempfile = { workspace = true }
quickcheck = { version = "1.0.3", default-features = false }
quickcheck_macros = { version = "1.0.0" }

[features]
serde = ["ruff_db/serde", "dep:serde"]

[lints]
workspace = true

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
Loading

0 comments on commit 80f65b7

Please sign in to comment.