Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

html2rest: Handle double link/image substitution and raise better err…

…or messages
  • Loading branch information...
commit ef52ed0f043a64d089c7d4e976ed50aefe277a6d 1 parent 52f434c
@jedie authored
View
53 creole/html2rest/emitter.py
@@ -9,7 +9,7 @@
http://openalea.gforge.inria.fr/doc/openalea/doc/_build/html/source/sphinx/rest_syntax.html
- :copyleft: 2011 by python-creole team, see AUTHORS for more details.
+ :copyleft: 2011-2012 by python-creole team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""
@@ -25,6 +25,10 @@
DO_SUBSTITUTION = ("th", "td",) # TODO: In witch kind of node must we also substitude links?
+class Html2restException(Exception):
+ pass
+
+
class ReStructuredTextEmitter(BaseEmitter):
"""
Build from a document_tree (html2creole.parser.HtmlParser instance) a
@@ -37,6 +41,8 @@ def __init__(self, *args, **kwargs):
self.table_auto_width = False
self._substitution_data = []
+ self._used_substitution_links = {}
+ self._used_substitution_images = {}
self._list_markup = ""
def _get_block_data(self):
@@ -176,18 +182,45 @@ def _should_do_substitution(self, node):
else:
return False
+ def _get_old_substitution(self, substitution_dict, text, url):
+ if text not in substitution_dict:
+ # save for the next time
+ substitution_dict[text] = url
+ else:
+ # text has links with the same link text
+ old_url = substitution_dict[text]
+ if old_url == url:
+ # same url -> substitution can be reused
+ return old_url
+ else:
+ msg = (
+ "Duplicate explicit target name:"
+ " substitution was used more than one time, but with different URL."
+ " - link text: %r url1: %r url2: %r"
+ ) % (text, old_url, url)
+ raise Html2restException(msg)
+
def a_emit(self, node):
link_text = self.emit_children(node)
url = node.attrs["href"]
+
+ old_url = self._get_old_substitution(self._used_substitution_links, link_text, url)
+
if self._should_do_substitution(node):
# make a hyperlink reference
- self._substitution_data.append(
- ".. _%s: %s" % (link_text, url)
- )
+ if not old_url:
+ # new substitution
+ self._substitution_data.append(
+ ".. _%s: %s" % (link_text, url)
+ )
return "`%s`_" % link_text
- # create a inline hyperlink
- return "`%s <%s>`_" % (link_text, url)
+ if old_url:
+ # reuse a existing substitution
+ return "`%s`_" % link_text
+ else:
+ # create a inline hyperlink
+ return "`%s <%s>`_" % (link_text, url)
def img_emit(self, node):
src = node.attrs["src"]
@@ -205,9 +238,13 @@ def img_emit(self, node):
if substitution_text == "": # Use filename as picture text
substitution_text = posixpath.basename(src)
- self._substitution_data.append(
- ".. |%s| image:: %s" % (substitution_text, src)
+ old_src = self._get_old_substitution(
+ self._used_substitution_images, substitution_text, src
)
+ if not old_src:
+ self._substitution_data.append(
+ ".. |%s| image:: %s" % (substitution_text, src)
+ )
return "|%s|" % substitution_text
View
149 creole/tests/test_cross_compare_rest.py
@@ -4,12 +4,12 @@
"""
cross compare reStructuredText unittest
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
+
Compare all similarities between:
* rest2html (used docutils)
* html2rest
- :copyleft: 2011 by python-creole team, see AUTHORS for more details.
+ :copyleft: 2011-2012 by python-creole team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""
@@ -25,7 +25,7 @@ def test_entities(self):
self.cross_compare_rest(
rest_string="""
less-than sign: <
-
+
greater-than sign: >
""",
html_string="""
@@ -39,9 +39,9 @@ def test_bullet_lists_basic(self):
self.cross_compare_rest(
rest_string="""
* item 1
-
+
* item 2
-
+
* item 3
""",
html_string="""
@@ -58,13 +58,13 @@ def test_numbered_lists(self):
self.cross_compare_rest(
rest_string="""
#. item 1
-
+
#. item 2
-
+
#. item 2.1
-
+
#. a `link in </url/>`_ list item 2.2
-
+
#. item 3
""",
html_string="""
@@ -88,25 +88,25 @@ def test_bullet_lists_nested(self):
self.cross_compare_rest(
rest_string="""
A nested bullet lists:
-
+
* item 1
-
+
* A **bold subitem 1.1** here.
-
+
* subsubitem 1.1.1
-
+
* subsubitem 1.1.2 with inline |substitution text| image.
-
+
* subitem 1.2
-
+
* item 2
-
+
* subitem 2.1
-
+
* *bold 2.2*
-
+
.. |substitution text| image:: /url/to/image.png
-
+
Text under list.
""",
html_string="""
@@ -168,11 +168,11 @@ def test_table(self):
self.cross_compare(
rest_string="""
before table.
-
+
+------------+
| table item |
+------------+
-
+
After table.
""",
html_string="""
@@ -191,7 +191,7 @@ def test_link_in_table1(self):
+---------------+
| `table item`_ |
+---------------+
-
+
.. _table item: foo/bar
""",
html_string="""
@@ -227,7 +227,7 @@ def test_link_in_table3(self):
+-----------------------------+
| * foo `table item 2`_ bar 2 |
+-----------------------------+
-
+
.. _table item 1: foo/bar/1/
.. _table item 2: foo/bar/2/
""",
@@ -238,7 +238,7 @@ def test_link_in_table3(self):
</ul>
</td>
</tr>
- <tr><td><ul>
+ <tr><td><ul>
<li>foo <a href="foo/bar/2/">table item 2</a> bar 2</li>
</ul>
</td>
@@ -255,10 +255,10 @@ def test_paragraph_bwlow_table_links(self):
+-----------------+
| `table item 2`_ |
+-----------------+
-
+
.. _table item 1: foo/bar/1/
.. _table item 2: foo/bar/2/
-
+
Text after table.
""",
html_string="""
@@ -273,6 +273,103 @@ def test_paragraph_bwlow_table_links(self):
# debug=True
)
+ def test_reuse_link_substitution1(self):
+ self.cross_compare(
+ rest_string="""
+ +--------------------------------+
+ | this is `foo bar`_ first time. |
+ +--------------------------------+
+ | and here `foo bar`_ again. |
+ +--------------------------------+
+
+ .. _foo bar: foo/bar/
+
+ Text after table.
+ """,
+ html_string="""
+ <table>
+ <tr><td>this is <a href="foo/bar/">foo bar</a> first time.</td>
+ </tr>
+ <tr><td>and here <a href="foo/bar/">foo bar</a> again.</td>
+ </tr>
+ </table>
+ <p>Text after table.</p>
+ """,
+# debug=True
+ )
+
+ def test_reuse_link_substitution2(self):
+ self.cross_compare(
+ rest_string="""
+ +--------------------------------+
+ | this is `foo bar`_ first time. |
+ +--------------------------------+
+
+ .. _foo bar: foo/bar/
+
+ and here `foo bar`_ again, after table.
+ """,
+ html_string="""
+ <table>
+ <tr><td>this is <a href="foo/bar/">foo bar</a> first time.</td>
+ </tr>
+ </table>
+ <p>and here <a href="foo/bar/">foo bar</a> again, after table.</p>
+ """,
+# debug=True
+ )
+
+ def test_reuse_image_substitution(self):
+ self.cross_compare(
+ rest_string="""
+ +----------------------+
+ | first |image| here |
+ +----------------------+
+ | second |image| there |
+ +----------------------+
+
+ .. |image| image:: /picture.png
+ """,
+ html_string="""
+ <table>
+ <tr><td>first <img alt="image" src="/picture.png" /> here</td>
+ </tr>
+ <tr><td>second <img alt="image" src="/picture.png" /> there</td>
+ </tr>
+ </table>
+ """,
+# debug=True
+ )
+
+ def test_duplicate_image_substitution(self):
+ self.cross_compare(
+ rest_string="""
+ +----------------------+
+ | a |same| image here |
+ +----------------------+
+ | a `same`_ link there |
+ +----------------------+
+
+ .. |same| image:: /image.png
+ .. _same: /url/foo/
+
+ again: the |same| image and `same`_ link!
+ """,
+ html_string="""
+ <table>
+ <tr><td>a <img alt="same" src="/image.png" /> image here</td>
+ </tr>
+ <tr><td>a <a href="/url/foo/">same</a> link there</td>
+ </tr>
+ </table>
+ <p>again: the <img alt="same" src="/image.png" /> image and <a href="/url/foo/">same</a> link!</p>
+ """,
+# debug=True
+ )
+
+
+
+
# def test_inline_literal(self):
# """ TODO
# http://docutils.sourceforge.net/docs/user/rst/quickref.html#inline-markup
View
63 creole/tests/test_html2rest.py
@@ -9,7 +9,7 @@
Note: This only works fine if there is no problematic whitespace handling.
- :copyleft: 2011 by python-creole team, see AUTHORS for more details.
+ :copyleft: 2011-2012 by python-creole team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""
@@ -17,6 +17,7 @@
import unittest
+from creole.html2rest.emitter import Html2restException
from creole.shared.unknown_tags import preformat_unknown_nodes
from creole.tests.utils.base_unittest import BaseCreoleTest
@@ -195,8 +196,66 @@ def test_table_without_headings(self):
</table>
"""
)
+
+ def test_duplicate_substitution1(self):
+ self.assertRaises(Html2restException, self.assert_html2rest,
+ rest_string="""
+ +-----------------------------+
+ | this is `same`_ first time. |
+ +-----------------------------+
+
+ .. _same: /first/
+
+ the `same </other/>`_ link?
+ """,
+ html_string="""
+ <table>
+ <tr><td>the <a href="/first/">same</a> first time.</td>
+ </tr>
+ </table>
+ <p>the <a href="/other/">same</a> link?</p>
+ """,
+# debug=True
+ )
+
+ def test_duplicate_link_substitution(self):
+ self.assertRaises(Html2restException, self.assert_html2rest,
+# self.cross_compare(
+ rest_string="""
+ +-----------------------------+
+ | this is `same`_ first time. |
+ +-----------------------------+
+
+ .. _same: /first/
+
+ the `same </other/>`_ link?
+ """,
+ html_string="""
+ <table>
+ <tr><td>the <a href="/first/">same</a> first time.</td>
+ </tr>
+ </table>
+ <p>the <a href="/other/">same</a> link?</p>
+ """,
+# debug=True
+ )
-
+ def test_duplicate_image_substitution(self):
+ self.assertRaises(Html2restException, self.assert_html2rest,
+# self.cross_compare(
+ rest_string="""
+ a |image|...
+ and a other |image|!
+
+ .. |image| image:: /image.png
+ .. |image| image:: /other.png
+ """,
+ html_string="""
+ <p>a <img src="/image.png" title="image" alt="image" />...<br />
+ and a other <img src="/other.png" title="image" alt="image" />!</p>
+ """,
+# debug=True
+ )
Please sign in to comment.
Something went wrong with that request. Please try again.