Page Menu
Home
Software Heritage
Search
Configure Global Search
Log In
Files
F7124700
D2667.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
15 KB
Subscribers
None
D2667.diff
View Options
diff --git a/swh/web/api/apidoc.py b/swh/web/api/apidoc.py
--- a/swh/web/api/apidoc.py
+++ b/swh/web/api/apidoc.py
@@ -63,6 +63,7 @@
self.reqheaders_set = set()
self.resheaders_set = set()
self.field_list_visited = False
+ self.current_json_obj = None
def process_paragraph(self, par):
"""
@@ -82,8 +83,12 @@
# remove parsed document markups
par = re.sub('<[^<]+?>', '', par)
# api urls cleanup to generate valid links afterwards
- par = re.sub(r'\(\w+\)', '', par)
- par = re.sub(r'\[.*\]', '', par)
+ subs_made = 1
+ while subs_made:
+ (par, subs_made) = re.subn(r'(:http:.*)(\(\w+\))', r'\1', par)
+ subs_made = 1
+ while subs_made:
+ (par, subs_made) = re.subn(r'(:http:.*)(\[.*\])', r'\1', par)
par = par.replace('//', '/')
# transform references to api endpoints into valid rst links
par = re.sub(':http:get:`([^,]*)`', r'`<\1>`_', par)
@@ -135,6 +140,7 @@
'type': field_data[1],
'doc': text})
self.inputs_set.add(field_data[2])
+ self.current_json_obj = self.data['inputs'][-1]
# Response type
if (field_data[0] in self.response_json_array_roles or
field_data[0] in self.response_json_object_roles):
@@ -150,6 +156,7 @@
'type': field_data[1],
'doc': text})
self.returns_set.add(field_data[2])
+ self.current_json_obj = self.data['returns'][-1]
# Status Codes
if field_data[0] in self.status_code_roles:
if field_data[1] not in self.status_codes_set:
@@ -218,6 +225,14 @@
if isinstance(child, docutils.nodes.paragraph):
line_text = self.process_paragraph(str(child))
self.data['description'] += '\t* %s\n' % line_text
+ elif self.current_json_obj:
+ self.current_json_obj['doc'] += '\n\n'
+ for child in node.traverse():
+ # process list item
+ if isinstance(child, docutils.nodes.paragraph):
+ line_text = self.process_paragraph(str(child))
+ self.current_json_obj['doc'] += '\t\t* %s\n' % line_text
+ self.current_json_obj = None
def visit_warning(self, node):
text = self.process_paragraph(str(node))
diff --git a/swh/web/assets/src/bundles/webapp/webapp.css b/swh/web/assets/src/bundles/webapp/webapp.css
--- a/swh/web/assets/src/bundles/webapp/webapp.css
+++ b/swh/web/assets/src/bundles/webapp/webapp.css
@@ -507,6 +507,12 @@
margin: 10px;
}
+.swh-apidoc .swh-rst blockquote {
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+
a.toggle-col {
text-decoration: none;
}
diff --git a/swh/web/common/middlewares.py b/swh/web/common/middlewares.py
--- a/swh/web/common/middlewares.py
+++ b/swh/web/common/middlewares.py
@@ -3,10 +3,11 @@
# License: GNU Affero General Public License version 3, or any later version
# See top-level LICENSE file for more information
-from bs4 import BeautifulSoup
from htmlmin import minify
import sentry_sdk
+from swh.web.common.utils import prettify_html
+
class HtmlPrettifyMiddleware(object):
"""
@@ -22,11 +23,10 @@
if 'text/html' in response.get('Content-Type', ''):
if hasattr(response, 'content'):
content = response.content
- response.content = BeautifulSoup(content, 'lxml').prettify()
+ response.content = prettify_html(content)
elif hasattr(response, 'streaming_content'):
content = b''.join(response.streaming_content)
- response.streaming_content = \
- BeautifulSoup(content, 'lxml').prettify()
+ response.streaming_content = prettify_html(content)
return response
diff --git a/swh/web/common/swh_templatetags.py b/swh/web/common/swh_templatetags.py
--- a/swh/web/common/swh_templatetags.py
+++ b/swh/web/common/swh_templatetags.py
@@ -6,8 +6,6 @@
import json
import re
-from inspect import cleandoc
-
from django import template
from django.core.serializers.json import DjangoJSONEncoder
from django.utils.safestring import mark_safe
@@ -21,12 +19,12 @@
@register.filter
-def safe_docstring_display(docstring):
+def docstring_display(docstring):
"""
Utility function to htmlize reST-formatted documentation in browsable
api.
"""
- return rst_to_html(cleandoc(docstring))
+ return rst_to_html(docstring)
@register.filter
diff --git a/swh/web/common/utils.py b/swh/web/common/utils.py
--- a/swh/web/common/utils.py
+++ b/swh/web/common/utils.py
@@ -14,6 +14,8 @@
import docutils.parsers.rst
import docutils.utils
+from bs4 import BeautifulSoup
+
from docutils.core import publish_parts
from docutils.writers.html5_polyglot import Writer, HTMLTranslator
@@ -477,3 +479,16 @@
pp = publish_parts(rst, writer=_HTML_WRITER,
settings_overrides=settings)
return f'<div class="swh-rst">{pp["html_body"]}</div>'
+
+
+def prettify_html(html: str) -> str:
+ """
+ Prettify an HTML document.
+
+ Args:
+ html: Input HTML document
+
+ Returns:
+ The prettified HTML document
+ """
+ return BeautifulSoup(html, 'lxml').prettify()
diff --git a/swh/web/templates/api/apidoc.html b/swh/web/templates/api/apidoc.html
--- a/swh/web/templates/api/apidoc.html
+++ b/swh/web/templates/api/apidoc.html
@@ -35,7 +35,7 @@
{% if description %}
<div>
<h4> Description </h4>
- {{ description | safe_docstring_display | safe }}
+ {{ description | docstring_display | safe }}
</div>
{% endif %}
{% if response_data is not None %}
@@ -71,7 +71,7 @@
<tbody>
{% for url in urls %}
<tr>
- <td>{{ url.rule | safe_docstring_display | safe }}</td>
+ <td>{{ url.rule | docstring_display | safe }}</td>
<td>{{ url.methods | dictsort:0 | join:', ' }}</td>
</tr>
{% endfor %}
@@ -86,7 +86,7 @@
{% for arg in args %}
<dl class="row">
<dt class="col col-md-2 text-right"> {{ arg.name }} ({{ arg.type }}) </dt>
- <dd class="col col-md-9"> {{ arg.doc | safe_docstring_display | safe }} </dd>
+ <dd class="col col-md-9"> {{ arg.doc | docstring_display | safe }} </dd>
</dl>
{% endfor %}
</div>
@@ -98,7 +98,7 @@
{% for param in params %}
<dl class="row">
<dt class="col col-md-2 text-right"> {{ param.name }} ({{ param.type }}) </dt>
- <dd class="col col-md-9"> {{ param.doc | safe_docstring_display | safe }} </dd>
+ <dd class="col col-md-9"> {{ param.doc | docstring_display | safe }} </dd>
</dl>
{% endfor %}
</div>
@@ -110,7 +110,7 @@
{% for header in reqheaders %}
<dl class="row">
<dt class="col col-md-2 text-right"> {{ header.name }} </dt>
- <dd class="col col-md-9"> {{ header.doc | safe_docstring_display | safe }} </dd>
+ <dd class="col col-md-9"> {{ header.doc | docstring_display | safe }} </dd>
</dl>
{% endfor %}
</div>
@@ -133,7 +133,7 @@
an object containing the following keys:
{% endif %}
{% if inputs_list != '' %}
- {{ inputs_list | safe_docstring_display | safe }}
+ {{ inputs_list | docstring_display | safe }}
{% endif %}
</p>
</dd>
@@ -147,7 +147,7 @@
{% for header in resheaders %}
<dl class="row">
<dt class="col col-md-2 text-right"> {{ header.name }} </dt>
- <dd class="col col-md-9"> {{ header.doc | safe_docstring_display | safe }} </dd>
+ <dd class="col col-md-9"> {{ header.doc | docstring_display | safe }} </dd>
</dl>
{% endfor %}
</div>
@@ -170,7 +170,7 @@
an object containing the following keys:
{% endif %}
{% if returns_list != '' %}
- {{ returns_list | safe_docstring_display | safe }}
+ {{ returns_list | docstring_display | safe }}
{% endif %}
</p>
</dd>
@@ -184,7 +184,7 @@
{% for status in status_codes %}
<dl class="row">
<dt class="col col-md-2 text-right"> {{ status.code }} </dt>
- <dd class="col col-md-9"> {{ status.doc | safe_docstring_display | safe }} </dd>
+ <dd class="col col-md-9"> {{ status.doc | docstring_display | safe }} </dd>
</dl>
{% endfor %}
</div>
diff --git a/swh/web/templates/api/endpoints.html b/swh/web/templates/api/endpoints.html
--- a/swh/web/templates/api/endpoints.html
+++ b/swh/web/templates/api/endpoints.html
@@ -59,7 +59,7 @@
{% endif %}
<td class="d-none d-sm-table-cell">
<a href="{% url doc.route_view_name %}">
- {{ doc.doc_intro | safe_docstring_display | safe }}
+ {{ doc.doc_intro | docstring_display | safe }}
</a>
</td>
</tr>
diff --git a/swh/web/tests/api/test_apidoc.py b/swh/web/tests/api/test_apidoc.py
--- a/swh/web/tests/api/test_apidoc.py
+++ b/swh/web/tests/api/test_apidoc.py
@@ -3,6 +3,8 @@
# License: GNU Affero General Public License version 3, or any later version
# See top-level LICENSE file for more information
+import textwrap
+
import pytest
from rest_framework.response import Response
@@ -12,8 +14,8 @@
from swh.web.api.apidoc import api_doc, _parse_httpdomain_doc
from swh.web.api.apiurls import api_route
from swh.web.common.exc import BadInputExc, ForbiddenExc, NotFoundExc
-from swh.web.common.utils import reverse
-from swh.web.tests.django_asserts import assert_template_used, assert_contains
+from swh.web.common.utils import reverse, prettify_html
+from swh.web.tests.django_asserts import assert_template_used
_httpdomain_doc = """
@@ -229,7 +231,7 @@
expected_reqheaders = [{
'doc': ('the requested response content type, either '
- '``application/json`` or ``application/yaml``'),
+ '``application/json`` (default) or ``application/yaml``'),
'name': 'Accept'
}]
@@ -378,9 +380,10 @@
:<jsonarr string -: Input array of pids
- :>jsonarr string type: swh object type
- :>jsonarr string sha1_git: swh object sha1_git
- :>jsonarr boolean found: whether the object was found or not
+ :>json object <swh_pid>: an object whose keys are input persistent
+ identifiers and values objects with the following keys:
+
+ * **known (bool)**: whether the object was found
"""
pass
@@ -392,40 +395,60 @@
assert rv.status_code == 200, rv.content
assert_template_used(rv, 'api/apidoc.html')
- input_html_doc = (
- ' <dl class="row">\n'
- ' <dt class="col col-md-2 text-right"> array </dt>\n'
- ' <dd class="col col-md-9">\n'
- ' <p>\n'
- ' \n'
- ' Input array of pids\n'
- ' \n'
- ' \n'
- ' </p>\n'
- ' </dd>\n'
- ' </dl>\n'
- )
-
- output_html_doc = (
- ' <dl class="row">\n'
- ' <dt class="col col-md-2 text-right"> array </dt>\n'
- ' <dd class="col col-md-9">\n'
- ' <p>\n'
- ' \n'
- ' an array of objects containing the following keys:\n'
- ' \n'
- ' \n'
- ' <div class="swh-rst"><ul class="simple">\n'
- '<li><p><strong>type (string)</strong>: swh object type</p></li>\n'
- '<li><p><strong>sha1_git (string)</strong>: swh object sha1_git</p></li>\n' # noqa
- '<li><p><strong>found (boolean)</strong>: whether the object was found or not</p></li>\n' # noqa
- '</ul>\n'
- '</div>\n'
- ' \n'
- ' </p>\n'
- ' </dd>\n'
- ' </dl>'
- )
-
- assert_contains(rv, input_html_doc)
- assert_contains(rv, output_html_doc)
+ input_html_doc = textwrap.indent((
+ '<dl class="row">\n'
+ ' <dt class="col col-md-2 text-right">\n'
+ ' array\n'
+ ' </dt>\n'
+ ' <dd class="col col-md-9">\n'
+ ' <p>\n'
+ ' Input array of pids\n'
+ ' </p>\n'
+ ' </dd>\n'
+ '</dl>\n'
+ ), ' '*7)
+
+ output_html_doc = textwrap.indent((
+ '<dl class="row">\n'
+ ' <dt class="col col-md-2 text-right">\n'
+ ' object\n'
+ ' </dt>\n'
+ ' <dd class="col col-md-9">\n'
+ ' <p>\n'
+ ' an object containing the following keys:\n'
+ ' </p>\n'
+ ' <div class="swh-rst">\n'
+ ' <blockquote>\n'
+ ' <ul>\n'
+ ' <li>\n'
+ ' <p>\n'
+ ' <strong>\n'
+ ' <swh_pid> (object)\n'
+ ' </strong>\n'
+ ' : an object whose keys are input persistent identifiers'
+ ' and values objects with the following keys:\n'
+ ' </p>\n'
+ ' <blockquote>\n'
+ ' <ul class="simple">\n'
+ ' <li>\n'
+ ' <p>\n'
+ ' <strong>\n'
+ ' known (bool)\n'
+ ' </strong>\n'
+ ' : whether the object was found\n'
+ ' </p>\n'
+ ' </li>\n'
+ ' </ul>\n'
+ ' </blockquote>\n'
+ ' </li>\n'
+ ' </ul>\n'
+ ' </blockquote>\n'
+ ' </div>\n'
+ ' </dd>\n'
+ '</dl>\n'
+ ), ' '*7)
+
+ html = prettify_html(rv.content)
+
+ assert input_html_doc in html
+ assert output_html_doc in html
diff --git a/swh/web/tests/common/test_templatetags.py b/swh/web/tests/common/test_templatetags.py
--- a/swh/web/tests/common/test_templatetags.py
+++ b/swh/web/tests/common/test_templatetags.py
@@ -4,7 +4,7 @@
# See top-level LICENSE file for more information
from swh.web.common.swh_templatetags import (
- urlize_links_and_mails, urlize_header_links, safe_docstring_display
+ urlize_links_and_mails, urlize_header_links, docstring_display
)
@@ -36,7 +36,7 @@
assert urlize_header_links(content) == expected_content
-def test_safe_docstring_display():
+def test_docstring_display():
# update api link with html links content with links
docstring = (
'This is my list header:\n\n'
@@ -49,13 +49,15 @@
expected_docstring = (
'<div class="swh-rst">'
'<p>This is my list header:</p>\n'
+ '<blockquote>\n'
'<ul class="simple">\n'
'<li><p>Here is item 1, with a continuation\n'
'line right here</p></li>\n'
'<li><p>Here is item 2</p></li>\n'
'</ul>\n'
'<p>Here is something that is not part of the list</p>\n'
+ '</blockquote>\n'
'</div>'
)
- assert safe_docstring_display(docstring) == expected_docstring
+ assert docstring_display(docstring) == expected_docstring
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Dec 21 2024, 5:37 PM (11 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3215589
Attached To
D2667: apidoc: Add bullet list support in input/output data documentation
Event Timeline
Log In to Comment