| import copy |
| import re |
| from typing import List, Optional, Sequence |
| |
| from .settings import DEFAULT_CONFIG, Config |
| from .wrap_modes import WrapModes as Modes |
| from .wrap_modes import formatter_from_string |
| |
| |
| def import_statement( |
| import_start: str, |
| from_imports: List[str], |
| comments: Sequence[str] = (), |
| line_separator: str = "\n", |
| config: Config = DEFAULT_CONFIG, |
| multi_line_output: Optional[Modes] = None, |
| ) -> str: |
| """Returns a multi-line wrapped form of the provided from import statement.""" |
| formatter = formatter_from_string((multi_line_output or config.multi_line_output).name) |
| dynamic_indent = " " * (len(import_start) + 1) |
| indent = config.indent |
| line_length = config.wrap_length or config.line_length |
| statement = formatter( |
| statement=import_start, |
| imports=copy.copy(from_imports), |
| white_space=dynamic_indent, |
| indent=indent, |
| line_length=line_length, |
| comments=comments, |
| line_separator=line_separator, |
| comment_prefix=config.comment_prefix, |
| include_trailing_comma=config.include_trailing_comma, |
| remove_comments=config.ignore_comments, |
| ) |
| if config.balanced_wrapping: |
| lines = statement.split(line_separator) |
| line_count = len(lines) |
| if len(lines) > 1: |
| minimum_length = min(len(line) for line in lines[:-1]) |
| else: |
| minimum_length = 0 |
| new_import_statement = statement |
| while len(lines[-1]) < minimum_length and len(lines) == line_count and line_length > 10: |
| statement = new_import_statement |
| line_length -= 1 |
| new_import_statement = formatter( |
| statement=import_start, |
| imports=copy.copy(from_imports), |
| white_space=dynamic_indent, |
| indent=indent, |
| line_length=line_length, |
| comments=comments, |
| line_separator=line_separator, |
| comment_prefix=config.comment_prefix, |
| include_trailing_comma=config.include_trailing_comma, |
| remove_comments=config.ignore_comments, |
| ) |
| lines = new_import_statement.split(line_separator) |
| if statement.count(line_separator) == 0: |
| return _wrap_line(statement, line_separator, config) |
| return statement |
| |
| |
| def line(content: str, line_separator: str, config: Config = DEFAULT_CONFIG) -> str: |
| """Returns a line wrapped to the specified line-length, if possible.""" |
| wrap_mode = config.multi_line_output |
| if len(content) > config.line_length and wrap_mode != Modes.NOQA: # type: ignore |
| line_without_comment = content |
| comment = None |
| if "#" in content: |
| line_without_comment, comment = content.split("#", 1) |
| for splitter in ("import ", ".", "as "): |
| exp = r"\b" + re.escape(splitter) + r"\b" |
| if re.search(exp, line_without_comment) and not line_without_comment.strip().startswith( |
| splitter |
| ): |
| line_parts = re.split(exp, line_without_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}{config.comment_prefix}{comment}" |
| next_line = [] |
| while (len(content) + 2) > ( |
| config.wrap_length or config.line_length |
| ) and line_parts: |
| next_line.append(line_parts.pop()) |
| content = splitter.join(line_parts) |
| if not content: |
| content = next_line.pop() |
| |
| cont_line = _wrap_line( |
| config.indent + splitter.join(next_line).lstrip(), line_separator, config |
| ) |
| if config.use_parentheses: |
| if splitter == "as ": |
| output = f"{content}{splitter}{cont_line.lstrip()}" |
| else: |
| _comma = "," if config.include_trailing_comma and not comment else "" |
| if wrap_mode in ( |
| Modes.VERTICAL_HANGING_INDENT, # type: ignore |
| Modes.VERTICAL_GRID_GROUPED, # type: ignore |
| ): |
| _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}({_comment}" |
| f"{line_separator}{cont_line}{_comma}{_separator})" |
| ) |
| lines = output.split(line_separator) |
| if config.comment_prefix in lines[-1] and lines[-1].endswith(")"): |
| content, comment = lines[-1].split(config.comment_prefix, 1) |
| lines[-1] = content + ")" + config.comment_prefix + comment[:-1] |
| return line_separator.join(lines) |
| return f"{content}{splitter}\\{line_separator}{cont_line}" |
| elif len(content) > config.line_length and wrap_mode == Modes.NOQA: # type: ignore |
| if "# NOQA" not in content: |
| return f"{content}{config.comment_prefix} NOQA" |
| |
| return content |
| |
| |
| _wrap_line = line |