mirror of
https://github.com/astral-sh/ruff
synced 2026-01-21 05:20:49 -05:00
[ty] Extract ty_site_packages crate (#22622)
This commit is contained in:
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -3176,6 +3176,7 @@ dependencies = [
|
||||
"serde",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_site_packages",
|
||||
"zip",
|
||||
]
|
||||
|
||||
@@ -4562,7 +4563,6 @@ dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitvec",
|
||||
"camino",
|
||||
"colored 3.0.0",
|
||||
"compact_str",
|
||||
"datatest-stable",
|
||||
"drop_bomb",
|
||||
@@ -4578,7 +4578,6 @@ dependencies = [
|
||||
"pretty_assertions",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"ruff_annotate_snippets",
|
||||
"ruff_db",
|
||||
"ruff_diagnostics",
|
||||
"ruff_index",
|
||||
@@ -4606,6 +4605,7 @@ dependencies = [
|
||||
"tracing",
|
||||
"ty_combine",
|
||||
"ty_module_resolver",
|
||||
"ty_site_packages",
|
||||
"ty_static",
|
||||
"ty_test",
|
||||
"ty_vendored",
|
||||
@@ -4649,6 +4649,26 @@ dependencies = [
|
||||
"ty_python_semantic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty_site_packages"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"colored 3.0.0",
|
||||
"get-size2",
|
||||
"indexmap",
|
||||
"ruff_annotate_snippets",
|
||||
"ruff_db",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tracing",
|
||||
"ty_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty_static"
|
||||
version = "0.0.1"
|
||||
|
||||
@@ -49,6 +49,7 @@ ty_module_resolver = { path = "crates/ty_module_resolver" }
|
||||
ty_project = { path = "crates/ty_project", default-features = false }
|
||||
ty_python_semantic = { path = "crates/ty_python_semantic" }
|
||||
ty_server = { path = "crates/ty_server" }
|
||||
ty_site_packages = { path = "crates/ty_site_packages" }
|
||||
ty_static = { path = "crates/ty_static" }
|
||||
ty_test = { path = "crates/ty_test" }
|
||||
ty_vendored = { path = "crates/ty_vendored" }
|
||||
|
||||
@@ -22,6 +22,7 @@ ruff_python_ast = { workspace = true }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_python_semantic = { workspace = true }
|
||||
ty_site_packages = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true, optional = true }
|
||||
|
||||
@@ -10,9 +10,10 @@ use ruff_python_ast::PythonVersion;
|
||||
use ty_module_resolver::{SearchPathSettings, SearchPaths};
|
||||
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||
use ty_python_semantic::{
|
||||
AnalysisSettings, Db, Program, ProgramSettings, PythonEnvironment, PythonPlatform,
|
||||
PythonVersionSource, PythonVersionWithSource, SysPrefixPathOrigin, default_lint_registry,
|
||||
AnalysisSettings, Db, Program, ProgramSettings, PythonPlatform, PythonVersionSource,
|
||||
PythonVersionWithSource, default_lint_registry,
|
||||
};
|
||||
use ty_site_packages::{PythonEnvironment, SysPrefixPathOrigin};
|
||||
|
||||
static EMPTY_VENDORED: std::sync::LazyLock<VendoredFileSystem> = std::sync::LazyLock::new(|| {
|
||||
let mut builder = VendoredFileSystemBuilder::new(CompressionMethod::Stored);
|
||||
|
||||
@@ -11,7 +11,6 @@ repository = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
ruff_annotate_snippets = { workspace = true }
|
||||
ruff_db = { workspace = true }
|
||||
ruff_diagnostics = { workspace = true }
|
||||
ruff_index = { workspace = true, features = ["salsa"] }
|
||||
@@ -26,13 +25,11 @@ ruff_source_file = { workspace = true }
|
||||
ruff_text_size = { workspace = true }
|
||||
ty_combine = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_static = { workspace = true }
|
||||
ty_site_packages = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
bitvec = { workspace = true }
|
||||
camino = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
compact_str = { workspace = true }
|
||||
drop_bomb = { workspace = true }
|
||||
get-size2 = { workspace = true, features = ["indexmap", "ordermap"] }
|
||||
@@ -63,6 +60,7 @@ ty_test = { workspace = true }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
camino = { workspace = true }
|
||||
datatest-stable = { workspace = true }
|
||||
glob = { workspace = true }
|
||||
indoc = { workspace = true }
|
||||
|
||||
@@ -8,17 +8,18 @@ use crate::lint::{LintRegistry, LintRegistryBuilder};
|
||||
use crate::suppression::{IGNORE_COMMENT_UNKNOWN_RULE, INVALID_IGNORE_COMMENT};
|
||||
pub use db::Db;
|
||||
pub use diagnostic::add_inferred_python_version_hint_to_diagnostic;
|
||||
pub use program::{
|
||||
Program, ProgramSettings, PythonVersionFileSource, PythonVersionSource, PythonVersionWithSource,
|
||||
};
|
||||
pub use program::{Program, ProgramSettings};
|
||||
pub use python_platform::PythonPlatform;
|
||||
use rustc_hash::FxHasher;
|
||||
pub use semantic_model::{
|
||||
Completion, HasDefinition, HasType, MemberDefinition, NameKind, SemanticModel,
|
||||
};
|
||||
pub use site_packages::{PythonEnvironment, SitePackagesPaths, SysPrefixPathOrigin};
|
||||
pub use suppression::{UNUSED_IGNORE_COMMENT, suppress_all, suppress_single};
|
||||
pub use ty_module_resolver::MisconfigurationMode;
|
||||
pub use ty_site_packages::{
|
||||
PythonEnvironment, PythonVersionFileSource, PythonVersionSource, PythonVersionWithSource,
|
||||
SitePackagesPaths, SysPrefixPathOrigin,
|
||||
};
|
||||
pub use types::DisplaySettings;
|
||||
pub use types::ide_support::{
|
||||
ImportAliasResolution, ResolvedDefinition, definitions_for_attribute, definitions_for_bin_op,
|
||||
@@ -38,7 +39,6 @@ mod python_platform;
|
||||
mod rank;
|
||||
pub mod semantic_index;
|
||||
mod semantic_model;
|
||||
pub(crate) mod site_packages;
|
||||
mod subscript;
|
||||
mod suppression;
|
||||
pub mod types;
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::Db;
|
||||
use crate::python_platform::PythonPlatform;
|
||||
|
||||
use ruff_db::diagnostic::Span;
|
||||
use ruff_db::files::system_path_to_file;
|
||||
use ruff_db::system::{SystemPath, SystemPathBuf};
|
||||
use ruff_db::system::SystemPath;
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ruff_text_size::TextRange;
|
||||
use salsa::Durability;
|
||||
use salsa::Setter;
|
||||
use ty_module_resolver::SearchPaths;
|
||||
use ty_site_packages::PythonVersionWithSource;
|
||||
|
||||
#[salsa::input(singleton, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub struct Program {
|
||||
@@ -91,73 +87,3 @@ pub struct ProgramSettings {
|
||||
pub python_platform: PythonPlatform,
|
||||
pub search_paths: SearchPaths,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default, get_size2::GetSize)]
|
||||
pub enum PythonVersionSource {
|
||||
/// Value loaded from a project's configuration file.
|
||||
ConfigFile(PythonVersionFileSource),
|
||||
|
||||
/// Value loaded from the `pyvenv.cfg` file of the virtual environment.
|
||||
/// The virtual environment might have been configured, activated or inferred.
|
||||
PyvenvCfgFile(PythonVersionFileSource),
|
||||
|
||||
/// Value inferred from the layout of the Python installation.
|
||||
///
|
||||
/// This only ever applies on Unix. On Unix, the `site-packages` directory
|
||||
/// will always be at `sys.prefix/lib/pythonX.Y/site-packages`,
|
||||
/// so we can infer the Python version from the parent directory of `site-packages`.
|
||||
InstallationDirectoryLayout { site_packages_parent_dir: Box<str> },
|
||||
|
||||
/// The value comes from a CLI argument, while it's left open if specified using a short argument,
|
||||
/// long argument (`--extra-paths`) or `--config key=value`.
|
||||
Cli,
|
||||
|
||||
/// The value comes from the user's editor,
|
||||
/// while it's left open if specified as a setting
|
||||
/// or if the value was auto-discovered by the editor
|
||||
/// (e.g., the Python environment)
|
||||
Editor,
|
||||
|
||||
/// We fell back to a default value because the value was not specified via the CLI or a config file.
|
||||
#[default]
|
||||
Default,
|
||||
}
|
||||
|
||||
/// Information regarding the file and [`TextRange`] of the configuration
|
||||
/// from which we inferred the Python version.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, get_size2::GetSize)]
|
||||
pub struct PythonVersionFileSource {
|
||||
path: Arc<SystemPathBuf>,
|
||||
range: Option<TextRange>,
|
||||
}
|
||||
|
||||
impl PythonVersionFileSource {
|
||||
pub fn new(path: Arc<SystemPathBuf>, range: Option<TextRange>) -> Self {
|
||||
Self { path, range }
|
||||
}
|
||||
|
||||
/// Attempt to resolve a [`Span`] that corresponds to the location of
|
||||
/// the configuration setting that specified the Python version.
|
||||
///
|
||||
/// Useful for subdiagnostics when informing the user
|
||||
/// what the inferred Python version of their project is.
|
||||
pub(crate) fn span(&self, db: &dyn Db) -> Option<Span> {
|
||||
let file = system_path_to_file(db, &*self.path).ok()?;
|
||||
Some(Span::from(file).with_optional_range(self.range))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Clone, get_size2::GetSize)]
|
||||
pub struct PythonVersionWithSource {
|
||||
pub version: PythonVersion,
|
||||
pub source: PythonVersionSource,
|
||||
}
|
||||
|
||||
impl Default for PythonVersionWithSource {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: PythonVersion::latest_ty(),
|
||||
source: PythonVersionSource::Default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
crates/ty_site_packages/Cargo.toml
Normal file
34
crates/ty_site_packages/Cargo.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
[package]
|
||||
name = "ty_site_packages"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
documentation = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
ruff_annotate_snippets = { workspace = true }
|
||||
ruff_db = { workspace = true }
|
||||
ruff_python_ast = { workspace = true }
|
||||
ruff_python_trivia = { workspace = true }
|
||||
ruff_source_file = { workspace = true }
|
||||
ruff_text_size = { workspace = true }
|
||||
ty_static = { workspace = true }
|
||||
|
||||
camino = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
get-size2 = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_db = { workspace = true, features = ["testing", "os"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -8,13 +8,14 @@
|
||||
//! reasonably ask us to type-check code assuming that the code runs
|
||||
//! on Linux.)
|
||||
|
||||
mod version;
|
||||
|
||||
use std::io;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, sync::Arc};
|
||||
|
||||
use crate::{PythonVersionFileSource, PythonVersionSource, PythonVersionWithSource};
|
||||
use camino::Utf8Component;
|
||||
use indexmap::IndexSet;
|
||||
use ruff_annotate_snippets::{Level, Renderer, Snippet};
|
||||
@@ -25,6 +26,7 @@ use ruff_source_file::{LineIndex, OneIndexed, SourceCode};
|
||||
use ruff_text_size::{TextLen, TextRange};
|
||||
use strum::IntoEnumIterator;
|
||||
use ty_static::EnvVars;
|
||||
pub use version::{PythonVersionFileSource, PythonVersionSource, PythonVersionWithSource};
|
||||
|
||||
type SitePackagesDiscoveryResult<T> = Result<T, SitePackagesDiscoveryError>;
|
||||
type StdlibDiscoveryResult<T> = Result<T, StdlibDiscoveryError>;
|
||||
92
crates/ty_site_packages/src/version.rs
Normal file
92
crates/ty_site_packages/src/version.rs
Normal file
@@ -0,0 +1,92 @@
|
||||
//! Types for representing the Python version and its source.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use ruff_db::Db;
|
||||
use ruff_db::diagnostic::Span;
|
||||
use ruff_db::files::system_path_to_file;
|
||||
use ruff_db::system::SystemPathBuf;
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ruff_text_size::TextRange;
|
||||
|
||||
/// The source of the Python version.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default, get_size2::GetSize)]
|
||||
pub enum PythonVersionSource {
|
||||
/// Value loaded from a project's configuration file.
|
||||
ConfigFile(PythonVersionFileSource),
|
||||
|
||||
/// Value loaded from the `pyvenv.cfg` file of the virtual environment.
|
||||
/// The virtual environment might have been configured, activated or inferred.
|
||||
PyvenvCfgFile(PythonVersionFileSource),
|
||||
|
||||
/// Value inferred from the layout of the Python installation.
|
||||
///
|
||||
/// This only ever applies on Unix. On Unix, the `site-packages` directory
|
||||
/// will always be at `sys.prefix/lib/pythonX.Y/site-packages`,
|
||||
/// so we can infer the Python version from the parent directory of `site-packages`.
|
||||
InstallationDirectoryLayout { site_packages_parent_dir: Box<str> },
|
||||
|
||||
/// The value comes from a CLI argument, while it's left open if specified using a short argument,
|
||||
/// long argument (`--extra-paths`) or `--config key=value`.
|
||||
Cli,
|
||||
|
||||
/// The value comes from the user's editor,
|
||||
/// while it's left open if specified as a setting
|
||||
/// or if the value was auto-discovered by the editor
|
||||
/// (e.g., the Python environment)
|
||||
Editor,
|
||||
|
||||
/// We fell back to a default value because the value was not specified via the CLI or a config file.
|
||||
#[default]
|
||||
Default,
|
||||
}
|
||||
|
||||
/// Information regarding the file and [`TextRange`] of the configuration
|
||||
/// from which we inferred the Python version.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, get_size2::GetSize)]
|
||||
pub struct PythonVersionFileSource {
|
||||
path: Arc<SystemPathBuf>,
|
||||
range: Option<TextRange>,
|
||||
}
|
||||
|
||||
impl PythonVersionFileSource {
|
||||
pub fn new(path: Arc<SystemPathBuf>, range: Option<TextRange>) -> Self {
|
||||
Self { path, range }
|
||||
}
|
||||
|
||||
/// Returns the path to the configuration file.
|
||||
pub fn path(&self) -> &SystemPathBuf {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// Returns the range of the configuration setting.
|
||||
pub fn range(&self) -> Option<TextRange> {
|
||||
self.range
|
||||
}
|
||||
|
||||
/// Attempt to resolve a [`Span`] that corresponds to the location of
|
||||
/// the configuration setting that specified the Python version.
|
||||
///
|
||||
/// Useful for subdiagnostics when informing the user
|
||||
/// what the inferred Python version of their project is.
|
||||
pub fn span(&self, db: &dyn Db) -> Option<Span> {
|
||||
let file = system_path_to_file(db, &*self.path).ok()?;
|
||||
Some(Span::from(file).with_optional_range(self.range))
|
||||
}
|
||||
}
|
||||
|
||||
/// A Python version with its source.
|
||||
#[derive(Eq, PartialEq, Debug, Clone, get_size2::GetSize)]
|
||||
pub struct PythonVersionWithSource {
|
||||
pub version: PythonVersion,
|
||||
pub source: PythonVersionSource,
|
||||
}
|
||||
|
||||
impl Default for PythonVersionWithSource {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: PythonVersion::latest_ty(),
|
||||
source: PythonVersionSource::Default,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user