[red-knot] Default python-platform to current platform (#17183)
Some checks are pending
CI / cargo clippy (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
[Knot Playground] Release / publish (push) Waiting to run

## Summary

As discussed in https://github.com/astral-sh/ruff/issues/16983 and
"mitigate" said issue for the alpha.

This PR changes the default for `PythonPlatform` to be the current
platform rather than `all`.

I'm not sure if we should be as sophisticated as supporting `ios` and
`android` as defaults but it was easy...

## Test Plan

Updated Markdown tests.

---------

Co-authored-by: David Peter <mail@david-peter.de>
This commit is contained in:
Micha Reiser 2025-04-09 12:05:18 +02:00 committed by GitHub
parent 00e00b9ad6
commit 8249a72412
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 49 additions and 52 deletions

View file

@ -75,7 +75,8 @@ pub(crate) struct CheckCommand {
///
/// This is used to specialize the type of `sys.platform` and will affect the visibility
/// of platform-specific functions and attributes. If the value is set to `all`, no
/// assumptions are made about the target platform.
/// assumptions are made about the target platform. If unspecified, the current system's
/// platform will be used.
#[arg(long, value_name = "PLATFORM", alias = "platform")]
pub(crate) python_platform: Option<String>,

View file

@ -54,20 +54,25 @@ impl Options {
project_root: &SystemPath,
system: &dyn System,
) -> ProgramSettings {
let (python_version, python_platform) = self
let python_version = self
.environment
.as_ref()
.map(|env| {
(
env.python_version.as_deref().copied(),
env.python_platform.as_deref(),
)
})
.and_then(|env| env.python_version.as_deref().copied())
.unwrap_or_default();
let python_platform = self
.environment
.as_ref()
.and_then(|env| env.python_platform.as_deref().cloned())
.unwrap_or_else(|| {
let default = PythonPlatform::default();
tracing::info!(
"Defaulting to default python version for this platform: '{default}'",
);
default
});
ProgramSettings {
python_version: python_version.unwrap_or_default(),
python_platform: python_platform.cloned().unwrap_or_default(),
python_version,
python_platform,
search_paths: self.to_search_path_settings(project_root, system),
}
}
@ -237,7 +242,12 @@ pub struct EnvironmentOptions {
/// If specified, Red Knot will tailor its use of type stub files,
/// which conditionalize type definitions based on the platform.
///
/// If no platform is specified, knot will use `all` or the current platform in the LSP use case.
/// If no platform is specified, knot will use the current platform:
/// - `win32` for Windows
/// - `darwin` for macOS
/// - `android` for Android
/// - `ios` for iOS
/// - `linux` for everything else
#[serde(skip_serializing_if = "Option::is_none")]
pub python_platform: Option<RangedValue<PythonPlatform>>,

View file

@ -56,7 +56,7 @@ We can access attributes on objects of all kinds:
```py
import sys
reveal_type(inspect.getattr_static(sys, "platform")) # revealed: LiteralString
reveal_type(inspect.getattr_static(sys, "dont_write_bytecode")) # revealed: bool
reveal_type(inspect.getattr_static(inspect, "getattr_static")) # revealed: Literal[getattr_static]
reveal_type(inspect.getattr_static(1, "real")) # revealed: property

View file

@ -1,23 +1,10 @@
# `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: LiteralString
```
## Explicit selection of `all` platforms
When `python-platform="all"` is specified, we fall back to the type of `sys.platform` declared in
typeshed:
```toml
[environment]
python-platform = "all"

View file

@ -195,24 +195,6 @@ if sys.platform == "win32":
sys.getwindowsversion()
```
##### Checking without a specified platform
If `python-platform` is not specified, we currently default to `all`:
```toml
[environment]
# python-platform not specified
```
```py
import sys
if sys.platform == "win32":
# TODO: we should not emit an error here
# error: [possibly-unbound-attribute]
sys.getwindowsversion()
```
## No (incorrect) diagnostics in unreachable code
```toml

View file

@ -1,7 +1,7 @@
use std::fmt::{Display, Formatter};
/// The target platform to assume when resolving types.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
@ -9,7 +9,6 @@ use std::fmt::{Display, Formatter};
)]
pub enum PythonPlatform {
/// Do not make any assumptions about the target platform.
#[default]
All,
/// Assume a specific target platform like `linux`, `darwin` or `win32`.
@ -39,6 +38,22 @@ impl Display for PythonPlatform {
}
}
impl Default for PythonPlatform {
fn default() -> Self {
if cfg!(target_os = "windows") {
PythonPlatform::Identifier("win32".to_string())
} else if cfg!(target_os = "macos") {
PythonPlatform::Identifier("darwin".to_string())
} else if cfg!(target_os = "android") {
PythonPlatform::Identifier("android".to_string())
} else if cfg!(target_os = "ios") {
PythonPlatform::Identifier("ios".to_string())
} else {
PythonPlatform::Identifier("linux".to_string())
}
}
}
#[cfg(feature = "schemars")]
mod schema {
use crate::PythonPlatform;

View file

@ -6,7 +6,7 @@ use config::SystemKind;
use parser as test_parser;
use red_knot_python_semantic::types::check_types;
use red_knot_python_semantic::{
Program, ProgramSettings, PythonPath, SearchPathSettings, SysPrefixPathOrigin,
Program, ProgramSettings, PythonPath, PythonPlatform, SearchPathSettings, SysPrefixPathOrigin,
};
use ruff_db::diagnostic::{create_parse_diagnostic, Diagnostic, DisplayDiagnosticConfig};
use ruff_db::files::{system_path_to_file, File};
@ -265,7 +265,9 @@ fn run_test(
let settings = ProgramSettings {
python_version,
python_platform: configuration.python_platform().unwrap_or_default(),
python_platform: configuration
.python_platform()
.unwrap_or(PythonPlatform::Identifier("linux".to_string())),
search_paths: SearchPathSettings {
src_roots: vec![src_path],
extra_paths: configuration.extra_paths().unwrap_or_default().to_vec(),