Skip to content

Commit

Permalink
Pretty-print JSON output
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasr8 authored and asottile committed Jul 4, 2023
1 parent 4bc2e03 commit e6f208d
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 9 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ jobs:
- os: ubuntu-latest
python: 3.9
toxenv: pre-commit
- os: ubuntu-latest
python: 3.9
toxenv: py
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
Expand Down
10 changes: 7 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Flake8-JSON
===========

This is a plugin for Flake8 that will format the output as JSON. By default,
the output is **not** pretty-printed. We would love to add that as a separate
formatter option, though.
This is a plugin for Flake8 that will format the output as JSON. The output of
the default JSON formatter is not pretty-printed. If you'd like the output to
be pretty-printed, use json-pretty instead.

CodeClimate support is also offered through this plugin as of v20.12.0

Expand All @@ -23,6 +23,10 @@ Usage
flake8 --format=json ...
.. code-block:: bash
flake8 --format=json-pretty ...
.. code-block:: bash
flake8 --format=codeclimate ...
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ where = src/
[options.entry_points]
flake8.report =
json = flake8_json_reporter.reporters:DefaultJSON
json-pretty = flake8_json_reporter.reporters:FormattedJSON
codeclimate = flake8_json_reporter.reporters:CodeClimateJSON

[bdist_wheel]
Expand Down
43 changes: 43 additions & 0 deletions src/flake8_json_reporter/reporters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Module containing all of the JSON reporters for Flake8."""
import hashlib
import json
import textwrap

from flake8.formatting import base

Expand Down Expand Up @@ -70,6 +71,48 @@ def format(self, violation):
self.reported_errors_count += 1


def _indent(text, indent):
return textwrap.indent(text, " " * indent)


class FormattedJSON(DefaultJSON):
"""Pretty-printing JSON formatter."""

def stop(self):
"""Override the default to finish printing JSON."""
if self.files_reported_count > 0:
self.write_line("\n")
self.write_line("}\n")

def beginning(self, filename):
"""We're starting a new file."""
if self.files_reported_count > 0:
self.write_line(",\n")
self.write_line(f" {json.dumps(filename)}: [")
else:
self.write_line(f"\n {json.dumps(filename)}: [")
self.reported_errors_count = 0

def finished(self, filename):
"""We've finished processing a file."""
self.files_reported_count += 1
if self.reported_errors_count > 0:
self.write_line("\n")
self.write_line(" ]")
else:
self.write_line("]")

def format(self, violation):
"""Format a violation."""
formatted = json.dumps(self.dictionary_from(violation), indent=2)
formatted = _indent(formatted, indent=4)
if self.reported_errors_count > 0:
self.write_line(",")
self.write_line("\n")
self.write_line(formatted)
self.reported_errors_count += 1


class CodeClimateJSON(base.BaseFormatter):
"""Formatter for CodeClimate JSON."""

Expand Down
Empty file added tests/__init__.py
Empty file.
121 changes: 121 additions & 0 deletions tests/flake8_json_reporter_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from argparse import Namespace

import pytest
from flake8.violation import Violation

from flake8_json_reporter.reporters import FormattedJSON


@pytest.fixture
def formatter():
"""Return a ``FormattedJSON`` instance."""
options = Namespace(output_file=None, color=False, tee=False)
formatter = FormattedJSON(options)
return formatter


@pytest.fixture
def violation():
return Violation(
code="E222",
filename="main.py",
line_number=42,
column_number=4,
text="multiple spaces after operator",
physical_line="x = 1",
)


def run(formatter, violations):
formatter.start()
for filename in violations:
formatter.beginning(filename)
for violation in violations[filename]:
formatter.format(violation)
formatter.finished(filename)
formatter.stop()


def test_no_files(capsys, formatter):
run(formatter, {})
stdout, _ = capsys.readouterr()
assert stdout == "{}\n"


def test_single_file_no_violations(capsys, formatter):
run(formatter, {"main.py": []})
stdout, _ = capsys.readouterr()
expected = """\
{
"main.py": []
}
"""
assert stdout == expected


def test_multiple_files_no_violations(capsys, formatter):
run(formatter, {"main.py": [], "__init__.py": []})
stdout, _ = capsys.readouterr()
expected = """\
{
"main.py": [],
"__init__.py": []
}
"""
assert stdout == expected


def test_single_file_single_violation(capsys, formatter, violation):
run(formatter, {"main.py": [violation]})
stdout, _ = capsys.readouterr()
expected = """\
{
"main.py": [
{
"code": "E222",
"filename": "main.py",
"line_number": 42,
"column_number": 4,
"text": "multiple spaces after operator",
"physical_line": "x = 1"
}
]
}
"""
assert stdout == expected


def test_single_file_multiple_violations(capsys, formatter, violation):
run(formatter, {"main.py": [violation] * 3})
stdout, _ = capsys.readouterr()
expected = """\
{
"main.py": [
{
"code": "E222",
"filename": "main.py",
"line_number": 42,
"column_number": 4,
"text": "multiple spaces after operator",
"physical_line": "x = 1"
},
{
"code": "E222",
"filename": "main.py",
"line_number": 42,
"column_number": 4,
"text": "multiple spaces after operator",
"physical_line": "x = 1"
},
{
"code": "E222",
"filename": "main.py",
"line_number": 42,
"column_number": 4,
"text": "multiple spaces after operator",
"physical_line": "x = 1"
}
]
}
"""
assert stdout == expected
10 changes: 4 additions & 6 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
[tox]
minversion = 2.3.1
envlist = flake8,pre-commit
envlist = py,flake8,pre-commit

[testenv]
deps =
flake8
pytest
commands =

[testenv:venv]
deps =
.
commands = {posargs}
pytest tests {posargs}

# Linters
[testenv:flake8]
Expand Down

0 comments on commit e6f208d

Please sign in to comment.