Skip to content

Commit

Permalink
[POC] Refactor code to avoid use of rich library
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed Nov 10, 2024
1 parent 4848777 commit 0ff50ef
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 235 deletions.
5 changes: 1 addition & 4 deletions .config/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,8 @@ linkchecker==10.5.0 # via mkdocs-ansible
markdown==3.7 # via markdown-include, mkdocs, mkdocs-autorefs, mkdocs-htmlproofer-plugin, mkdocs-material, mkdocstrings, pymdown-extensions
markdown-exec==1.9.3 # via mkdocs-ansible
markdown-include==0.8.1 # via mkdocs-ansible
markdown-it-py==3.0.0 # via rich
markupsafe==3.0.2 # via jinja2, mkdocs, mkdocs-autorefs, mkdocstrings
mccabe==0.7.0 # via pylint
mdurl==0.1.2 # via markdown-it-py
mergedeep==1.3.4 # via mkdocs, mkdocs-get-deps
mkdocs==1.6.1 # via mkdocs-ansible, mkdocs-autorefs, mkdocs-gen-files, mkdocs-htmlproofer-plugin, mkdocs-macros-plugin, mkdocs-material, mkdocs-minify-plugin, mkdocs-monorepo-plugin, mkdocstrings
mkdocs-ansible==24.3.1 # via ansible-lint (pyproject.toml)
Expand All @@ -77,7 +75,7 @@ platformdirs==4.3.6 # via black, mkdocs-get-deps, mkdocstrings, pylint, to
pluggy==1.5.0 # via pytest, tox
psutil==6.1.0 # via ansible-lint (pyproject.toml)
pycparser==2.22 # via cffi
pygments==2.18.0 # via mkdocs-material, rich
pygments==2.18.0 # via mkdocs-material
pylint==3.3.1 # via ansible-lint (pyproject.toml)
pymdown-extensions==10.12 # via markdown-exec, mkdocs-ansible, mkdocs-material, mkdocstrings
pyproject-api==1.8.0 # via tox
Expand All @@ -92,7 +90,6 @@ pyyaml-env-tag==0.1 # via mkdocs
referencing==0.35.1 # via jsonschema, jsonschema-specifications, types-jsonschema
regex==2024.11.6 # via mkdocs-material
requests==2.32.3 # via linkchecker, mkdocs-htmlproofer-plugin, mkdocs-material
rich==13.9.4 # via ansible-lint (pyproject.toml)
rpds-py==0.21.0 # via jsonschema, referencing
ruamel-yaml==0.18.6 # via ansible-lint (pyproject.toml)
ruamel-yaml-clib==0.2.12 # via ruamel-yaml, ansible-lint (pyproject.toml)
Expand Down
4 changes: 0 additions & 4 deletions .config/requirements-lock.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,14 @@ importlib-metadata==8.5.0 # via ansible-lint (pyproject.toml)
jinja2==3.1.4 # via ansible-core
jsonschema==4.23.0 # via ansible-compat, ansible-lint (pyproject.toml)
jsonschema-specifications==2024.10.1 # via jsonschema
markdown-it-py==3.0.0 # via rich
markupsafe==3.0.2 # via jinja2
mdurl==0.1.2 # via markdown-it-py
mypy-extensions==1.0.0 # via black
packaging==24.2 # via ansible-compat, ansible-core, black, ansible-lint (pyproject.toml)
pathspec==0.12.1 # via black, yamllint, ansible-lint (pyproject.toml)
platformdirs==4.3.6 # via black
pycparser==2.22 # via cffi
pygments==2.18.0 # via rich
pyyaml==6.0.2 # via ansible-compat, ansible-core, yamllint, ansible-lint (pyproject.toml)
referencing==0.35.1 # via jsonschema, jsonschema-specifications
rich==13.9.4 # via ansible-lint (pyproject.toml)
rpds-py==0.21.0 # via jsonschema, referencing
ruamel-yaml==0.18.6 # via ansible-lint (pyproject.toml)
ruamel-yaml-clib==0.2.12 # via ruamel-yaml
Expand Down
1 change: 0 additions & 1 deletion .config/requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ jsonschema>=4.10.0 # MIT, version needed for improved errors
packaging>=21.3 # Apache-2.0,BSD-2-Clause
pathspec>=0.10.3 # Mozilla Public License 2.0 (MPL 2.0)
pyyaml>=5.4.1 # MIT (centos 9 has 5.3.1)
rich>=12.0.0 # MIT
ruamel.yaml>=0.18.5 # MIT
subprocess-tee>=0.4.1 # MIT, used by ansible-compat
yamllint >= 1.30.0 # GPLv3
Expand Down
1 change: 0 additions & 1 deletion .github/lower-constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ jsonschema==4.10.0 # MIT, version needed for improved errors
packaging==21.3
pathspec==0.10.3
pyyaml==5.4.1
rich==12.0.0
ruamel.yaml==0.18.5 # MIT
subprocess-tee==0.4.1 # MIT, used by ansible-compat
# https://packages.ubuntu.com/noble/python3-wcmatch
Expand Down
2 changes: 0 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ repos:
- pytest-mock
- pytest>=7.2.2
- pip>=22.3.1
- rich>=13.2.0
- ruamel-yaml-clib>=0.2.8
- ruamel-yaml>=0.18.6
- subprocess-tee
Expand Down Expand Up @@ -195,7 +194,6 @@ repos:
- pytest-mock
- pytest>=7.2.2
- pyyaml
- rich>=13.2.0
- ruamel-yaml-clib>=0.2.7
- ruamel-yaml>=0.18.2
- setuptools # needed for pkg_resources import
Expand Down
41 changes: 18 additions & 23 deletions src/ansiblelint/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@

from ansible_compat.prerun import get_cache_dir
from filelock import FileLock, Timeout
from rich.markup import escape

from ansiblelint.console import Theme
from ansiblelint.constants import RC, SKIP_SCHEMA_UPDATE

# safety check for broken ansible core, needs to happen first
Expand All @@ -51,10 +51,6 @@
from ansiblelint._mockings import _perform_mockings_cleanup
from ansiblelint.app import get_app
from ansiblelint.color import (
console,
console_options,
console_stderr,
reconfigure,
render_yaml,
)
from ansiblelint.config import (
Expand Down Expand Up @@ -87,7 +83,7 @@ class LintLogHandler(logging.Handler):
def emit(self, record: logging.LogRecord) -> None:
try:
msg = self.format(record)
console_stderr.print(f"[dim]{msg}[/dim]", highlight=False)
print(f"{Theme.dim}{msg}{Theme.normal}", file=sys.stderr) # noqa: T201
except RecursionError: # See issue 36272
raise
except Exception: # pylint: disable=broad-exception-caught # noqa: BLE001
Expand Down Expand Up @@ -166,23 +162,20 @@ def initialize_options(arguments: list[str] | None = None) -> None | FileLock:
def _do_list(rules: RulesCollection) -> int:
# On purpose lazy-imports to avoid pre-loading Ansible
# pylint: disable=import-outside-toplevel
from ansiblelint.generate_docs import rules_as_md, rules_as_rich, rules_as_str
from ansiblelint.generate_docs import rules_as_md, rules_as_str

if options.list_rules:
_rule_format_map: dict[str, Callable[..., Any]] = {
"brief": rules_as_str,
"full": rules_as_rich,
"md": rules_as_md,
"full": rules_as_md,
}

console.print(
_rule_format_map.get(options.format, rules_as_str)(rules),
highlight=False,
)
md = _rule_format_map.get(options.format, rules_as_str)(rules)
md.display()
return 0

if options.list_tags:
console.print(render_yaml(rules.list_tags()))
print(render_yaml(rules.list_tags())) # noqa: T201
return 0

# we should not get here!
Expand Down Expand Up @@ -289,19 +282,21 @@ def main(argv: list[str] | None = None) -> int:
argv = sys.argv
cache_dir_lock = initialize_options(argv[1:])

console_options["force_terminal"] = options.colored
reconfigure(console_options)
# console_options["force_terminal"] = options.colored
# reconfigure(console_options)

if options.version:
deps = get_deps_versions()
msg = f"ansible-lint [repr.number]{__version__}[/] using[dim]"
msg = (
f"ansible-lint {Theme.number}{__version__}{Theme.normal} using\n{Theme.dim}"
)
for k, v in deps.items():
msg += f" {escape(k)}:[repr.number]{v}[/]"
msg += "[/]"
console.print(msg, markup=True, highlight=False)
msg += f" {k} {Theme.number}{v}{Theme.normal}\n"
msg += f"{Theme.dim}"
print(msg) # noqa: T201
msg = get_version_warning()
if msg:
console.print(msg)
print(msg) # noqa: T201
support_banner()
sys.exit(0)
else:
Expand Down Expand Up @@ -339,9 +334,9 @@ def main(argv: list[str] | None = None) -> int:
from ansiblelint.rules import RulesCollection

if options.list_profiles:
from ansiblelint.generate_docs import profiles_as_rich
from ansiblelint.generate_docs import profiles_as_md

console.print(profiles_as_rich())
profiles_as_md().display()
return 0

app = get_app(
Expand Down
64 changes: 27 additions & 37 deletions src/ansiblelint/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
from typing import TYPE_CHECKING, Any

from ansible_compat.runtime import Runtime
from rich.markup import escape
from rich.table import Table

from ansiblelint import formatters
from ansiblelint._mockings import _perform_mockings
from ansiblelint.color import console, console_stderr, render_yaml
from ansiblelint.color import render_yaml
from ansiblelint.config import PROFILES, Options, get_version_warning
from ansiblelint.config import options as default_options
from ansiblelint.console import Theme
from ansiblelint.constants import RC, RULE_DOC_URL
from ansiblelint.loaders import IGNORE_FILE
from ansiblelint.requirements import Reqs
Expand Down Expand Up @@ -80,10 +79,8 @@ def render_matches(self, matches: list[MatchError]) -> None:
):
# If formatter CodeclimateJSONFormatter or SarifFormatter is chosen,
# then print only the matches in JSON
console.print(
print( # noqa: T201
self.formatter.format_result(matches),
markup=False,
highlight=False,
)
return

Expand All @@ -98,15 +95,15 @@ def render_matches(self, matches: list[MatchError]) -> None:
for match in ignored_matches:
if match.ignored:
# highlight must be off or apostrophes may produce unexpected results
console.print(self.formatter.apply(match), highlight=False)
print(self.formatter.apply(match)) # noqa: T201
if fatal_matches:
_logger.warning(
"Listing %s violation(s) that are fatal",
len(fatal_matches),
)
for match in fatal_matches:
if not match.ignored:
console.print(self.formatter.apply(match), highlight=False)
print(self.formatter.apply(match)) # noqa: T201

# If run under GitHub Actions we also want to emit output recognized by it.
if os.getenv("GITHUB_ACTIONS") == "true" and os.getenv("GITHUB_WORKFLOW"):
Expand All @@ -115,10 +112,9 @@ def render_matches(self, matches: list[MatchError]) -> None:
)
formatter = formatters.AnnotationsFormatter(self.options.cwd, True)
for match in itertools.chain(fatal_matches, ignored_matches):
console_stderr.print(
print( # noqa: T201
formatter.apply(match),
markup=False,
highlight=False,
file=sys.stderr,
)

# If sarif_file is set, we also dump the results to a sarif file.
Expand Down Expand Up @@ -216,7 +212,8 @@ def report_outcome(
ignore_file_path = Path(
os.environ.get("ANSIBLE_LINT_IGNORE_FILE", IGNORE_FILE.default),
)
console_stderr.print(f"Writing ignore file to {ignore_file_path}")
msg = f"Writing ignore file to {ignore_file_path}"
_logger.info(msg)
lines = set()
for rule in result.matches:
lines.add(f"{rule.filename} {rule.tag}\n")
Expand All @@ -226,7 +223,7 @@ def report_outcome(
)
ignore_file.writelines(sorted(lines))
elif matched_rules and not self.options.quiet:
console_stderr.print(
_logger.info(
"Read [link=https://ansible.readthedocs.io/projects/lint/configuring/#ignoring-rules-for-entire-files]documentation[/link] for instructions on how to ignore specific rule violations.",
)

Expand All @@ -253,7 +250,7 @@ def report_outcome(
mark_as_success = False

if not self.options.quiet:
console_stderr.print(render_yaml(msg))
print(render_yaml(msg), file=sys.stderr) # noqa: T201
self.report_summary(
summary,
changed_files_count,
Expand Down Expand Up @@ -303,7 +300,7 @@ def report_summary( # pylint: disable=too-many-locals # noqa: C901
summary.sort()

if changed_files_count:
console_stderr.print(f"Modified {changed_files_count} files.")
_logger.info("Modified %d files.", changed_files_count)

# determine which profile passed
summary.passed_profile = ""
Expand All @@ -317,33 +314,26 @@ def report_summary( # pylint: disable=too-many-locals # noqa: C901

stars = ""
if summary.tag_stats:
table = Table(
title="Rule Violation Summary",
collapse_padding=True,
box=None,
show_lines=False,
)
table.add_column("count", justify="right")
table.add_column("tag")
table.add_column("profile")
table.add_column("rule associated tags")
table = "# Rule Violation Summary\n\n"
# table.add_column("count", justify="right")
# table.add_column("tag")
# table.add_column("profile")
# table.add_column("rule associated tags")
for tag, stats in summary.tag_stats.items():
table.add_row(
str(stats.count),
f"[link={RULE_DOC_URL}{ tag.split('[')[0] }]{escape(tag)}[/link]",
stats.profile,
f"{', '.join(stats.associated_tags)}{' (warning)' if stats.warning else ''}",
style="yellow" if stats.warning else "red",
)
# rate stars for the top 5 profiles (min would not get
tags = f"{', '.join(stats.associated_tags)}{' (warning)' if stats.warning else ''}"
profile = stats.profile
table += f"{stats.count:3} {Theme.link(RULE_DOC_URL, tag.split('[')[0])} {Theme.dim}profile:{profile} tags:{tags}{Theme.normal}\n"
rating = 5 - (len(PROFILES.keys()) - passed_profile_count)
if 0 < rating < 6:
stars = f" Rating: {rating}/5 star"

console_stderr.print(table)
console_stderr.print()
print(table, file=sys.stderr) # noqa: T201

msg = "[green]Passed[/]" if is_success else "[red][bold]Failed[/][/]"
msg = (
f"{Theme.success}Passed{Theme.normal}"
if is_success
else f"{Theme.failed}Failed{Theme.normal}"
)

msg += f": {summary.failures} failure(s), {summary.warnings} warning(s)"
if summary.fixed:
Expand Down Expand Up @@ -373,7 +363,7 @@ def report_summary( # pylint: disable=too-many-locals # noqa: C901
if version_warning:
msg += f"\n{version_warning}"

console_stderr.print(msg)
_logger.info(msg)


def choose_formatter_factory(
Expand Down
25 changes: 10 additions & 15 deletions src/ansiblelint/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,7 @@ def get_cli_parser() -> argparse.ArgumentParser:
dest="list_rules",
default=False,
action="store_true",
help="List all the rules. For listing rules only the following formats "
"for argument -f are supported: {brief, full, md} with 'brief' as default.",
help="List all the rules.",
)
listing_group.add_argument(
"-T",
Expand Down Expand Up @@ -575,22 +574,18 @@ def get_config(arguments: list[str]) -> Options:
for i, value in enumerate(arguments):
if arguments[i].startswith("--write"):
arguments[i] = value.replace("--write", "--fix")
_logger.warning(
"Replaced deprecated '--write' option with '--fix', change you call to avoid future regressions when we remove old option.",
log_entries.append(
(
logging.WARNING,
"Replaced deprecated '--write' option with '--fix', change you call to avoid future regressions when we remove old option.",
),
)
options = Options(**vars(parser.parse_args(arguments)))

# docs is not document, being used for internal documentation building
if options.list_rules and options.format not in [
None,
"brief",
"full",
"md",
]:
parser.error(
f"argument -f: invalid choice: '{options.format}'. "
f"In combination with argument -L only 'brief', "
f"'rich' or 'md' are supported with -f.",
if options.list_rules and options.format:
log_entries.append(
(logging.WARNING, "Ignoring --format option when listing rules."),
)

# save info about custom config file, as options.config_file may be modified by merge_config
Expand All @@ -611,7 +606,7 @@ def get_config(arguments: list[str]) -> Options:
log_entries.append(
(
logging.INFO,
f"Identified [filename]{project_dir}[/] as project root due [bold]{method}[/].",
f"Identified `{project_dir}` as project root due **{method}**.",
),
)

Expand Down
Loading

0 comments on commit 0ff50ef

Please sign in to comment.