Skip to content

Commit 767f0ee

Browse files
committed
[ty] Add --config-file
217
1 parent 4e68dd9 commit 767f0ee

File tree

12 files changed

+275
-63
lines changed

12 files changed

+275
-63
lines changed

crates/ruff_benchmark/benches/ty.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ fn setup_tomllib_case() -> Case {
7878

7979
let src_root = SystemPath::new("/src");
8080
let mut metadata = ProjectMetadata::discover(src_root, &system).unwrap();
81-
metadata.apply_cli_options(Options {
81+
metadata.apply_options(Options {
8282
environment: Some(EnvironmentOptions {
8383
python_version: Some(RangedValue::cli(PythonVersion::PY312)),
8484
..EnvironmentOptions::default()
@@ -224,7 +224,7 @@ fn setup_micro_case(code: &str) -> Case {
224224

225225
let src_root = SystemPath::new("/src");
226226
let mut metadata = ProjectMetadata::discover(src_root, &system).unwrap();
227-
metadata.apply_cli_options(Options {
227+
metadata.apply_options(Options {
228228
environment: Some(EnvironmentOptions {
229229
python_version: Some(RangedValue::cli(PythonVersion::PY312)),
230230
..EnvironmentOptions::default()

crates/ty/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ ty_server = { workspace = true }
2222

2323
anyhow = { workspace = true }
2424
argfile = { workspace = true }
25-
clap = { workspace = true, features = ["wrap_help", "string"] }
25+
clap = { workspace = true, features = ["wrap_help", "string", "env"] }
2626
clap_complete_command = { workspace = true }
2727
colored = { workspace = true }
2828
countme = { workspace = true, features = ["enable"] }

crates/ty/docs/cli.md

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

crates/ty/src/args.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ pub(crate) struct CheckCommand {
107107
#[clap(flatten)]
108108
pub(crate) config: ConfigsArg,
109109

110+
/// The path to a `ty.toml` file to use for configuration.
111+
///
112+
/// While ty configuration can be included in a `pyproject.toml` file, it is not allowed in this context.
113+
#[arg(long, env = "TY_CONFIG_FILE", value_name = "PATH")]
114+
pub(crate) config_file: Option<SystemPathBuf>,
115+
110116
/// The format to use for printing diagnostic messages.
111117
#[arg(long)]
112118
pub(crate) output_format: Option<OutputFormat>,

crates/ty/src/lib.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use ruff_db::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Severity};
2323
use ruff_db::max_parallelism;
2424
use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf};
2525
use salsa::plumbing::ZalsaDatabase;
26-
use ty_project::metadata::options::Options;
26+
use ty_project::metadata::options::ProjectOptionsOverrides;
2727
use ty_project::watch::ProjectWatcher;
2828
use ty_project::{Db, DummyReporter, Reporter, watch};
2929
use ty_project::{ProjectDatabase, ProjectMetadata};
@@ -102,13 +102,21 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
102102
.map(|path| SystemPath::absolute(path, &cwd))
103103
.collect();
104104

105-
let system = OsSystem::new(cwd);
105+
let system = OsSystem::new(&cwd);
106106
let watch = args.watch;
107107
let exit_zero = args.exit_zero;
108+
let config_file = args
109+
.config_file
110+
.as_ref()
111+
.map(|path| SystemPath::absolute(path, &cwd));
112+
113+
let mut project_metadata = match &config_file {
114+
Some(config_file) => ProjectMetadata::from_config_file(config_file.clone(), &system)?,
115+
None => ProjectMetadata::discover(&project_path, &system)?,
116+
};
108117

109-
let cli_options = args.into_options();
110-
let mut project_metadata = ProjectMetadata::discover(&project_path, &system)?;
111-
project_metadata.apply_cli_options(cli_options.clone());
118+
let options = args.into_options();
119+
project_metadata.apply_options(options.clone());
112120
project_metadata.apply_configuration_files(&system)?;
113121

114122
let mut db = ProjectDatabase::new(project_metadata, system)?;
@@ -117,7 +125,8 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
117125
db.project().set_included_paths(&mut db, check_paths);
118126
}
119127

120-
let (main_loop, main_loop_cancellation_token) = MainLoop::new(cli_options);
128+
let meta_options = ProjectOptionsOverrides::new(config_file, options);
129+
let (main_loop, main_loop_cancellation_token) = MainLoop::new(meta_options);
121130

122131
// Listen to Ctrl+C and abort the watch mode.
123132
let main_loop_cancellation_token = Mutex::new(Some(main_loop_cancellation_token));
@@ -178,19 +187,19 @@ struct MainLoop {
178187
/// The file system watcher, if running in watch mode.
179188
watcher: Option<ProjectWatcher>,
180189

181-
cli_options: Options,
190+
meta_options: ProjectOptionsOverrides,
182191
}
183192

184193
impl MainLoop {
185-
fn new(cli_options: Options) -> (Self, MainLoopCancellationToken) {
194+
fn new(meta_options: ProjectOptionsOverrides) -> (Self, MainLoopCancellationToken) {
186195
let (sender, receiver) = crossbeam_channel::bounded(10);
187196

188197
(
189198
Self {
190199
sender: sender.clone(),
191200
receiver,
192201
watcher: None,
193-
cli_options,
202+
meta_options,
194203
},
195204
MainLoopCancellationToken { sender },
196205
)
@@ -340,7 +349,7 @@ impl MainLoop {
340349
MainLoopMessage::ApplyChanges(changes) => {
341350
revision += 1;
342351
// Automatically cancels any pending queries and waits for them to complete.
343-
db.apply_changes(changes, Some(&self.cli_options));
352+
db.apply_changes(changes, Some(&self.meta_options));
344353
if let Some(watcher) = self.watcher.as_mut() {
345354
watcher.update(db);
346355
}

crates/ty/tests/cli.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,41 @@ fn check_conda_prefix_var_to_resolve_path() -> anyhow::Result<()> {
16291629
----- stderr -----
16301630
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
16311631
");
1632+
1633+
Ok(())
1634+
}
1635+
1636+
#[test]
1637+
fn config_file_override() -> anyhow::Result<()> {
1638+
let case = TestCase::with_files(vec![
1639+
("test.py", r"print(x) # [unresolved-reference]"),
1640+
(
1641+
"ty-override.toml",
1642+
r#"
1643+
[terminal]
1644+
error-on-warning = true
1645+
"#,
1646+
),
1647+
])?;
1648+
1649+
assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference").arg("--config-file").arg("ty-override.toml"), @r"
1650+
success: false
1651+
exit_code: 1
1652+
----- stdout -----
1653+
warning[unresolved-reference]: Name `x` used when not defined
1654+
--> test.py:1:7
1655+
|
1656+
1 | print(x) # [unresolved-reference]
1657+
| ^
1658+
|
1659+
info: rule `unresolved-reference` was selected on the command line
1660+
1661+
Found 1 diagnostic
1662+
1663+
----- stderr -----
1664+
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
1665+
");
1666+
16321667
Ok(())
16331668
}
16341669

0 commit comments

Comments
 (0)