Skip to content

Module isort.format

View Source
import re

import sys

from datetime import datetime

from difflib import unified_diff

from pathlib import Path

from typing import Optional, TextIO

try:

    import colorama

except ImportError:

    colorama_unavailable = True

else:

    colorama_unavailable = False

    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 "):

        import_line = import_line.replace("from ", "")

        import_line = import_line.replace(" import ", ".")

    elif import_line.startswith("import "):

        import_line = import_line.replace("import ", "")

    return import_line

def format_natural(import_line: str) -> str:

    import_line = import_line.strip()

    if not import_line.startswith("from ") and not import_line.startswith("import "):

        if "." not in import_line:

            return f"import {import_line}"

        parts = import_line.split(".")

        end = parts.pop(-1)

        return f"from {'.'.join(parts)} import {end}"

    return import_line

def show_unified_diff(

    *,

    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.

    - **file_input**: A string that represents the contents of a file before changes.

    - **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.

    """

    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)

    )

    unified_diff_lines = unified_diff(

        file_input.splitlines(keepends=True),

        file_output.splitlines(keepends=True),

        fromfile=file_name + ":before",

        tofile=file_name + ":after",

        fromfiledate=file_mtime,

        tofiledate=str(datetime.now()),

    )

    for line in unified_diff_lines:

        printer.diff_line(line)

def ask_whether_to_apply_changes_to_file(file_path: str) -> bool:

    answer = None

    while answer not in ("yes", "y", "no", "n", "quit", "q"):

        answer = input(f"Apply suggested changes to '{file_path}' [y/n/q]? ")  # nosec

        answer = answer.lower()

        if answer in ("no", "n"):

            return False

        if answer in ("quit", "q"):

            sys.exit(1)

    return True

def remove_whitespace(content: str, line_separator: str = "\n") -> str:

    content = content.replace(line_separator, "").replace(" ", "").replace("\x0c", "")

    return content

class BasicPrinter:

    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}", file=self.output)

    def error(self, message: str) -> None:

        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, 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: 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, output: Optional[TextIO] = None):

    if color and colorama_unavailable:

        no_colorama_message = (

            "\n"

            "Sorry, but to use --color (color_output) the colorama python package is required.\n\n"

            "Reference: https://pypi.org/project/colorama/\n\n"

            "You can either install it separately on your system or as the colors extra "

            "for isort. Ex: \n\n"

            "$ pip install isort[colors]\n"

        )

        print(no_colorama_message, file=sys.stderr)

        sys.exit(1)

    return ColoramaPrinter(output) if color else BasicPrinter(output)

Variables

ADDED_LINE_PATTERN
REMOVED_LINE_PATTERN
colorama_unavailable

Functions

ask_whether_to_apply_changes_to_file

def ask_whether_to_apply_changes_to_file(
    file_path: str
) -> bool
View Source
def ask_whether_to_apply_changes_to_file(file_path: str) -> bool:

    answer = None

    while answer not in ("yes", "y", "no", "n", "quit", "q"):

        answer = input(f"Apply suggested changes to '{file_path}' [y/n/q]? ")  # nosec

        answer = answer.lower()

        if answer in ("no", "n"):

            return False

        if answer in ("quit", "q"):

            sys.exit(1)

    return True

create_terminal_printer

def create_terminal_printer(
    color: bool,
    output: Union[TextIO, NoneType] = None
)
View Source
def create_terminal_printer(color: bool, output: Optional[TextIO] = None):

    if color and colorama_unavailable:

        no_colorama_message = (

            "\n"

            "Sorry, but to use --color (color_output) the colorama python package is required.\n\n"

            "Reference: https://pypi.org/project/colorama/\n\n"

            "You can either install it separately on your system or as the colors extra "

            "for isort. Ex: \n\n"

            "$ pip install isort[colors]\n"

        )

        print(no_colorama_message, file=sys.stderr)

        sys.exit(1)

    return ColoramaPrinter(output) if color else BasicPrinter(output)

format_natural

def format_natural(
    import_line: str
) -> str
View Source
def format_natural(import_line: str) -> str:

    import_line = import_line.strip()

    if not import_line.startswith("from ") and not import_line.startswith("import "):

        if "." not in import_line:

            return f"import {import_line}"

        parts = import_line.split(".")

        end = parts.pop(-1)

        return f"from {'.'.join(parts)} import {end}"

    return import_line

format_simplified

def format_simplified(
    import_line: str
) -> str
View Source
def format_simplified(import_line: str) -> str:

    import_line = import_line.strip()

    if import_line.startswith("from "):

        import_line = import_line.replace("from ", "")

        import_line = import_line.replace(" import ", ".")

    elif import_line.startswith("import "):

        import_line = import_line.replace("import ", "")

    return import_line

remove_whitespace

def remove_whitespace(
    content: str,
    line_separator: str = '\n'
) -> str
View Source
def remove_whitespace(content: str, line_separator: str = "\n") -> str:

    content = content.replace(line_separator, "").replace(" ", "").replace("\x0c", "")

    return content

show_unified_diff

def show_unified_diff(
    *,
    file_input: str,
    file_output: str,
    file_path: Union[pathlib.Path, NoneType],
    output: Union[TextIO, NoneType] = None,
    color_output: bool = False
)

Shows a unified_diff for the provided input and output against the provided file path.

  • file_input: A string that represents the contents of a file before changes.
  • 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.
View Source
def show_unified_diff(

    *,

    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.

    - **file_input**: A string that represents the contents of a file before changes.

    - **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.

    """

    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)

    )

    unified_diff_lines = unified_diff(

        file_input.splitlines(keepends=True),

        file_output.splitlines(keepends=True),

        fromfile=file_name + ":before",

        tofile=file_name + ":after",

        fromfiledate=file_mtime,

        tofiledate=str(datetime.now()),

    )

    for line in unified_diff_lines:

        printer.diff_line(line)

Classes

BasicPrinter

class BasicPrinter(
    output: Union[TextIO, NoneType] = None
)
View Source
class BasicPrinter:

    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}", file=self.output)

    def error(self, message: str) -> None:

        print(f"{self.ERROR}: {message}", file=sys.stderr)

    def diff_line(self, line: str) -> None:

        self.output.write(line)

Descendants

  • isort.format.ColoramaPrinter

Class variables

ERROR
SUCCESS

Methods

diff_line
def diff_line(
    self,
    line: str
) -> None
View Source
    def diff_line(self, line: str) -> None:

        self.output.write(line)
error
def error(
    self,
    message: str
) -> None
View Source
    def error(self, message: str) -> None:

        print(f"{self.ERROR}: {message}", file=sys.stderr)
success
def success(
    self,
    message: str
) -> None
View Source
    def success(self, message: str) -> None:

        print(f"{self.SUCCESS}: {message}", file=self.output)

ColoramaPrinter

class ColoramaPrinter(
    output: Union[TextIO, NoneType] = None
)
View Source
class ColoramaPrinter(BasicPrinter):

    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: 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))

Ancestors (in MRO)

  • isort.format.BasicPrinter

Class variables

ERROR
SUCCESS

Static methods

style_text
def style_text(
    text: str,
    style: Union[str, NoneType] = None
) -> str
View Source
    @staticmethod

    def style_text(text: str, style: Optional[str] = None) -> str:

        if style is None:

            return text

        return style + text + colorama.Style.RESET_ALL

Methods

diff_line
def diff_line(
    self,
    line: str
) -> None
View Source
    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))
error
def error(
    self,
    message: str
) -> None
View Source
    def error(self, message: str) -> None:

        print(f"{self.ERROR}: {message}", file=sys.stderr)
success
def success(
    self,
    message: str
) -> None
View Source
    def success(self, message: str) -> None:

        print(f"{self.SUCCESS}: {message}", file=self.output)