Skip to content

Commit 0c61c94

Browse files
committed
[ty] Tell the user why we inferred the Python version we inferred
1 parent cfbb914 commit 0c61c94

File tree

22 files changed

+210
-45
lines changed

22 files changed

+210
-45
lines changed

crates/ruff_graph/src/db.rs

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ impl ModuleDb {
4545
&db,
4646
ProgramSettings {
4747
python_version,
48+
python_version_source: ty_python_semantic::ValueSource::default(),
4849
python_platform: PythonPlatform::default(),
4950
search_paths,
5051
},

crates/ty/tests/cli.rs

+66
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,72 @@ fn config_override_python_platform() -> anyhow::Result<()> {
241241
Ok(())
242242
}
243243

244+
#[test]
245+
fn config_file_annotation_showing_where_python_version_set() -> anyhow::Result<()> {
246+
let case = TestCase::with_files([
247+
(
248+
"pyproject.toml",
249+
r#"
250+
[tool.ty.environment]
251+
python-version = "3.8"
252+
"#,
253+
),
254+
(
255+
"test.py",
256+
r#"
257+
aiter
258+
"#,
259+
),
260+
])?;
261+
262+
assert_cmd_snapshot!(case.command(), @r#"
263+
success: false
264+
exit_code: 1
265+
----- stdout -----
266+
error[unresolved-reference]: Name `aiter` used when not defined
267+
--> test.py:2:1
268+
|
269+
2 | aiter
270+
| ^^^^^
271+
|
272+
info: `aiter` was added as a builtin in Python 3.10, but Python 3.8 was assumed when resolving types
273+
--> pyproject.toml:3:18
274+
|
275+
2 | [tool.ty.environment]
276+
3 | python-version = "3.8"
277+
| ^^^^^ Python 3.8 assumed due to this configuration setting
278+
|
279+
info: rule `unresolved-reference` is enabled by default
280+
281+
Found 1 diagnostic
282+
283+
----- stderr -----
284+
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
285+
"#);
286+
287+
assert_cmd_snapshot!(case.command().arg("--python-version=3.9"), @r"
288+
success: false
289+
exit_code: 1
290+
----- stdout -----
291+
error[unresolved-reference]: Name `aiter` used when not defined
292+
--> test.py:2:1
293+
|
294+
2 | aiter
295+
| ^^^^^
296+
|
297+
info: `aiter` was added as a builtin in Python 3.10, but Python 3.9 was assumed when resolving types
298+
info: This is because Python 3.9 was specified on the command line
299+
info: rule `unresolved-reference` is enabled by default
300+
301+
Found 1 diagnostic
302+
303+
----- stderr -----
304+
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
305+
");
306+
307+
Ok(())
308+
}
309+
244310
/// Paths specified on the CLI are relative to the current working directory and not the project root.
245311
///
246312
/// We test this by adding an extra search path from the CLI to the libs directory when

crates/ty/tests/file_watching.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -392,19 +392,24 @@ where
392392
let mut project = ProjectMetadata::discover(&project_path, &system)?;
393393
project.apply_configuration_files(&system)?;
394394

395-
let program_settings = project.to_program_settings(&system);
396-
397-
for path in program_settings
398-
.search_paths
399-
.extra_paths
400-
.iter()
401-
.chain(program_settings.search_paths.custom_typeshed.as_ref())
395+
let environment_options = project.options().environment.as_ref();
396+
397+
for path in environment_options
398+
.and_then(|env| env.extra_paths.as_ref())
399+
.into_iter()
400+
.flatten()
401+
.chain(
402+
environment_options
403+
.as_ref()
404+
.and_then(|env| env.python.as_ref()),
405+
)
406+
.chain(environment_options.and_then(|env| env.typeshed.as_ref()))
402407
{
403-
std::fs::create_dir_all(path.as_std_path())
404-
.with_context(|| format!("Failed to create search path `{path}`"))?;
408+
std::fs::create_dir_all(path.path().as_std_path())
409+
.with_context(|| format!("Failed to create search path `{}`", path.path()))?;
405410
}
406411

407-
let mut db = ProjectDatabase::new(project, system)?;
412+
let mut db = ProjectDatabase::new(project.clone(), system)?;
408413

409414
if let Some(included_paths) = included_paths {
410415
db.project().set_included_paths(&mut db, included_paths);

crates/ty_ide/src/inlay_hints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ mod tests {
192192
&db,
193193
ProgramSettings {
194194
python_version: PythonVersion::latest_ty(),
195+
python_version_source: ty_python_semantic::ValueSource::default(),
195196
python_platform: PythonPlatform::default(),
196197
search_paths: SearchPathSettings {
197198
extra_paths: vec![],

crates/ty_ide/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ mod tests {
229229
&db,
230230
ProgramSettings {
231231
python_version: PythonVersion::latest_ty(),
232+
python_version_source: ty_python_semantic::ValueSource::default(),
232233
python_platform: PythonPlatform::default(),
233234
search_paths: SearchPathSettings {
234235
extra_paths: vec![],

crates/ty_project/src/db.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl ProjectDatabase {
5959
// we may want to have a dedicated method for this?
6060

6161
// Initialize the `Program` singleton
62-
let program_settings = project_metadata.to_program_settings(db.system());
62+
let program_settings = project_metadata.to_program_settings(&db);
6363
Program::from_settings(&db, program_settings)?;
6464

6565
db.project = Some(Project::from_metadata(&db, project_metadata));

crates/ty_project/src/db/changes.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl ProjectDatabase {
182182
);
183183
}
184184

185-
let program_settings = metadata.to_program_settings(self.system());
185+
let program_settings = metadata.to_program_settings(self);
186186

187187
let program = Program::get(self);
188188
if let Err(error) = program.update_from_settings(self, program_settings) {
@@ -209,7 +209,7 @@ impl ProjectDatabase {
209209
} else if custom_stdlib_change {
210210
let search_paths = project
211211
.metadata(self)
212-
.to_program_settings(self.system())
212+
.to_program_settings(self)
213213
.search_paths;
214214

215215
if let Err(error) = program.update_search_paths(self, &search_paths) {

crates/ty_project/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ mod tests {
680680
&db,
681681
ProgramSettings {
682682
python_version: PythonVersion::default(),
683+
python_version_source: ty_python_semantic::ValueSource::default(),
683684
python_platform: PythonPlatform::default(),
684685
search_paths: SearchPathSettings::new(vec![SystemPathBuf::from(".")]),
685686
},

crates/ty_project/src/metadata.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub mod pyproject;
1717
pub mod settings;
1818
pub mod value;
1919

20-
#[derive(Debug, PartialEq, Eq)]
20+
#[derive(Debug, PartialEq, Eq, Clone)]
2121
#[cfg_attr(test, derive(serde::Serialize))]
2222
pub struct ProjectMetadata {
2323
pub(super) name: Name,
@@ -239,8 +239,8 @@ impl ProjectMetadata {
239239
&self.extra_configuration_paths
240240
}
241241

242-
pub fn to_program_settings(&self, system: &dyn System) -> ProgramSettings {
243-
self.options.to_program_settings(self.root(), system)
242+
pub fn to_program_settings(&self, db: &dyn crate::Db) -> ProgramSettings {
243+
self.options.to_program_settings(db, self.root())
244244
}
245245

246246
/// Combine the project options with the CLI options where the CLI options take precedence.

crates/ty_project/src/metadata/options.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,29 @@ impl Options {
8686

8787
pub(crate) fn to_program_settings(
8888
&self,
89+
db: &dyn crate::Db,
8990
project_root: &SystemPath,
90-
system: &dyn System,
9191
) -> ProgramSettings {
92-
let python_version = self
92+
let (python_version, python_version_source) = self
9393
.environment
9494
.as_ref()
95-
.and_then(|env| env.python_version.as_deref().copied())
96-
.unwrap_or(PythonVersion::latest_ty());
95+
.and_then(|env| env.python_version.as_ref())
96+
.map(|ranged_version| {
97+
(
98+
ranged_version.inner_copied(),
99+
match ranged_version.source() {
100+
ValueSource::Cli => ty_python_semantic::ValueSource::Cli,
101+
ValueSource::File(path) => ty_python_semantic::ValueSource::File(
102+
system_path_to_file(db, &**path).ok(),
103+
ranged_version.range(),
104+
),
105+
},
106+
)
107+
})
108+
.unwrap_or((
109+
PythonVersion::latest_ty(),
110+
ty_python_semantic::ValueSource::default(),
111+
));
97112
let python_platform = self
98113
.environment
99114
.as_ref()
@@ -105,8 +120,9 @@ impl Options {
105120
});
106121
ProgramSettings {
107122
python_version,
123+
python_version_source,
108124
python_platform,
109-
search_paths: self.to_search_path_settings(project_root, system),
125+
search_paths: self.to_search_path_settings(project_root, db.system()),
110126
}
111127
}
112128

crates/ty_project/src/metadata/value.rs

+9
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ impl<T> RangedValue<T> {
133133
}
134134
}
135135

136+
impl<T> RangedValue<T>
137+
where
138+
T: Copy,
139+
{
140+
pub fn inner_copied(&self) -> T {
141+
self.value
142+
}
143+
}
144+
136145
impl<T> Combine for RangedValue<T> {
137146
fn combine(self, _other: Self) -> Self
138147
where

crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_reference…_-_Diagnostics_for_unre…_-_New_builtin_used_on_…_(51edda0b1aebc2bf).snap

+2-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ error[unresolved-reference]: Name `aiter` used when not defined
2424
1 | aiter # error: [unresolved-reference]
2525
| ^^^^^
2626
|
27-
info: `aiter` was added as a builtin in Python 3.10
28-
info: The inferred target version of your project is Python 3.9
29-
info: If using a pyproject.toml file, consider adjusting the `project.requires-python` or `tool.ty.environment.python-version` field
27+
info: `aiter` was added as a builtin in Python 3.10, but Python 3.9 was assumed when resolving types
28+
info: This is because Python 3.9 was specified on the command line
3029
info: rule `unresolved-reference` is enabled by default
3130
3231
```

crates/ty_python_semantic/src/db.rs

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ pub(crate) mod tests {
180180
&db,
181181
ProgramSettings {
182182
python_version: self.python_version,
183+
python_version_source: crate::ValueSource::default(),
183184
python_platform: self.python_platform,
184185
search_paths: SearchPathSettings::new(vec![src_root]),
185186
},

crates/ty_python_semantic/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::suppression::{INVALID_IGNORE_COMMENT, UNKNOWN_RULE, UNUSED_IGNORE_COM
77
pub use db::Db;
88
pub use module_name::ModuleName;
99
pub use module_resolver::{resolve_module, system_module_search_paths, KnownModule, Module};
10-
pub use program::{Program, ProgramSettings, PythonPath, SearchPathSettings};
10+
pub use program::{Program, ProgramSettings, PythonPath, SearchPathSettings, ValueSource};
1111
pub use python_platform::PythonPlatform;
1212
pub use semantic_model::{HasType, SemanticModel};
1313
pub use site_packages::SysPrefixPathOrigin;

crates/ty_python_semantic/src/module_resolver/resolver.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,7 @@ mod tests {
14901490
&db,
14911491
ProgramSettings {
14921492
python_version: PythonVersion::PY38,
1493+
python_version_source: crate::ValueSource::default(),
14931494
python_platform: PythonPlatform::default(),
14941495
search_paths: SearchPathSettings {
14951496
extra_paths: vec![],
@@ -1996,6 +1997,7 @@ not_a_directory
19961997
&db,
19971998
ProgramSettings {
19981999
python_version: PythonVersion::default(),
2000+
python_version_source: crate::ValueSource::default(),
19992001
python_platform: PythonPlatform::default(),
20002002
search_paths: SearchPathSettings {
20012003
extra_paths: vec![],
@@ -2069,6 +2071,7 @@ not_a_directory
20692071
&db,
20702072
ProgramSettings {
20712073
python_version: PythonVersion::default(),
2074+
python_version_source: crate::ValueSource::default(),
20722075
python_platform: PythonPlatform::default(),
20732076
search_paths: SearchPathSettings {
20742077
extra_paths: vec![],
@@ -2109,6 +2112,7 @@ not_a_directory
21092112
&db,
21102113
ProgramSettings {
21112114
python_version: PythonVersion::default(),
2115+
python_version_source: crate::ValueSource::default(),
21122116
python_platform: PythonPlatform::default(),
21132117
search_paths: SearchPathSettings {
21142118
extra_paths: vec![],

crates/ty_python_semantic/src/module_resolver/testing.rs

+2
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ impl TestCaseBuilder<MockedTypeshed> {
236236
&db,
237237
ProgramSettings {
238238
python_version,
239+
python_version_source: crate::ValueSource::default(),
239240
python_platform,
240241
search_paths: SearchPathSettings {
241242
extra_paths: vec![],
@@ -294,6 +295,7 @@ impl TestCaseBuilder<VendoredTypeshed> {
294295
&db,
295296
ProgramSettings {
296297
python_version,
298+
python_version_source: crate::ValueSource::default(),
297299
python_platform,
298300
search_paths: SearchPathSettings {
299301
python_path: PythonPath::KnownSitePackages(vec![site_packages.clone()]),

0 commit comments

Comments
 (0)