Use Jupyter mode while parsing Notebook files (#5552)

## Summary

Enable using the new `Mode::Jupyter` for the tokenizer/parser to parse
Jupyter line magic tokens.

The individual call to the lexer i.e., `lex_starts_at` done by various
rules should consider the context of the source code (is this content
from a Jupyter Notebook?). Thus, a new field `source_type` (of type
`PySourceType`) is added to `Checker` which is being passed around as an
argument to the relevant functions. This is then used to determine the
`Mode` for the lexer.

## Test Plan

Add new test cases to make sure that the magic statement is considered
while generating the diagnostic and autofix:
* For `I001`, if there's a magic statement in between two import blocks,
they should be sorted independently

fixes: #6090
This commit is contained in:
Dhruv Manilawala 2023-08-05 06:02:07 +05:30 committed by GitHub
parent d788957ec4
commit 32fa05765a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 652 additions and 196 deletions

View file

@ -29,7 +29,8 @@ use ruff::{fs, IOError};
use ruff_diagnostics::Diagnostic;
use ruff_macros::CacheKey;
use ruff_python_ast::imports::ImportMap;
use ruff_python_stdlib::path::{is_jupyter_notebook, is_project_toml};
use ruff_python_ast::PySourceType;
use ruff_python_stdlib::path::is_project_toml;
use ruff_source_file::{LineIndex, SourceCode, SourceFileBuilder};
#[derive(CacheKey)]
@ -211,8 +212,10 @@ pub(crate) fn lint_path(
});
}
let source_type = PySourceType::from(path);
// Read the file from disk
let mut source_kind = if is_jupyter_notebook(path) {
let mut source_kind = if source_type.is_jupyter() {
match load_jupyter_notebook(path) {
Ok(notebook) => SourceKind::Jupyter(notebook),
Err(diagnostic) => return Ok(*diagnostic),
@ -249,6 +252,7 @@ pub(crate) fn lint_path(
noqa,
&settings.lib,
&mut source_kind,
source_type,
) {
if !fixed.is_empty() {
match autofix {
@ -335,6 +339,7 @@ pub(crate) fn lint_path(
&settings.lib,
noqa,
Some(&source_kind),
source_type,
);
let fixed = FxHashMap::default();
(result, fixed)
@ -347,6 +352,7 @@ pub(crate) fn lint_path(
&settings.lib,
noqa,
Some(&source_kind),
source_type,
);
let fixed = FxHashMap::default();
(result, fixed)
@ -396,6 +402,8 @@ pub(crate) fn lint_stdin(
autofix: flags::FixMode,
) -> Result<Diagnostics> {
let mut source_kind = SourceKind::Python(contents.to_string());
let source_type = PySourceType::default();
// Lint the inputs.
let (
LinterResult {
@ -415,6 +423,7 @@ pub(crate) fn lint_stdin(
noqa,
settings,
&mut source_kind,
source_type,
) {
match autofix {
flags::FixMode::Apply => {
@ -450,6 +459,7 @@ pub(crate) fn lint_stdin(
settings,
noqa,
Some(&source_kind),
source_type,
);
let fixed = FxHashMap::default();
@ -468,6 +478,7 @@ pub(crate) fn lint_stdin(
settings,
noqa,
Some(&source_kind),
source_type,
);
let fixed = FxHashMap::default();
(result, fixed)