Skip to content

Commit d082c46

Browse files
committed
feat: Add HTML report output, report docs
1 parent e6f63e6 commit d082c46

File tree

12 files changed

+253
-37
lines changed

12 files changed

+253
-37
lines changed

README.rst

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
code-annotations
22
=============================
33

4-
|pypi-badge| |CI| |codecov-badge| |doc-badge| |pyversions-badge|
5-
|license-badge|
6-
74
Extensible tools for parsing annotations in codebases
85

96
Overview
@@ -55,28 +52,3 @@ Have a question about this repository, or about Open edX in general? Please
5552
refer to this `list of resources`_ if you need any assistance.
5653

5754
.. _list of resources: https://open.edx.org/getting-help
58-
59-
60-
.. |pypi-badge| image:: https://img.shields.io/pypi/v/code-annotations.svg
61-
:target: https://pypi.python.org/pypi/code-annotations/
62-
:alt: PyPI
63-
64-
.. |CI| image:: https://github.com/openedx/code-annotations/workflows/Python%20CI/badge.svg?branch=master
65-
:target: https://github.com/openedx/code-annotations/actions?query=workflow%3A%22Python+CI%22
66-
:alt: CI
67-
68-
.. |codecov-badge| image:: http://codecov.io/github/edx/code-annotations/coverage.svg?branch=master
69-
:target: http://codecov.io/github/edx/code-annotations?branch=master
70-
:alt: Codecov
71-
72-
.. |doc-badge| image:: https://readthedocs.org/projects/code-annotations/badge/?version=latest
73-
:target: http://code-annotations.readthedocs.io/en/latest/
74-
:alt: Documentation
75-
76-
.. |pyversions-badge| image:: https://img.shields.io/pypi/pyversions/code-annotations.svg
77-
:target: https://pypi.python.org/pypi/code-annotations/
78-
:alt: Supported Python versions
79-
80-
.. |license-badge| image:: https://img.shields.io/github/license/edx/code-annotations.svg
81-
:target: https://github.com/openedx/code-annotations/blob/master/LICENSE.txt
82-
:alt: License

code_annotations/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
PACKAGE_DIR = os.path.dirname(os.path.realpath(__file__))
1818
DEFAULT_TEMPLATE_DIR = os.path.join(PACKAGE_DIR, "report_templates")
1919

20+
2021
class AnnotationConfig:
2122
"""
2223
Configuration shared among all Code Annotations commands.
@@ -67,9 +68,9 @@ def __init__(self, config_file_path, report_path_override=None, verbosity=1, sou
6768
os.path.join(DEFAULT_TEMPLATE_DIR, self.rendered_report_format)
6869
)
6970
self.rendered_report_dir = raw_config.get('rendered_report_dir', 'annotation_reports')
70-
self.rendered_report_source_link_prefix = raw_config.get('rendered_report_source_link_prefix')
71+
self.rendered_report_source_link_prefix = raw_config.get('rendered_report_source_link_prefix', None)
7172
self.trim_filename_prefixes = raw_config.get('trim_filename_prefixes', [])
72-
self.third_party_package_location = raw_config.get('third_party_package_location', None)
73+
self.third_party_package_location = raw_config.get('third_party_package_location', "site-packages")
7374
self.rendered_report_file_extension = f".{self.rendered_report_format}"
7475

7576
self._configure_annotations(raw_config)

code_annotations/generate_docs.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ def _add_report_file_to_full_report(self, report_file, report):
8686
else:
8787
report[trimmed_filename] = loaded_report[filename]
8888

89-
9089
def _aggregate_reports(self):
9190
"""
9291
Combine all of the given report files into a single report object.
@@ -105,6 +104,7 @@ def _write_doc_file(self, doc_title, doc_filename, doc_data):
105104
Write out a single report file with the given data. This is rendered using the configured top level template.
106105
107106
Args:
107+
doc_title: Title to use for the document.
108108
doc_filename: Filename to write to.
109109
doc_data: Dict of reporting data to use, in the {'file name': [list, of, annotations,]} style.
110110
"""
@@ -128,8 +128,7 @@ def _write_doc_file(self, doc_title, doc_filename, doc_data):
128128
slugify=slugify,
129129
source_link_prefix=self.config.rendered_report_source_link_prefix,
130130
third_party_package_location=self.config.third_party_package_location,
131-
),
132-
)
131+
))
133132

134133
def _generate_per_choice_docs(self):
135134
"""
@@ -155,7 +154,9 @@ def _generate_per_annotation_docs(self):
155154
if report_annotation['annotation_token'] == annotation:
156155
annotation_report[filename].append(report_annotation)
157156

158-
self._write_doc_file(f"All References to Annotation '{annotation}'", f'annotation_{annotation}', annotation_report)
157+
self._write_doc_file(
158+
f"All References to Annotation '{annotation}'", f'annotation_{annotation}', annotation_report
159+
)
159160

160161
def render(self):
161162
"""
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{% if is_third_party %}
2+
{# no links for third party code since we don't know where to link to #}
3+
{% if annotation.extra and annotation.extra.object_id %}
4+
{{ annotation.extra.object_id }} {% if annotation.line_number > 0 %}line {{ annotation.line_number }}{% endif %}: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
5+
{% else %}
6+
{% if loop.changed(annotation.line_number)%}{{ filename }}:{{ annotation.line_number }}<br />{% endif %}:
7+
{{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
8+
{% endif %}
9+
10+
{% elif annotation.extra and annotation.extra.object_id %}
11+
<a href="{{ source_link_prefix }}{{ filename }}#L{{ annotation.line_number }}" target="_blank">{{ annotation.extra.object_id }} {% if annotation.line_number > 0 %}line {{ annotation.line_number }}{% endif %}</a>: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
12+
{% else %}
13+
<a href="{{ source_link_prefix }}{{ filename }}#L{{ annotation.line_number }}" target="_blank">`{{ filename }}:{{ annotation.line_number }}: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
14+
{% endif %}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{% if annotation.annotation_data is sequence and annotation.annotation_data is not string %}
2+
{% for a in annotation.annotation_data %}
3+
<a href="choice-{{ slugify(a) }}.html">{{ a }}</a>{% if not loop.last %}, {% endif %}
4+
{% endfor %}
5+
6+
{% else %}
7+
{{ annotation.annotation_data }}
8+
{% endif %}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{% extends "base.tpl" %}
2+
{% block content %}
3+
Annotations found in {{ report|length }} files.
4+
5+
{% for filename in report %}
6+
{% set is_third_party = third_party_package_location in filename %}
7+
8+
<h2 id="file-{{ slugify(filename) }}">{{ filename }}</h2>
9+
<div class="file-annotations">
10+
{{ report[filename]|length }} annotations {% if is_third_party %}(installed package){% endif %}<br />
11+
</div>
12+
13+
{% for annotation in report[filename] %}
14+
{% if loop.changed(annotation.report_group_id) %}
15+
{% if not loop.first %}</ul></div>{% endif %}
16+
<div class="group-annotations"><ul>
17+
{% endif %}
18+
<li>{% include 'annotation.tpl' %}</li>
19+
{% if loop.last %}
20+
</ul></div>
21+
{% endif %}
22+
{% endfor %}
23+
24+
25+
{% endfor %}
26+
27+
{% endblock %}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<html>
2+
<head>
3+
<title>{{ doc_title }}</title>
4+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5+
<style>
6+
body {
7+
font-family: 'Trebuchet MS', sans-serif;
8+
}
9+
10+
.title {
11+
text-align: center;
12+
}
13+
14+
.table {
15+
display: table;
16+
border-spacing: 12px;
17+
}
18+
19+
.row {
20+
display: table-row;
21+
margin-bottom: 0;
22+
margin-top: 0;
23+
width: 100%;
24+
}
25+
26+
.cell1 {
27+
display: table-cell;
28+
width: 20%;
29+
margin-right: 1%;
30+
border: 1px solid #ccc;
31+
margin 12px;
32+
background-color: #ffffee;
33+
}
34+
35+
.cell2 {
36+
display: table-cell;
37+
width: 79%;
38+
margin-right: 1%;
39+
margin 12px;
40+
}
41+
42+
.group-annotations {
43+
border: 1px solid #ccc;
44+
margin: 10px;
45+
}
46+
</style>
47+
</head>
48+
<body>
49+
<h1 class="title">{{ doc_title }}</h1>
50+
51+
<div class="table">
52+
<div class="row">
53+
<div class="cell1">
54+
<h3><a href="index.html">Home</a></h3>
55+
56+
<h3>Annotations</h3>
57+
58+
<ul>
59+
{% for a in all_annotations %}
60+
<li><a href="annotation-{{ slugify(a) }}.html">annotation_{{ slugify(a) }}</a></li>
61+
{% endfor %}
62+
</ul>
63+
64+
<h3>Choices</h3>
65+
66+
<ul>
67+
{% for choice in all_choices %}
68+
<li><a href="choice-{{ slugify(choice) }}.html">choice_{{ slugify(choice) }}</a></li>
69+
{% endfor %}
70+
</ul>
71+
</div>
72+
<div class="cell2">
73+
<h2>Files in this page</h2>
74+
<ul>
75+
{% for filename in report %}
76+
<li><a href="#file-{{ slugify(filename) }}">{{ filename }}</a></li>
77+
{% endfor %}
78+
</ul>
79+
80+
{% block content %}{% endblock %}
81+
</div>
82+
</div>
83+
</div>
84+
{% block footer %}
85+
<div class="footer">
86+
<br /><br />
87+
<hr />
88+
Built at {{ create_time.strftime('%Y-%m-%d %H:%M:%S %Z') }}
89+
</div>
90+
{% endblock %}
91+
</body>
92+
</html>

docs/configuration.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ Configuring Code Annotations is a pretty simple affair. Here is an example showi
2626
- py3
2727
javascript:
2828
- js
29+
# Options only used for human readable reports
30+
report_template_dir: /my_custom_templates/report_templates/
31+
rendered_report_dir: rendered_reports
32+
rendered_report_format: html
33+
rendered_report_source_link_prefix: https://github.com/my_org/my_project/blob/master/
34+
trim_filename_prefixes:
35+
- /my_org/my_project/
36+
- /my_project/venv/lib/python3.11/
37+
third_party_package_location: site-packages
2938
3039
``source_path``
3140
The file or directory to be searched for annotations. If a directory, it will be searched recursively. This can be
@@ -68,3 +77,21 @@ Configuring Code Annotations is a pretty simple affair. Here is an example showi
6877
extensions are turned on here. The key is the extension name, as given in the ``setup.py`` or ``setup.cfg`` of the
6978
package that installed the extension. The values are a list of file extensions that, when found, will be passed to
7079
the extension for annotation searching. See :doc:`extensions` for details.
80+
81+
``report_template_dir`` (optional)
82+
When running the ``generate_docs`` comman you can specify a custom template directory here to override the default templates if you would like a different look.
83+
84+
``rendered_report_dir`` (optional)
85+
When running the ``generate_docs`` command, this option specifies the directory where the rendered report will be written. The default is ``annotation_reports`` in the current working directory.
86+
87+
``rendered_report_format`` (optional)
88+
When running the ``generate_docs`` command, this option specifies the format of the rendered report. Options are ``html`` and ``rst``. The default is ``rst``.
89+
90+
``rendered_report_source_link_prefix`` (optional)
91+
When running the ``generate_docs`` command, this option specifies the URL prefix to use when linking to source files in the rendered report. When specified, "local" source files (those not found in site-packages) will be appended to this setting to create hyperlinks to the lines in source files online. For Github links this is the correct format: ``https://github.com/openedx/edx-platform/blob/master/``. The default is an None.
92+
93+
``trim_filename_prefixes`` (optional)
94+
When running the ``generate_docs`` command, this option specifies a list of prefixes to remove from the beginning of filenames in the rendered report. This is useful for making the report more readable by removing long, repetitive prefixes of the type often found in a Django search. The default is an empty list.
95+
96+
``third_party_package_location`` (optional)
97+
When running the ``generate_docs`` command, this option specifies the location of third party packages that may have been found in a Django search. This is used to determine if a file is a third party file or not. The default is ``site-packages``.

docs/getting_started.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,17 @@ Add more structure to your annotations
126126
Annotations can be more than simple messages. They can enforce the use of choices from a fixed list, and can be grouped
127127
to provide more context-aware information. See :doc:`configuration` and :doc:`writing_annotations` for more information
128128
on how to use those options.
129+
130+
Get a human readable report
131+
---------------------------
132+
The output generated by the search commands is a YAML file. To get a human readable report generated from one of those files in either rst or html format, you can use the ``generate_docs`` command.
133+
134+
There are several configuration options available for this command, including the ability to specify the output format, the output directory, and create links to the source files on sites like Github. For more information, see :doc:`configuration`. Once your configuration is set, you can run:
135+
136+
.. code-block:: bash
137+
138+
$ code_annotations generate_docs --config_file /path/to/your/config /path/to/your/report.yaml
139+
140+
Which will generate files in the output directory you configured. From there you can open the files in your browser to see the report, if you chose HTML, or use a tool like `restview`_ to render the RST files to your browser.
141+
142+
.. _restview: https://pypi.python.org/pypi/restview

tests/test_configurations/.annotations_test_success_with_report_docs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
source_path: tests/extensions/javascript_test_files/
22
report_path: test_reports
33
safelist_path: .annotation_safe_list.yml
4-
report_template_dir: code_annotations/report_templates/
4+
report_template_dir: code_annotations/report_templates/rst
55
rendered_report_dir: test_reports/
6-
rendered_report_file_extension: .rst
6+
rendered_report_format: rst
77
rendered_report_source_link_prefix: https://github.com/openedx/edx-platform/tree/master/
8+
89
coverage_target: 50.0
910
annotations:
1011
".. no_pii:":

0 commit comments

Comments
 (0)