Thanks to visit codestin.com
Credit goes to github.com

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
29 changes: 26 additions & 3 deletions pydocx/export/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,24 @@ def export(self):
# document (e.g. fields)
# In the first pass, discard any generated results
self.first_pass = True
for result in self.export_node(document):
pass
self._first_pass_export()

self._convert_complex_fields_into_simple_fields()
self._post_first_pass_processing()

# actually render the results
self.first_pass = False
for result in self.export_node(document):
yield result

def _first_pass_export(self):
document = self.main_document_part.document
if document:
for result in self.export_node(document):
pass

def _post_first_pass_processing(self):
self._convert_complex_fields_into_simple_fields()

def _convert_complex_fields_into_simple_fields(self):
if not self.complex_field_runs:
return
Expand All @@ -132,6 +140,13 @@ def _convert_complex_fields_into_simple_fields(self):
runs_to_remove_by_field = {}
runs_to_remove = set()

# All of the complex field runs need to be wrapped in simple fields,
# and then the runs need to be removed from their original container
# The new simple fields that contain the runs are inserted into the
# structure and the parent links are updated

# First create all the necessary simple fields and group the runs into
# their simple fields.
for run in self.complex_field_runs:
for child in run.children:
if field is not None and previous_run is not None:
Expand Down Expand Up @@ -166,6 +181,8 @@ def _convert_complex_fields_into_simple_fields(self):
runs_to_remove.add(run)
previous_run = run

# Next, remove all of the runs from the run's current parent, and
# inject the field in their place.
for field in fields:
runs_to_remove = runs_to_remove_by_field.get(field, set())
if not field.children:
Expand All @@ -180,6 +197,12 @@ def _convert_complex_fields_into_simple_fields(self):
previous_parent_new_children.append(child)
first_run.parent.children = previous_parent_new_children

# If we don't do this, the field's parent will be None. That will
# break the hierarchy.
field.parent = first_run.parent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this at all. Could it benefit from a code comment, perhaps?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem was field.parent was never being set, so it was None. Yet the new field was being inserted into the structure. As a consequence, it mean that the contained runs had no way to detect whether they were contained within a paragraph that was a heading, since the structure only went up as far as the field.


# Update the run parent links to point to the field, since the
# field is now the run's new parent.
for run in field.children:
run.parent = field

Expand Down
51 changes: 49 additions & 2 deletions tests/export/html/test_field_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,58 @@
)


from pydocx.openxml.packaging import MainDocumentPart
from pydocx.openxml.packaging import MainDocumentPart, StyleDefinitionsPart
from pydocx.test import DocumentGeneratorTestCase
from pydocx.test.utils import WordprocessingDocumentFactory


class HeadingTestCase(DocumentGeneratorTestCase):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a testcase named HyperlinkFieldCodeTestCase in this module, so wouldn't calling this HeadingFieldCodeTestCase be more consistent?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should rename the other class to drop the FieldCode, since the module is test_field_code?

def test_styles_are_ignored(self):
style_xml = '''
<style styleId="heading1" type="paragraph">
<name val="Heading 1"/>
<rPr>
<b val="on"/>
<caps val="on"/>
<smallCaps val="on"/>
<strike val="on"/>
<dstrike val="on"/>
</rPr>
</style>
'''

document_xml = '''
<p>
<pPr>
<pStyle val="heading1"/>
</pPr>
<r>
<fldChar fldCharType="begin"/>
</r>
<r>
<instrText> FOOBAR baz</instrText>
</r>
<r>
<fldChar fldCharType="separate"/>
</r>
<r>
<t>AAA</t>
</r>
<r>
<fldChar fldCharType="end"/>
</r>
</p>
'''
document = WordprocessingDocumentFactory()
document.add(StyleDefinitionsPart, style_xml)
document.add(MainDocumentPart, document_xml)

expected_html = '''
<h1>AAA</h1>
'''
self.assert_document_generates_html(document, expected_html)


class FieldCodeTestCase(DocumentGeneratorTestCase):
def test_unsupported_instr_content_is_not_ignored(self):
document_xml = '''
Expand Down Expand Up @@ -92,7 +139,7 @@ def test_multiple_instr_with_same_paragraph_parent(self):
self.assert_document_generates_html(document, expected_html)


class HyperlinkFieldCodeTestCase(DocumentGeneratorTestCase):
class HyperlinkTestCase(DocumentGeneratorTestCase):
def test_spanning_single_paragraph(self):
document_xml = '''
<p>
Expand Down
41 changes: 39 additions & 2 deletions tests/export/html/test_simple_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,50 @@
from unittest import TestCase


from pydocx.openxml.packaging import MainDocumentPart
from pydocx.openxml.packaging import MainDocumentPart, StyleDefinitionsPart
from pydocx.openxml.wordprocessing.simple_field import SimpleField
from pydocx.test import DocumentGeneratorTestCase
from pydocx.test.utils import WordprocessingDocumentFactory


class HyperlinkSimpleFieldTestCase(DocumentGeneratorTestCase):
class HeadingTestCase(DocumentGeneratorTestCase):
def test_styles_are_ignored(self):
style_xml = '''
<style styleId="heading1" type="paragraph">
<name val="Heading 1"/>
<rPr>
<b val="on"/>
<caps val="on"/>
<smallCaps val="on"/>
<strike val="on"/>
<dstrike val="on"/>
</rPr>
</style>
'''

document_xml = '''
<p>
<pPr>
<pStyle val="heading1"/>
</pPr>
<fldSimple instr="FOO bar">
<r>
<t>AAA</t>
</r>
</fldSimple>
</p>
'''
document = WordprocessingDocumentFactory()
document.add(StyleDefinitionsPart, style_xml)
document.add(MainDocumentPart, document_xml)

expected_html = '''
<h1>AAA</h1>
'''
self.assert_document_generates_html(document, expected_html)


class HyperlinkTestCase(DocumentGeneratorTestCase):
def test_single_run(self):
document_xml = '''
<p>
Expand Down