Skip to content

Commit 97d0659

Browse files
authored
Pass ParserOptions to the parser (#16220)
## Summary This is part of the preparation for detecting syntax errors in the parser from #16090. As suggested in [this comment](#16090), I started working on a `ParseOptions` struct that could be stored in the parser. For this initial refactor, I only made it hold the existing `Mode` option, but for syntax errors, we will also need it to have a `PythonVersion`. For that use case, I'm picturing something like a `ParseOptions::with_python_version` method, so you can extend the current calls to something like ```rust ParseOptions::from(mode).with_python_version(settings.target_version) ``` But I thought it was worth adding `ParseOptions` alone without changing any other behavior first. Most of the diff is just updating call sites taking `Mode` to take `ParseOptions::from(Mode)` or those taking `PySourceType`s to take `ParseOptions::from(PySourceType)`. The interesting changes are in the new `parser/options.rs` file and smaller parts of `parser/mod.rs` and `ruff_python_parser/src/lib.rs`. ## Test Plan Existing tests, this should not change any behavior.
1 parent cfc6941 commit 97d0659

File tree

25 files changed

+148
-93
lines changed

25 files changed

+148
-93
lines changed

crates/ruff_benchmark/benches/formatter.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use ruff_benchmark::{
88
TestCase, LARGE_DATASET, NUMPY_CTYPESLIB, NUMPY_GLOBALS, PYDANTIC_TYPES, UNICODE_PYPINYIN,
99
};
1010
use ruff_python_formatter::{format_module_ast, PreviewMode, PyFormatOptions};
11-
use ruff_python_parser::{parse, Mode};
11+
use ruff_python_parser::{parse, Mode, ParseOptions};
1212
use ruff_python_trivia::CommentRanges;
1313

1414
#[cfg(target_os = "windows")]
@@ -48,8 +48,8 @@ fn benchmark_formatter(criterion: &mut Criterion) {
4848
&case,
4949
|b, case| {
5050
// Parse the source.
51-
let parsed =
52-
parse(case.code(), Mode::Module).expect("Input should be a valid Python code");
51+
let parsed = parse(case.code(), ParseOptions::from(Mode::Module))
52+
.expect("Input should be a valid Python code");
5353

5454
let comment_ranges = CommentRanges::from(parsed.tokens());
5555

crates/ruff_dev/src/print_ast.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use anyhow::Result;
77

88
use ruff_linter::source_kind::SourceKind;
99
use ruff_python_ast::PySourceType;
10-
use ruff_python_parser::{parse, AsMode};
10+
use ruff_python_parser::{parse, ParseOptions};
1111

1212
#[derive(clap::Args)]
1313
pub(crate) struct Args {
@@ -24,7 +24,8 @@ pub(crate) fn main(args: &Args) -> Result<()> {
2424
args.file.display()
2525
)
2626
})?;
27-
let python_ast = parse(source_kind.source_code(), source_type.as_mode())?.into_syntax();
27+
let python_ast =
28+
parse(source_kind.source_code(), ParseOptions::from(source_type))?.into_syntax();
2829
println!("{python_ast:#?}");
2930
Ok(())
3031
}

crates/ruff_graph/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use anyhow::Result;
44

55
use ruff_db::system::{SystemPath, SystemPathBuf};
66
use ruff_python_ast::helpers::to_module_path;
7-
use ruff_python_parser::{parse, Mode};
7+
use ruff_python_parser::{parse, Mode, ParseOptions};
88

99
use crate::collector::Collector;
1010
pub use crate::db::ModuleDb;
@@ -30,7 +30,7 @@ impl ModuleImports {
3030
) -> Result<Self> {
3131
// Read and parse the source code.
3232
let source = std::fs::read_to_string(path)?;
33-
let parsed = parse(&source, Mode::Module)?;
33+
let parsed = parse(&source, ParseOptions::from(Mode::Module))?;
3434

3535
let module_path =
3636
package.and_then(|package| to_module_path(package.as_std_path(), path.as_std_path()));

crates/ruff_linter/src/message/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ mod tests {
309309

310310
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Edit, Fix};
311311
use ruff_notebook::NotebookIndex;
312-
use ruff_python_parser::{parse_unchecked, Mode};
312+
use ruff_python_parser::{parse_unchecked, Mode, ParseOptions};
313313
use ruff_source_file::{OneIndexed, SourceFileBuilder};
314314
use ruff_text_size::{Ranged, TextRange, TextSize};
315315

@@ -325,7 +325,7 @@ if call(foo
325325
";
326326
let locator = Locator::new(source);
327327
let source_file = SourceFileBuilder::new("syntax_errors.py", source).finish();
328-
parse_unchecked(source, Mode::Module)
328+
parse_unchecked(source, ParseOptions::from(Mode::Module))
329329
.errors()
330330
.iter()
331331
.map(|parse_error| {

crates/ruff_python_ast_integration_tests/tests/source_order.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use insta::assert_snapshot;
44

55
use ruff_python_ast::visitor::source_order::{SourceOrderVisitor, TraversalSignal};
66
use ruff_python_ast::{AnyNodeRef, BoolOp, CmpOp, Operator, Singleton, UnaryOp};
7-
use ruff_python_parser::{parse, Mode};
7+
use ruff_python_parser::{parse, Mode, ParseOptions};
88

99
#[test]
1010
fn function_arguments() {
@@ -147,7 +147,7 @@ fn f_strings() {
147147
}
148148

149149
fn trace_source_order_visitation(source: &str) -> String {
150-
let parsed = parse(source, Mode::Module).unwrap();
150+
let parsed = parse(source, ParseOptions::from(Mode::Module)).unwrap();
151151

152152
let mut visitor = RecordVisitor::default();
153153
visitor.visit_mod(parsed.syntax());

crates/ruff_python_ast_integration_tests/tests/visitor.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use ruff_python_ast::{
1313
Expr, FString, FStringElement, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern,
1414
Stmt, StringLiteral, TypeParam, UnaryOp, WithItem,
1515
};
16-
use ruff_python_parser::{parse, Mode};
16+
use ruff_python_parser::{parse, Mode, ParseOptions};
1717

1818
#[test]
1919
fn function_arguments() {
@@ -156,7 +156,7 @@ fn f_strings() {
156156
}
157157

158158
fn trace_visitation(source: &str) -> String {
159-
let parsed = parse(source, Mode::Module).unwrap();
159+
let parsed = parse(source, ParseOptions::from(Mode::Module)).unwrap();
160160

161161
let mut visitor = RecordVisitor::default();
162162
walk_module(&mut visitor, parsed.syntax());

crates/ruff_python_codegen/src/generator.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1435,7 +1435,7 @@ impl<'a> Generator<'a> {
14351435
#[cfg(test)]
14361436
mod tests {
14371437
use ruff_python_ast::{Mod, ModModule};
1438-
use ruff_python_parser::{self, parse_module, Mode};
1438+
use ruff_python_parser::{self, parse_module, Mode, ParseOptions};
14391439
use ruff_source_file::LineEnding;
14401440

14411441
use crate::stylist::Indentation;
@@ -1467,7 +1467,8 @@ mod tests {
14671467
fn jupyter_round_trip(contents: &str) -> String {
14681468
let indentation = Indentation::default();
14691469
let line_ending = LineEnding::default();
1470-
let parsed = ruff_python_parser::parse(contents, Mode::Ipython).unwrap();
1470+
let parsed =
1471+
ruff_python_parser::parse(contents, ParseOptions::from(Mode::Ipython)).unwrap();
14711472
let Mod::Module(ModModule { body, .. }) = parsed.into_syntax() else {
14721473
panic!("Source code didn't return ModModule")
14731474
};

crates/ruff_python_codegen/src/stylist.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl Deref for Indentation {
148148

149149
#[cfg(test)]
150150
mod tests {
151-
use ruff_python_parser::{parse_module, parse_unchecked, Mode};
151+
use ruff_python_parser::{parse_module, parse_unchecked, Mode, ParseOptions};
152152
use ruff_source_file::{find_newline, LineEnding};
153153

154154
use super::{Indentation, Quote, Stylist};
@@ -215,7 +215,7 @@ x = (
215215
 3,
216216
)
217217
";
218-
let parsed = parse_unchecked(contents, Mode::Module);
218+
let parsed = parse_unchecked(contents, ParseOptions::from(Mode::Module));
219219
assert_eq!(
220220
Stylist::from_tokens(parsed.tokens(), contents).indentation(),
221221
&Indentation(" ".to_string())

crates/ruff_python_formatter/src/cli.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use clap::{command, Parser, ValueEnum};
77

88
use ruff_formatter::SourceCode;
99
use ruff_python_ast::PySourceType;
10-
use ruff_python_parser::{parse, AsMode};
10+
use ruff_python_parser::{parse, ParseOptions};
1111
use ruff_python_trivia::CommentRanges;
1212
use ruff_text_size::Ranged;
1313

@@ -48,7 +48,7 @@ pub fn format_and_debug_print(source: &str, cli: &Cli, source_path: &Path) -> Re
4848
let source_type = PySourceType::from(source_path);
4949

5050
// Parse the AST.
51-
let parsed = parse(source, source_type.as_mode()).context("Syntax error in input")?;
51+
let parsed = parse(source, ParseOptions::from(source_type)).context("Syntax error in input")?;
5252

5353
let options = PyFormatOptions::from_extension(source_path)
5454
.with_preview(if cli.preview {

crates/ruff_python_formatter/src/comments/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ mod tests {
514514

515515
use ruff_formatter::SourceCode;
516516
use ruff_python_ast::{Mod, PySourceType};
517-
use ruff_python_parser::{parse, AsMode, Parsed};
517+
use ruff_python_parser::{parse, ParseOptions, Parsed};
518518
use ruff_python_trivia::CommentRanges;
519519

520520
use crate::comments::Comments;
@@ -529,8 +529,8 @@ mod tests {
529529
fn from_code(source: &'a str) -> Self {
530530
let source_code = SourceCode::new(source);
531531
let source_type = PySourceType::Python;
532-
let parsed =
533-
parse(source, source_type.as_mode()).expect("Expect source to be valid Python");
532+
let parsed = parse(source, ParseOptions::from(source_type))
533+
.expect("Expect source to be valid Python");
534534
let comment_ranges = CommentRanges::from(parsed.tokens());
535535

536536
CommentsTestCase {

crates/ruff_python_formatter/src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub use range::format_range;
55
use ruff_formatter::prelude::*;
66
use ruff_formatter::{format, write, FormatError, Formatted, PrintError, Printed, SourceCode};
77
use ruff_python_ast::{AnyNodeRef, Mod};
8-
use ruff_python_parser::{parse, AsMode, ParseError, Parsed};
8+
use ruff_python_parser::{parse, ParseError, ParseOptions, Parsed};
99
use ruff_python_trivia::CommentRanges;
1010
use ruff_text_size::Ranged;
1111

@@ -112,7 +112,7 @@ pub fn format_module_source(
112112
options: PyFormatOptions,
113113
) -> Result<Printed, FormatModuleError> {
114114
let source_type = options.source_type();
115-
let parsed = parse(source, source_type.as_mode())?;
115+
let parsed = parse(source, ParseOptions::from(source_type))?;
116116
let comment_ranges = CommentRanges::from(parsed.tokens());
117117
let formatted = format_module_ast(&parsed, &comment_ranges, source, options)?;
118118
Ok(formatted.print()?)
@@ -154,7 +154,7 @@ mod tests {
154154
use insta::assert_snapshot;
155155

156156
use ruff_python_ast::PySourceType;
157-
use ruff_python_parser::{parse, AsMode};
157+
use ruff_python_parser::{parse, ParseOptions};
158158
use ruff_python_trivia::CommentRanges;
159159
use ruff_text_size::{TextRange, TextSize};
160160

@@ -199,7 +199,7 @@ def main() -> None:
199199

200200
// Parse the AST.
201201
let source_path = "code_inline.py";
202-
let parsed = parse(source, source_type.as_mode()).unwrap();
202+
let parsed = parse(source, ParseOptions::from(source_type)).unwrap();
203203
let comment_ranges = CommentRanges::from(parsed.tokens());
204204
let options = PyFormatOptions::from_extension(Path::new(source_path));
205205
let formatted = format_module_ast(&parsed, &comment_ranges, source, options).unwrap();

crates/ruff_python_formatter/src/range.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use ruff_formatter::{
66
};
77
use ruff_python_ast::visitor::source_order::{walk_body, SourceOrderVisitor, TraversalSignal};
88
use ruff_python_ast::{AnyNodeRef, Stmt, StmtMatch, StmtTry};
9-
use ruff_python_parser::{parse, AsMode};
9+
use ruff_python_parser::{parse, ParseOptions};
1010
use ruff_python_trivia::{
1111
indentation_at_offset, BackwardsTokenizer, CommentRanges, SimpleToken, SimpleTokenKind,
1212
};
@@ -73,7 +73,7 @@ pub fn format_range(
7373

7474
assert_valid_char_boundaries(range, source);
7575

76-
let parsed = parse(source, options.source_type().as_mode())?;
76+
let parsed = parse(source, ParseOptions::from(options.source_type()))?;
7777
let source_code = SourceCode::new(source);
7878
let comment_ranges = CommentRanges::from(parsed.tokens());
7979
let comments = Comments::from_ast(parsed.syntax(), source_code, &comment_ranges);

crates/ruff_python_formatter/src/string/docstring.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use regex::Regex;
1111

1212
use ruff_formatter::printer::SourceMapGeneration;
1313
use ruff_python_ast::{str::Quote, AnyStringFlags, StringFlags};
14+
use ruff_python_parser::ParseOptions;
1415
use ruff_python_trivia::CommentRanges;
1516
use {
1617
ruff_formatter::{write, FormatOptions, IndentStyle, LineWidth, Printed},
@@ -492,8 +493,6 @@ impl<'src> DocstringLinePrinter<'_, '_, '_, 'src> {
492493
&mut self,
493494
kind: &mut CodeExampleKind<'_>,
494495
) -> FormatResult<Option<Vec<OutputDocstringLine<'static>>>> {
495-
use ruff_python_parser::AsMode;
496-
497496
let line_width = match self.f.options().docstring_code_line_width() {
498497
DocstringCodeLineWidth::Fixed(width) => width,
499498
DocstringCodeLineWidth::Dynamic => {
@@ -570,7 +569,8 @@ impl<'src> DocstringLinePrinter<'_, '_, '_, 'src> {
570569
std::format!(r#""""{}""""#, printed.as_code())
571570
}
572571
};
573-
let result = ruff_python_parser::parse(&wrapped, self.f.options().source_type().as_mode());
572+
let result =
573+
ruff_python_parser::parse(&wrapped, ParseOptions::from(self.f.options().source_type()));
574574
// If the resulting code is not valid, then reset and pass through
575575
// the docstring lines as-is.
576576
if result.is_err() {
@@ -1580,10 +1580,8 @@ fn docstring_format_source(
15801580
docstring_quote_style: Quote,
15811581
source: &str,
15821582
) -> Result<Printed, FormatModuleError> {
1583-
use ruff_python_parser::AsMode;
1584-
15851583
let source_type = options.source_type();
1586-
let parsed = ruff_python_parser::parse(source, source_type.as_mode())?;
1584+
let parsed = ruff_python_parser::parse(source, ParseOptions::from(source_type))?;
15871585
let comment_ranges = CommentRanges::from(parsed.tokens());
15881586
let source_code = ruff_formatter::SourceCode::new(source);
15891587
let comments = crate::Comments::from_ast(parsed.syntax(), source_code, &comment_ranges);

crates/ruff_python_formatter/tests/fixtures.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::normalizer::Normalizer;
1111
use ruff_formatter::FormatOptions;
1212
use ruff_python_ast::comparable::ComparableMod;
1313
use ruff_python_formatter::{format_module_source, format_range, PreviewMode, PyFormatOptions};
14-
use ruff_python_parser::{parse, AsMode};
14+
use ruff_python_parser::{parse, ParseOptions};
1515
use ruff_source_file::{LineIndex, OneIndexed};
1616
use ruff_text_size::{TextRange, TextSize};
1717

@@ -393,14 +393,14 @@ fn ensure_unchanged_ast(
393393
let source_type = options.source_type();
394394

395395
// Parse the unformatted code.
396-
let mut unformatted_ast = parse(unformatted_code, source_type.as_mode())
396+
let mut unformatted_ast = parse(unformatted_code, ParseOptions::from(source_type))
397397
.expect("Unformatted code to be valid syntax")
398398
.into_syntax();
399399
Normalizer.visit_module(&mut unformatted_ast);
400400
let unformatted_ast = ComparableMod::from(&unformatted_ast);
401401

402402
// Parse the formatted code.
403-
let mut formatted_ast = parse(formatted_code, source_type.as_mode())
403+
let mut formatted_ast = parse(formatted_code, ParseOptions::from(source_type))
404404
.expect("Formatted code to be valid syntax")
405405
.into_syntax();
406406
Normalizer.visit_module(&mut formatted_ast);

0 commit comments

Comments
 (0)