123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- """Defines all wrap modes that can be used when outputting formatted imports"""
- import enum
- from inspect import signature
- from typing import Any, Callable, Dict, List
- import isort.comments
- _wrap_modes: Dict[str, Callable[..., str]] = {}
- def from_string(value: str) -> "WrapModes":
- return getattr(WrapModes, str(value), None) or WrapModes(int(value))
- def formatter_from_string(name: str) -> Callable[..., str]:
- return _wrap_modes.get(name.upper(), grid)
- def _wrap_mode_interface(
- statement: str,
- imports: List[str],
- white_space: str,
- indent: str,
- line_length: int,
- comments: List[str],
- line_separator: str,
- comment_prefix: str,
- include_trailing_comma: bool,
- remove_comments: bool,
- ) -> str:
- """Defines the common interface used by all wrap mode functions"""
- return ""
- def _wrap_mode(function: Callable[..., str]) -> Callable[..., str]:
- """Registers an individual wrap mode. Function name and order are significant and used for
- creating enum.
- """
- _wrap_modes[function.__name__.upper()] = function
- function.__signature__ = signature(_wrap_mode_interface) # type: ignore
- function.__annotations__ = _wrap_mode_interface.__annotations__
- return function
- @_wrap_mode
- def grid(**interface: Any) -> str:
- if not interface["imports"]:
- return ""
- 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,
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- if (
- len(next_statement.split(interface["line_separator"])[-1]) + 1
- > interface["line_length"]
- ):
- lines = [f"{interface['white_space']}{next_import.split(' ')[0]}"]
- for part in next_import.split(" ")[1:]:
- new_line = f"{lines[-1]} {part}"
- if len(new_line) + 1 > interface["line_length"]:
- lines.append(f"{interface['white_space']}{part}")
- else:
- lines[-1] = new_line
- next_import = interface["line_separator"].join(lines)
- interface["statement"] = (
- isort.comments.add_to_line(
- interface["comments"],
- f"{interface['statement']},",
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- + f"{interface['line_separator']}{next_import}"
- )
- interface["comments"] = []
- else:
- interface["statement"] += ", " + next_import
- return f"{interface['statement']}{',' if interface['include_trailing_comma'] else ''})"
- @_wrap_mode
- def vertical(**interface: Any) -> str:
- if not interface["imports"]:
- return ""
- first_import = (
- isort.comments.add_to_line(
- interface["comments"],
- interface["imports"].pop(0) + ",",
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- + interface["line_separator"]
- + interface["white_space"]
- )
- _imports = ("," + interface["line_separator"] + interface["white_space"]).join(
- interface["imports"]
- )
- _comma_maybe = "," if interface["include_trailing_comma"] else ""
- return f"{interface['statement']}({first_import}{_imports}{_comma_maybe})"
- def _hanging_indent_end_line(line: str) -> str:
- if not line.endswith(" "):
- line += " "
- return line + "\\"
- @_wrap_mode
- def hanging_indent(**interface: Any) -> str:
- if not interface["imports"]:
- return ""
- line_length_limit = interface["line_length"] - 3
- next_import = interface["imports"].pop(0)
- next_statement = interface["statement"] + next_import
- # Check for first import
- if len(next_statement) > line_length_limit:
- next_statement = (
- _hanging_indent_end_line(interface["statement"])
- + interface["line_separator"]
- + interface["indent"]
- + next_import
- )
- interface["statement"] = next_statement
- while interface["imports"]:
- next_import = interface["imports"].pop(0)
- next_statement = interface["statement"] + ", " + next_import
- if len(next_statement.split(interface["line_separator"])[-1]) > line_length_limit:
- next_statement = (
- _hanging_indent_end_line(interface["statement"] + ",")
- + f"{interface['line_separator']}{interface['indent']}{next_import}"
- )
- interface["statement"] = next_statement
- interface[
- "statement"
- ] = f"{interface['statement']}{',' if interface['include_trailing_comma'] else ''}"
- if interface["comments"]:
- statement_with_comments = isort.comments.add_to_line(
- interface["comments"],
- interface["statement"],
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- if len(statement_with_comments.split(interface["line_separator"])[-1]) <= (
- line_length_limit + 2
- ):
- return statement_with_comments
- return (
- _hanging_indent_end_line(interface["statement"])
- + str(interface["line_separator"])
- + isort.comments.add_to_line(
- interface["comments"],
- interface["indent"],
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"].lstrip(),
- )
- )
- return str(interface["statement"])
- @_wrap_mode
- def vertical_hanging_indent(**interface: Any) -> str:
- _line_with_comments = isort.comments.add_to_line(
- interface["comments"],
- "",
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- _imports = ("," + interface["line_separator"] + interface["indent"]).join(interface["imports"])
- _comma_maybe = "," if interface["include_trailing_comma"] else ""
- return (
- f"{interface['statement']}({_line_with_comments}{interface['line_separator']}"
- f"{interface['indent']}{_imports}{_comma_maybe}{interface['line_separator']})"
- )
- def _vertical_grid_common(need_trailing_char: bool, **interface: Any) -> str:
- if not interface["imports"]:
- return ""
- interface["statement"] += (
- isort.comments.add_to_line(
- interface["comments"],
- "(",
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- + interface["line_separator"]
- + interface["indent"]
- + interface["imports"].pop(0)
- )
- while interface["imports"]:
- next_import = interface["imports"].pop(0)
- next_statement = f"{interface['statement']}, {next_import}"
- current_line_length = len(next_statement.split(interface["line_separator"])[-1])
- if interface["imports"] or interface["include_trailing_comma"]:
- # We need to account for a comma after this import.
- current_line_length += 1
- if not interface["imports"] and need_trailing_char:
- # We need to account for a closing ) we're going to add.
- current_line_length += 1
- if current_line_length > interface["line_length"]:
- next_statement = (
- f"{interface['statement']},{interface['line_separator']}"
- f"{interface['indent']}{next_import}"
- )
- interface["statement"] = next_statement
- if interface["include_trailing_comma"]:
- interface["statement"] += ","
- return str(interface["statement"])
- @_wrap_mode
- def vertical_grid(**interface: Any) -> str:
- return _vertical_grid_common(need_trailing_char=True, **interface) + ")"
- @_wrap_mode
- def vertical_grid_grouped(**interface: Any) -> str:
- return (
- _vertical_grid_common(need_trailing_char=False, **interface)
- + str(interface["line_separator"])
- + ")"
- )
- @_wrap_mode
- def vertical_grid_grouped_no_comma(**interface: Any) -> str:
- # This is a deprecated alias for vertical_grid_grouped above. This function
- # needs to exist for backwards compatibility but should never get called.
- raise NotImplementedError
- @_wrap_mode
- def noqa(**interface: Any) -> str:
- _imports = ", ".join(interface["imports"])
- retval = f"{interface['statement']}{_imports}"
- comment_str = " ".join(interface["comments"])
- if interface["comments"]:
- if (
- len(retval) + len(interface["comment_prefix"]) + 1 + len(comment_str)
- <= interface["line_length"]
- ):
- return f"{retval}{interface['comment_prefix']} {comment_str}"
- if "NOQA" in interface["comments"]:
- return f"{retval}{interface['comment_prefix']} {comment_str}"
- return f"{retval}{interface['comment_prefix']} NOQA {comment_str}"
- if len(retval) <= interface["line_length"]:
- return retval
- return f"{retval}{interface['comment_prefix']} NOQA"
- @_wrap_mode
- def vertical_hanging_indent_bracket(**interface: Any) -> str:
- if not interface["imports"]:
- return ""
- statement = vertical_hanging_indent(**interface)
- return f'{statement[:-1]}{interface["indent"]})'
- @_wrap_mode
- def vertical_prefix_from_module_import(**interface: Any) -> str:
- if not interface["imports"]:
- return ""
- prefix_statement = interface["statement"]
- 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(statement_with_comments.split(interface["line_separator"])[-1]) + 1
- > interface["line_length"]
- ):
- statement = (
- isort.comments.add_to_line(
- comments,
- output_statement,
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- + f"{interface['line_separator']}{prefix_statement}{next_import}"
- )
- comments = []
- output_statement = statement
- if comments and statement_with_comments:
- output_statement = statement_with_comments
- return str(output_statement)
- @_wrap_mode
- def hanging_indent_with_parentheses(**interface: Any) -> str:
- if not interface["imports"]:
- return ""
- line_length_limit = interface["line_length"] - 1
- interface["statement"] += "("
- next_import = interface["imports"].pop(0)
- next_statement = interface["statement"] + next_import
- # Check for first import
- if len(next_statement) > line_length_limit:
- next_statement = (
- isort.comments.add_to_line(
- interface["comments"],
- interface["statement"],
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- + f"{interface['line_separator']}{interface['indent']}{next_import}"
- )
- interface["comments"] = []
- interface["statement"] = next_statement
- while interface["imports"]:
- next_import = interface["imports"].pop(0)
- if (
- not interface["line_separator"] in interface["statement"]
- and "#" in interface["statement"]
- ): # pragma: no cover # TODO: fix, this is because of test run inconsistency.
- line, comments = interface["statement"].split("#", 1)
- next_statement = (
- f"{line.rstrip()}, {next_import}{interface['comment_prefix']}{comments}"
- )
- else:
- next_statement = isort.comments.add_to_line(
- interface["comments"],
- interface["statement"] + ", " + next_import,
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- current_line = next_statement.split(interface["line_separator"])[-1]
- if len(current_line) > line_length_limit:
- next_statement = (
- isort.comments.add_to_line(
- interface["comments"],
- interface["statement"] + ",",
- removed=interface["remove_comments"],
- comment_prefix=interface["comment_prefix"],
- )
- + f"{interface['line_separator']}{interface['indent']}{next_import}"
- )
- interface["comments"] = []
- interface["statement"] = next_statement
- return f"{interface['statement']}{',' if interface['include_trailing_comma'] else ''})"
- @_wrap_mode
- def backslash_grid(**interface: Any) -> str:
- interface["indent"] = interface["white_space"][:-1]
- return hanging_indent(**interface)
- WrapModes = enum.Enum( # type: ignore
- "WrapModes", {wrap_mode: index for index, wrap_mode in enumerate(_wrap_modes.keys())}
- )
|