Skip to content

Commit

Permalink
Merge pull request #140 from openedx/bmtcril/finish_rendering
Browse files Browse the repository at this point in the history
Simple local report rendering
  • Loading branch information
bmtcril authored Jan 16, 2025
2 parents 5c4397a + 5058d4b commit 28debe3
Show file tree
Hide file tree
Showing 22 changed files with 351 additions and 72 deletions.
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
7 changes: 6 additions & 1 deletion code_annotations/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,15 @@ def generate_docs(config_file, verbosity, report_files):
try:
config = AnnotationConfig(config_file, verbosity)

if not report_files:
raise ConfigurationException(
"No report files provided. Please provide one or more report files to generate docs from."
)

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 }}
Loading

0 comments on commit 28debe3

Please sign in to comment.