Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple local report rendering #140

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ include CONTRIBUTING.rst
include LICENSE.txt
include README.rst
include requirements/base.in
recursive-include code_annotations *.html *.png *.gif *js *.css *jpg *jpeg *svg *py *.yaml *.yml
recursive-include code_annotations *.tpl *.html *.png *.gif *js *.css *jpg *jpeg *svg *py *.yaml *.yml
28 changes: 0 additions & 28 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
code-annotations
=============================

|pypi-badge| |CI| |codecov-badge| |doc-badge| |pyversions-badge|
|license-badge|

Extensible tools for parsing annotations in codebases

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

.. _list of resources: https://open.edx.org/getting-help


.. |pypi-badge| image:: https://img.shields.io/pypi/v/code-annotations.svg
:target: https://pypi.python.org/pypi/code-annotations/
:alt: PyPI

.. |CI| image:: https://github.com/openedx/code-annotations/workflows/Python%20CI/badge.svg?branch=master
:target: https://github.com/openedx/code-annotations/actions?query=workflow%3A%22Python+CI%22
:alt: CI

.. |codecov-badge| image:: http://codecov.io/github/edx/code-annotations/coverage.svg?branch=master
:target: http://codecov.io/github/edx/code-annotations?branch=master
:alt: Codecov

.. |doc-badge| image:: https://readthedocs.org/projects/code-annotations/badge/?version=latest
:target: http://code-annotations.readthedocs.io/en/latest/
:alt: Documentation

.. |pyversions-badge| image:: https://img.shields.io/pypi/pyversions/code-annotations.svg
:target: https://pypi.python.org/pypi/code-annotations/
:alt: Supported Python versions

.. |license-badge| image:: https://img.shields.io/github/license/edx/code-annotations.svg
:target: https://github.com/openedx/code-annotations/blob/master/LICENSE.txt
:alt: License
18 changes: 14 additions & 4 deletions code_annotations/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
from code_annotations.exceptions import ConfigurationException
from code_annotations.helpers import VerboseEcho

PACKAGE_DIR = os.path.dirname(os.path.realpath(__file__))
DEFAULT_TEMPLATE_DIR = os.path.join(PACKAGE_DIR, "report_templates")


class AnnotationConfig:
"""
Expand Down Expand Up @@ -58,10 +61,17 @@ def __init__(self, config_file_path, report_path_override=None, verbosity=1, sou
self.echo(f"Configured for source path: {self.source_path}")

self._configure_coverage(raw_config.get('coverage_target', None))
self.report_template_dir = raw_config.get('report_template_dir')
self.rendered_report_dir = raw_config.get('rendered_report_dir')
self.rendered_report_file_extension = raw_config.get('rendered_report_file_extension')
self.rendered_report_source_link_prefix = raw_config.get('rendered_report_source_link_prefix')

self.rendered_report_format = raw_config.get('rendered_report_format', 'rst')
self.report_template_dir = raw_config.get(
'report_template_dir',
os.path.join(DEFAULT_TEMPLATE_DIR, self.rendered_report_format)
)
self.rendered_report_dir = raw_config.get('rendered_report_dir', 'annotation_reports')
self.rendered_report_source_link_prefix = raw_config.get('rendered_report_source_link_prefix', None)
self.trim_filename_prefixes = raw_config.get('trim_filename_prefixes', [])
self.third_party_package_location = raw_config.get('third_party_package_location', "site-packages")
self.rendered_report_file_extension = f".{self.rendered_report_format}"

self._configure_annotations(raw_config)
self._configure_extensions()
Expand Down
2 changes: 1 addition & 1 deletion code_annotations/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def generate_docs(config_file, verbosity, report_files):
for key in (
"report_template_dir",
"rendered_report_dir",
"rendered_report_file_extension",
"rendered_report_format",
"rendered_report_source_link_prefix",
):
if not getattr(config, key):
Expand Down
30 changes: 20 additions & 10 deletions code_annotations/generate_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ def __init__(self, config, report_files):
self.config = config
self.echo = self.config.echo
self.report_files = report_files
self.create_time = datetime.datetime.utcnow().isoformat()

self.create_time = datetime.datetime.now(tz=datetime.timezone.utc)
self.full_report = self._aggregate_reports()

self.jinja_environment = jinja2.Environment(
Expand Down Expand Up @@ -62,6 +61,12 @@ def _add_report_file_to_full_report(self, report_file, report):
loaded_report = yaml.safe_load(report_file)

for filename in loaded_report:
trimmed_filename = filename
for prefix in self.config.trim_filename_prefixes:
if filename.startswith(prefix):
trimmed_filename = filename[len(prefix):]
break

if filename in report:
for loaded_annotation in loaded_report[filename]:
found = False
Expand All @@ -74,9 +79,9 @@ def _add_report_file_to_full_report(self, report_file, report):
break

if not found:
report[filename].append(loaded_annotation)
report[trimmed_filename].append(loaded_annotation)
else:
report[filename] = loaded_report[filename]
report[trimmed_filename] = loaded_report[filename]

def _aggregate_reports(self):
"""
Expand All @@ -91,11 +96,12 @@ def _aggregate_reports(self):

return report

def _write_doc_file(self, doc_filename, doc_data):
def _write_doc_file(self, doc_title, doc_filename, doc_data):
"""
Write out a single report file with the given data. This is rendered using the configured top level template.

Args:
doc_title: Title to use for the document.
doc_filename: Filename to write to.
doc_data: Dict of reporting data to use, in the {'file name': [list, of, annotations,]} style.
"""
Expand All @@ -110,14 +116,16 @@ def _write_doc_file(self, doc_filename, doc_data):

with open(full_doc_filename, 'w') as output:
output.write(self.top_level_template.render(
doc_title=doc_title,
create_time=self.create_time,
report=doc_data,
all_choices=self.all_choices,
all_annotations=self.config.annotation_tokens,
group_mapping=self.group_mapping,
slugify=slugify,
source_link_prefix=self.config.rendered_report_source_link_prefix)
)
source_link_prefix=self.config.rendered_report_source_link_prefix,
third_party_package_location=self.config.third_party_package_location,
))

def _generate_per_choice_docs(self):
"""
Expand All @@ -130,7 +138,7 @@ def _generate_per_choice_docs(self):
if isinstance(annotation['annotation_data'], list) and choice in annotation['annotation_data']:
choice_report[filename].append(annotation)

self._write_doc_file(f'choice_{choice}', choice_report)
self._write_doc_file(f"All References to Choice '{choice}'", f'choice_{choice}', choice_report)

def _generate_per_annotation_docs(self):
"""
Expand All @@ -143,13 +151,15 @@ def _generate_per_annotation_docs(self):
if report_annotation['annotation_token'] == annotation:
annotation_report[filename].append(report_annotation)

self._write_doc_file(f'annotation_{annotation}', annotation_report)
self._write_doc_file(
f"All References to Annotation '{annotation}'", f'annotation_{annotation}', annotation_report
)

def render(self):
"""
Perform the rendering of all documentation using the configured Jinja2 templates.
"""
# Generate the top level list of all annotations
self._write_doc_file('index', self.full_report)
self._write_doc_file("Complete Annotation List", 'index', self.full_report)
self._generate_per_choice_docs()
self._generate_per_annotation_docs()
5 changes: 0 additions & 5 deletions code_annotations/report_templates/annotation.tpl

This file was deleted.

3 changes: 0 additions & 3 deletions code_annotations/report_templates/annotation_group.tpl

This file was deleted.

14 changes: 0 additions & 14 deletions code_annotations/report_templates/base.tpl

This file was deleted.

14 changes: 14 additions & 0 deletions code_annotations/report_templates/html/annotation.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% if is_third_party %}
{# no links for third party code since we don't know where to link to #}
{% if annotation.extra and annotation.extra.object_id %}
{{ annotation.extra.object_id }} {% if annotation.line_number > 0 %}line {{ annotation.line_number }}{% endif %}: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
{% else %}
{% if loop.changed(annotation.line_number)%}{{ filename }}:{{ annotation.line_number }}<br />{% endif %}:
{{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
{% endif %}

{% elif annotation.extra and annotation.extra.object_id %}
<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" %}
{% else %}
<a href="{{ source_link_prefix }}{{ filename }}#L{{ annotation.line_number }}" target="_blank">`{{ filename }}:{{ annotation.line_number }}: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
{% endif %}
8 changes: 8 additions & 0 deletions code_annotations/report_templates/html/annotation_data.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% if annotation.annotation_data is sequence and annotation.annotation_data is not string %}
{% for a in annotation.annotation_data %}
<a href="choice-{{ slugify(a) }}.html">{{ a }}</a>{% if not loop.last %}, {% endif %}
{% endfor %}

{% else %}
{{ annotation.annotation_data }}
{% endif %}
27 changes: 27 additions & 0 deletions code_annotations/report_templates/html/annotation_list.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% extends "base.tpl" %}
{% block content %}
Annotations found in {{ report|length }} files.

{% for filename in report %}
{% set is_third_party = third_party_package_location in filename %}

<h2 id="file-{{ slugify(filename) }}">{{ filename }}</h2>
<div class="file-annotations">
{{ report[filename]|length }} annotations {% if is_third_party %}(installed package){% endif %}<br />
</div>

{% for annotation in report[filename] %}
{% if loop.changed(annotation.report_group_id) %}
{% if not loop.first %}</ul></div>{% endif %}
<div class="group-annotations"><ul>
{% endif %}
<li>{% include 'annotation.tpl' %}</li>
{% if loop.last %}
</ul></div>
{% endif %}
{% endfor %}


{% endfor %}

{% endblock %}
92 changes: 92 additions & 0 deletions code_annotations/report_templates/html/base.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<html>
<head>
<title>{{ doc_title }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
body {
font-family: 'Trebuchet MS', sans-serif;
}

.title {
text-align: center;
}

.table {
display: table;
border-spacing: 12px;
}

.row {
display: table-row;
margin-bottom: 0;
margin-top: 0;
width: 100%;
}

.cell1 {
display: table-cell;
width: 20%;
margin-right: 1%;
border: 1px solid #ccc;
margin 12px;
background-color: #ffffee;
}

.cell2 {
display: table-cell;
width: 79%;
margin-right: 1%;
margin 12px;
}

.group-annotations {
border: 1px solid #ccc;
margin: 10px;
}
</style>
</head>
<body>
<h1 class="title">{{ doc_title }}</h1>

<div class="table">
<div class="row">
<div class="cell1">
<h3><a href="index.html">Home</a></h3>

<h3>Annotations</h3>

<ul>
{% for a in all_annotations %}
<li><a href="annotation-{{ slugify(a) }}.html">annotation_{{ slugify(a) }}</a></li>
{% endfor %}
</ul>

<h3>Choices</h3>

<ul>
{% for choice in all_choices %}
<li><a href="choice-{{ slugify(choice) }}.html">choice_{{ slugify(choice) }}</a></li>
{% endfor %}
</ul>
</div>
<div class="cell2">
<h2>Files in this page</h2>
<ul>
{% for filename in report %}
<li><a href="#file-{{ slugify(filename) }}">{{ filename }}</a></li>
{% endfor %}
</ul>

{% block content %}{% endblock %}
</div>
</div>
</div>
{% block footer %}
<div class="footer">
<br /><br />
<hr />
Built at {{ create_time.strftime('%Y-%m-%d %H:%M:%S %Z') }}
</div>
{% endblock %}
</body>
</html>
13 changes: 13 additions & 0 deletions code_annotations/report_templates/rst/annotation.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% if is_third_party %}
{# no links for third party code since we don't know where to link to #}
{% if annotation.extra and annotation.extra.object_id %}
{{ annotation.extra.object_id }} {% if annotation.line_number > 0 %}line {{ annotation.line_number }}{% endif %}: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
{% else %}
{{ filename }}:{{ annotation.line_number }}: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
{% endif %}

{% elif annotation.extra and annotation.extra.object_id %}
`{{ annotation.extra.object_id }} {% if annotation.line_number > 0 %}line {{ annotation.line_number }}{% endif %} <{{ source_link_prefix }}{{ filename }}#L{{ annotation.line_number }}>`_: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
{% else %}
`{{ filename }}:{{ annotation.line_number }} <{{ source_link_prefix }}{{ filename }}#L{{ annotation.line_number }}>`_: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
{% endif %}
2 changes: 2 additions & 0 deletions code_annotations/report_templates/rst/annotation_group.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.. _index.rst#{{ slugify(filename + '-' + annotation.report_group_id |string) }}:
.. admonition:: {{ group_mapping[annotation.annotation_token] or annotation.annotation_token }}
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
{% extends "base.tpl" %}
{% block content %}
Complete Annotation List
------------------------
Annotations found in {{ report|length }} files.

{% for filename in report %}
{{ filename }} has {{ report[filename]|length }} annotations.
{% set is_third_party = third_party_package_location in filename %}

{{ filename }}
{{ "-" * filename|length }}

.. note:: {{ report[filename]|length }} annotations {% if is_third_party %}(installed package){% endif %}


{% for annotation in report[filename] %}
{% if annotation.report_group_id %}
{% if loop.changed(annotation.report_group_id) %}
{% include 'annotation_group.tpl' %}


{% endif %}
* {% include 'annotation.tpl' %}

Expand Down
Loading
Loading