Add support for sys.platform
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# `sys.platform`
|
||||
|
||||
## Default value
|
||||
|
||||
When no target platform is specified, we fall back to the type of `sys.platform` declared in
|
||||
typeshed:
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
# No python-platform entry
|
||||
```
|
||||
|
||||
```py
|
||||
import sys
|
||||
|
||||
reveal_type(sys.platform) # revealed: str
|
||||
```
|
||||
|
||||
## Explicit selection of `all` platforms
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-platform = "all"
|
||||
```
|
||||
|
||||
```py
|
||||
import sys
|
||||
|
||||
reveal_type(sys.platform) # revealed: str
|
||||
```
|
||||
|
||||
## Explicit selection of a specific platform
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-platform = "linux"
|
||||
```
|
||||
|
||||
```py
|
||||
import sys
|
||||
|
||||
reveal_type(sys.platform) # revealed: Literal["linux"]
|
||||
```
|
||||
@@ -16,7 +16,7 @@ pub(crate) mod tests {
|
||||
|
||||
use crate::program::{Program, SearchPathSettings};
|
||||
use crate::python_version::PythonVersion;
|
||||
use crate::{default_lint_registry, ProgramSettings};
|
||||
use crate::{default_lint_registry, ProgramSettings, PythonPlatform};
|
||||
|
||||
use super::Db;
|
||||
use crate::lint::RuleSelection;
|
||||
@@ -127,6 +127,8 @@ pub(crate) mod tests {
|
||||
pub(crate) struct TestDbBuilder<'a> {
|
||||
/// Target Python version
|
||||
python_version: PythonVersion,
|
||||
/// Target Python platform
|
||||
python_platform: PythonPlatform,
|
||||
/// Path to a custom typeshed directory
|
||||
custom_typeshed: Option<SystemPathBuf>,
|
||||
/// Path and content pairs for files that should be present
|
||||
@@ -137,6 +139,7 @@ pub(crate) mod tests {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
python_version: PythonVersion::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
custom_typeshed: None,
|
||||
files: vec![],
|
||||
}
|
||||
@@ -173,6 +176,7 @@ pub(crate) mod tests {
|
||||
&db,
|
||||
&ProgramSettings {
|
||||
python_version: self.python_version,
|
||||
python_platform: self.python_platform,
|
||||
search_paths,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ pub use db::Db;
|
||||
pub use module_name::ModuleName;
|
||||
pub use module_resolver::{resolve_module, system_module_search_paths, KnownModule, Module};
|
||||
pub use program::{Program, ProgramSettings, SearchPathSettings, SitePackages};
|
||||
pub use python_platform::PythonPlatform;
|
||||
pub use python_version::PythonVersion;
|
||||
pub use semantic_model::{HasTy, SemanticModel};
|
||||
|
||||
@@ -17,6 +18,7 @@ mod module_name;
|
||||
mod module_resolver;
|
||||
mod node_key;
|
||||
mod program;
|
||||
mod python_platform;
|
||||
mod python_version;
|
||||
pub mod semantic_index;
|
||||
mod semantic_model;
|
||||
|
||||
@@ -721,8 +721,8 @@ mod tests {
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::module_resolver::module::ModuleKind;
|
||||
use crate::module_resolver::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder};
|
||||
use crate::ProgramSettings;
|
||||
use crate::PythonVersion;
|
||||
use crate::{ProgramSettings, PythonPlatform};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -1262,7 +1262,7 @@ mod tests {
|
||||
fn symlink() -> anyhow::Result<()> {
|
||||
use anyhow::Context;
|
||||
|
||||
use crate::program::Program;
|
||||
use crate::{program::Program, PythonPlatform};
|
||||
use ruff_db::system::{OsSystem, SystemPath};
|
||||
|
||||
use crate::db::tests::TestDb;
|
||||
@@ -1296,6 +1296,7 @@ mod tests {
|
||||
&db,
|
||||
&ProgramSettings {
|
||||
python_version: PythonVersion::PY38,
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
extra_paths: vec![],
|
||||
src_root: src.clone(),
|
||||
@@ -1801,6 +1802,7 @@ not_a_directory
|
||||
&db,
|
||||
&ProgramSettings {
|
||||
python_version: PythonVersion::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
extra_paths: vec![],
|
||||
src_root: SystemPathBuf::from("/src"),
|
||||
|
||||
@@ -4,7 +4,7 @@ use ruff_db::vendored::VendoredPathBuf;
|
||||
use crate::db::tests::TestDb;
|
||||
use crate::program::{Program, SearchPathSettings};
|
||||
use crate::python_version::PythonVersion;
|
||||
use crate::{ProgramSettings, SitePackages};
|
||||
use crate::{ProgramSettings, PythonPlatform, SitePackages};
|
||||
|
||||
/// A test case for the module resolver.
|
||||
///
|
||||
@@ -101,6 +101,7 @@ pub(crate) struct UnspecifiedTypeshed;
|
||||
pub(crate) struct TestCaseBuilder<T> {
|
||||
typeshed_option: T,
|
||||
python_version: PythonVersion,
|
||||
python_platform: PythonPlatform,
|
||||
first_party_files: Vec<FileSpec>,
|
||||
site_packages_files: Vec<FileSpec>,
|
||||
}
|
||||
@@ -147,6 +148,7 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
Self {
|
||||
typeshed_option: UnspecifiedTypeshed,
|
||||
python_version: PythonVersion::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
first_party_files: vec![],
|
||||
site_packages_files: vec![],
|
||||
}
|
||||
@@ -157,12 +159,14 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
let TestCaseBuilder {
|
||||
typeshed_option: _,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
} = self;
|
||||
TestCaseBuilder {
|
||||
typeshed_option: VendoredTypeshed,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
}
|
||||
@@ -176,6 +180,7 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
let TestCaseBuilder {
|
||||
typeshed_option: _,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
} = self;
|
||||
@@ -183,6 +188,7 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
TestCaseBuilder {
|
||||
typeshed_option: typeshed,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
}
|
||||
@@ -212,6 +218,7 @@ impl TestCaseBuilder<MockedTypeshed> {
|
||||
let TestCaseBuilder {
|
||||
typeshed_option,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
} = self;
|
||||
@@ -227,6 +234,7 @@ impl TestCaseBuilder<MockedTypeshed> {
|
||||
&db,
|
||||
&ProgramSettings {
|
||||
python_version,
|
||||
python_platform,
|
||||
search_paths: SearchPathSettings {
|
||||
extra_paths: vec![],
|
||||
src_root: src.clone(),
|
||||
@@ -269,6 +277,7 @@ impl TestCaseBuilder<VendoredTypeshed> {
|
||||
let TestCaseBuilder {
|
||||
typeshed_option: VendoredTypeshed,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
} = self;
|
||||
@@ -283,6 +292,7 @@ impl TestCaseBuilder<VendoredTypeshed> {
|
||||
&db,
|
||||
&ProgramSettings {
|
||||
python_version,
|
||||
python_platform,
|
||||
search_paths: SearchPathSettings {
|
||||
site_packages: SitePackages::Known(vec![site_packages.clone()]),
|
||||
..SearchPathSettings::new(src.clone())
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::python_platform::PythonPlatform;
|
||||
use crate::python_version::PythonVersion;
|
||||
use anyhow::Context;
|
||||
use salsa::Durability;
|
||||
@@ -12,6 +13,8 @@ use crate::Db;
|
||||
pub struct Program {
|
||||
pub python_version: PythonVersion,
|
||||
|
||||
pub python_platform: PythonPlatform,
|
||||
|
||||
#[return_ref]
|
||||
pub(crate) search_paths: SearchPaths,
|
||||
}
|
||||
@@ -20,6 +23,7 @@ impl Program {
|
||||
pub fn from_settings(db: &dyn Db, settings: &ProgramSettings) -> anyhow::Result<Self> {
|
||||
let ProgramSettings {
|
||||
python_version,
|
||||
python_platform,
|
||||
search_paths,
|
||||
} = settings;
|
||||
|
||||
@@ -28,9 +32,11 @@ impl Program {
|
||||
let search_paths = SearchPaths::from_settings(db, search_paths)
|
||||
.with_context(|| "Invalid search path settings")?;
|
||||
|
||||
Ok(Program::builder(settings.python_version, search_paths)
|
||||
.durability(Durability::HIGH)
|
||||
.new(db))
|
||||
Ok(
|
||||
Program::builder(*python_version, python_platform.clone(), search_paths)
|
||||
.durability(Durability::HIGH)
|
||||
.new(db),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn update_search_paths(
|
||||
@@ -57,6 +63,7 @@ impl Program {
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
pub struct ProgramSettings {
|
||||
pub python_version: PythonVersion,
|
||||
pub python_platform: PythonPlatform,
|
||||
pub search_paths: SearchPathSettings,
|
||||
}
|
||||
|
||||
|
||||
13
crates/red_knot_python_semantic/src/python_platform.rs
Normal file
13
crates/red_knot_python_semantic/src/python_platform.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The target platform to assume when resolving types.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum PythonPlatform {
|
||||
/// Do not make any assumptions about the target platform.
|
||||
#[default]
|
||||
All,
|
||||
/// Assume a target platform like `linux`, `darwin`, `win32`, etc.
|
||||
#[serde(untagged)]
|
||||
Individual(String),
|
||||
}
|
||||
@@ -137,6 +137,21 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
|
||||
{
|
||||
return Symbol::Type(Type::BooleanLiteral(true), Boundness::Bound);
|
||||
}
|
||||
if name == "platform"
|
||||
&& file_to_module(db, scope.file(db)).is_some_and(|module| module.name() == "sys")
|
||||
{
|
||||
match Program::get(db).python_platform(db) {
|
||||
crate::PythonPlatform::Individual(platform) => {
|
||||
return Symbol::Type(
|
||||
Type::StringLiteral(StringLiteralType::new(db, platform.as_str())),
|
||||
Boundness::Bound,
|
||||
);
|
||||
}
|
||||
crate::PythonPlatform::All => {
|
||||
// Fall through to the looked up type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let table = symbol_table(db, scope);
|
||||
table
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//! ```
|
||||
|
||||
use anyhow::Context;
|
||||
use red_knot_python_semantic::PythonVersion;
|
||||
use red_knot_python_semantic::{PythonPlatform, PythonVersion};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug, Default, Clone)]
|
||||
@@ -28,13 +28,22 @@ impl MarkdownTestConfig {
|
||||
pub(crate) fn python_version(&self) -> Option<PythonVersion> {
|
||||
self.environment.as_ref().and_then(|env| env.python_version)
|
||||
}
|
||||
|
||||
pub(crate) fn python_platform(&self) -> Option<PythonPlatform> {
|
||||
self.environment
|
||||
.as_ref()
|
||||
.and_then(|env| env.python_platform.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default, Clone)]
|
||||
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
|
||||
pub(crate) struct Environment {
|
||||
/// Python version to assume when resolving types.
|
||||
/// Target Python version to assume when resolving types.
|
||||
pub(crate) python_version: Option<PythonVersion>,
|
||||
|
||||
/// Target platform to assume when resolving types.
|
||||
pub(crate) python_platform: Option<PythonPlatform>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use red_knot_python_semantic::lint::RuleSelection;
|
||||
use red_knot_python_semantic::{
|
||||
default_lint_registry, Db as SemanticDb, Program, ProgramSettings, PythonVersion,
|
||||
SearchPathSettings,
|
||||
default_lint_registry, Db as SemanticDb, Program, ProgramSettings, PythonPlatform,
|
||||
PythonVersion, SearchPathSettings,
|
||||
};
|
||||
use ruff_db::files::{File, Files};
|
||||
use ruff_db::system::{DbWithTestSystem, System, SystemPath, SystemPathBuf, TestSystem};
|
||||
@@ -40,6 +40,7 @@ impl Db {
|
||||
&db,
|
||||
&ProgramSettings {
|
||||
python_version: PythonVersion::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings::new(db.workspace_root.clone()),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -52,6 +52,9 @@ pub fn run(path: &Utf8Path, long_title: &str, short_title: &str, test_name: &str
|
||||
Program::get(&db)
|
||||
.set_python_version(&mut db)
|
||||
.to(test.configuration().python_version().unwrap_or_default());
|
||||
Program::get(&db)
|
||||
.set_python_platform(&mut db)
|
||||
.to(test.configuration().python_platform().unwrap_or_default());
|
||||
|
||||
// Remove all files so that the db is in a "fresh" state.
|
||||
db.memory_file_system().remove_all();
|
||||
|
||||
@@ -40,6 +40,7 @@ impl Configuration {
|
||||
WorkspaceSettings {
|
||||
program: ProgramSettings {
|
||||
python_version: self.python_version.unwrap_or_default(),
|
||||
python_platform: Default::default(),
|
||||
search_paths: self.search_paths.to_settings(workspace_root),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ impl ModuleDb {
|
||||
&db,
|
||||
&ProgramSettings {
|
||||
python_version,
|
||||
python_platform: Default::default(),
|
||||
search_paths,
|
||||
},
|
||||
)?;
|
||||
|
||||
Reference in New Issue
Block a user