Repository: jupyter/nbconvert
Pull request #2024 (2023-07-19 09:22:53)

Show a warning if an image has no alternative text
This PR changes the default alternative text for images, when exporting to HTML, and it also adds a warning in logs.

It also adds test on the warning, and some tests for the language code (which were missing).


Patch:
diff --git a/nbconvert/exporters/html.py b/nbconvert/exporters/html.py
index 055e6991..367039d7 100644
--- a/nbconvert/exporters/html.py
+++ b/nbconvert/exporters/html.py
@@ -211,7 +211,7 @@ class HTMLExporter(TemplateExporter):
     @validate("language_code")
     def _valid_language_code(self, proposal):
         if self.language_code not in iso639_1:
-            self.log.warn(
+            self.log.warning(
                 f'"{self.language_code}" is not an ISO 639-1 language code. '
                 'It has been replaced by the default value "en".'
             )
@@ -259,8 +259,12 @@ class HTMLExporter(TemplateExporter):
         html, resources = super().from_notebook_node(nb, resources, **kw)
         soup = BeautifulSoup(html, features="html.parser")
         # Add image's alternative text
+        missing_alt = 0
         for elem in soup.select("img:not([alt])"):
-            elem.attrs["alt"] = "Image"
+            elem.attrs["alt"] = "No description has been provided for this image"
+            missing_alt += 1
+        if missing_alt:
+            self.log.warning(f"Alternative text is missing on {missing_alt} image(s).")
         # Set input and output focusable
         for elem in soup.select(".jp-Notebook div.jp-Cell-inputWrapper"):
             elem.attrs["tabindex"] = "0"


Test patch:
diff --git a/nbconvert/exporters/tests/test_html.py b/nbconvert/exporters/tests/test_html.py
index 04c2a74f..3b8be156 100644
--- a/nbconvert/exporters/tests/test_html.py
+++ b/nbconvert/exporters/tests/test_html.py
@@ -73,10 +73,17 @@ class TestHTMLExporter(ExportersTestsBase):
         """
         Does HTMLExporter with the 'classic' template treat pngs with width/height metadata correctly?
         """
-        (output, resources) = HTMLExporter(template_name="classic").from_filename(
-            self._get_notebook(nb_name="pngmetadata.ipynb")
+        exporter = HTMLExporter(template_name="classic")
+        with self.assertLogs(exporter.log, level="WARN") as log:
+            (output, resources) = exporter.from_filename(
+                self._get_notebook(nb_name="pngmetadata.ipynb")
+            )
+            assert len(log.output) == 1
+            assert "Alternative text is missing on 1 image(s)." in log.output[0]
+
+        check_for_png = re.compile(
+            r'<img alt="No description has been provided for this image"([^>]*?)>'
         )
-        check_for_png = re.compile(r'<img alt="Image"([^>]*?)>')
         result = check_for_png.search(output)
         assert result
         attr_string = result.group(1)
@@ -198,3 +205,23 @@ class TestHTMLExporter(ExportersTestsBase):
             assert "<script>alert('text/markdown output')</script>" not in output
             assert "<script>alert('text/html output')</script>" not in output
             assert "alert('application/javascript output')" not in output
+
+    def test_language_code_not_set(self):
+        (output, resources) = HTMLExporter(template_name="classic").from_filename(
+            self._get_notebook()
+        )
+        assert '<html lang="en">' in output
+
+    def test_set_language_code(self):
+        exporter = HTMLExporter(template_name="classic", language_code="fr")
+        (output, resources) = exporter.from_filename(self._get_notebook())
+        assert '<html lang="fr">' in output
+
+    def test_language_code_error(self):
+        with self.assertLogs(level="WARN") as log:
+            exporter = HTMLExporter(template_name="classic", language_code="zz")
+            assert len(log.output) == 1
+            assert '"zz" is not an ISO 639-1 language code.' in log.output[0]
+        (output, resources) = exporter.from_filename(self._get_notebook())
+
+        assert '<html lang="en">' in output