Skip to content

Commit e159962

Browse files
Allow including text/x-rst outputs in rst conversion, transition away from text/restructuredtext (#2167)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 55ff3e9 commit e159962

File tree

7 files changed

+112
-2
lines changed

7 files changed

+112
-2
lines changed

nbconvert/exporters/rst.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from traitlets import default
77
from traitlets.config import Config
88

9+
from ..filters import DataTypeFilter
910
from .templateexporter import TemplateExporter
1011

1112

@@ -22,9 +23,24 @@ def _file_extension_default(self):
2223
def _template_name_default(self):
2324
return "rst"
2425

25-
output_mimetype = "text/restructuredtext"
26+
@default("raw_mimetypes")
27+
def _raw_mimetypes_default(self):
28+
# Up to summer 2024, nbconvert had a mistaken output_mimetype.
29+
# Listing that as an extra option here maintains compatibility for
30+
# notebooks with raw cells marked as that mimetype.
31+
return [self.output_mimetype, "text/restructuredtext", ""]
32+
33+
output_mimetype = "text/x-rst"
2634
export_from_notebook = "reST"
2735

36+
def default_filters(self):
37+
"""Override filter_data_type to use native rst outputs"""
38+
dtf = DataTypeFilter()
39+
dtf.display_data_priority = [self.output_mimetype, *dtf.display_data_priority]
40+
filters = dict(super().default_filters())
41+
filters["filter_data_type"] = dtf
42+
return filters.items()
43+
2844
@property
2945
def default_config(self):
3046
c = Config(

nbconvert/exporters/templateexporter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ def from_notebook_node( # type:ignore[explicit-override, override]
407407
"""
408408
nb_copy, resources = super().from_notebook_node(nb, resources, **kw)
409409
resources.setdefault("raw_mimetypes", self.raw_mimetypes)
410+
resources.setdefault("output_mimetype", self.output_mimetype)
410411
resources["global_content_filter"] = {
411412
"include_code": not self.exclude_code_cell,
412413
"include_markdown": not self.exclude_markdown,

share/templates/base/display_priority.j2

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
{%- elif type == 'application/vnd.jupyter.widget-view+json' -%}
3939
{%- block data_widget_view -%}
4040
{%- endblock -%}
41+
{%- elif type == resources.output_mimetype -%}
42+
{%- block data_native -%}
43+
{%- endblock -%}
4144
{%- else -%}
4245
{%- block data_other -%}
4346
{%- endblock -%}

share/templates/rst/conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"base_template": "base",
33
"mimetypes": {
4-
"text/restructuredtext": true
4+
"text/x-rst": true
55
}
66
}

share/templates/rst/index.rst.j2

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
{{ output.text | indent }}
4545
{% endblock stream %}
4646

47+
{% block data_native %}
48+
{{ output.data['text/x-rst'] }}
49+
{% endblock data_native %}
50+
4751
{% block data_svg %}
4852
.. image:: {{ output.metadata.filenames['image/svg+xml'] | urlencode }}
4953
{% endblock data_svg %}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"id": "d5202f0f-21b8-4509-a9e2-45caf1c7db7a",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"from textwrap import indent\n",
11+
"\n",
12+
"\n",
13+
"class Note:\n",
14+
" def __init__(self, text):\n",
15+
" self.text = text\n",
16+
"\n",
17+
" def _repr_html_(self):\n",
18+
" return f'<div style=\"font-weight: bold; font-size: 16pt;\">{self.text}</div>'\n",
19+
"\n",
20+
" def _repr_mimebundle_(self, include=None, exclude=None):\n",
21+
" return {\"text/x-rst\": \".. note::\\n\\n\" + indent(self.text, \" \")}"
22+
]
23+
},
24+
{
25+
"cell_type": "code",
26+
"execution_count": 2,
27+
"id": "5145b05f-3a07-4cff-8738-516a9c27cb58",
28+
"metadata": {},
29+
"outputs": [
30+
{
31+
"data": {
32+
"text/html": [
33+
"<div style=\"font-weight: bold; font-size: 16pt;\">Testing testing</div>"
34+
],
35+
"text/plain": [
36+
"<__main__.Note at 0x7f457c0250d0>"
37+
],
38+
"text/x-rst": [
39+
".. note::\n",
40+
"\n",
41+
" Testing testing"
42+
]
43+
},
44+
"execution_count": 2,
45+
"metadata": {},
46+
"output_type": "execute_result"
47+
}
48+
],
49+
"source": [
50+
"Note(\"Testing testing\")"
51+
]
52+
}
53+
],
54+
"metadata": {
55+
"kernelspec": {
56+
"display_name": "Python 3 (ipykernel)",
57+
"language": "python",
58+
"name": "python3"
59+
},
60+
"language_info": {
61+
"codemirror_mode": {
62+
"name": "ipython",
63+
"version": 3
64+
},
65+
"file_extension": ".py",
66+
"mimetype": "text/x-python",
67+
"name": "python",
68+
"nbconvert_exporter": "python",
69+
"pygments_lexer": "ipython3",
70+
"version": "3.12.4"
71+
}
72+
},
73+
"nbformat": 4,
74+
"nbformat_minor": 5
75+
}

tests/exporters/test_rst.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,14 @@ def test_png_metadata(self):
6868
assert ":width:" in attr_string
6969
assert ":height:" in attr_string
7070
assert "px" in attr_string
71+
72+
def test_rst_output(self):
73+
"""
74+
Is native text/x-rst output included when converting
75+
"""
76+
(output, resources) = RSTExporter().from_filename(
77+
self._get_notebook(nb_name="rst_output.ipynb")
78+
)
79+
assert len(output) > 0
80+
assert "\n.. note::" in output
81+
assert ".. raw:: html" not in output # rst should shadow html output

0 commit comments

Comments
 (0)