diff --git a/crates/ruff_graph/src/db.rs b/crates/ruff_graph/src/db.rs index 9626b63b6d..06b3eca96c 100644 --- a/crates/ruff_graph/src/db.rs +++ b/crates/ruff_graph/src/db.rs @@ -9,8 +9,8 @@ use ruff_db::{Db as SourceDb, Upcast}; use ruff_python_ast::PythonVersion; use ty_python_semantic::lint::{LintRegistry, RuleSelection}; use ty_python_semantic::{ - Db, Program, ProgramSettings, PythonPath, PythonPlatform, SearchPathSettings, - default_lint_registry, + Db, Program, ProgramSettings, PythonPath, PythonPlatform, PythonVersionSource, + PythonVersionWithSource, SearchPathSettings, default_lint_registry, }; static EMPTY_VENDORED: std::sync::LazyLock = std::sync::LazyLock::new(|| { @@ -44,7 +44,10 @@ impl ModuleDb { Program::from_settings( &db, ProgramSettings { - python_version, + python_version: PythonVersionWithSource { + version: python_version, + source: PythonVersionSource::default(), + }, python_platform: PythonPlatform::default(), search_paths, }, diff --git a/crates/ty/docs/rules.md b/crates/ty/docs/rules.md index 5acf281cce..7cc1eb9ef0 100644 --- a/crates/ty/docs/rules.md +++ b/crates/ty/docs/rules.md @@ -50,7 +50,7 @@ Calling a non-callable object will raise a `TypeError` at runtime. ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L87) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L88) ## `conflicting-argument-forms` @@ -81,7 +81,7 @@ f(int) # error ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L118) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L119) ## `conflicting-declarations` @@ -111,7 +111,7 @@ a = 1 ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L144) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L145) ## `conflicting-metaclass` @@ -142,7 +142,7 @@ class C(A, B): ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L169) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L170) ## `cyclic-class-definition` @@ -173,7 +173,7 @@ class B(A): ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L195) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L196) ## `duplicate-base` @@ -199,7 +199,7 @@ class B(A, A): ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L239) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L240) ## `escape-character-in-forward-annotation` @@ -336,7 +336,7 @@ TypeError: multiple bases have instance lay-out conflict ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20incompatible-slots) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L260) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L261) ## `inconsistent-mro` @@ -365,7 +365,7 @@ class C(A, B): ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L346) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L347) ## `index-out-of-bounds` @@ -390,7 +390,7 @@ t[3] # IndexError: tuple index out of range ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L370) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L371) ## `invalid-argument-type` @@ -416,7 +416,7 @@ func("foo") # error: [invalid-argument-type] ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L390) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L391) ## `invalid-assignment` @@ -443,7 +443,7 @@ a: int = '' ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L430) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L431) ## `invalid-attribute-access` @@ -476,7 +476,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1336) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1337) ## `invalid-base` @@ -490,7 +490,7 @@ TODO #14889 ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L452) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L453) ## `invalid-context-manager` @@ -516,7 +516,7 @@ with 1: ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L461) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L462) ## `invalid-declaration` @@ -544,7 +544,7 @@ a: str ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L482) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L483) ## `invalid-exception-caught` @@ -585,7 +585,7 @@ except ZeroDivisionError: ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L505) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L506) ## `invalid-generic-class` @@ -616,7 +616,7 @@ class C[U](Generic[T]): ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L541) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L542) ## `invalid-legacy-type-variable` @@ -649,7 +649,7 @@ def f(t: TypeVar("U")): ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L567) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L568) ## `invalid-metaclass` @@ -681,7 +681,7 @@ class B(metaclass=f): ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L616) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L617) ## `invalid-overload` @@ -729,7 +729,7 @@ def foo(x: int) -> int: ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L643) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L644) ## `invalid-parameter-default` @@ -754,7 +754,7 @@ def f(a: int = ''): ... ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L686) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L687) ## `invalid-protocol` @@ -787,7 +787,7 @@ TypeError: Protocols can only inherit from other protocols, got ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L318) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L319) ## `invalid-raise` @@ -835,7 +835,7 @@ def g(): ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L706) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L707) ## `invalid-return-type` @@ -859,7 +859,7 @@ def func() -> int: ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L411) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L412) ## `invalid-super-argument` @@ -903,7 +903,7 @@ super(B, A) # error: `A` does not satisfy `issubclass(A, B)` ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L749) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L750) ## `invalid-syntax-in-forward-annotation` @@ -943,7 +943,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L595) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L596) ## `invalid-type-checking-constant` @@ -972,7 +972,7 @@ TYPE_CHECKING = '' ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L788) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L789) ## `invalid-type-form` @@ -1001,7 +1001,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L812) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L813) ## `invalid-type-variable-constraints` @@ -1035,7 +1035,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L836) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L837) ## `missing-argument` @@ -1059,7 +1059,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x' ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L865) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L866) ## `no-matching-overload` @@ -1087,7 +1087,7 @@ func("string") # error: [no-matching-overload] ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L884) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L885) ## `non-subscriptable` @@ -1110,7 +1110,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L907) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L908) ## `not-iterable` @@ -1135,7 +1135,7 @@ for i in 34: # TypeError: 'int' object is not iterable ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L925) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L926) ## `parameter-already-assigned` @@ -1161,7 +1161,7 @@ f(1, x=2) # Error raised here ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L976) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L977) ## `raw-string-type-annotation` @@ -1220,7 +1220,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1312) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1313) ## `subclass-of-final-class` @@ -1248,7 +1248,7 @@ class B(A): ... # Error raised here ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1067) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1068) ## `too-many-positional-arguments` @@ -1274,7 +1274,7 @@ f("foo") # Error raised here ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1112) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1113) ## `type-assertion-failure` @@ -1301,7 +1301,7 @@ def _(x: int): ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1090) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1091) ## `unavailable-implicit-super-arguments` @@ -1345,7 +1345,7 @@ class A: ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1133) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1134) ## `unknown-argument` @@ -1371,7 +1371,7 @@ f(x=1, y=2) # Error raised here ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1190) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1191) ## `unresolved-attribute` @@ -1398,7 +1398,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo' ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1211) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1212) ## `unresolved-import` @@ -1422,7 +1422,7 @@ import foo # ModuleNotFoundError: No module named 'foo' ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1233) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1234) ## `unresolved-reference` @@ -1446,7 +1446,7 @@ print(x) # NameError: name 'x' is not defined ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1252) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1253) ## `unsupported-bool-conversion` @@ -1482,7 +1482,7 @@ b1 < b2 < b1 # exception raised here ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L945) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L946) ## `unsupported-operator` @@ -1509,7 +1509,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A' ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1271) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1272) ## `zero-stepsize-in-slice` @@ -1533,7 +1533,7 @@ l[1:10:0] # ValueError: slice step cannot be zero ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1293) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1294) ## `call-possibly-unbound-method` @@ -1551,7 +1551,7 @@ Calling an unbound method will raise an `AttributeError` at runtime. ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-possibly-unbound-method) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L105) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L106) ## `invalid-ignore-comment` @@ -1607,7 +1607,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c' ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L997) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L998) ## `possibly-unbound-import` @@ -1638,7 +1638,7 @@ from module import a # ImportError: cannot import name 'a' from 'module' ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1019) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1020) ## `redundant-cast` @@ -1664,7 +1664,7 @@ cast(int, f()) # Redundant ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1364) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1365) ## `undefined-reveal` @@ -1687,7 +1687,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1172) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1173) ## `unknown-rule` @@ -1740,7 +1740,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime. ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L221) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L222) ## `possibly-unresolved-reference` @@ -1767,7 +1767,7 @@ print(x) # NameError: name 'x' is not defined ### Links * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference) -* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1045) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1046) ## `unused-ignore-comment` diff --git a/crates/ty/tests/cli.rs b/crates/ty/tests/cli.rs index f0e7e2c0ba..c0a510a143 100644 --- a/crates/ty/tests/cli.rs +++ b/crates/ty/tests/cli.rs @@ -241,6 +241,73 @@ fn config_override_python_platform() -> anyhow::Result<()> { Ok(()) } +#[test] +fn config_file_annotation_showing_where_python_version_set() -> anyhow::Result<()> { + let case = TestCase::with_files([ + ( + "pyproject.toml", + r#" + [tool.ty.environment] + python-version = "3.8" + "#, + ), + ( + "test.py", + r#" + aiter + "#, + ), + ])?; + + assert_cmd_snapshot!(case.command(), @r#" + success: false + exit_code: 1 + ----- stdout ----- + error[unresolved-reference]: Name `aiter` used when not defined + --> test.py:2:1 + | + 2 | aiter + | ^^^^^ + | + info: `aiter` was added as a builtin in Python 3.10 + info: Python 3.8 was assumed when resolving types + --> pyproject.toml:3:18 + | + 2 | [tool.ty.environment] + 3 | python-version = "3.8" + | ^^^^^ Python 3.8 assumed due to this configuration setting + | + info: rule `unresolved-reference` is enabled by default + + Found 1 diagnostic + + ----- stderr ----- + WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors. + "#); + + assert_cmd_snapshot!(case.command().arg("--python-version=3.9"), @r" + success: false + exit_code: 1 + ----- stdout ----- + error[unresolved-reference]: Name `aiter` used when not defined + --> test.py:2:1 + | + 2 | aiter + | ^^^^^ + | + info: `aiter` was added as a builtin in Python 3.10 + info: Python 3.9 was assumed when resolving types because it was specified on the command line + info: rule `unresolved-reference` is enabled by default + + Found 1 diagnostic + + ----- stderr ----- + WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors. + "); + + Ok(()) +} + /// Paths specified on the CLI are relative to the current working directory and not the project root. /// /// We test this by adding an extra search path from the CLI to the libs directory when diff --git a/crates/ty_ide/src/inlay_hints.rs b/crates/ty_ide/src/inlay_hints.rs index 263e56cbc9..4539b54308 100644 --- a/crates/ty_ide/src/inlay_hints.rs +++ b/crates/ty_ide/src/inlay_hints.rs @@ -158,9 +158,9 @@ mod tests { use crate::db::tests::TestDb; use ruff_db::system::{DbWithWritableSystem, SystemPathBuf}; - use ruff_python_ast::PythonVersion; use ty_python_semantic::{ - Program, ProgramSettings, PythonPath, PythonPlatform, SearchPathSettings, + Program, ProgramSettings, PythonPath, PythonPlatform, PythonVersionWithSource, + SearchPathSettings, }; pub(super) fn inlay_hint_test(source: &str) -> InlayHintTest { @@ -191,7 +191,7 @@ mod tests { Program::from_settings( &db, ProgramSettings { - python_version: PythonVersion::latest_ty(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings { extra_paths: vec![], diff --git a/crates/ty_ide/src/lib.rs b/crates/ty_ide/src/lib.rs index fe86113064..e403996788 100644 --- a/crates/ty_ide/src/lib.rs +++ b/crates/ty_ide/src/lib.rs @@ -207,10 +207,10 @@ mod tests { use ruff_db::diagnostic::{Diagnostic, DiagnosticFormat, DisplayDiagnosticConfig}; use ruff_db::files::{File, system_path_to_file}; use ruff_db::system::{DbWithWritableSystem, SystemPath, SystemPathBuf}; - use ruff_python_ast::PythonVersion; use ruff_text_size::TextSize; use ty_python_semantic::{ - Program, ProgramSettings, PythonPath, PythonPlatform, SearchPathSettings, + Program, ProgramSettings, PythonPath, PythonPlatform, PythonVersionWithSource, + SearchPathSettings, }; pub(super) fn cursor_test(source: &str) -> CursorTest { @@ -230,7 +230,7 @@ mod tests { Program::from_settings( &db, ProgramSettings { - python_version: PythonVersion::latest_ty(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings { extra_paths: vec![], diff --git a/crates/ty_project/src/lib.rs b/crates/ty_project/src/lib.rs index ae395ecfc0..bbe84382af 100644 --- a/crates/ty_project/src/lib.rs +++ b/crates/ty_project/src/lib.rs @@ -663,10 +663,11 @@ mod tests { use ruff_db::source::source_text; use ruff_db::system::{DbWithTestSystem, DbWithWritableSystem as _, SystemPath, SystemPathBuf}; use ruff_db::testing::assert_function_query_was_not_run; - use ruff_python_ast::PythonVersion; use ruff_python_ast::name::Name; use ty_python_semantic::types::check_types; - use ty_python_semantic::{Program, ProgramSettings, PythonPlatform, SearchPathSettings}; + use ty_python_semantic::{ + Program, ProgramSettings, PythonPlatform, PythonVersionWithSource, SearchPathSettings, + }; #[test] fn check_file_skips_type_checking_when_file_cant_be_read() -> ruff_db::system::Result<()> { @@ -677,7 +678,7 @@ mod tests { Program::from_settings( &db, ProgramSettings { - python_version: PythonVersion::default(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings::new(vec![SystemPathBuf::from(".")]), }, diff --git a/crates/ty_project/src/metadata/options.rs b/crates/ty_project/src/metadata/options.rs index f8c83ad5b4..00bab6dd95 100644 --- a/crates/ty_project/src/metadata/options.rs +++ b/crates/ty_project/src/metadata/options.rs @@ -10,7 +10,10 @@ use serde::{Deserialize, Serialize}; use std::fmt::Debug; use thiserror::Error; use ty_python_semantic::lint::{GetLintError, Level, LintSource, RuleSelection}; -use ty_python_semantic::{ProgramSettings, PythonPath, PythonPlatform, SearchPathSettings}; +use ty_python_semantic::{ + ProgramSettings, PythonPath, PythonPlatform, PythonVersionSource, PythonVersionWithSource, + SearchPathSettings, +}; use super::settings::{Settings, TerminalSettings}; @@ -93,8 +96,17 @@ impl Options { let python_version = self .environment .as_ref() - .and_then(|env| env.python_version.as_deref().copied()) - .unwrap_or(PythonVersion::latest_ty()); + .and_then(|env| env.python_version.as_ref()) + .map(|ranged_version| PythonVersionWithSource { + version: **ranged_version, + source: match ranged_version.source() { + ValueSource::Cli => PythonVersionSource::Cli, + ValueSource::File(path) => { + PythonVersionSource::File(path.clone(), ranged_version.range()) + } + }, + }) + .unwrap_or_default(); let python_platform = self .environment .as_ref() diff --git a/crates/ty_python_semantic/resources/mdtest/snapshots/annotations.md_-_Assignment_with_anno…_-_PEP-604_in_non-type-…_-_Earlier_versions_(f2859c9800f37c7).snap b/crates/ty_python_semantic/resources/mdtest/snapshots/annotations.md_-_Assignment_with_anno…_-_PEP-604_in_non-type-…_-_Earlier_versions_(f2859c9800f37c7).snap index c66ac9c49c..3cfe98c8f7 100644 --- a/crates/ty_python_semantic/resources/mdtest/snapshots/annotations.md_-_Assignment_with_anno…_-_PEP-604_in_non-type-…_-_Earlier_versions_(f2859c9800f37c7).snap +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/annotations.md_-_Assignment_with_anno…_-_PEP-604_in_non-type-…_-_Earlier_versions_(f2859c9800f37c7).snap @@ -27,8 +27,7 @@ error[unsupported-operator]: Operator `|` is unsupported between objects of type | ^^^^^^^^^ | info: Note that `X | Y` PEP 604 union syntax is only available in Python 3.10 and later -info: The inferred target version of your project is Python 3.9 -info: If using a pyproject.toml file, consider adjusting the `project.requires-python` or `tool.ty.environment.python-version` field +info: Python 3.9 was assumed when resolving types because it was specified on the command line info: rule `unsupported-operator` is enabled by default ``` diff --git a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_reference…_-_Diagnostics_for_unre…_-_New_builtin_used_on_…_(51edda0b1aebc2bf).snap b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_reference…_-_Diagnostics_for_unre…_-_New_builtin_used_on_…_(51edda0b1aebc2bf).snap index 4669867bfa..fd14c51a15 100644 --- a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_reference…_-_Diagnostics_for_unre…_-_New_builtin_used_on_…_(51edda0b1aebc2bf).snap +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_reference…_-_Diagnostics_for_unre…_-_New_builtin_used_on_…_(51edda0b1aebc2bf).snap @@ -25,8 +25,7 @@ error[unresolved-reference]: Name `aiter` used when not defined | ^^^^^ | info: `aiter` was added as a builtin in Python 3.10 -info: The inferred target version of your project is Python 3.9 -info: If using a pyproject.toml file, consider adjusting the `project.requires-python` or `tool.ty.environment.python-version` field +info: Python 3.9 was assumed when resolving types because it was specified on the command line info: rule `unresolved-reference` is enabled by default ``` diff --git a/crates/ty_python_semantic/src/db.rs b/crates/ty_python_semantic/src/db.rs index 451cde45e7..99e560905b 100644 --- a/crates/ty_python_semantic/src/db.rs +++ b/crates/ty_python_semantic/src/db.rs @@ -17,7 +17,10 @@ pub(crate) mod tests { use std::sync::{Arc, Mutex}; use crate::program::{Program, SearchPathSettings}; - use crate::{ProgramSettings, PythonPlatform, default_lint_registry}; + use crate::{ + ProgramSettings, PythonPlatform, PythonVersionSource, PythonVersionWithSource, + default_lint_registry, + }; use super::Db; use crate::lint::{LintRegistry, RuleSelection}; @@ -179,7 +182,10 @@ pub(crate) mod tests { Program::from_settings( &db, ProgramSettings { - python_version: self.python_version, + python_version: PythonVersionWithSource { + version: self.python_version, + source: PythonVersionSource::default(), + }, python_platform: self.python_platform, search_paths: SearchPathSettings::new(vec![src_root]), }, diff --git a/crates/ty_python_semantic/src/lib.rs b/crates/ty_python_semantic/src/lib.rs index 640b7cefb8..8857a48341 100644 --- a/crates/ty_python_semantic/src/lib.rs +++ b/crates/ty_python_semantic/src/lib.rs @@ -7,7 +7,10 @@ use crate::suppression::{INVALID_IGNORE_COMMENT, UNKNOWN_RULE, UNUSED_IGNORE_COM pub use db::Db; pub use module_name::ModuleName; pub use module_resolver::{KnownModule, Module, resolve_module, system_module_search_paths}; -pub use program::{Program, ProgramSettings, PythonPath, SearchPathSettings}; +pub use program::{ + Program, ProgramSettings, PythonPath, PythonVersionSource, PythonVersionWithSource, + SearchPathSettings, +}; pub use python_platform::PythonPlatform; pub use semantic_model::{HasType, SemanticModel}; pub use site_packages::SysPrefixPathOrigin; diff --git a/crates/ty_python_semantic/src/module_resolver/resolver.rs b/crates/ty_python_semantic/src/module_resolver/resolver.rs index d39edc57ca..49bf534e77 100644 --- a/crates/ty_python_semantic/src/module_resolver/resolver.rs +++ b/crates/ty_python_semantic/src/module_resolver/resolver.rs @@ -978,7 +978,7 @@ 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, PythonPlatform}; + use crate::{ProgramSettings, PythonPlatform, PythonVersionWithSource}; use super::*; @@ -1435,7 +1435,9 @@ mod tests { fn symlink() -> anyhow::Result<()> { use anyhow::Context; - use crate::{PythonPlatform, program::Program}; + use crate::{ + PythonPlatform, PythonVersionSource, PythonVersionWithSource, program::Program, + }; use ruff_db::system::{OsSystem, SystemPath}; use crate::db::tests::TestDb; @@ -1468,7 +1470,10 @@ mod tests { Program::from_settings( &db, ProgramSettings { - python_version: PythonVersion::PY38, + python_version: PythonVersionWithSource { + version: PythonVersion::PY38, + source: PythonVersionSource::default(), + }, python_platform: PythonPlatform::default(), search_paths: SearchPathSettings { extra_paths: vec![], @@ -1984,7 +1989,7 @@ not_a_directory Program::from_settings( &db, ProgramSettings { - python_version: PythonVersion::default(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings { extra_paths: vec![], @@ -2063,7 +2068,7 @@ not_a_directory Program::from_settings( &db, ProgramSettings { - python_version: PythonVersion::default(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings { extra_paths: vec![], @@ -2106,7 +2111,7 @@ not_a_directory Program::from_settings( &db, ProgramSettings { - python_version: PythonVersion::default(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings { extra_paths: vec![], diff --git a/crates/ty_python_semantic/src/module_resolver/testing.rs b/crates/ty_python_semantic/src/module_resolver/testing.rs index 75e0dfdc23..5f1e9c4b6e 100644 --- a/crates/ty_python_semantic/src/module_resolver/testing.rs +++ b/crates/ty_python_semantic/src/module_resolver/testing.rs @@ -6,7 +6,9 @@ use ruff_python_ast::PythonVersion; use crate::db::tests::TestDb; use crate::program::{Program, SearchPathSettings}; -use crate::{ProgramSettings, PythonPath, PythonPlatform}; +use crate::{ + ProgramSettings, PythonPath, PythonPlatform, PythonVersionSource, PythonVersionWithSource, +}; /// A test case for the module resolver. /// @@ -235,7 +237,10 @@ impl TestCaseBuilder { Program::from_settings( &db, ProgramSettings { - python_version, + python_version: PythonVersionWithSource { + version: python_version, + source: PythonVersionSource::default(), + }, python_platform, search_paths: SearchPathSettings { extra_paths: vec![], @@ -293,7 +298,10 @@ impl TestCaseBuilder { Program::from_settings( &db, ProgramSettings { - python_version, + python_version: PythonVersionWithSource { + version: python_version, + source: PythonVersionSource::default(), + }, python_platform, search_paths: SearchPathSettings { python_path: PythonPath::KnownSitePackages(vec![site_packages.clone()]), diff --git a/crates/ty_python_semantic/src/program.rs b/crates/ty_python_semantic/src/program.rs index f114a3e19a..74e662e355 100644 --- a/crates/ty_python_semantic/src/program.rs +++ b/crates/ty_python_semantic/src/program.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::Db; use crate::module_resolver::SearchPaths; use crate::python_platform::PythonPlatform; @@ -6,12 +8,14 @@ use crate::site_packages::SysPrefixPathOrigin; use anyhow::Context; use ruff_db::system::{SystemPath, SystemPathBuf}; use ruff_python_ast::PythonVersion; +use ruff_text_size::TextRange; use salsa::Durability; use salsa::Setter; #[salsa::input(singleton)] pub struct Program { - pub python_version: PythonVersion, + #[returns(ref)] + pub python_version_with_source: PythonVersionWithSource, #[returns(ref)] pub python_platform: PythonPlatform, @@ -23,23 +27,30 @@ pub struct Program { impl Program { pub fn from_settings(db: &dyn Db, settings: ProgramSettings) -> anyhow::Result { let ProgramSettings { - python_version, + python_version: python_version_with_source, python_platform, search_paths, } = settings; - tracing::info!("Python version: Python {python_version}, platform: {python_platform}"); + tracing::info!( + "Python version: Python {python_version}, platform: {python_platform}", + python_version = python_version_with_source.version + ); let search_paths = SearchPaths::from_settings(db, &search_paths) .with_context(|| "Invalid search path settings")?; Ok( - Program::builder(python_version, python_platform, search_paths) + Program::builder(python_version_with_source, python_platform, search_paths) .durability(Durability::HIGH) .new(db), ) } + pub fn python_version(self, db: &dyn Db) -> PythonVersion { + self.python_version_with_source(db).version + } + pub fn update_from_settings( self, db: &mut dyn Db, @@ -56,9 +67,9 @@ impl Program { self.set_python_platform(db).to(python_platform); } - if python_version != self.python_version(db) { - tracing::debug!("Updating python version: Python {python_version}"); - self.set_python_version(db).to(python_version); + if &python_version != self.python_version_with_source(db) { + tracing::debug!("Updating python version: `{python_version:?}`"); + self.set_python_version_with_source(db).to(python_version); } self.update_search_paths(db, &search_paths)?; @@ -87,13 +98,41 @@ impl Program { } #[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct ProgramSettings { - pub python_version: PythonVersion, + pub python_version: PythonVersionWithSource, pub python_platform: PythonPlatform, pub search_paths: SearchPathSettings, } +#[derive(Clone, Debug, Eq, PartialEq, Default)] +pub enum PythonVersionSource { + /// Value loaded from a project's configuration file. + File(Arc, Option), + + /// 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, + + /// We fell back to a default value because the value was not specified via the CLI or a config file. + #[default] + Default, +} + +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct PythonVersionWithSource { + pub version: PythonVersion, + pub source: PythonVersionSource, +} + +impl Default for PythonVersionWithSource { + fn default() -> Self { + Self { + version: PythonVersion::latest_ty(), + source: PythonVersionSource::Default, + } + } +} + /// Configures the search paths for module resolution. #[derive(Eq, PartialEq, Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize))] diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 22692f5696..da9ca6af97 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -2887,6 +2887,7 @@ mod tests { use super::*; use crate::db::tests::setup_db; use crate::module_resolver::resolve_module; + use crate::{PythonVersionSource, PythonVersionWithSource}; use salsa::Setter; use strum::IntoEnumIterator; @@ -2910,8 +2911,11 @@ mod tests { let mut db = setup_db(); Program::get(&db) - .set_python_version(&mut db) - .to(PythonVersion::latest_ty()); + .set_python_version_with_source(&mut db) + .to(PythonVersionWithSource { + version: PythonVersion::latest_ty(), + source: PythonVersionSource::default(), + }); for class in KnownClass::iter() { assert_ne!( @@ -2935,8 +2939,11 @@ mod tests { }; Program::get(&db) - .set_python_version(&mut db) - .to(version_added); + .set_python_version_with_source(&mut db) + .to(PythonVersionWithSource { + version: version_added, + source: PythonVersionSource::default(), + }); assert_ne!( class.to_instance(&db), diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index a9e6c6075c..e7ad9c76d5 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -11,8 +11,9 @@ use crate::types::string_annotation::{ RAW_STRING_TYPE_ANNOTATION, }; use crate::types::{KnownFunction, KnownInstanceType, Type, protocol_class::ProtocolClassLiteral}; -use crate::{Program, declare_lint}; -use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, SubDiagnostic}; +use crate::{Program, PythonVersionWithSource, declare_lint}; +use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, Span, SubDiagnostic}; +use ruff_db::files::system_path_to_file; use ruff_python_ast::{self as ast, AnyNodeRef}; use ruff_python_stdlib::builtins::version_builtin_was_added; use ruff_text_size::{Ranged, TextRange}; @@ -1670,15 +1671,41 @@ pub(super) fn report_possibly_unbound_attribute( } pub(super) fn add_inferred_python_version_hint(db: &dyn Db, mut diagnostic: LintDiagnosticGuard) { - diagnostic.info(format_args!( - "The inferred target version of your project is Python {}", - Program::get(db).python_version(db) - )); + let program = Program::get(db); + let PythonVersionWithSource { version, source } = program.python_version_with_source(db); - diagnostic.info( - "If using a pyproject.toml file, \ - consider adjusting the `project.requires-python` or `tool.ty.environment.python-version` field" - ); + match source { + crate::PythonVersionSource::Cli => { + diagnostic.info(format_args!( + "Python {version} was assumed when resolving types because it was specified on the command line", + )); + } + crate::PythonVersionSource::File(path, range) => { + if let Ok(file) = system_path_to_file(db.upcast(), &**path) { + let mut sub_diagnostic = SubDiagnostic::new( + Severity::Info, + format_args!("Python {version} was assumed when resolving types"), + ); + sub_diagnostic.annotate( + Annotation::primary(Span::from(file).with_optional_range(*range)).message( + format_args!("Python {version} assumed due to this configuration setting"), + ), + ); + diagnostic.sub(sub_diagnostic); + } else { + diagnostic.info(format_args!( + "Python {version} was assumed when resolving types because of your configuration file(s)", + )); + } + } + crate::PythonVersionSource::Default => { + diagnostic.info(format_args!( + "Python {version} was assumed when resolving types \ + because it is the newest Python version supported by ty, \ + and neither a command-line argument nor a configuration setting was provided", + )); + } + } } pub(super) fn report_unresolved_reference(context: &InferContext, expr_name_node: &ast::ExprName) { @@ -1692,9 +1719,6 @@ pub(super) fn report_unresolved_reference(context: &InferContext, expr_name_node diagnostic.info(format_args!( "`{id}` was added as a builtin in Python 3.{version_added_to_builtins}" )); - - // TODO: can we tell the user *why* we're inferring this target version? - // CLI flag? pyproject.toml? Python environment? add_inferred_python_version_hint(context.db(), diagnostic); } } diff --git a/crates/ty_test/src/assertion.rs b/crates/ty_test/src/assertion.rs index f342a16013..2e9bfd338c 100644 --- a/crates/ty_test/src/assertion.rs +++ b/crates/ty_test/src/assertion.rs @@ -493,16 +493,17 @@ mod tests { use super::*; use ruff_db::files::system_path_to_file; use ruff_db::system::DbWithWritableSystem as _; - use ruff_python_ast::PythonVersion; use ruff_python_trivia::textwrap::dedent; use ruff_source_file::OneIndexed; - use ty_python_semantic::{Program, ProgramSettings, PythonPlatform, SearchPathSettings}; + use ty_python_semantic::{ + Program, ProgramSettings, PythonPlatform, PythonVersionWithSource, SearchPathSettings, + }; fn get_assertions(source: &str) -> InlineFileAssertions { let mut db = Db::setup(); let settings = ProgramSettings { - python_version: PythonVersion::default(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings::new(Vec::new()), }; diff --git a/crates/ty_test/src/lib.rs b/crates/ty_test/src/lib.rs index 7773875377..8375bf2046 100644 --- a/crates/ty_test/src/lib.rs +++ b/crates/ty_test/src/lib.rs @@ -19,7 +19,8 @@ use std::backtrace::BacktraceStatus; use std::fmt::Write; use ty_python_semantic::types::check_types; use ty_python_semantic::{ - Program, ProgramSettings, PythonPath, PythonPlatform, SearchPathSettings, SysPrefixPathOrigin, + Program, ProgramSettings, PythonPath, PythonPlatform, PythonVersionSource, + PythonVersionWithSource, SearchPathSettings, SysPrefixPathOrigin, }; mod assertion; @@ -260,7 +261,10 @@ fn run_test( let configuration = test.configuration(); let settings = ProgramSettings { - python_version, + python_version: PythonVersionWithSource { + version: python_version, + source: PythonVersionSource::Cli, + }, python_platform: configuration .python_platform() .unwrap_or(PythonPlatform::Identifier("linux".to_string())), diff --git a/crates/ty_test/src/matcher.rs b/crates/ty_test/src/matcher.rs index e8094a6ce7..ff90010f78 100644 --- a/crates/ty_test/src/matcher.rs +++ b/crates/ty_test/src/matcher.rs @@ -341,11 +341,12 @@ mod tests { use ruff_db::diagnostic::{Annotation, Diagnostic, DiagnosticId, Severity, Span}; use ruff_db::files::{File, system_path_to_file}; use ruff_db::system::DbWithWritableSystem as _; - use ruff_python_ast::PythonVersion; use ruff_python_trivia::textwrap::dedent; use ruff_source_file::OneIndexed; use ruff_text_size::TextRange; - use ty_python_semantic::{Program, ProgramSettings, PythonPlatform, SearchPathSettings}; + use ty_python_semantic::{ + Program, ProgramSettings, PythonPlatform, PythonVersionWithSource, SearchPathSettings, + }; struct ExpectedDiagnostic { id: DiagnosticId, @@ -384,7 +385,7 @@ mod tests { let mut db = crate::db::Db::setup(); let settings = ProgramSettings { - python_version: PythonVersion::default(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings::new(Vec::new()), }; diff --git a/fuzz/fuzz_targets/ty_check_invalid_syntax.rs b/fuzz/fuzz_targets/ty_check_invalid_syntax.rs index 47b4dc5bef..dbc814644c 100644 --- a/fuzz/fuzz_targets/ty_check_invalid_syntax.rs +++ b/fuzz/fuzz_targets/ty_check_invalid_syntax.rs @@ -5,21 +5,21 @@ use std::sync::{Arc, Mutex, OnceLock}; -use libfuzzer_sys::{fuzz_target, Corpus}; +use libfuzzer_sys::{Corpus, fuzz_target}; -use ruff_db::files::{system_path_to_file, File, Files}; +use ruff_db::files::{File, Files, system_path_to_file}; use ruff_db::system::{ DbWithTestSystem, DbWithWritableSystem as _, System, SystemPathBuf, TestSystem, }; use ruff_db::vendored::VendoredFileSystem; use ruff_db::{Db as SourceDb, Upcast}; use ruff_python_ast::PythonVersion; -use ruff_python_parser::{parse_unchecked, Mode, ParseOptions}; +use ruff_python_parser::{Mode, ParseOptions, parse_unchecked}; use ty_python_semantic::lint::LintRegistry; use ty_python_semantic::types::check_types; use ty_python_semantic::{ - default_lint_registry, lint::RuleSelection, Db as SemanticDb, Program, ProgramSettings, - PythonPlatform, SearchPathSettings, + Db as SemanticDb, Program, ProgramSettings, PythonPlatform, SearchPathSettings, + default_lint_registry, lint::RuleSelection, PythonVersionWithSource, }; /// Database that can be used for testing. @@ -118,7 +118,7 @@ fn setup_db() -> TestDb { Program::from_settings( &db, ProgramSettings { - python_version: PythonVersion::default(), + python_version: PythonVersionWithSource::default(), python_platform: PythonPlatform::default(), search_paths: SearchPathSettings::new(vec![src_root]), },