Skip to content

yamlfix.services

Define all the orchestration functionality required by the program to work.

Classes and functions that connect the different domain model objects with the adapters and handlers to achieve the program's purpose.

fix_code(source_code)

Fix yaml source code to correct the format.

It corrects these errors
  • Add --- at the beginning of the file.
  • Correct truthy strings: 'True' -> true, 'no' -> 'false'
  • Remove unnecessary apostrophes: title: 'Why we sleep' -> title: Why we sleep.

Parameters:

Name Type Description Default
source_code str

Source code to be corrected.

required

Returns:

Type Description
str

Corrected source code.

Source code in yamlfix/services.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def fix_code(source_code: str) -> str:
    """Fix yaml source code to correct the format.

    It corrects these errors:

        * Add --- at the beginning of the file.
        * Correct truthy strings: 'True' -> true, 'no' -> 'false'
        * Remove unnecessary apostrophes: `title: 'Why we sleep'` ->
            `title: Why we sleep`.

    Args:
        source_code: Source code to be corrected.

    Returns:
        Corrected source code.
    """
    # Leave Ansible vaults unmodified
    if source_code.startswith("$ANSIBLE_VAULT;"):
        return source_code

    if source_code.startswith("#!"):
        # Skip the shebang line if present, leaving it unmodified
        eolpos = source_code.find("\n") + 1
        shebang = source_code[:eolpos]
        source_code = source_code[eolpos:]
    else:
        shebang = ""

    fixers = [
        _fix_truthy_strings,
        _fix_comments,
        _fix_jinja_variables,
        _ruamel_yaml_fixer,
        _restore_truthy_strings,
        _restore_double_exclamations,
        _restore_jinja_variables,
        _fix_top_level_lists,
        _add_newline_at_end_of_file,
    ]
    for fixer in fixers:
        source_code = fixer(source_code)

    return shebang + source_code

fix_files(files, dry_run=None)

Fix the yaml source code of a list of files.

If the input is taken from stdin, it will return the fixed value.

Parameters:

Name Type Description Default
files Files

List of files to fix.

required
dry_run Optional[bool]

Whether to write changes or not.

None

Returns:

Type Description
Union[Optional[str], Tuple[Optional[str], bool]]

A tuple with the following items:

Union[Optional[str], Tuple[Optional[str], bool]]
  • Fixed code or None.
Union[Optional[str], Tuple[Optional[str], bool]]
  • A bool to indicate whether at least one file has been changed.
Source code in yamlfix/services.py
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
def fix_files(  # pylint: disable=too-many-branches
    files: Files, dry_run: Optional[bool] = None
) -> Union[Optional[str], Tuple[Optional[str], bool]]:  # noqa: TAE002
    """Fix the yaml source code of a list of files.

    If the input is taken from stdin, it will return the fixed value.

    Args:
        files: List of files to fix.
        dry_run: Whether to write changes or not.

    Returns:
        A tuple with the following items:
        * Fixed code or None.
        * A bool to indicate whether at least one file has been changed.
    """
    changed = False

    if dry_run is None:
        warnings.warn(
            """
            From 2023-01-12 fix_files will change the return type from
            `Optional[str]` to Tuple[Optional[str], bool], where the first
            element of the Tuple is the fixed source and the second a bool that
            returns whether the source has changed.

            For more information check https://github.com/lyz-code/yamlfix/pull/182
            """,
            UserWarning,
        )

    for file_ in files:
        if isinstance(file_, str):
            with open(file_, "r", encoding="utf-8") as file_descriptor:
                source = file_descriptor.read()
                file_name = file_
        else:
            source = file_.read()
            file_name = file_.name

        log.debug("Fixing file %s...", file_name)
        fixed_source = fix_code(source)

        if fixed_source != source:
            changed = True

        if file_name == "<stdin>":
            if dry_run is None:
                return fixed_source
            return (fixed_source, changed)

        if fixed_source != source:
            if dry_run:
                log.debug("Need to fix file %s.", file_name)
                continue
            if isinstance(file_, str):
                with open(file_, "w", encoding="utf-8") as file_descriptor:
                    file_descriptor.write(fixed_source)
            else:
                file_.seek(0)
                file_.write(fixed_source)
                file_.truncate()
            log.debug("Fixed file %s.", file_name)
        else:
            log.debug("Left file %s unmodified.", file_name)

    if dry_run is None:
        return None

    return (None, changed)

yamlfix.entrypoints

Define the different ways to expose the program functionality.

Functions

ConsoleColorFormatter

Bases: logging.Formatter

Custom formatter that prints log levels to the console as colored plus signs.

Source code in yamlfix/entrypoints/__init__.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class ConsoleColorFormatter(logging.Formatter):
    """Custom formatter that prints log levels to the console as colored plus signs."""

    colors = {
        logging.DEBUG: GREEN,
        logging.INFO: CYAN,
        logging.WARNING: YELLOW,
        logging.ERROR: RED,
    }

    def format(self, record: logging.LogRecord) -> str:
        """Format log records as a colored plus sign followed by the log message."""
        color = self.colors.get(record.levelno, 0)
        self._style._fmt = f"[\033[{color}m+\033[0m] %(message)s"  # noqa: W0212
        return super().format(record)

format(record)

Format log records as a colored plus sign followed by the log message.

Source code in yamlfix/entrypoints/__init__.py
27
28
29
30
31
def format(self, record: logging.LogRecord) -> str:
    """Format log records as a colored plus sign followed by the log message."""
    color = self.colors.get(record.levelno, 0)
    self._style._fmt = f"[\033[{color}m+\033[0m] %(message)s"  # noqa: W0212
    return super().format(record)

load_logger(verbose=False)

Configure the Logging logger.

Parameters:

Name Type Description Default
verbose bool

Set the logging level to Debug.

False
Source code in yamlfix/entrypoints/__init__.py
34
35
36
37
38
39
40
41
42
43
def load_logger(verbose: bool = False) -> None:
    """Configure the Logging logger.

    Args:
        verbose: Set the logging level to Debug.
    """
    log_level = logging.DEBUG if verbose else logging.INFO
    logging.basicConfig(stream=sys.stderr, level=log_level)
    for handler in logging.getLogger().handlers:
        handler.setFormatter(ConsoleColorFormatter())

yamlfix.version

Utilities to retrieve the information of the program version.

version_info()

Display the version of the program, python and the platform.

Source code in yamlfix/version.py
11
12
13
14
15
16
17
18
19
20
def version_info() -> str:
    """Display the version of the program, python and the platform."""
    return dedent(
        f"""\
        ------------------------------------------------------------------
             yamlfix: {__version__}
             Python: {sys.version.split(" ", maxsplit=1)[0]}
             Platform: {platform.platform()}
        ------------------------------------------------------------------"""
    )

Last update: 2022-06-13