diff --git a/MANIFEST.in b/MANIFEST.in
index 08f31b1..7061606 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -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
diff --git a/README.rst b/README.rst
index dd91285..37e6f32 100644
--- a/README.rst
+++ b/README.rst
@@ -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
@@ -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
diff --git a/code_annotations/base.py b/code_annotations/base.py
index dddfcb7..6f7964d 100644
--- a/code_annotations/base.py
+++ b/code_annotations/base.py
@@ -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:
"""
@@ -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()
diff --git a/code_annotations/cli.py b/code_annotations/cli.py
index 853da13..9e56f02 100644
--- a/code_annotations/cli.py
+++ b/code_annotations/cli.py
@@ -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):
diff --git a/code_annotations/generate_docs.py b/code_annotations/generate_docs.py
index abf8319..e32dc37 100644
--- a/code_annotations/generate_docs.py
+++ b/code_annotations/generate_docs.py
@@ -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(
@@ -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
@@ -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):
"""
@@ -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.
"""
@@ -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):
"""
@@ -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):
"""
@@ -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()
diff --git a/code_annotations/report_templates/annotation.tpl b/code_annotations/report_templates/annotation.tpl
deleted file mode 100644
index d0ce6c8..0000000
--- a/code_annotations/report_templates/annotation.tpl
+++ /dev/null
@@ -1,5 +0,0 @@
-{% if annotation.extra and annotation.extra.object_id %}
-`<{{ annotation.extra.object_id }}> line {{ annotation.line_number }} <{{ 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 %}
diff --git a/code_annotations/report_templates/annotation_group.tpl b/code_annotations/report_templates/annotation_group.tpl
deleted file mode 100644
index ed719b0..0000000
--- a/code_annotations/report_templates/annotation_group.tpl
+++ /dev/null
@@ -1,3 +0,0 @@
-.. _index.rst#{{ slugify(filename + '-' + annotation.report_group_id |string) }}:
-.. admonition:: Group "{{ group_mapping[annotation.annotation_token] }}"
-
diff --git a/code_annotations/report_templates/base.tpl b/code_annotations/report_templates/base.tpl
deleted file mode 100644
index b460430..0000000
--- a/code_annotations/report_templates/base.tpl
+++ /dev/null
@@ -1,14 +0,0 @@
-{% block content %}{% endblock %}
-
-{% for choice in all_choices %}
-.. _choice_{{ slugify(choice) }}: {{ slugify('choice_' + choice) + '.rst' }}
-{% endfor %}
-
-{% for annotation in all_annotations %}
-.. _annotation_{{ slugify(annotation) }}: {{ slugify('annotation_' + annotation) + '.rst' }}
-{% endfor %}
-
-
-{% block footer %}
-Built at {{ create_time }}
-{% endblock %}
diff --git a/code_annotations/report_templates/html/annotation.tpl b/code_annotations/report_templates/html/annotation.tpl
new file mode 100644
index 0000000..8f4055b
--- /dev/null
+++ b/code_annotations/report_templates/html/annotation.tpl
@@ -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 }}
{% endif %}:
+ {{ 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 %}: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
+{% else %}
+`{{ filename }}:{{ annotation.line_number }}: {{ annotation.annotation_token }} {% include "annotation_data.tpl" %}
+{% endif %}
diff --git a/code_annotations/report_templates/html/annotation_data.tpl b/code_annotations/report_templates/html/annotation_data.tpl
new file mode 100644
index 0000000..a95251c
--- /dev/null
+++ b/code_annotations/report_templates/html/annotation_data.tpl
@@ -0,0 +1,8 @@
+{% if annotation.annotation_data is sequence and annotation.annotation_data is not string %}
+{% for a in annotation.annotation_data %}
+{{ a }}{% if not loop.last %}, {% endif %}
+{% endfor %}
+
+{% else %}
+{{ annotation.annotation_data }}
+{% endif %}
diff --git a/code_annotations/report_templates/html/annotation_list.tpl b/code_annotations/report_templates/html/annotation_list.tpl
new file mode 100644
index 0000000..83434f2
--- /dev/null
+++ b/code_annotations/report_templates/html/annotation_list.tpl
@@ -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 %}
+
+