From eb54f3c5a2f480d7eff42f52b8cef8c9588bad1e Mon Sep 17 00:00:00 2001 From: Kurt McKee Date: Wed, 5 Mar 2025 13:27:52 -0600 Subject: [PATCH] Run `slyp` against the code base This addresses several formatting issues, including: * Same-line str concatenation * Same-indentation-level multi-line str concatenation in function parameters and dict definitions * Unnecessary parentheses around str constants Although the initial work was automated, manual work was required to reflow multi-line concatenated strings to fit under the 100-character limit. --- isort/main.py | 316 +++++++++++------- isort/output.py | 6 +- scripts/build_config_option_docs.py | 20 +- .../integration/test_projects_using_isort.py | 6 +- tests/unit/test_isort.py | 140 ++++---- tests/unit/test_main.py | 4 +- tests/unit/test_regressions.py | 2 +- 7 files changed, 280 insertions(+), 214 deletions(-) diff --git a/isort/main.py b/isort/main.py index 5a6447d3..a55531c8 100644 --- a/isort/main.py +++ b/isort/main.py @@ -133,14 +133,15 @@ def _print_hard_fail( def _build_arg_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( - description="Sort Python import definitions alphabetically " - "within logical sections. Run with no arguments to see a quick " - "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://pycqa.github.io/isort/docs/upgrade_guides/5.0.0.html", + description=( + "Sort Python import definitions alphabetically within logical sections. " + "Run with no arguments to see a quick 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://pycqa.github.io/isort/docs/upgrade_guides/5.0.0.html" + ), add_help=False, # prevent help option from appearing in "optional arguments" group ) @@ -190,8 +191,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--dedup-headings", dest="dedup_headings", action="store_true", - help="Tells isort to only show an identical custom import heading comment once, even if" - " there are multiple sections with the comment set.", + help=( + "Tells isort to only show an identical custom import heading comment once, even if" + " there are multiple sections with the comment set." + ), ) general_group.add_argument( "-q", @@ -209,9 +212,11 @@ def _build_arg_parser() -> argparse.ArgumentParser: ) general_group.add_argument( "--overwrite-in-place", - help="Tells isort to overwrite in place using the same file handle. " - "Comes at a performance and memory usage penalty over its standard " - "approach but ensures all file flags and modes stay unchanged.", + help=( + "Tells isort to overwrite in place using the same file handle. " + "Comes at a performance and memory usage penalty over its standard " + "approach but ensures all file flags and modes stay unchanged." + ), dest="overwrite_in_place", action="store_true", ) @@ -232,8 +237,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--diff", dest="show_diff", action="store_true", - help="Prints a diff of all the changes isort would make to a file, instead of " - "changing it in place", + help=( + "Prints a diff of all the changes isort would make to a file, " + "instead of changing it in place." + ), ) general_group.add_argument( "-c", @@ -241,9 +248,12 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--check", action="store_true", dest="check", - help="Checks the file for unsorted / unformatted imports and prints them to the " - "command line without modifying the file. Returns 0 when nothing would change and " - "returns 1 when the file would be reformatted.", + help=( + "Checks the file for unsorted / unformatted imports " + "and prints them to the command line without modifying the file. " + "Returns 0 when nothing would change " + "and returns 1 when the file would be reformatted." + ), ) general_group.add_argument( "--ws", @@ -258,31 +268,39 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--settings-file", "--settings", dest="settings_path", - help="Explicitly set the settings path or file instead of auto determining " - "based on file location.", + help=( + "Explicitly set the settings path or file " + "instead of auto determining based on file location." + ), ) general_group.add_argument( "--cr", "--config-root", dest="config_root", - help="Explicitly set the config root for resolving all configs. When used " - "with the --resolve-all-configs flag, isort will look at all sub-folders " - "in this config root to resolve config files and sort files based on the " - "closest available config(if any)", + help=( + "Explicitly set the config root for resolving all configs. " + "When used with the --resolve-all-configs flag, " + "isort will look at all sub-folders in this config root to resolve config files " + "and sort files based on the closest available config (if any)." + ), ) general_group.add_argument( "--resolve-all-configs", dest="resolve_all_configs", action="store_true", - help="Tells isort to resolve the configs for all sub-directories " - "and sort files in terms of its closest config files.", + help=( + "Tells isort to resolve the configs for all sub-directories " + "and sort files in terms of its closest config files." + ), ) general_group.add_argument( "--profile", dest="profile", type=str, - help="Base profile type to use for configuration. " - f"Profiles include: {', '.join(profiles.keys())}. As well as any shared profiles.", + help=( + "Base profile type to use for configuration. " + f"Profiles include: {', '.join(profiles.keys())}. As well as any shared profiles." + ), ) general_group.add_argument( "--old-finders", @@ -338,26 +356,32 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--filter-files", dest="filter_files", action="store_true", - help="Tells isort to filter files even when they are explicitly passed in as " - "part of the CLI command.", + help=( + "Tells isort to filter files even when they are explicitly passed in as " + "part of the CLI command." + ), ) target_group.add_argument( "-s", "--skip", - help="Files that isort should skip over. If you want to skip multiple " - "files you should specify twice: --skip file1 --skip file2. Values can be " - "file names, directory names or file paths. To skip all files in a nested path " - "use --skip-glob.", + help=( + "Files that isort should skip over. If you want to skip multiple files " + "you should specify twice: --skip file1 --skip file2. " + "Values can be file names, directory names or file paths. " + "To skip all files in a nested path use --skip-glob." + ), dest="skip", action="append", ) target_group.add_argument( "--extend-skip", - help="Extends --skip to add additional files that isort should skip over. " - "If you want to skip multiple " - "files you should specify twice: --skip file1 --skip file2. Values can be " - "file names, directory names or file paths. To skip all files in a nested path " - "use --skip-glob.", + help=( + "Extends --skip to add additional files that isort should skip over. " + "If you want to skip multiple files you should specify twice: " + "--skip file1 --skip file2. " + "Values can be file names, directory names or file paths. " + "To skip all files in a nested path use --skip-glob." + ), dest="extend_skip", action="append", ) @@ -379,8 +403,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--skip-gitignore", action="store_true", dest="skip_gitignore", - help="Treat project as a git repository and ignore files listed in .gitignore." - "\nNOTE: This requires git to be installed and accessible from the same shell as isort.", + help=( + "Treat project as a git repository and ignore files listed in .gitignore." + "\nNOTE: This requires git to be installed and accessible from the same shell as isort." + ), ) target_group.add_argument( "--ext", @@ -419,16 +445,20 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--add-import", dest="add_imports", action="append", - help="Adds the specified import line to all files, " - "automatically determining correct placement.", + help=( + "Adds the specified import line to all files, " + "automatically determining correct placement." + ), ) output_group.add_argument( "--append", "--append-only", dest="append_only", action="store_true", - help="Only adds the imports specified in --add-import if the file" - " contains existing imports.", + help=( + "Only adds the imports specified in --add-import if the file" + " contains existing imports." + ), ) output_group.add_argument( "--af", @@ -448,12 +478,14 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--float-to-top", 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 (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.", + help=( + "Causes all non-indented imports to float to the top of the file having its imports " + "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." + ), ) output_group.add_argument( "--dont-float-to-top", @@ -473,8 +505,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--combine-star", dest="combine_star", action="store_true", - help="Ensures that if a star import is present, " - "nothing else is imported from that namespace.", + help=( + "Ensures that if a star import is present, " + "nothing else is imported from that namespace." + ), ) output_group.add_argument( "-e", @@ -488,8 +522,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--from-first", dest="from_first", action="store_true", - help="Switches the typical ordering preference, " - "showing from imports first then straight ones.", + help=( + "Switches the typical ordering preference, " + "showing from imports first then straight ones." + ), ) output_group.add_argument( "--fgw", @@ -498,9 +534,11 @@ def _build_arg_parser() -> argparse.ArgumentParser: const=2, type=int, dest="force_grid_wrap", - 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.", + 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." + ), ) output_group.add_argument( "-i", @@ -522,8 +560,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--le", "--line-ending", dest="line_ending", - help="Forces line endings to the specified value. " - "If not set, values will be guessed per-file.", + help=( + "Forces line endings to the specified value. " + "If not set, values will be guessed per-file." + ), ) output_group.add_argument( "--ls", @@ -535,8 +575,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: output_group.add_argument( "--lss", "--length-sort-straight", - help="Sort straight imports by their string length. Similar to `length_sort` " - "but applies only to straight imports and doesn't affect from imports.", + 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", ) @@ -547,10 +589,12 @@ def _build_arg_parser() -> argparse.ArgumentParser: choices=list(WrapModes.__members__.keys()) + [str(mode.value) for mode in WrapModes.__members__.values()], type=str, - help="Multi line output (0-grid, 1-vertical, 2-hanging, 3-vert-hanging, 4-vert-grid, " - "5-vert-grid-grouped, 6-deprecated-alias-for-5, 7-noqa, " - "8-vertical-hanging-indent-bracket, 9-vertical-prefix-from-module-import, " - "10-hanging-indent-with-parentheses).", + help=( + "Multi line output (0-grid, 1-vertical, 2-hanging, 3-vert-hanging, 4-vert-grid, " + "5-vert-grid-grouped, 6-deprecated-alias-for-5, 7-noqa, " + "8-vertical-hanging-indent-bracket, 9-vertical-prefix-from-module-import, " + "10-hanging-indent-with-parentheses)." + ), ) output_group.add_argument( "-n", @@ -564,34 +608,40 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--no-inline-sort", dest="no_inline_sort", action="store_true", - help="Leaves `from` imports with multiple imports 'as-is' " - "(e.g. `from foo import a, c ,b`).", + help=( + "Leaves `from` imports with multiple imports 'as-is' " + "(e.g. `from foo import a, c ,b`)." + ), ) output_group.add_argument( "--ot", "--order-by-type", dest="order_by_type", action="store_true", - help="Order imports by type, which is determined by case, in addition to alphabetically.\n" - "\n**NOTE**: type here refers to the implied type from the import name capitalization.\n" - ' isort does not do type introspection for the imports. These "types" are simply: ' - "CONSTANT_VARIABLE, CamelCaseClass, variable_or_function. If your project follows PEP8" - " or a related coding standard and has many imports this is a good default, otherwise you " - "likely will want to turn it off. From the CLI the `--dont-order-by-type` option will turn " - "this off.", + help=( + "Order imports by type, which is determined by case, in addition to alphabetically.\n\n" + "**NOTE**: type here refers to the implied type from the import name capitalization.\n" + 'isort does not do type introspection for the imports. These "types" are simply: ' + "CONSTANT_VARIABLE, CamelCaseClass, variable_or_function. " + "If your project follows PEP8or a related coding standard and has many imports " + "this is a good default, otherwise you likely will want to turn it off. " + "From the CLI the `--dont-order-by-type` option will turn this off." + ), ) output_group.add_argument( "--dt", "--dont-order-by-type", dest="dont_order_by_type", action="store_true", - help="Don't order imports by type, which is determined by case, in addition to " - "alphabetically.\n\n" - "**NOTE**: type here refers to the implied type from the import name capitalization.\n" - ' isort does not do type introspection for the imports. These "types" are simply: ' - "CONSTANT_VARIABLE, CamelCaseClass, variable_or_function. If your project follows PEP8" - " or a related coding standard and has many imports this is a good default. You can turn " - "this on from the CLI using `--order-by-type`.", + help=( + "Don't order imports by type, which is determined by case, in addition to " + "alphabetically.\n\n" + "**NOTE**: type here refers to the implied type from the import name capitalization.\n" + 'isort does not do type introspection for the imports. These "types" are simply: ' + "CONSTANT_VARIABLE, CamelCaseClass, variable_or_function. If your project follows PEP8" + " or a related coding standard and has many imports this is a good default. " + "You can turn this on from the CLI using `--order-by-type`." + ), ) output_group.add_argument( "--rr", @@ -609,8 +659,11 @@ def _build_arg_parser() -> argparse.ArgumentParser: output_group.add_argument( "--sort-order", dest="sort_order", - help="Specify sorting function. Can be built in (natural[default] = force numbers " - "to be sequential, native = Python's built-in sorted function) or an installable plugin.", + help=( + "Specify sorting function. Can be built in (natural[default] = force numbers " + "to be sequential, native = Python's built-in sorted function) " + "or an installable plugin." + ), ) inline_args_group.add_argument( "--sl", @@ -638,9 +691,12 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--use-parentheses", dest="use_parentheses", action="store_true", - help="Use parentheses for line continuation on length limit instead of slashes." - " **NOTE**: This is separate from wrap modes, and only affects how individual lines that " - " are too long get continued, not sections of multiple imports.", + help=( + "Use parentheses for line continuation on length limit instead of slashes. " + "**NOTE**: This is separate from wrap modes, " + "and only affects how individual lines that are too long get continued, " + "not sections of multiple imports." + ), ) output_group.add_argument( "-l", @@ -656,8 +712,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--wrap-length", dest="wrap_length", type=int, - help="Specifies how long lines that are wrapped should be, if not set line_length is used." - "\nNOTE: wrap_length must be LOWER than or equal to line_length.", + help=( + "Specifies how long lines that are wrapped should be, if not set line_length is used." + "\nNOTE: wrap_length must be LOWER than or equal to line_length." + ), ) output_group.add_argument( "--case-sensitive", @@ -734,9 +792,11 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--os", dest="only_sections", action="store_true", - help="Causes imports to be sorted based on their sections like STDLIB, THIRDPARTY, etc. " - "Within sections, the imports are ordered by their import style and the imports with " - "the same style maintain their relative positions.", + help=( + "Causes imports to be sorted based on their sections like STDLIB, THIRDPARTY, etc. " + "Within sections, the imports are ordered by their import style and the imports with " + "the same style maintain their relative positions." + ), ) section_group.add_argument( "--ds", @@ -757,25 +817,31 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--force-sort-within-sections", action="store_true", dest="force_sort_within_sections", - help="Don't sort straight-style imports (like import sys) before from-style imports " - "(like from itertools import groupby). Instead, sort the imports by module, " - "independent of import style.", + help=( + "Don't sort straight-style imports (like import sys) before from-style imports " + "(like from itertools import groupby). Instead, sort the imports by module, " + "independent of import style." + ), ) section_group.add_argument( "--hcss", "--honor-case-in-force-sorted-sections", action="store_true", dest="honor_case_in_force_sorted_sections", - help="Honor `--case-sensitive` when `--force-sort-within-sections` is being used. " - "Without this option set, `--order-by-type` decides module name ordering too.", + help=( + "Honor `--case-sensitive` when `--force-sort-within-sections` is being used. " + "Without this option set, `--order-by-type` decides module name ordering too." + ), ) section_group.add_argument( "--srss", "--sort-relative-in-force-sorted-sections", action="store_true", dest="sort_relative_in_force_sorted_sections", - help="When using `--force-sort-within-sections`, sort relative imports the same " - "way as they are sorted when not using that setting.", + help=( + "When using `--force-sort-within-sections`, sort relative imports the same " + "way as they are sorted when not using that setting." + ), ) section_group.add_argument( "--fass", @@ -796,8 +862,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--csi", dest="combine_straight_imports", action="store_true", - help="Combines all the bare straight imports of the same section in a single line. " - "Won't work with sections which have 'as' imports", + help=( + "Combines all the bare straight imports of the same section in a single line. " + "Won't work with sections which have 'as' imports" + ), ) section_group.add_argument( "--nlb", @@ -811,9 +879,11 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--src-path", dest="src_paths", action="append", - help="Add an explicitly defined source path " - "(modules within src paths have their imports automatically categorized as first_party)." - " Glob expansion (`*` and `**`) is supported for this option.", + help=( + "Add an explicitly defined source path (modules within src paths " + "have their imports automatically categorized as first_party). " + "Glob expansion (`*` and `**`) is supported for this option." + ), ) section_group.add_argument( "-b", @@ -833,12 +903,14 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--future", dest="known_future_library", action="append", - 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 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.", + 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 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." + ), ) section_group.add_argument( "-o", @@ -858,8 +930,10 @@ def _build_arg_parser() -> argparse.ArgumentParser: "--known-local-folder", dest="known_local_folder", action="append", - help="Force isort to recognize a module as being a local folder. " - "Generally, this is reserved for relative imports (from . import module).", + help=( + "Force isort to recognize a module as being a local folder. " + "Generally, this is reserved for relative imports (from . import module)." + ), ) section_group.add_argument( "--virtual-env", @@ -877,11 +951,13 @@ def _build_arg_parser() -> argparse.ArgumentParser: action="store", dest="py_version", choices=(*tuple(VALID_PY_TARGETS), "auto"), - 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 " - "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.", + 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 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." + ), ) # deprecated options @@ -975,8 +1051,10 @@ def identify_imports_main( argv: Optional[Sequence[str]] = None, stdin: Optional[TextIOWrapper] = None ) -> None: parser = argparse.ArgumentParser( - description="Get all import definitions from a given file." - "Use `-` as the first argument to represent stdin." + description=( + "Get all import definitions from a given file." + "Use `-` as the first argument to represent stdin." + ) ) parser.add_argument( "files", nargs="+", help="One or more Python source files that need their imports sorted." diff --git a/isort/output.py b/isort/output.py index 65a6ff7e..5740080e 100644 --- a/isort/output.py +++ b/isort/output.py @@ -338,7 +338,7 @@ def _with_from_imports( ) if comment: single_import_line += ( - f"{(comments and ';') or config.comment_prefix} " f"{comment}" + f"{(comments and ';') or config.comment_prefix} {comment}" ) if from_import in as_imports: if ( @@ -467,7 +467,7 @@ def _with_from_imports( comment_prefix=config.comment_prefix, ) single_import_line += ( - f"{(use_comments and ';') or config.comment_prefix} " f"{comment}" + f"{(use_comments and ';') or config.comment_prefix} {comment}" ) output.append(wrap.line(single_import_line, parsed.line_separator, config)) @@ -486,7 +486,7 @@ def _with_from_imports( ) import_statement = with_comments( comments, - import_start + (", ").join(from_import_section), + import_start + ", ".join(from_import_section), removed=config.ignore_comments, comment_prefix=config.comment_prefix, ) diff --git a/scripts/build_config_option_docs.py b/scripts/build_config_option_docs.py index 3afd8e15..ebe5d54e 100755 --- a/scripts/build_config_option_docs.py +++ b/scripts/build_config_option_docs.py @@ -109,17 +109,23 @@ def __str__(self): "length_sort_sections": "Sort the given sections by length", "forced_separate": "Force certain sub modules to show separately", "sections": "What sections isort should display imports for and in what order", - "known_other": "known_OTHER is how imports of custom sections are defined. " - "OTHER is a placeholder for the custom section name.", - "comment_prefix": "Allows customizing how isort prefixes comments that it adds or modifies on import lines" - "Generally ` #` (two spaces before a pound symbol) is use, though one space is also common.", + "known_other": ( + "known_OTHER is how imports of custom sections are defined. " + "OTHER is a placeholder for the custom section name." + ), + "comment_prefix": ( + "Allows customizing how isort prefixes comments that it adds or modifies on import lines" + "Generally ` #` (two spaces before a pound symbol) is use, though one space is also common." + ), "lines_before_imports": "The number of blank lines to place before imports. -1 for automatic determination", "lines_after_imports": "The number of blank lines to place after imports. -1 for automatic determination", "lines_between_sections": "The number of lines to place between sections", "lines_between_types": "The number of lines to place between direct and from imports", - "lexicographical": "Lexicographical order is strictly alphabetical order. " - "For example by default isort will sort `1, 10, 2` into `1, 2, 10` - but with " - "lexicographical sorting enabled it will remain `1, 10, 2`.", + "lexicographical": ( + "Lexicographical order is strictly alphabetical order. " + "For example by default isort will sort `1, 10, 2` into `1, 2, 10` - but with " + "lexicographical sorting enabled it will remain `1, 10, 2`." + ), "ignore_comments": "If enabled, isort will strip comments that exist within import lines.", "constants": "An override list of tokens to always recognize as a CONSTANT for order_by_type regardless of casing.", "classes": "An override list of tokens to always recognize as a Class for order_by_type regardless of casing.", diff --git a/tests/integration/test_projects_using_isort.py b/tests/integration/test_projects_using_isort.py index 61f66e7e..cdfd15e2 100644 --- a/tests/integration/test_projects_using_isort.py +++ b/tests/integration/test_projects_using_isort.py @@ -29,8 +29,10 @@ def run_isort(arguments: Generator[str, None, None] | Sequence[str]): @pytest.mark.xfail( - reason="Project is incorrectly formatted after PR #2236, should be fixed " - "after a release and the project formatting again." + reason=( + "Project is incorrectly formatted after PR #2236, should be fixed " + "after a release and the project formatting again." + ) ) def test_django(tmpdir): git_clone("https://github.com/django/django.git", tmpdir) diff --git a/tests/unit/test_isort.py b/tests/unit/test_isort.py index e72f1fee..d9ebcf87 100644 --- a/tests/unit/test_isort.py +++ b/tests/unit/test_isort.py @@ -75,7 +75,7 @@ def test_happy_path() -> None: 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" + "import os\nimport sys\n\nimport django.settings\n\nimport myproject.test\n" ) @@ -111,14 +111,12 @@ def test_correct_space_between_imports() -> None: """ 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") + 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_input_decorator = "import sys\n@my_decorator\ndef 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" + "import sys\n\n\n@my_decorator\ndef my_method():\n print('hello world')\n" ) test_input_class = "import sys\nclass MyClass(object):\n pass\n" @@ -924,18 +922,18 @@ def test_add_imports() -> None: 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" + "from __future__ import print_function\n\n\nclass 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 == ("") + 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") + assert test_output == "import lib4\n" def test_remove_imports() -> None: @@ -945,9 +943,7 @@ def test_remove_imports() -> None: 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_input = "import lib6\nimport lib2\nimport lib5\nimport lib1\nfrom lib8 import a" test_output = isort.code( code=test_input, remove_imports=["import lib2", "import lib6", "from lib8 import a"] ) @@ -992,7 +988,7 @@ def test_quotes_in_file() -> None: 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') + 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 @@ -1108,14 +1104,14 @@ def test_default_section() -> None: 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" + "import os\nimport sys\n\nimport django.settings\n\nimport 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" + "import myproject.test\nimport os\nimport sys\n\nimport django.settings\n" ) @@ -1223,9 +1219,7 @@ def test_force_single_line_imports() -> None: "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_input = "from third_party import lib_a, lib_b, lib_d\nfrom 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 ) @@ -1249,9 +1243,7 @@ def test_force_single_line_long_imports() -> None: 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_input = "from third_party import lib_a, lib_b, lib_d\nfrom third_party.lib_c import lib1\n" test_output = isort.code( code=test_input, multi_line_output=WrapModes.GRID, @@ -1616,7 +1608,7 @@ def test_relative_import_with_space() -> None: with a space. """ test_input = "from ... fields.sproqet import SproqetCollection" - assert isort.code(test_input) == ("from ...fields.sproqet import SproqetCollection\n") + 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 @@ -1628,7 +1620,7 @@ def test_relative_import_with_space() -> None: 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") + assert isort.code(test_input) == "from pkg import more_stuff, other_suff, stuff\n" # test again with a custom configuration custom_configuration: dict[str, Any] = { @@ -1639,7 +1631,7 @@ def test_multiline_import() -> None: "forced_separate": "asdf", } expected_output = ( - "from pkg import more_stuff\n" "from pkg import other_suff\n" "from pkg import stuff\n" + "from pkg import more_stuff\nfrom pkg import other_suff\nfrom pkg import stuff\n" ) assert isort.code(test_input, **custom_configuration) == expected_output @@ -1648,14 +1640,14 @@ 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") + assert output == "from os import getuid\n\nprint getuid()\n" def test_atomic_mode() -> None: """With atomic mode isort should be able to automatically detect and stop syntax errors""" # 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") + 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 @@ -1725,7 +1717,7 @@ def test_custom_lines_before_import_section() -> None: ln = "\n" # default case is no line added before the import - assert isort.code(test_input) == (test_input) + assert isort.code(test_input) == test_input # test again with a custom number of lines before the import section assert isort.code(test_input, lines_before_imports=2) == 2 * ln + test_input @@ -1747,30 +1739,28 @@ def test_custom_lines_after_import_section() -> None: 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") + 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") + 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") + 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") + 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") + 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" - ) + test_input = "from a import b\n# comment should be ignored\ndef my_function():\n pass\n" assert isort.code(test_input) == ( "from a import b\n" "\n" @@ -1802,7 +1792,7 @@ def test_smart_lines_after_import_section() -> None: # 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" + "from a import b\n" "\n" 'X = """test\n' '"""\n' "def my_function():\n pass\n" ) @@ -1866,11 +1856,9 @@ def test_keep_comments() -> None: ) # 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" - ) + test_input = "from a import b # My Comment1\nfrom a import c # My Comment2\nfrom 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" + "from a import b # My Comment1\nfrom a import c # My Comment2\nfrom a import d\n" ) # Test case where imports with comments will be beyond line length limit @@ -1916,8 +1904,8 @@ def test_multiline_split_on_dot() -> None: 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") + 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: @@ -1929,7 +1917,7 @@ def test_include_trailing_comma() -> None: include_trailing_comma=True, ) assert test_output_grid == ( - "from third_party import (lib1, lib2,\n" " lib3, lib4,)\n" + "from third_party import (lib1, lib2,\n lib3, lib4,)\n" ) test_output_vertical = isort.code( @@ -1952,7 +1940,7 @@ def test_include_trailing_comma() -> None: include_trailing_comma=True, ) assert test_output_vertical_indent == ( - "from third_party import (\n" " lib1,\n" " lib2,\n" " lib3,\n" " lib4,\n" ")\n" + "from third_party import (\n lib1,\n lib2,\n lib3,\n lib4,\n)\n" ) test_output_vertical_grid = isort.code( @@ -2136,7 +2124,7 @@ def test_same_line_statements() -> None: contains multiple statements including an import """ test_input = "import pdb; import nose\n" - assert isort.code(test_input) == ("import pdb\n\nimport 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 @@ -2164,9 +2152,7 @@ def test_long_line_comments() -> None: 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" - ) + test_input = "from __future__ import print_function\nfrom __future__ import\tprint_function\n" assert isort.code(test_input) == "from __future__ import print_function\n" @@ -2504,9 +2490,7 @@ def test_force_grid_wrap_long() -> None: 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_input = "import sys\nimport os\nimport myproject.{ test }\nimport django.{ settings }" test_output = isort.code( code=test_input, known_third_party=["django"], known_first_party=["myproject"] ) @@ -2519,7 +2503,7 @@ def test_uses_jinja_variables() -> None: "import myproject.{ test }\n" ) - test_input = "import {{ cookiecutter.repo_name }}\n" "from foo import {{ cookiecutter.bar }}\n" + test_input = "import {{ cookiecutter.repo_name }}\nfrom foo import {{ cookiecutter.bar }}\n" assert isort.code(test_input) == test_input @@ -2760,7 +2744,7 @@ def test_alphabetic_sorting_no_newlines() -> None: 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_input = "import os\nimport unittest\n\nfrom a import b\n\n\nprint(1)\n" test_output = isort.code( code=test_input, force_alphabetical_sort_within_sections=True, lines_after_imports=2 ) @@ -2809,9 +2793,7 @@ def test_sort_within_section() -> None: ) assert test_output == test_input - test_input = ( - "from Foob import ar\n" "import foo\n" "from foo import Quux\n" "from foo import baz\n" - ) + test_input = "from Foob import ar\nimport foo\nfrom foo import Quux\nfrom foo import baz\n" test_output = isort.code( code=test_input, case_sensitive=True, @@ -2868,9 +2850,7 @@ def test_sort_within_section_case_honored() -> None: ) assert test_output == test_input - test_input = ( - "from Foob import ar\n" "import foo\n" "from foo import Quux\n" "from foo import baz\n" - ) + test_input = "from Foob import ar\nimport foo\nfrom foo import Quux\nfrom foo import baz\n" test_output = isort.code( code=test_input, case_sensitive=True, @@ -2885,13 +2865,13 @@ def test_sort_within_section_case_honored() -> None: 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") + 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=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" ) @@ -3094,18 +3074,22 @@ def test_sys_path_mutation(tmpdir) -> None: 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)", + 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)", + code=( + "from ..views import (" + " _a," + "_xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx as xxxxxx_xxxxxxx_xxxxxxxx_xxx_xxxxxxx)" + ), line_length=79, combine_as_imports=True, ) @@ -3782,9 +3766,7 @@ 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" - ) + 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"]) @@ -4325,7 +4307,7 @@ 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" + "[isort]\nskip =\n file_to_be_skipped.py\nskip_glob =\n *glob_skip*\n" ) base_dir.join("file_glob_skip.py").write( @@ -4470,9 +4452,9 @@ def test_isort_keeps_comments_issue_691() -> None: def test_isort_multiline_with_tab_issue_1714() -> None: - test_input = "from sys \\ \n" "\timport version\n" "print(version)\n" + test_input = "from sys \\ \n\timport version\nprint(version)\n" - expected_output = "from sys import version\n" "\n" "print(version)\n" + expected_output = "from sys import version\n\nprint(version)\n" assert isort.code(test_input) == expected_output @@ -5486,20 +5468,18 @@ def test_only_sections() -> None: def test_combine_straight_imports() -> None: """Tests to ensure that combine_straight_imports works correctly""" - test_input = ( - "import os\n" "import sys\n" "# this is a comment\n" "import math # inline comment\n" - ) + test_input = "import os\nimport sys\n# this is a comment\nimport math # inline comment\n" assert isort.code(test_input, combine_straight_imports=True) == ( - "# this is a comment\n" "import math, os, sys # inline comment\n" + "# this is a comment\nimport math, os, sys # inline comment\n" ) # test to ensure that combine_straight_import works with only_sections - test_input = "import sys, os\n" "import a\n" "import math\n" "import b\n" + test_input = "import sys, os\nimport a\nimport math\nimport b\n" assert isort.code(test_input, combine_straight_imports=True, only_sections=True) == ( - "import sys, os, math\n" "\n" "import a, b\n" + "import sys, os, math\n\nimport a, b\n" ) @@ -5556,7 +5536,7 @@ def seek(self, offset: int, whence: int = os.SEEK_SET, /) -> int: def seekable(self): return False - test_input = NonSeekableTestStream("import m2\n" "import m1\n" "not_import = 7") + test_input = NonSeekableTestStream("import m2\nimport m1\nnot_import = 7") identified_imports = list(map(str, api.find_imports_in_stream(test_input))) assert identified_imports == [":1 import m2", ":2 import m1"] diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index a1ff83a3..1c822787 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -1042,12 +1042,12 @@ def test_only_modified_flag(tmpdir, capsys): def test_identify_imports_main(tmpdir, capsys): - file_content = "import mod2\nimport mod2\n" "a = 1\n" "import mod1\n" + file_content = "import mod2\nimport mod2\na = 1\nimport mod1\n" some_file = tmpdir.join("some_file.py") some_file.write(file_content) file_imports = f"{some_file}:1 import mod2\n{some_file}:4 import mod1\n" file_imports_with_dupes = ( - f"{some_file}:1 import mod2\n{some_file}:2 import mod2\n" f"{some_file}:4 import mod1\n" + f"{some_file}:1 import mod2\n{some_file}:2 import mod2\n{some_file}:4 import mod1\n" ) main.identify_imports_main([str(some_file), "--unique"]) diff --git a/tests/unit/test_regressions.py b/tests/unit/test_regressions.py index 4180f81c..ca856ddd 100644 --- a/tests/unit/test_regressions.py +++ b/tests/unit/test_regressions.py @@ -495,7 +495,7 @@ def test_windows_diff_too_large_misrepresentative_issue_1348(test_path): 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" + "-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" )