diff --git a/crates/red_knot/src/args.rs b/crates/red_knot/src/args.rs index 75b21f4cf25a9..233a081445a42 100644 --- a/crates/red_knot/src/args.rs +++ b/crates/red_knot/src/args.rs @@ -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, diff --git a/crates/red_knot_project/src/metadata/options.rs b/crates/red_knot_project/src/metadata/options.rs index 22b3d43f43b0e..d035f4cf7be5d 100644 --- a/crates/red_knot_project/src/metadata/options.rs +++ b/crates/red_knot_project/src/metadata/options.rs @@ -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>, diff --git a/crates/red_knot_python_semantic/resources/mdtest/call/getattr_static.md b/crates/red_knot_python_semantic/resources/mdtest/call/getattr_static.md index f781de4398c99..390fb565f81c5 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/getattr_static.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/getattr_static.md @@ -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 diff --git a/crates/red_knot_python_semantic/resources/mdtest/sys_platform.md b/crates/red_knot_python_semantic/resources/mdtest/sys_platform.md index 6c980b65c685b..1cf9410456f76 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/sys_platform.md +++ b/crates/red_knot_python_semantic/resources/mdtest/sys_platform.md @@ -1,23 +1,10 @@ # `sys.platform` -## Default value +## Explicit selection of `all` platforms -When no target platform is specified, we fall back to the type of `sys.platform` declared in +When `python-platform="all"` 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 - ```toml [environment] python-platform = "all" diff --git a/crates/red_knot_python_semantic/resources/mdtest/unreachable.md b/crates/red_knot_python_semantic/resources/mdtest/unreachable.md index 3f56372d97eef..9b185aee7a3da 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/unreachable.md +++ b/crates/red_knot_python_semantic/resources/mdtest/unreachable.md @@ -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 diff --git a/crates/red_knot_python_semantic/src/python_platform.rs b/crates/red_knot_python_semantic/src/python_platform.rs index e7650724baf83..5bef91f5559e9 100644 --- a/crates/red_knot_python_semantic/src/python_platform.rs +++ b/crates/red_knot_python_semantic/src/python_platform.rs @@ -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; diff --git a/crates/red_knot_test/src/lib.rs b/crates/red_knot_test/src/lib.rs index 41ed865ac2a6e..c31a68040a4fa 100644 --- a/crates/red_knot_test/src/lib.rs +++ b/crates/red_knot_test/src/lib.rs @@ -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(), diff --git a/knot.schema.json b/knot.schema.json index 2808a7df2e4ad..2d3f00b962d5f 100644 --- a/knot.schema.json +++ b/knot.schema.json @@ -89,7 +89,7 @@ ] }, "python-platform": { - "description": "Specifies the target platform that will be used to analyze the source code. If specified, Red Knot will tailor its use of type stub files, which conditionalize type definitions based on the platform.\n\nIf no platform is specified, knot will use `all` or the current platform in the LSP use case.", + "description": "Specifies the target platform that will be used to analyze the source code. If specified, Red Knot will tailor its use of type stub files, which conditionalize type definitions based on the platform.\n\nIf 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", "anyOf": [ { "$ref": "#/definitions/PythonPlatform"