diff -Nru isort-5.4.2/debian/changelog isort-5.6.4/debian/changelog --- isort-5.4.2/debian/changelog 2020-08-15 20:16:19.000000000 +0000 +++ isort-5.6.4/debian/changelog 2020-11-05 09:24:46.000000000 +0000 @@ -1,3 +1,18 @@ +isort (5.6.4-1) unstable; urgency=medium + + [ Ondřej Nový ] + * d/control: Update Maintainer field with new Debian Python Team + contact address. + * d/control: Update Vcs-* fields with new Debian Python Team Salsa + layout. + + [ Tristan Seligmann ] + * New upstream release. + * Disable autopkgtests temporarily; upstream no longer ships the tests + in the sdist. + + -- Tristan Seligmann Thu, 05 Nov 2020 11:24:46 +0200 + isort (5.4.2-1) unstable; urgency=medium * New upstream release. diff -Nru isort-5.4.2/debian/control isort-5.6.4/debian/control --- isort-5.4.2/debian/control 2020-08-15 20:16:19.000000000 +0000 +++ isort-5.6.4/debian/control 2020-11-05 09:24:46.000000000 +0000 @@ -1,7 +1,7 @@ Source: isort Section: python Priority: optional -Maintainer: Python Applications Packaging Team +Maintainer: Debian Python Team Uploaders: Tristan Seligmann Build-Depends: debhelper-compat (= 13), @@ -10,8 +10,8 @@ python3-setuptools, Standards-Version: 4.5.0 Homepage: https://github.com/timothycrosley/isort -Vcs-Git: https://salsa.debian.org/python-team/applications/isort.git -Vcs-Browser: https://salsa.debian.org/python-team/applications/isort +Vcs-Git: https://salsa.debian.org/python-team/packages/isort.git +Vcs-Browser: https://salsa.debian.org/python-team/packages/isort Rules-Requires-Root: no Package: isort diff -Nru isort-5.4.2/debian/patches/0001-Devendor-toml.patch isort-5.6.4/debian/patches/0001-Devendor-toml.patch --- isort-5.4.2/debian/patches/0001-Devendor-toml.patch 2020-08-15 20:16:19.000000000 +0000 +++ isort-5.6.4/debian/patches/0001-Devendor-toml.patch 2020-11-05 09:24:46.000000000 +0000 @@ -8,7 +8,7 @@ 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/isort/settings.py b/isort/settings.py -index 68f09bb..adf75a5 100644 +index 96fc941..507abd3 100644 --- a/isort/settings.py +++ b/isort/settings.py @@ -17,7 +17,7 @@ from warnings import warn @@ -17,11 +17,11 @@ from ._future import dataclass, field -from ._vendored import toml +import toml - from .exceptions import FormattingPluginDoesNotExist, InvalidSettingsPath, ProfileDoesNotExist - from .profiles import profiles - from .sections import DEFAULT as SECTION_DEFAULTS + from .exceptions import ( + FormattingPluginDoesNotExist, + InvalidSettingsPath, diff --git a/setup.py b/setup.py -index 0ded62a..db5292e 100644 +index ad89790..1a3fb7b 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,6 @@ from setuptools import setup @@ -30,5 +30,5 @@ 'isort._future', - 'isort._vendored.toml', 'isort.deprecated', - 'isort.stdlibs', - 'tests'] + 'isort.stdlibs'] + diff -Nru isort-5.4.2/debian/tests/control isort-5.6.4/debian/tests/control --- isort-5.4.2/debian/tests/control 2020-08-15 20:16:19.000000000 +0000 +++ isort-5.6.4/debian/tests/control 2020-11-05 09:24:46.000000000 +0000 @@ -1,20 +1,20 @@ -Test-Command: for p in $(py3versions -s); - do $p -m pytest - --ignore tests/test_pylama_isort.py - --ignore tests/test_deprecated_finders.py - --ignore tests/test_importable.py - --ignore tests/test_hypothesmith.py - --deselect tests/test_ticketed_features.py::test_isort_literals_issue_1358 - --deselect tests/test_ticketed_features.py::test_isort_supports_formatting_plugins_issue_1353 - --deselect tests/test_ticketed_features.py::test_isort_supports_shared_profiles_issue_970 - --deselect tests/test_literal.py::test_value_assignment - tests/; done -Depends: - git, - python3-all, - python3-colorama, - python3-hypothesis, - python3-hypothesis-auto, - python3-pytest, - python3-setuptools, - @, +# Test-Command: for p in $(py3versions -s); +# do $p -m pytest +# --ignore tests/test_pylama_isort.py +# --ignore tests/test_deprecated_finders.py +# --ignore tests/test_importable.py +# --ignore tests/test_hypothesmith.py +# --deselect tests/test_ticketed_features.py::test_isort_literals_issue_1358 +# --deselect tests/test_ticketed_features.py::test_isort_supports_formatting_plugins_issue_1353 +# --deselect tests/test_ticketed_features.py::test_isort_supports_shared_profiles_issue_970 +# --deselect tests/test_literal.py::test_value_assignment +# tests/; done +# Depends: +# git, +# python3-all, +# python3-colorama, +# python3-hypothesis, +# python3-hypothesis-auto, +# python3-pytest, +# python3-setuptools, +# @, diff -Nru isort-5.4.2/isort/api.py isort-5.6.4/isort/api.py --- isort-5.4.2/isort/api.py 2020-08-12 05:18:52.937633500 +0000 +++ isort-5.6.4/isort/api.py 2020-10-13 06:20:58.554927300 +0000 @@ -131,6 +131,7 @@ file_output=_output_stream.read(), file_path=file_path, output=output_stream if show_diff is True else cast(TextIO, show_diff), + color_output=config.color_output, ) return changed @@ -199,6 +200,9 @@ """ config = _config(path=file_path, config=config, **config_kwargs) + if show_diff: + input_stream = StringIO(input_stream.read()) + changed: bool = sort_stream( input_stream=input_stream, output_stream=Empty, @@ -209,7 +213,7 @@ ) printer = create_terminal_printer(color=config.color_output) if not changed: - if config.verbose: + if config.verbose and not config.only_modified: printer.success(f"{file_path or ''} Everything Looks Good!") return True else: @@ -233,6 +237,7 @@ file_output=output_stream.read(), file_path=file_path, output=None if show_diff is True else cast(TextIO, show_diff), + color_output=config.color_output, ) return False @@ -296,6 +301,8 @@ - ****config_kwargs**: Any config modifications. """ with io.File.read(filename) as source_file: + actual_file_path = file_path or source_file.path + config = _config(path=actual_file_path, config=config, **config_kwargs) changed: bool = False try: if write_to_stdout: @@ -303,10 +310,9 @@ input_stream=source_file.stream, output_stream=sys.stdout, config=config, - file_path=file_path or source_file.path, + file_path=actual_file_path, disregard_skip=disregard_skip, extension=extension, - **config_kwargs, ) else: tmp_file = source_file.path.with_suffix(source_file.path.suffix + ".isorted") @@ -319,10 +325,9 @@ input_stream=source_file.stream, output_stream=output_stream, config=config, - file_path=file_path or source_file.path, + file_path=actual_file_path, disregard_skip=disregard_skip, extension=extension, - **config_kwargs, ) if changed: if show_diff or ask_to_apply: @@ -333,8 +338,9 @@ show_unified_diff( file_input=source_file.stream.read(), file_output=tmp_out.read(), - file_path=file_path or source_file.path, + file_path=actual_file_path, output=None if show_diff is True else cast(TextIO, show_diff), + color_output=config.color_output, ) if show_diff or ( ask_to_apply @@ -351,11 +357,11 @@ try: # Python 3.8+: use `missing_ok=True` instead of try except. tmp_file.unlink() except FileNotFoundError: - pass + pass # pragma: no cover except ExistingSyntaxErrors: - warn(f"{file_path} unable to sort due to existing syntax errors") + warn(f"{actual_file_path} unable to sort due to existing syntax errors") except IntroducedSyntaxErrors: # pragma: no cover - warn(f"{file_path} unable to sort as isort introduces new syntax errors") + warn(f"{actual_file_path} unable to sort as isort introduces new syntax errors") return changed diff -Nru isort-5.4.2/isort/core.py isort-5.6.4/isort/core.py --- isort-5.4.2/isort/core.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/isort/core.py 2020-10-13 06:20:58.554927300 +0000 @@ -58,7 +58,6 @@ contains_imports: bool = False in_top_comment: bool = False first_import_section: bool = True - section_comments = [f"# {heading}" for heading in config.import_headings.values()] indent: str = "" isort_off: bool = False code_sorting: Union[bool, str] = False @@ -66,6 +65,9 @@ code_sorting_indent: str = "" cimports: bool = False made_changes: bool = False + stripped_line: str = "" + end_of_file: bool = False + verbose_output: List[str] = [] if config.float_to_top: new_input = "" @@ -82,9 +84,14 @@ if line == "# isort: off\n": isort_off = True if current: + if add_imports: + add_line_separator = line_separator or "\n" + current += add_line_separator + add_line_separator.join(add_imports) + add_imports = [] parsed = parse.file_contents(current, config=config) + verbose_output += parsed.verbose_output extra_space = "" - while current[-1] == "\n": + while current and current[-1] == "\n": extra_space += "\n" current = current[:-1] extra_space = extra_space.replace("\n", "", 1) @@ -112,6 +119,7 @@ return False not_imports = True + end_of_file = True line = "" if not line_separator: line_separator = "\n" @@ -137,17 +145,21 @@ if file_skip_comment in line: raise FileSkipComment("Passed in content") + if not in_quote and stripped_line == "# isort: off": + isort_off = True + if ( (index == 0 or (index in (1, 2) and not contains_imports)) and stripped_line.startswith("#") - and stripped_line not in section_comments + and stripped_line not in config.section_comments ): in_top_comment = True elif in_top_comment: - if not line.startswith("#") or stripped_line in section_comments: + if not line.startswith("#") or stripped_line in config.section_comments: in_top_comment = False first_comment_index_end = index - 1 + was_in_quote = bool(in_quote) if (not stripped_line.startswith("#") or in_quote) and '"' in line or "'" in line: char_index = 0 if first_comment_index_start == -1 and ( @@ -173,15 +185,11 @@ break char_index += 1 - not_imports = bool(in_quote) or in_top_comment or isort_off - if not (in_quote or in_top_comment): - stripped_line = line.strip() + not_imports = bool(in_quote) or was_in_quote or in_top_comment or isort_off + if not (in_quote or was_in_quote or in_top_comment): if isort_off: if stripped_line == "# isort: on": isort_off = False - elif stripped_line == "# isort: off": - not_imports = True - isort_off = True elif stripped_line.endswith("# isort: split"): not_imports = True elif stripped_line in CODE_SORT_COMMENTS: @@ -208,19 +216,16 @@ else: code_sorting_section += line line = "" - elif stripped_line in config.section_comments and not import_section: - import_section += line + elif stripped_line in config.section_comments: + if import_section and not contains_imports: + output_stream.write(import_section) + import_section = line + not_imports = False + else: + import_section += line indent = line[: -len(line.lstrip())] elif not (stripped_line or contains_imports): - if add_imports and not indent and not config.append_only: - if not import_section: - output_stream.write(line) - line = "" - import_section += line_separator.join(add_imports) + line_separator - contains_imports = True - add_imports = [] - else: - not_imports = True + not_imports = True elif ( not stripped_line or stripped_line.startswith("#") @@ -278,6 +283,7 @@ raw_import_section: str = import_section if ( add_imports + and (stripped_line or end_of_file) and not config.append_only and not in_top_comment and not in_quote @@ -285,6 +291,8 @@ and not line.lstrip().startswith(COMMENT_INDICATORS) ): import_section = line_separator.join(add_imports) + line_separator + if end_of_file and index != 0: + output_stream.write(line_separator) contains_imports = True add_imports = [] @@ -305,6 +313,7 @@ raw_import_section += line if not contains_imports: output_stream.write(import_section) + else: leading_whitespace = import_section[: -len(import_section.lstrip())] trailing_whitespace = import_section[len(import_section.rstrip()) :] @@ -320,8 +329,11 @@ line[len(indent) :] for line in import_section.splitlines(keepends=True) ) + parsed_content = parse.file_contents(import_section, config=config) + verbose_output += parsed_content.verbose_output + sorted_import_section = output.sorted_imports( - parse.file_contents(import_section, config=config), + parsed_content, _indented_config(config, indent), extension, import_type="cimport" if cimports else "import", @@ -340,7 +352,6 @@ line_separator=line_separator, ignore_whitespace=config.ignore_whitespace, ) - output_stream.write(sorted_import_section) if not line and not indent and next_import_section: output_stream.write(line_separator) @@ -361,6 +372,29 @@ output_stream.write(line) not_imports = False + if stripped_line and not in_quote and not import_section and not next_import_section: + if stripped_line == "yield": + while not stripped_line or stripped_line == "yield": + new_line = input_stream.readline() + if not new_line: + break + + output_stream.write(new_line) + stripped_line = new_line.strip().split("#")[0] + + if stripped_line.startswith("raise") or stripped_line.startswith("yield"): + while stripped_line.endswith("\\"): + new_line = input_stream.readline() + if not new_line: + break + + output_stream.write(new_line) + stripped_line = new_line.strip().split("#")[0] + + if made_changes and config.only_modified: + for output_str in verbose_output: + print(output_str) + return made_changes diff -Nru isort-5.4.2/isort/deprecated/finders.py isort-5.6.4/isort/deprecated/finders.py --- isort-5.4.2/isort/deprecated/finders.py 2020-08-15 03:12:49.688459900 +0000 +++ isort-5.6.4/isort/deprecated/finders.py 2020-10-08 06:39:26.721052600 +0000 @@ -7,6 +7,7 @@ import sys import sysconfig from abc import ABCMeta, abstractmethod +from contextlib import contextmanager from fnmatch import fnmatch from functools import lru_cache from glob import glob @@ -15,7 +16,7 @@ from isort import sections from isort.settings import KNOWN_SECTION_MAPPING, Config -from isort.utils import chdir, exists_case_sensitive +from isort.utils import exists_case_sensitive try: from pipreqs import pipreqs @@ -36,6 +37,17 @@ Pipfile = None +@contextmanager +def chdir(path: str) -> Iterator[None]: + """Context manager for changing dir and restoring previous workdir after exit.""" + curdir = os.getcwd() + os.chdir(path) + try: + yield + finally: + os.chdir(curdir) + + class BaseFinder(metaclass=ABCMeta): def __init__(self, config: Config) -> None: self.config = config diff -Nru isort-5.4.2/isort/exceptions.py isort-5.6.4/isort/exceptions.py --- isort-5.4.2/isort/exceptions.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/isort/exceptions.py 2020-10-08 06:39:26.721052600 +0000 @@ -1,4 +1,7 @@ """All isort specific exception classes should be defined here""" +from pathlib import Path +from typing import Any, Dict, Union + from .profiles import profiles @@ -132,3 +135,37 @@ "...\n\n" ) self.code = code + + +class UnsupportedSettings(ISortError): + """Raised when settings are passed into isort (either from config, CLI, or runtime) + that it doesn't support. + """ + + @staticmethod + def _format_option(name: str, value: Any, source: str) -> str: + return f"\t- {name} = {value} (source: '{source}')" + + def __init__(self, unsupported_settings: Dict[str, Dict[str, str]]): + errors = "\n".join( + self._format_option(name, **option) for name, option in unsupported_settings.items() + ) + + super().__init__( + "isort was provided settings that it doesn't support:\n\n" + f"{errors}\n\n" + "For a complete and up-to-date listing of supported settings see: " + "https://pycqa.github.io/isort/docs/configuration/options/.\n" + ) + self.unsupported_settings = unsupported_settings + + +class UnsupportedEncoding(ISortError): + """Raised when isort encounters an encoding error while trying to read a file""" + + def __init__( + self, + filename: Union[str, Path], + ): + super().__init__(f"Unknown or unsupported encoding in {filename}") + self.filename = filename diff -Nru isort-5.4.2/isort/format.py isort-5.6.4/isort/format.py --- isort-5.4.2/isort/format.py 2020-07-29 05:49:17.446505300 +0000 +++ isort-5.6.4/isort/format.py 2020-09-20 21:35:13.196999500 +0000 @@ -1,3 +1,4 @@ +import re import sys from datetime import datetime from difflib import unified_diff @@ -13,6 +14,10 @@ colorama.init() +ADDED_LINE_PATTERN = re.compile(r"\+[^+]") +REMOVED_LINE_PATTERN = re.compile(r"-[^-]") + + def format_simplified(import_line: str) -> str: import_line = import_line.strip() if import_line.startswith("from "): @@ -37,7 +42,12 @@ def show_unified_diff( - *, file_input: str, file_output: str, file_path: Optional[Path], output: Optional[TextIO] = None + *, + file_input: str, + file_output: str, + file_path: Optional[Path], + output: Optional[TextIO] = None, + color_output: bool = False, ): """Shows a unified_diff for the provided input and output against the provided file path. @@ -45,8 +55,9 @@ - **file_output**: A string that represents the contents of a file after changes. - **file_path**: A Path object that represents the file path of the file being changed. - **output**: A stream to output the diff to. If non is provided uses sys.stdout. + - **color_output**: Use color in output if True. """ - output = sys.stdout if output is None else output + printer = create_terminal_printer(color_output, output) file_name = "" if file_path is None else str(file_path) file_mtime = str( datetime.now() if file_path is None else datetime.fromtimestamp(file_path.stat().st_mtime) @@ -60,7 +71,7 @@ tofiledate=str(datetime.now()), ) for line in unified_diff_lines: - output.write(line) + printer.diff_line(line) def ask_whether_to_apply_changes_to_file(file_path: str) -> bool: @@ -84,28 +95,45 @@ ERROR = "ERROR" SUCCESS = "SUCCESS" + def __init__(self, output: Optional[TextIO] = None): + self.output = output or sys.stdout + def success(self, message: str) -> None: - print(f"{self.SUCCESS}: {message}") + print(f"{self.SUCCESS}: {message}", file=self.output) def error(self, message: str) -> None: - print( - f"{self.ERROR}: {message}", - # TODO this should print to stderr, but don't want to make it backward incompatible now - # file=sys.stderr - ) + print(f"{self.ERROR}: {message}", file=sys.stderr) + + def diff_line(self, line: str) -> None: + self.output.write(line) class ColoramaPrinter(BasicPrinter): - def __init__(self): + def __init__(self, output: Optional[TextIO] = None): + self.output = output or sys.stdout + # Note: this constants are instance variables instead ofs class variables + # because they refer to colorama which might not be installed. self.ERROR = self.style_text("ERROR", colorama.Fore.RED) self.SUCCESS = self.style_text("SUCCESS", colorama.Fore.GREEN) + self.ADDED_LINE = colorama.Fore.GREEN + self.REMOVED_LINE = colorama.Fore.RED @staticmethod - def style_text(text: str, style: str) -> str: + def style_text(text: str, style: Optional[str] = None) -> str: + if style is None: + return text return style + text + colorama.Style.RESET_ALL + def diff_line(self, line: str) -> None: + style = None + if re.match(ADDED_LINE_PATTERN, line): + style = self.ADDED_LINE + elif re.match(REMOVED_LINE_PATTERN, line): + style = self.REMOVED_LINE + self.output.write(self.style_text(line, style)) + -def create_terminal_printer(color: bool): +def create_terminal_printer(color: bool, output: Optional[TextIO] = None): if color and colorama_unavailable: no_colorama_message = ( "\n" @@ -118,4 +146,4 @@ print(no_colorama_message, file=sys.stderr) sys.exit(1) - return ColoramaPrinter() if color else BasicPrinter() + return ColoramaPrinter(output) if color else BasicPrinter(output) diff -Nru isort-5.4.2/isort/_future/_dataclasses.py isort-5.6.4/isort/_future/_dataclasses.py --- isort-5.4.2/isort/_future/_dataclasses.py 2020-07-29 04:24:06.097084800 +0000 +++ isort-5.6.4/isort/_future/_dataclasses.py 2020-09-24 04:22:12.517273200 +0000 @@ -1137,7 +1137,10 @@ name = item tp = "typing.Any" elif len(item) == 2: - name, tp, = item + ( + name, + tp, + ) = item elif len(item) == 3: name, tp, spec = item namespace[name] = spec @@ -1173,7 +1176,7 @@ c = C(1, 2) c1 = replace(c, x=3) assert c1.x == 3 and c1.y == 2 - """ + """ # We're going to mutate 'changes', but that's okay because it's a # new dict, even if called with 'replace(obj, **my_changes)'. diff -Nru isort-5.4.2/isort/hooks.py isort-5.6.4/isort/hooks.py --- isort-5.4.2/isort/hooks.py 2020-08-05 04:44:25.122057400 +0000 +++ isort-5.6.4/isort/hooks.py 2020-09-20 21:35:13.196999500 +0000 @@ -33,7 +33,9 @@ return [line.strip() for line in stdout.splitlines()] -def git_hook(strict: bool = False, modify: bool = False, lazy: bool = False) -> int: +def git_hook( + strict: bool = False, modify: bool = False, lazy: bool = False, settings_file: str = "" +) -> int: """ Git pre-commit hook to check staged files for isort errors @@ -46,6 +48,11 @@ :param bool lazy - if True, also check/fix unstaged files. This is useful if you frequently use ``git commit -a`` for example. If False, ony check/fix the staged files for isort errors. + :param str settings_file - A path to a file to be used as + the configuration file for this run. + When settings_file is the empty string, the configuration file + will be searched starting at the directory containing the first + staged file, if any, and going upward in the directory structure. :return number of errors if in strict mode, 0 otherwise. """ @@ -60,7 +67,10 @@ return 0 errors = 0 - config = Config(settings_path=os.path.dirname(os.path.abspath(files_modified[0]))) + config = Config( + settings_file=settings_file, + settings_path=os.path.dirname(os.path.abspath(files_modified[0])), + ) for filename in files_modified: if filename.endswith(".py"): # Get the staged contents of the file diff -Nru isort-5.4.2/isort/io.py isort-5.6.4/isort/io.py --- isort-5.4.2/isort/io.py 2020-07-29 04:24:06.097084800 +0000 +++ isort-5.6.4/isort/io.py 2020-10-08 06:39:26.721052600 +0000 @@ -4,7 +4,9 @@ from contextlib import contextmanager from io import BytesIO, StringIO, TextIOWrapper from pathlib import Path -from typing import Iterator, NamedTuple, TextIO, Union +from typing import Callable, Iterator, NamedTuple, TextIO, Union + +from isort.exceptions import UnsupportedEncoding _ENCODING_PATTERN = re.compile(br"^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)") @@ -15,8 +17,15 @@ encoding: str @staticmethod + def detect_encoding(filename: str, readline: Callable[[], bytes]): + try: + return tokenize.detect_encoding(readline)[0] + except Exception: + raise UnsupportedEncoding(filename) + + @staticmethod def from_contents(contents: str, filename: str) -> "File": - encoding, _ = tokenize.detect_encoding(BytesIO(contents.encode("utf-8")).readline) + encoding = File.detect_encoding(filename, BytesIO(contents.encode("utf-8")).readline) return File(StringIO(contents), path=Path(filename).resolve(), encoding=encoding) @property @@ -30,7 +39,7 @@ """ buffer = open(filename, "rb") try: - encoding, _ = tokenize.detect_encoding(buffer.readline) + encoding = File.detect_encoding(filename, buffer.readline) buffer.seek(0) text = TextIOWrapper(buffer, encoding, line_buffering=True, newline="") text.mode = "r" # type: ignore diff -Nru isort-5.4.2/isort/literal.py isort-5.6.4/isort/literal.py --- isort-5.4.2/isort/literal.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/isort/literal.py 2020-10-08 06:39:26.721052600 +0000 @@ -21,17 +21,18 @@ def assignments(code: str) -> str: - sort_assignments = {} + values = {} for line in code.splitlines(keepends=True): - if line: - if " = " not in line: - raise AssignmentsFormatMismatch(code) - else: - variable_name, value = line.split(" = ", 1) - sort_assignments[variable_name] = value + if not line.strip(): + continue + if " = " not in line: + raise AssignmentsFormatMismatch(code) + variable_name, value = line.split(" = ", 1) + values[variable_name] = value - sorted_assignments = dict(sorted(sort_assignments.items(), key=lambda item: item[1])) - return "".join(f"{key} = {value}" for key, value in sorted_assignments.items()) + return "".join( + f"{variable_name} = {values[variable_name]}" for variable_name in sorted(values.keys()) + ) def assignment(code: str, sort_type: str, extension: str, config: Config = DEFAULT_CONFIG) -> str: diff -Nru isort-5.4.2/isort/main.py isort-5.6.4/isort/main.py --- isort-5.4.2/isort/main.py 2020-08-15 03:12:49.688459900 +0000 +++ isort-5.6.4/isort/main.py 2020-10-08 06:39:26.721052600 +0000 @@ -10,7 +10,8 @@ from warnings import warn from . import __version__, api, sections -from .exceptions import FileSkipped +from .exceptions import FileSkipped, UnsupportedEncoding +from .format import create_terminal_printer from .logo import ASCII_ART from .profiles import profiles from .settings import VALID_PY_TARGETS, Config, WrapModes @@ -61,14 +62,15 @@ `isort . --check --diff` - Check to see if imports are correctly sorted within this project. `isort --help` - In-depth information about isort's available command-line options. -Visit https://timothycrosley.github.io/isort/ for complete information about how to use isort. +Visit https://pycqa.github.io/isort/ for complete information about how to use isort. """ class SortAttempt: - def __init__(self, incorrectly_sorted: bool, skipped: bool) -> None: + def __init__(self, incorrectly_sorted: bool, skipped: bool, supported_encoding: bool) -> None: self.incorrectly_sorted = incorrectly_sorted self.skipped = skipped + self.supported_encoding = supported_encoding def sort_imports( @@ -87,7 +89,7 @@ incorrectly_sorted = not api.check_file(file_name, config=config, **kwargs) except FileSkipped: skipped = True - return SortAttempt(incorrectly_sorted, skipped) + return SortAttempt(incorrectly_sorted, skipped, True) else: try: incorrectly_sorted = not api.sort_file( @@ -99,13 +101,27 @@ ) except FileSkipped: skipped = True - return SortAttempt(incorrectly_sorted, skipped) + return SortAttempt(incorrectly_sorted, skipped, True) except (OSError, ValueError) as error: warn(f"Unable to parse file {file_name} due to {error}") return None + except UnsupportedEncoding: + if config.verbose: + warn(f"Encoding not supported for {file_name}") + return SortAttempt(incorrectly_sorted, skipped, False) + except Exception: + printer = create_terminal_printer(color=config.color_output) + printer.error( + f"Unrecoverable exception thrown when parsing {file_name}! " + "This should NEVER happen.\n" + "If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new" + ) + raise -def iter_source_code(paths: Iterable[str], config: Config, skipped: List[str]) -> Iterator[str]: +def iter_source_code( + paths: Iterable[str], config: Config, skipped: List[str], broken: List[str] +) -> Iterator[str]: """Iterate over all Python source files defined in paths.""" visited_dirs: Set[Path] = set() @@ -115,17 +131,16 @@ base_path = Path(dirpath) for dirname in list(dirnames): full_path = base_path / dirname + resolved_path = full_path.resolve() if config.is_skipped(full_path): skipped.append(dirname) dirnames.remove(dirname) - - resolved_path = full_path.resolve() - if resolved_path in visited_dirs: # pragma: no cover - if not config.quiet: - warn(f"Likely recursive symlink detected to {resolved_path}") - dirnames.remove(dirname) else: - visited_dirs.add(resolved_path) + if resolved_path in visited_dirs: # pragma: no cover + if not config.quiet: + warn(f"Likely recursive symlink detected to {resolved_path}") + dirnames.remove(dirname) + visited_dirs.add(resolved_path) for filename in filenames: filepath = os.path.join(dirpath, filename) @@ -134,6 +149,8 @@ skipped.append(filename) else: yield filepath + elif not os.path.exists(path): + broken.append(path) else: yield path @@ -145,9 +162,9 @@ "start guide, otherwise, one or more files/directories/stdin must be provided. " "Use `-` as the first argument to represent stdin. Use --interactive to use the pre 5.0.0 " "interactive behavior." - "" + " " "If you've used isort 4 but are new to isort 5, see the upgrading guide:" - "https://timothycrosley.github.io/isort/docs/upgrade_guides/5.0.0/." + "https://pycqa.github.io/isort/docs/upgrade_guides/5.0.0/." ) inline_args_group = parser.add_mutually_exclusive_group() parser.add_argument( @@ -156,7 +173,7 @@ dest="src_paths", action="append", help="Add an explicitly defined source path " - "(modules within src paths have their imports automatically catorgorized as first_party).", + "(modules within src paths have their imports automatically categorized as first_party).", ) parser.add_argument( "-a", @@ -259,7 +276,12 @@ "--future", dest="known_future_library", action="append", - help="Force isort to recognize a module as part of the future compatibility libraries.", + help="Force isort to recognize a module as part of Python's internal future compatibility " + "libraries. WARNING: this overrides the behavior of __future__ handling and therefore" + " can result in code that can't execute. If you're looking to add dependencies such " + "as six a better option is to create a another section below --future using custom " + "sections. See: https://github.com/PyCQA/isort#custom-sections-and-ordering and the " + "discussion here: https://github.com/PyCQA/isort/issues/1463.", ) parser.add_argument( "--fas", @@ -289,8 +311,9 @@ const=2, type=int, dest="force_grid_wrap", - help="Force number of from imports (defaults to 2) to be grid wrapped regardless of line " - "length", + help="Force number of from imports (defaults to 2 when passed as CLI flag without value)" + "to be grid wrapped regardless of line " + "length. If 0 is passed in (the global default) only line length is considered.", ) parser.add_argument( "--fss", @@ -330,7 +353,8 @@ parser.add_argument( "--lss", "--length-sort-straight", - help="Sort straight imports by their string length.", + help="Sort straight imports by their string length. Similar to `length_sort` " + "but applies only to straight imports and doesn't affect from imports.", dest="length_sort_straight", action="store_true", ) @@ -587,9 +611,9 @@ action="store", dest="py_version", choices=tuple(VALID_PY_TARGETS) + ("auto",), - help="Tells isort to set the known standard library based on the the specified Python " + help="Tells isort to set the known standard library based on the specified Python " "version. Default is to assume any Python 3 version could be the target, and use a union " - "off all stdlib modules across versions. If auto is specified, the version of the " + "of all stdlib modules across versions. If auto is specified, the version of the " "interpreter used to run isort " f"(currently: {sys.version_info.major}{sys.version_info.minor}) will be used.", ) @@ -620,6 +644,12 @@ help="See isort's determined config, as well as sources of config options.", ) parser.add_argument( + "--show-files", + dest="show_files", + action="store_true", + help="See the files isort will be ran against with the current config options.", + ) + parser.add_argument( "--honor-noqa", dest="honor_noqa", action="store_true", @@ -646,7 +676,8 @@ dest="float_to_top", action="store_true", help="Causes all non-indented imports to float to the top of the file having its imports " - "sorted. It can be an excellent shortcut for collecting imports every once in a while " + "sorted (immediately below the top of file comment).\n" + "This can be an excellent shortcut for collecting imports every once in a while " "when you place them in the middle of a file to avoid context switching.\n\n" "*NOTE*: It currently doesn't work with cimports and introduces some extra over-head " "and a performance penalty.", @@ -728,6 +759,23 @@ help=argparse.SUPPRESS, ) + parser.add_argument( + "--only-sections", + "--os", + dest="only_sections", + action="store_true", + help="Causes imports to be sorted only based on their sections like STDLIB,THIRDPARTY etc. " + "Imports are unaltered and keep their relative positions within the different sections.", + ) + + parser.add_argument( + "--only-modified", + "--om", + dest="only_modified", + action="store_true", + help="Suppresses verbose output for non-modified files.", + ) + return parser @@ -776,6 +824,9 @@ return show_config: bool = arguments.pop("show_config", False) + show_files: bool = arguments.pop("show_files", False) + if show_config and show_files: + sys.exit("Error: either specify show-config or show-files not both.") if "settings_path" in arguments: if os.path.isfile(arguments["settings_path"]): @@ -813,6 +864,8 @@ deprecated_flags = config_dict.pop("deprecated_flags", False) remapped_deprecated_args = config_dict.pop("remapped_deprecated_args", False) wrong_sorted_files = False + all_attempt_broken = False + no_valid_encodings = False if "src_paths" in config_dict: config_dict["src_paths"] = { @@ -824,14 +877,27 @@ print(json.dumps(config.__dict__, indent=4, separators=(",", ": "), default=_preconvert)) return elif file_names == ["-"]: - arguments.setdefault("settings_path", os.getcwd()) - api.sort_stream( - input_stream=sys.stdin if stdin is None else stdin, - output_stream=sys.stdout, - **arguments, - ) + if show_files: + sys.exit("Error: can't show files for streaming input.") + + if check: + incorrectly_sorted = not api.check_stream( + input_stream=sys.stdin if stdin is None else stdin, + config=config, + show_diff=show_diff, + ) + + wrong_sorted_files = incorrectly_sorted + else: + api.sort_stream( + input_stream=sys.stdin if stdin is None else stdin, + output_stream=sys.stdout, + config=config, + show_diff=show_diff, + ) else: skipped: List[str] = [] + broken: List[str] = [] if config.filter_files: filtered_files = [] @@ -842,8 +908,14 @@ filtered_files.append(file_name) file_names = filtered_files - file_names = iter_source_code(file_names, config, skipped) + file_names = iter_source_code(file_names, config, skipped, broken) + if show_files: + for file_name in file_names: + print(file_name) + return num_skipped = 0 + num_broken = 0 + num_invalid_encoding = 0 if config.verbose: print(ASCII_ART) @@ -875,6 +947,9 @@ for file_name in file_names ) + # If any files passed in are missing considered as error, should be removed + is_no_attempt = True + any_encoding_valid = False for sort_attempt in attempt_iterator: if not sort_attempt: continue # pragma: no cover - shouldn't happen, satisfies type constraint @@ -886,6 +961,13 @@ 1 # pragma: no cover - shouldn't happen, due to skip in iter_source_code ) + if not sort_attempt.supported_encoding: + num_invalid_encoding += 1 + else: + any_encoding_valid = True + + is_no_attempt = False + num_skipped += len(skipped) if num_skipped and not arguments.get("quiet", False): if config.verbose: @@ -896,6 +978,18 @@ ) print(f"Skipped {num_skipped} files") + num_broken += len(broken) + if num_broken and not arguments.get("quite", False): + if config.verbose: + for was_broken in broken: + warn(f"{was_broken} was broken path, make sure it exists correctly") + print(f"Broken {num_broken} paths") + + if num_broken > 0 and is_no_attempt: + all_attempt_broken = True + if num_invalid_encoding > 0 and not any_encoding_valid: + no_valid_encodings = True + if not config.quiet and (remapped_deprecated_args or deprecated_flags): if remapped_deprecated_args: warn( @@ -909,12 +1003,20 @@ ) warn( "W0500: Please see the 5.0.0 Upgrade guide: " - "https://timothycrosley.github.io/isort/docs/upgrade_guides/5.0.0/" + "https://pycqa.github.io/isort/docs/upgrade_guides/5.0.0/" ) if wrong_sorted_files: sys.exit(1) + if all_attempt_broken: + sys.exit(1) + + if no_valid_encodings: + printer = create_terminal_printer(color=config.color_output) + printer.error("No valid encodings.") + sys.exit(1) + if __name__ == "__main__": main() diff -Nru isort-5.4.2/isort/output.py isort-5.6.4/isort/output.py --- isort-5.4.2/isort/output.py 2020-08-13 08:23:21.599986000 +0000 +++ isort-5.6.4/isort/output.py 2020-10-08 06:39:26.721052600 +0000 @@ -9,7 +9,7 @@ from .comments import add_to_line as with_comments from .settings import DEFAULT_CONFIG, Config -STATEMENT_DECLERATIONS: Tuple[str, ...] = ("def ", "cdef ", "cpdef ", "class ", "@", "async def") +STATEMENT_DECLARATIONS: Tuple[str, ...] = ("def ", "cdef ", "cpdef ", "class ", "@", "async def") def sorted_imports( @@ -29,7 +29,6 @@ formatted_output: List[str] = parsed.lines_without_imports.copy() remove_imports = [format_simplified(removal) for removal in config.remove_imports] - sort_ignore_case = config.force_alphabetical_sort_within_sections sections: Iterable[str] = itertools.chain(parsed.sections, config.forced_separate) if config.no_sections: @@ -50,62 +49,34 @@ pending_lines_before = False for section in sections: straight_modules = parsed.imports[section]["straight"] - straight_modules = sorting.naturally( - straight_modules, - key=lambda key: sorting.module_key( - key, config, section_name=section, straight_import=True - ), - ) + if not config.only_sections: + straight_modules = sorting.naturally( + straight_modules, + key=lambda key: sorting.module_key( + key, config, section_name=section, straight_import=True + ), + ) + from_modules = parsed.imports[section]["from"] - from_modules = sorting.naturally( - from_modules, key=lambda key: sorting.module_key(key, config, section_name=section) + if not config.only_sections: + from_modules = sorting.naturally( + from_modules, key=lambda key: sorting.module_key(key, config, section_name=section) + ) + + straight_imports = _with_straight_imports( + parsed, config, straight_modules, section, remove_imports, import_type + ) + from_imports = _with_from_imports( + parsed, config, from_modules, section, remove_imports, import_type ) - section_output: List[str] = [] + lines_between = [""] * ( + config.lines_between_types if from_modules and straight_modules else 0 + ) if config.from_first: - section_output = _with_from_imports( - parsed, - config, - from_modules, - section, - section_output, - sort_ignore_case, - remove_imports, - import_type, - ) - if config.lines_between_types and from_modules and straight_modules: - section_output.extend([""] * config.lines_between_types) - section_output = _with_straight_imports( - parsed, - config, - straight_modules, - section, - section_output, - remove_imports, - import_type, - ) + section_output = from_imports + lines_between + straight_imports else: - section_output = _with_straight_imports( - parsed, - config, - straight_modules, - section, - section_output, - remove_imports, - import_type, - ) - if config.lines_between_types and from_modules and straight_modules: - section_output.extend([""] * config.lines_between_types) - section_output = _with_from_imports( - parsed, - config, - from_modules, - section, - section_output, - sort_ignore_case, - remove_imports, - import_type, - ) + section_output = straight_imports + lines_between + from_imports if config.force_sort_within_sections: # collapse comments @@ -121,7 +92,7 @@ comments_above = [] else: new_section_output.append(line) - + # only_sections options is not imposed if force_sort_within_sections is True new_section_output = sorting.naturally( new_section_output, key=partial( @@ -130,6 +101,8 @@ force_to_top=config.force_to_top, lexicographical=config.lexicographical, length_sort=config.length_sort, + reverse_relative=config.reverse_relative, + group_by_package=config.group_by_package, ), ) @@ -138,12 +111,6 @@ for line in new_section_output: comments = getattr(line, "comments", ()) if comments: - if ( - config.ensure_newline_before_comments - and section_output - and section_output[-1] - ): - section_output.append("") section_output.extend(comments) section_output.append(str(line)) @@ -172,6 +139,9 @@ else: pending_lines_before = pending_lines_before or not no_lines_before + if config.ensure_newline_before_comments: + output = _ensure_newline_before_comment(output) + while output and output[-1].strip() == "": output.pop() # pragma: no cover while output and output[0].strip() == "": @@ -220,7 +190,7 @@ if config.lines_after_imports != -1: formatted_output[imports_tail:0] = ["" for line in range(config.lines_after_imports)] - elif extension != "pyi" and next_construct.startswith(STATEMENT_DECLERATIONS): + elif extension != "pyi" and next_construct.startswith(STATEMENT_DECLARATIONS): formatted_output[imports_tail:0] = ["", ""] else: formatted_output[imports_tail:0] = [""] @@ -246,12 +216,10 @@ config: Config, from_modules: Iterable[str], section: str, - section_output: List[str], - ignore_case: bool, remove_imports: List[str], import_type: str, ) -> List[str]: - new_section_output = section_output.copy() + output: List[str] = [] for module in from_modules: if module in remove_imports: continue @@ -261,12 +229,19 @@ if not config.no_inline_sort or ( config.force_single_line and module not in config.single_line_exclusions ): - from_imports = sorting.naturally( - from_imports, - key=lambda key: sorting.module_key( - key, config, True, ignore_case, section_name=section - ), - ) + ignore_case = config.force_alphabetical_sort_within_sections + + if not config.only_sections: + from_imports = sorting.naturally( + from_imports, + key=lambda key: sorting.module_key( + key, + config, + True, + ignore_case, + section_name=section, + ), + ) if remove_imports: from_imports = [ line for line in from_imports if f"{module}.{line}" not in remove_imports @@ -283,7 +258,8 @@ if config.combine_as_imports and not ("*" in from_imports and config.combine_star): if not config.no_inline_sort: for as_import in as_imports: - as_imports[as_import] = sorting.naturally(as_imports[as_import]) + if not config.only_sections: + as_imports[as_import] = sorting.naturally(as_imports[as_import]) for from_import in copy.copy(from_imports): if from_import in as_imports: idx = from_imports.index(from_import) @@ -292,23 +268,18 @@ else: from_imports[idx : (idx + 1)] = as_imports.pop(from_import) + only_show_as_imports = False + comments = parsed.categorized_comments["from"].pop(module, ()) + above_comments = parsed.categorized_comments["above"]["from"].pop(module, None) while from_imports: - comments = parsed.categorized_comments["from"].pop(module, ()) - above_comments = parsed.categorized_comments["above"]["from"].pop(module, None) if above_comments: - if new_section_output and config.ensure_newline_before_comments: - new_section_output.append("") - new_section_output.extend(above_comments) + output.extend(above_comments) + above_comments = None if "*" in from_imports and config.combine_star: - if config.combine_as_imports: - comments = list(comments or ()) - comments += parsed.categorized_comments["from"].pop( - f"{module}.__combined_as__", [] - ) import_statement = wrap.line( with_comments( - comments, + _with_star_comments(parsed, module, list(comments or ())), f"{import_start}*", removed=config.ignore_comments, comment_prefix=config.comment_prefix, @@ -316,7 +287,10 @@ parsed.line_separator, config, ) - from_imports = [] + from_imports = [ + from_import for from_import in from_imports if from_import in as_imports + ] + only_show_as_imports = True elif config.force_single_line and module not in config.single_line_exclusions: import_statement = "" while from_imports: @@ -335,36 +309,66 @@ f"{comments and ';' or config.comment_prefix} " f"{comment}" ) if from_import in as_imports: - if parsed.imports[section]["from"][module][from_import]: - new_section_output.append( + if ( + parsed.imports[section]["from"][module][from_import] + and not only_show_as_imports + ): + output.append( wrap.line(single_import_line, parsed.line_separator, config) ) from_comments = parsed.categorized_comments["straight"].get( f"{module}.{from_import}" ) - new_section_output.extend( - with_comments( - from_comments, - wrap.line(import_start + as_import, parsed.line_separator, config), - removed=config.ignore_comments, - comment_prefix=config.comment_prefix, + + if not config.only_sections: + output.extend( + with_comments( + from_comments, + wrap.line( + import_start + as_import, parsed.line_separator, config + ), + removed=config.ignore_comments, + comment_prefix=config.comment_prefix, + ) + for as_import in sorting.naturally(as_imports[from_import]) + ) + + else: + output.extend( + with_comments( + from_comments, + wrap.line( + import_start + as_import, parsed.line_separator, config + ), + removed=config.ignore_comments, + comment_prefix=config.comment_prefix, + ) + for as_import in as_imports[from_import] ) - for as_import in sorting.naturally(as_imports[from_import]) - ) else: - new_section_output.append( - wrap.line(single_import_line, parsed.line_separator, config) - ) + output.append(wrap.line(single_import_line, parsed.line_separator, config)) comments = None else: while from_imports and from_imports[0] in as_imports: from_import = from_imports.pop(0) - as_imports[from_import] = sorting.naturally(as_imports[from_import]) - from_comments = parsed.categorized_comments["straight"].get( - f"{module}.{from_import}" + + if not config.only_sections: + as_imports[from_import] = sorting.naturally(as_imports[from_import]) + from_comments = ( + parsed.categorized_comments["straight"].get(f"{module}.{from_import}") or [] ) - if parsed.imports[section]["from"][module][from_import]: - new_section_output.append( + if ( + parsed.imports[section]["from"][module][from_import] + and not only_show_as_imports + ): + specific_comment = ( + parsed.categorized_comments["nested"] + .get(module, {}) + .pop(from_import, None) + ) + if specific_comment: + from_comments.append(specific_comment) + output.append( wrap.line( with_comments( from_comments, @@ -376,24 +380,36 @@ config, ) ) - new_section_output.extend( - wrap.line( - with_comments( - from_comments, - import_start + as_import, - removed=config.ignore_comments, - comment_prefix=config.comment_prefix, - ), - parsed.line_separator, - config, + from_comments = [] + + for as_import in as_imports[from_import]: + specific_comment = ( + parsed.categorized_comments["nested"] + .get(module, {}) + .pop(as_import, None) + ) + if specific_comment: + from_comments.append(specific_comment) + + output.append( + wrap.line( + with_comments( + from_comments, + import_start + as_import, + removed=config.ignore_comments, + comment_prefix=config.comment_prefix, + ), + parsed.line_separator, + config, + ) ) - for as_import in as_imports[from_import] - ) + + from_comments = [] if "*" in from_imports: - new_section_output.append( + output.append( with_comments( - comments, + _with_star_comments(parsed, module, list(comments or ())), f"{import_start}*", removed=config.ignore_comments, comment_prefix=config.comment_prefix, @@ -416,9 +432,7 @@ single_import_line += ( f"{comments and ';' or config.comment_prefix} " f"{comment}" ) - new_section_output.append( - wrap.line(single_import_line, parsed.line_separator, config) - ) + output.append(wrap.line(single_import_line, parsed.line_separator, config)) from_imports.remove(from_import) comments = None @@ -486,8 +500,8 @@ import_statement = wrap.line(import_statement, parsed.line_separator, config) if import_statement: - new_section_output.append(import_statement) - return new_section_output + output.append(import_statement) + return output def _with_straight_imports( @@ -495,11 +509,10 @@ config: Config, straight_modules: Iterable[str], section: str, - section_output: List[str], remove_imports: List[str], import_type: str, ) -> List[str]: - new_section_output = section_output.copy() + output: List[str] = [] for module in straight_modules: if module in remove_imports: continue @@ -517,10 +530,8 @@ comments_above = parsed.categorized_comments["above"]["straight"].pop(module, None) if comments_above: - if new_section_output and config.ensure_newline_before_comments: - new_section_output.append("") - new_section_output.extend(comments_above) - new_section_output.extend( + output.extend(comments_above) + output.extend( with_comments( parsed.categorized_comments["straight"].get(module), idef, @@ -530,7 +541,7 @@ for idef in import_definition ) - return new_section_output + return output def _output_as_string(lines: List[str], line_separator: str) -> str: @@ -550,3 +561,24 @@ instance = super().__new__(cls, value) # type: ignore instance.comments = comments return instance + + +def _ensure_newline_before_comment(output): + new_output: List[str] = [] + + def is_comment(line): + return line and line.startswith("#") + + for line, prev_line in zip(output, [None] + output): + if is_comment(line) and prev_line != "" and not is_comment(prev_line): + new_output.append("") + new_output.append(line) + return new_output + + +def _with_star_comments(parsed: parse.ParsedContent, module: str, comments: List[str]) -> List[str]: + star_comment = parsed.categorized_comments["nested"].get(module, {}).pop("*", None) + if star_comment: + return comments + [star_comment] + else: + return comments diff -Nru isort-5.4.2/isort/parse.py isort-5.6.4/isort/parse.py --- isort-5.4.2/isort/parse.py 2020-08-13 03:47:19.716318000 +0000 +++ isort-5.6.4/isort/parse.py 2020-10-13 06:20:58.554927300 +0000 @@ -113,7 +113,7 @@ break char_index += 1 - if ";" in line and needs_import: + if ";" in line.split("#")[0] and needs_import: for part in (part.strip() for part in line.split(";")): if ( part @@ -138,6 +138,7 @@ original_line_count: int line_separator: str sections: Any + verbose_output: List[str] def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedContent: @@ -163,6 +164,8 @@ "from": defaultdict(list), } imports: OrderedDict[str, Dict[str, Any]] = OrderedDict() + verbose_output: List[str] = [] + for section in chain(config.sections, config.forced_separate): imports[section] = {"straight": OrderedDict(), "from": OrderedDict()} categorized_comments: CommentsDict = { @@ -201,10 +204,61 @@ out_lines.append(line) continue - for line in ( - (line.strip() for line in line.split(";")) if ";" in line else (line,) # type: ignore + lstripped_line = line.lstrip() + if ( + config.float_to_top + and import_index == -1 + and line + and not in_quote + and not lstripped_line.startswith("#") + and not lstripped_line.startswith("'''") + and not lstripped_line.startswith('"""') ): - line, raw_line = _normalize_line(line) + if not lstripped_line.startswith("import") and not lstripped_line.startswith("from"): + import_index = index - 1 + while import_index and not in_lines[import_index - 1]: + import_index -= 1 + else: + commentless = line.split("#", 1)[0].strip() + if ( + ("isort:skip" in line or "isort: skip" in line) + and "(" in commentless + and ")" not in commentless + ): + import_index = index + + starting_line = line + while "isort:skip" in starting_line or "isort: skip" in starting_line: + commentless = starting_line.split("#", 1)[0] + if ( + "(" in commentless + and not commentless.rstrip().endswith(")") + and import_index < line_count + ): + + while import_index < line_count and not commentless.rstrip().endswith( + ")" + ): + commentless = in_lines[import_index].split("#", 1)[0] + import_index += 1 + else: + import_index += 1 + + if import_index >= line_count: + break + else: + starting_line = in_lines[import_index] + + line, *end_of_line_comment = line.split("#", 1) + if ";" in line: + statements = [line.strip() for line in line.split(";")] + else: + statements = [line] + if end_of_line_comment: + statements[-1] = f"{statements[-1]}#{end_of_line_comment[0]}" + + for statement in statements: + line, raw_line = _normalize_line(statement) type_of_import = import_type(line, config) or "" if not type_of_import: out_lines.append(raw_line) @@ -216,15 +270,10 @@ import_string, comment = parse_comments(line) comments = [comment] if comment else [] line_parts = [part for part in _strip_syntax(import_string).strip().split(" ") if part] - if ( - type_of_import == "from" - and len(line_parts) == 2 - and line_parts[1] != "*" - and comments - ): + if type_of_import == "from" and len(line_parts) == 2 and comments: nested_comments[line_parts[-1]] = comments[0] - if "(" in line.split("#")[0] and index < line_count: + if "(" in line.split("#", 1)[0] and index < line_count: while not line.split("#")[0].strip().endswith(")") and index < line_count: line, new_comment = parse_comments(in_lines[index]) index += 1 @@ -234,7 +283,7 @@ if ( type_of_import == "from" and stripped_line - and " " not in stripped_line + and " " not in stripped_line.replace(" as ", "") and new_comment ): nested_comments[stripped_line] = comments[-1] @@ -256,7 +305,7 @@ if ( type_of_import == "from" and stripped_line - and " " not in stripped_line + and " " not in stripped_line.replace(" as ", "") and new_comment ): nested_comments[stripped_line] = comments[-1] @@ -271,7 +320,7 @@ if ( type_of_import == "from" and stripped_line - and " " not in stripped_line + and " " not in stripped_line.replace(" as ", "") and new_comment ): nested_comments[stripped_line] = comments[-1] @@ -281,7 +330,7 @@ if ( type_of_import == "from" and stripped_line - and " " not in stripped_line + and " " not in stripped_line.replace(" as ", "") and new_comment ): nested_comments[stripped_line] = comments[-1] @@ -316,6 +365,9 @@ item.replace("{|", "{ ").replace("|}", " }") for item in _strip_syntax(import_string).split() ] + + attach_comments_to: Optional[List[Any]] = None + direct_imports = just_imports[1:] straight_import = True if "as" in just_imports and (just_imports.index("as") + 1) < len(just_imports): straight_import = False @@ -327,10 +379,22 @@ top_level_module = just_imports[0] module = top_level_module + "." + nested_module as_name = just_imports[as_index + 1] + direct_imports.remove(nested_module) + direct_imports.remove(as_name) + direct_imports.remove("as") if nested_module == as_name and config.remove_redundant_aliases: pass elif as_name not in as_map["from"][module]: as_map["from"][module].append(as_name) + + full_name = f"{nested_module} as {as_name}" + associated_comment = nested_comments.get(full_name) + if associated_comment: + categorized_comments["nested"].setdefault(top_level_module, {})[ + full_name + ] = associated_comment + if associated_comment in comments: + comments.pop(comments.index(associated_comment)) else: module = just_imports[as_index - 1] as_name = just_imports[as_index + 1] @@ -339,20 +403,27 @@ elif as_name not in as_map["straight"][module]: as_map["straight"][module].append(as_name) - if config.combine_as_imports and nested_module: - categorized_comments["from"].setdefault( - f"{top_level_module}.__combined_as__", [] - ).extend(comments) - comments = [] - else: - categorized_comments["straight"][module] = comments - comments = [] + if comments and attach_comments_to is None: + if nested_module and config.combine_as_imports: + attach_comments_to = categorized_comments["from"].setdefault( + f"{top_level_module}.__combined_as__", [] + ) + else: + attach_comments_to = categorized_comments["straight"].setdefault( + module, [] + ) del just_imports[as_index : as_index + 2] + if type_of_import == "from": import_from = just_imports.pop(0) placed_module = finder(import_from) - if config.verbose: + if config.verbose and not config.only_modified: print(f"from-type place_module for {import_from} returned {placed_module}") + + elif config.verbose: + verbose_output.append( + f"from-type place_module for {import_from} returned {placed_module}" + ) if placed_module == "": warn( f"could not place module {import_from} of line {line} --" @@ -367,8 +438,9 @@ ] = associated_comment if associated_comment in comments: comments.pop(comments.index(associated_comment)) - if comments: - categorized_comments["from"].setdefault(import_from, []).extend(comments) + + if comments and attach_comments_to is None: + attach_comments_to = categorized_comments["from"].setdefault(import_from, []) if len(out_lines) > max(import_index, 1) - 1: last = out_lines and out_lines[-1].rstrip() or "" @@ -395,14 +467,21 @@ if import_from not in root: root[import_from] = OrderedDict( - (module, straight_import) for module in just_imports + (module, module in direct_imports) for module in just_imports ) else: root[import_from].update( - (module, straight_import | root[import_from].get(module, False)) + (module, root[import_from].get(module, False) or module in direct_imports) for module in just_imports ) + + if comments and attach_comments_to is not None: + attach_comments_to.extend(comments) else: + if comments and attach_comments_to is not None: + attach_comments_to.extend(comments) + comments = [] + for module in just_imports: if comments: categorized_comments["straight"][module] = comments @@ -432,8 +511,13 @@ categorized_comments["above"]["straight"].get(module, []) ) placed_module = finder(module) - if config.verbose: + if config.verbose and not config.only_modified: print(f"else-type place_module for {module} returned {placed_module}") + + elif config.verbose: + verbose_output.append( + f"else-type place_module for {module} returned {placed_module}" + ) if placed_module == "": warn( f"could not place module {module} of line {line} --" @@ -460,4 +544,5 @@ original_line_count=original_line_count, line_separator=line_separator, sections=config.sections, + verbose_output=verbose_output, ) diff -Nru isort-5.4.2/isort/place.py isort-5.6.4/isort/place.py --- isort-5.4.2/isort/place.py 2020-08-05 04:44:25.110057000 +0000 +++ isort-5.6.4/isort/place.py 2020-10-13 06:20:58.554927300 +0000 @@ -3,7 +3,7 @@ from fnmatch import fnmatch from functools import lru_cache from pathlib import Path -from typing import Optional, Tuple +from typing import FrozenSet, Iterable, Optional, Tuple from isort import sections from isort.settings import DEFAULT_CONFIG, Config @@ -54,16 +54,37 @@ module_names_to_check = (".".join(parts[:first_k]) for first_k in range(len(parts), 0, -1)) for module_name_to_check in module_names_to_check: for pattern, placement in config.known_patterns: - if pattern.match(module_name_to_check): + if placement in config.sections and pattern.match(module_name_to_check): return (placement, f"Matched configured known pattern {pattern}") return None -def _src_path(name: str, config: Config) -> Optional[Tuple[str, str]]: - for src_path in config.src_paths: - root_module_name = name.split(".")[0] +def _src_path( + name: str, + config: Config, + src_paths: Optional[Iterable[Path]] = None, + prefix: Tuple[str, ...] = (), +) -> Optional[Tuple[str, str]]: + if src_paths is None: + src_paths = config.src_paths + + root_module_name, *nested_module = name.split(".", 1) + new_prefix = prefix + (root_module_name,) + namespace = ".".join(new_prefix) + + for src_path in src_paths: module_path = (src_path / root_module_name).resolve() + if not prefix and not module_path.is_dir() and src_path.name == root_module_name: + module_path = src_path.resolve() + if nested_module and ( + namespace in config.namespace_packages + or ( + config.auto_identify_namespace_packages + and _is_namespace_package(module_path, config.supported_extensions) + ) + ): + return _src_path(nested_module[0], config, (module_path,), new_prefix) if ( _is_module(module_path) or _is_package(module_path) @@ -89,6 +110,35 @@ return exists_case_sensitive(str(path)) and path.is_dir() +def _is_namespace_package(path: Path, src_extensions: FrozenSet[str]) -> bool: + if not _is_package(path): + return False + + init_file = path / "__init__.py" + if not init_file.exists(): + filenames = [ + filepath + for filepath in path.iterdir() + if filepath.suffix.lstrip(".") in src_extensions + or filepath.name.lower() in ("setup.cfg", "pyproject.toml") + ] + if filenames: + return False + else: + with init_file.open() as open_init_file: + file_start = open_init_file.read(4096) + if ( + "__import__('pkg_resources').declare_namespace(__name__)" not in file_start + and '__import__("pkg_resources").declare_namespace(__name__)' not in file_start + and "__path__ = __import__('pkgutil').extend_path(__path__, __name__)" + not in file_start + and '__path__ = __import__("pkgutil").extend_path(__path__, __name__)' + not in file_start + ): + return False + return True + + def _src_path_is_module(src_path: Path, module_name: str) -> bool: return ( module_name == src_path.name and src_path.is_dir() and exists_case_sensitive(str(src_path)) diff -Nru isort-5.4.2/isort/profiles.py isort-5.6.4/isort/profiles.py --- isort-5.4.2/isort/profiles.py 2020-07-29 04:24:06.097084800 +0000 +++ isort-5.6.4/isort/profiles.py 2020-10-08 06:39:26.721052600 +0000 @@ -15,12 +15,18 @@ "multi_line_output": 5, "line_length": 79, } -pycharm = {"multi_line_output": 3, "force_grid_wrap": 2} +pycharm = { + "multi_line_output": 3, + "force_grid_wrap": 2, + "lines_after_imports": 2, +} google = { "force_single_line": True, "force_sort_within_sections": True, "lexicographical": True, "single_line_exclusions": ("typing",), + "order_by_type": False, + "group_by_package": True, } open_stack = { "force_single_line": True, diff -Nru isort-5.4.2/isort/pylama_isort.py isort-5.6.4/isort/pylama_isort.py --- isort-5.4.2/isort/pylama_isort.py 2020-08-04 04:14:13.867264500 +0000 +++ isort-5.6.4/isort/pylama_isort.py 2020-10-08 06:39:26.721052600 +0000 @@ -5,6 +5,8 @@ from pylama.lint import Linter as BaseLinter +from isort.exceptions import FileSkipped + from . import api @@ -25,9 +27,17 @@ def run(self, path: str, **meta: Any) -> List[Dict[str, Any]]: """Lint the file. Return an array of error dicts if appropriate.""" with supress_stdout(): - if not api.check_file(path): - return [ - {"lnum": 0, "col": 0, "text": "Incorrectly sorted imports.", "type": "ISORT"} - ] - else: - return [] + try: + if not api.check_file(path, disregard_skip=False): + return [ + { + "lnum": 0, + "col": 0, + "text": "Incorrectly sorted imports.", + "type": "ISORT", + } + ] + except FileSkipped: + pass + + return [] diff -Nru isort-5.4.2/isort/settings.py isort-5.6.4/isort/settings.py --- isort-5.4.2/isort/settings.py 2020-08-15 03:12:49.688459900 +0000 +++ isort-5.6.4/isort/settings.py 2020-10-13 06:20:58.554927300 +0000 @@ -18,7 +18,12 @@ from . import stdlibs from ._future import dataclass, field from ._vendored import toml -from .exceptions import FormattingPluginDoesNotExist, InvalidSettingsPath, ProfileDoesNotExist +from .exceptions import ( + FormattingPluginDoesNotExist, + InvalidSettingsPath, + ProfileDoesNotExist, + UnsupportedSettings, +) from .profiles import profiles from .sections import DEFAULT as SECTION_DEFAULTS from .sections import FIRSTPARTY, FUTURE, LOCALFOLDER, STDLIB, THIRDPARTY @@ -26,7 +31,7 @@ from .wrap_modes import from_string as wrap_mode_from_string _SHEBANG_RE = re.compile(br"^#!.*\bpython[23w]?\b") -SUPPORTED_EXTENSIONS = frozenset({"py", "pyi", "pyx"}) +SUPPORTED_EXTENSIONS = frozenset({"py", "pyi", "pyx", "pxd"}) BLOCKED_EXTENSIONS = frozenset({"pex"}) FILE_SKIP_COMMENTS: Tuple[str, ...] = ( "isort:" + "skip_file", @@ -54,11 +59,14 @@ ".hg", ".mypy_cache", ".nox", + ".svn", + ".bzr", "_build", "buck-out", "build", "dist", ".pants.d", + ".direnv", "node_modules", } ) @@ -161,6 +169,7 @@ force_grid_wrap: int = 0 force_sort_within_sections: bool = False lexicographical: bool = False + group_by_package: bool = False ignore_whitespace: bool = False no_lines_before: FrozenSet[str] = frozenset() no_inline_sort: bool = False @@ -173,7 +182,7 @@ directory: str = "" profile: str = "" honor_noqa: bool = False - src_paths: FrozenSet[Path] = frozenset() + src_paths: Tuple[Path, ...] = () old_finders: bool = False remove_redundant_aliases: bool = False float_to_top: bool = False @@ -189,6 +198,10 @@ classes: FrozenSet[str] = frozenset() variables: FrozenSet[str] = frozenset() dedup_headings: bool = False + only_sections: bool = False + only_modified: bool = False + auto_identify_namespace_packages: bool = True + namespace_packages: FrozenSet[str] = frozenset() def __post_init__(self): py_version = self.py_version @@ -255,6 +268,11 @@ super().__init__(**config_vars) # type: ignore return + # We can't use self.quiet to conditionally show warnings before super.__init__() is called + # at the end of this method. _Config is also frozen so setting self.quiet isn't possible. + # Therefore we extract quiet early here in a variable and use that in warning conditions. + quiet = config_overrides.get("quiet", False) + sources: List[Dict[str, Any]] = [_DEFAULT_SETTINGS] config_settings: Dict[str, Any] @@ -265,6 +283,14 @@ CONFIG_SECTIONS.get(os.path.basename(settings_file), FALLBACK_CONFIG_SECTIONS), ) project_root = os.path.dirname(settings_file) + if not config_settings and not quiet: + warn( + f"A custom settings file was specified: {settings_file} but no configuration " + "was found inside. This can happen when [settings] is used as the config " + "header instead of [isort]. " + "See: https://pycqa.github.io/isort/docs/configuration/config_files" + "/#custom_config_files for more information." + ) elif settings_path: if not os.path.exists(settings_path): raise InvalidSettingsPath(settings_path) @@ -324,27 +350,24 @@ combined_config.pop(key) if maps_to_section in KNOWN_SECTION_MAPPING: section_name = f"known_{KNOWN_SECTION_MAPPING[maps_to_section].lower()}" - if section_name in combined_config and not self.quiet: + if section_name in combined_config and not quiet: warn( f"Can't set both {key} and {section_name} in the same config file.\n" f"Default to {section_name} if unsure." "\n\n" - "See: https://timothycrosley.github.io/isort/" + "See: https://pycqa.github.io/isort/" "#custom-sections-and-ordering." ) else: combined_config[section_name] = frozenset(value) else: known_other[import_heading] = frozenset(value) - if ( - maps_to_section not in combined_config.get("sections", ()) - and not self.quiet - ): + if maps_to_section not in combined_config.get("sections", ()) and not quiet: warn( f"`{key}` setting is defined, but {maps_to_section} is not" " included in `sections` config option:" f" {combined_config.get('sections', SECTION_DEFAULTS)}.\n\n" - "See: https://timothycrosley.github.io/isort/" + "See: https://pycqa.github.io/isort/" "#custom-sections-and-ordering." ) if key.startswith(IMPORT_HEADING_PREFIX): @@ -378,11 +401,15 @@ path_root = Path(combined_config.get("directory", project_root)).resolve() path_root = path_root if path_root.is_dir() else path_root.parent if "src_paths" not in combined_config: - combined_config["src_paths"] = frozenset((path_root, path_root / "src")) + combined_config["src_paths"] = (path_root / "src", path_root) else: - combined_config["src_paths"] = frozenset( - path_root / path for path in combined_config.get("src_paths", ()) - ) + src_paths: List[Path] = [] + for src_path in combined_config.get("src_paths", ()): + full_path = path_root / src_path + if full_path not in src_paths: + src_paths.append(full_path) + + combined_config["src_paths"] = tuple(src_paths) if "formatter" in combined_config: import pkg_resources @@ -406,7 +433,7 @@ if deprecated_options_used: for deprecated_option in deprecated_options_used: combined_config.pop(deprecated_option) - if not self.quiet: + if not quiet: warn( "W0503: Deprecated config options were used: " f"{', '.join(deprecated_options_used)}." @@ -420,6 +447,19 @@ combined_config.pop(f"{IMPORT_HEADING_PREFIX}{import_heading_key}") combined_config["import_headings"] = import_headings + unsupported_config_errors = {} + for option in set(combined_config.keys()).difference( + getattr(_Config, "__dataclass_fields__", {}).keys() + ): + for source in reversed(sources): + if option in source: + unsupported_config_errors[option] = { + "value": source[option], + "source": source["source"], + } + if unsupported_config_errors: + raise UnsupportedSettings(unsupported_config_errors) + super().__init__(sources=tuple(sources), **combined_config) # type: ignore def is_supported_filetype(self, file_name: str): @@ -498,12 +538,13 @@ return self._known_patterns self._known_patterns = [] - for placement in reversed(self.sections): + pattern_sections = [STDLIB] + [section for section in self.sections if section != STDLIB] + for placement in reversed(pattern_sections): known_placement = KNOWN_SECTION_MAPPING.get(placement, placement).lower() config_key = f"{KNOWN_PREFIX}{known_placement}" known_modules = getattr(self, config_key, self.known_other.get(known_placement, ())) extra_modules = getattr(self, f"extra_{known_placement}", ()) - all_modules = set(known_modules).union(extra_modules) + all_modules = set(extra_modules).union(known_modules) known_patterns = [ pattern for known_pattern in all_modules diff -Nru isort-5.4.2/isort/setuptools_commands.py isort-5.6.4/isort/setuptools_commands.py --- isort-5.4.2/isort/setuptools_commands.py 2020-08-04 04:14:13.851263500 +0000 +++ isort-5.6.4/isort/setuptools_commands.py 2020-10-08 06:39:26.721052600 +0000 @@ -31,13 +31,13 @@ def distribution_files(self) -> Iterator[str]: """Find distribution packages.""" # This is verbatim from flake8 - if self.distribution.packages: + if self.distribution.packages: # pragma: no cover package_dirs = self.distribution.package_dir or {} for package in self.distribution.packages: pkg_dir = package if package in package_dirs: pkg_dir = package_dirs[package] - elif "" in package_dirs: + elif "" in package_dirs: # pragma: no cover pkg_dir = package_dirs[""] + os.path.sep + pkg_dir yield pkg_dir.replace(".", os.path.sep) diff -Nru isort-5.4.2/isort/sorting.py isort-5.6.4/isort/sorting.py --- isort-5.4.2/isort/sorting.py 2020-08-13 03:47:19.716318000 +0000 +++ isort-5.6.4/isort/sorting.py 2020-10-08 06:39:26.721052600 +0000 @@ -57,9 +57,18 @@ force_to_top: List[str], lexicographical: bool = False, length_sort: bool = False, + reverse_relative: bool = False, + group_by_package: bool = False, ) -> str: section = "B" + if reverse_relative and line.startswith("from ."): + match = re.match(r"^from (\.+)\s*(.*)", line) + if match: # pragma: no cover - regex always matches if line starts with "from ." + line = f"from {' '.join(match.groups())}" + if group_by_package and line.strip().startswith("from"): + line = line.split(" import", 1)[0] + if lexicographical: line = _import_line_intro_re.sub("", _import_line_midline_import_re.sub(".", line)) else: diff -Nru isort-5.4.2/isort/stdlibs/py3.py isort-5.6.4/isort/stdlibs/py3.py --- isort-5.4.2/isort/stdlibs/py3.py 2020-07-29 04:24:06.097084800 +0000 +++ isort-5.6.4/isort/stdlibs/py3.py 2020-10-08 06:39:26.721052600 +0000 @@ -1,3 +1,3 @@ -from . import py35, py36, py37, py38 +from . import py35, py36, py37, py38, py39 -stdlib = py35.stdlib | py36.stdlib | py37.stdlib | py38.stdlib +stdlib = py35.stdlib | py36.stdlib | py37.stdlib | py38.stdlib | py39.stdlib diff -Nru isort-5.4.2/isort/utils.py isort-5.6.4/isort/utils.py --- isort-5.4.2/isort/utils.py 2020-08-04 04:14:13.875265000 +0000 +++ isort-5.6.4/isort/utils.py 2020-10-08 06:39:26.721052600 +0000 @@ -1,7 +1,5 @@ import os import sys -from contextlib import contextmanager -from typing import Iterator def exists_case_sensitive(path: str) -> bool: @@ -16,14 +14,3 @@ directory, basename = os.path.split(path) result = basename in os.listdir(directory) return result - - -@contextmanager -def chdir(path: str) -> Iterator[None]: - """Context manager for changing dir and restoring previous workdir after exit.""" - curdir = os.getcwd() - os.chdir(path) - try: - yield - finally: - os.chdir(curdir) diff -Nru isort-5.4.2/isort/_version.py isort-5.6.4/isort/_version.py --- isort-5.4.2/isort/_version.py 2020-08-15 03:12:49.688459900 +0000 +++ isort-5.6.4/isort/_version.py 2020-10-13 06:21:26.691629600 +0000 @@ -1 +1 @@ -__version__ = "5.4.2" +__version__ = "5.6.4" diff -Nru isort-5.4.2/isort/wrap_modes.py isort-5.6.4/isort/wrap_modes.py --- isort-5.4.2/isort/wrap_modes.py 2020-07-29 04:24:06.097084800 +0000 +++ isort-5.6.4/isort/wrap_modes.py 2020-10-13 06:20:58.554927300 +0000 @@ -34,7 +34,7 @@ def _wrap_mode(function): """Registers an individual wrap mode. Function name and order are significant and used for - creating enum. + creating enum. """ _wrap_modes[function.__name__.upper()] = function function.__signature__ = signature(_wrap_mode_interface) @@ -273,32 +273,40 @@ def vertical_prefix_from_module_import(**interface): if not interface["imports"]: return "" + prefix_statement = interface["statement"] - interface["statement"] += interface["imports"].pop(0) - while interface["imports"]: - next_import = interface["imports"].pop(0) - next_statement = isort.comments.add_to_line( - interface["comments"], - interface["statement"] + ", " + next_import, + output_statement = prefix_statement + interface["imports"].pop(0) + comments = interface["comments"] + + statement = output_statement + statement_with_comments = "" + for next_import in interface["imports"]: + statement = statement + ", " + next_import + statement_with_comments = isort.comments.add_to_line( + comments, + statement, removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) if ( - len(next_statement.split(interface["line_separator"])[-1]) + 1 + len(statement_with_comments.split(interface["line_separator"])[-1]) + 1 > interface["line_length"] ): - next_statement = ( + statement = ( isort.comments.add_to_line( - interface["comments"], - f"{interface['statement']}", + comments, + output_statement, removed=interface["remove_comments"], comment_prefix=interface["comment_prefix"], ) + f"{interface['line_separator']}{prefix_statement}{next_import}" ) - interface["comments"] = [] - interface["statement"] = next_statement - return interface["statement"] + comments = [] + output_statement = statement + + if comments and statement_with_comments: + output_statement = statement_with_comments + return output_statement @_wrap_mode @@ -306,6 +314,12 @@ return _hanging_indent_common(use_parentheses=True, **interface) +@_wrap_mode +def backslash_grid(**interface): + interface["indent"] = interface["white_space"][:-1] + return _hanging_indent_common(use_parentheses=False, **interface) + + WrapModes = enum.Enum( # type: ignore "WrapModes", {wrap_mode: index for index, wrap_mode in enumerate(_wrap_modes.keys())} ) diff -Nru isort-5.4.2/isort/wrap.py isort-5.6.4/isort/wrap.py --- isort-5.4.2/isort/wrap.py 2020-08-05 04:44:25.110057000 +0000 +++ isort-5.6.4/isort/wrap.py 2020-09-20 21:35:13.200999500 +0000 @@ -75,11 +75,13 @@ splitter ): line_parts = re.split(exp, line_without_comment) - if comment: + if comment and not (config.use_parentheses and "noqa" in comment): _comma_maybe = ( "," if (config.include_trailing_comma and config.use_parentheses) else "" ) - line_parts[-1] = f"{line_parts[-1].strip()}{_comma_maybe} #{comment}" + line_parts[ + -1 + ] = f"{line_parts[-1].strip()}{_comma_maybe}{config.comment_prefix}{comment}" next_line = [] while (len(content) + 2) > ( config.wrap_length or config.line_length @@ -104,8 +106,14 @@ _separator = line_separator else: _separator = "" + _comment = "" + if comment and "noqa" in comment: + _comment = f"{config.comment_prefix}{comment}" + cont_line = cont_line.rstrip() + _comma = "," if config.include_trailing_comma else "" output = ( - f"{content}{splitter}({line_separator}{cont_line}{_comma}{_separator})" + f"{content}{splitter}({_comment}" + f"{line_separator}{cont_line}{_comma}{_separator})" ) lines = output.split(line_separator) if config.comment_prefix in lines[-1] and lines[-1].endswith(")"): diff -Nru isort-5.4.2/PKG-INFO isort-5.6.4/PKG-INFO --- isort-5.4.2/PKG-INFO 2020-08-15 03:13:04.999499000 +0000 +++ isort-5.6.4/PKG-INFO 2020-10-13 06:36:35.482539000 +0000 @@ -1,8 +1,8 @@ Metadata-Version: 2.1 Name: isort -Version: 5.4.2 +Version: 5.6.4 Summary: A Python utility / library to sort Python imports. -Home-page: https://timothycrosley.github.io/isort/ +Home-page: https://pycqa.github.io/isort/ License: MIT Keywords: Refactor,Lint,Imports,Sort,Clean Author: Timothy Crosley @@ -31,30 +31,28 @@ Requires-Dist: pip-api; extra == "requirements_deprecated_finder" Requires-Dist: pipreqs; extra == "pipfile_deprecated_finder" or extra == "requirements_deprecated_finder" Requires-Dist: requirementslib; extra == "pipfile_deprecated_finder" -Requires-Dist: tomlkit (>=0.5.3); extra == "pipfile_deprecated_finder" -Project-URL: Changelog, https://github.com/timothycrosley/isort/blob/master/CHANGELOG.md -Project-URL: Documentation, https://timothycrosley.github.io/isort/ -Project-URL: Repository, https://github.com/timothycrosley/isort +Project-URL: Changelog, https://github.com/pycqa/isort/blob/master/CHANGELOG.md +Project-URL: Documentation, https://pycqa.github.io/isort/ +Project-URL: Repository, https://github.com/pycqa/isort Description-Content-Type: text/markdown -[![isort - isort your imports, so you don't have to.](https://raw.githubusercontent.com/timothycrosley/isort/develop/art/logo_large.png)](https://timothycrosley.github.io/isort/) +[![isort - isort your imports, so you don't have to.](https://raw.githubusercontent.com/pycqa/isort/develop/art/logo_large.png)](https://pycqa.github.io/isort/) ------------------------------------------------------------------------ [![PyPI version](https://badge.fury.io/py/isort.svg)](https://badge.fury.io/py/isort) -[![Test Status](https://github.com/timothycrosley/isort/workflows/Test/badge.svg?branch=develop)](https://github.com/timothycrosley/isort/actions?query=workflow%3ATest) -[![Lint Status](https://github.com/timothycrosley/isort/workflows/Lint/badge.svg?branch=develop)](https://github.com/timothycrosley/isort/actions?query=workflow%3ALint) -[![Code coverage Status](https://codecov.io/gh/timothycrosley/isort/branch/develop/graph/badge.svg)](https://codecov.io/gh/timothycrosley/isort) -[![Maintainability](https://api.codeclimate.com/v1/badges/060372d3e77573072609/maintainability)](https://codeclimate.com/github/timothycrosley/isort/maintainability) +[![Test Status](https://github.com/pycqa/isort/workflows/Test/badge.svg?branch=develop)](https://github.com/pycqa/isort/actions?query=workflow%3ATest) +[![Lint Status](https://github.com/pycqa/isort/workflows/Lint/badge.svg?branch=develop)](https://github.com/pycqa/isort/actions?query=workflow%3ALint) +[![Code coverage Status](https://codecov.io/gh/pycqa/isort/branch/develop/graph/badge.svg)](https://codecov.io/gh/pycqa/isort) [![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://pypi.org/project/isort/) [![Join the chat at https://gitter.im/timothycrosley/isort](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/timothycrosley/isort?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Downloads](https://pepy.tech/badge/isort)](https://pepy.tech/project/isort) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) -[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/timothycrosley/isort/?ref=repository-badge) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) +[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/pycqa/isort/?ref=repository-badge) _________________ -[Read Latest Documentation](https://timothycrosley.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/timothycrosley/isort/) +[Read Latest Documentation](https://pycqa.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/pycqa/isort/) _________________ isort your imports, so you don't have to. @@ -62,13 +60,13 @@ isort is a Python utility / library to sort imports alphabetically, and automatically separated into sections and by type. It provides a command line utility, Python library and [plugins for various -editors](https://github.com/timothycrosley/isort/wiki/isort-Plugins) to +editors](https://github.com/pycqa/isort/wiki/isort-Plugins) to quickly sort all your imports. It requires Python 3.6+ to run but supports formatting Python 2 code too. -[Try isort now from your browser!](https://timothycrosley.github.io/isort/docs/quick_start/0.-try/) +[Try isort now from your browser!](https://pycqa.github.io/isort/docs/quick_start/0.-try/) -![Example Usage](https://raw.github.com/timothycrosley/isort/develop/example.gif) +![Example Usage](https://raw.github.com/pycqa/isort/develop/example.gif) Before isort: @@ -176,7 +174,7 @@ **From within Python**: -```bash +```python import isort isort.file("pythonfile.py") @@ -184,7 +182,7 @@ or: -```bash +```python import isort sorted_code = isort.code("import b\nimport a\n") @@ -194,7 +192,7 @@ Several plugins have been written that enable to use isort from within a variety of text-editors. You can find a full list of them [on the isort -wiki](https://github.com/timothycrosley/isort/wiki/isort-Plugins). +wiki](https://github.com/pycqa/isort/wiki/isort-Plugins). Additionally, I will enthusiastically accept pull requests that include plugins for other text editors and add documentation for them as I am notified. @@ -203,7 +201,7 @@ You will notice above the \"multi\_line\_output\" setting. This setting defines how from imports wrap when they extend past the line\_length -limit and has 6 possible settings: +limit and has 12 possible settings: **0 - Grid** @@ -324,7 +322,18 @@ lib4, lib5, lib6) ``` -Note: to change the how constant indents appear - simply change the +**11 - Backslash Grid** + +Same as Mode 0 - _Grid_ but uses backslashes instead of parentheses to group imports. + +```python +from third_party import lib1, lib2, lib3, \ + lib4, lib5 +``` + +## Indentation + +To change the how constant indents appear - simply change the indent property with the following accepted formats: - Number of spaces you would like. For example: 4 would cause standard @@ -482,7 +491,7 @@ from a import a # This will always appear below because it is a from import. ``` -However, if you prefer to keep strict alphabetical sorting you can set [force sort within sections](https://timothycrosley.github.io/isort/docs/configuration/options/#force-sort-within-sections) to true. Resulting in: +However, if you prefer to keep strict alphabetical sorting you can set [force sort within sections](https://pycqa.github.io/isort/docs/configuration/options/#force-sort-within-sections) to true. Resulting in: ```python @@ -490,7 +499,7 @@ import b ``` -You can even tell isort to always place from imports on top, instead of the default of placing them on bottom, using [from first](https://timothycrosley.github.io/isort/docs/configuration/options/#from-first). +You can even tell isort to always place from imports on top, instead of the default of placing them on bottom, using [from first](https://pycqa.github.io/isort/docs/configuration/options/#from-first). ```python from b import b # If from first is set to True, all from imports will be placed before non-from imports. @@ -562,9 +571,9 @@ The `--check-only` option ------------------------- -isort can also be used to used to verify that code is correctly -formatted by running it with `-c`. Any files that contain incorrectly -sorted and/or formatted imports will be outputted to `stderr`. +isort can also be used to verify that code is correctly formatted +by running it with `-c`. Any files that contain incorrectly sorted +and/or formatted imports will be outputted to `stderr`. ```bash isort **/*.py -c -v @@ -595,7 +604,7 @@ import sys from isort.hooks import git_hook -sys.exit(git_hook(strict=True, modify=True, lazy=True)) +sys.exit(git_hook(strict=True, modify=True, lazy=True, settings_file="")) ``` If you just want to display warnings, but allow the commit to happen @@ -608,6 +617,15 @@ leave it out or set it to `False` to check only files added to your index. +If you want to use a specific configuration file for the hook, you can pass its +path to settings_file. If no path is specifically requested, `git_hook` will +search for the configuration file starting at the directory containing the first +staged file, as per `git diff-index` ordering, and going upward in the directory +structure until a valid configuration file is found or +[`MAX_CONFIG_SEARCH_DEPTH`](src/config.py:35) directories are checked. +The settings_file parameter is used to support users who keep their configuration +file in a directory that might not be a parent of all the other files. + ## Setuptools integration Upon installation, isort enables a `setuptools` command that checks @@ -638,21 +656,21 @@ ## Spread the word -[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) Place this badge at the top of your repository to let others know your project uses isort. For README.md: ```markdown -[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) ``` Or README.rst: ```rst .. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336 - :target: https://timothycrosley.github.io/isort/ + :target: https://pycqa.github.io/isort/ ``` ## Security contact information diff -Nru isort-5.4.2/pyproject.toml isort-5.6.4/pyproject.toml --- isort-5.4.2/pyproject.toml 2020-08-15 03:12:49.688459900 +0000 +++ isort-5.6.4/pyproject.toml 2020-10-13 06:21:21.211492800 +0000 @@ -3,14 +3,14 @@ [tool.poetry] name = "isort" -version = "5.4.2" +version = "5.6.4" description = "A Python utility / library to sort Python imports." authors = ["Timothy Crosley "] license = "MIT" readme = "README.md" -repository = "https://github.com/timothycrosley/isort" -homepage = "https://timothycrosley.github.io/isort/" -documentation = "https://timothycrosley.github.io/isort/" +repository = "https://github.com/pycqa/isort" +homepage = "https://pycqa.github.io/isort/" +documentation = "https://pycqa.github.io/isort/" keywords = ["Refactor", "Lint", "Imports", "Sort", "Clean"] classifiers = [ "Development Status :: 6 - Mature", @@ -30,22 +30,23 @@ "Topic :: Software Development :: Libraries", "Topic :: Utilities", ] -urls = { Changelog = "https://github.com/timothycrosley/isort/blob/master/CHANGELOG.md" } +urls = { Changelog = "https://github.com/pycqa/isort/blob/master/CHANGELOG.md" } packages = [ { include = "isort" }, - { include = "tests", format = "sdist" }, +] +include = [ + { path = "tests", format = "sdist" }, ] [tool.poetry.dependencies] python = "^3.6" pipreqs = {version = "*", optional = true} requirementslib = {version = "*", optional = true} -tomlkit = {version = ">=0.5.3", optional = true} pip-api = {version = "*", optional = true} colorama = {version = "^0.4.3", optional = true} [tool.poetry.extras] -pipfile_deprecated_finder = ["pipreqs", "tomlkit", "requirementslib", "pip-shims<=0.3.4"] +pipfile_deprecated_finder = ["pipreqs", "requirementslib", "pip-shims<=0.3.4"] requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama"] @@ -54,7 +55,7 @@ bandit = "^1.6" safety = "^1.8" flake8-bugbear = "^19.8" -black = {version = "^19.10b0", allow-prereleases = true} +black = {version = "^20.08b1", allow-prereleases = true} mypy = "^0.761.0" ipython = "^7.7" pytest = "^5.0" @@ -64,12 +65,11 @@ hypothesis-auto = { version = "^1.0.0" } hypothesmith = "^0.1.3" examples = { version = "^1.0.0" } -cruft = { version = "^1.1" } +cruft = { version = "^2.2" } portray = { version = "^1.3.0" } pipfile = "^0.0.2" requirementslib = "^1.5" pipreqs = "^0.4.9" -tomlkit = ">=0.5.3" pip_api = "^0.0.12" numpy = "^1.16.0" pylama = "^7.7" @@ -79,7 +79,7 @@ gitdb2 = "^4.0.2" httpx = "^0.13.3" example_shared_isort_profile = "^0.0.1" -example_isort_formatting_plugin = "^0.0.1" +example_isort_formatting_plugin = "^0.0.2" [tool.poetry.scripts] isort = "isort.main:main" @@ -88,10 +88,10 @@ isort = "isort.main:ISortCommand" [tool.poetry.plugins."pylama.linter"] -isort = "isort = isort.pylama_isort:Linter" +isort = "isort.pylama_isort:Linter" [tool.portray.mkdocs] -edit_uri = "https://github.com/timothycrosley/isort/edit/develop/" +edit_uri = "https://github.com/pycqa/isort/edit/develop/" extra_css = ["art/stylesheets/extra.css"] [tool.portray.mkdocs.theme] @@ -101,5 +101,5 @@ palette = {scheme = "isort"} [build-system] -requires = ["poetry>=0.12"] -build-backend = "poetry.masonry.api" +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff -Nru isort-5.4.2/README.md isort-5.6.4/README.md --- isort-5.4.2/README.md 2020-08-13 03:47:19.716318000 +0000 +++ isort-5.6.4/README.md 2020-10-08 06:39:26.721052600 +0000 @@ -1,21 +1,20 @@ -[![isort - isort your imports, so you don't have to.](https://raw.githubusercontent.com/timothycrosley/isort/develop/art/logo_large.png)](https://timothycrosley.github.io/isort/) +[![isort - isort your imports, so you don't have to.](https://raw.githubusercontent.com/pycqa/isort/develop/art/logo_large.png)](https://pycqa.github.io/isort/) ------------------------------------------------------------------------ [![PyPI version](https://badge.fury.io/py/isort.svg)](https://badge.fury.io/py/isort) -[![Test Status](https://github.com/timothycrosley/isort/workflows/Test/badge.svg?branch=develop)](https://github.com/timothycrosley/isort/actions?query=workflow%3ATest) -[![Lint Status](https://github.com/timothycrosley/isort/workflows/Lint/badge.svg?branch=develop)](https://github.com/timothycrosley/isort/actions?query=workflow%3ALint) -[![Code coverage Status](https://codecov.io/gh/timothycrosley/isort/branch/develop/graph/badge.svg)](https://codecov.io/gh/timothycrosley/isort) -[![Maintainability](https://api.codeclimate.com/v1/badges/060372d3e77573072609/maintainability)](https://codeclimate.com/github/timothycrosley/isort/maintainability) +[![Test Status](https://github.com/pycqa/isort/workflows/Test/badge.svg?branch=develop)](https://github.com/pycqa/isort/actions?query=workflow%3ATest) +[![Lint Status](https://github.com/pycqa/isort/workflows/Lint/badge.svg?branch=develop)](https://github.com/pycqa/isort/actions?query=workflow%3ALint) +[![Code coverage Status](https://codecov.io/gh/pycqa/isort/branch/develop/graph/badge.svg)](https://codecov.io/gh/pycqa/isort) [![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://pypi.org/project/isort/) [![Join the chat at https://gitter.im/timothycrosley/isort](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/timothycrosley/isort?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Downloads](https://pepy.tech/badge/isort)](https://pepy.tech/project/isort) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) -[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/timothycrosley/isort/?ref=repository-badge) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) +[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/pycqa/isort/?ref=repository-badge) _________________ -[Read Latest Documentation](https://timothycrosley.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/timothycrosley/isort/) +[Read Latest Documentation](https://pycqa.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/pycqa/isort/) _________________ isort your imports, so you don't have to. @@ -23,13 +22,13 @@ isort is a Python utility / library to sort imports alphabetically, and automatically separated into sections and by type. It provides a command line utility, Python library and [plugins for various -editors](https://github.com/timothycrosley/isort/wiki/isort-Plugins) to +editors](https://github.com/pycqa/isort/wiki/isort-Plugins) to quickly sort all your imports. It requires Python 3.6+ to run but supports formatting Python 2 code too. -[Try isort now from your browser!](https://timothycrosley.github.io/isort/docs/quick_start/0.-try/) +[Try isort now from your browser!](https://pycqa.github.io/isort/docs/quick_start/0.-try/) -![Example Usage](https://raw.github.com/timothycrosley/isort/develop/example.gif) +![Example Usage](https://raw.github.com/pycqa/isort/develop/example.gif) Before isort: @@ -137,7 +136,7 @@ **From within Python**: -```bash +```python import isort isort.file("pythonfile.py") @@ -145,7 +144,7 @@ or: -```bash +```python import isort sorted_code = isort.code("import b\nimport a\n") @@ -155,7 +154,7 @@ Several plugins have been written that enable to use isort from within a variety of text-editors. You can find a full list of them [on the isort -wiki](https://github.com/timothycrosley/isort/wiki/isort-Plugins). +wiki](https://github.com/pycqa/isort/wiki/isort-Plugins). Additionally, I will enthusiastically accept pull requests that include plugins for other text editors and add documentation for them as I am notified. @@ -164,7 +163,7 @@ You will notice above the \"multi\_line\_output\" setting. This setting defines how from imports wrap when they extend past the line\_length -limit and has 6 possible settings: +limit and has 12 possible settings: **0 - Grid** @@ -285,7 +284,18 @@ lib4, lib5, lib6) ``` -Note: to change the how constant indents appear - simply change the +**11 - Backslash Grid** + +Same as Mode 0 - _Grid_ but uses backslashes instead of parentheses to group imports. + +```python +from third_party import lib1, lib2, lib3, \ + lib4, lib5 +``` + +## Indentation + +To change the how constant indents appear - simply change the indent property with the following accepted formats: - Number of spaces you would like. For example: 4 would cause standard @@ -443,7 +453,7 @@ from a import a # This will always appear below because it is a from import. ``` -However, if you prefer to keep strict alphabetical sorting you can set [force sort within sections](https://timothycrosley.github.io/isort/docs/configuration/options/#force-sort-within-sections) to true. Resulting in: +However, if you prefer to keep strict alphabetical sorting you can set [force sort within sections](https://pycqa.github.io/isort/docs/configuration/options/#force-sort-within-sections) to true. Resulting in: ```python @@ -451,7 +461,7 @@ import b ``` -You can even tell isort to always place from imports on top, instead of the default of placing them on bottom, using [from first](https://timothycrosley.github.io/isort/docs/configuration/options/#from-first). +You can even tell isort to always place from imports on top, instead of the default of placing them on bottom, using [from first](https://pycqa.github.io/isort/docs/configuration/options/#from-first). ```python from b import b # If from first is set to True, all from imports will be placed before non-from imports. @@ -523,9 +533,9 @@ The `--check-only` option ------------------------- -isort can also be used to used to verify that code is correctly -formatted by running it with `-c`. Any files that contain incorrectly -sorted and/or formatted imports will be outputted to `stderr`. +isort can also be used to verify that code is correctly formatted +by running it with `-c`. Any files that contain incorrectly sorted +and/or formatted imports will be outputted to `stderr`. ```bash isort **/*.py -c -v @@ -556,7 +566,7 @@ import sys from isort.hooks import git_hook -sys.exit(git_hook(strict=True, modify=True, lazy=True)) +sys.exit(git_hook(strict=True, modify=True, lazy=True, settings_file="")) ``` If you just want to display warnings, but allow the commit to happen @@ -569,6 +579,15 @@ leave it out or set it to `False` to check only files added to your index. +If you want to use a specific configuration file for the hook, you can pass its +path to settings_file. If no path is specifically requested, `git_hook` will +search for the configuration file starting at the directory containing the first +staged file, as per `git diff-index` ordering, and going upward in the directory +structure until a valid configuration file is found or +[`MAX_CONFIG_SEARCH_DEPTH`](src/config.py:35) directories are checked. +The settings_file parameter is used to support users who keep their configuration +file in a directory that might not be a parent of all the other files. + ## Setuptools integration Upon installation, isort enables a `setuptools` command that checks @@ -599,21 +618,21 @@ ## Spread the word -[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) Place this badge at the top of your repository to let others know your project uses isort. For README.md: ```markdown -[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) ``` Or README.rst: ```rst .. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336 - :target: https://timothycrosley.github.io/isort/ + :target: https://pycqa.github.io/isort/ ``` ## Security contact information diff -Nru isort-5.4.2/setup.py isort-5.6.4/setup.py --- isort-5.4.2/setup.py 2020-08-15 03:13:04.998760700 +0000 +++ isort-5.6.4/setup.py 2020-10-13 06:36:35.481438900 +0000 @@ -6,32 +6,31 @@ 'isort._future', 'isort._vendored.toml', 'isort.deprecated', - 'isort.stdlibs', - 'tests'] + 'isort.stdlibs'] package_data = \ {'': ['*']} extras_require = \ {'colors': ['colorama>=0.4.3,<0.5.0'], - 'pipfile_deprecated_finder': ['pipreqs', 'requirementslib', 'tomlkit>=0.5.3'], + 'pipfile_deprecated_finder': ['pipreqs', 'requirementslib'], 'requirements_deprecated_finder': ['pipreqs', 'pip-api']} entry_points = \ {'console_scripts': ['isort = isort.main:main'], 'distutils.commands': ['isort = isort.main:ISortCommand'], - 'pylama.linter': ['isort = isort = isort.pylama_isort:Linter']} + 'pylama.linter': ['isort = isort.pylama_isort:Linter']} setup_kwargs = { 'name': 'isort', - 'version': '5.4.2', + 'version': '5.6.4', 'description': 'A Python utility / library to sort Python imports.', - 'long_description': '[![isort - isort your imports, so you don\'t have to.](https://raw.githubusercontent.com/timothycrosley/isort/develop/art/logo_large.png)](https://timothycrosley.github.io/isort/)\n\n------------------------------------------------------------------------\n\n[![PyPI version](https://badge.fury.io/py/isort.svg)](https://badge.fury.io/py/isort)\n[![Test Status](https://github.com/timothycrosley/isort/workflows/Test/badge.svg?branch=develop)](https://github.com/timothycrosley/isort/actions?query=workflow%3ATest)\n[![Lint Status](https://github.com/timothycrosley/isort/workflows/Lint/badge.svg?branch=develop)](https://github.com/timothycrosley/isort/actions?query=workflow%3ALint)\n[![Code coverage Status](https://codecov.io/gh/timothycrosley/isort/branch/develop/graph/badge.svg)](https://codecov.io/gh/timothycrosley/isort)\n[![Maintainability](https://api.codeclimate.com/v1/badges/060372d3e77573072609/maintainability)](https://codeclimate.com/github/timothycrosley/isort/maintainability)\n[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://pypi.org/project/isort/)\n[![Join the chat at https://gitter.im/timothycrosley/isort](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/timothycrosley/isort?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n[![Downloads](https://pepy.tech/badge/isort)](https://pepy.tech/project/isort)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/)\n[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/timothycrosley/isort/?ref=repository-badge)\n_________________\n\n[Read Latest Documentation](https://timothycrosley.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/timothycrosley/isort/)\n_________________\n\nisort your imports, so you don\'t have to.\n\nisort is a Python utility / library to sort imports alphabetically, and\nautomatically separated into sections and by type. It provides a command line\nutility, Python library and [plugins for various\neditors](https://github.com/timothycrosley/isort/wiki/isort-Plugins) to\nquickly sort all your imports. It requires Python 3.6+ to run but\nsupports formatting Python 2 code too.\n\n[Try isort now from your browser!](https://timothycrosley.github.io/isort/docs/quick_start/0.-try/)\n\n![Example Usage](https://raw.github.com/timothycrosley/isort/develop/example.gif)\n\nBefore isort:\n\n```python\nfrom my_lib import Object\n\nimport os\n\nfrom my_lib import Object3\n\nfrom my_lib import Object2\n\nimport sys\n\nfrom third_party import lib15, lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14\n\nimport sys\n\nfrom __future__ import absolute_import\n\nfrom third_party import lib3\n\nprint("Hey")\nprint("yo")\n```\n\nAfter isort:\n\n```python\nfrom __future__ import absolute_import\n\nimport os\nimport sys\n\nfrom third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8,\n lib9, lib10, lib11, lib12, lib13, lib14, lib15)\n\nfrom my_lib import Object, Object2, Object3\n\nprint("Hey")\nprint("yo")\n```\n\n## Installing isort\n\nInstalling isort is as simple as:\n\n```bash\npip install isort\n```\n\nInstall isort with requirements.txt support:\n\n```bash\npip install isort[requirements_deprecated_finder]\n```\n\nInstall isort with Pipfile support:\n\n```bash\npip install isort[pipfile_deprecated_finder]\n```\n\nInstall isort with both formats support:\n\n```bash\npip install isort[requirements_deprecated_finder,pipfile_deprecated_finder]\n```\n\n## Using isort\n\n**From the command line**:\n\n```bash\nisort mypythonfile.py mypythonfile2.py\n```\n\nor recursively:\n\n```bash\nisort .\n```\n\n*which is equivalent to:*\n\n```bash\nisort **/*.py\n```\n\nor to see the proposed changes without applying them:\n\n```bash\nisort mypythonfile.py --diff\n```\n\nFinally, to atomically run isort against a project, only applying\nchanges if they don\'t introduce syntax errors do:\n\n```bash\nisort --atomic .\n```\n\n(Note: this is disabled by default as it keeps isort from being able to\nrun against code written using a different version of Python)\n\n**From within Python**:\n\n```bash\nimport isort\n\nisort.file("pythonfile.py")\n```\n\nor:\n\n```bash\nimport isort\n\nsorted_code = isort.code("import b\\nimport a\\n")\n```\n\n## Installing isort\'s for your preferred text editor\n\nSeveral plugins have been written that enable to use isort from within a\nvariety of text-editors. You can find a full list of them [on the isort\nwiki](https://github.com/timothycrosley/isort/wiki/isort-Plugins).\nAdditionally, I will enthusiastically accept pull requests that include\nplugins for other text editors and add documentation for them as I am\nnotified.\n\n## Multi line output modes\n\nYou will notice above the \\"multi\\_line\\_output\\" setting. This setting\ndefines how from imports wrap when they extend past the line\\_length\nlimit and has 6 possible settings:\n\n**0 - Grid**\n\n```python\nfrom third_party import (lib1, lib2, lib3,\n lib4, lib5, ...)\n```\n\n**1 - Vertical**\n\n```python\nfrom third_party import (lib1,\n lib2,\n lib3\n lib4,\n lib5,\n ...)\n```\n\n**2 - Hanging Indent**\n\n```python\nfrom third_party import \\\n lib1, lib2, lib3, \\\n lib4, lib5, lib6\n```\n\n**3 - Vertical Hanging Indent**\n\n```python\nfrom third_party import (\n lib1,\n lib2,\n lib3,\n lib4,\n)\n```\n\n**4 - Hanging Grid**\n\n```python\nfrom third_party import (\n lib1, lib2, lib3, lib4,\n lib5, ...)\n```\n\n**5 - Hanging Grid Grouped**\n\n```python\nfrom third_party import (\n lib1, lib2, lib3, lib4,\n lib5, ...\n)\n```\n\n**6 - Hanging Grid Grouped, No Trailing Comma**\n\nIn Mode 5 isort leaves a single extra space to maintain consistency of\noutput when a comma is added at the end. Mode 6 is the same - except\nthat no extra space is maintained leading to the possibility of lines\none character longer. You can enforce a trailing comma by using this in\nconjunction with `-tc` or `include_trailing_comma: True`.\n\n```python\nfrom third_party import (\n lib1, lib2, lib3, lib4,\n lib5\n)\n```\n\n**7 - NOQA**\n\n```python\nfrom third_party import lib1, lib2, lib3, ... # NOQA\n```\n\nAlternatively, you can set `force_single_line` to `True` (`-sl` on the\ncommand line) and every import will appear on its own line:\n\n```python\nfrom third_party import lib1\nfrom third_party import lib2\nfrom third_party import lib3\n...\n```\n\n**8 - Vertical Hanging Indent Bracket**\n\nSame as Mode 3 - _Vertical Hanging Indent_ but the closing parentheses\non the last line is indented.\n\n```python\nfrom third_party import (\n lib1,\n lib2,\n lib3,\n lib4,\n )\n```\n\n**9 - Vertical Prefix From Module Import**\n\nStarts a new line with the same `from MODULE import ` prefix when lines are longer than the line length limit.\n\n```python\nfrom third_party import lib1, lib2, lib3\nfrom third_party import lib4, lib5, lib6\n```\n\n**10 - Hanging Indent With Parentheses**\n\nSame as Mode 2 - _Hanging Indent_ but uses parentheses instead of backslash\nfor wrapping long lines.\n\n```python\nfrom third_party import (\n lib1, lib2, lib3,\n lib4, lib5, lib6)\n```\n\nNote: to change the how constant indents appear - simply change the\nindent property with the following accepted formats:\n\n- Number of spaces you would like. For example: 4 would cause standard\n 4 space indentation.\n- Tab\n- A verbatim string with quotes around it.\n\nFor example:\n\n```python\n" "\n```\n\nis equivalent to 4.\n\nFor the import styles that use parentheses, you can control whether or\nnot to include a trailing comma after the last import with the\n`include_trailing_comma` option (defaults to `False`).\n\n## Intelligently Balanced Multi-line Imports\n\nAs of isort 3.1.0 support for balanced multi-line imports has been\nadded. With this enabled isort will dynamically change the import length\nto the one that produces the most balanced grid, while staying below the\nmaximum import length defined.\n\nExample:\n\n```python\nfrom __future__ import (absolute_import, division,\n print_function, unicode_literals)\n```\n\nWill be produced instead of:\n\n```python\nfrom __future__ import (absolute_import, division, print_function,\n unicode_literals)\n```\n\nTo enable this set `balanced_wrapping` to `True` in your config or pass\nthe `-e` option into the command line utility.\n\n## Custom Sections and Ordering\n\nYou can change the section order with `sections` option from the default\nof:\n\n```ini\nFUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER\n```\n\nto your preference:\n\n```ini\nsections=FUTURE,STDLIB,FIRSTPARTY,THIRDPARTY,LOCALFOLDER\n```\n\nYou also can define your own sections and their order.\n\nExample:\n\n```ini\nknown_django=django\nknown_pandas=pandas,numpy\nsections=FUTURE,STDLIB,DJANGO,THIRDPARTY,PANDAS,FIRSTPARTY,LOCALFOLDER\n```\n\nwould create two new sections with the specified known modules.\n\nThe `no_lines_before` option will prevent the listed sections from being\nsplit from the previous section by an empty line.\n\nExample:\n\n```ini\nsections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER\nno_lines_before=LOCALFOLDER\n```\n\nwould produce a section with both FIRSTPARTY and LOCALFOLDER modules\ncombined.\n\n**IMPORTANT NOTE**: It is very important to know when setting `known` sections that the naming\ndoes not directly map for historical reasons. For custom settings, the only difference is\ncapitalization (`known_custom=custom` VS `sections=CUSTOM,...`) for all others reference the\nfollowing mapping:\n\n - `known_standard_library` : `STANDARD_LIBRARY`\n - `extra_standard_library` : `STANDARD_LIBRARY` # Like known standard library but appends instead of replacing\n - `known_future_library` : `FUTURE`\n - `known_first_party`: `FIRSTPARTY`\n - `known_third_party`: `THIRDPARTY`\n - `known_local_folder`: `LOCALFOLDER`\n\nThis will likely be changed in isort 6.0.0+ in a backwards compatible way.\n\n## Auto-comment import sections\n\nSome projects prefer to have import sections uniquely titled to aid in\nidentifying the sections quickly when visually scanning. isort can\nautomate this as well. To do this simply set the\n`import_heading_{section_name}` setting for each section you wish to\nhave auto commented - to the desired comment.\n\nFor Example:\n\n```ini\nimport_heading_stdlib=Standard Library\nimport_heading_firstparty=My Stuff\n```\n\nWould lead to output looking like the following:\n\n```python\n# Standard Library\nimport os\nimport sys\n\nimport django.settings\n\n# My Stuff\nimport myproject.test\n```\n\n## Ordering by import length\n\nisort also makes it easy to sort your imports by length, simply by\nsetting the `length_sort` option to `True`. This will result in the\nfollowing output style:\n\n```python\nfrom evn.util import (\n Pool,\n Dict,\n Options,\n Constant,\n DecayDict,\n UnexpectedCodePath,\n)\n```\n\nIt is also possible to opt-in to sorting imports by length for only\nspecific sections by using `length_sort_` followed by the section name\nas a configuration item, e.g.:\n\n length_sort_stdlib=1\n\n## Controlling how isort sections `from` imports\n\nBy default isort places straight (`import y`) imports above from imports (`from x import y`):\n\n```python\nimport b\nfrom a import a # This will always appear below because it is a from import.\n```\n\nHowever, if you prefer to keep strict alphabetical sorting you can set [force sort within sections](https://timothycrosley.github.io/isort/docs/configuration/options/#force-sort-within-sections) to true. Resulting in:\n\n\n```python\nfrom a import a # This will now appear at top because a appears in the alphabet before b\nimport b\n```\n\nYou can even tell isort to always place from imports on top, instead of the default of placing them on bottom, using [from first](https://timothycrosley.github.io/isort/docs/configuration/options/#from-first).\n\n```python\nfrom b import b # If from first is set to True, all from imports will be placed before non-from imports.\nimport a\n```\n\n## Skip processing of imports (outside of configuration)\n\nTo make isort ignore a single import simply add a comment at the end of\nthe import line containing the text `isort:skip`:\n\n```python\nimport module # isort:skip\n```\n\nor:\n\n```python\nfrom xyz import (abc, # isort:skip\n yo,\n hey)\n```\n\nTo make isort skip an entire file simply add `isort:skip_file` to the\nmodule\'s doc string:\n\n```python\n""" my_module.py\n Best module ever\n\n isort:skip_file\n"""\n\nimport b\nimport a\n```\n\n## Adding an import to multiple files\n\nisort makes it easy to add an import statement across multiple files,\nwhile being assured it\'s correctly placed.\n\nTo add an import to all files:\n\n```bash\nisort -a "from __future__ import print_function" *.py\n```\n\nTo add an import only to files that already have imports:\n\n```bash\nisort -a "from __future__ import print_function" --append-only *.py\n```\n\n\n## Removing an import from multiple files\n\nisort also makes it easy to remove an import from multiple files,\nwithout having to be concerned with how it was originally formatted.\n\nFrom the command line:\n\n```bash\nisort --rm "os.system" *.py\n```\n\n## Using isort to verify code\n\nThe `--check-only` option\n-------------------------\n\nisort can also be used to used to verify that code is correctly\nformatted by running it with `-c`. Any files that contain incorrectly\nsorted and/or formatted imports will be outputted to `stderr`.\n\n```bash\nisort **/*.py -c -v\n\nSUCCESS: /home/timothy/Projects/Open_Source/isort/isort_kate_plugin.py Everything Looks Good!\nERROR: /home/timothy/Projects/Open_Source/isort/isort/isort.py Imports are incorrectly sorted.\n```\n\nOne great place this can be used is with a pre-commit git hook, such as\nthis one by \\@acdha:\n\n\n\nThis can help to ensure a certain level of code quality throughout a\nproject.\n\nGit hook\n--------\n\nisort provides a hook function that can be integrated into your Git\npre-commit script to check Python code before committing.\n\nTo cause the commit to fail if there are isort errors (strict mode),\ninclude the following in `.git/hooks/pre-commit`:\n\n```python\n#!/usr/bin/env python\nimport sys\nfrom isort.hooks import git_hook\n\nsys.exit(git_hook(strict=True, modify=True, lazy=True))\n```\n\nIf you just want to display warnings, but allow the commit to happen\nanyway, call `git_hook` without the strict parameter. If you want to\ndisplay warnings, but not also fix the code, call `git_hook` without the\nmodify parameter.\nThe `lazy` argument is to support users who are "lazy" to add files\nindividually to the index and tend to use `git commit -a` instead.\nSet it to `True` to ensure all tracked files are properly isorted,\nleave it out or set it to `False` to check only files added to your\nindex.\n\n## Setuptools integration\n\nUpon installation, isort enables a `setuptools` command that checks\nPython files declared by your project.\n\nRunning `python setup.py isort` on the command line will check the files\nlisted in your `py_modules` and `packages`. If any warning is found, the\ncommand will exit with an error code:\n\n```bash\n$ python setup.py isort\n```\n\nAlso, to allow users to be able to use the command without having to\ninstall isort themselves, add isort to the setup\\_requires of your\n`setup()` like so:\n\n```python\nsetup(\n name="project",\n packages=["project"],\n\n setup_requires=[\n "isort"\n ]\n)\n```\n\n## Spread the word\n\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/)\n\nPlace this badge at the top of your repository to let others know your project uses isort.\n\nFor README.md:\n\n```markdown\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/)\n```\n\nOr README.rst:\n\n```rst\n.. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336\n :target: https://timothycrosley.github.io/isort/\n```\n\n## Security contact information\n\nTo report a security vulnerability, please use the [Tidelift security\ncontact](https://tidelift.com/security). Tidelift will coordinate the\nfix and disclosure.\n\n## Why isort?\n\nisort simply stands for import sort. It was originally called\n"sortImports" however I got tired of typing the extra characters and\ncame to the realization camelCase is not pythonic.\n\nI wrote isort because in an organization I used to work in the manager\ncame in one day and decided all code must have alphabetically sorted\nimports. The code base was huge - and he meant for us to do it by hand.\nHowever, being a programmer - I\\\'m too lazy to spend 8 hours mindlessly\nperforming a function, but not too lazy to spend 16 hours automating it.\nI was given permission to open source sortImports and here we are :)\n\n------------------------------------------------------------------------\n\n[Get professionally supported isort with the Tidelift\nSubscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme)\n\nProfessional support for isort is available as part of the [Tidelift\nSubscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme).\nTidelift gives software development teams a single source for purchasing\nand maintaining their software, with professional grade assurances from\nthe experts who know it best, while seamlessly integrating with existing\ntools.\n\n------------------------------------------------------------------------\n\nThanks and I hope you find isort useful!\n\n~Timothy Crosley\n', + 'long_description': '[![isort - isort your imports, so you don\'t have to.](https://raw.githubusercontent.com/pycqa/isort/develop/art/logo_large.png)](https://pycqa.github.io/isort/)\n\n------------------------------------------------------------------------\n\n[![PyPI version](https://badge.fury.io/py/isort.svg)](https://badge.fury.io/py/isort)\n[![Test Status](https://github.com/pycqa/isort/workflows/Test/badge.svg?branch=develop)](https://github.com/pycqa/isort/actions?query=workflow%3ATest)\n[![Lint Status](https://github.com/pycqa/isort/workflows/Lint/badge.svg?branch=develop)](https://github.com/pycqa/isort/actions?query=workflow%3ALint)\n[![Code coverage Status](https://codecov.io/gh/pycqa/isort/branch/develop/graph/badge.svg)](https://codecov.io/gh/pycqa/isort)\n[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://pypi.org/project/isort/)\n[![Join the chat at https://gitter.im/timothycrosley/isort](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/timothycrosley/isort?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n[![Downloads](https://pepy.tech/badge/isort)](https://pepy.tech/project/isort)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)\n[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/pycqa/isort/?ref=repository-badge)\n_________________\n\n[Read Latest Documentation](https://pycqa.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/pycqa/isort/)\n_________________\n\nisort your imports, so you don\'t have to.\n\nisort is a Python utility / library to sort imports alphabetically, and\nautomatically separated into sections and by type. It provides a command line\nutility, Python library and [plugins for various\neditors](https://github.com/pycqa/isort/wiki/isort-Plugins) to\nquickly sort all your imports. It requires Python 3.6+ to run but\nsupports formatting Python 2 code too.\n\n[Try isort now from your browser!](https://pycqa.github.io/isort/docs/quick_start/0.-try/)\n\n![Example Usage](https://raw.github.com/pycqa/isort/develop/example.gif)\n\nBefore isort:\n\n```python\nfrom my_lib import Object\n\nimport os\n\nfrom my_lib import Object3\n\nfrom my_lib import Object2\n\nimport sys\n\nfrom third_party import lib15, lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14\n\nimport sys\n\nfrom __future__ import absolute_import\n\nfrom third_party import lib3\n\nprint("Hey")\nprint("yo")\n```\n\nAfter isort:\n\n```python\nfrom __future__ import absolute_import\n\nimport os\nimport sys\n\nfrom third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8,\n lib9, lib10, lib11, lib12, lib13, lib14, lib15)\n\nfrom my_lib import Object, Object2, Object3\n\nprint("Hey")\nprint("yo")\n```\n\n## Installing isort\n\nInstalling isort is as simple as:\n\n```bash\npip install isort\n```\n\nInstall isort with requirements.txt support:\n\n```bash\npip install isort[requirements_deprecated_finder]\n```\n\nInstall isort with Pipfile support:\n\n```bash\npip install isort[pipfile_deprecated_finder]\n```\n\nInstall isort with both formats support:\n\n```bash\npip install isort[requirements_deprecated_finder,pipfile_deprecated_finder]\n```\n\n## Using isort\n\n**From the command line**:\n\n```bash\nisort mypythonfile.py mypythonfile2.py\n```\n\nor recursively:\n\n```bash\nisort .\n```\n\n*which is equivalent to:*\n\n```bash\nisort **/*.py\n```\n\nor to see the proposed changes without applying them:\n\n```bash\nisort mypythonfile.py --diff\n```\n\nFinally, to atomically run isort against a project, only applying\nchanges if they don\'t introduce syntax errors do:\n\n```bash\nisort --atomic .\n```\n\n(Note: this is disabled by default as it keeps isort from being able to\nrun against code written using a different version of Python)\n\n**From within Python**:\n\n```python\nimport isort\n\nisort.file("pythonfile.py")\n```\n\nor:\n\n```python\nimport isort\n\nsorted_code = isort.code("import b\\nimport a\\n")\n```\n\n## Installing isort\'s for your preferred text editor\n\nSeveral plugins have been written that enable to use isort from within a\nvariety of text-editors. You can find a full list of them [on the isort\nwiki](https://github.com/pycqa/isort/wiki/isort-Plugins).\nAdditionally, I will enthusiastically accept pull requests that include\nplugins for other text editors and add documentation for them as I am\nnotified.\n\n## Multi line output modes\n\nYou will notice above the \\"multi\\_line\\_output\\" setting. This setting\ndefines how from imports wrap when they extend past the line\\_length\nlimit and has 12 possible settings:\n\n**0 - Grid**\n\n```python\nfrom third_party import (lib1, lib2, lib3,\n lib4, lib5, ...)\n```\n\n**1 - Vertical**\n\n```python\nfrom third_party import (lib1,\n lib2,\n lib3\n lib4,\n lib5,\n ...)\n```\n\n**2 - Hanging Indent**\n\n```python\nfrom third_party import \\\n lib1, lib2, lib3, \\\n lib4, lib5, lib6\n```\n\n**3 - Vertical Hanging Indent**\n\n```python\nfrom third_party import (\n lib1,\n lib2,\n lib3,\n lib4,\n)\n```\n\n**4 - Hanging Grid**\n\n```python\nfrom third_party import (\n lib1, lib2, lib3, lib4,\n lib5, ...)\n```\n\n**5 - Hanging Grid Grouped**\n\n```python\nfrom third_party import (\n lib1, lib2, lib3, lib4,\n lib5, ...\n)\n```\n\n**6 - Hanging Grid Grouped, No Trailing Comma**\n\nIn Mode 5 isort leaves a single extra space to maintain consistency of\noutput when a comma is added at the end. Mode 6 is the same - except\nthat no extra space is maintained leading to the possibility of lines\none character longer. You can enforce a trailing comma by using this in\nconjunction with `-tc` or `include_trailing_comma: True`.\n\n```python\nfrom third_party import (\n lib1, lib2, lib3, lib4,\n lib5\n)\n```\n\n**7 - NOQA**\n\n```python\nfrom third_party import lib1, lib2, lib3, ... # NOQA\n```\n\nAlternatively, you can set `force_single_line` to `True` (`-sl` on the\ncommand line) and every import will appear on its own line:\n\n```python\nfrom third_party import lib1\nfrom third_party import lib2\nfrom third_party import lib3\n...\n```\n\n**8 - Vertical Hanging Indent Bracket**\n\nSame as Mode 3 - _Vertical Hanging Indent_ but the closing parentheses\non the last line is indented.\n\n```python\nfrom third_party import (\n lib1,\n lib2,\n lib3,\n lib4,\n )\n```\n\n**9 - Vertical Prefix From Module Import**\n\nStarts a new line with the same `from MODULE import ` prefix when lines are longer than the line length limit.\n\n```python\nfrom third_party import lib1, lib2, lib3\nfrom third_party import lib4, lib5, lib6\n```\n\n**10 - Hanging Indent With Parentheses**\n\nSame as Mode 2 - _Hanging Indent_ but uses parentheses instead of backslash\nfor wrapping long lines.\n\n```python\nfrom third_party import (\n lib1, lib2, lib3,\n lib4, lib5, lib6)\n```\n\n**11 - Backslash Grid**\n\nSame as Mode 0 - _Grid_ but uses backslashes instead of parentheses to group imports.\n\n```python\nfrom third_party import lib1, lib2, lib3, \\\n lib4, lib5\n```\n\n## Indentation\n\nTo change the how constant indents appear - simply change the\nindent property with the following accepted formats:\n\n- Number of spaces you would like. For example: 4 would cause standard\n 4 space indentation.\n- Tab\n- A verbatim string with quotes around it.\n\nFor example:\n\n```python\n" "\n```\n\nis equivalent to 4.\n\nFor the import styles that use parentheses, you can control whether or\nnot to include a trailing comma after the last import with the\n`include_trailing_comma` option (defaults to `False`).\n\n## Intelligently Balanced Multi-line Imports\n\nAs of isort 3.1.0 support for balanced multi-line imports has been\nadded. With this enabled isort will dynamically change the import length\nto the one that produces the most balanced grid, while staying below the\nmaximum import length defined.\n\nExample:\n\n```python\nfrom __future__ import (absolute_import, division,\n print_function, unicode_literals)\n```\n\nWill be produced instead of:\n\n```python\nfrom __future__ import (absolute_import, division, print_function,\n unicode_literals)\n```\n\nTo enable this set `balanced_wrapping` to `True` in your config or pass\nthe `-e` option into the command line utility.\n\n## Custom Sections and Ordering\n\nYou can change the section order with `sections` option from the default\nof:\n\n```ini\nFUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER\n```\n\nto your preference:\n\n```ini\nsections=FUTURE,STDLIB,FIRSTPARTY,THIRDPARTY,LOCALFOLDER\n```\n\nYou also can define your own sections and their order.\n\nExample:\n\n```ini\nknown_django=django\nknown_pandas=pandas,numpy\nsections=FUTURE,STDLIB,DJANGO,THIRDPARTY,PANDAS,FIRSTPARTY,LOCALFOLDER\n```\n\nwould create two new sections with the specified known modules.\n\nThe `no_lines_before` option will prevent the listed sections from being\nsplit from the previous section by an empty line.\n\nExample:\n\n```ini\nsections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER\nno_lines_before=LOCALFOLDER\n```\n\nwould produce a section with both FIRSTPARTY and LOCALFOLDER modules\ncombined.\n\n**IMPORTANT NOTE**: It is very important to know when setting `known` sections that the naming\ndoes not directly map for historical reasons. For custom settings, the only difference is\ncapitalization (`known_custom=custom` VS `sections=CUSTOM,...`) for all others reference the\nfollowing mapping:\n\n - `known_standard_library` : `STANDARD_LIBRARY`\n - `extra_standard_library` : `STANDARD_LIBRARY` # Like known standard library but appends instead of replacing\n - `known_future_library` : `FUTURE`\n - `known_first_party`: `FIRSTPARTY`\n - `known_third_party`: `THIRDPARTY`\n - `known_local_folder`: `LOCALFOLDER`\n\nThis will likely be changed in isort 6.0.0+ in a backwards compatible way.\n\n## Auto-comment import sections\n\nSome projects prefer to have import sections uniquely titled to aid in\nidentifying the sections quickly when visually scanning. isort can\nautomate this as well. To do this simply set the\n`import_heading_{section_name}` setting for each section you wish to\nhave auto commented - to the desired comment.\n\nFor Example:\n\n```ini\nimport_heading_stdlib=Standard Library\nimport_heading_firstparty=My Stuff\n```\n\nWould lead to output looking like the following:\n\n```python\n# Standard Library\nimport os\nimport sys\n\nimport django.settings\n\n# My Stuff\nimport myproject.test\n```\n\n## Ordering by import length\n\nisort also makes it easy to sort your imports by length, simply by\nsetting the `length_sort` option to `True`. This will result in the\nfollowing output style:\n\n```python\nfrom evn.util import (\n Pool,\n Dict,\n Options,\n Constant,\n DecayDict,\n UnexpectedCodePath,\n)\n```\n\nIt is also possible to opt-in to sorting imports by length for only\nspecific sections by using `length_sort_` followed by the section name\nas a configuration item, e.g.:\n\n length_sort_stdlib=1\n\n## Controlling how isort sections `from` imports\n\nBy default isort places straight (`import y`) imports above from imports (`from x import y`):\n\n```python\nimport b\nfrom a import a # This will always appear below because it is a from import.\n```\n\nHowever, if you prefer to keep strict alphabetical sorting you can set [force sort within sections](https://pycqa.github.io/isort/docs/configuration/options/#force-sort-within-sections) to true. Resulting in:\n\n\n```python\nfrom a import a # This will now appear at top because a appears in the alphabet before b\nimport b\n```\n\nYou can even tell isort to always place from imports on top, instead of the default of placing them on bottom, using [from first](https://pycqa.github.io/isort/docs/configuration/options/#from-first).\n\n```python\nfrom b import b # If from first is set to True, all from imports will be placed before non-from imports.\nimport a\n```\n\n## Skip processing of imports (outside of configuration)\n\nTo make isort ignore a single import simply add a comment at the end of\nthe import line containing the text `isort:skip`:\n\n```python\nimport module # isort:skip\n```\n\nor:\n\n```python\nfrom xyz import (abc, # isort:skip\n yo,\n hey)\n```\n\nTo make isort skip an entire file simply add `isort:skip_file` to the\nmodule\'s doc string:\n\n```python\n""" my_module.py\n Best module ever\n\n isort:skip_file\n"""\n\nimport b\nimport a\n```\n\n## Adding an import to multiple files\n\nisort makes it easy to add an import statement across multiple files,\nwhile being assured it\'s correctly placed.\n\nTo add an import to all files:\n\n```bash\nisort -a "from __future__ import print_function" *.py\n```\n\nTo add an import only to files that already have imports:\n\n```bash\nisort -a "from __future__ import print_function" --append-only *.py\n```\n\n\n## Removing an import from multiple files\n\nisort also makes it easy to remove an import from multiple files,\nwithout having to be concerned with how it was originally formatted.\n\nFrom the command line:\n\n```bash\nisort --rm "os.system" *.py\n```\n\n## Using isort to verify code\n\nThe `--check-only` option\n-------------------------\n\nisort can also be used to verify that code is correctly formatted\nby running it with `-c`. Any files that contain incorrectly sorted\nand/or formatted imports will be outputted to `stderr`.\n\n```bash\nisort **/*.py -c -v\n\nSUCCESS: /home/timothy/Projects/Open_Source/isort/isort_kate_plugin.py Everything Looks Good!\nERROR: /home/timothy/Projects/Open_Source/isort/isort/isort.py Imports are incorrectly sorted.\n```\n\nOne great place this can be used is with a pre-commit git hook, such as\nthis one by \\@acdha:\n\n\n\nThis can help to ensure a certain level of code quality throughout a\nproject.\n\nGit hook\n--------\n\nisort provides a hook function that can be integrated into your Git\npre-commit script to check Python code before committing.\n\nTo cause the commit to fail if there are isort errors (strict mode),\ninclude the following in `.git/hooks/pre-commit`:\n\n```python\n#!/usr/bin/env python\nimport sys\nfrom isort.hooks import git_hook\n\nsys.exit(git_hook(strict=True, modify=True, lazy=True, settings_file=""))\n```\n\nIf you just want to display warnings, but allow the commit to happen\nanyway, call `git_hook` without the strict parameter. If you want to\ndisplay warnings, but not also fix the code, call `git_hook` without the\nmodify parameter.\nThe `lazy` argument is to support users who are "lazy" to add files\nindividually to the index and tend to use `git commit -a` instead.\nSet it to `True` to ensure all tracked files are properly isorted,\nleave it out or set it to `False` to check only files added to your\nindex.\n\nIf you want to use a specific configuration file for the hook, you can pass its\npath to settings_file. If no path is specifically requested, `git_hook` will\nsearch for the configuration file starting at the directory containing the first\nstaged file, as per `git diff-index` ordering, and going upward in the directory\nstructure until a valid configuration file is found or\n[`MAX_CONFIG_SEARCH_DEPTH`](src/config.py:35) directories are checked.\nThe settings_file parameter is used to support users who keep their configuration\nfile in a directory that might not be a parent of all the other files.\n\n## Setuptools integration\n\nUpon installation, isort enables a `setuptools` command that checks\nPython files declared by your project.\n\nRunning `python setup.py isort` on the command line will check the files\nlisted in your `py_modules` and `packages`. If any warning is found, the\ncommand will exit with an error code:\n\n```bash\n$ python setup.py isort\n```\n\nAlso, to allow users to be able to use the command without having to\ninstall isort themselves, add isort to the setup\\_requires of your\n`setup()` like so:\n\n```python\nsetup(\n name="project",\n packages=["project"],\n\n setup_requires=[\n "isort"\n ]\n)\n```\n\n## Spread the word\n\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)\n\nPlace this badge at the top of your repository to let others know your project uses isort.\n\nFor README.md:\n\n```markdown\n[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)\n```\n\nOr README.rst:\n\n```rst\n.. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336\n :target: https://pycqa.github.io/isort/\n```\n\n## Security contact information\n\nTo report a security vulnerability, please use the [Tidelift security\ncontact](https://tidelift.com/security). Tidelift will coordinate the\nfix and disclosure.\n\n## Why isort?\n\nisort simply stands for import sort. It was originally called\n"sortImports" however I got tired of typing the extra characters and\ncame to the realization camelCase is not pythonic.\n\nI wrote isort because in an organization I used to work in the manager\ncame in one day and decided all code must have alphabetically sorted\nimports. The code base was huge - and he meant for us to do it by hand.\nHowever, being a programmer - I\\\'m too lazy to spend 8 hours mindlessly\nperforming a function, but not too lazy to spend 16 hours automating it.\nI was given permission to open source sortImports and here we are :)\n\n------------------------------------------------------------------------\n\n[Get professionally supported isort with the Tidelift\nSubscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme)\n\nProfessional support for isort is available as part of the [Tidelift\nSubscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme).\nTidelift gives software development teams a single source for purchasing\nand maintaining their software, with professional grade assurances from\nthe experts who know it best, while seamlessly integrating with existing\ntools.\n\n------------------------------------------------------------------------\n\nThanks and I hope you find isort useful!\n\n~Timothy Crosley\n', 'author': 'Timothy Crosley', 'author_email': 'timothy.crosley@gmail.com', 'maintainer': None, 'maintainer_email': None, - 'url': 'https://timothycrosley.github.io/isort/', + 'url': 'https://pycqa.github.io/isort/', 'packages': packages, 'package_data': package_data, 'extras_require': extras_require, diff -Nru isort-5.4.2/tests/conftest.py isort-5.6.4/tests/conftest.py --- isort-5.4.2/tests/conftest.py 2020-08-04 04:14:13.903266200 +0000 +++ isort-5.6.4/tests/conftest.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -"""isort test wide fixtures and configuration""" -import os -from pathlib import Path - -import pytest - -TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -SRC_DIR = os.path.abspath(os.path.join(TEST_DIR, "../isort/")) - - -@pytest.fixture -def test_dir(): - return TEST_DIR - - -@pytest.fixture -def src_dir(): - return SRC_DIR - - -@pytest.fixture -def test_path(): - return Path(TEST_DIR).resolve() - - -@pytest.fixture -def src_path(): - return Path(SRC_DIR).resolve() diff -Nru isort-5.4.2/tests/example_crlf_file.py isort-5.6.4/tests/example_crlf_file.py --- isort-5.4.2/tests/example_crlf_file.py 2020-08-04 04:20:37.688786000 +0000 +++ isort-5.6.4/tests/example_crlf_file.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -import b -import a - - -def func(): - x = 1 - y = 2 - z = 3 - c = 4 - return x + y + z + c diff -Nru isort-5.4.2/tests/test_api.py isort-5.6.4/tests/test_api.py --- isort-5.4.2/tests/test_api.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/tests/test_api.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -"""Tests the isort API module""" -from io import StringIO -from unittest.mock import MagicMock, patch - -import pytest - -from isort import api -from isort.settings import Config - - -def test_sort_file(tmpdir) -> None: - tmp_file = tmpdir.join("test_bad_syntax.py") - tmp_file.write_text("""print('mismathing quotes")""", "utf8") - with pytest.warns(UserWarning): - api.sort_file(tmp_file, atomic=True) - with pytest.warns(UserWarning): - api.sort_file(tmp_file, atomic=True, write_to_stdout=True) - - imperfect = tmpdir.join("test_needs_changes.py") - imperfect.write_text("import b\nimport a\n", "utf8") - api.sort_file(imperfect, write_to_stdout=True, show_diff=True) - - # First show diff, but ensure change wont get written by asking to apply - # and ensuring answer is no. - with patch("isort.format.input", MagicMock(return_value="n")): - api.sort_file(imperfect, show_diff=True, ask_to_apply=True) - - # Then run again, but apply the change without asking - api.sort_file(imperfect, show_diff=True) - - -def test_check_file(tmpdir) -> None: - perfect = tmpdir.join("test_no_changes.py") - perfect.write_text("import a\nimport b\n", "utf8") - assert api.check_file(perfect, show_diff=True) - - imperfect = tmpdir.join("test_needs_changes.py") - imperfect.write_text("import b\nimport a\n", "utf8") - assert not api.check_file(imperfect, show_diff=True) - - -def test_sorted_imports_multiple_configs() -> None: - with pytest.raises(ValueError): - api.sort_code_string("import os", config=Config(line_length=80), line_length=80) - - -def test_diff_stream() -> None: - output = StringIO() - assert api.sort_stream(StringIO("import b\nimport a\n"), output, show_diff=True) - output.seek(0) - assert "import a\n import b\n" in output.read() - - -def test_sort_code_string_mixed_newlines(): - assert api.sort_code_string("import A\n\r\nimportA\n\n") == "import A\r\n\r\nimportA\r\n\n" diff -Nru isort-5.4.2/tests/test_comments.py isort-5.6.4/tests/test_comments.py --- isort-5.4.2/tests/test_comments.py 2020-07-29 04:24:06.097084800 +0000 +++ isort-5.6.4/tests/test_comments.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -from hypothesis_auto import auto_pytest_magic - -from isort import comments - -auto_pytest_magic(comments.parse) -auto_pytest_magic(comments.add_to_line) - - -def test_add_to_line(): - assert comments.add_to_line([], "import os # comment", removed=True).strip() == "import os" diff -Nru isort-5.4.2/tests/test_deprecated_finders.py isort-5.6.4/tests/test_deprecated_finders.py --- isort-5.4.2/tests/test_deprecated_finders.py 2020-08-04 04:14:13.911266800 +0000 +++ isort-5.6.4/tests/test_deprecated_finders.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,210 +0,0 @@ -import importlib.machinery -import os -import posixpath -from pathlib import Path -from unittest.mock import patch - -from isort import sections, settings -from isort.deprecated import finders -from isort.deprecated.finders import FindersManager -from isort.settings import Config - -PIPFILE = """ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[requires] -python_version = "3.5" - -[packages] -Django = "~=1.11" -deal = {editable = true, git = "https://github.com/orsinium/deal.git"} - -[dev-packages] -""" - - -class TestFindersManager: - def test_init(self): - assert FindersManager(settings.DEFAULT_CONFIG) - - class ExceptionOnInit(finders.BaseFinder): - def __init__(*args, **kwargs): - super().__init__(*args, **kwargs) - raise ValueError("test") - - with patch( - "isort.deprecated.finders.FindersManager._default_finders_classes", - FindersManager._default_finders_classes + (ExceptionOnInit,), - ): - assert FindersManager(settings.Config(verbose=True)) - - def test_no_finders(self): - assert FindersManager(settings.DEFAULT_CONFIG, []).find("isort") is None - - def test_find_broken_finder(self): - class ExceptionOnFind(finders.BaseFinder): - def find(*args, **kwargs): - raise ValueError("test") - - assert ( - FindersManager(settings.Config(verbose=True), [ExceptionOnFind]).find("isort") is None - ) - - -class AbstractTestFinder: - kind = finders.BaseFinder - - @classmethod - def setup_class(cls): - cls.instance = cls.kind(settings.DEFAULT_CONFIG) - - def test_create(self): - assert self.kind(settings.DEFAULT_CONFIG) - - def test_find(self): - self.instance.find("isort") - self.instance.find("") - - -class TestForcedSeparateFinder(AbstractTestFinder): - kind = finders.ForcedSeparateFinder - - -class TestDefaultFinder(AbstractTestFinder): - kind = finders.DefaultFinder - - -class TestKnownPatternFinder(AbstractTestFinder): - kind = finders.KnownPatternFinder - - -class TestLocalFinder(AbstractTestFinder): - kind = finders.LocalFinder - - -class TestPathFinder(AbstractTestFinder): - kind = finders.PathFinder - - def test_conda_and_virtual_env(self, tmpdir): - python3lib = tmpdir.mkdir("lib").mkdir("python3") - python3lib.mkdir("site-packages").mkdir("y") - python3lib.mkdir("n").mkdir("site-packages").mkdir("x") - tmpdir.mkdir("z").join("__init__.py").write("__version__ = '1.0.0'") - tmpdir.chdir() - - conda = self.kind(settings.Config(conda_env=str(tmpdir)), str(tmpdir)) - venv = self.kind(settings.Config(virtual_env=str(tmpdir)), str(tmpdir)) - assert conda.find("y") == venv.find("y") == "THIRDPARTY" - assert conda.find("x") == venv.find("x") == "THIRDPARTY" - assert conda.find("z") == "THIRDPARTY" - assert conda.find("os") == venv.find("os") == "STDLIB" - - def test_default_section(self, tmpdir): - tmpdir.join("file.py").write("import b\nimport a\n") - assert self.kind(settings.Config(default_section="CUSTOM"), tmpdir).find("file") == "CUSTOM" - - def test_src_paths(self, tmpdir): - tmpdir.join("file.py").write("import b\nimport a\n") - assert ( - self.kind(settings.Config(src_paths=[Path(str(tmpdir))]), tmpdir).find("file") - == settings.DEFAULT_CONFIG.default_section - ) - - -class TestPipfileFinder(AbstractTestFinder): - kind = finders.PipfileFinder - - -class TestRequirementsFinder(AbstractTestFinder): - kind = finders.RequirementsFinder - - def test_no_pipreqs(self): - with patch("isort.deprecated.finders.pipreqs", None): - assert not self.kind(settings.DEFAULT_CONFIG).find("isort") - - def test_not_enabled(self): - test_finder = self.kind(settings.DEFAULT_CONFIG) - test_finder.enabled = False - assert not test_finder.find("isort") - - def test_requirements_dir(self, tmpdir): - tmpdir.mkdir("requirements").join("development.txt").write("x==1.00") - test_finder = self.kind(settings.DEFAULT_CONFIG, str(tmpdir)) - assert test_finder.find("x") - - -def test_requirements_finder(tmpdir) -> None: - subdir = tmpdir.mkdir("subdir").join("lol.txt") - subdir.write("flask") - req_file = tmpdir.join("requirements.txt") - req_file.write("Django==1.11\n-e git+https://github.com/orsinium/deal.git#egg=deal\n") - for path in (str(tmpdir), str(subdir)): - - finder = finders.RequirementsFinder(config=Config(), path=path) - - files = list(finder._get_files()) - assert len(files) == 1 # file finding - assert files[0].endswith("requirements.txt") # file finding - assert set(finder._get_names(str(req_file))) == {"Django", "deal"} # file parsing - - assert finder.find("django") == sections.THIRDPARTY # package in reqs - assert finder.find("flask") is None # package not in reqs - assert finder.find("deal") == sections.THIRDPARTY # vcs - - assert len(finder.mapping) > 100 - assert finder._normalize_name("deal") == "deal" - assert finder._normalize_name("Django") == "django" # lowercase - assert finder._normalize_name("django_haystack") == "haystack" # mapping - assert finder._normalize_name("Flask-RESTful") == "flask_restful" # conver `-`to `_` - - req_file.remove() - - -def test_pipfile_finder(tmpdir) -> None: - pipfile = tmpdir.join("Pipfile") - pipfile.write(PIPFILE) - finder = finders.PipfileFinder(config=Config(), path=str(tmpdir)) - - assert set(finder._get_names(str(tmpdir))) == {"Django", "deal"} # file parsing - - assert finder.find("django") == sections.THIRDPARTY # package in reqs - assert finder.find("flask") is None # package not in reqs - assert finder.find("deal") == sections.THIRDPARTY # vcs - - assert len(finder.mapping) > 100 - assert finder._normalize_name("deal") == "deal" - assert finder._normalize_name("Django") == "django" # lowercase - assert finder._normalize_name("django_haystack") == "haystack" # mapping - assert finder._normalize_name("Flask-RESTful") == "flask_restful" # conver `-`to `_` - - pipfile.remove() - - -def test_path_finder(monkeypatch) -> None: - config = config = Config() - finder = finders.PathFinder(config=config) - third_party_prefix = next(path for path in finder.paths if "site-packages" in path) - ext_suffixes = importlib.machinery.EXTENSION_SUFFIXES - imaginary_paths = { - posixpath.join(finder.stdlib_lib_prefix, "example_1.py"), - posixpath.join(third_party_prefix, "example_2.py"), - posixpath.join(os.getcwd(), "example_3.py"), - } - imaginary_paths.update( - { - posixpath.join(third_party_prefix, "example_" + str(i) + ext_suffix) - for i, ext_suffix in enumerate(ext_suffixes, 4) - } - ) - - monkeypatch.setattr( - "isort.deprecated.finders.exists_case_sensitive", lambda p: p in imaginary_paths - ) - assert finder.find("example_1") == sections.STDLIB - assert finder.find("example_2") == sections.THIRDPARTY - assert finder.find("example_3") == settings.DEFAULT_CONFIG.default_section - for i, _ in enumerate(ext_suffixes, 4): - assert finder.find("example_" + str(i)) == sections.THIRDPARTY diff -Nru isort-5.4.2/tests/test_exceptions.py isort-5.6.4/tests/test_exceptions.py --- isort-5.4.2/tests/test_exceptions.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/tests/test_exceptions.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -from isort import exceptions - - -class TestISortError: - def setup_class(self): - self.instance = exceptions.ISortError() - - def test_init(self): - assert isinstance(self.instance, exceptions.ISortError) - - -class TestExistingSyntaxErrors(TestISortError): - def setup_class(self): - self.instance = exceptions.ExistingSyntaxErrors("file_path") - - def test_variables(self): - assert self.instance.file_path == "file_path" - - -class TestIntroducedSyntaxErrors(TestISortError): - def setup_class(self): - self.instance = exceptions.IntroducedSyntaxErrors("file_path") - - def test_variables(self): - assert self.instance.file_path == "file_path" - - -class TestFileSkipped(TestISortError): - def setup_class(self): - self.instance = exceptions.FileSkipped("message", "file_path") - - def test_variables(self): - assert self.instance.file_path == "file_path" - assert str(self.instance) == "message" - - -class TestFileSkipComment(TestISortError): - def setup_class(self): - self.instance = exceptions.FileSkipComment("file_path") - - def test_variables(self): - assert self.instance.file_path == "file_path" - - -class TestFileSkipSetting(TestISortError): - def setup_class(self): - self.instance = exceptions.FileSkipSetting("file_path") - - def test_variables(self): - assert self.instance.file_path == "file_path" - - -class TestProfileDoesNotExist(TestISortError): - def setup_class(self): - self.instance = exceptions.ProfileDoesNotExist("profile") - - def test_variables(self): - assert self.instance.profile == "profile" - - -class TestLiteralParsingFailure(TestISortError): - def setup_class(self): - self.instance = exceptions.LiteralParsingFailure("x = [", SyntaxError) - - def test_variables(self): - assert self.instance.code == "x = [" - assert self.instance.original_error == SyntaxError - - -class TestLiteralSortTypeMismatch(TestISortError): - def setup_class(self): - self.instance = exceptions.LiteralSortTypeMismatch(tuple, list) - - def test_variables(self): - assert self.instance.kind == tuple - assert self.instance.expected_kind == list - - -class TestAssignmentsFormatMismatch(TestISortError): - def setup_class(self): - self.instance = exceptions.AssignmentsFormatMismatch("print x") - - def test_variables(self): - assert self.instance.code == "print x" diff -Nru isort-5.4.2/tests/test_format.py isort-5.6.4/tests/test_format.py --- isort-5.4.2/tests/test_format.py 2020-07-29 05:49:17.450505500 +0000 +++ isort-5.6.4/tests/test_format.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -from unittest.mock import MagicMock, patch - -import colorama -import pytest -from hypothesis_auto import auto_pytest_magic - -import isort.format - -auto_pytest_magic(isort.format.show_unified_diff, auto_allow_exceptions_=(UnicodeEncodeError,)) - - -def test_ask_whether_to_apply_changes_to_file(): - with patch("isort.format.input", MagicMock(return_value="y")): - assert isort.format.ask_whether_to_apply_changes_to_file("") - with patch("isort.format.input", MagicMock(return_value="n")): - assert not isort.format.ask_whether_to_apply_changes_to_file("") - with patch("isort.format.input", MagicMock(return_value="q")): - with pytest.raises(SystemExit): - assert isort.format.ask_whether_to_apply_changes_to_file("") - - -def test_basic_printer(capsys): - printer = isort.format.create_terminal_printer(color=False) - printer.success("All good!") - out, _ = capsys.readouterr() - assert out == "SUCCESS: All good!\n" - printer.error("Some error") - out, _ = capsys.readouterr() - assert out == "ERROR: Some error\n" - - -def test_colored_printer_success(capsys): - printer = isort.format.create_terminal_printer(color=True) - printer.success("All good!") - out, _ = capsys.readouterr() - assert "SUCCESS" in out - assert "All good!" in out - assert colorama.Fore.GREEN in out - - -def test_colored_printer_error(capsys): - printer = isort.format.create_terminal_printer(color=True) - printer.error("Some error") - out, _ = capsys.readouterr() - assert "ERROR" in out - assert "Some error" in out - assert colorama.Fore.RED in out - - -@patch("isort.format.colorama_unavailable", True) -def test_colorama_not_available_handled_gracefully(capsys): - with pytest.raises(SystemExit) as system_exit: - _ = isort.format.create_terminal_printer(color=True) - assert system_exit.value.code > 0 - _, err = capsys.readouterr() - assert "colorama" in err - assert "colors extra" in err diff -Nru isort-5.4.2/tests/test_hooks.py isort-5.6.4/tests/test_hooks.py --- isort-5.4.2/tests/test_hooks.py 2020-08-04 04:14:13.903266200 +0000 +++ isort-5.6.4/tests/test_hooks.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -import os -from unittest.mock import MagicMock, patch - -from isort import exceptions, hooks - - -def test_git_hook(src_dir): - """Simple smoke level testing of git hooks""" - - # Ensure correct subprocess command is called - with patch("subprocess.run", MagicMock()) as run_mock: - hooks.git_hook() - assert run_mock.called_once() - assert run_mock.call_args[0][0] == [ - "git", - "diff-index", - "--cached", - "--name-only", - "--diff-filter=ACMRTUXB", - "HEAD", - ] - - hooks.git_hook(lazy=True) - assert run_mock.called_once() - assert run_mock.call_args[0][0] == [ - "git", - "diff-index", - "--name-only", - "--diff-filter=ACMRTUXB", - "HEAD", - ] - - # Test with incorrectly sorted file returned from git - with patch( - "isort.hooks.get_lines", MagicMock(return_value=[os.path.join(src_dir, "main.py")]) - ) as run_mock: - - class FakeProcessResponse(object): - stdout = b"import b\nimport a" - - with patch("subprocess.run", MagicMock(return_value=FakeProcessResponse())) as run_mock: - with patch("isort.api", MagicMock(return_value=False)): - hooks.git_hook(modify=True) - - # Test with skipped file returned from git - with patch( - "isort.hooks.get_lines", MagicMock(return_value=[os.path.join(src_dir, "main.py")]) - ) as run_mock: - - class FakeProcessResponse(object): - stdout = b"# isort: skip-file\nimport b\nimport a\n" - - with patch("subprocess.run", MagicMock(return_value=FakeProcessResponse())) as run_mock: - with patch("isort.api", MagicMock(side_effect=exceptions.FileSkipped("", ""))): - hooks.git_hook(modify=True) diff -Nru isort-5.4.2/tests/test_hypothesmith.py isort-5.6.4/tests/test_hypothesmith.py --- isort-5.4.2/tests/test_hypothesmith.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/tests/test_hypothesmith.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -import ast -from typing import get_type_hints - -import hypothesis -import libcst -from hypothesis import strategies as st -from hypothesmith import from_grammar, from_node - -import isort - - -def _as_config(kw) -> isort.Config: - if "wrap_length" in kw and "line_length" in kw: - kw["wrap_length"], kw["line_length"] = sorted([kw["wrap_length"], kw["line_length"]]) - try: - return isort.Config(**kw) - except ValueError: - kw["wrap_length"] = 0 - return isort.Config(**kw) - - -def _record_targets(code: str, prefix: str = "") -> str: - # target larger inputs - the Hypothesis engine will do a multi-objective - # hill-climbing search using these scores to generate 'better' examples. - nodes = list(ast.walk(ast.parse(code))) - import_nodes = [n for n in nodes if isinstance(n, (ast.Import, ast.ImportFrom))] - uniq_nodes = {type(n) for n in nodes} - for value, label in [ - (len(import_nodes), "total number of import nodes"), - (len(uniq_nodes), "number of unique ast node types"), - ]: - hypothesis.target(float(value), label=prefix + label) - return code - - -def configs(**force_strategies: st.SearchStrategy) -> st.SearchStrategy[isort.Config]: - """Generate arbitrary Config objects.""" - skip = { - "line_ending", - "sections", - "known_future_library", - "forced_separate", - "lines_after_imports", - "lines_between_sections", - "lines_between_types", - "sources", - "virtual_env", - "conda_env", - "directory", - "formatter", - "formatting_function", - } - inferred_kwargs = { - k: st.from_type(v) - for k, v in get_type_hints(isort.settings._Config).items() - if k not in skip - } - specific = { - "line_length": st.integers(0, 200), - "wrap_length": st.integers(0, 200), - "indent": st.integers(0, 20).map(lambda n: n * " "), - "default_section": st.sampled_from(sorted(isort.settings.KNOWN_SECTION_MAPPING)), - "force_grid_wrap": st.integers(0, 20), - "profile": st.sampled_from(sorted(isort.settings.profiles)), - "py_version": st.sampled_from(("auto",) + isort.settings.VALID_PY_TARGETS), - } - kwargs = {**inferred_kwargs, **specific, **force_strategies} - return st.fixed_dictionaries({}, optional=kwargs).map(_as_config) - - -st.register_type_strategy(isort.Config, configs()) - - -@hypothesis.example("import A\nimportA\r\n\n", isort.Config(), False) -@hypothesis.given( - source_code=st.lists( - from_grammar(auto_target=False) - | from_node(auto_target=False) - | from_node(libcst.Import, auto_target=False) - | from_node(libcst.ImportFrom, auto_target=False), - min_size=1, - max_size=10, - ).map("\n".join), - config=st.builds(isort.Config), - disregard_skip=st.booleans(), -) -@hypothesis.seed(235738473415671197623909623354096762459) -@hypothesis.settings( - suppress_health_check=[hypothesis.HealthCheck.too_slow, hypothesis.HealthCheck.filter_too_much] -) -def test_isort_is_idempotent(source_code: str, config: isort.Config, disregard_skip: bool) -> None: - # NOTE: if this test finds a bug, please notify @Zac-HD so that it can be added to the - # Hypothesmith trophy case. This really helps with research impact evaluations! - _record_targets(source_code) - result = isort.code(source_code, config=config, disregard_skip=disregard_skip) - assert result == isort.code(result, config=config, disregard_skip=disregard_skip) diff -Nru isort-5.4.2/tests/test_importable.py isort-5.6.4/tests/test_importable.py --- isort-5.4.2/tests/test_importable.py 2020-07-29 04:24:06.097084800 +0000 +++ isort-5.6.4/tests/test_importable.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -"""Basic set of tests to ensure entire code base is importable""" -import pytest - - -def test_importable(): - """Simple smoketest to ensure all isort modules are importable""" - import isort - import isort._future - import isort._future._dataclasses - import isort._version - import isort.api - import isort.comments - import isort.deprecated.finders - import isort.exceptions - import isort.format - import isort.hooks - import isort.logo - import isort.main - import isort.output - import isort.parse - import isort.place - import isort.profiles - import isort.pylama_isort - import isort.sections - import isort.settings - import isort.setuptools_commands - import isort.sorting - import isort.stdlibs - import isort.stdlibs.all - import isort.stdlibs.py2 - import isort.stdlibs.py3 - import isort.stdlibs.py27 - import isort.stdlibs.py35 - import isort.stdlibs.py36 - import isort.stdlibs.py37 - import isort.utils - import isort.wrap - import isort.wrap_modes - - with pytest.raises(SystemExit): - import isort.__main__ # noqa: F401 diff -Nru isort-5.4.2/tests/test_io.py isort-5.6.4/tests/test_io.py --- isort-5.4.2/tests/test_io.py 2020-07-29 04:24:06.097084800 +0000 +++ isort-5.6.4/tests/test_io.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -import sys -from unittest.mock import patch - -import pytest - -from isort import io - - -class TestFile: - @pytest.mark.skipif(sys.platform == "win32", reason="Can't run file encoding test in AppVeyor") - def test_read(self, tmpdir): - test_file_content = """# -*- encoding: ascii -*- - -import Ὡ -""" - test_file = tmpdir.join("file.py") - test_file.write(test_file_content) - with pytest.raises(Exception): - with io.File.read(str(test_file)) as file_handler: - file_handler.stream.read() - - def test_from_content(self, tmpdir): - test_file = tmpdir.join("file.py") - test_file.write_text("import os", "utf8") - file_obj = io.File.from_contents("import os", filename=str(test_file)) - assert file_obj - assert file_obj.extension == "py" - - def test_open(self, tmpdir): - with pytest.raises(Exception): - io.File._open("THISCANTBEAREALFILEὩὩὩὩὩὩὩὩὩὩὩὩ.ὩὩὩὩὩ") - - def raise_arbitrary_exception(*args, **kwargs): - raise RuntimeError("test") - - test_file = tmpdir.join("file.py") - test_file.write("import os") - assert io.File._open(str(test_file)) - - # correctly responds to error determining encoding - with patch("tokenize.detect_encoding", raise_arbitrary_exception): - with pytest.raises(Exception): - io.File._open(str(test_file)) diff -Nru isort-5.4.2/tests/test_isort.py isort-5.6.4/tests/test_isort.py --- isort-5.4.2/tests/test_isort.py 2020-08-15 03:12:49.688459900 +0000 +++ isort-5.6.4/tests/test_isort.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,4755 +0,0 @@ -"""Tests all major functionality of the isort library - -Should be ran using py.test by simply running py.test in the isort project directory -""" -import os -import os.path -from pathlib import Path -import subprocess -import sys -from tempfile import NamedTemporaryFile -from typing import Any, Dict, Iterator, List, Set, Tuple - -import py -import pytest -import isort -from isort import main, api, sections -from isort.settings import WrapModes, Config -from isort.utils import exists_case_sensitive -from isort.exceptions import FileSkipped, ExistingSyntaxErrors - -try: - import toml -except ImportError: - toml = None - -TEST_DEFAULT_CONFIG = """ -[*.{py,pyi}] -max_line_length = 120 -indent_style = space -indent_size = 4 -known_first_party = isort -known_third_party = kate -known_something_else = something_entirely_different -sections = FUTURE, STDLIB, THIRDPARTY, FIRSTPARTY, LOCALFOLDER, SOMETHING_ELSE -ignore_frosted_errors = E103 -skip = build,.tox,venv -balanced_wrapping = true -""" -SHORT_IMPORT = "from third_party import lib1, lib2, lib3, lib4" -SINGLE_FROM_IMPORT = "from third_party import lib1" -SINGLE_LINE_LONG_IMPORT = "from third_party import lib1, lib2, lib3, lib4, lib5, lib5ab" -REALLY_LONG_IMPORT = ( - "from third_party import lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11," - "lib12, lib13, lib14, lib15, lib16, lib17, lib18, lib20, lib21, lib22" -) -REALLY_LONG_IMPORT_WITH_COMMENT = ( - "from third_party import lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, " - "lib10, lib11, lib12, lib13, lib14, lib15, lib16, lib17, lib18, lib20, lib21, lib22" - " # comment" -) - - -@pytest.fixture(scope="session", autouse=True) -def default_settings_path(tmpdir_factory) -> Iterator[str]: - config_dir = tmpdir_factory.mktemp("config") - config_file = config_dir.join(".editorconfig").strpath - - with open(config_file, "w") as editorconfig: - editorconfig.write(TEST_DEFAULT_CONFIG) - - assert Config(config_file).known_other - - with config_dir.as_cwd(): - yield config_dir.strpath - - -def test_happy_path() -> None: - """Test the most basic use case, straight imports no code, simply not organized by category.""" - test_input = "import sys\nimport os\nimport myproject.test\nimport django.settings" - test_output = isort.code(test_input, known_first_party=["myproject"]) - assert test_output == ( - "import os\n" "import sys\n" "\n" "import django.settings\n" "\n" "import myproject.test\n" - ) - - -def test_code_intermixed() -> None: - """Defines what should happen when isort encounters imports intermixed with - code. - - (it should pull them all to the top) - - """ - test_input = ( - "import sys\n" - "print('yo')\n" - "print('I like to put code between imports cause I want stuff to break')\n" - "import myproject.test\n" - ) - test_output = isort.code(test_input) - assert test_output == ( - "import sys\n" - "\n" - "print('yo')\n" - "print('I like to put code between imports cause I want stuff to break')\n" - "import myproject.test\n" - ) - - -def test_correct_space_between_imports() -> None: - """Ensure after imports a correct amount of space (in newlines) is - enforced. - - (2 for method, class, or decorator definitions 1 for anything else) - - """ - test_input_method = "import sys\ndef my_method():\n print('hello world')\n" - test_output_method = isort.code(test_input_method) - assert test_output_method == ("import sys\n\n\ndef my_method():\n print('hello world')\n") - - test_input_decorator = ( - "import sys\n" "@my_decorator\n" "def my_method():\n" " print('hello world')\n" - ) - test_output_decorator = isort.code(test_input_decorator) - assert test_output_decorator == ( - "import sys\n" "\n" "\n" "@my_decorator\n" "def my_method():\n" " print('hello world')\n" - ) - - test_input_class = "import sys\nclass MyClass(object):\n pass\n" - test_output_class = isort.code(test_input_class) - assert test_output_class == "import sys\n\n\nclass MyClass(object):\n pass\n" - - test_input_other = "import sys\nprint('yo')\n" - test_output_other = isort.code(test_input_other) - assert test_output_other == "import sys\n\nprint('yo')\n" - - test_input_inquotes = ( - "import sys\n" - "@my_decorator('''hello\nworld''')\n" - "def my_method():\n" - " print('hello world')\n" - ) - test_output_inquotes = api.sort_code_string(test_input_inquotes) - assert ( - test_output_inquotes == "import sys\n" - "\n\n" - "@my_decorator('''hello\nworld''')\n" - "def my_method():\n" - " print('hello world')\n" - ) - test_input_assign = "import sys\nVAR = 1\n" - test_output_assign = api.sort_code_string(test_input_assign) - assert test_output_assign == "import sys\n\nVAR = 1\n" - - test_input_assign = "import sys\nVAR = 1\ndef y():\n" - test_output_assign = api.sort_code_string(test_input_assign) - assert test_output_assign == "import sys\n\nVAR = 1\ndef y():\n" - - test_input = """ -import os - -x = "hi" -def x(): - pass -""" - assert isort.code(test_input) == test_input - - -def test_sort_on_number() -> None: - """Ensure numbers get sorted logically (10 > 9 not the other way around)""" - test_input = "import lib10\nimport lib9\n" - test_output = isort.code(test_input) - assert test_output == "import lib9\nimport lib10\n" - - -def test_line_length() -> None: - """Ensure isort enforces the set line_length.""" - assert len(isort.code(REALLY_LONG_IMPORT, line_length=80).split("\n")[0]) <= 80 - assert len(isort.code(REALLY_LONG_IMPORT, line_length=120).split("\n")[0]) <= 120 - - test_output = isort.code(REALLY_LONG_IMPORT, line_length=42) - assert test_output == ( - "from third_party import (lib1, lib2, lib3,\n" - " lib4, lib5, lib6,\n" - " lib7, lib8, lib9,\n" - " lib10, lib11,\n" - " lib12, lib13,\n" - " lib14, lib15,\n" - " lib16, lib17,\n" - " lib18, lib20,\n" - " lib21, lib22)\n" - ) - - test_input = ( - "from django.contrib.gis.gdal.field import (\n" - " OFTDate, OFTDateTime, OFTInteger, OFTInteger64, OFTReal, OFTString,\n" - " OFTTime,\n" - ")\n" - ) # Test case described in issue #654 - assert ( - isort.code( - code=test_input, - include_trailing_comma=True, - line_length=79, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - balanced_wrapping=False, - ) - == test_input - ) - - test_output = isort.code(code=REALLY_LONG_IMPORT, line_length=42, wrap_length=32) - assert test_output == ( - "from third_party import (lib1,\n" - " lib2,\n" - " lib3,\n" - " lib4,\n" - " lib5,\n" - " lib6,\n" - " lib7,\n" - " lib8,\n" - " lib9,\n" - " lib10,\n" - " lib11,\n" - " lib12,\n" - " lib13,\n" - " lib14,\n" - " lib15,\n" - " lib16,\n" - " lib17,\n" - " lib18,\n" - " lib20,\n" - " lib21,\n" - " lib22)\n" - ) - - test_input = ( - "from .test import a_very_long_function_name_that_exceeds_the_normal_pep8_line_length\n" - ) - with pytest.raises(ValueError): - test_output = isort.code(code=REALLY_LONG_IMPORT, line_length=80, wrap_length=99) - test_output = isort.code(REALLY_LONG_IMPORT, line_length=100, wrap_length=99) == test_input - - # Test Case described in issue #1015 - test_output = isort.code( - REALLY_LONG_IMPORT, line_length=25, multi_line_output=WrapModes.HANGING_INDENT - ) - assert test_output == ( - "from third_party import \\\n" - " lib1, lib2, lib3, \\\n" - " lib4, lib5, lib6, \\\n" - " lib7, lib8, lib9, \\\n" - " lib10, lib11, \\\n" - " lib12, lib13, \\\n" - " lib14, lib15, \\\n" - " lib16, lib17, \\\n" - " lib18, lib20, \\\n" - " lib21, lib22\n" - ) - - -def test_output_modes() -> None: - """Test setting isort to use various output modes works as expected""" - test_output_grid = isort.code( - code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.GRID, line_length=40 - ) - assert test_output_grid == ( - "from third_party import (lib1, lib2,\n" - " lib3, lib4,\n" - " lib5, lib6,\n" - " lib7, lib8,\n" - " lib9, lib10,\n" - " lib11, lib12,\n" - " lib13, lib14,\n" - " lib15, lib16,\n" - " lib17, lib18,\n" - " lib20, lib21,\n" - " lib22)\n" - ) - - test_output_vertical = isort.code( - code=REALLY_LONG_IMPORT, multi_line_output=WrapModes.VERTICAL, line_length=40 - ) - assert test_output_vertical == ( - "from third_party import (lib1,\n" - " lib2,\n" - " lib3,\n" - " lib4,\n" - " lib5,\n" - " lib6,\n" - " lib7,\n" - " lib8,\n" - " lib9,\n" - " lib10,\n" - " lib11,\n" - " lib12,\n" - " lib13,\n" - " lib14,\n" - " lib15,\n" - " lib16,\n" - " lib17,\n" - " lib18,\n" - " lib20,\n" - " lib21,\n" - " lib22)\n" - ) - - comment_output_vertical = isort.code( - code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.VERTICAL, line_length=40 - ) - assert comment_output_vertical == ( - "from third_party import (lib1, # comment\n" - " lib2,\n" - " lib3,\n" - " lib4,\n" - " lib5,\n" - " lib6,\n" - " lib7,\n" - " lib8,\n" - " lib9,\n" - " lib10,\n" - " lib11,\n" - " lib12,\n" - " lib13,\n" - " lib14,\n" - " lib15,\n" - " lib16,\n" - " lib17,\n" - " lib18,\n" - " lib20,\n" - " lib21,\n" - " lib22)\n" - ) - - test_output_hanging_indent = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.HANGING_INDENT, - line_length=40, - indent=" ", - ) - assert test_output_hanging_indent == ( - "from third_party import lib1, lib2, \\\n" - " lib3, lib4, lib5, lib6, lib7, \\\n" - " lib8, lib9, lib10, lib11, lib12, \\\n" - " lib13, lib14, lib15, lib16, lib17, \\\n" - " lib18, lib20, lib21, lib22\n" - ) - - comment_output_hanging_indent = isort.code( - code=REALLY_LONG_IMPORT_WITH_COMMENT, - multi_line_output=WrapModes.HANGING_INDENT, - line_length=40, - indent=" ", - ) - assert comment_output_hanging_indent == ( - "from third_party import lib1, \\ # comment\n" - " lib2, lib3, lib4, lib5, lib6, \\\n" - " lib7, lib8, lib9, lib10, lib11, \\\n" - " lib12, lib13, lib14, lib15, lib16, \\\n" - " lib17, lib18, lib20, lib21, lib22\n" - ) - - test_output_vertical_indent = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - line_length=40, - indent=" ", - ) - assert test_output_vertical_indent == ( - "from third_party import (\n" - " lib1,\n" - " lib2,\n" - " lib3,\n" - " lib4,\n" - " lib5,\n" - " lib6,\n" - " lib7,\n" - " lib8,\n" - " lib9,\n" - " lib10,\n" - " lib11,\n" - " lib12,\n" - " lib13,\n" - " lib14,\n" - " lib15,\n" - " lib16,\n" - " lib17,\n" - " lib18,\n" - " lib20,\n" - " lib21,\n" - " lib22\n" - ")\n" - ) - - comment_output_vertical_indent = isort.code( - code=REALLY_LONG_IMPORT_WITH_COMMENT, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - line_length=40, - indent=" ", - ) - assert comment_output_vertical_indent == ( - "from third_party import ( # comment\n" - " lib1,\n" - " lib2,\n" - " lib3,\n" - " lib4,\n" - " lib5,\n" - " lib6,\n" - " lib7,\n" - " lib8,\n" - " lib9,\n" - " lib10,\n" - " lib11,\n" - " lib12,\n" - " lib13,\n" - " lib14,\n" - " lib15,\n" - " lib16,\n" - " lib17,\n" - " lib18,\n" - " lib20,\n" - " lib21,\n" - " lib22\n" - ")\n" - ) - - test_output_vertical_grid = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.VERTICAL_GRID, - line_length=40, - indent=" ", - ) - assert test_output_vertical_grid == ( - "from third_party import (\n" - " lib1, lib2, lib3, lib4, lib5, lib6,\n" - " lib7, lib8, lib9, lib10, lib11,\n" - " lib12, lib13, lib14, lib15, lib16,\n" - " lib17, lib18, lib20, lib21, lib22)\n" - ) - - comment_output_vertical_grid = isort.code( - code=REALLY_LONG_IMPORT_WITH_COMMENT, - multi_line_output=WrapModes.VERTICAL_GRID, - line_length=40, - indent=" ", - ) - assert comment_output_vertical_grid == ( - "from third_party import ( # comment\n" - " lib1, lib2, lib3, lib4, lib5, lib6,\n" - " lib7, lib8, lib9, lib10, lib11,\n" - " lib12, lib13, lib14, lib15, lib16,\n" - " lib17, lib18, lib20, lib21, lib22)\n" - ) - - test_output_vertical_grid_grouped = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - line_length=40, - indent=" ", - ) - assert test_output_vertical_grid_grouped == ( - "from third_party import (\n" - " lib1, lib2, lib3, lib4, lib5, lib6,\n" - " lib7, lib8, lib9, lib10, lib11,\n" - " lib12, lib13, lib14, lib15, lib16,\n" - " lib17, lib18, lib20, lib21, lib22\n" - ")\n" - ) - - comment_output_vertical_grid_grouped = isort.code( - code=REALLY_LONG_IMPORT_WITH_COMMENT, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - line_length=40, - indent=" ", - ) - assert comment_output_vertical_grid_grouped == ( - "from third_party import ( # comment\n" - " lib1, lib2, lib3, lib4, lib5, lib6,\n" - " lib7, lib8, lib9, lib10, lib11,\n" - " lib12, lib13, lib14, lib15, lib16,\n" - " lib17, lib18, lib20, lib21, lib22\n" - ")\n" - ) - - output_noqa = isort.code(code=REALLY_LONG_IMPORT_WITH_COMMENT, multi_line_output=WrapModes.NOQA) - assert output_noqa == ( - "from third_party import lib1, lib2, lib3, lib4, lib5, lib6, lib7," - " lib8, lib9, lib10, lib11," - " lib12, lib13, lib14, lib15, lib16, lib17, lib18, lib20, lib21, lib22 " - "# NOQA comment\n" - ) - - test_case = isort.code( - code=SINGLE_LINE_LONG_IMPORT, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED_NO_COMMA, - line_length=40, - indent=" ", - ) - test_output_vertical_grid_grouped_doesnt_wrap_early = test_case - assert test_output_vertical_grid_grouped_doesnt_wrap_early == ( - "from third_party import (\n lib1, lib2, lib3, lib4, lib5, lib5ab\n)\n" - ) - - test_output_prefix_from_module = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.VERTICAL_PREFIX_FROM_MODULE_IMPORT, - line_length=40, - ) - assert test_output_prefix_from_module == ( - "from third_party import lib1, lib2\n" - "from third_party import lib3, lib4\n" - "from third_party import lib5, lib6\n" - "from third_party import lib7, lib8\n" - "from third_party import lib9, lib10\n" - "from third_party import lib11, lib12\n" - "from third_party import lib13, lib14\n" - "from third_party import lib15, lib16\n" - "from third_party import lib17, lib18\n" - "from third_party import lib20, lib21\n" - "from third_party import lib22\n" - ) - - test_output_prefix_from_module_with_comment = isort.code( - code=REALLY_LONG_IMPORT_WITH_COMMENT, - multi_line_output=WrapModes.VERTICAL_PREFIX_FROM_MODULE_IMPORT, - line_length=40, - indent=" ", - ) - assert test_output_prefix_from_module_with_comment == ( - "from third_party import lib1 # comment\n" - "from third_party import lib2, lib3\n" - "from third_party import lib4, lib5\n" - "from third_party import lib6, lib7\n" - "from third_party import lib8, lib9\n" - "from third_party import lib10, lib11\n" - "from third_party import lib12, lib13\n" - "from third_party import lib14, lib15\n" - "from third_party import lib16, lib17\n" - "from third_party import lib18, lib20\n" - "from third_party import lib21, lib22\n" - ) - - test_output_hanging_indent_with_parentheses = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.HANGING_INDENT_WITH_PARENTHESES, - line_length=40, - indent=" ", - ) - assert test_output_hanging_indent_with_parentheses == ( - "from third_party import (lib1, lib2,\n" - " lib3, lib4, lib5, lib6, lib7, lib8,\n" - " lib9, lib10, lib11, lib12, lib13,\n" - " lib14, lib15, lib16, lib17, lib18,\n" - " lib20, lib21, lib22)\n" - ) - - comment_output_hanging_indent_with_parentheses = isort.code( - code=REALLY_LONG_IMPORT_WITH_COMMENT, - multi_line_output=WrapModes.HANGING_INDENT_WITH_PARENTHESES, - line_length=40, - indent=" ", - ) - assert comment_output_hanging_indent_with_parentheses == ( - "from third_party import (lib1, # comment\n" - " lib2, lib3, lib4, lib5, lib6, lib7,\n" - " lib8, lib9, lib10, lib11, lib12,\n" - " lib13, lib14, lib15, lib16, lib17,\n" - " lib18, lib20, lib21, lib22)\n" - ) - - test_input = ( - "def a():\n" - " from allennlp.modules.text_field_embedders.basic_text_field_embedder" - " import BasicTextFieldEmbedder" - ) - test_output = isort.code(test_input, line_length=100) - assert test_output == ( - "def a():\n" - " from allennlp.modules.text_field_embedders.basic_text_field_embedder import \\\n" - " BasicTextFieldEmbedder" - ) - - test_input = ( - "class A:\n" - " def a():\n" - " from allennlp.common.registrable import Registrable" - " # import here to avoid circular imports\n" - "\n\n" - "class B:\n" - " def b():\n" - " from allennlp.common.registrable import Registrable" - " # import here to avoid circular imports\n" - ) - test_output = isort.code(test_input, line_length=100) - assert test_output == test_input - - -def test_qa_comment_case() -> None: - test_input = "from veryveryveryveryveryveryveryveryveryveryvery import X # NOQA" - test_output = isort.code(code=test_input, line_length=40, multi_line_output=WrapModes.NOQA) - assert test_output == "from veryveryveryveryveryveryveryveryveryveryvery import X # NOQA\n" - - test_input = "import veryveryveryveryveryveryveryveryveryveryvery # NOQA" - test_output = isort.code(code=test_input, line_length=40, multi_line_output=WrapModes.NOQA) - assert test_output == "import veryveryveryveryveryveryveryveryveryveryvery # NOQA\n" - - -def test_length_sort() -> None: - """Test setting isort to sort on length instead of alphabetically.""" - test_input = ( - "import medium_sizeeeeeeeeeeeeee\n" - "import shortie\n" - "import looooooooooooooooooooooooooooooooooooooong\n" - "import medium_sizeeeeeeeeeeeeea\n" - ) - test_output = isort.code(test_input, length_sort=True) - assert test_output == ( - "import shortie\n" - "import medium_sizeeeeeeeeeeeeea\n" - "import medium_sizeeeeeeeeeeeeee\n" - "import looooooooooooooooooooooooooooooooooooooong\n" - ) - - -def test_length_sort_straight() -> None: - """Test setting isort to sort straight imports on length instead of alphabetically.""" - test_input = ( - "import medium_sizeeeeeeeeeeeeee\n" - "import shortie\n" - "import looooooooooooooooooooooooooooooooooooooong\n" - "from medium_sizeeeeeeeeeeeeee import b\n" - "from shortie import c\n" - "from looooooooooooooooooooooooooooooooooooooong import a\n" - ) - test_output = isort.code(test_input, length_sort_straight=True) - assert test_output == ( - "import shortie\n" - "import medium_sizeeeeeeeeeeeeee\n" - "import looooooooooooooooooooooooooooooooooooooong\n" - "from looooooooooooooooooooooooooooooooooooooong import a\n" - "from medium_sizeeeeeeeeeeeeee import b\n" - "from shortie import c\n" - ) - - -def test_length_sort_section() -> None: - """Test setting isort to sort on length instead of alphabetically for a specific section.""" - test_input = ( - "import medium_sizeeeeeeeeeeeeee\n" - "import shortie\n" - "import datetime\n" - "import sys\n" - "import os\n" - "import looooooooooooooooooooooooooooooooooooooong\n" - "import medium_sizeeeeeeeeeeeeea\n" - ) - test_output = isort.code(test_input, length_sort_sections=("stdlib",)) - assert test_output == ( - "import os\n" - "import sys\n" - "import datetime\n" - "\n" - "import looooooooooooooooooooooooooooooooooooooong\n" - "import medium_sizeeeeeeeeeeeeea\n" - "import medium_sizeeeeeeeeeeeeee\n" - "import shortie\n" - ) - - -def test_convert_hanging() -> None: - """Ensure that isort will convert hanging indents to correct indent - method.""" - test_input = ( - "from third_party import lib1, lib2, \\\n" - " lib3, lib4, lib5, lib6, lib7, \\\n" - " lib8, lib9, lib10, lib11, lib12, \\\n" - " lib13, lib14, lib15, lib16, lib17, \\\n" - " lib18, lib20, lib21, lib22\n" - ) - test_output = isort.code(code=test_input, multi_line_output=WrapModes.GRID, line_length=40) - assert test_output == ( - "from third_party import (lib1, lib2,\n" - " lib3, lib4,\n" - " lib5, lib6,\n" - " lib7, lib8,\n" - " lib9, lib10,\n" - " lib11, lib12,\n" - " lib13, lib14,\n" - " lib15, lib16,\n" - " lib17, lib18,\n" - " lib20, lib21,\n" - " lib22)\n" - ) - - -def test_custom_indent() -> None: - """Ensure setting a custom indent will work as expected.""" - test_output = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.HANGING_INDENT, - line_length=40, - indent=" ", - balanced_wrapping=False, - ) - assert test_output == ( - "from third_party import lib1, lib2, \\\n" - " lib3, lib4, lib5, lib6, lib7, lib8, \\\n" - " lib9, lib10, lib11, lib12, lib13, \\\n" - " lib14, lib15, lib16, lib17, lib18, \\\n" - " lib20, lib21, lib22\n" - ) - - test_output = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.HANGING_INDENT, - line_length=40, - indent="' '", - balanced_wrapping=False, - ) - assert test_output == ( - "from third_party import lib1, lib2, \\\n" - " lib3, lib4, lib5, lib6, lib7, lib8, \\\n" - " lib9, lib10, lib11, lib12, lib13, \\\n" - " lib14, lib15, lib16, lib17, lib18, \\\n" - " lib20, lib21, lib22\n" - ) - - test_output = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.HANGING_INDENT, - line_length=40, - indent="tab", - balanced_wrapping=False, - ) - assert test_output == ( - "from third_party import lib1, lib2, \\\n" - "\tlib3, lib4, lib5, lib6, lib7, lib8, \\\n" - "\tlib9, lib10, lib11, lib12, lib13, \\\n" - "\tlib14, lib15, lib16, lib17, lib18, \\\n" - "\tlib20, lib21, lib22\n" - ) - - test_output = isort.code( - code=REALLY_LONG_IMPORT, - multi_line_output=WrapModes.HANGING_INDENT, - line_length=40, - indent=2, - balanced_wrapping=False, - ) - assert test_output == ( - "from third_party import lib1, lib2, \\\n" - " lib3, lib4, lib5, lib6, lib7, lib8, \\\n" - " lib9, lib10, lib11, lib12, lib13, \\\n" - " lib14, lib15, lib16, lib17, lib18, \\\n" - " lib20, lib21, lib22\n" - ) - - -def test_use_parentheses() -> None: - test_input = ( - "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import " - " my_custom_function as my_special_function" - ) - test_output = isort.code(test_input, line_length=79, use_parentheses=True) - - assert test_output == ( - "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import (\n" - " my_custom_function as my_special_function)\n" - ) - - test_output = isort.code( - code=test_input, line_length=79, use_parentheses=True, include_trailing_comma=True - ) - - assert test_output == ( - "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import (\n" - " my_custom_function as my_special_function,)\n" - ) - - test_output = isort.code( - code=test_input, - line_length=79, - use_parentheses=True, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - ) - - assert test_output == ( - "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import (\n" - " my_custom_function as my_special_function\n)\n" - ) - - test_output = isort.code( - code=test_input, - line_length=79, - use_parentheses=True, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - include_trailing_comma=True, - ) - - assert test_output == ( - "from fooooooooooooooooooooooooo.baaaaaaaaaaaaaaaaaaarrrrrrr import (\n" - " my_custom_function as my_special_function,\n)\n" - ) - - -def test_skip() -> None: - """Ensure skipping a single import will work as expected.""" - test_input = ( - "import myproject\n" - "import django\n" - "print('hey')\n" - "import sys # isort: skip this import needs to be placed here\n\n\n\n\n\n\n" - ) - - test_output = isort.code(test_input, known_first_party=["myproject"]) - assert test_output == ( - "import django\n" - "\n" - "import myproject\n" - "\n" - "print('hey')\n" - "import sys # isort: skip this import needs to be placed here\n" - ) - - -def test_skip_with_file_name() -> None: - """Ensure skipping a file works even when file_contents is provided.""" - test_input = "import django\nimport myproject\n" - with pytest.raises(FileSkipped): - isort.code( - file_path=Path("/baz.py"), code=test_input, settings_path=os.getcwd(), skip=["baz.py"] - ) - - -def test_skip_within_file() -> None: - """Ensure skipping a whole file works.""" - test_input = "# isort: skip_file\nimport django\nimport myproject\n" - with pytest.raises(FileSkipped): - isort.code(test_input, known_third_party=["django"]) - - -def test_force_to_top() -> None: - """Ensure forcing a single import to the top of its category works as expected.""" - test_input = "import lib6\nimport lib2\nimport lib5\nimport lib1\n" - test_output = isort.code(test_input, force_to_top=["lib5"]) - assert test_output == "import lib5\nimport lib1\nimport lib2\nimport lib6\n" - - -def test_add_imports() -> None: - """Ensures adding imports works as expected.""" - test_input = "import lib6\nimport lib2\nimport lib5\nimport lib1\n\n" - test_output = isort.code(code=test_input, add_imports=["import lib4", "import lib7"]) - assert test_output == ( - "import lib1\n" - "import lib2\n" - "import lib4\n" - "import lib5\n" - "import lib6\n" - "import lib7\n" - ) - - # Using simplified syntax - test_input = "import lib6\nimport lib2\nimport lib5\nimport lib1\n\n" - test_output = isort.code(code=test_input, add_imports=["lib4", "lib7", "lib8.a"]) - assert test_output == ( - "import lib1\n" - "import lib2\n" - "import lib4\n" - "import lib5\n" - "import lib6\n" - "import lib7\n" - "from lib8 import a\n" - ) - - # On a file that has no pre-existing imports - test_input = '"""Module docstring"""\n' "class MyClass(object):\n pass\n" - test_output = isort.code(code=test_input, add_imports=["from __future__ import print_function"]) - assert test_output == ( - '"""Module docstring"""\n' - "from __future__ import print_function\n" - "\n" - "\n" - "class MyClass(object):\n" - " pass\n" - ) - - # On a file that has no pre-existing imports, and no doc-string - test_input = "class MyClass(object):\n pass\n" - test_output = isort.code(code=test_input, add_imports=["from __future__ import print_function"]) - assert test_output == ( - "from __future__ import print_function\n" "\n" "\n" "class MyClass(object):\n" " pass\n" - ) - - # On a file with no content what so ever - test_input = "" - test_output = isort.code(test_input, add_imports=["lib4"]) - assert test_output == ("") - - # On a file with no content what so ever, after force_adds is set to True - test_input = "" - test_output = isort.code(code=test_input, add_imports=["lib4"], force_adds=True) - assert test_output == ("import lib4\n") - - -def test_remove_imports() -> None: - """Ensures removing imports works as expected.""" - test_input = "import lib6\nimport lib2\nimport lib5\nimport lib1" - test_output = isort.code(test_input, remove_imports=["lib2", "lib6"]) - assert test_output == "import lib1\nimport lib5\n" - - # Using natural syntax - test_input = ( - "import lib6\n" "import lib2\n" "import lib5\n" "import lib1\n" "from lib8 import a" - ) - test_output = isort.code( - code=test_input, remove_imports=["import lib2", "import lib6", "from lib8 import a"] - ) - assert test_output == "import lib1\nimport lib5\n" - - # From imports - test_input = "from x import y" - test_output = isort.code(test_input, remove_imports=["x"]) - assert test_output == "" - - test_input = "from x import y" - test_output = isort.code(test_input, remove_imports=["x.y"]) - assert test_output == "" - - -def test_comments_above(): - """Test to ensure comments above an import will stay in place""" - test_input = "import os\n\nfrom x import y\n\n# comment\nfrom z import __version__, api\n" - assert isort.code(test_input, ensure_newline_before_comments=True) == test_input - - -def test_explicitly_local_import() -> None: - """Ensure that explicitly local imports are separated.""" - test_input = "import lib1\nimport lib2\nimport .lib6\nfrom . import lib7" - assert isort.code(test_input) == ( - "import lib1\nimport lib2\n\nimport .lib6\nfrom . import lib7\n" - ) - assert isort.code(test_input, old_finders=True) == ( - "import lib1\nimport lib2\n\nimport .lib6\nfrom . import lib7\n" - ) - - -def test_quotes_in_file() -> None: - """Ensure imports within triple quotes don't get imported.""" - test_input = "import os\n\n" '"""\n' "Let us\nimport foo\nokay?\n" '"""\n' - assert isort.code(test_input) == test_input - - test_input = "import os\n\n" '\'"""\'\n' "import foo\n" - assert isort.code(test_input) == test_input - - test_input = "import os\n\n" '"""Let us"""\n' "import foo\n\n" '"""okay?"""\n' - assert isort.code(test_input) == test_input - - test_input = "import os\n\n" '#"""\n' "import foo\n" '#"""' - assert isort.code(test_input) == ('import os\n\nimport foo\n\n#"""\n#"""\n') - - test_input = "import os\n\n'\\\nimport foo'\n" - assert isort.code(test_input) == test_input - - test_input = "import os\n\n'''\n\\'''\nimport junk\n'''\n" - assert isort.code(test_input) == test_input - - -def test_check_newline_in_imports(capsys) -> None: - """Ensure tests works correctly when new lines are in imports.""" - test_input = "from lib1 import (\n sub1,\n sub2,\n sub3\n)\n" - - assert api.check_code_string( - code=test_input, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - line_length=20, - verbose=True, - ) - out, _ = capsys.readouterr() - assert "SUCCESS" in out - - -def test_forced_separate() -> None: - """Ensure that forcing certain sub modules to show separately works as expected.""" - test_input = ( - "import sys\n" - "import warnings\n" - "from collections import OrderedDict\n" - "\n" - "from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation\n" - "from django.core.paginator import InvalidPage\n" - "from django.core.urlresolvers import reverse\n" - "from django.db import models\n" - "from django.db.models.fields import FieldDoesNotExist\n" - "from django.utils import six\n" - "from django.utils.deprecation import RenameMethodsBase\n" - "from django.utils.encoding import force_str, force_text\n" - "from django.utils.http import urlencode\n" - "from django.utils.translation import ugettext, ugettext_lazy\n" - "\n" - "from django.contrib.admin import FieldListFilter\n" - "from django.contrib.admin.exceptions import DisallowedModelAdminLookup\n" - "from django.contrib.admin.options import IncorrectLookupParameters, IS_POPUP_VAR, " - "TO_FIELD_VAR\n" - ) - assert ( - isort.code( - code=test_input, - forced_separate=["django.contrib"], - known_third_party=["django"], - line_length=120, - order_by_type=False, - ) - == test_input - ) - assert ( - isort.code( - code=test_input, - forced_separate=["django.contrib"], - known_third_party=["django"], - line_length=120, - order_by_type=False, - old_finders=True, - ) - == test_input - ) - - test_input = "from .foo import bar\n\nfrom .y import ca\n" - assert ( - isort.code(code=test_input, forced_separate=[".y"], line_length=120, order_by_type=False) - == test_input - ) - assert ( - isort.code( - code=test_input, - forced_separate=[".y"], - line_length=120, - order_by_type=False, - old_finders=True, - ) - == test_input - ) - - -def test_default_section() -> None: - """Test to ensure changing the default section works as expected.""" - test_input = "import sys\nimport os\nimport myproject.test\nimport django.settings" - test_output = isort.code( - code=test_input, known_third_party=["django"], default_section="FIRSTPARTY" - ) - assert test_output == ( - "import os\n" "import sys\n" "\n" "import django.settings\n" "\n" "import myproject.test\n" - ) - - test_output_custom = isort.code( - code=test_input, known_third_party=["django"], default_section="STDLIB" - ) - assert test_output_custom == ( - "import myproject.test\n" "import os\n" "import sys\n" "\n" "import django.settings\n" - ) - - -def test_first_party_overrides_standard_section() -> None: - """Test to ensure changing the default section works as expected.""" - test_input = ( - "from HTMLParser import HTMLParseError, HTMLParser\n" - "import sys\n" - "import os\n" - "import profile.test\n" - ) - test_output = isort.code(code=test_input, known_first_party=["profile"], py_version="27") - assert test_output == ( - "import os\n" - "import sys\n" - "from HTMLParser import HTMLParseError, HTMLParser\n" - "\n" - "import profile.test\n" - ) - - -def test_thirdy_party_overrides_standard_section() -> None: - """Test to ensure changing the default section works as expected.""" - test_input = "import sys\nimport os\nimport profile.test\n" - test_output = isort.code(test_input, known_third_party=["profile"]) - assert test_output == "import os\nimport sys\n\nimport profile.test\n" - - -def test_known_pattern_path_expansion(tmpdir) -> None: - """Test to ensure patterns ending with path sep gets expanded - and nested packages treated as known patterns. - """ - src_dir = tmpdir.mkdir("src") - src_dir.mkdir("foo") - src_dir.mkdir("bar") - test_input = ( - "from kate_plugin import isort_plugin\n" - "import sys\n" - "from foo import settings\n" - "import bar\n" - "import this\n" - "import os\n" - ) - test_output = isort.code( - code=test_input, - default_section="THIRDPARTY", - known_first_party=["src/", "this", "kate_plugin"], - directory=str(tmpdir), - ) - test_output_old_finder = isort.code( - code=test_input, - default_section="FIRSTPARTY", - old_finders=True, - known_first_party=["src/", "this", "kate_plugin"], - directory=str(tmpdir), - ) - assert ( - test_output_old_finder - == test_output - == ( - "import os\n" - "import sys\n" - "\n" - "import bar\n" - "import this\n" - "from foo import settings\n" - "from kate_plugin import isort_plugin\n" - ) - ) - - -def test_force_single_line_imports() -> None: - """Test to ensure forcing imports to each have their own line works as expected.""" - test_input = ( - "from third_party import lib1, lib2, \\\n" - " lib3, lib4, lib5, lib6, lib7, \\\n" - " lib8, lib9, lib10, lib11, lib12, \\\n" - " lib13, lib14, lib15, lib16, lib17, \\\n" - " lib18, lib20, lib21, lib22\n" - ) - test_output = isort.code( - code=test_input, multi_line_output=WrapModes.GRID, line_length=40, force_single_line=True - ) - assert test_output == ( - "from third_party import lib1\n" - "from third_party import lib2\n" - "from third_party import lib3\n" - "from third_party import lib4\n" - "from third_party import lib5\n" - "from third_party import lib6\n" - "from third_party import lib7\n" - "from third_party import lib8\n" - "from third_party import lib9\n" - "from third_party import lib10\n" - "from third_party import lib11\n" - "from third_party import lib12\n" - "from third_party import lib13\n" - "from third_party import lib14\n" - "from third_party import lib15\n" - "from third_party import lib16\n" - "from third_party import lib17\n" - "from third_party import lib18\n" - "from third_party import lib20\n" - "from third_party import lib21\n" - "from third_party import lib22\n" - ) - - test_input = ( - "from third_party import lib_a, lib_b, lib_d\n" "from third_party.lib_c import lib1\n" - ) - test_output = isort.code( - code=test_input, multi_line_output=WrapModes.GRID, line_length=40, force_single_line=True - ) - assert test_output == ( - "from third_party import lib_a\n" - "from third_party import lib_b\n" - "from third_party import lib_d\n" - "from third_party.lib_c import lib1\n" - ) - - -def test_force_single_line_long_imports() -> None: - test_input = "from veryveryveryveryveryvery import small, big\n" - test_output = isort.code( - code=test_input, multi_line_output=WrapModes.NOQA, line_length=40, force_single_line=True - ) - assert test_output == ( - "from veryveryveryveryveryvery import big\n" - "from veryveryveryveryveryvery import small # NOQA\n" - ) - - -def test_force_single_line_imports_and_sort_within_sections() -> None: - test_input = ( - "from third_party import lib_a, lib_b, lib_d\n" "from third_party.lib_c import lib1\n" - ) - test_output = isort.code( - code=test_input, - multi_line_output=WrapModes.GRID, - line_length=40, - force_single_line=True, - force_sort_within_sections=True, - ) - assert test_output == ( - "from third_party import lib_a\n" - "from third_party import lib_b\n" - "from third_party import lib_d\n" - "from third_party.lib_c import lib1\n" - ) - test_output = isort.code( - code=test_input, - multi_line_output=WrapModes.GRID, - line_length=40, - force_single_line=True, - force_sort_within_sections=True, - lexicographical=True, - ) - assert test_output == ( - "from third_party import lib_a\n" - "from third_party import lib_b\n" - "from third_party.lib_c import lib1\n" - "from third_party import lib_d\n" - ) - - # Ensure force_sort_within_sections can work with length sort - # See: https://github.com/timothycrosley/isort/issues/1038 - test_input = """import sympy -import numpy as np -import pandas as pd -from matplotlib import pyplot as plt -""" - test_output = ( - isort.code(code=test_input, force_sort_within_sections=True, length_sort=True) == test_input - ) - - -def test_titled_imports() -> None: - """Tests setting custom titled/commented import sections.""" - test_input = ( - "import sys\n" - "import unicodedata\n" - "import statistics\n" - "import os\n" - "import myproject.test\n" - "import django.settings" - ) - test_output = isort.code( - code=test_input, - known_first_party=["myproject"], - import_heading_stdlib="Standard Library", - import_heading_firstparty="My Stuff", - ) - assert test_output == ( - "# Standard Library\n" - "import os\n" - "import statistics\n" - "import sys\n" - "import unicodedata\n" - "\n" - "import django.settings\n" - "\n" - "# My Stuff\n" - "import myproject.test\n" - ) - test_second_run = isort.code( - code=test_output, - known_first_party=["myproject"], - import_heading_stdlib="Standard Library", - import_heading_firstparty="My Stuff", - ) - assert test_second_run == test_output - - -def test_balanced_wrapping() -> None: - """Tests balanced wrapping mode, where the length of individual lines maintain width.""" - test_input = ( - "from __future__ import (absolute_import, division, print_function,\n" - " unicode_literals)" - ) - test_output = isort.code(code=test_input, line_length=70, balanced_wrapping=True) - assert test_output == ( - "from __future__ import (absolute_import, division,\n" - " print_function, unicode_literals)\n" - ) - - -def test_relative_import_with_space() -> None: - """Tests the case where the relation and the module that is being imported from is separated - with a space. - """ - test_input = "from ... fields.sproqet import SproqetCollection" - assert isort.code(test_input) == ("from ...fields.sproqet import SproqetCollection\n") - test_input = "from .import foo" - test_output = "from . import foo\n" - assert isort.code(test_input) == test_output - test_input = "from.import foo" - test_output = "from . import foo\n" - assert isort.code(test_input) == test_output - - -def test_multiline_import() -> None: - """Test the case where import spawns multiple lines with inconsistent indentation.""" - test_input = "from pkg \\\n import stuff, other_suff \\\n more_stuff" - assert isort.code(test_input) == ("from pkg import more_stuff, other_suff, stuff\n") - - # test again with a custom configuration - custom_configuration = { - "force_single_line": True, - "line_length": 120, - "known_first_party": ["asdf", "qwer"], - "default_section": "THIRDPARTY", - "forced_separate": "asdf", - } # type: Dict[str, Any] - expected_output = ( - "from pkg import more_stuff\n" "from pkg import other_suff\n" "from pkg import stuff\n" - ) - assert isort.code(test_input, **custom_configuration) == expected_output - - -def test_single_multiline() -> None: - """Test the case where a single import spawns multiple lines.""" - test_input = "from os import\\\n getuid\n\nprint getuid()\n" - output = isort.code(test_input) - assert output == ("from os import getuid\n\nprint getuid()\n") - - -def test_atomic_mode() -> None: - # without syntax error, everything works OK - test_input = "from b import d, c\nfrom a import f, e\n" - assert isort.code(test_input, atomic=True) == ("from a import e, f\nfrom b import c, d\n") - - # with syntax error content is not changed - test_input += "while True print 'Hello world'" # blatant syntax error - with pytest.raises(ExistingSyntaxErrors): - isort.code(test_input, atomic=True) - - -def test_order_by_type() -> None: - test_input = "from module import Class, CONSTANT, function" - assert isort.code(test_input, order_by_type=True) == ( - "from module import CONSTANT, Class, function\n" - ) - - # More complex sample data - test_input = "from module import Class, CONSTANT, function, BASIC, Apple" - assert isort.code(test_input, order_by_type=True) == ( - "from module import BASIC, CONSTANT, Apple, Class, function\n" - ) - - # Really complex sample data, to verify we don't mess with top level imports, only nested ones - test_input = ( - "import StringIO\n" - "import glob\n" - "import os\n" - "import shutil\n" - "import tempfile\n" - "import time\n" - "from subprocess import PIPE, Popen, STDOUT\n" - ) - - assert isort.code(test_input, order_by_type=True, py_version="27") == ( - "import glob\n" - "import os\n" - "import shutil\n" - "import StringIO\n" - "import tempfile\n" - "import time\n" - "from subprocess import PIPE, STDOUT, Popen\n" - ) - - -def test_custom_lines_after_import_section() -> None: - """Test the case where the number of lines to output after imports has been explicitly set.""" - test_input = "from a import b\nfoo = 'bar'\n" - - # default case is one space if not method or class after imports - assert isort.code(test_input) == ("from a import b\n\nfoo = 'bar'\n") - - # test again with a custom number of lines after the import section - assert isort.code(test_input, lines_after_imports=2) == ("from a import b\n\n\nfoo = 'bar'\n") - - -def test_smart_lines_after_import_section() -> None: - """Tests the default 'smart' behavior for dealing with lines after the import section""" - # one space if not method or class after imports - test_input = "from a import b\nfoo = 'bar'\n" - assert isort.code(test_input) == ("from a import b\n\nfoo = 'bar'\n") - - # two spaces if a method or class after imports - test_input = "from a import b\ndef my_function():\n pass\n" - assert isort.code(test_input) == ("from a import b\n\n\ndef my_function():\n pass\n") - - # two spaces if an async method after imports - test_input = "from a import b\nasync def my_function():\n pass\n" - assert isort.code(test_input) == ("from a import b\n\n\nasync def my_function():\n pass\n") - - # two spaces if a method or class after imports - even if comment before function - test_input = ( - "from a import b\n" "# comment should be ignored\n" "def my_function():\n" " pass\n" - ) - assert isort.code(test_input) == ( - "from a import b\n" - "\n" - "\n" - "# comment should be ignored\n" - "def my_function():\n" - " pass\n" - ) - - # the same logic does not apply to doc strings - test_input = ( - "from a import b\n" - '"""\n' - " comment should be ignored\n" - '"""\n' - "def my_function():\n" - " pass\n" - ) - assert isort.code(test_input) == ( - "from a import b\n" - "\n" - '"""\n' - " comment should be ignored\n" - '"""\n' - "def my_function():\n" - " pass\n" - ) - - # Ensure logic doesn't incorrectly skip over assignments to multi-line strings - test_input = 'from a import b\nX = """test\n"""\ndef my_function():\n pass\n' - assert isort.code(test_input) == ( - "from a import b\n" "\n" 'X = """test\n' '"""\n' "def my_function():\n" " pass\n" - ) - - -def test_settings_overwrite() -> None: - """Test to ensure settings overwrite instead of trying to combine.""" - assert Config(known_standard_library=["not_std_library"]).known_standard_library == frozenset( - {"not_std_library"} - ) - assert Config(known_first_party=["thread"]).known_first_party == frozenset({"thread"}) - - -def test_combined_from_and_as_imports() -> None: - """Test to ensure it's possible to combine from and as imports.""" - test_input = ( - "from translate.misc.multistring import multistring\n" - "from translate.storage import base, factory\n" - "from translate.storage.placeables import general, parse as rich_parse\n" - ) - assert isort.code(test_input, combine_as_imports=True) == test_input - test_input = "import os \nimport os as _os" - test_output = "import os\nimport os as _os\n" - assert isort.code(test_input) == test_output - - -def test_as_imports_with_line_length() -> None: - """Test to ensure it's possible to combine from and as imports.""" - test_input = ( - "from translate.storage import base as storage_base\n" - "from translate.storage.placeables import general, parse as rich_parse\n" - ) - assert isort.code(code=test_input, combine_as_imports=False, line_length=40) == ( - "from translate.storage import \\\n base as storage_base\n" - "from translate.storage.placeables import \\\n general\n" - "from translate.storage.placeables import \\\n parse as rich_parse\n" - ) - - -def test_keep_comments() -> None: - """Test to ensure isort properly keeps comments in tact after sorting.""" - # Straight Import - test_input = "import foo # bar\n" - assert isort.code(test_input) == test_input - - # Star import - test_input_star = "from foo import * # bar\n" - assert isort.code(test_input_star) == test_input_star - - # Force Single Line From Import - test_input = "from foo import bar # comment\n" - assert isort.code(test_input, force_single_line=True) == test_input - - # From import - test_input = "from foo import bar # My Comment\n" - assert isort.code(test_input) == test_input - - # More complicated case - test_input = "from a import b # My Comment1\nfrom a import c # My Comment2\n" - assert isort.code(test_input) == ( - "from a import b # My Comment1\nfrom a import c # My Comment2\n" - ) - - # Test case where imports comments make imports extend pass the line length - test_input = ( - "from a import b # My Comment1\n" "from a import c # My Comment2\n" "from a import d\n" - ) - assert isort.code(test_input, line_length=45) == ( - "from a import b # My Comment1\n" "from a import c # My Comment2\n" "from a import d\n" - ) - - # Test case where imports with comments will be beyond line length limit - test_input = ( - "from a import b, c # My Comment1\n" - "from a import c, d # My Comment2 is really really really really long\n" - ) - assert isort.code(test_input, line_length=45) == ( - "from a import ( # My Comment1; My Comment2 is really really really really long\n" - " b, c, d)\n" - ) - - # Test that comments are not stripped from 'import ... as ...' by default - test_input = "from a import b as bb # b comment\nfrom a import c as cc # c comment\n" - assert isort.code(test_input) == test_input - - # Test that 'import ... as ...' comments are not collected inappropriately - test_input = ( - "from a import b as bb # b comment\n" - "from a import c as cc # c comment\n" - "from a import d\n" - ) - assert isort.code(test_input) == test_input - assert isort.code(test_input, combine_as_imports=True) == ( - "from a import b as bb, c as cc, d # b comment; c comment\n" - ) - - -def test_multiline_split_on_dot() -> None: - """Test to ensure isort correctly handles multiline imports, - even when split right after a '.' - """ - test_input = ( - "from my_lib.my_package.test.level_1.level_2.level_3.level_4.level_5.\\\n" - " my_module import my_function" - ) - assert isort.code(test_input, line_length=70) == ( - "from my_lib.my_package.test.level_1.level_2.level_3.level_4.level_5.my_module import \\\n" - " my_function\n" - ) - - -def test_import_star() -> None: - """Test to ensure isort handles star imports correctly""" - test_input = "from blah import *\nfrom blah import _potato\n" - assert isort.code(test_input) == ("from blah import *\nfrom blah import _potato\n") - assert isort.code(test_input, combine_star=True) == ("from blah import *\n") - - -def test_include_trailing_comma() -> None: - """Test for the include_trailing_comma option""" - test_output_grid = isort.code( - code=SHORT_IMPORT, - multi_line_output=WrapModes.GRID, - line_length=40, - include_trailing_comma=True, - ) - assert test_output_grid == ( - "from third_party import (lib1, lib2,\n" " lib3, lib4,)\n" - ) - - test_output_vertical = isort.code( - code=SHORT_IMPORT, - multi_line_output=WrapModes.VERTICAL, - line_length=40, - include_trailing_comma=True, - ) - assert test_output_vertical == ( - "from third_party import (lib1,\n" - " lib2,\n" - " lib3,\n" - " lib4,)\n" - ) - - test_output_vertical_indent = isort.code( - code=SHORT_IMPORT, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - line_length=40, - include_trailing_comma=True, - ) - assert test_output_vertical_indent == ( - "from third_party import (\n" " lib1,\n" " lib2,\n" " lib3,\n" " lib4,\n" ")\n" - ) - - test_output_vertical_grid = isort.code( - code=SHORT_IMPORT, - multi_line_output=WrapModes.VERTICAL_GRID, - line_length=40, - include_trailing_comma=True, - ) - assert test_output_vertical_grid == ( - "from third_party import (\n lib1, lib2, lib3, lib4,)\n" - ) - - test_output_vertical_grid_grouped = isort.code( - code=SHORT_IMPORT, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - line_length=40, - include_trailing_comma=True, - ) - assert test_output_vertical_grid_grouped == ( - "from third_party import (\n lib1, lib2, lib3, lib4,\n)\n" - ) - - test_output_wrap_single_import_with_use_parentheses = isort.code( - code=SINGLE_FROM_IMPORT, line_length=25, include_trailing_comma=True, use_parentheses=True - ) - assert test_output_wrap_single_import_with_use_parentheses == ( - "from third_party import (\n lib1,)\n" - ) - - test_output_wrap_single_import_vertical_indent = isort.code( - code=SINGLE_FROM_IMPORT, - line_length=25, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - include_trailing_comma=True, - use_parentheses=True, - ) - assert test_output_wrap_single_import_vertical_indent == ( - "from third_party import (\n lib1,\n)\n" - ) - - trailing_comma_with_comment = ( - "from six.moves.urllib.parse import urlencode " - "# pylint: disable=no-name-in-module,import-error" - ) - expected_trailing_comma_with_comment = ( - "from six.moves.urllib.parse import (\n" - " urlencode, # pylint: disable=no-n" - "ame-in-module,import-error\n)\n" - ) - trailing_comma_with_comment = isort.code( - code=trailing_comma_with_comment, - line_length=80, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - include_trailing_comma=True, - use_parentheses=True, - ) - assert trailing_comma_with_comment == expected_trailing_comma_with_comment - # The next time around, it should be equal - trailing_comma_with_comment = isort.code( - code=trailing_comma_with_comment, - line_length=80, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - include_trailing_comma=True, - use_parentheses=True, - ) - assert trailing_comma_with_comment == expected_trailing_comma_with_comment - - -def test_similar_to_std_library() -> None: - """Test to ensure modules that are named similarly to a standard library import - don't end up clobbered - """ - test_input = "import datetime\n\nimport requests\nimport times\n" - assert isort.code(test_input, known_third_party=["requests", "times"]) == test_input - - -def test_correctly_placed_imports() -> None: - """Test to ensure comments stay on correct placement after being sorted""" - test_input = "from a import b # comment for b\nfrom a import c # comment for c\n" - assert isort.code(test_input, force_single_line=True) == ( - "from a import b # comment for b\nfrom a import c # comment for c\n" - ) - assert isort.code(test_input) == ( - "from a import b # comment for b\nfrom a import c # comment for c\n" - ) - - # Full example test from issue #143 - test_input = ( - "from itertools import chain\n" - "\n" - "from django.test import TestCase\n" - "from model_mommy import mommy\n" - "\n" - "from apps.clientman.commands.download_usage_rights import " - "associate_right_for_item_product\n" - "from apps.clientman.commands.download_usage_rights import " - "associate_right_for_item_product_d" - "efinition\n" - "from apps.clientman.commands.download_usage_rights import " - "associate_right_for_item_product_d" - "efinition_platform\n" - "from apps.clientman.commands.download_usage_rights import " - "associate_right_for_item_product_p" - "latform\n" - "from apps.clientman.commands.download_usage_rights import " - "associate_right_for_territory_reta" - "il_model\n" - "from apps.clientman.commands.download_usage_rights import " - "associate_right_for_territory_reta" - "il_model_definition_platform_provider # noqa\n" - "from apps.clientman.commands.download_usage_rights import " - "clear_right_for_item_product\n" - "from apps.clientman.commands.download_usage_rights import " - "clear_right_for_item_product_defini" - "tion\n" - "from apps.clientman.commands.download_usage_rights import " - "clear_right_for_item_product_defini" - "tion_platform\n" - "from apps.clientman.commands.download_usage_rights import " - "clear_right_for_item_product_platfo" - "rm\n" - "from apps.clientman.commands.download_usage_rights import " - "clear_right_for_territory_retail_mo" - "del\n" - "from apps.clientman.commands.download_usage_rights import " - "clear_right_for_territory_retail_mo" - "del_definition_platform_provider # noqa\n" - "from apps.clientman.commands.download_usage_rights import " - "create_download_usage_right\n" - "from apps.clientman.commands.download_usage_rights import " - "delete_download_usage_right\n" - "from apps.clientman.commands.download_usage_rights import " - "disable_download_for_item_product\n" - "from apps.clientman.commands.download_usage_rights import " - "disable_download_for_item_product_d" - "efinition\n" - "from apps.clientman.commands.download_usage_rights import " - "disable_download_for_item_product_d" - "efinition_platform\n" - "from apps.clientman.commands.download_usage_rights import " - "disable_download_for_item_product_p" - "latform\n" - "from apps.clientman.commands.download_usage_rights import " - "disable_download_for_territory_reta" - "il_model\n" - "from apps.clientman.commands.download_usage_rights import " - "disable_download_for_territory_reta" - "il_model_definition_platform_provider # noqa\n" - "from apps.clientman.commands.download_usage_rights import " - "get_download_rights_for_item\n" - "from apps.clientman.commands.download_usage_rights import " - "get_right\n" - ) - assert ( - isort.code( - code=test_input, - force_single_line=True, - line_length=140, - known_third_party=["django", "model_mommy"], - default_section=sections.FIRSTPARTY, - ) - == test_input - ) - - -def test_auto_detection() -> None: - """Initial test to ensure isort auto-detection works correctly - - will grow over time as new issues are raised. - """ - - # Issue 157 - test_input = "import binascii\nimport os\n\nimport cv2\nimport requests\n" - assert isort.code(test_input, known_third_party=["cv2", "requests"]) == test_input - - # alternative solution - assert isort.code(test_input, default_section="THIRDPARTY") == test_input - - -def test_same_line_statements() -> None: - """Ensure isort correctly handles the case where a single line - contains multiple statements including an import - """ - test_input = "import pdb; import nose\n" - assert isort.code(test_input) == ("import pdb\n\nimport nose\n") - - test_input = "import pdb; pdb.set_trace()\nimport nose; nose.run()\n" - assert isort.code(test_input) == test_input - - -def test_long_line_comments() -> None: - """Ensure isort correctly handles comments at the end of extremely long lines""" - test_input = ( - "from foo.utils.fabric_stuff.live import check_clean_live, deploy_live, " - "sync_live_envdir, " - "update_live_app, update_live_cron # noqa\n" - "from foo.utils.fabric_stuff.stage import check_clean_stage, deploy_stage, " - "sync_stage_envdir, " - "update_stage_app, update_stage_cron # noqa\n" - ) - assert isort.code(code=test_input, line_length=100, balanced_wrapping=True) == ( - "from foo.utils.fabric_stuff.live import (check_clean_live, deploy_live, # noqa\n" - " sync_live_envdir, update_live_app, " - "update_live_cron)\n" - "from foo.utils.fabric_stuff.stage import (check_clean_stage, deploy_stage, # noqa\n" - " sync_stage_envdir, update_stage_app, " - "update_stage_cron)\n" - ) - - -def test_tab_character_in_import() -> None: - """Ensure isort correctly handles import statements that contain a tab character""" - test_input = ( - "from __future__ import print_function\n" "from __future__ import\tprint_function\n" - ) - assert isort.code(test_input) == "from __future__ import print_function\n" - - -def test_split_position() -> None: - """Ensure isort splits on import instead of . when possible""" - test_input = ( - "from p24.shared.exceptions.master.host_state_flag_unchanged " - "import HostStateUnchangedException\n" - ) - assert isort.code(test_input, line_length=80) == ( - "from p24.shared.exceptions.master.host_state_flag_unchanged import \\\n" - " HostStateUnchangedException\n" - ) - - -def test_place_comments() -> None: - """Ensure manually placing imports works as expected""" - test_input = ( - "import sys\n" - "import os\n" - "import myproject.test\n" - "import django.settings\n" - "\n" - "# isort: imports-thirdparty\n" - "# isort: imports-firstparty\n" - "# isort:imports-stdlib\n" - "\n" - ) - expected_output = ( - "\n# isort: imports-thirdparty\n" - "import django.settings\n" - "\n" - "# isort: imports-firstparty\n" - "import myproject.test\n" - "\n" - "# isort:imports-stdlib\n" - "import os\n" - "import sys\n" - ) - test_output = isort.code(test_input, known_first_party=["myproject"]) - assert test_output == expected_output - test_output = isort.code(test_output, known_first_party=["myproject"]) - assert test_output == expected_output - - -def test_placement_control() -> None: - """Ensure that most specific placement control match wins""" - test_input = ( - "import os\n" - "import sys\n" - "from bottle import Bottle, redirect, response, run\n" - "import p24.imports._argparse as argparse\n" - "import p24.imports._subprocess as subprocess\n" - "import p24.imports._VERSION as VERSION\n" - "import p24.shared.media_wiki_syntax as syntax\n" - ) - test_output = isort.code( - code=test_input, - known_first_party=["p24", "p24.imports._VERSION"], - known_standard_library=["p24.imports", "os", "sys"], - known_third_party=["bottle"], - default_section="THIRDPARTY", - ) - - assert test_output == ( - "import os\n" - "import p24.imports._argparse as argparse\n" - "import p24.imports._subprocess as subprocess\n" - "import sys\n" - "\n" - "from bottle import Bottle, redirect, response, run\n" - "\n" - "import p24.imports._VERSION as VERSION\n" - "import p24.shared.media_wiki_syntax as syntax\n" - ) - - -def test_custom_sections() -> None: - """Ensure that most specific placement control match wins""" - test_input = ( - "import os\n" - "import sys\n" - "from django.conf import settings\n" - "from bottle import Bottle, redirect, response, run\n" - "import p24.imports._argparse as argparse\n" - "from django.db import models\n" - "import p24.imports._subprocess as subprocess\n" - "import pandas as pd\n" - "import p24.imports._VERSION as VERSION\n" - "import numpy as np\n" - "import p24.shared.media_wiki_syntax as syntax\n" - ) - test_output = isort.code( - code=test_input, - known_first_party=["p24", "p24.imports._VERSION"], - import_heading_stdlib="Standard Library", - import_heading_thirdparty="Third Party", - import_heading_firstparty="First Party", - import_heading_django="Django", - import_heading_pandas="Pandas", - known_standard_library=["p24.imports", "os", "sys"], - known_third_party=["bottle"], - known_django=["django"], - known_pandas=["pandas", "numpy"], - default_section="THIRDPARTY", - sections=[ - "FUTURE", - "STDLIB", - "DJANGO", - "THIRDPARTY", - "PANDAS", - "FIRSTPARTY", - "LOCALFOLDER", - ], - ) - assert test_output == ( - "# Standard Library\n" - "import os\n" - "import p24.imports._argparse as argparse\n" - "import p24.imports._subprocess as subprocess\n" - "import sys\n" - "\n" - "# Django\n" - "from django.conf import settings\n" - "from django.db import models\n" - "\n" - "# Third Party\n" - "from bottle import Bottle, redirect, response, run\n" - "\n" - "# Pandas\n" - "import numpy as np\n" - "import pandas as pd\n" - "\n" - "# First Party\n" - "import p24.imports._VERSION as VERSION\n" - "import p24.shared.media_wiki_syntax as syntax\n" - ) - - -def test_glob_known() -> None: - """Ensure that most specific placement control match wins""" - test_input = ( - "import os\n" - "from django_whatever import whatever\n" - "import sys\n" - "from django.conf import settings\n" - "from . import another\n" - ) - test_output = isort.code( - code=test_input, - import_heading_stdlib="Standard Library", - import_heading_thirdparty="Third Party", - import_heading_firstparty="First Party", - import_heading_django="Django", - import_heading_djangoplugins="Django Plugins", - import_heading_localfolder="Local", - known_django=["django"], - known_djangoplugins=["django_*"], - default_section="THIRDPARTY", - sections=[ - "FUTURE", - "STDLIB", - "DJANGO", - "DJANGOPLUGINS", - "THIRDPARTY", - "FIRSTPARTY", - "LOCALFOLDER", - ], - ) - assert test_output == ( - "# Standard Library\n" - "import os\n" - "import sys\n" - "\n" - "# Django\n" - "from django.conf import settings\n" - "\n" - "# Django Plugins\n" - "from django_whatever import whatever\n" - "\n" - "# Local\n" - "from . import another\n" - ) - - -def test_sticky_comments() -> None: - """Test to ensure it is possible to make comments 'stick' above imports""" - test_input = ( - "import os\n" - "\n" - "# Used for type-hinting (ref: https://github.com/davidhalter/jedi/issues/414).\n" - "from selenium.webdriver.remote.webdriver import WebDriver # noqa\n" - ) - assert isort.code(test_input) == test_input - - test_input = ( - "from django import forms\n" - "# While this couples the geographic forms to the GEOS library,\n" - "# it decouples from database (by not importing SpatialBackend).\n" - "from django.contrib.gis.geos import GEOSException, GEOSGeometry\n" - "from django.utils.translation import ugettext_lazy as _\n" - ) - assert isort.code(test_input) == test_input - - -def test_zipimport() -> None: - """Imports ending in "import" shouldn't be clobbered""" - test_input = "from zipimport import zipimport\n" - assert isort.code(test_input) == test_input - - -def test_from_ending() -> None: - """Imports ending in "from" shouldn't be clobbered.""" - test_input = "from foo import get_foo_from, get_foo\n" - expected_output = "from foo import get_foo, get_foo_from\n" - assert isort.code(test_input) == expected_output - - -def test_from_first() -> None: - """Tests the setting from_first works correctly""" - test_input = "from os import path\nimport os\n" - assert isort.code(test_input, from_first=True) == test_input - - -def test_top_comments() -> None: - """Ensure correct behavior with top comments""" - test_input = ( - "# -*- encoding: utf-8 -*-\n" - "# Test comment\n" - "#\n" - "from __future__ import unicode_literals\n" - ) - assert isort.code(test_input) == test_input - - test_input = ( - "# -*- coding: utf-8 -*-\n" - "from django.db import models\n" - "from django.utils.encoding import python_2_unicode_compatible\n" - ) - assert isort.code(test_input) == test_input - - test_input = "# Comment\nimport sys\n" - assert isort.code(test_input) == test_input - - test_input = "# -*- coding\nimport sys\n" - assert isort.code(test_input) == test_input - - -def test_consistency() -> None: - """Ensures consistency of handling even when dealing with non ordered-by-type imports""" - test_input = "from sqlalchemy.dialects.postgresql import ARRAY, array\n" - assert isort.code(test_input, order_by_type=True) == test_input - - -def test_force_grid_wrap() -> None: - """Ensures removing imports works as expected.""" - test_input = "from bar import lib2\nfrom foo import lib6, lib7\n" - test_output = isort.code( - code=test_input, force_grid_wrap=2, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT - ) - assert ( - test_output - == """from bar import lib2 -from foo import ( - lib6, - lib7 -) -""" - ) - test_output = isort.code( - code=test_input, force_grid_wrap=3, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT - ) - assert test_output == test_input - - -def test_force_grid_wrap_long() -> None: - """Ensure that force grid wrap still happens with long line length""" - test_input = ( - "from foo import lib6, lib7\n" - "from bar import lib2\n" - "from babar import something_that_is_kind_of_long" - ) - test_output = isort.code( - code=test_input, - force_grid_wrap=2, - multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, - line_length=9999, - ) - assert ( - test_output - == """from babar import something_that_is_kind_of_long -from bar import lib2 -from foo import ( - lib6, - lib7 -) -""" - ) - - -def test_uses_jinja_variables() -> None: - """Test a basic set of imports that use jinja variables""" - test_input = ( - "import sys\n" "import os\n" "import myproject.{ test }\n" "import django.{ settings }" - ) - test_output = isort.code( - code=test_input, known_third_party=["django"], known_first_party=["myproject"] - ) - assert test_output == ( - "import os\n" - "import sys\n" - "\n" - "import django.{ settings }\n" - "\n" - "import myproject.{ test }\n" - ) - - test_input = "import {{ cookiecutter.repo_name }}\n" "from foo import {{ cookiecutter.bar }}\n" - assert isort.code(test_input) == test_input - - -def test_fcntl() -> None: - """Test to ensure fcntl gets correctly recognized as stdlib import""" - test_input = "import fcntl\nimport os\nimport sys\n" - assert isort.code(test_input) == test_input - - -def test_import_split_is_word_boundary_aware() -> None: - """Test to ensure that isort splits words in a boundary aware manner""" - test_input = ( - "from mycompany.model.size_value_array_import_func import \\\n" - " get_size_value_array_import_func_jobs" - ) - test_output = isort.code( - code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=79 - ) - assert test_output == ( - "from mycompany.model.size_value_array_import_func import (\n" - " get_size_value_array_import_func_jobs\n" - ")\n" - ) - - -def test_other_file_encodings(tmpdir) -> None: - """Test to ensure file encoding is respected""" - for encoding in ("latin1", "utf8"): - tmp_fname = tmpdir.join(f"test_{encoding}.py") - file_contents = f"# coding: {encoding}\n\ns = u'ã'\n" - tmp_fname.write_binary(file_contents.encode(encoding)) - api.sort_file(Path(tmp_fname), file_path=Path(tmp_fname), settings_path=os.getcwd()) - assert tmp_fname.read_text(encoding) == file_contents - - -def test_encoding_not_in_comment(tmpdir) -> None: - """Test that 'encoding' not in a comment is ignored""" - tmp_fname = tmpdir.join("test_encoding.py") - file_contents = "class Foo\n coding: latin1\n\ns = u'ã'\n" - tmp_fname.write_binary(file_contents.encode("utf8")) - assert ( - isort.code( - Path(tmp_fname).read_text("utf8"), file_path=Path(tmp_fname), settings_path=os.getcwd() - ) - == file_contents - ) - - -def test_encoding_not_in_first_two_lines(tmpdir) -> None: - """Test that 'encoding' not in the first two lines is ignored""" - tmp_fname = tmpdir.join("test_encoding.py") - file_contents = "\n\n# -*- coding: latin1\n\ns = u'ã'\n" - tmp_fname.write_binary(file_contents.encode("utf8")) - assert ( - isort.code( - Path(tmp_fname).read_text("utf8"), file_path=Path(tmp_fname), settings_path=os.getcwd() - ) - == file_contents - ) - - -def test_comment_at_top_of_file() -> None: - """Test to ensure isort correctly handles top of file comments""" - test_input = ( - "# Comment one\n" - "from django import forms\n" - "# Comment two\n" - "from django.contrib.gis.geos import GEOSException\n" - ) - assert isort.code(test_input) == test_input - - test_input = "# -*- coding: utf-8 -*-\nfrom django.db import models\n" - assert isort.code(test_input) == test_input - - -def test_alphabetic_sorting() -> None: - """Test to ensure isort correctly handles single line imports""" - test_input = ( - "import unittest\n" - "\n" - "import ABC\n" - "import Zope\n" - "from django.contrib.gis.geos import GEOSException\n" - "from plone.app.testing import getRoles\n" - "from plone.app.testing import ManageRoles\n" - "from plone.app.testing import setRoles\n" - "from Products.CMFPlone import utils\n" - ) - options = { - "force_single_line": True, - "force_alphabetical_sort_within_sections": True, - } # type: Dict[str, Any] - - output = isort.code(test_input, **options) - assert output == test_input - - test_input = "# -*- coding: utf-8 -*-\nfrom django.db import models\n" - assert isort.code(test_input) == test_input - - -def test_alphabetic_sorting_multi_line() -> None: - """Test to ensure isort correctly handles multiline import see: issue 364""" - test_input = ( - "from a import (CONSTANT_A, cONSTANT_B, CONSTANT_C, CONSTANT_D, CONSTANT_E,\n" - " CONSTANT_F, CONSTANT_G, CONSTANT_H, CONSTANT_I, CONSTANT_J)\n" - ) - options = {"force_alphabetical_sort_within_sections": True} # type: Dict[str, Any] - assert isort.code(test_input, **options) == test_input - - -def test_comments_not_duplicated() -> None: - """Test to ensure comments aren't duplicated: issue 303""" - test_input = ( - "from flask import url_for\n" - "# Whole line comment\n" - "from service import demo # inline comment\n" - "from service import settings\n" - ) - output = isort.code(test_input) - assert output.count("# Whole line comment\n") == 1 - assert output.count("# inline comment\n") == 1 - - -def test_top_of_line_comments() -> None: - """Test to ensure top of line comments stay where they should: issue 260""" - test_input = ( - "# -*- coding: utf-8 -*-\n" - "from django.db import models\n" - "#import json as simplejson\n" - "from myproject.models import Servidor\n" - "\n" - "import reversion\n" - "\n" - "import logging\n" - ) - output = isort.code(test_input) - print(output) - assert output.startswith("# -*- coding: utf-8 -*-\n") - - -def test_basic_comment() -> None: - """Test to ensure a basic comment wont crash isort""" - test_input = "import logging\n# Foo\nimport os\n" - assert isort.code(test_input) == test_input - - -def test_shouldnt_add_lines() -> None: - """Ensure that isort doesn't add a blank line when a top of import comment is present, - See: issue #316 - """ - test_input = '"""Text"""\n' "# This is a comment\nimport pkg_resources\n" - assert isort.code(test_input) == test_input - - -def test_sections_parsed_correct(tmpdir) -> None: - """Ensure that modules for custom sections parsed as list from config file and - isort result is correct - """ - conf_file_data = ( - "[settings]\n" - "sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER,COMMON\n" - "known_common=nose\n" - "import_heading_common=Common Library\n" - "import_heading_stdlib=Standard Library\n" - ) - test_input = "import os\nfrom nose import *\nimport nose\nfrom os import path" - correct_output = ( - "# Standard Library\n" - "import os\n" - "from os import path\n" - "\n" - "# Common Library\n" - "import nose\n" - "from nose import *\n" - ) - tmpdir.join(".isort.cfg").write(conf_file_data) - assert isort.code(test_input, settings_path=str(tmpdir)) == correct_output - - -@pytest.mark.skipif(toml is None, reason="Requires toml package to be installed.") -def test_pyproject_conf_file(tmpdir) -> None: - """Ensure that modules for custom sections parsed as list from config file and - isort result is correct - """ - conf_file_data = ( - "[build-system]\n" - 'requires = ["setuptools", "wheel"]\n' - "[tool.poetry]\n" - 'name = "isort"\n' - 'version = "0.1.0"\n' - 'license = "MIT"\n' - "[tool.isort]\n" - "lines_between_types=1\n" - 'known_common="nose"\n' - 'known_first_party="foo"\n' - 'import_heading_common="Common Library"\n' - 'import_heading_stdlib="Standard Library"\n' - 'sections="FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER,COMMON"\n' - "include_trailing_comma = true\n" - ) - test_input = "import os\nfrom nose import *\nimport nose\nfrom os import path\nimport foo" - correct_output = ( - "# Standard Library\n" - "import os\n" - "\n" - "from os import path\n" - "\n" - "import foo\n" - "\n" - "# Common Library\n" - "import nose\n" - "\n" - "from nose import *\n" - ) - tmpdir.join("pyproject.toml").write(conf_file_data) - assert isort.code(test_input, settings_path=str(tmpdir)) == correct_output - - -def test_alphabetic_sorting_no_newlines() -> None: - """Test to ensure that alphabetical sort does not - erroneously introduce new lines (issue #328) - """ - test_input = "import os\n" - test_output = isort.code(code=test_input, force_alphabetical_sort_within_sections=True) - assert test_input == test_output - - test_input = "import os\n" "import unittest\n" "\n" "from a import b\n" "\n" "\n" "print(1)\n" - test_output = isort.code( - code=test_input, force_alphabetical_sort_within_sections=True, lines_after_imports=2 - ) - assert test_input == test_output - - -def test_sort_within_section() -> None: - """Test to ensure its possible to force isort to sort within sections""" - test_input = ( - "from Foob import ar\n" - "import foo\n" - "from foo import bar\n" - "from foo.bar import Quux, baz\n" - ) - test_output = isort.code(test_input, force_sort_within_sections=True) - assert test_output == test_input - - test_input = ( - "import foo\n" - "from foo import bar\n" - "from foo.bar import baz\n" - "from foo.bar import Quux\n" - "from Foob import ar\n" - ) - test_output = isort.code( - code=test_input, - force_sort_within_sections=True, - order_by_type=False, - force_single_line=True, - ) - assert test_output == test_input - - -def test_sorting_with_two_top_comments() -> None: - """Test to ensure isort will sort files that contain 2 top comments""" - test_input = "#! comment1\n''' comment2\n'''\nimport b\nimport a\n" - assert isort.code(test_input) == ("#! comment1\n''' comment2\n'''\nimport a\nimport b\n") - - -def test_lines_between_sections() -> None: - """Test to ensure lines_between_sections works""" - test_input = "from bar import baz\nimport os\n" - assert isort.code(test_input, lines_between_sections=0) == ("import os\nfrom bar import baz\n") - assert isort.code(test_input, lines_between_sections=2) == ( - "import os\n\n\nfrom bar import baz\n" - ) - - -def test_forced_sepatate_globs() -> None: - """Test to ensure that forced_separate glob matches lines""" - test_input = ( - "import os\n" - "\n" - "from myproject.foo.models import Foo\n" - "\n" - "from myproject.utils import util_method\n" - "\n" - "from myproject.bar.models import Bar\n" - "\n" - "import sys\n" - ) - test_output = isort.code(code=test_input, forced_separate=["*.models"], line_length=120) - - assert test_output == ( - "import os\n" - "import sys\n" - "\n" - "from myproject.utils import util_method\n" - "\n" - "from myproject.bar.models import Bar\n" - "from myproject.foo.models import Foo\n" - ) - - -def test_no_additional_lines_issue_358() -> None: - """Test to ensure issue 358 is resolved and running isort multiple times - does not add extra newlines - """ - test_input = ( - '"""This is a docstring"""\n' - "# This is a comment\n" - "from __future__ import (\n" - " absolute_import,\n" - " division,\n" - " print_function,\n" - " unicode_literals\n" - ")\n" - ) - expected_output = ( - '"""This is a docstring"""\n' - "# This is a comment\n" - "from __future__ import (\n" - " absolute_import,\n" - " division,\n" - " print_function,\n" - " unicode_literals\n" - ")\n" - ) - test_output = isort.code( - code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 - ) - assert test_output == expected_output - - test_output = isort.code( - code=test_output, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 - ) - assert test_output == expected_output - - for _attempt in range(5): - test_output = isort.code( - code=test_output, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 - ) - assert test_output == expected_output - - test_input = ( - '"""This is a docstring"""\n' - "\n" - "# This is a comment\n" - "from __future__ import (\n" - " absolute_import,\n" - " division,\n" - " print_function,\n" - " unicode_literals\n" - ")\n" - ) - expected_output = ( - '"""This is a docstring"""\n' - "\n" - "# This is a comment\n" - "from __future__ import (\n" - " absolute_import,\n" - " division,\n" - " print_function,\n" - " unicode_literals\n" - ")\n" - ) - test_output = isort.code( - code=test_input, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 - ) - assert test_output == expected_output - - test_output = isort.code( - code=test_output, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 - ) - assert test_output == expected_output - - for _attempt in range(5): - test_output = isort.code( - code=test_output, multi_line_output=WrapModes.VERTICAL_HANGING_INDENT, line_length=20 - ) - assert test_output == expected_output - - -def test_import_by_paren_issue_375() -> None: - """Test to ensure isort can correctly handle sorting imports where the - paren is directly by the import body - """ - test_input = "from .models import(\n Foo,\n Bar,\n)\n" - assert isort.code(test_input) == "from .models import Bar, Foo\n" - - -def test_import_by_paren_issue_460() -> None: - """Test to ensure isort can doesnt move comments around """ - test_input = """ -# First comment -# Second comment -# third comment -import io -import os -""" - assert isort.code((test_input)) == test_input - - -def test_function_with_docstring() -> None: - """Test to ensure isort can correctly sort imports when the first found content is a - function with a docstring - """ - add_imports = ["from __future__ import unicode_literals"] - test_input = "def foo():\n" ' """ Single line triple quoted doctring """\n' " pass\n" - expected_output = ( - "from __future__ import unicode_literals\n" - "\n" - "\n" - "def foo():\n" - ' """ Single line triple quoted doctring """\n' - " pass\n" - ) - assert isort.code(test_input, add_imports=add_imports) == expected_output - - -def test_plone_style() -> None: - """Test to ensure isort correctly plone style imports""" - test_input = ( - "from django.contrib.gis.geos import GEOSException\n" - "from plone.app.testing import getRoles\n" - "from plone.app.testing import ManageRoles\n" - "from plone.app.testing import setRoles\n" - "from Products.CMFPlone import utils\n" - "\n" - "import ABC\n" - "import unittest\n" - "import Zope\n" - ) - options = {"force_single_line": True, "force_alphabetical_sort": True} # type: Dict[str, Any] - assert isort.code(test_input, **options) == test_input - - -def test_third_party_case_sensitive() -> None: - """Modules which match builtins by name but not on case should not be picked up on Windows.""" - test_input = "import thirdparty\nimport os\nimport ABC\n" - - expected_output = "import os\n\nimport ABC\nimport thirdparty\n" - assert isort.code(test_input) == expected_output - - -def test_exists_case_sensitive_file(tmpdir) -> None: - """Test exists_case_sensitive function for a file.""" - tmpdir.join("module.py").ensure(file=1) - assert exists_case_sensitive(str(tmpdir.join("module.py"))) - assert not exists_case_sensitive(str(tmpdir.join("MODULE.py"))) - - -def test_exists_case_sensitive_directory(tmpdir) -> None: - """Test exists_case_sensitive function for a directory.""" - tmpdir.join("pkg").ensure(dir=1) - assert exists_case_sensitive(str(tmpdir.join("pkg"))) - assert not exists_case_sensitive(str(tmpdir.join("PKG"))) - - -def test_sys_path_mutation(tmpdir) -> None: - """Test to ensure sys.path is not modified""" - tmpdir.mkdir("src").mkdir("a") - test_input = "from myproject import test" - options = {"virtual_env": str(tmpdir)} # type: Dict[str, Any] - expected_length = len(sys.path) - isort.code(test_input, **options) - assert len(sys.path) == expected_length - isort.code(test_input, old_finders=True, **options) - - -def test_long_single_line() -> None: - """Test to ensure long single lines get handled correctly""" - output = isort.code( - code="from ..views import (" - " _a," - "_xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx as xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx)", - line_length=79, - ) - for line in output.split("\n"): - assert len(line) <= 79 - - output = isort.code( - code="from ..views import (" - " _a," - "_xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx as xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx)", - line_length=79, - combine_as_imports=True, - ) - for line in output.split("\n"): - assert len(line) <= 79 - - -def test_import_inside_class_issue_432() -> None: - """Test to ensure issue 432 is resolved and isort - doesn't insert imports in the middle of classes - """ - test_input = "# coding=utf-8\nclass Foo:\n def bar(self):\n pass\n" - expected_output = ( - "# coding=utf-8\n" - "import baz\n" - "\n" - "\n" - "class Foo:\n" - " def bar(self):\n" - " pass\n" - ) - assert isort.code(test_input, add_imports=["import baz"]) == expected_output - - -def test_wildcard_import_without_space_issue_496() -> None: - """Test to ensure issue #496: wildcard without space, is resolved""" - test_input = "from findorserver.coupon.models import*" - expected_output = "from findorserver.coupon.models import *\n" - assert isort.code(test_input) == expected_output - - -def test_import_line_mangles_issues_491() -> None: - """Test to ensure comment on import with parens doesn't cause issues""" - test_input = "import os # ([\n\n" 'print("hi")\n' - assert isort.code(test_input) == test_input - - -def test_import_line_mangles_issues_505() -> None: - """Test to ensure comment on import with parens doesn't cause issues""" - test_input = "from sys import * # (\n\n\ndef test():\n" ' print("Test print")\n' - assert isort.code(test_input) == test_input - - -def test_import_line_mangles_issues_439() -> None: - """Test to ensure comment on import with parens doesn't cause issues""" - test_input = "import a # () import\nfrom b import b\n" - assert isort.code(test_input) == test_input - - -def test_alias_using_paren_issue_466() -> None: - """Test to ensure issue #466: Alias causes slash incorrectly is resolved""" - test_input = ( - "from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper\n" - ) - expected_output = ( - "from django.db.backends.mysql.base import (\n" - " DatabaseWrapper as MySQLDatabaseWrapper)\n" - ) - assert isort.code(test_input, line_length=50, use_parentheses=True) == expected_output - - test_input = ( - "from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper\n" - ) - expected_output = ( - "from django.db.backends.mysql.base import (\n" - " DatabaseWrapper as MySQLDatabaseWrapper\n" - ")\n" - ) - assert ( - isort.code( - code=test_input, - line_length=50, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - use_parentheses=True, - ) - == expected_output - ) - - -def test_long_alias_using_paren_issue_957() -> None: - test_input = ( - "from package import module as very_very_very_very_very_very_very" - "_very_very_very_long_alias\n" - ) - expected_output = ( - "from package import (\n" - " module as very_very_very_very_very_very_very_very_very_very_long_alias\n" - ")\n" - ) - out = isort.code( - code=test_input, - line_length=50, - use_parentheses=True, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - ) - assert out == expected_output - - test_input = ( - "from deep.deep.deep.deep.deep.deep.deep.deep.deep.package import module as " - "very_very_very_very_very_very_very_very_very_very_long_alias\n" - ) - expected_output = ( - "from deep.deep.deep.deep.deep.deep.deep.deep.deep.package import (\n" - " module as very_very_very_very_very_very_very_very_very_very_long_alias\n" - ")\n" - ) - out = isort.code( - code=test_input, - line_length=50, - use_parentheses=True, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - ) - assert out == expected_output - - test_input = ( - "from deep.deep.deep.deep.deep.deep.deep.deep.deep.package " - "import very_very_very_very_very_very_very_very_very_very_long_module as very_very_very_" - "very_very_very_very_very_very_very_long_alias\n" - ) - expected_output = ( - "from deep.deep.deep.deep.deep.deep.deep.deep.deep.package import (\n" - " very_very_very_very_very_very_very_very_very_very_long_module as very_very_very_very" - "_very_very_very_very_very_very_long_alias\n" - ")\n" - ) - out = isort.code( - code=test_input, - line_length=50, - use_parentheses=True, - multi_line_output=WrapModes.VERTICAL_GRID_GROUPED, - ) - assert out == expected_output - - -def test_strict_whitespace_by_default(capsys) -> None: - test_input = "import os\nfrom django.conf import settings\n" - assert not api.check_code_string(test_input) - out, _ = capsys.readouterr() - assert "ERROR" in out - assert out.endswith("Imports are incorrectly sorted and/or formatted.\n") - - -def test_strict_whitespace_no_closing_newline_issue_676(capsys) -> None: - test_input = "import os\n\nfrom django.conf import settings\n\nprint(1)" - assert api.check_code_string(test_input) - out, _ = capsys.readouterr() - assert out == "" - - -def test_ignore_whitespace(capsys) -> None: - test_input = "import os\nfrom django.conf import settings\n" - assert api.check_code_string(test_input, ignore_whitespace=True) - out, _ = capsys.readouterr() - assert out == "" - - -def test_import_wraps_with_comment_issue_471() -> None: - """Test to ensure issue #471 is resolved""" - test_input = ( - "from very_long_module_name import SuperLongClassName #@UnusedImport" - " -- long string of comments which wrap over" - ) - expected_output = ( - "from very_long_module_name import (\n" - " SuperLongClassName) # @UnusedImport -- long string of comments which wrap over\n" - ) - assert ( - isort.code(code=test_input, line_length=50, multi_line_output=1, use_parentheses=True) - == expected_output - ) - - -def test_import_case_produces_inconsistent_results_issue_472() -> None: - """Test to ensure sorting imports with same name but different case produces - the same result across platforms - """ - test_input = ( - "from sqlalchemy.dialects.postgresql import ARRAY\n" - "from sqlalchemy.dialects.postgresql import array\n" - ) - assert isort.code(test_input, force_single_line=True) == test_input - - test_input = ( - "from scrapy.core.downloader.handlers.http import " - "HttpDownloadHandler, HTTPDownloadHandler\n" - ) - assert isort.code(test_input, line_length=100) == test_input - - -def test_inconsistent_behavior_in_python_2_and_3_issue_479() -> None: - """Test to ensure Python 2 and 3 have the same behavior""" - test_input = ( - "from workalendar.europe import UnitedKingdom\n" - "\n" - "from future.standard_library import hooks\n" - ) - assert isort.code(test_input, known_first_party=["future"]) == test_input - - -def test_sort_within_section_comments_issue_436() -> None: - """Test to ensure sort within sections leaves comments untouched""" - test_input = ( - "import os.path\n" - "import re\n" - "\n" - "# report.py exists in ... comment line 1\n" - "# this file needs to ... comment line 2\n" - "# it must not be ... comment line 3\n" - "import report\n" - ) - assert isort.code(test_input, force_sort_within_sections=True) == test_input - - -def test_sort_within_sections_with_force_to_top_issue_473() -> None: - """Test to ensure it's possible to sort within sections with items forced to top""" - test_input = "import z\nimport foo\nfrom foo import bar\n" - assert ( - isort.code(code=test_input, force_sort_within_sections=True, force_to_top=["z"]) - == test_input - ) - - -def test_correct_number_of_new_lines_with_comment_issue_435() -> None: - """Test to ensure that injecting a comment in-between imports - doesn't mess up the new line spacing - """ - test_input = "import foo\n\n# comment\n\n\ndef baz():\n pass\n" - assert isort.code(test_input) == test_input - - -def test_future_below_encoding_issue_545() -> None: - """Test to ensure future is always below comment""" - test_input = ( - "#!/usr/bin/env python\n" - "from __future__ import print_function\n" - "import logging\n" - "\n" - 'print("hello")\n' - ) - expected_output = ( - "#!/usr/bin/env python\n" - "from __future__ import print_function\n" - "\n" - "import logging\n" - "\n" - 'print("hello")\n' - ) - assert isort.code(test_input) == expected_output - - -def test_no_extra_lines_issue_557() -> None: - """Test to ensure no extra lines are prepended""" - test_input = ( - "import os\n" - "\n" - "from scrapy.core.downloader.handlers.http import " - "HttpDownloadHandler, HTTPDownloadHandler\n" - ) - expected_output = ( - "import os\n" - "from scrapy.core.downloader.handlers.http import HttpDownloadHandler, " - "HTTPDownloadHandler\n" - ) - assert ( - isort.code( - code=test_input, - force_alphabetical_sort=True, - force_sort_within_sections=True, - line_length=100, - ) - == expected_output - ) - - -def test_long_import_wrap_support_with_mode_2() -> None: - """Test to ensure mode 2 still allows wrapped imports with slash""" - test_input = ( - "from foobar.foobar.foobar.foobar import \\\n" - " an_even_longer_function_name_over_80_characters\n" - ) - assert ( - isort.code(code=test_input, multi_line_output=WrapModes.HANGING_INDENT, line_length=80) - == test_input - ) - - -def test_pylint_comments_incorrectly_wrapped_issue_571() -> None: - """Test to ensure pylint comments don't get wrapped""" - test_input = ( - "from PyQt5.QtCore import QRegExp # @UnresolvedImport pylint: disable=import-error," - "useless-suppression\n" - ) - expected_output = ( - "from PyQt5.QtCore import \\\n" - " QRegExp # @UnresolvedImport pylint: disable=import-error,useless-suppression\n" - ) - assert isort.code(test_input, line_length=60) == expected_output - - -def test_ensure_async_methods_work_issue_537() -> None: - """Test to ensure async methods are correctly identified""" - test_input = ( - "from myapp import myfunction\n" - "\n" - "\n" - "async def test_myfunction(test_client, app):\n" - " a = await myfunction(test_client, app)\n" - ) - assert isort.code(test_input) == test_input - - -def test_ensure_as_imports_sort_correctly_within_from_imports_issue_590() -> None: - """Test to ensure combination from and as import statements are sorted correct""" - test_input = "from os import defpath\nfrom os import pathsep as separator\n" - assert isort.code(test_input, force_sort_within_sections=True) == test_input - - test_input = "from os import defpath\nfrom os import pathsep as separator\n" - assert isort.code(test_input) == test_input - - test_input = "from os import defpath\nfrom os import pathsep as separator\n" - assert isort.code(test_input, force_single_line=True) == test_input - - -def test_ensure_line_endings_are_preserved_issue_493() -> None: - """Test to ensure line endings are not converted""" - test_input = "from os import defpath\r\nfrom os import pathsep as separator\r\n" - assert isort.code(test_input) == test_input - test_input = "from os import defpath\rfrom os import pathsep as separator\r" - assert isort.code(test_input) == test_input - test_input = "from os import defpath\nfrom os import pathsep as separator\n" - assert isort.code(test_input) == test_input - - -def test_not_splitted_sections() -> None: - whiteline = "\n" - stdlib_section = "import unittest\n" - firstparty_section = "from app.pkg1 import mdl1\n" - local_section = "from .pkg2 import mdl2\n" - statement = "foo = bar\n" - test_input = ( - stdlib_section - + whiteline - + firstparty_section - + whiteline - + local_section - + whiteline - + statement - ) - - assert isort.code(test_input, known_first_party=["app"]) == test_input - assert isort.code(test_input, no_lines_before=["LOCALFOLDER"], known_first_party=["app"]) == ( - stdlib_section + whiteline + firstparty_section + local_section + whiteline + statement - ) - # by default STDLIB and FIRSTPARTY sections are split by THIRDPARTY section, - # so don't merge them if THIRDPARTY imports aren't exist - assert ( - isort.code(test_input, no_lines_before=["FIRSTPARTY"], known_first_party=["app"]) - == test_input - ) - # in case when THIRDPARTY section is excluded from sections list, - # it's ok to merge STDLIB and FIRSTPARTY - assert isort.code( - code=test_input, - sections=["STDLIB", "FIRSTPARTY", "LOCALFOLDER"], - no_lines_before=["FIRSTPARTY"], - known_first_party=["app"], - ) == (stdlib_section + firstparty_section + whiteline + local_section + whiteline + statement) - # it doesn't change output, because stdlib packages don't have any whitelines before them - assert ( - isort.code(test_input, no_lines_before=["STDLIB"], known_first_party=["app"]) == test_input - ) - - -def test_no_lines_before_empty_section() -> None: - test_input = "import first\nimport custom\n" - assert ( - isort.code( - code=test_input, - known_third_party=["first"], - known_custom=["custom"], - sections=["THIRDPARTY", "LOCALFOLDER", "CUSTOM"], - no_lines_before=["THIRDPARTY", "LOCALFOLDER", "CUSTOM"], - ) - == test_input - ) - - -def test_no_inline_sort() -> None: - """Test to ensure multiple `from` imports in one line are not sorted if `--no-inline-sort` flag - is enabled. - If `--force-single-line-imports` flag is enabled, then `--no-inline-sort` is ignored. - """ - test_input = "from foo import a, c, b\n" - assert isort.code(test_input, no_inline_sort=True, force_single_line=False) == test_input - assert ( - isort.code(test_input, no_inline_sort=False, force_single_line=False) - == "from foo import a, b, c\n" - ) - expected = "from foo import a\nfrom foo import b\nfrom foo import c\n" - assert isort.code(test_input, no_inline_sort=False, force_single_line=True) == expected - assert isort.code(test_input, no_inline_sort=True, force_single_line=True) == expected - - -def test_relative_import_of_a_module() -> None: - """Imports can be dynamically created (PEP302) and is used by modules such as six. - This test ensures that these types of imports are still sorted to the correct type - instead of being categorized as local. - """ - test_input = ( - "from __future__ import absolute_import\n" - "\n" - "import itertools\n" - "\n" - "from six import add_metaclass\n" - "\n" - "from six.moves import asd\n" - ) - - expected_results = ( - "from __future__ import absolute_import\n" - "\n" - "import itertools\n" - "\n" - "from six import add_metaclass\n" - "from six.moves import asd\n" - ) - - sorted_result = isort.code(test_input, force_single_line=True) - assert sorted_result == expected_results - - -def test_escaped_parens_sort() -> None: - test_input = "from foo import \\ \n(a,\nb,\nc)\n" - expected = "from foo import a, b, c\n" - assert isort.code(test_input) == expected - - -def test_escaped_parens_sort_with_comment() -> None: - test_input = "from foo import \\ \n(a,\nb,# comment\nc)\n" - expected = "from foo import b # comment\nfrom foo import a, c\n" - assert isort.code(test_input) == expected - - -def test_escaped_parens_sort_with_first_comment() -> None: - test_input = "from foo import \\ \n(a,# comment\nb,\nc)\n" - expected = "from foo import a # comment\nfrom foo import b, c\n" - assert isort.code(test_input) == expected - - -def test_escaped_no_parens_sort_with_first_comment() -> None: - test_input = "from foo import a, \\\nb, \\\nc # comment\n" - expected = "from foo import c # comment\nfrom foo import a, b\n" - assert isort.code(test_input) == expected - - -@pytest.mark.skip(reason="TODO: Duplicates currently not handled.") -def test_to_ensure_imports_are_brought_to_top_issue_651() -> None: - test_input = ( - "from __future__ import absolute_import, unicode_literals\n" - "\n" - 'VAR = """\n' - "multiline text\n" - '"""\n' - "\n" - "from __future__ import unicode_literals\n" - "from __future__ import absolute_import\n" - ) - expected_output = ( - "from __future__ import absolute_import, unicode_literals\n" - "\n" - 'VAR = """\n' - "multiline text\n" - '"""\n' - ) - assert isort.code(test_input) == expected_output - - -def test_to_ensure_importing_from_imports_module_works_issue_662() -> None: - test_input = ( - "@wraps(fun)\n" - "def __inner(*args, **kwargs):\n" - " from .imports import qualname\n" - "\n" - " warn(description=description or qualname(fun), deprecation=deprecation, " - "removal=removal)\n" - ) - assert isort.code(test_input) == test_input - - -def test_to_ensure_no_unexpected_changes_issue_666() -> None: - test_input = ( - "from django.conf import settings\n" - "from django.core.management import call_command\n" - "from django.core.management.base import BaseCommand\n" - "from django.utils.translation import ugettext_lazy as _\n" - "\n" - 'TEMPLATE = """\n' - "# This file is generated automatically with the management command\n" - "#\n" - "# manage.py bis_compile_i18n\n" - "#\n" - "# please dont change it manually.\n" - "from django.utils.translation import ugettext_lazy as _\n" - '"""\n' - ) - assert isort.code(test_input) == test_input - - -def test_to_ensure_tabs_dont_become_space_issue_665() -> None: - test_input = "import os\n\n\ndef my_method():\n\tpass\n" - assert isort.code(test_input) == test_input - - -def test_new_lines_are_preserved() -> None: - with NamedTemporaryFile("w", suffix="py", delete=False) as rn_newline: - pass - - try: - with open(rn_newline.name, mode="w", newline="") as rn_newline_input: - rn_newline_input.write("import sys\r\nimport os\r\n") - - api.sort_file(rn_newline.name, settings_path=os.getcwd()) - with open(rn_newline.name) as new_line_file: - print(new_line_file.read()) - with open(rn_newline.name, newline="") as rn_newline_file: - rn_newline_contents = rn_newline_file.read() - assert rn_newline_contents == "import os\r\nimport sys\r\n" - finally: - os.remove(rn_newline.name) - - with NamedTemporaryFile("w", suffix="py", delete=False) as r_newline: - pass - - try: - with open(r_newline.name, mode="w", newline="") as r_newline_input: - r_newline_input.write("import sys\rimport os\r") - - api.sort_file(r_newline.name, settings_path=os.getcwd()) - with open(r_newline.name, newline="") as r_newline_file: - r_newline_contents = r_newline_file.read() - assert r_newline_contents == "import os\rimport sys\r" - finally: - os.remove(r_newline.name) - - with NamedTemporaryFile("w", suffix="py", delete=False) as n_newline: - pass - - try: - with open(n_newline.name, mode="w", newline="") as n_newline_input: - n_newline_input.write("import sys\nimport os\n") - - api.sort_file(n_newline.name, settings_path=os.getcwd()) - with open(n_newline.name, newline="") as n_newline_file: - n_newline_contents = n_newline_file.read() - assert n_newline_contents == "import os\nimport sys\n" - finally: - os.remove(n_newline.name) - - -def test_forced_separate_is_deterministic_issue_774(tmpdir) -> None: - - config_file = tmpdir.join("setup.cfg") - config_file.write( - "[isort]\n" - "forced_separate:\n" - " separate1\n" - " separate2\n" - " separate3\n" - " separate4\n" - ) - - test_input = ( - "import time\n" - "\n" - "from separate1 import foo\n" - "\n" - "from separate2 import bar\n" - "\n" - "from separate3 import baz\n" - "\n" - "from separate4 import quux\n" - ) - - assert isort.code(test_input, settings_file=config_file.strpath) == test_input - - -def test_monkey_patched_urllib() -> None: - with pytest.raises(ImportError): - # Previous versions of isort monkey patched urllib which caused unusual - # importing for other projects. - from urllib import quote # type: ignore # noqa: F401 - - -def test_argument_parsing() -> None: - from isort.main import parse_args - - args = parse_args(["--dt", "-t", "foo", "--skip=bar", "baz.py"]) - assert args["order_by_type"] is False - assert args["force_to_top"] == ["foo"] - assert args["skip"] == ["bar"] - assert args["files"] == ["baz.py"] - - -@pytest.mark.parametrize("multiprocess", (False, True)) -def test_command_line(tmpdir, capfd, multiprocess: bool) -> None: - from isort.main import main - - tmpdir.join("file1.py").write("import re\nimport os\n\nimport contextlib\n\n\nimport isort") - tmpdir.join("file2.py").write( - ("import collections\nimport time\n\nimport abc" "\n\n\nimport isort") - ) - arguments = [str(tmpdir), "--settings-path", os.getcwd()] - if multiprocess: - arguments.extend(["--jobs", "2"]) - main(arguments) - assert ( - tmpdir.join("file1.py").read() - == "import contextlib\nimport os\nimport re\n\nimport isort\n" - ) - assert ( - tmpdir.join("file2.py").read() - == "import abc\nimport collections\nimport time\n\nimport isort\n" - ) - if not (sys.platform.startswith("win") or sys.platform.startswith("darwin")): - out, err = capfd.readouterr() - assert not [error for error in err.split("\n") if error and "warning:" not in error] - # it informs us about fixing the files: - assert str(tmpdir.join("file1.py")) in out - assert str(tmpdir.join("file2.py")) in out - - -@pytest.mark.parametrize("quiet", (False, True)) -def test_quiet(tmpdir, capfd, quiet: bool) -> None: - if sys.platform.startswith("win"): - return - from isort.main import main - - tmpdir.join("file1.py").write("import re\nimport os") - tmpdir.join("file2.py").write("") - arguments = [str(tmpdir)] - if quiet: - arguments.append("-q") - main(arguments) - out, err = capfd.readouterr() - assert not err - assert bool(out) != quiet - - -@pytest.mark.parametrize("enabled", (False, True)) -def test_safety_skips(tmpdir, enabled: bool) -> None: - tmpdir.join("victim.py").write("# ...") - toxdir = tmpdir.mkdir(".tox") - toxdir.join("verysafe.py").write("# ...") - tmpdir.mkdir("_build").mkdir("python3.7").join("importantsystemlibrary.py").write("# ...") - tmpdir.mkdir(".pants.d").join("pants.py").write("import os") - if enabled: - config = Config(directory=str(tmpdir)) - else: - config = Config(skip=[], directory=str(tmpdir)) - skipped = [] # type: List[str] - codes = [str(tmpdir)] - main.iter_source_code(codes, config, skipped) - - # if enabled files within nested unsafe directories should be skipped - file_names = { - os.path.relpath(f, str(tmpdir)) - for f in main.iter_source_code([str(tmpdir)], config, skipped) - } - if enabled: - assert file_names == {"victim.py"} - assert len(skipped) == 3 - else: - assert file_names == { - os.sep.join((".tox", "verysafe.py")), - os.sep.join(("_build", "python3.7", "importantsystemlibrary.py")), - os.sep.join((".pants.d", "pants.py")), - "victim.py", - } - assert not skipped - - # directly pointing to files within unsafe directories shouldn't skip them either way - file_names = { - os.path.relpath(f, str(toxdir)) - for f in main.iter_source_code([str(toxdir)], Config(directory=str(toxdir)), skipped) - } - assert file_names == {"verysafe.py"} - - -@pytest.mark.parametrize( - "skip_glob_assert", - ( - ([], 0, {os.sep.join(("code", "file.py"))}), - (["**/*.py"], 1, set()), - (["*/code/*.py"], 1, set()), - ), -) -def test_skip_glob(tmpdir, skip_glob_assert: Tuple[List[str], int, Set[str]]) -> None: - skip_glob, skipped_count, file_names_expected = skip_glob_assert - base_dir = tmpdir.mkdir("build") - code_dir = base_dir.mkdir("code") - code_dir.join("file.py").write("import os") - - config = Config(skip_glob=skip_glob, directory=str(base_dir)) - skipped = [] # type: List[str] - file_names = { - os.path.relpath(f, str(base_dir)) - for f in main.iter_source_code([str(base_dir)], config, skipped) - } - assert len(skipped) == skipped_count - assert file_names == file_names_expected - - -def test_comments_not_removed_issue_576() -> None: - test_input = ( - "import distutils\n" - "# this comment is important and should not be removed\n" - "from sys import api_version as api_version\n" - ) - assert isort.code(test_input) == test_input - - -def test_reverse_relative_imports_issue_417() -> None: - test_input = ( - "from . import ipsum\n" - "from . import lorem\n" - "from .dolor import consecteur\n" - "from .sit import apidiscing\n" - "from .. import donec\n" - "from .. import euismod\n" - "from ..mi import iaculis\n" - "from ..nec import tempor\n" - "from ... import diam\n" - "from ... import dui\n" - "from ...eu import dignissim\n" - "from ...ex import metus\n" - ) - assert isort.code(test_input, force_single_line=True, reverse_relative=True) == test_input - - -def test_inconsistent_relative_imports_issue_577() -> None: - test_input = ( - "from ... import diam\n" - "from ... import dui\n" - "from ...eu import dignissim\n" - "from ...ex import metus\n" - "from .. import donec\n" - "from .. import euismod\n" - "from ..mi import iaculis\n" - "from ..nec import tempor\n" - "from . import ipsum\n" - "from . import lorem\n" - "from .dolor import consecteur\n" - "from .sit import apidiscing\n" - ) - assert isort.code(test_input, force_single_line=True) == test_input - - -def test_unwrap_issue_762() -> None: - test_input = "from os.path \\\nimport (join, split)\n" - assert isort.code(test_input) == "from os.path import join, split\n" - - test_input = "from os.\\\n path import (join, split)" - assert isort.code(test_input) == "from os.path import join, split\n" - - -def test_multiple_as_imports() -> None: - test_input = "from a import b as b\nfrom a import b as bb\nfrom a import b as bb_\n" - test_output = isort.code(test_input) - assert test_output == test_input - test_output = isort.code(test_input, combine_as_imports=True) - assert test_output == "from a import b as b, b as bb, b as bb_\n" - test_output = isort.code(test_input) - assert test_output == test_input - test_output = isort.code(code=test_input, combine_as_imports=True) - assert test_output == "from a import b as b, b as bb, b as bb_\n" - - test_input = ( - "from a import b\n" - "from a import b as b\n" - "from a import b as bb\n" - "from a import b as bb_\n" - ) - test_output = isort.code(test_input) - assert test_output == test_input - test_output = isort.code(code=test_input, combine_as_imports=True) - assert test_output == "from a import b, b as b, b as bb, b as bb_\n" - - test_input = ( - "from a import b as e\n" - "from a import b as c\n" - "from a import b\n" - "from a import b as f\n" - ) - test_output = isort.code(test_input) - assert ( - test_output - == "from a import b\nfrom a import b as c\nfrom a import b as e\nfrom a import b as f\n" - ) - test_output = isort.code(code=test_input, no_inline_sort=True) - assert ( - test_output - == "from a import b\nfrom a import b as c\nfrom a import b as e\nfrom a import b as f\n" - ) - test_output = isort.code(code=test_input, combine_as_imports=True) - assert test_output == "from a import b, b as c, b as e, b as f\n" - test_output = isort.code(code=test_input, combine_as_imports=True, no_inline_sort=True) - assert test_output == "from a import b, b as e, b as c, b as f\n" - - test_input = "import a as a\nimport a as aa\nimport a as aa_\n" - test_output = isort.code(code=test_input, combine_as_imports=True) - assert test_output == test_input - - assert test_output == "import a as a\nimport a as aa\nimport a as aa_\n" - test_output = isort.code(code=test_input, combine_as_imports=True) - assert test_output == test_input - - -def test_all_imports_from_single_module() -> None: - test_input = ( - "import a\n" - "from a import *\n" - "from a import b as d\n" - "from a import z, x, y\n" - "from a import b\n" - "from a import w, i as j\n" - "from a import b as c, g as h\n" - "from a import e as f\n" - ) - test_output = isort.code( - code=test_input, - combine_star=False, - combine_as_imports=False, - force_single_line=False, - no_inline_sort=False, - ) - assert test_output == ( - "import a\n" - "from a import *\n" - "from a import b\n" - "from a import b as c\n" - "from a import b as d\n" - "from a import e as f\n" - "from a import g as h\n" - "from a import i as j\n" - "from a import w, x, y, z\n" - ) - test_output = isort.code( - code=test_input, - combine_star=True, - combine_as_imports=False, - force_single_line=False, - no_inline_sort=False, - ) - assert test_output == "import a\nfrom a import *\n" - test_output = isort.code( - code=test_input, - combine_star=False, - combine_as_imports=True, - force_single_line=False, - no_inline_sort=False, - ) - assert test_output == ( - "import a\n" - "from a import *\n" - "from a import b, b as c, b as d, e as f, g as h, i as j, w, x, y, z\n" - ) - test_output = isort.code( - code=test_input, - combine_star=False, - combine_as_imports=False, - force_single_line=True, - no_inline_sort=False, - ) - assert test_output == ( - "import a\n" - "from a import *\n" - "from a import b\n" - "from a import b as c\n" - "from a import b as d\n" - "from a import e as f\n" - "from a import g as h\n" - "from a import i as j\n" - "from a import w\n" - "from a import x\n" - "from a import y\n" - "from a import z\n" - ) - test_output = isort.code( - code=test_input, - combine_star=False, - combine_as_imports=False, - force_single_line=False, - no_inline_sort=True, - ) - assert test_output == ( - "import a\n" - "from a import *\n" - "from a import b\n" - "from a import b as c\n" - "from a import b as d\n" - "from a import z, x, y, w\n" - "from a import i as j\n" - "from a import g as h\n" - "from a import e as f\n" - ) - test_output = isort.code( - code=test_input, - combine_star=True, - combine_as_imports=True, - force_single_line=False, - no_inline_sort=False, - ) - assert test_output == "import a\nfrom a import *\n" - test_output = isort.code( - code=test_input, - combine_star=True, - combine_as_imports=False, - force_single_line=True, - no_inline_sort=False, - ) - assert test_output == "import a\nfrom a import *\n" - test_output = isort.code( - code=test_input, - combine_star=True, - combine_as_imports=False, - force_single_line=False, - no_inline_sort=True, - ) - assert test_output == "import a\nfrom a import *\n" - test_output = isort.code( - code=test_input, - combine_star=False, - combine_as_imports=True, - force_single_line=True, - no_inline_sort=False, - ) - assert test_output == ( - "import a\n" - "from a import *\n" - "from a import b\n" - "from a import b as c\n" - "from a import b as d\n" - "from a import e as f\n" - "from a import g as h\n" - "from a import i as j\n" - "from a import w\n" - "from a import x\n" - "from a import y\n" - "from a import z\n" - ) - test_output = isort.code( - code=test_input, - combine_star=False, - combine_as_imports=True, - force_single_line=False, - no_inline_sort=True, - ) - assert test_output == ( - "import a\n" - "from a import *\n" - "from a import b, b as d, b as c, z, x, y, w, i as j, g as h, e as f\n" - ) - test_output = isort.code( - code=test_input, - combine_star=False, - combine_as_imports=False, - force_single_line=True, - no_inline_sort=True, - ) - assert test_output == ( - "import a\n" - "from a import *\n" - "from a import b\n" - "from a import b as c\n" - "from a import b as d\n" - "from a import e as f\n" - "from a import g as h\n" - "from a import i as j\n" - "from a import w\n" - "from a import x\n" - "from a import y\n" - "from a import z\n" - ) - test_output = isort.code( - code=test_input, - combine_star=True, - combine_as_imports=True, - force_single_line=True, - no_inline_sort=False, - ) - assert test_output == "import a\nfrom a import *\n" - - -def test_noqa_issue_679() -> None: - """Test to ensure that NOQA notation is being observed as expected - if honor_noqa is set to `True` - """ - test_input = """ -import os - -import requestsss -import zed # NOQA -import ujson # NOQA - -import foo""" - test_output = """ -import os - -import foo -import requestsss -import ujson # NOQA -import zed # NOQA -""" - test_output_honor_noqa = """ -import os - -import foo -import requestsss - -import zed # NOQA -import ujson # NOQA -""" - assert isort.code(test_input) == test_output - assert isort.code(test_input.lower()) == test_output.lower() - assert isort.code(test_input, honor_noqa=True) == test_output_honor_noqa - assert isort.code(test_input.lower(), honor_noqa=True) == test_output_honor_noqa.lower() - - -def test_extract_multiline_output_wrap_setting_from_a_config_file(tmpdir: py.path.local) -> None: - editorconfig_contents = ["root = true", " [*.py]", "multi_line_output = 5"] - config_file = tmpdir.join(".editorconfig") - config_file.write("\n".join(editorconfig_contents)) - - config = Config(settings_path=str(tmpdir)) - assert config.multi_line_output == WrapModes.VERTICAL_GRID_GROUPED - - -def test_ensure_support_for_non_typed_but_cased_alphabetic_sort_issue_890() -> None: - test_input = ( - "from pkg import BALL\n" - "from pkg import RC\n" - "from pkg import Action\n" - "from pkg import Bacoo\n" - "from pkg import RCNewCode\n" - "from pkg import actual\n" - "from pkg import rc\n" - "from pkg import recorder\n" - ) - expected_output = ( - "from pkg import Action\n" - "from pkg import BALL\n" - "from pkg import Bacoo\n" - "from pkg import RC\n" - "from pkg import RCNewCode\n" - "from pkg import actual\n" - "from pkg import rc\n" - "from pkg import recorder\n" - ) - assert ( - isort.code( - code=test_input, case_sensitive=True, order_by_type=False, force_single_line=True - ) - == expected_output - ) - - -def test_to_ensure_empty_line_not_added_to_file_start_issue_889() -> None: - test_input = "# comment\nimport os\n# comment2\nimport sys\n" - assert isort.code(test_input) == test_input - - -def test_to_ensure_correctly_handling_of_whitespace_only_issue_811(capsys) -> None: - test_input = ( - "import os\n" "import sys\n" "\n" "\x0c\n" "def my_function():\n" ' print("hi")\n' - ) - isort.code(test_input, ignore_whitespace=True) - out, err = capsys.readouterr() - assert out == "" - assert err == "" - - -def test_standard_library_deprecates_user_issue_778() -> None: - test_input = "import os\n\nimport user\n" - assert isort.code(test_input) == test_input - - -def test_settings_path_skip_issue_909(tmpdir) -> None: - base_dir = tmpdir.mkdir("project") - config_dir = base_dir.mkdir("conf") - config_dir.join(".isort.cfg").write( - "[isort]\n" "skip =\n" " file_to_be_skipped.py\n" "skip_glob =\n" " *glob_skip*\n" - ) - - base_dir.join("file_glob_skip.py").write( - "import os\n\n" 'print("Hello World")\n' "\nimport sys\nimport os\n" - ) - base_dir.join("file_to_be_skipped.py").write( - "import os\n\n" 'print("Hello World")' "\nimport sys\nimport os\n" - ) - - test_run_directory = os.getcwd() - os.chdir(str(base_dir)) - with pytest.raises( - Exception - ): # without the settings path provided: the command should not skip & identify errors - subprocess.run(["isort", ".", "--check-only"], check=True) - result = subprocess.run( - ["isort", ".", "--check-only", "--settings-path=conf/.isort.cfg"], - stdout=subprocess.PIPE, - check=True, - ) - os.chdir(str(test_run_directory)) - - assert b"skipped 2" in result.stdout.lower() - - -def test_skip_paths_issue_938(tmpdir) -> None: - base_dir = tmpdir.mkdir("project") - config_dir = base_dir.mkdir("conf") - config_dir.join(".isort.cfg").write( - "[isort]\n" - "line_length = 88\n" - "multi_line_output = 4\n" - "lines_after_imports = 2\n" - "skip_glob =\n" - " migrations/**.py\n" - ) - base_dir.join("dont_skip.py").write("import os\n\n" 'print("Hello World")' "\nimport sys\n") - - migrations_dir = base_dir.mkdir("migrations") - migrations_dir.join("file_glob_skip.py").write( - "import os\n\n" 'print("Hello World")\n' "\nimport sys\n" - ) - - test_run_directory = os.getcwd() - os.chdir(str(base_dir)) - result = subprocess.run( - ["isort", "dont_skip.py", "migrations/file_glob_skip.py"], - stdout=subprocess.PIPE, - check=True, - ) - os.chdir(str(test_run_directory)) - - assert b"skipped" not in result.stdout.lower() - - os.chdir(str(base_dir)) - result = subprocess.run( - [ - "isort", - "--filter-files", - "--settings-path=conf/.isort.cfg", - "dont_skip.py", - "migrations/file_glob_skip.py", - ], - stdout=subprocess.PIPE, - check=True, - ) - os.chdir(str(test_run_directory)) - - assert b"skipped 1" in result.stdout.lower() - - -def test_failing_file_check_916() -> None: - test_input = ( - "#!/usr/bin/env python\n" - "# -*- coding: utf-8 -*-\n" - "from __future__ import unicode_literals\n" - ) - expected_output = ( - "#!/usr/bin/env python\n" - "# -*- coding: utf-8 -*-\n" - "# FUTURE\n" - "from __future__ import unicode_literals\n" - ) - settings = { - "import_heading_future": "FUTURE", - "sections": ["FUTURE", "STDLIB", "NORDIGEN", "FIRSTPARTY", "THIRDPARTY", "LOCALFOLDER"], - "indent": " ", - "multi_line_output": 3, - "lines_after_imports": 2, - } # type: Dict[str, Any] - assert isort.code(test_input, **settings) == expected_output - assert isort.code(expected_output, **settings) == expected_output - assert api.check_code_string(expected_output, **settings) - - -def test_import_heading_issue_905() -> None: - config = { - "import_heading_stdlib": "Standard library imports", - "import_heading_thirdparty": "Third party imports", - "import_heading_firstparty": "Local imports", - "known_third_party": ["numpy"], - "known_first_party": ["oklib"], - } # type: Dict[str, Any] - test_input = ( - "# Standard library imports\n" - "from os import path as osp\n" - "\n" - "# Third party imports\n" - "import numpy as np\n" - "\n" - "# Local imports\n" - "from oklib.plot_ok import imagesc\n" - ) - assert isort.code(test_input, **config) == test_input - - -def test_isort_keeps_comments_issue_691() -> None: - test_input = ( - "import os\n" - "# This will make sure the app is always imported when\n" - "# Django starts so that shared_task will use this app.\n" - "from .celery import app as celery_app # noqa\n" - "\n" - "PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))\n" - "\n" - "def path(*subdirectories):\n" - " return os.path.join(PROJECT_DIR, *subdirectories)\n" - ) - expected_output = ( - "import os\n" - "\n" - "# This will make sure the app is always imported when\n" - "# Django starts so that shared_task will use this app.\n" - "from .celery import app as celery_app # noqa\n" - "\n" - "PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))\n" - "\n" - "def path(*subdirectories):\n" - " return os.path.join(PROJECT_DIR, *subdirectories)\n" - ) - assert isort.code(test_input) == expected_output - - -def test_isort_ensures_blank_line_between_import_and_comment() -> None: - config = { - "ensure_newline_before_comments": True, - "known_one": ["one"], - "known_two": ["two"], - "known_three": ["three"], - "known_four": ["four"], - "sections": [ - "FUTURE", - "STDLIB", - "FIRSTPARTY", - "THIRDPARTY", - "LOCALFOLDER", - "ONE", - "TWO", - "THREE", - "FOUR", - ], - } # type: Dict[str, Any] - test_input = ( - "import os\n" - "# noinspection PyUnresolvedReferences\n" - "import one.a\n" - "# noinspection PyUnresolvedReferences\n" - "import one.b\n" - "# noinspection PyUnresolvedReferences\n" - "import two.a as aa\n" - "# noinspection PyUnresolvedReferences\n" - "import two.b as bb\n" - "# noinspection PyUnresolvedReferences\n" - "from three.a import a\n" - "# noinspection PyUnresolvedReferences\n" - "from three.b import b\n" - "# noinspection PyUnresolvedReferences\n" - "from four.a import a as aa\n" - "# noinspection PyUnresolvedReferences\n" - "from four.b import b as bb\n" - ) - expected_output = ( - "import os\n" - "\n" - "# noinspection PyUnresolvedReferences\n" - "import one.a\n" - "\n" - "# noinspection PyUnresolvedReferences\n" - "import one.b\n" - "\n" - "# noinspection PyUnresolvedReferences\n" - "import two.a as aa\n" - "\n" - "# noinspection PyUnresolvedReferences\n" - "import two.b as bb\n" - "\n" - "# noinspection PyUnresolvedReferences\n" - "from three.a import a\n" - "\n" - "# noinspection PyUnresolvedReferences\n" - "from three.b import b\n" - "\n" - "# noinspection PyUnresolvedReferences\n" - "from four.a import a as aa\n" - "\n" - "# noinspection PyUnresolvedReferences\n" - "from four.b import b as bb\n" - ) - assert isort.code(test_input, **config) == expected_output - - -def test_pyi_formatting_issue_942(tmpdir) -> None: - test_input = "import os\n\n\ndef my_method():\n" - expected_py_output = test_input.splitlines() - expected_pyi_output = "import os\n\ndef my_method():\n".splitlines() - assert isort.code(test_input).splitlines() == expected_py_output - assert isort.code(test_input, extension="pyi").splitlines() == expected_pyi_output - - source_py = tmpdir.join("source.py") - source_py.write(test_input) - assert ( - isort.code(code=Path(source_py).read_text(), file_path=Path(source_py)).splitlines() - == expected_py_output - ) - - source_pyi = tmpdir.join("source.pyi") - source_pyi.write(test_input) - assert ( - isort.code( - code=Path(source_pyi).read_text(), extension="pyi", file_path=Path(source_pyi) - ).splitlines() - == expected_pyi_output - ) - - # Ensure it works for direct file API as well (see: issue #1284) - source_pyi = tmpdir.join("source.pyi") - source_pyi.write(test_input) - api.sort_file(Path(source_pyi)) - - assert source_pyi.read().splitlines() == expected_pyi_output - - -def test_move_class_issue_751() -> None: - test_input = ( - "# -*- coding: utf-8 -*-" - "\n" - "# Define your item pipelines here" - "#" - "# Don't forget to add your pipeline to the ITEM_PIPELINES setting" - "# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html" - "from datetime import datetime" - "from .items import WeiboMblogItem" - "\n" - "class WeiboMblogPipeline(object):" - " def process_item(self, item, spider):" - " if isinstance(item, WeiboMblogItem):" - " item = self._process_item(item, spider)" - " return item" - "\n" - " def _process_item(self, item, spider):" - " item['inserted_at'] = datetime.now()" - " return item" - "\n" - ) - assert isort.code(test_input) == test_input - - -def test_python_version() -> None: - from isort.main import parse_args - - # test that the py_version can be added as flag - args = parse_args(["--py=27"]) - assert args["py_version"] == "27" - - args = parse_args(["--python-version=3"]) - assert args["py_version"] == "3" - - test_input = "import os\n\nimport user\n" - assert isort.code(test_input, py_version="3") == test_input - - # user is part of the standard library in python 2 - output_python_2 = "import os\nimport user\n" - assert isort.code(test_input, py_version="27") == output_python_2 - - test_input = "import os\nimport xml" - - print(isort.code(test_input, py_version="all")) - - -def test_isort_with_single_character_import() -> None: - """Tests to ensure isort handles single capatilized single character imports - as class objects by default - - See Issue #376: https://github.com/timothycrosley/isort/issues/376 - """ - test_input = "from django.db.models import CASCADE, SET_NULL, Q\n" - assert isort.code(test_input) == test_input - - -def test_isort_nested_imports() -> None: - """Ensure imports in a nested block get sorted correctly""" - test_input = """ - def import_test(): - import sys - import os - - # my imports - from . import def - from . import abc - - return True - """ - assert ( - isort.code(test_input) - == """ - def import_test(): - import os - import sys - - # my imports - from . import abc, def - - return True - """ - ) - - -def test_isort_off() -> None: - """Test that isort can be turned on and off at will using comments""" - test_input = """import os - -# isort: off -import sys -import os -# isort: on - -from . import local -""" - assert isort.code(test_input) == test_input - - -def test_isort_split() -> None: - """Test the ability to split isort import sections""" - test_input = """import os -import sys - -# isort: split - -import os -import sys -""" - assert isort.code(test_input) == test_input - - test_input = """import c - -import b # isort: split - -import a -import c -""" - assert isort.code(test_input) == test_input - - -def test_comment_look_alike(): - """Test to ensure isort will handle what looks like a single line comment - at the end of a multi-line comment. - """ - test_input = ''' -"""This is a multi-line comment - -ending with what appears to be a single line comment -# Single Line Comment""" -import sys -import os -''' - assert ( - isort.code(test_input) - == ''' -"""This is a multi-line comment - -ending with what appears to be a single line comment -# Single Line Comment""" -import os -import sys -''' - ) - - -def test_cimport_support(): - """Test to ensure cimports (Cython style imports) work""" - test_input = """ -import os -import sys -import cython -import platform -import traceback -import time -import types -import re -import copy -import inspect # used by JavascriptBindings.__SetObjectMethods() -import urllib -import json -import datetime -import random - -if sys.version_info.major == 2: - import urlparse -else: - from urllib import parse as urlparse - -if sys.version_info.major == 2: - from urllib import pathname2url as urllib_pathname2url -else: - from urllib.request import pathname2url as urllib_pathname2url - -from cpython.version cimport PY_MAJOR_VERSION -import weakref - -# We should allow multiple string types: str, unicode, bytes. -# PyToCefString() can handle them all. -# Important: -# If you set it to basestring, Cython will accept exactly(!) -# str/unicode in Py2 and str in Py3. This won't work in Py3 -# as we might want to pass bytes as well. Also it will -# reject string subtypes, so using it in publi API functions -# would be a bad idea. -ctypedef object py_string - -# You can't use "void" along with cpdef function returning None, it is planned to be -# added to Cython in the future, creating this virtual type temporarily. If you -# change it later to "void" then don't forget to add "except *". -ctypedef object py_void -ctypedef long WindowHandle - -from cpython cimport PyLong_FromVoidPtr - -from cpython cimport bool as py_bool -from libcpp cimport bool as cpp_bool - -from libcpp.map cimport map as cpp_map -from multimap cimport multimap as cpp_multimap -from libcpp.pair cimport pair as cpp_pair -from libcpp.vector cimport vector as cpp_vector - -from libcpp.string cimport string as cpp_string -from wstring cimport wstring as cpp_wstring - -from libc.string cimport strlen -from libc.string cimport memcpy - -# preincrement and dereference must be "as" otherwise not seen. -from cython.operator cimport preincrement as preinc, dereference as deref - -# from cython.operator cimport address as addr # Address of an c++ object? - -from libc.stdlib cimport calloc, malloc, free -from libc.stdlib cimport atoi - -# When pyx file cimports * from a pxd file and that pxd cimports * from another pxd -# then these names will be visible in pyx file. - -# Circular imports are allowed in form "cimport ...", but won't work if you do -# "from ... cimport *", this is important to know in pxd files. - -from libc.stdint cimport uint64_t -from libc.stdint cimport uintptr_t - -cimport ctime - -IF UNAME_SYSNAME == "Windows": - from windows cimport * - from dpi_aware_win cimport * -ELIF UNAME_SYSNAME == "Linux": - from linux cimport * -ELIF UNAME_SYSNAME == "Darwin": - from mac cimport * - -from cpp_utils cimport * -from task cimport * - -from cef_string cimport * -cdef extern from *: - ctypedef CefString ConstCefString "const CefString" - -from cef_types_wrappers cimport * -from cef_task cimport * -from cef_runnable cimport * - -from cef_platform cimport * - -from cef_ptr cimport * -from cef_app cimport * -from cef_browser cimport * -cimport cef_browser_static -from cef_client cimport * -from client_handler cimport * -from cef_frame cimport * - -# cannot cimport *, that would cause name conflicts with constants. -cimport cef_types -ctypedef cef_types.cef_paint_element_type_t PaintElementType -ctypedef cef_types.cef_jsdialog_type_t JSDialogType -from cef_types cimport CefKeyEvent -from cef_types cimport CefMouseEvent -from cef_types cimport CefScreenInfo - -# cannot cimport *, name conflicts -IF UNAME_SYSNAME == "Windows": - cimport cef_types_win -ELIF UNAME_SYSNAME == "Darwin": - cimport cef_types_mac -ELIF UNAME_SYSNAME == "Linux": - cimport cef_types_linux - -from cef_time cimport * -from cef_drag cimport * - -import os - -IF CEF_VERSION == 1: - from cef_v8 cimport * - cimport cef_v8_static - cimport cef_v8_stack_trace - from v8function_handler cimport * - from cef_request_cef1 cimport * - from cef_web_urlrequest_cef1 cimport * - cimport cef_web_urlrequest_static_cef1 - from web_request_client_cef1 cimport * - from cef_stream cimport * - cimport cef_stream_static - from cef_response_cef1 cimport * - from cef_stream cimport * - from cef_content_filter cimport * - from content_filter_handler cimport * - from cef_download_handler cimport * - from download_handler cimport * - from cef_cookie_cef1 cimport * - cimport cef_cookie_manager_namespace - from cookie_visitor cimport * - from cef_render_handler cimport * - from cef_drag_data cimport * - -IF UNAME_SYSNAME == "Windows": - IF CEF_VERSION == 1: - from http_authentication cimport * - -IF CEF_VERSION == 3: - from cef_values cimport * - from cefpython_app cimport * - from cef_process_message cimport * - from cef_web_plugin_cef3 cimport * - from cef_request_handler_cef3 cimport * - from cef_request_cef3 cimport * - from cef_cookie_cef3 cimport * - from cef_string_visitor cimport * - cimport cef_cookie_manager_namespace - from cookie_visitor cimport * - from string_visitor cimport * - from cef_callback_cef3 cimport * - from cef_response_cef3 cimport * - from cef_resource_handler_cef3 cimport * - from resource_handler_cef3 cimport * - from cef_urlrequest_cef3 cimport * - from web_request_client_cef3 cimport * - from cef_command_line cimport * - from cef_request_context cimport * - from cef_request_context_handler cimport * - from request_context_handler cimport * - from cef_jsdialog_handler cimport * -""" - expected_output = """ -import copy -import datetime -import inspect # used by JavascriptBindings.__SetObjectMethods() -import json -import os -import platform -import random -import re -import sys -import time -import traceback -import types -import urllib - -import cython - -if sys.version_info.major == 2: - import urlparse -else: - from urllib import parse as urlparse - -if sys.version_info.major == 2: - from urllib import pathname2url as urllib_pathname2url -else: - from urllib.request import pathname2url as urllib_pathname2url - -from cpython.version cimport PY_MAJOR_VERSION - -import weakref - -# We should allow multiple string types: str, unicode, bytes. -# PyToCefString() can handle them all. -# Important: -# If you set it to basestring, Cython will accept exactly(!) -# str/unicode in Py2 and str in Py3. This won't work in Py3 -# as we might want to pass bytes as well. Also it will -# reject string subtypes, so using it in publi API functions -# would be a bad idea. -ctypedef object py_string - -# You can't use "void" along with cpdef function returning None, it is planned to be -# added to Cython in the future, creating this virtual type temporarily. If you -# change it later to "void" then don't forget to add "except *". -ctypedef object py_void -ctypedef long WindowHandle - -cimport ctime -from cpython cimport PyLong_FromVoidPtr -from cpython cimport bool as py_bool -# preincrement and dereference must be "as" otherwise not seen. -from cython.operator cimport dereference as deref -from cython.operator cimport preincrement as preinc -from libc.stdint cimport uint64_t, uintptr_t -from libc.stdlib cimport atoi, calloc, free, malloc -from libc.string cimport memcpy, strlen -from libcpp cimport bool as cpp_bool -from libcpp.map cimport map as cpp_map -from libcpp.pair cimport pair as cpp_pair -from libcpp.string cimport string as cpp_string -from libcpp.vector cimport vector as cpp_vector -from multimap cimport multimap as cpp_multimap -from wstring cimport wstring as cpp_wstring - -# from cython.operator cimport address as addr # Address of an c++ object? - - -# When pyx file cimports * from a pxd file and that pxd cimports * from another pxd -# then these names will be visible in pyx file. - -# Circular imports are allowed in form "cimport ...", but won't work if you do -# "from ... cimport *", this is important to know in pxd files. - - - -IF UNAME_SYSNAME == "Windows": - from dpi_aware_win cimport * - from windows cimport * -ELIF UNAME_SYSNAME == "Linux": - from linux cimport * -ELIF UNAME_SYSNAME == "Darwin": - from mac cimport * - -from cef_string cimport * -from cpp_utils cimport * -from task cimport * - - -cdef extern from *: - ctypedef CefString ConstCefString "const CefString" - -cimport cef_browser_static -# cannot cimport *, that would cause name conflicts with constants. -cimport cef_types -from cef_app cimport * -from cef_browser cimport * -from cef_client cimport * -from cef_frame cimport * -from cef_platform cimport * -from cef_ptr cimport * -from cef_runnable cimport * -from cef_task cimport * -from cef_types_wrappers cimport * -from client_handler cimport * - -ctypedef cef_types.cef_paint_element_type_t PaintElementType -ctypedef cef_types.cef_jsdialog_type_t JSDialogType -from cef_types cimport CefKeyEvent, CefMouseEvent, CefScreenInfo - -# cannot cimport *, name conflicts -IF UNAME_SYSNAME == "Windows": - cimport cef_types_win -ELIF UNAME_SYSNAME == "Darwin": - cimport cef_types_mac -ELIF UNAME_SYSNAME == "Linux": - cimport cef_types_linux - -from cef_drag cimport * -from cef_time cimport * - -import os - -IF CEF_VERSION == 1: - cimport cef_cookie_manager_namespace - cimport cef_stream_static - cimport cef_v8_stack_trace - cimport cef_v8_static - cimport cef_web_urlrequest_static_cef1 - from cef_content_filter cimport * - from cef_cookie_cef1 cimport * - from cef_download_handler cimport * - from cef_drag_data cimport * - from cef_render_handler cimport * - from cef_request_cef1 cimport * - from cef_response_cef1 cimport * - from cef_stream cimport * - from cef_v8 cimport * - from cef_web_urlrequest_cef1 cimport * - from content_filter_handler cimport * - from cookie_visitor cimport * - from download_handler cimport * - from v8function_handler cimport * - from web_request_client_cef1 cimport * - -IF UNAME_SYSNAME == "Windows": - IF CEF_VERSION == 1: - from http_authentication cimport * - -IF CEF_VERSION == 3: - cimport cef_cookie_manager_namespace - from cef_callback_cef3 cimport * - from cef_command_line cimport * - from cef_cookie_cef3 cimport * - from cef_jsdialog_handler cimport * - from cef_process_message cimport * - from cef_request_cef3 cimport * - from cef_request_context cimport * - from cef_request_context_handler cimport * - from cef_request_handler_cef3 cimport * - from cef_resource_handler_cef3 cimport * - from cef_response_cef3 cimport * - from cef_string_visitor cimport * - from cef_urlrequest_cef3 cimport * - from cef_values cimport * - from cef_web_plugin_cef3 cimport * - from cefpython_app cimport * - from cookie_visitor cimport * - from request_context_handler cimport * - from resource_handler_cef3 cimport * - from string_visitor cimport * - from web_request_client_cef3 cimport * -""" - assert isort.code(test_input).strip() == expected_output.strip() - assert isort.code(test_input, old_finders=True).strip() == expected_output.strip() - - -def test_cdef_support(): - assert ( - isort.code( - code=""" -from cpython.version cimport PY_MAJOR_VERSION - -cdef extern from *: - ctypedef CefString ConstCefString "const CefString" -""" - ) - == """ -from cpython.version cimport PY_MAJOR_VERSION - - -cdef extern from *: - ctypedef CefString ConstCefString "const CefString" -""" - ) - - assert ( - isort.code( - code=""" -from cpython.version cimport PY_MAJOR_VERSION - -cpdef extern from *: - ctypedef CefString ConstCefString "const CefString" -""" - ) - == """ -from cpython.version cimport PY_MAJOR_VERSION - - -cpdef extern from *: - ctypedef CefString ConstCefString "const CefString" -""" - ) - - -def test_top_level_import_order() -> None: - test_input = ( - "from rest_framework import throttling, viewsets\n" - "from rest_framework.authentication import TokenAuthentication\n" - ) - assert isort.code(test_input, force_sort_within_sections=True) == test_input - - -def test_noqa_issue_1065() -> None: - test_input = """ -# -# USER SIGNALS -# - -from flask_login import user_logged_in, user_logged_out # noqa - -from flask_security.signals import ( # noqa - password_changed as user_reset_password, # noqa - user_confirmed, # noqa - user_registered, # noqa -) # noqa - -from flask_principal import identity_changed as user_identity_changed # noqa -""" - expected_output = """ -# -# USER SIGNALS -# - -from flask_login import user_logged_in, user_logged_out # noqa -from flask_principal import identity_changed as user_identity_changed # noqa -from flask_security.signals import password_changed as user_reset_password # noqa -from flask_security.signals import user_confirmed # noqa -from flask_security.signals import user_registered # noqa -""" - assert isort.code(test_input, line_length=100) == expected_output - - -def test_single_line_exclusions(): - test_input = """ -# start comment -from os import path, system -from typing import List, TypeVar -""" - expected_output = """ -# start comment -from os import path -from os import system -from typing import List, TypeVar -""" - assert ( - isort.code(code=test_input, force_single_line=True, single_line_exclusions=("typing",)) - == expected_output - ) - - -def test_nested_comment_handling(): - test_input = """ -if True: - import foo - -# comment for bar -""" - assert isort.code(test_input) == test_input - - # If comments appear inside import sections at same indentation they can be re-arranged. - test_input = """ -if True: - import sys - - # os import - import os -""" - expected_output = """ -if True: - # os import - import os - import sys -""" - assert isort.code(test_input) == expected_output - - # Comments shouldn't be unexpectedly rearranged. See issue #1090. - test_input = """ -def f(): - # comment 1 - # comment 2 - - # comment 3 - # comment 4 - from a import a - from b import b - -""" - assert isort.code(test_input) == test_input - - # Whitespace shouldn't be adjusted for nested imports. See issue #1090. - test_input = """ -try: - import foo - except ImportError: - import bar -""" - assert isort.code(test_input) == test_input - - -def test_comments_top_of_file(): - """Test to ensure comments at top of file are correctly handled. See issue #1091.""" - test_input = """# comment 1 - -# comment 2 -# comment 3 -# comment 4 -from foo import * -""" - assert isort.code(test_input) == test_input - - test_input = """# -*- coding: utf-8 -*- - -# Define your item pipelines here -# -# Don't forget to add your pipeline to the ITEM_PIPELINES setting -# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html -from datetime import datetime - -from .items import WeiboMblogItem - - -class WeiboMblogPipeline(object): - def process_item(self, item, spider): - if isinstance(item, WeiboMblogItem): - item = self._process_item(item, spider) - return item - - def _process_item(self, item, spider): - item['inserted_at'] = datetime.now() - return item -""" - assert isort.code(test_input) == test_input - - -def test_multiple_aliases(): - """Test to ensure isort will retain multiple aliases. See issue #1037""" - test_input = """import datetime -import datetime as datetime -import datetime as dt -import datetime as dt2 -""" - assert isort.code(code=test_input) == test_input - - -def test_parens_in_comment(): - """Test to ensure isort can handle parens placed in comments. See issue #1103""" - test_input = """from foo import ( # (some text in brackets) - bar, -) -""" - expected_output = "from foo import bar # (some text in brackets)\n" - assert isort.code(test_input) == expected_output - - -def test_as_imports_mixed(): - """Test to ensure as imports can be mixed with non as. See issue #908""" - test_input = """from datetime import datetime -import datetime.datetime as dt -""" - expected_output = """import datetime.datetime as dt -from datetime import datetime -""" - assert isort.code(test_input) == expected_output - - -def test_no_sections_with_future(): - """Test to ensure no_sections works with future. See issue #807""" - test_input = """from __future__ import print_function -import os - """ - expected_output = """from __future__ import print_function - -import os -""" - assert isort.code(test_input, no_sections=True) == expected_output - - -def test_no_sections_with_as_import(): - """Test to ensure no_sections work with as import.""" - test_input = """import oumpy as np -import sympy -""" - assert isort.code(test_input, no_sections=True) == test_input - - -def test_no_lines_too_long(): - """Test to ensure no lines end up too long. See issue: #1015""" - test_input = """from package1 import first_package, \ -second_package -from package2 import \\ - first_package - """ - expected_output = """from package1 import \\ - first_package, \\ - second_package -from package2 import \\ - first_package -""" - assert isort.code(test_input, line_length=25, multi_line_output=2) == expected_output - - -def test_python_future_category(): - """Test to ensure a manual python future category will work as needed to install aliases - - see: Issue #1005 - """ - test_input = """from __future__ import absolute_import - -# my future comment -from future import standard_library - -standard_library.install_aliases() - -import os -import re -import time - -from logging.handlers import SysLogHandler - -from builtins import len, object, str - -from katlogger import log_formatter, log_rollover - -from .query_elastic import QueryElastic -""" - expected_output = """from __future__ import absolute_import - -# my future comment -from future import standard_library - -standard_library.install_aliases() - -# Python Standard Library -import os -import re -import time - -from builtins import len, object, str -from logging.handlers import SysLogHandler - -# CAM Packages -from katlogger import log_formatter, log_rollover - -# Explicitly Local -from .query_elastic import QueryElastic -""" - assert ( - isort.code( - code=test_input, - force_grid_wrap=False, - include_trailing_comma=True, - indent=4, - line_length=90, - multi_line_output=3, - lines_between_types=1, - sections=[ - "FUTURE_LIBRARY", - "FUTURE_THIRDPARTY", - "STDLIB", - "THIRDPARTY", - "FIRSTPARTY", - "LOCALFOLDER", - ], - import_heading_stdlib="Python Standard Library", - import_heading_thirdparty="Third Library", - import_heading_firstparty="CAM Packages", - import_heading_localfolder="Explicitly Local", - known_first_party=["katlogger"], - known_future_thirdparty=["future"], - ) - == expected_output - ) - - -def test_combine_star_comments_above(): - input_text = """from __future__ import absolute_import - -# my future comment -from future import *, something -""" - expected_output = """from __future__ import absolute_import - -# my future comment -from future import * -""" - assert isort.code(input_text, combine_star=True) == expected_output - - -def test_deprecated_settings(): - """Test to ensure isort warns when deprecated settings are used, but doesn't fail to run""" - with pytest.warns(UserWarning): - assert isort.code("hi", not_skip=True) diff -Nru isort-5.4.2/tests/test_literal.py isort-5.6.4/tests/test_literal.py --- isort-5.4.2/tests/test_literal.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/tests/test_literal.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -import pytest - -import isort.literal -from isort import exceptions -from isort.settings import Config - - -def test_value_mismatch(): - with pytest.raises(exceptions.LiteralSortTypeMismatch): - isort.literal.assignment("x = [1, 2, 3]", "set", "py") - - -def test_invalid_syntax(): - with pytest.raises(exceptions.LiteralParsingFailure): - isort.literal.assignment("x = [1, 2, 3", "list", "py") - - -def test_invalid_sort_type(): - with pytest.raises(ValueError): - isort.literal.assignment("x = [1, 2, 3", "tuple-list-not-exist", "py") - - -def test_value_assignment(): - assert isort.literal.assignment("x = ['b', 'a']", "list", "py") == "x = ['a', 'b']" - assert ( - isort.literal.assignment("x = ['b', 'a']", "list", "py", Config(formatter="example")) - == 'x = ["a", "b"]' - ) - - -def test_assignments_invalid_section(): - with pytest.raises(exceptions.AssignmentsFormatMismatch): - isort.literal.assignment("x++", "assignments", "py") diff -Nru isort-5.4.2/tests/test_main.py isort-5.6.4/tests/test_main.py --- isort-5.4.2/tests/test_main.py 2020-08-13 03:47:19.720318300 +0000 +++ isort-5.6.4/tests/test_main.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,243 +0,0 @@ -import json -import subprocess -from datetime import datetime -from io import BytesIO, TextIOWrapper - -import pytest -from hypothesis_auto import auto_pytest_magic - -from isort import main -from isort._version import __version__ -from isort.exceptions import InvalidSettingsPath -from isort.settings import DEFAULT_CONFIG, Config -from isort.wrap_modes import WrapModes - -auto_pytest_magic(main.sort_imports) - - -def test_iter_source_code(tmpdir): - tmp_file = tmpdir.join("file.py") - tmp_file.write("import os, sys\n") - assert tuple(main.iter_source_code((tmp_file,), DEFAULT_CONFIG, [])) == (tmp_file,) - - -def test_sort_imports(tmpdir): - tmp_file = tmpdir.join("file.py") - tmp_file.write("import os, sys\n") - assert main.sort_imports(str(tmp_file), DEFAULT_CONFIG, check=True).incorrectly_sorted - main.sort_imports(str(tmp_file), DEFAULT_CONFIG) - assert not main.sort_imports(str(tmp_file), DEFAULT_CONFIG, check=True).incorrectly_sorted - - skip_config = Config(skip=["file.py"]) - assert main.sort_imports( - str(tmp_file), config=skip_config, check=True, disregard_skip=False - ).skipped - assert main.sort_imports(str(tmp_file), config=skip_config, disregard_skip=False).skipped - - -def test_parse_args(): - assert main.parse_args([]) == {} - assert main.parse_args(["--multi-line", "1"]) == {"multi_line_output": WrapModes.VERTICAL} - assert main.parse_args(["--multi-line", "GRID"]) == {"multi_line_output": WrapModes.GRID} - assert main.parse_args(["--dont-order-by-type"]) == {"order_by_type": False} - assert main.parse_args(["--dt"]) == {"order_by_type": False} - - -def test_ascii_art(capsys): - main.main(["--version"]) - out, error = capsys.readouterr() - assert ( - out - == f""" - _ _ - (_) ___ ___ _ __| |_ - | |/ _/ / _ \\/ '__ _/ - | |\\__ \\/\\_\\/| | | |_ - |_|\\___/\\___/\\_/ \\_/ - - isort your imports, so you don't have to. - - VERSION {__version__} - -""" - ) - assert error == "" - - -def test_preconvert(): - assert main._preconvert(frozenset([1, 1, 2])) == [1, 2] - assert main._preconvert(WrapModes.GRID) == "GRID" - assert main._preconvert(main._preconvert) == "_preconvert" - with pytest.raises(TypeError): - main._preconvert(datetime.now()) - - -def test_main(capsys, tmpdir): - base_args = [ - "-sp", - str(tmpdir), - "--virtual-env", - str(tmpdir), - "--src-path", - str(tmpdir), - ] - tmpdir.mkdir(".git") - - # If nothing is passed in the quick guide is returned without erroring - main.main([]) - out, error = capsys.readouterr() - assert main.QUICK_GUIDE in out - assert not error - - # If no files are passed in but arguments are the quick guide is returned, alongside an error. - with pytest.raises(SystemExit): - main.main(base_args) - out, error = capsys.readouterr() - assert main.QUICK_GUIDE in out - - # Unless the config is requested, in which case it will be returned alone as JSON - main.main(base_args + ["--show-config"]) - out, error = capsys.readouterr() - returned_config = json.loads(out) - assert returned_config - assert returned_config["virtual_env"] == str(tmpdir) - - # This should work even if settings path is not provided - main.main(base_args[2:] + ["--show-config"]) - out, error = capsys.readouterr() - assert json.loads(out)["virtual_env"] == str(tmpdir) - - # This should raise an error if an invalid settings path is provided - with pytest.raises(InvalidSettingsPath): - main.main( - base_args[2:] - + ["--show-config"] - + ["--settings-path", "/random-root-folder-that-cant-exist-right?"] - ) - - # Should be able to set settings path to a file - config_file = tmpdir.join(".isort.cfg") - config_file.write( - """ -[settings] -profile=hug -verbose=true -""" - ) - config_args = ["--settings-path", str(config_file)] - main.main( - config_args - + ["--virtual-env", "/random-root-folder-that-cant-exist-right?"] - + ["--show-config"] - ) - out, error = capsys.readouterr() - assert json.loads(out)["profile"] == "hug" - - # Should be able to stream in content to sort - input_content = TextIOWrapper( - BytesIO( - b""" -import b -import a -""" - ) - ) - main.main(config_args + ["-"], stdin=input_content) - out, error = capsys.readouterr() - assert ( - out - == f""" -else-type place_module for b returned {DEFAULT_CONFIG.default_section} -else-type place_module for a returned {DEFAULT_CONFIG.default_section} -import a -import b -""" - ) - - # Should be able to run with just a file - python_file = tmpdir.join("has_imports.py") - python_file.write( - """ -import b -import a -""" - ) - main.main([str(python_file), "--filter-files", "--verbose"]) - assert python_file.read().lstrip() == "import a\nimport b\n" - - # Add a file to skip - should_skip = tmpdir.join("should_skip.py") - should_skip.write("import nothing") - main.main( - [ - str(python_file), - str(should_skip), - "--filter-files", - "--verbose", - "--skip", - str(should_skip), - ] - ) - - # Should raise a system exit if check only, with broken file - python_file.write( - """ -import b -import a -""" - ) - with pytest.raises(SystemExit): - main.main( - [ - str(python_file), - str(should_skip), - "--filter-files", - "--verbose", - "--check-only", - "--skip", - str(should_skip), - ] - ) - - # Should have same behavior if full directory is skipped - with pytest.raises(SystemExit): - main.main( - [str(tmpdir), "--filter-files", "--verbose", "--check-only", "--skip", str(should_skip)] - ) - - # Nested files should be skipped without needing --filter-files - nested_file = tmpdir.mkdir("nested_dir").join("skip.py") - nested_file.write("import b;import a") - python_file.write( - """ -import a -import b -""" - ) - main.main([str(tmpdir), "--skip", "skip.py", "--check"]) - - # without filter options passed in should successfully sort files - main.main([str(python_file), str(should_skip), "--verbose", "--atomic"]) - - # should respect gitignore if requested. - out, error = capsys.readouterr() # clear sysoutput before tests - subprocess.run(["git", "init", str(tmpdir)]) - main.main([str(python_file), "--skip-gitignore", "--filter-files"]) - out, error = capsys.readouterr() - assert "Skipped" not in out - tmpdir.join(".gitignore").write("has_imports.py") - main.main([str(python_file)]) - out, error = capsys.readouterr() - assert "Skipped" not in out - main.main([str(python_file), "--skip-gitignore", "--filter-files"]) - out, error = capsys.readouterr() - assert "Skipped" in out - - # warnings should be displayed if old flags are used - with pytest.warns(UserWarning): - main.main([str(python_file), "--recursive", "-fss"]) - - -def test_isort_command(): - """Ensure ISortCommand got registered, otherwise setuptools error must have occured""" - assert main.ISortCommand diff -Nru isort-5.4.2/tests/test_output.py isort-5.6.4/tests/test_output.py --- isort-5.4.2/tests/test_output.py 2020-07-29 04:24:06.101085000 +0000 +++ isort-5.6.4/tests/test_output.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -from hypothesis_auto import auto_pytest_magic - -from isort import output - -auto_pytest_magic(output.with_comments, auto_allow_exceptions_=(ValueError,)) diff -Nru isort-5.4.2/tests/test_parse.py isort-5.6.4/tests/test_parse.py --- isort-5.4.2/tests/test_parse.py 2020-07-29 04:24:06.101085000 +0000 +++ isort-5.6.4/tests/test_parse.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -from hypothesis_auto import auto_pytest_magic - -from isort import parse -from isort.settings import Config - -TEST_CONTENTS = """ -import xyz -import abc -import (\\ # one - one as \\ # two - three) -import \\ - zebra as \\ # one - not_bacon -from x import (\\ # one - one as \\ # two - three) - - -def function(): - pass -""" - - -def test_file_contents(): - ( - in_lines, - out_lines, - import_index, - _, - _, - _, - _, - _, - change_count, - original_line_count, - _, - _, - ) = parse.file_contents(TEST_CONTENTS, config=Config(default_section="")) - assert "\n".join(in_lines) == TEST_CONTENTS - assert "import" not in "\n".join(out_lines) - assert import_index == 1 - assert change_count == -11 - assert original_line_count == len(in_lines) - - -auto_pytest_magic(parse.import_type) -auto_pytest_magic(parse.skip_line) -auto_pytest_magic(parse._strip_syntax) -auto_pytest_magic(parse._infer_line_separator) diff -Nru isort-5.4.2/tests/test_place.py isort-5.6.4/tests/test_place.py --- isort-5.4.2/tests/test_place.py 2020-07-29 04:24:06.101085000 +0000 +++ isort-5.6.4/tests/test_place.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -"""Tests for the isort import placement module""" -from functools import partial - -from isort import place, sections -from isort.settings import Config - - -def test_module(src_path): - place_tester = partial(place.module, config=Config(src_paths=[src_path])) - assert place_tester("isort") == sections.FIRSTPARTY - assert place_tester("os") == sections.STDLIB - assert place_tester(".deprecated") == sections.LOCALFOLDER - assert place_tester("__future__") == sections.FUTURE - assert place_tester("hug") == sections.THIRDPARTY - - -def test_extra_standard_library(src_path): - place_tester = partial( - place.module, config=Config(src_paths=[src_path], extra_standard_library=["hug"]) - ) - assert place_tester("os") == sections.STDLIB - assert place_tester("hug") == sections.STDLIB diff -Nru isort-5.4.2/tests/test_pylama_isort.py isort-5.6.4/tests/test_pylama_isort.py --- isort-5.4.2/tests/test_pylama_isort.py 2020-07-29 04:24:06.101085000 +0000 +++ isort-5.6.4/tests/test_pylama_isort.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -import os - -from isort.pylama_isort import Linter - - -class TestLinter: - instance = Linter() - - def test_allow(self): - assert not self.instance.allow("test_case.pyc") - assert not self.instance.allow("test_case.c") - assert self.instance.allow("test_case.py") - - def test_run(self, src_dir, tmpdir): - assert not self.instance.run(os.path.join(src_dir, "api.py")) - - incorrect = tmpdir.join("incorrect.py") - incorrect.write("import b\nimport a\n") - assert self.instance.run(str(incorrect)) diff -Nru isort-5.4.2/tests/test_regressions.py isort-5.6.4/tests/test_regressions.py --- isort-5.4.2/tests/test_regressions.py 2020-08-13 08:23:21.599986000 +0000 +++ isort-5.6.4/tests/test_regressions.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,537 +0,0 @@ -"""A growing set of tests designed to ensure isort doesn't have regressions in new versions""" -from io import StringIO - -import isort - - -def test_isort_duplicating_comments_issue_1264(): - """Ensure isort doesn't duplicate comments when force_sort_within_sections is set to `True` - as was the case in issue #1264: https://github.com/timothycrosley/isort/issues/1264 - """ - assert ( - isort.code( - """ -from homeassistant.util.logging import catch_log_exception - -# Loading the config flow... -from . import config_flow -""", - force_sort_within_sections=True, - ).count("# Loading the config flow...") - == 1 - ) - - -def test_moving_comments_issue_726(): - test_input = ( - "from Blue import models as BlueModels\n" - "# comment for PlaidModel\n" - "from Plaid.models import PlaidModel\n" - ) - assert isort.code(test_input, force_sort_within_sections=True) == test_input - - test_input = ( - "# comment for BlueModels\n" - "from Blue import models as BlueModels\n" - "# comment for PlaidModel\n" - "# another comment for PlaidModel\n" - "from Plaid.models import PlaidModel\n" - ) - assert isort.code(test_input, force_sort_within_sections=True) == test_input - - -def test_blank_lined_removed_issue_1275(): - """Ensure isort doesn't accidentally remove blank lines after doc strings and before imports. - See: https://github.com/timothycrosley/isort/issues/1275 - """ - assert ( - isort.code( - '''""" -My docstring -""" - -from b import thing -from a import other_thing -''' - ) - == '''""" -My docstring -""" - -from a import other_thing -from b import thing -''' - ) - - assert ( - isort.code( - '''""" -My docstring -""" - -from b import thing -from a import other_thing -''', - add_imports=["from b import thing"], - ) - == '''""" -My docstring -""" - -from a import other_thing -from b import thing -''' - ) - - -def test_blank_lined_removed_issue_1283(): - """Ensure isort doesn't accidentally remove blank lines after __version__ identifiers. - See: https://github.com/timothycrosley/isort/issues/1283 - """ - test_input = """__version__ = "0.58.1" - -from starlette import status -""" - assert isort.code(test_input) == test_input - - -def test_extra_blank_line_added_nested_imports_issue_1290(): - """Ensure isort doesn't added unecessary blank lines above nested imports. - See: https://github.com/timothycrosley/isort/issues/1290 - """ - test_input = '''from typing import TYPE_CHECKING - -# Special imports -from special import thing - -if TYPE_CHECKING: - # Special imports - from special import another_thing - - -def func(): - """Docstring""" - - # Special imports - from special import something_else - return -''' - assert ( - isort.code( - test_input, - import_heading_special="Special imports", - known_special=["special"], - sections=["FUTURE", "STDLIB", "THIRDPARTY", "SPECIAL", "FIRSTPARTY", "LOCALFOLDER"], - ) - == test_input - ) - - -def test_add_imports_shouldnt_make_isort_unusable_issue_1297(): - """Test to ensure add imports doesn't cause any unexpected behaviour when combined with check - See: https://github.com/timothycrosley/isort/issues/1297 - """ - assert isort.check_code( - """from __future__ import unicode_literals - -from os import path -""", - add_imports={"from __future__ import unicode_literals"}, - ) - - -def test_no_extra_lines_for_imports_in_functions_issue_1277(): - """Test to ensure isort doesn't introduce extra blank lines for imports within function. - See: https://github.com/timothycrosley/isort/issues/1277 - """ - test_input = """ -def main(): - import time - - import sys -""" - expected_output = """ -def main(): - import sys - import time -""" - assert isort.code(isort.code(isort.code(test_input))) == expected_output - - -def test_no_extra_blank_lines_in_methods_issue_1293(): - """Test to ensure isort isn't introducing extra lines in methods that contain imports - See: https://github.com/timothycrosley/isort/issues/1293 - """ - test_input = """ - -class Something(object): - def on_email_deleted(self, email): - from hyperkitty.tasks import rebuild_thread_cache_new_email - - # update or cleanup thread # noqa: E303 (isort issue) - if self.emails.count() == 0: - ... -""" - assert isort.code(test_input) == test_input - assert isort.code(test_input, lines_after_imports=2) == test_input - - -def test_force_single_line_shouldnt_remove_preceding_comment_lines_issue_1296(): - """Tests to ensure force_single_line setting doesn't result in lost comments. - See: https://github.com/timothycrosley/isort/issues/1296 - """ - test_input = """ -# A comment -# A comment - -# Oh no, I'm gone -from moo import foo -""" - # assert isort.code(test_input) == test_input - assert isort.code(test_input, force_single_line=True) == test_input - - -def test_ensure_new_line_before_comments_mixed_with_ensure_newline_before_comments_1295(): - """Tests to ensure that the black profile can be used in conjunction with - force_sort_within_sections. - - See: https://github.com/timothycrosley/isort/issues/1295 - """ - test_input = """ -from openzwave.group import ZWaveGroup -from openzwave.network import ZWaveNetwork - -# pylint: disable=import-error -from openzwave.option import ZWaveOption -""" - assert isort.code(test_input, profile="black") == test_input - assert isort.code(test_input, profile="black", force_sort_within_sections=True) == test_input - - -def test_trailing_comma_doesnt_introduce_broken_code_with_comment_and_wrap_issue_1302(): - """Tests to assert the combination of include_trailing_comma and a wrapped line doesnt break. - See: https://github.com/timothycrosley/isort/issues/1302. - """ - assert ( - isort.code( - """ -from somewhere import very_very_very_very_very_very_long_symbol # some comment -""", - line_length=50, - include_trailing_comma=True, - ) - == """ -from somewhere import \\ - very_very_very_very_very_very_long_symbol # some comment -""" - ) - - -def test_ensure_sre_parse_is_identified_as_stdlib_issue_1304(): - """Ensure sre_parse is idenified as STDLIB. - See: https://github.com/timothycrosley/isort/issues/1304. - """ - assert isort.place_module("sre_parse") == isort.place_module("sre") == isort.settings.STDLIB - - -def test_add_imports_shouldnt_move_lower_comments_issue_1300(): - """Ensure add_imports doesn't move comments immediately below imports. - See:: https://github.com/timothycrosley/isort/issues/1300. - """ - test_input = """from __future__ import unicode_literals - -from os import path - -# A comment for a constant -ANSWER = 42 -""" - assert isort.code(test_input, add_imports=["from os import path"]) == test_input - - -def test_windows_newline_issue_1277(): - """Test to ensure windows new lines are correctly handled within indented scopes. - See: https://github.com/timothycrosley/isort/issues/1277 - """ - assert ( - isort.code("\ndef main():\r\n import time\r\n\n import sys\r\n") - == "\ndef main():\r\n import sys\r\n import time\r\n" - ) - - -def test_windows_newline_issue_1278(): - """Test to ensure windows new lines are correctly handled within indented scopes. - See: https://github.com/timothycrosley/isort/issues/1278 - """ - assert isort.check_code( - "\ntry:\r\n import datadog_agent\r\n\r\n " - "from ..log import CheckLoggingAdapter, init_logging\r\n\r\n init_logging()\r\n" - "except ImportError:\r\n pass\r\n" - ) - - -def test_check_never_passes_with_indented_headings_issue_1301(): - """Test to ensure that test can pass even when there are indented headings. - See: https://github.com/timothycrosley/isort/issues/1301 - """ - assert isort.check_code( - """ -try: - # stdlib - import logging - from os import abc, path -except ImportError: - pass -""", - import_heading_stdlib="stdlib", - ) - - -def test_isort_shouldnt_fail_on_long_from_with_dot_issue_1190(): - """Test to ensure that isort will correctly handle formatting a long from import that contains - a dot. - See: https://github.com/timothycrosley/isort/issues/1190 - """ - assert ( - isort.code( - """ -from this_is_a_very_long_import_statement.that_will_occur_across_two_lines\\ - .when_the_line_length.is_only_seventynine_chars import ( - function1, - function2, -) - """, - line_length=79, - multi_line_output=3, - ) - == """ -from this_is_a_very_long_import_statement.that_will_occur_across_two_lines""" - """.when_the_line_length.is_only_seventynine_chars import ( - function1, - function2 -) -""" - ) - - -def test_isort_shouldnt_add_extra_new_line_when_fass_and_n_issue_1315(): - """Test to ensure isort doesnt add a second extra new line when combining --fss and -n options. - See: https://github.com/timothycrosley/isort/issues/1315 - """ - assert isort.check_code( - """import sys - -# Comment canary -from . import foo -""", - ensure_newline_before_comments=True, # -n - force_sort_within_sections=True, # -fss - show_diff=True, # for better debugging in the case the test case fails. - ) - - assert ( - isort.code( - """ -from . import foo -# Comment canary -from .. import foo -""", - ensure_newline_before_comments=True, - force_sort_within_sections=True, - ) - == """ -from . import foo - -# Comment canary -from .. import foo -""" - ) - - -def test_isort_doesnt_rewrite_import_with_dot_to_from_import_issue_1280(): - """Test to ensure isort doesn't rewrite imports in the from of import y.x into from y import x. - This is because they are not technically fully equivalent to eachother and can introduce broken - behaviour. - See: https://github.com/timothycrosley/isort/issues/1280 - """ - assert isort.check_code( - """ - import test.module - import test.module as m - from test import module - from test import module as m - """, - show_diff=True, - ) - - -def test_isort_shouldnt_introduce_extra_lines_with_fass_issue_1322(): - """Tests to ensure isort doesn't introduce extra lines when used with fass option. - See: https://github.com/timothycrosley/isort/issues/1322 - """ - assert ( - isort.code( - """ - import logging - -# Comment canary -from foo import bar -import quux -""", - force_sort_within_sections=True, - ensure_newline_before_comments=True, - ) - == """ - import logging - -# Comment canary -from foo import bar -import quux -""" - ) - - -def test_comments_should_cause_wrapping_on_long_lines_black_mode_issue_1219(): - """Tests to ensure if isort encounters a single import line which is made too long with a comment - it is wrapped when using black profile. - See: https://github.com/timothycrosley/isort/issues/1219 - """ - assert isort.check_code( - """ -from many_stop_words import ( - get_stop_words as get_base_stopwords, # extended list of stop words, also for en -) -""", - show_diff=True, - profile="black", - ) - - -def test_comment_blocks_should_stay_associated_without_extra_lines_issue_1156(): - """Tests to ensure isort doesn't add an extra line when there are large import blocks - or otherwise warp the intent. - See: https://github.com/timothycrosley/isort/issues/1156 - """ - assert ( - isort.code( - """from top_level_ignored import config # isort:skip -#################################### -# COMMENT BLOCK SEPARATING THESE # -#################################### -from ast import excepthandler -import logging -""" - ) - == """from top_level_ignored import config # isort:skip -import logging -#################################### -# COMMENT BLOCK SEPARATING THESE # -#################################### -from ast import excepthandler -""" - ) - - -def test_comment_shouldnt_be_duplicated_with_fass_enabled_issue_1329(): - """Tests to ensure isort doesn't duplicate comments when imports occur with comment on top, - immediately after large comment blocks. - See: https://github.com/timothycrosley/isort/pull/1329/files. - """ - assert isort.check_code( - """''' -Multi-line docstring -''' -# Comment for A. -import a -# Comment for B - not A! -import b -""", - force_sort_within_sections=True, - show_diff=True, - ) - - -def test_wrap_mode_equal_to_line_length_with_indendet_imports_issue_1333(): - assert isort.check_code( - """ -import a -import b - - -def function(): - import a as b - import c as d -""", - line_length=17, - wrap_length=17, - show_diff=True, - ) - - -def test_isort_skipped_nested_imports_issue_1339(): - """Ensure `isort:skip are honored in nested imports. - See: https://github.com/timothycrosley/isort/issues/1339. - """ - assert isort.check_code( - """ - def import_test(): - from os ( # isort:skip - import path - ) - """, - show_diff=True, - ) - - -def test_windows_diff_too_large_misrepresentative_issue_1348(test_path): - """Ensure isort handles windows files correctly when it come to producing a diff with --diff. - See: https://github.com/timothycrosley/isort/issues/1348 - """ - diff_output = StringIO() - isort.file(test_path / "example_crlf_file.py", show_diff=diff_output) - diff_output.seek(0) - assert diff_output.read().endswith( - "-1,5 +1,5 @@\n+import a\r\n import b\r\n" "-import a\r\n \r\n \r\n def func():\r\n" - ) - - -def test_combine_as_does_not_lose_comments_issue_1321(): - """Test to ensure isort doesn't lose comments when --combine-as is used. - See: https://github.com/timothycrosley/isort/issues/1321 - """ - test_input = """ -from foo import * # noqa -from foo import bar as quux # other -from foo import x as a # noqa - -import operator as op # op comment -import datetime as dtime # dtime comment - -from datetime import date as d # dcomm -from datetime import datetime as dt # dtcomm -""" - - expected_output = """ -import datetime as dtime # dtime comment -import operator as op # op comment -from datetime import date as d, datetime as dt # dcomm; dtcomm - -from foo import * # noqa -from foo import bar as quux, x as a # other; noqa -""" - - assert isort.code(test_input, combine_as_imports=True) == expected_output - - -def test_combine_as_does_not_lose_comments_issue_1381(): - """Test to ensure isort doesn't lose comments when --combine-as is used. - See: https://github.com/timothycrosley/isort/issues/1381 - """ - test_input = """ -from smtplib import SMTPConnectError, SMTPNotSupportedError # important comment -""" - assert "# important comment" in isort.code(test_input, combine_as_imports=True) - - test_input = """ -from appsettings import AppSettings, ObjectSetting, StringSetting # type: ignore -""" - assert "# type: ignore" in isort.code(test_input, combine_as_imports=True) diff -Nru isort-5.4.2/tests/test_settings.py isort-5.6.4/tests/test_settings.py --- isort-5.4.2/tests/test_settings.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/tests/test_settings.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -import os -import sys -from pathlib import Path - -import pytest - -from isort import exceptions, settings -from isort.settings import Config - - -class TestConfig: - instance = Config() - - def test_init(self): - assert Config() - - def test_known_settings(self): - assert Config(known_third_party=["one"]).known_third_party == frozenset({"one"}) - assert Config(known_thirdparty=["two"]).known_third_party == frozenset({"two"}) - assert Config( - known_third_party=["one"], known_thirdparty=["two"] - ).known_third_party == frozenset({"one"}) - - def test_invalid_settings_path(self): - with pytest.raises(exceptions.InvalidSettingsPath): - Config(settings_path="this_couldnt_possibly_actually_exists/could_it") - - def test_invalid_pyversion(self): - with pytest.raises(ValueError): - Config(py_version=10) - - def test_invalid_profile(self): - with pytest.raises(exceptions.ProfileDoesNotExist): - Config(profile="blackandwhitestylemixedwithpep8") - - def test_is_skipped(self): - assert Config().is_skipped(Path("C:\\path\\isort.py")) - assert Config(skip=["/path/isort.py"]).is_skipped(Path("C:\\path\\isort.py")) - - def test_is_supported_filetype(self): - assert self.instance.is_supported_filetype("file.py") - assert self.instance.is_supported_filetype("file.pyi") - assert self.instance.is_supported_filetype("file.pyx") - assert not self.instance.is_supported_filetype("file.pyc") - assert not self.instance.is_supported_filetype("file.txt") - assert not self.instance.is_supported_filetype("file.pex") - - def test_is_supported_filetype_ioerror(self, tmpdir): - does_not_exist = tmpdir.join("fake.txt") - assert not self.instance.is_supported_filetype(str(does_not_exist)) - - def test_is_supported_filetype_shebang(self, tmpdir): - path = tmpdir.join("myscript") - path.write("#!/usr/bin/env python\n") - assert self.instance.is_supported_filetype(str(path)) - - def test_is_supported_filetype_editor_backup(self, tmpdir): - path = tmpdir.join("myscript~") - path.write("#!/usr/bin/env python\n") - assert not self.instance.is_supported_filetype(str(path)) - - def test_is_supported_filetype_defaults(self, tmpdir): - assert self.instance.is_supported_filetype(str(tmpdir.join("stub.pyi"))) - assert self.instance.is_supported_filetype(str(tmpdir.join("source.py"))) - assert self.instance.is_supported_filetype(str(tmpdir.join("source.pyx"))) - - def test_is_supported_filetype_configuration(self, tmpdir): - config = Config(supported_extensions=("pyx",), blocked_extensions=("py",)) - assert config.is_supported_filetype(str(tmpdir.join("stub.pyx"))) - assert not config.is_supported_filetype(str(tmpdir.join("stub.py"))) - - @pytest.mark.skipif( - sys.platform == "win32", reason="cannot create fifo file on Windows platform" - ) - def test_is_supported_filetype_fifo(self, tmpdir): - fifo_file = os.path.join(tmpdir, "fifo_file") - os.mkfifo(fifo_file) - assert not self.instance.is_supported_filetype(fifo_file) - - -def test_as_list(): - assert settings._as_list([" one "]) == ["one"] - assert settings._as_list("one,two") == ["one", "two"] - - -def test_find_config(tmpdir): - tmp_config = tmpdir.join(".isort.cfg") - - # can't find config if it has no relevant section - settings._find_config.cache_clear() - settings._get_config_data.cache_clear() - tmp_config.write_text( - """ -[section] -force_grid_wrap=true -""", - "utf8", - ) - assert not settings._find_config(str(tmpdir))[1] - - # or if it is malformed - settings._find_config.cache_clear() - settings._get_config_data.cache_clear() - tmp_config.write_text("""arstoyrsyan arienrsaeinrastyngpuywnlguyn354q^%$)(%_)@$""", "utf8") - assert not settings._find_config(str(tmpdir))[1] - - # can when it has either a file format, or generic relevant section - settings._find_config.cache_clear() - settings._get_config_data.cache_clear() - tmp_config.write_text( - """ -[isort] -force_grid_wrap=true -""", - "utf8", - ) - assert settings._find_config(str(tmpdir))[1] - - -def test_get_config_data(tmpdir): - test_config = tmpdir.join("test_config.editorconfig") - test_config.write_text( - """ -root = true - -[*.py] -indent_style=tab -indent_size=tab -force_grid_wrap=false -comment_prefix="text" -""", - "utf8", - ) - loaded_settings = settings._get_config_data(str(test_config), sections=("*.py",)) - assert loaded_settings - assert loaded_settings["comment_prefix"] == "text" - assert loaded_settings["force_grid_wrap"] == 0 - assert loaded_settings["indent"] == "\t" - assert str(tmpdir) in loaded_settings["source"] - - -def test_as_bool(): - assert settings._as_bool("TrUe") is True - assert settings._as_bool("true") is True - assert settings._as_bool("t") is True - assert settings._as_bool("FALSE") is False - assert settings._as_bool("faLSE") is False - assert settings._as_bool("f") is False - with pytest.raises(ValueError): - settings._as_bool("") - with pytest.raises(ValueError): - settings._as_bool("falsey") - with pytest.raises(ValueError): - settings._as_bool("truthy") diff -Nru isort-5.4.2/tests/test_setuptools_command.py isort-5.6.4/tests/test_setuptools_command.py --- isort-5.4.2/tests/test_setuptools_command.py 2020-07-29 04:24:06.101085000 +0000 +++ isort-5.6.4/tests/test_setuptools_command.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -from isort import setuptools_commands - - -def test_isort_command_smoke(src_dir): - """A basic smoke test for the setuptools_commands command""" - from distutils.dist import Distribution - - command = setuptools_commands.ISortCommand(Distribution()) - command.distribution.packages = ["isort"] - command.distribution.package_dir = {"isort": src_dir} - command.initialize_options() - command.finalize_options() - try: - command.run() - except BaseException: - pass - - command.distribution.package_dir = {"": "isort"} - command.distribution.py_modules = ["one", "two"] - command.initialize_options() - command.finalize_options() - command.run() - - command.distribution.packages = ["not_a_file"] - command.distribution.package_dir = {"not_a_file": src_dir} - command.initialize_options() - command.finalize_options() - try: - command.run() - except BaseException: - pass diff -Nru isort-5.4.2/tests/test_ticketed_features.py isort-5.6.4/tests/test_ticketed_features.py --- isort-5.4.2/tests/test_ticketed_features.py 2020-08-05 05:39:09.377879400 +0000 +++ isort-5.6.4/tests/test_ticketed_features.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,545 +0,0 @@ -"""A growing set of tests designed to ensure when isort implements a feature described in a ticket -it fully works as defined in the associated ticket. -""" -from functools import partial -from io import StringIO - -import pytest - -import isort -from isort import Config, exceptions - - -def test_semicolon_ignored_for_dynamic_lines_after_import_issue_1178(): - """Test to ensure even if a semicolon is in the decorator in the line following an import - the correct line spacing detrmination will be made. - See: https://github.com/timothycrosley/isort/issues/1178. - """ - assert isort.check_code( - """ -import pytest - - -@pytest.mark.skip(';') -def test_thing(): pass -""", - show_diff=True, - ) - - -def test_isort_automatically_removes_duplicate_aliases_issue_1193(): - """Test to ensure isort can automatically remove duplicate aliases. - See: https://github.com/timothycrosley/isort/issues/1281 - """ - assert isort.check_code("from urllib import parse as parse\n", show_diff=True) - assert ( - isort.code("from urllib import parse as parse", remove_redundant_aliases=True) - == "from urllib import parse\n" - ) - assert isort.check_code("import os as os\n", show_diff=True) - assert isort.code("import os as os", remove_redundant_aliases=True) == "import os\n" - - -def test_isort_enables_floating_imports_to_top_of_module_issue_1228(): - """Test to ensure isort will allow floating all non-indented imports to the top of a file. - See: https://github.com/timothycrosley/isort/issues/1228. - """ - assert ( - isort.code( - """ -import os - - -def my_function_1(): - pass - -import sys - -def my_function_2(): - pass -""", - float_to_top=True, - ) - == """ -import os -import sys - - -def my_function_1(): - pass - - -def my_function_2(): - pass -""" - ) - - assert ( - isort.code( - """ -import os - - -def my_function_1(): - pass - -# isort: split -import sys - -def my_function_2(): - pass -""", - float_to_top=True, - ) - == """ -import os - - -def my_function_1(): - pass - -# isort: split -import sys - - -def my_function_2(): - pass -""" - ) - - -assert ( - isort.code( - """ -import os - - -def my_function_1(): - pass - -# isort: off -import b -import a -def y(): - pass - -# isort: on -import b - -def my_function_2(): - pass - -import a -""", - float_to_top=True, - ) - == """ -import os - - -def my_function_1(): - pass - -# isort: off -import b -import a -def y(): - pass - -# isort: on -import a -import b - - -def my_function_2(): - pass -""" -) - - -def test_isort_provides_official_api_for_diff_output_issue_1335(): - """Test to ensure isort API for diff capturing allows capturing diff without sys.stdout. - See: https://github.com/timothycrosley/isort/issues/1335. - """ - diff_output = StringIO() - isort.code("import b\nimport a\n", show_diff=diff_output) - diff_output.seek(0) - assert "+import a" in diff_output.read() - - -def test_isort_warns_when_known_sections_dont_match_issue_1331(): - """Test to ensure that isort warns if there is a mismatch between sections and known_sections. - See: https://github.com/timothycrosley/isort/issues/1331. - """ - assert ( - isort.place_module( - "bot_core", - config=Config( - known_robotlocomotion_upstream=["bot_core"], - sections=["ROBOTLOCOMOTION_UPSTREAM", "THIRDPARTY"], - ), - ) - == "ROBOTLOCOMOTION_UPSTREAM" - ) - with pytest.warns(UserWarning): - assert ( - isort.place_module( - "bot_core", - config=Config( - known_robotlocomotion_upstream=["bot_core"], - sections=["ROBOTLOOMOTION_UPSTREAM", "THIRDPARTY"], - ), - ) - == "THIRDPARTY" - ) - with pytest.warns(UserWarning): - assert ( - isort.place_module( - "bot_core", config=Config(known_robotlocomotion_upstream=["bot_core"]) - ) - == "THIRDPARTY" - ) - - -def test_isort_supports_append_only_imports_issue_727(): - """Test to ensure isort provides a way to only add imports as an append. - See: https://github.com/timothycrosley/isort/issues/727. - """ - assert isort.code("", add_imports=["from __future__ import absolute_imports"]) == "" - assert ( - isort.code("import os", add_imports=["from __future__ import absolute_imports"]) - == """from __future__ import absolute_imports - -import os -""" - ) - - -def test_isort_supports_shared_profiles_issue_970(): - """Test to ensure isort provides a way to use shared profiles. - See: https://github.com/timothycrosley/isort/issues/970. - """ - assert isort.code("import a", profile="example") == "import a\n" # shared profile - assert isort.code("import a", profile="black") == "import a\n" # bundled profile - with pytest.raises(exceptions.ProfileDoesNotExist): - assert isort.code("import a", profile="madeupfake") == "import a\n" # non-existent profile - - -def test_isort_supports_formatting_plugins_issue_1353(): - """Test to ensure isort provides a way to create and share formatting plugins. - See: https://github.com/timothycrosley/isort/issues/1353. - """ - assert isort.code("import a", formatter="example") == "import a\n" # formatting plugin - with pytest.raises(exceptions.FormattingPluginDoesNotExist): - assert isort.code("import a", formatter="madeupfake") == "import a\n" # non-existent plugin - - -def test_treating_comments_as_code_issue_1357(): - """Test to ensure isort provides a way to treat comments as code. - See: https://github.com/timothycrosley/isort/issues/1357 - """ - assert ( - isort.code( - """# %% -import numpy as np -np.array([1,2,3]) - -# %% -import pandas as pd -pd.Series([1,2,3]) - -# %% -# This is a comment on the second import -import pandas as pd -pd.Series([4,5,6])""", - treat_comments_as_code=["# comment1", "# %%"], - ) - == """# %% -import numpy as np - -np.array([1,2,3]) - -# %% -import pandas as pd - -pd.Series([1,2,3]) - -# %% -# This is a comment on the second import -import pandas as pd - -pd.Series([4,5,6]) -""" - ) - assert ( - isort.code( - """# %% -import numpy as np -np.array([1,2,3]) - -# %% -import pandas as pd -pd.Series([1,2,3]) - -# %% -# This is a comment on the second import -import pandas as pd -pd.Series([4,5,6])""", - treat_comments_as_code=["# comment1", "# %%"], - float_to_top=True, - ) - == """# %% -import numpy as np -# This is a comment on the second import -import pandas as pd - -np.array([1,2,3]) - -# %% -pd.Series([1,2,3]) - -# %% -pd.Series([4,5,6]) -""" - ) - assert ( - isort.code( - """# %% -import numpy as np -np.array([1,2,3]) - -# %% -import pandas as pd -pd.Series([1,2,3]) - -# %% -# This is a comment on the second import -import pandas as pd -pd.Series([4,5,6])""", - treat_all_comments_as_code=True, - ) - == """# %% -import numpy as np - -np.array([1,2,3]) - -# %% -import pandas as pd - -pd.Series([1,2,3]) - -# %% -# This is a comment on the second import -import pandas as pd - -pd.Series([4,5,6]) -""" - ) - assert ( - isort.code( - """import b - -# these are special imports that have to do with installing X plugin -import c -import a -""", - treat_all_comments_as_code=True, - ) - == """import b - -# these are special imports that have to do with installing X plugin -import a -import c -""" - ) - - -def test_isort_literals_issue_1358(): - assert ( - isort.code( - """ -import x -import a - - -# isort: list -__all__ = ["b", "a", "b"] - -# isort: unique-list -__all__ = ["b", "a", "b"] - -# isort: tuple -__all__ = ("b", "a", "b") - -# isort: unique-tuple -__all__ = ("b", "a", "b") - -# isort: set -__all__ = {"b", "a", "b"} - - -def method(): - # isort: list - x = ["b", "a"] - - -# isort: dict -y = {"z": "z", "b": "b", "b": "c"}""" - ) - == """ -import a -import x - -# isort: list -__all__ = ['a', 'b', 'b'] - -# isort: unique-list -__all__ = ['a', 'b'] - -# isort: tuple -__all__ = ('a', 'b', 'b') - -# isort: unique-tuple -__all__ = ('a', 'b') - -# isort: set -__all__ = {'a', 'b'} - - -def method(): - # isort: list - x = ['a', 'b'] - - -# isort: dict -y = {'b': 'c', 'z': 'z'}""" - ) - assert ( - isort.code( - """ -import x -import a - - -# isort: list -__all__ = ["b", "a", "b"] - -# isort: unique-list -__all__ = ["b", "a", "b"] - -# isort: tuple -__all__ = ("b", "a", "b") - -# isort: unique-tuple -__all__ = ("b", "a", "b") - -# isort: set -__all__ = {"b", "a", "b"} - - -def method(): - # isort: list - x = ["b", "a"] - - -# isort: assignments -d = x -b = 2 -a = 1 - -# isort: dict -y = {"z": "z", "b": "b", "b": "c"}""", - formatter="example", - ) - == """ -import a -import x - -# isort: list -__all__ = ["a", "b", "b"] - -# isort: unique-list -__all__ = ["a", "b"] - -# isort: tuple -__all__ = ("a", "b", "b") - -# isort: unique-tuple -__all__ = ("a", "b") - -# isort: set -__all__ = {"a", "b"} - - -def method(): - # isort: list - x = ["a", "b"] - - -# isort: assignments -a = 1 -b = 2 -d = x - -# isort: dict -y = {"b": "c", "z": "z"}""" - ) - - -def test_isort_allows_setting_import_types_issue_1181(): - """Test to ensure isort provides a way to set the type of imports. - See: https://github.com/timothycrosley/isort/issues/1181 - """ - assert isort.code("from x import AA, Big, variable") == "from x import AA, Big, variable\n" - assert ( - isort.code("from x import AA, Big, variable", constants=["variable"]) - == "from x import AA, variable, Big\n" - ) - assert ( - isort.code("from x import AA, Big, variable", variables=["AA"]) - == "from x import Big, AA, variable\n" - ) - assert ( - isort.code( - "from x import AA, Big, variable", - constants=["Big"], - variables=["AA"], - classes=["variable"], - ) - == "from x import Big, variable, AA\n" - ) - - -def test_isort_enables_deduping_section_headers_issue_953(): - """isort should provide a way to only have identical import headings show up once. - See: https://github.com/timothycrosley/isort/issues/953 - """ - isort_code = partial( - isort.code, - config=Config( - import_heading_firstparty="Local imports.", - import_heading_localfolder="Local imports.", - dedup_headings=True, - known_first_party=["isort"], - ), - ) - - assert ( - isort_code("from . import something") - == """# Local imports. -from . import something -""" - ) - assert ( - isort_code( - """from isort import y - -from . import something""" - ) - == """# Local imports. -from isort import y - -from . import something -""" - ) - assert isort_code("import os") == "import os\n" diff -Nru isort-5.4.2/tests/test_wrap_modes.py isort-5.6.4/tests/test_wrap_modes.py --- isort-5.4.2/tests/test_wrap_modes.py 2020-07-29 04:24:06.101085000 +0000 +++ isort-5.6.4/tests/test_wrap_modes.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -from hypothesis_auto import auto_pytest_magic - -from isort import wrap_modes - -auto_pytest_magic(wrap_modes.grid, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic(wrap_modes.vertical, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic(wrap_modes.hanging_indent, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic(wrap_modes.vertical_hanging_indent, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic(wrap_modes.vertical_grid, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic(wrap_modes.vertical_grid_grouped, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic(wrap_modes.vertical_grid_grouped_no_comma, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic(wrap_modes.noqa, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic(wrap_modes.noqa, auto_allow_exceptions_=(ValueError,), comments=["NOQA"]) -auto_pytest_magic( - wrap_modes.vertical_prefix_from_module_import, auto_allow_exceptions_=(ValueError,) -) -auto_pytest_magic(wrap_modes.vertical_hanging_indent_bracket, auto_allow_exceptions_=(ValueError,)) -auto_pytest_magic( - wrap_modes.vertical_hanging_indent_bracket, - auto_allow_exceptions_=(ValueError,), - imports=["one", "two"], -) -auto_pytest_magic(wrap_modes.hanging_indent_with_parentheses, auto_allow_exceptions_=(ValueError,)) - - -def test_wrap_mode_interface(): - assert ( - wrap_modes._wrap_mode_interface("statement", [], "", "", 80, [], "", "", True, True) == "" - ) - - -def test_auto_saved(): - """hypothesis_auto tests cases that have been saved to ensure they run each test cycle""" - assert ( - wrap_modes.noqa( - **{ - "comment_prefix": "-\U000bf82c\x0c\U0004608f\x10%", - "comments": [], - "imports": [], - "include_trailing_comma": False, - "indent": "0\x19", - "line_length": -19659, - "line_separator": "\x15\x0b\U00086494\x1d\U000e00a2\U000ee216\U0006708a\x03\x1f", - "remove_comments": False, - "statement": "\U00092452", - "white_space": "\U000a7322\U000c20e3-\U0010eae4\x07\x14\U0007d486", - } - ) - == "\U00092452-\U000bf82c\x0c\U0004608f\x10% NOQA" - ) - assert ( - wrap_modes.noqa( - **{ - "comment_prefix": '\x12\x07\U0009e994🁣"\U000ae787\x0e', - "comments": ["\x00\U0001ae99\U0005c3e7\U0004d08e", "\x1e", "", ""], - "imports": ["*"], - "include_trailing_comma": True, - "indent": "", - "line_length": 31492, - "line_separator": "\U00071610\U0005bfbc", - "remove_comments": False, - "statement": "", - "white_space": "\x08\x01ⷓ\x16%\U0006cd8c", - } - ) - == '*\x12\x07\U0009e994🁣"\U000ae787\x0e \x00\U0001ae99\U0005c3e7\U0004d08e \x1e ' - ) diff -Nru isort-5.4.2/tests/test_wrap.py isort-5.6.4/tests/test_wrap.py --- isort-5.4.2/tests/test_wrap.py 2020-07-29 04:24:06.101085000 +0000 +++ isort-5.6.4/tests/test_wrap.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -from isort import wrap -from isort.settings import Config - - -def test_import_statement(): - assert wrap.import_statement("", [], []) == "" - assert ( - wrap.import_statement("from x import ", ["y"], [], config=Config(balanced_wrapping=True)) - == "from x import (y)" - ) - assert ( - wrap.import_statement("from long_import ", ["verylong"] * 10, []) - == """from long_import (verylong, verylong, verylong, verylong, verylong, verylong, - verylong, verylong, verylong, verylong)""" - )