From 5a0d977ed9d635b5e2e10967f5286aaba8e1abb1 Mon Sep 17 00:00:00 2001 From: Aniruddha Date: Fri, 17 Mar 2023 20:30:29 +0530 Subject: [PATCH] Add ParsingError exception and catch all parsing errors within this exception rather than crashing --- isort/api.py | 4 ++++ isort/core.py | 10 +++++++--- isort/exceptions.py | 10 +++++++++- tests/unit/test_exceptions.py | 8 ++++++++ tests/unit/test_isort.py | 15 ++++++++++++++- 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/isort/api.py b/isort/api.py index 2c89d3739..ed6485be8 100644 --- a/isort/api.py +++ b/isort/api.py @@ -32,6 +32,7 @@ FileSkipComment, FileSkipSetting, IntroducedSyntaxErrors, + ParsingError, ) from .format import ask_whether_to_apply_changes_to_file, create_terminal_printer, show_unified_diff from .io import Empty, File @@ -217,6 +218,9 @@ def sort_stream( except FileSkipComment: raise FileSkipComment(content_source) + except ParsingError: + raise ParsingError(file_path) + if config.atomic: _internal_output.seek(0) try: diff --git a/isort/core.py b/isort/core.py index 101038548..e707d098b 100644 --- a/isort/core.py +++ b/isort/core.py @@ -7,7 +7,7 @@ from isort.settings import DEFAULT_CONFIG, Config from . import output, parse -from .exceptions import ExistingSyntaxErrors, FileSkipComment +from .exceptions import ExistingSyntaxErrors, FileSkipComment, ISortError, ParsingError from .format import format_natural, remove_whitespace from .settings import FILE_SKIP_COMMENTS @@ -417,8 +417,12 @@ def process( import_section = "".join( line[len(indent) :] for line in import_section.splitlines(keepends=True) ) - - parsed_content = parse.file_contents(import_section, config=config) + try: + parsed_content = parse.file_contents(import_section, config=config) + except ISortError as error: + raise error + except Exception: + raise ParsingError(file_path=None) verbose_output += parsed_content.verbose_output sorted_import_section = output.sorted_imports( diff --git a/isort/exceptions.py b/isort/exceptions.py index 6be82406a..c225ce380 100644 --- a/isort/exceptions.py +++ b/isort/exceptions.py @@ -1,7 +1,7 @@ """All isort specific exception classes should be defined here""" from functools import partial from pathlib import Path -from typing import Any, Dict, List, Type, Union +from typing import Any, Dict, List, Optional, Type, Union from .profiles import profiles @@ -195,3 +195,11 @@ def __init__(self, import_module: str, section: str): "See https://pycqa.github.io/isort/#custom-sections-and-ordering " "for more info." ) + + +class ParsingError(ISortError): + """Raised when there's a failure with parsing the imports""" + + def __init__(self, file_path: Optional[Path]): + super().__init__(f"isort couldn't parse imports for {file_path}") + self.file_path = file_path diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py index f153e3751..6729ee7ad 100644 --- a/tests/unit/test_exceptions.py +++ b/tests/unit/test_exceptions.py @@ -126,3 +126,11 @@ def setup_class(self): def test_variables(self): assert self.instance.filename == "file.py" + + +class TestParsingError(TestISortError): + def setup_class(self): + self.instance: exceptions.ParsingError = exceptions.ParsingError(file_path=None) + + def test_variables(self): + assert self.instance.file_path is None diff --git a/tests/unit/test_isort.py b/tests/unit/test_isort.py index 7b6743c7b..92485727f 100644 --- a/tests/unit/test_isort.py +++ b/tests/unit/test_isort.py @@ -16,7 +16,7 @@ import isort from isort import api, files, sections -from isort.exceptions import ExistingSyntaxErrors, FileSkipped, MissingSection +from isort.exceptions import ExistingSyntaxErrors, FileSkipped, MissingSection, ParsingError from isort.settings import Config from isort.utils import exists_case_sensitive @@ -5671,3 +5671,16 @@ def test_reexport_not_last_line() -> None: meme = "rickroll" """ assert isort.code(test_input, config=Config(sort_reexports=True)) == expd_output + + +def test_doesnot_break_for_syntax_error() -> None: + """Test to ensure that isort doesn't break for syntax error while parsing import""" + test_input = """ +from pathlib import Path +from typing import Optional, Union +import numpy as np + +from os.path.import Path +""" + with pytest.raises(ParsingError): + isort.code(test_input)