Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion sphinxcontrib/confluencebuilder/storage/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def __init__(self, document, builder):
self._manpage_url = getattr(config, 'manpages_url', None)
self._needs_navnode_spacing = False
self._pending_anchors = []
self._quote_context = []
self._reference_context = []
self._thead_context = []
self._v2_header_added = False
Expand Down Expand Up @@ -913,6 +914,7 @@ def visit_doctest_block(self, node):
# -----------------------------

def visit_block_quote(self, node):
has_content = True
bq_classes = node.get('classes', [])

# if column widths are explicitly given, apply specific column widths
Expand All @@ -933,6 +935,7 @@ def visit_block_quote(self, node):
self.context.append(self.end_tag(node))
elif self.v2:
self._indent_level += 1
has_content = False
else:
style = ''

Expand Down Expand Up @@ -982,12 +985,16 @@ def visit_block_quote(self, node):
**{'style': style}))
self.context.append(self.end_tag(node))

self._quote_context.append(has_content)

def depart_block_quote(self, node):
if first(findall(node, nodes.attribution)) or not self.v2:
if self._quote_context[-1]:
self.body.append(self.context.pop()) # blockquote/div
else:
self._indent_level -= 1

self._quote_context.pop()

def visit_attribution(self, node):
# see `visit_block_quote` fallback case
if not self.v2:
Expand Down
9 changes: 9 additions & 0 deletions sphinxcontrib/confluencebuilder/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ def visit_document(self, node):
def depart_document(self, node):
self.body_final = ''

# warn if there is some context that has not yet been consumed
#
# This should never happen unless there is a development bug or a user
# is injecting custom nodes that are incomplete. This is a sign that
# a translator handle has populated an interim context with data that
# should be in the body, but departure logic has not yet applied it.
if self.context:
self.warn('not all context consumed (developer note)')

# prepend header (if any)
if self.builder.config.confluence_header_file is not None:
header_template_data = ''
Expand Down
27 changes: 26 additions & 1 deletion tests/unit-tests/test_rst_epigraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from tests.lib.parse import parse
from tests.lib.testcase import ConfluenceTestCase
from tests.lib.testcase import setup_builder
from tests.lib.testcase import setup_editor


class TestConfluenceRstEpigraph(ConfluenceTestCase):
Expand All @@ -14,7 +15,7 @@ def setUpClass(cls):
cls.dataset = cls.datasets / 'rst' / 'epigraph'

@setup_builder('confluence')
def test_storage_rst_epigraph(self):
def test_storage_rst_epigraph_v1(self):
out_dir = self.build(self.dataset)

with parse('index', out_dir) as data:
Expand All @@ -41,3 +42,27 @@ def test_storage_rst_epigraph(self):

quote_source = quote_sep.next_sibling.strip()
self.assertEqual(quote_source, '— source')

@setup_builder('confluence')
@setup_editor('v2')
def test_storage_rst_epigraph_v2(self):
out_dir = self.build(self.dataset)

with parse('index', out_dir) as data:
quotes = data.find_all('blockquote')
self.assertEqual(len(quotes), 2)

quote = quotes.pop(0)

quote_text = quote.find('p')
self.assertIsNotNone(quote_text)
self.assertEqual(quote_text.text.strip(), 'quote1')

quote = quotes.pop(0)

quote_text = quote.find('p')
self.assertIsNotNone(quote_text)
self.assertEqual(quote_text.text.strip(), 'quote2')

quote_source = quote_text.next_sibling.strip()
self.assertEqual(quote_source, '— source')
27 changes: 26 additions & 1 deletion tests/unit-tests/test_rst_pull_quote.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from tests.lib.parse import parse
from tests.lib.testcase import ConfluenceTestCase
from tests.lib.testcase import setup_builder
from tests.lib.testcase import setup_editor


class TestConfluenceConfigHeaderFooter(ConfluenceTestCase):
Expand All @@ -14,7 +15,7 @@ def setUpClass(cls):
cls.dataset = cls.datasets / 'rst' / 'pull-quote'

@setup_builder('confluence')
def test_storage_rst_pull_quote(self):
def test_storage_rst_pull_quote_v1(self):
out_dir = self.build(self.dataset)

with parse('index', out_dir) as data:
Expand All @@ -41,3 +42,27 @@ def test_storage_rst_pull_quote(self):

quote_source = quote_sep.next_sibling.strip()
self.assertEqual(quote_source, '— source')

@setup_builder('confluence')
@setup_editor('v2')
def test_storage_rst_pull_quote_v2(self):
out_dir = self.build(self.dataset)

with parse('index', out_dir) as data:
quotes = data.find_all('blockquote')
self.assertEqual(len(quotes), 2)

quote = quotes.pop(0)

quote_text = quote.find('p')
self.assertIsNotNone(quote_text)
self.assertEqual(quote_text.text.strip(), 'quote1')

quote = quotes.pop(0)

quote_text = quote.find('p')
self.assertIsNotNone(quote_text)
self.assertEqual(quote_text.text.strip(), 'quote2')

quote_source = quote_text.next_sibling.strip()
self.assertEqual(quote_source, '— source')