Skip to content

Commit 833be2e

Browse files
authored
[ty] Change environment.root to accept multiple paths (#18913)
1 parent 0194452 commit 833be2e

4 files changed

Lines changed: 39 additions & 28 deletions

File tree

crates/ty/docs/configuration.md

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ty/tests/cli/python_environment.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -972,9 +972,9 @@ fn src_root_deprecation_warning_with_environment_root() -> anyhow::Result<()> {
972972
r#"
973973
[tool.ty.src]
974974
root = "./src"
975-
975+
976976
[tool.ty.environment]
977-
root = "./app"
977+
root = ["./app"]
978978
"#,
979979
),
980980
("app/test.py", ""),
@@ -1012,9 +1012,9 @@ fn environment_root_takes_precedence_over_src_root() -> anyhow::Result<()> {
10121012
r#"
10131013
[tool.ty.src]
10141014
root = "./src"
1015-
1015+
10161016
[tool.ty.environment]
1017-
root = "./app"
1017+
root = ["./app"]
10181018
"#,
10191019
),
10201020
("src/test.py", "import my_module"),

crates/ty_project/src/metadata/options.rs

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -146,34 +146,36 @@ impl Options {
146146
let src = self.src.or_default();
147147

148148
#[allow(deprecated)]
149-
let src_roots = if let Some(src_root) = self
150-
.environment
151-
.as_ref()
152-
.and_then(|environment| environment.root.as_ref())
153-
.or_else(|| src.root.as_ref())
149+
let src_roots = if let Some(roots) = environment
150+
.root
151+
.as_deref()
152+
.or_else(|| Some(std::slice::from_ref(src.root.as_ref()?)))
154153
{
155-
vec![src_root.absolute(project_root, system)]
154+
roots
155+
.iter()
156+
.map(|root| root.absolute(project_root, system))
157+
.collect()
156158
} else {
157159
let src = project_root.join("src");
158160

159161
let mut roots = if system.is_directory(&src) {
160162
// Default to `src` and the project root if `src` exists and the root hasn't been specified.
161163
// This corresponds to the `src-layout`
162164
tracing::debug!(
163-
"Including `./src` in `src.root` because a `./src` directory exists"
165+
"Including `.` and `./src` in `environment.root` because a `./src` directory exists"
164166
);
165167
vec![project_root.to_path_buf(), src]
166168
} else if system.is_directory(&project_root.join(project_name).join(project_name)) {
167169
// `src-layout` but when the folder isn't called `src` but has the same name as the project.
168170
// For example, the "src" folder for `psycopg` is called `psycopg` and the python files are in `psycopg/psycopg/_adapters_map.py`
169171
tracing::debug!(
170-
"Including `./{project_name}` in `src.root` because a `./{project_name}/{project_name}` directory exists"
172+
"Including `.` and `/{project_name}` in `environment.root` because a `./{project_name}/{project_name}` directory exists"
171173
);
172174

173175
vec![project_root.to_path_buf(), project_root.join(project_name)]
174176
} else {
175177
// Default to a [flat project structure](https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/).
176-
tracing::debug!("Defaulting `src.root` to `.`");
178+
tracing::debug!("Including `.` in `environment.root`");
177179
vec![project_root.to_path_buf()]
178180
};
179181

@@ -186,7 +188,7 @@ impl Options {
186188
{
187189
// If the `tests` directory exists and is not a package, include it as a source root.
188190
tracing::debug!(
189-
"Including `./tests` in `src.root` because a `./tests` directory exists"
191+
"Including `./tests` in `environment.root` because a `./tests` directory exists"
190192
);
191193

192194
roots.push(tests_dir);
@@ -248,7 +250,7 @@ impl Options {
248250
let mut diagnostics = Vec::new();
249251
let rules = self.to_rule_selection(db, &mut diagnostics);
250252

251-
let terminal_options = self.terminal.clone().unwrap_or_default();
253+
let terminal_options = self.terminal.or_default();
252254
let terminal = TerminalSettings {
253255
output_format: terminal_options
254256
.output_format
@@ -329,7 +331,7 @@ impl Options {
329331
project_root: &SystemPath,
330332
diagnostics: &mut Vec<OptionDiagnostic>,
331333
) -> Result<Vec<Override>, Box<OptionDiagnostic>> {
332-
let override_options = self.overrides.as_deref().unwrap_or_default();
334+
let override_options = &**self.overrides.or_default();
333335

334336
let mut overrides = Vec::with_capacity(override_options.len());
335337

@@ -352,9 +354,11 @@ impl Options {
352354
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
353355
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
354356
pub struct EnvironmentOptions {
355-
/// The root of the project, used for finding first-party modules.
357+
/// The root paths of the project, used for finding first-party modules.
356358
///
357-
/// If left unspecified, ty will try to detect common project layouts and initialize `src.root` accordingly:
359+
/// Accepts a list of directory paths searched in priority order (first has highest priority).
360+
///
361+
/// If left unspecified, ty will try to detect common project layouts and initialize `root` accordingly:
358362
///
359363
/// * if a `./src` directory exists, include `.` and `./src` in the first party search path (src layout or flat)
360364
/// * if a `./<project-name>/<project-name>` directory exists, include `.` and `./<project-name>` in the first party search path
@@ -365,12 +369,13 @@ pub struct EnvironmentOptions {
365369
#[serde(skip_serializing_if = "Option::is_none")]
366370
#[option(
367371
default = r#"null"#,
368-
value_type = "str",
372+
value_type = "list[str]",
369373
example = r#"
370-
root = "./app"
374+
# Multiple directories (priority order)
375+
root = ["./src", "./lib", "./vendor"]
371376
"#
372377
)]
373-
pub root: Option<RelativePathBuf>,
378+
pub root: Option<Vec<RelativePathBuf>>,
374379

375380
/// Specifies the version of Python that will be used to analyze the source code.
376381
/// The version should be specified as a string in the format `M.m` where `M` is the major version

ty.schema.json

Lines changed: 6 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)