From 48e542b687d72e316fff0480b16f87cfd2dc1e31 Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Wed, 22 Feb 2017 10:31:47 +0200 Subject: [PATCH 1/6] Adjust paragraph margins/spacing inside lists --- pydocx/constants.py | 6 + pydocx/export/base.py | 3 - pydocx/export/html.py | 190 +++++++++++++----- pydocx/export/numbering_span.py | 4 +- pydocx/models.py | 8 + pydocx/openxml/wordprocessing/abstract_num.py | 3 +- pydocx/openxml/wordprocessing/doc_defaults.py | 29 +++ pydocx/openxml/wordprocessing/paragraph.py | 59 +++++- .../wordprocessing/paragraph_properties.py | 29 +++ pydocx/openxml/wordprocessing/styles.py | 4 +- pydocx/test/testcases.py | 1 + tests/export/test_docx.py | 2 + .../paragraph_indentation_inside_lists.docx | Bin 0 -> 14095 bytes .../paragraph_indentation_inside_lists.html | 29 +++ tests/fixtures/paragraph_spacing.docx | Bin 0 -> 14202 bytes tests/fixtures/paragraph_spacing.html | 33 +++ 16 files changed, 345 insertions(+), 55 deletions(-) create mode 100644 pydocx/openxml/wordprocessing/doc_defaults.py create mode 100644 tests/fixtures/paragraph_indentation_inside_lists.docx create mode 100644 tests/fixtures/paragraph_indentation_inside_lists.html create mode 100644 tests/fixtures/paragraph_spacing.docx create mode 100644 tests/fixtures/paragraph_spacing.html diff --git a/pydocx/constants.py b/pydocx/constants.py index 9f7c1788..435a20a7 100644 --- a/pydocx/constants.py +++ b/pydocx/constants.py @@ -33,6 +33,12 @@ POINTS_PER_EM = 12 +# Defined in 17.15.1.25 +DEFAULT_AUTOMATIC_TAB_STOP_INTERVAL = 720 # twips + +# Define the whitespace character +HTML_WHITE_SPACE = ' ' + PYDOCX_STYLES = { 'insert': { 'color': 'green', diff --git a/pydocx/export/base.py b/pydocx/export/base.py index 67b002bc..923d1464 100644 --- a/pydocx/export/base.py +++ b/pydocx/export/base.py @@ -310,10 +310,7 @@ def yield_paragraph_children(self, paragraph): yield child def get_paragraph_styles_to_apply(self, paragraph): - properties = paragraph.effective_properties property_rules = [ - (properties.justification, self.export_paragraph_property_justification), - (True, self.export_paragraph_property_indentation), ] for actual_value, handler in property_rules: if actual_value: diff --git a/pydocx/export/html.py b/pydocx/export/html.py index 18e3ea53..2a839fbc 100644 --- a/pydocx/export/html.py +++ b/pydocx/export/html.py @@ -17,7 +17,8 @@ POINTS_PER_EM, PYDOCX_STYLES, TWIPS_PER_POINT, - EMUS_PER_PIXEL + EMUS_PER_PIXEL, + HTML_WHITE_SPACE ) from pydocx.export.base import PyDocXExporter from pydocx.export.numbering_span import NumberingItem @@ -101,6 +102,7 @@ def __init__( allow_self_closing=False, closed=False, allow_whitespace=False, + custom_text=None, **attrs ): self.tag = tag @@ -108,6 +110,7 @@ def __init__( self.attrs = attrs self.closed = closed self.allow_whitespace = allow_whitespace + self.custom_text = custom_text def apply(self, results, allow_empty=True): if not allow_empty: @@ -116,6 +119,10 @@ def apply(self, results, allow_empty=True): return sequence = [[self]] + + if self.custom_text: + sequence.append([self.custom_text]) + if results is not None: sequence.append(results) @@ -178,6 +185,10 @@ def style(self): styles = { 'body': { 'margin': '0px auto', + }, + 'p': { + 'margin-top': '0px', + 'margin-bottom': '0px' } } @@ -248,17 +259,15 @@ def export_footnote(self, footnote): return tag.apply(results, allow_empty=False) def get_paragraph_tag(self, paragraph): + if paragraph.is_empty: + return HtmlTag('p', custom_text=HTML_WHITE_SPACE) + heading_style = paragraph.heading_style if heading_style: tag = self.get_heading_tag(paragraph) if tag: return tag - if self.in_table_cell: - return - if paragraph.has_structured_document_parent(): - return - if isinstance(paragraph.parent, NumberingItem): - return + return HtmlTag('p') def get_heading_tag(self, paragraph): @@ -277,12 +286,10 @@ def get_heading_tag(self, paragraph): def export_paragraph(self, paragraph): results = super(PyDocXHTMLExporter, self).export_paragraph(paragraph) - results = is_not_empty_and_not_only_whitespace(results) - if results is None: - return - tag = self.get_paragraph_tag(paragraph) if tag: + attrs = self.get_paragraph_styles(paragraph) + tag.attrs = attrs results = tag.apply(results) for result in results: @@ -291,9 +298,21 @@ def export_paragraph(self, paragraph): def export_paragraph_property_justification(self, paragraph, results): # TODO these classes could be applied on the paragraph, and not as # inline spans - alignment = paragraph.effective_properties.justification # TODO These alignment values are for traditional conformance. Strict # conformance uses different values + attrs = self.get_paragraph_property_justification(paragraph) + if attrs: + tag = HtmlTag('span', **attrs) + results = tag.apply(results, allow_empty=False) + return results + + def get_paragraph_property_justification(self, paragraph): + attrs = {} + if not paragraph.effective_properties: + return attrs + + alignment = paragraph.effective_properties.justification + if alignment in [JUSTIFY_LEFT, JUSTIFY_CENTER, JUSTIFY_RIGHT]: pydocx_class = 'pydocx-{alignment}'.format( alignment=alignment, @@ -301,42 +320,105 @@ def export_paragraph_property_justification(self, paragraph, results): attrs = { 'class': pydocx_class, } - tag = HtmlTag('span', **attrs) - results = tag.apply(results, allow_empty=False) elif alignment is not None: # TODO What if alignment is something else? pass - return results + + return attrs def export_paragraph_property_indentation(self, paragraph, results): # TODO these classes should be applied on the paragraph, and not as # inline styles - properties = paragraph.effective_properties + attrs = self.get_paragraph_property_indentation(paragraph) + + if attrs: + tag = HtmlTag('span', **attrs) + results = tag.apply(results, allow_empty=False) + + return results + def get_paragraph_property_spacing(self, paragraph): style = {} - # Numbering properties can define a text indentation on a paragraph - if properties.numbering_properties: - indentation_left = None - indentation_first_line = None + spacing = paragraph.get_spacing() - paragraph_num_level = paragraph.get_numbering_level() + if spacing['line']: + style['line-height'] = '%s%%' % (spacing['line'] * 100) + if spacing['after']: + style['margin-bottom'] = '{0:.2f}em'.format(convert_twips_to_ems(spacing['after'])) + if style: + style = { + 'style': convert_dictionary_to_style_fragment(style) + } + + return style + + def get_paragraph_property_indentation(self, paragraph): + style = {} + attrs = {} + properties = paragraph.effective_properties - if paragraph_num_level: - listing_style = self.export_listing_paragraph_property_indentation( - paragraph, - paragraph_num_level.paragraph_properties, - include_text_indent=True + indentation_right = None + indentation_left = 0 + indentation_first_line = None + span_paragraph_properties = None + span_indentation_left = 0 + + try: + if isinstance(paragraph.parent, NumberingItem): + span_paragraph_properties = paragraph.parent.numbering_span.numbering_level.\ + paragraph_properties + span_indentation_left = span_paragraph_properties.to_int( + 'indentation_left', + default=0 ) - if 'text-indent' in listing_style and listing_style['text-indent'] != '0.00em': - style['text-indent'] = listing_style['text-indent'] - style['display'] = 'inline-block' - else: - indentation_left = properties.to_int('indentation_left') - indentation_first_line = properties.to_int('indentation_first_line') + span_indentation_hanging = span_paragraph_properties.to_int( + 'indentation_hanging', + default=0 + ) + if span_paragraph_properties: + indentation_left -= (span_indentation_left - span_indentation_hanging) + + except AttributeError: + pass - indentation_right = properties.to_int('indentation_right') + if properties: + indentation_right = properties.to_int('indentation_right') + + if properties.numbering_properties is None: + # For paragraph inside list we need to properly adjust indentations + # by recalculating their indentations based on the parent span + indentation_left = properties.to_int('indentation_left', default=0) + indentation_first_line = properties.to_int('indentation_first_line', default=0) + + if isinstance(paragraph.parent, NumberingItem): + if properties.is_list_paragraph and properties.no_indentation: + indentation_left = 0 + elif span_paragraph_properties: + indentation_left -= span_indentation_left + # In this case we don't need to set text-indent separately because + # it's part of the left margin + indentation_left += indentation_first_line + indentation_first_line = None + else: + # TODO Here we may encounter fake lists and not always margins are + # set properly. + pass + else: + indentation_left = None + indentation_first_line = None + paragraph_num_level = paragraph.get_numbering_level() + + if paragraph_num_level: + listing_style = self.export_listing_paragraph_property_indentation( + paragraph, + paragraph_num_level.paragraph_properties, + include_text_indent=True + ) + if 'text-indent' in listing_style and \ + listing_style['text-indent'] != '0.00em': + style['text-indent'] = listing_style['text-indent'] if indentation_right: right = convert_twips_to_ems(indentation_right) @@ -349,16 +431,34 @@ def export_paragraph_property_indentation(self, paragraph, results): if indentation_first_line: first_line = convert_twips_to_ems(indentation_first_line) style['text-indent'] = '{0:.2f}em'.format(first_line) - style['display'] = 'inline-block' if style: attrs = { 'style': convert_dictionary_to_style_fragment(style) } - tag = HtmlTag('span', **attrs) - results = tag.apply(results, allow_empty=False) - return results + return attrs + + def get_paragraph_styles(self, paragraph): + attributes = {} + + property_rules = [ + (True, self.get_paragraph_property_justification), + (True, self.get_paragraph_property_indentation), + (True, self.get_paragraph_property_spacing), + ] + for actual_value, handler in property_rules: + if actual_value: + handler_results = handler(paragraph) + for attr_name in ['style', 'class']: + new_value = handler_results.get(attr_name, '') + if new_value: + if attr_name in attributes: + attributes[attr_name] += ';%s' % new_value + else: + attributes[attr_name] = '%s' % new_value + + return attributes def export_listing_paragraph_property_indentation( self, @@ -435,7 +535,7 @@ def export_listing_paragraph_property_indentation( margin_left = convert_twips_to_ems(margin_left) style['margin-left'] = '{0:.2f}em'.format(margin_left) - # we don't allow negative hanging + # We don't allow negative hanging if hanging < 0: hanging = 0 @@ -671,9 +771,10 @@ def export_table_cell(self, table_cell): tag = HtmlTag('td', **attrs) numbering_spans = self.yield_numbering_spans(table_cell.children) - results = self.yield_nested_with_line_breaks_between_paragraphs( + + results = self.yield_nested( numbering_spans, - self.export_node, + self.export_node ) if tag: results = tag.apply(results) @@ -819,19 +920,16 @@ def export_numbering_span(self, numbering_span): return tag.apply(results) def export_numbering_item(self, numbering_item): - results = self.yield_nested_with_line_breaks_between_paragraphs( - numbering_item.children, - self.export_node, - ) + results = super(PyDocXHTMLExporter, self).export_numbering_item(numbering_item) style = None if numbering_item.children: - level_properties = numbering_item.numbering_span.\ + level_properties = numbering_item.numbering_span. \ numbering_level.paragraph_properties # get the first paragraph properties which will contain information # on how to properly indent listing item - paragraph = numbering_item.children[0] + paragraph = numbering_item.get_first_child() style = self.export_listing_paragraph_property_indentation(paragraph, level_properties) diff --git a/pydocx/export/numbering_span.py b/pydocx/export/numbering_span.py index 809ff672..1986c4dd 100644 --- a/pydocx/export/numbering_span.py +++ b/pydocx/export/numbering_span.py @@ -14,9 +14,7 @@ from pydocx.openxml.wordprocessing.tab_char import TabChar from pydocx.openxml.wordprocessing.text import Text from pydocx.util.memoize import memoized - -# Defined in 17.15.1.25 -DEFAULT_AUTOMATIC_TAB_STOP_INTERVAL = 720 # twips +from pydocx.constants import DEFAULT_AUTOMATIC_TAB_STOP_INTERVAL roman_numeral_map = tuple(zip( (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1), diff --git a/pydocx/models.py b/pydocx/models.py index a8b2e2b6..3f435be5 100644 --- a/pydocx/models.py +++ b/pydocx/models.py @@ -395,3 +395,11 @@ def child_handler(child): # Create a new instance using the values we've calculated return cls(**kwargs) + + @property + def default_doc_styles(self): + part = getattr(self.container, 'style_definitions_part', None) + if part: + return part.styles.doc_defaults + + return None diff --git a/pydocx/openxml/wordprocessing/abstract_num.py b/pydocx/openxml/wordprocessing/abstract_num.py index cdad313e..01930c4c 100644 --- a/pydocx/openxml/wordprocessing/abstract_num.py +++ b/pydocx/openxml/wordprocessing/abstract_num.py @@ -5,6 +5,7 @@ unicode_literals, ) +from pydocx.constants import DEFAULT_AUTOMATIC_TAB_STOP_INTERVAL from pydocx.models import XmlModel, XmlChild, XmlAttribute, XmlCollection from pydocx.openxml.wordprocessing.level import Level @@ -41,6 +42,6 @@ def get_indentation_between_levels(self): default=0) ind_step = lvl1_ind - lvl0_ind except IndexError: - ind_step = 720 # default one + ind_step = DEFAULT_AUTOMATIC_TAB_STOP_INTERVAL # default one return ind_step diff --git a/pydocx/openxml/wordprocessing/doc_defaults.py b/pydocx/openxml/wordprocessing/doc_defaults.py new file mode 100644 index 00000000..b76d4a54 --- /dev/null +++ b/pydocx/openxml/wordprocessing/doc_defaults.py @@ -0,0 +1,29 @@ +# coding: utf-8 +from __future__ import ( + absolute_import, + print_function, + unicode_literals, +) + +from pydocx.models import XmlModel, XmlChild +from pydocx.openxml.wordprocessing.paragraph_properties import ParagraphProperties +from pydocx.openxml.wordprocessing.run_properties import RunProperties + + +class ParagraphStyleDefaults(XmlModel): + XML_TAG = 'pPrDefault' + + properties = XmlChild(type=ParagraphProperties) + + +class RunStyleDefaults(XmlModel): + XML_TAG = 'rPrDefault' + + properties = XmlChild(type=RunProperties) + + +class DocDefaults(XmlModel): + XML_TAG = 'docDefaults' + + paragraph = XmlChild(type=ParagraphStyleDefaults) + run = XmlChild(type=RunStyleDefaults) diff --git a/pydocx/openxml/wordprocessing/paragraph.py b/pydocx/openxml/wordprocessing/paragraph.py index bdb6b387..5ceed8e6 100644 --- a/pydocx/openxml/wordprocessing/paragraph.py +++ b/pydocx/openxml/wordprocessing/paragraph.py @@ -4,7 +4,7 @@ print_function, unicode_literals, ) -from pydocx.util.memoize import memoized + from pydocx.models import XmlModel, XmlCollection, XmlChild from pydocx.openxml.wordprocessing.hyperlink import Hyperlink from pydocx.openxml.wordprocessing.paragraph_properties import ParagraphProperties # noqa @@ -17,6 +17,7 @@ from pydocx.openxml.wordprocessing.sdt_run import SdtRun from pydocx.openxml.wordprocessing.simple_field import SimpleField from pydocx.openxml.wordprocessing.bookmark import Bookmark +from pydocx.util.memoize import memoized class Paragraph(XmlModel): @@ -39,6 +40,20 @@ def __init__(self, **kwargs): super(Paragraph, self).__init__(**kwargs) self._effective_properties = None + @property + def is_empty(self): + if not self.children: + return True + + # we may have cases when a paragraph has a Bookmark with name '_GoBack' + # and we should treat it as empty paragraph + if len(self.children) == 1 and \ + isinstance(self.children[0], Bookmark) and \ + self.children[0].name in ('_GoBack',): + return True + + return False + @property def effective_properties(self): # TODO need to calculate effective properties like Run @@ -206,3 +221,45 @@ def get_indentation(self, indentation, only_level_ind=False): ind = level.paragraph_properties.to_int(indentation, default=0) return ind + + def get_spacing(self): + """Get paragraph spacing according to: + ECMA-376, 3rd Edition (June, 2011), + Fundamentals and Markup Language Reference § 17.3.1.33. + + Note: Partial implementation for now. + """ + results = { + 'line': None, + 'after': None + } + + default_properties_spacing = self.default_doc_styles.paragraph.properties + no_spacing_properties = not self.properties or self.properties.no_spacing + + if not default_properties_spacing and no_spacing_properties: + return results + + if no_spacing_properties: + properties = default_properties_spacing + else: + properties = self.properties + + spacing_line = properties.to_int('spacing_line') + spacing_after = properties.to_int('spacing_after') + + if default_properties_spacing and spacing_line is None \ + and bool(properties.spacing_after_auto_spacing): + # get the spacing_line from the default definition + spacing_line = default_properties_spacing.to_int('spacing_line') + + if spacing_line: + line = spacing_line / 240.0 + # default line spacing is 1 so no need to add attribute + if line != 1.0: + results['line'] = line + + if spacing_after is not None: + results['after'] = spacing_after + + return results diff --git a/pydocx/openxml/wordprocessing/paragraph_properties.py b/pydocx/openxml/wordprocessing/paragraph_properties.py index c6bbc374..ae79513e 100644 --- a/pydocx/openxml/wordprocessing/paragraph_properties.py +++ b/pydocx/openxml/wordprocessing/paragraph_properties.py @@ -7,6 +7,7 @@ from pydocx.models import XmlModel, XmlChild from pydocx.openxml.wordprocessing.numbering_properties import NumberingProperties # noqa +from pydocx.types import OnOff class ParagraphProperties(XmlModel): @@ -25,6 +26,12 @@ class ParagraphProperties(XmlModel): indentation_first_line = XmlChild(name='ind', attrname='firstLine') indentation_hanging = XmlChild(name='ind', attrname='hanging') + # paragraph spacing + spacing_after = XmlChild(name='spacing', attrname='after') + spacing_line = XmlChild(name='spacing', attrname='line') + spacing_line_rule = XmlChild(name='spacing', attrname='lineRule') + spacing_after_auto_spacing = XmlChild(type=OnOff, name='spacing', attrname='afterAutospacing') + @property def start_margin_position(self): # Regarding indentation, @@ -51,3 +58,25 @@ def to_int(self, attribute, default=None): return int(getattr(self, attribute, default)) except (ValueError, TypeError): return default + + @property + def is_list_paragraph(self): + return self.parent_style == 'ListParagraph' + + @property + def no_indentation(self): + return not any(( + self.indentation_left, + self.indentation_hanging, + self.indentation_right, + self.indentation_first_line, + )) + + @property + def no_spacing(self): + return not any(( + self.spacing_line, + self.spacing_after, + self.spacing_after_auto_spacing, + self.spacing_line_rule, + )) diff --git a/pydocx/openxml/wordprocessing/styles.py b/pydocx/openxml/wordprocessing/styles.py index 46bf6287..8d1a1d16 100644 --- a/pydocx/openxml/wordprocessing/styles.py +++ b/pydocx/openxml/wordprocessing/styles.py @@ -7,14 +7,16 @@ from collections import defaultdict -from pydocx.models import XmlCollection, XmlModel +from pydocx.models import XmlCollection, XmlModel, XmlChild from pydocx.openxml.wordprocessing.style import Style +from pydocx.openxml.wordprocessing.doc_defaults import DocDefaults class Styles(XmlModel): XML_TAG = 'styles' styles = XmlCollection(Style) + doc_defaults = XmlChild(type=DocDefaults) def __init__(self, styles=None, *args, **kwargs): super(Styles, self).__init__(styles=styles, *args, **kwargs) diff --git a/pydocx/test/testcases.py b/pydocx/test/testcases.py index 50e144c1..9298400d 100644 --- a/pydocx/test/testcases.py +++ b/pydocx/test/testcases.py @@ -50,6 +50,7 @@ '.pydocx-tab {display:inline-block;width:4em}' '.pydocx-underline {text-decoration:underline}' 'body {margin:0px auto;width:51.00em}' + 'p {margin-bottom:0px;margin-top:0px}' '' ) diff --git a/tests/export/test_docx.py b/tests/export/test_docx.py index 16fa43d1..b74fbfce 100644 --- a/tests/export/test_docx.py +++ b/tests/export/test_docx.py @@ -33,6 +33,8 @@ class ConvertDocxToHtmlTestCase(DocXFixtureTestCaseFactory): 'inline_tags', 'justification', 'paragraph_with_margins', + 'paragraph_indentation_inside_lists', + 'paragraph_spacing', 'list_in_table', 'lists_with_margins', 'lists_with_styles', diff --git a/tests/fixtures/paragraph_indentation_inside_lists.docx b/tests/fixtures/paragraph_indentation_inside_lists.docx new file mode 100644 index 0000000000000000000000000000000000000000..ac5ea19fb0ddfdc3fed7122da3ebeee1db2a298f GIT binary patch literal 14095 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/paragraph_indentation_inside_lists.html b/tests/fixtures/paragraph_indentation_inside_lists.html new file mode 100644 index 00000000..47876675 --- /dev/null +++ b/tests/fixtures/paragraph_indentation_inside_lists.html @@ -0,0 +1,29 @@ +

Heading 1

+

Heading 2

+

 

+
    +
  1. +

    AAA

    +
      +
    1. +

      BBB

      +

      Heading 3

      +
    2. +
    3. +

      CCC

      +

       

      +

      Heading 4

      +

       

      +
    4. +
    5. +

      DDD

      +

      Heading 5

      +
    6. +
    +
  2. +
  3. +

    EEE

    +
  4. +
+

 

+

Heading 6

diff --git a/tests/fixtures/paragraph_spacing.docx b/tests/fixtures/paragraph_spacing.docx new file mode 100644 index 0000000000000000000000000000000000000000..9d32f36d0d52afc7b03e1fd121777bb598300e3a GIT binary patch literal 14202 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 R06+wNz(5je%=z25{|9SEiJ|}i literal 0 HcmV?d00001 diff --git a/tests/fixtures/paragraph_spacing.html b/tests/fixtures/paragraph_spacing.html new file mode 100644 index 00000000..31a09b03 --- /dev/null +++ b/tests/fixtures/paragraph_spacing.html @@ -0,0 +1,33 @@ +

Heading 1

+

Heading 2

+

 

+
    +
  1. +

    AAA

    +
      +
    1. +

      BBB

      +

      Heading 3

      +
    2. +
    3. +

      CCC

      +

      +  

      +

      Heading + 4

      +

      +  

      +
    4. +
    5. +

      DDD

      +

      Heading + 5

      +
    6. +
    +
  2. +
  3. +

    EEE

    +
  4. +
+

 

+

Heading 6

From 8b907c3fdc52a5babf0f6053eaf0c76760b3e025 Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Thu, 9 Mar 2017 13:41:45 +0200 Subject: [PATCH 2/6] Handle contextual spacing for paragraphs --- pydocx/export/base.py | 6 ++ pydocx/export/html.py | 85 ++++++++++++++++-- pydocx/openxml/wordprocessing/paragraph.py | 77 ++++++++++++---- .../wordprocessing/paragraph_properties.py | 18 +--- .../wordprocessing/paragraph_spacing.py | 27 ++++++ pydocx/openxml/wordprocessing/style.py | 2 + pydocx/openxml/wordprocessing/table.py | 30 ++++++- pydocx/openxml/wordprocessing/table_cell.py | 11 ++- .../wordprocessing/table_cell_properties.py | 10 ++- .../wordprocessing/table_properties.py | 14 +++ pydocx/test/testcases.py | 2 +- pydocx/types.py | 6 ++ tests/fixtures/paragraph_spacing.docx | Bin 14202 -> 16789 bytes tests/fixtures/paragraph_spacing.html | 71 +++++++++------ 14 files changed, 283 insertions(+), 76 deletions(-) create mode 100644 pydocx/openxml/wordprocessing/paragraph_spacing.py create mode 100644 pydocx/openxml/wordprocessing/table_properties.py diff --git a/pydocx/export/base.py b/pydocx/export/base.py index 923d1464..a1985af6 100644 --- a/pydocx/export/base.py +++ b/pydocx/export/base.py @@ -31,6 +31,7 @@ def __init__(self, path): self.footnote_tracker = [] self.captured_runs = None + self.paragraphs = [] self.complex_field_runs = [] self.node_type_to_export_func_map = { @@ -299,6 +300,11 @@ def yield_body_children(self, body): return self.yield_numbering_spans(body.children) def export_paragraph(self, paragraph): + if self.first_pass: + # To properly handle contextual spacing we need to know what is the style + # of the previous and next paragraphs. So, we save all the paragraphs here. + self.paragraphs.append(paragraph) + children = self.yield_paragraph_children(paragraph) results = self.yield_nested(children, self.export_node) if paragraph.effective_properties: diff --git a/pydocx/export/html.py b/pydocx/export/html.py index 2a839fbc..321d3c6a 100644 --- a/pydocx/export/html.py +++ b/pydocx/export/html.py @@ -5,7 +5,6 @@ print_function, unicode_literals, ) - import base64 import posixpath from itertools import chain @@ -187,8 +186,8 @@ def style(self): 'margin': '0px auto', }, 'p': { - 'margin-top': '0px', - 'margin-bottom': '0px' + 'margin-top': '0', + 'margin-bottom': '0' } } @@ -259,7 +258,10 @@ def export_footnote(self, footnote): return tag.apply(results, allow_empty=False) def get_paragraph_tag(self, paragraph): - if paragraph.is_empty: + if self.in_table_cell and paragraph.parent.properties.is_continue_vertical_merge: + # We ignore such paragraphs here because are added via rowspan + return + elif paragraph.is_empty: return HtmlTag('p', custom_text=HTML_WHITE_SPACE) heading_style = paragraph.heading_style @@ -340,13 +342,78 @@ def export_paragraph_property_indentation(self, paragraph, results): def get_paragraph_property_spacing(self, paragraph): style = {} + if self.first_pass: + return style + + previous_paragraph = None + next_paragraph = None + previous_paragraph_spacing = None + next_paragraph_spacing = None + spacing_after = None + spacing_before = None + + current_paragraph_spacing = paragraph.get_spacing() + current_par_index = self.paragraphs.index(paragraph) + + if current_par_index > 0: + previous_paragraph = self.paragraphs[current_par_index - 1] + previous_paragraph_spacing = previous_paragraph.get_spacing() + if current_par_index < len(self.paragraphs) - 1: + next_paragraph = self.paragraphs[current_par_index + 1] + next_paragraph_spacing = next_paragraph.get_spacing() + + if next_paragraph: + current_after = current_paragraph_spacing['after'] or 0 + next_before = next_paragraph_spacing['before'] or 0 + + same_style = current_paragraph_spacing['parent_style'] == \ + next_paragraph_spacing['parent_style'] + + if same_style: + if not current_paragraph_spacing['contextual_spacing']: + if next_paragraph_spacing['contextual_spacing']: + spacing_after = current_after + else: + if current_after > next_before: + spacing_after = current_after + else: + if current_after > next_before: + spacing_after = current_after + else: + spacing_after = current_paragraph_spacing['after'] + + if previous_paragraph: + current_before = current_paragraph_spacing['before'] or 0 + prev_after = previous_paragraph_spacing['after'] or 0 + + same_style = current_paragraph_spacing['parent_style'] == \ + previous_paragraph_spacing['parent_style'] + + if same_style: + if not current_paragraph_spacing['contextual_spacing']: + if previous_paragraph_spacing['contextual_spacing']: + if current_before > prev_after: + spacing_before = current_before - prev_after + else: + spacing_before = 0 + else: + if current_before > prev_after: + spacing_before = current_before + else: + if current_before > prev_after: + spacing_before = current_before + else: + spacing_before = current_paragraph_spacing['before'] + + if current_paragraph_spacing['line']: + style['line-height'] = '{0}%'.format(current_paragraph_spacing['line'] * 100) + + if spacing_after: + style['margin-bottom'] = '{0:.2f}em'.format(convert_twips_to_ems(spacing_after)) - spacing = paragraph.get_spacing() + if spacing_before: + style['margin-top'] = '{0:.2f}em'.format(convert_twips_to_ems(spacing_before)) - if spacing['line']: - style['line-height'] = '%s%%' % (spacing['line'] * 100) - if spacing['after']: - style['margin-bottom'] = '{0:.2f}em'.format(convert_twips_to_ems(spacing['after'])) if style: style = { 'style': convert_dictionary_to_style_fragment(style) diff --git a/pydocx/openxml/wordprocessing/paragraph.py b/pydocx/openxml/wordprocessing/paragraph.py index 5ceed8e6..2a020ba5 100644 --- a/pydocx/openxml/wordprocessing/paragraph.py +++ b/pydocx/openxml/wordprocessing/paragraph.py @@ -6,17 +6,18 @@ ) from pydocx.models import XmlModel, XmlCollection, XmlChild +from pydocx.openxml.wordprocessing.bookmark import Bookmark +from pydocx.openxml.wordprocessing.deleted_run import DeletedRun from pydocx.openxml.wordprocessing.hyperlink import Hyperlink +from pydocx.openxml.wordprocessing.inserted_run import InsertedRun from pydocx.openxml.wordprocessing.paragraph_properties import ParagraphProperties # noqa from pydocx.openxml.wordprocessing.run import Run -from pydocx.openxml.wordprocessing.tab_char import TabChar -from pydocx.openxml.wordprocessing.text import Text -from pydocx.openxml.wordprocessing.smart_tag_run import SmartTagRun -from pydocx.openxml.wordprocessing.inserted_run import InsertedRun -from pydocx.openxml.wordprocessing.deleted_run import DeletedRun from pydocx.openxml.wordprocessing.sdt_run import SdtRun from pydocx.openxml.wordprocessing.simple_field import SimpleField -from pydocx.openxml.wordprocessing.bookmark import Bookmark +from pydocx.openxml.wordprocessing.smart_tag_run import SmartTagRun +from pydocx.openxml.wordprocessing.tab_char import TabChar +from pydocx.openxml.wordprocessing.text import Text +from pydocx.openxml.wordprocessing.table_cell import TableCell from pydocx.util.memoize import memoized @@ -231,27 +232,62 @@ def get_spacing(self): """ results = { 'line': None, - 'after': None + 'after': None, + 'before': None, + 'contextual_spacing': False, + 'parent_style': None } - default_properties_spacing = self.default_doc_styles.paragraph.properties - no_spacing_properties = not self.properties or self.properties.no_spacing + # Get the paragraph_properties from the parent styles + style_paragraph_properties = None + for style in self.get_style_chain_stack(): + if style.paragraph_properties: + style_paragraph_properties = style.paragraph_properties + break + + if style_paragraph_properties: + results['contextual_spacing'] = bool(style_paragraph_properties.contextual_spacing) + + default_paragraph_properties = None + if self.default_doc_styles and self.default_doc_styles.paragraph: + default_paragraph_properties = self.default_doc_styles.paragraph.properties - if not default_properties_spacing and no_spacing_properties: + # Spacing properties can be defined in multiple places and we need to get some + # kind of order of check + properties_order = [None, None, None] + if self.properties: + properties_order[0] = self.properties + if isinstance(self.parent, TableCell): + properties_order[1] = self.parent.parent_table.get_paragraph_properties() + if not self.properties or not self.properties.spacing_properties: + properties_order[2] = default_paragraph_properties + + spacing_properties = None + contextual_spacing = None + + for properties in properties_order: + if spacing_properties is None: + spacing_properties = getattr(properties, 'spacing_properties', None) + if contextual_spacing is None: + contextual_spacing = getattr(properties, 'contextual_spacing', None) + + if not spacing_properties: return results - if no_spacing_properties: - properties = default_properties_spacing - else: - properties = self.properties + if contextual_spacing is not None: + results['contextual_spacing'] = bool(contextual_spacing) - spacing_line = properties.to_int('spacing_line') - spacing_after = properties.to_int('spacing_after') + if self.properties: + results['parent_style'] = self.properties.parent_style - if default_properties_spacing and spacing_line is None \ - and bool(properties.spacing_after_auto_spacing): + spacing_line = spacing_properties.to_int('line') + spacing_after = spacing_properties.to_int('after') + spacing_before = spacing_properties.to_int('before') + + if default_paragraph_properties and spacing_line is None \ + and bool(spacing_properties.after_auto_spacing): # get the spacing_line from the default definition - spacing_line = default_properties_spacing.to_int('spacing_line') + spacing_line = default_paragraph_properties.spacing_properties.to_int('line') if spacing_line: line = spacing_line / 240.0 @@ -262,4 +298,7 @@ def get_spacing(self): if spacing_after is not None: results['after'] = spacing_after + if spacing_before is not None: + results['before'] = spacing_before + return results diff --git a/pydocx/openxml/wordprocessing/paragraph_properties.py b/pydocx/openxml/wordprocessing/paragraph_properties.py index ae79513e..ce7ce1ac 100644 --- a/pydocx/openxml/wordprocessing/paragraph_properties.py +++ b/pydocx/openxml/wordprocessing/paragraph_properties.py @@ -7,6 +7,7 @@ from pydocx.models import XmlModel, XmlChild from pydocx.openxml.wordprocessing.numbering_properties import NumberingProperties # noqa +from pydocx.openxml.wordprocessing.paragraph_spacing import ParagraphSpacing from pydocx.types import OnOff @@ -26,11 +27,9 @@ class ParagraphProperties(XmlModel): indentation_first_line = XmlChild(name='ind', attrname='firstLine') indentation_hanging = XmlChild(name='ind', attrname='hanging') + contextual_spacing = XmlChild(type=OnOff, name='contextualSpacing', attrname='val') # paragraph spacing - spacing_after = XmlChild(name='spacing', attrname='after') - spacing_line = XmlChild(name='spacing', attrname='line') - spacing_line_rule = XmlChild(name='spacing', attrname='lineRule') - spacing_after_auto_spacing = XmlChild(type=OnOff, name='spacing', attrname='afterAutospacing') + spacing_properties = XmlChild(type=ParagraphSpacing) @property def start_margin_position(self): @@ -70,13 +69,4 @@ def no_indentation(self): self.indentation_hanging, self.indentation_right, self.indentation_first_line, - )) - - @property - def no_spacing(self): - return not any(( - self.spacing_line, - self.spacing_after, - self.spacing_after_auto_spacing, - self.spacing_line_rule, - )) + )) \ No newline at end of file diff --git a/pydocx/openxml/wordprocessing/paragraph_spacing.py b/pydocx/openxml/wordprocessing/paragraph_spacing.py new file mode 100644 index 00000000..6912bdd3 --- /dev/null +++ b/pydocx/openxml/wordprocessing/paragraph_spacing.py @@ -0,0 +1,27 @@ +# coding: utf-8 +from __future__ import ( + absolute_import, + print_function, + unicode_literals, +) + +from pydocx.models import XmlModel, XmlAttribute +from pydocx.types import OnOff + + +class ParagraphSpacing(XmlModel): + XML_TAG = 'spacing' + + after = XmlAttribute(name='after') + before = XmlAttribute(name='before') + line = XmlAttribute(name='line') + line_rule = XmlAttribute(name='lineRule') + after_auto_spacing = XmlAttribute(type=OnOff, name='afterAutospacing') + + def to_int(self, attribute, default=None): + # TODO would be nice if this integer conversion was handled + # implicitly by the model somehow + try: + return int(getattr(self, attribute, default)) + except (ValueError, TypeError): + return default diff --git a/pydocx/openxml/wordprocessing/style.py b/pydocx/openxml/wordprocessing/style.py index 2092d30c..faf73749 100644 --- a/pydocx/openxml/wordprocessing/style.py +++ b/pydocx/openxml/wordprocessing/style.py @@ -7,6 +7,7 @@ from pydocx.models import XmlModel, XmlChild, XmlAttribute from pydocx.openxml.wordprocessing.run_properties import RunProperties +from pydocx.openxml.wordprocessing.paragraph_properties import ParagraphProperties class Style(XmlModel): @@ -16,6 +17,7 @@ class Style(XmlModel): style_id = XmlAttribute(name='styleId', default='') name = XmlChild(attrname='val', default='') run_properties = XmlChild(type=RunProperties) + paragraph_properties = XmlChild(type=ParagraphProperties) parent_style = XmlChild(name='basedOn', attrname='val') def is_a_heading(self): diff --git a/pydocx/openxml/wordprocessing/table.py b/pydocx/openxml/wordprocessing/table.py index 61314b29..87d105f3 100644 --- a/pydocx/openxml/wordprocessing/table.py +++ b/pydocx/openxml/wordprocessing/table.py @@ -7,13 +7,16 @@ from collections import defaultdict -from pydocx.models import XmlModel, XmlCollection +from pydocx.models import XmlModel, XmlCollection, XmlChild from pydocx.openxml.wordprocessing.table_row import TableRow +from pydocx.openxml.wordprocessing.table_properties import TableProperties class Table(XmlModel): XML_TAG = 'tbl' + properties = XmlChild(type=TableProperties) + rows = XmlCollection( TableRow, ) @@ -45,3 +48,28 @@ def calculate_table_cell_spans(self): if active_rowspan_for_column: cell_to_rowspan_count[active_rowspan_for_column] += 1 # noqa return dict(cell_to_rowspan_count) + + def get_style_chain_stack(self): + if not self.properties: + return + + parent_style = self.properties.parent_style + if not parent_style: + return + + part = getattr(self.container, 'style_definitions_part', None) + if part: + style_stack = part.get_style_chain_stack('table', parent_style) + for result in style_stack: + yield result + + def get_paragraph_properties(self): + """Get default style paragraph properties for table""" + + paragraph_properties = None + for style in self.get_style_chain_stack(): + if style.paragraph_properties: + paragraph_properties = style.paragraph_properties + break + + return paragraph_properties diff --git a/pydocx/openxml/wordprocessing/table_cell.py b/pydocx/openxml/wordprocessing/table_cell.py index 8a538e86..309a8c2c 100644 --- a/pydocx/openxml/wordprocessing/table_cell.py +++ b/pydocx/openxml/wordprocessing/table_cell.py @@ -6,7 +6,6 @@ ) from pydocx.models import XmlModel, XmlCollection, XmlChild -from pydocx.openxml.wordprocessing.paragraph import Paragraph from pydocx.openxml.wordprocessing.table_cell_properties import TableCellProperties # noqa @@ -16,6 +15,14 @@ class TableCell(XmlModel): properties = XmlChild(type=TableCellProperties) children = XmlCollection( - Paragraph, + 'wordprocessing.Paragraph', 'wordprocessing.Table', ) + + @property + def parent_table(self): + return self.parent.parent + + @property + def table_properties(self): + return self.parent_table.properties diff --git a/pydocx/openxml/wordprocessing/table_cell_properties.py b/pydocx/openxml/wordprocessing/table_cell_properties.py index 2a94c9b0..7ae94c31 100644 --- a/pydocx/openxml/wordprocessing/table_cell_properties.py +++ b/pydocx/openxml/wordprocessing/table_cell_properties.py @@ -21,7 +21,11 @@ def should_close_previous_vertical_merge(self): # of preceding cells shall be closed. if self.vertical_merge is None: return True + return not self.is_continue_vertical_merge + + @property + def is_continue_vertical_merge(self): + if self.vertical_merge is None: + return False merge = self.vertical_merge.get('val', 'continue') - if merge != 'continue': - return True - return False + return merge == 'continue' diff --git a/pydocx/openxml/wordprocessing/table_properties.py b/pydocx/openxml/wordprocessing/table_properties.py new file mode 100644 index 00000000..76b005d2 --- /dev/null +++ b/pydocx/openxml/wordprocessing/table_properties.py @@ -0,0 +1,14 @@ +# coding: utf-8 +from __future__ import ( + absolute_import, + print_function, + unicode_literals, +) + +from pydocx.models import XmlModel, XmlChild + + +class TableProperties(XmlModel): + XML_TAG = 'tblPr' + + parent_style = XmlChild(name='tblStyle', attrname='val') diff --git a/pydocx/test/testcases.py b/pydocx/test/testcases.py index 9298400d..f2c5158f 100644 --- a/pydocx/test/testcases.py +++ b/pydocx/test/testcases.py @@ -50,7 +50,7 @@ '.pydocx-tab {display:inline-block;width:4em}' '.pydocx-underline {text-decoration:underline}' 'body {margin:0px auto;width:51.00em}' - 'p {margin-bottom:0px;margin-top:0px}' + 'p {margin-bottom:0;margin-top:0}' '' ) diff --git a/pydocx/types.py b/pydocx/types.py index 722024ab..327008c0 100644 --- a/pydocx/types.py +++ b/pydocx/types.py @@ -12,6 +12,12 @@ def __init__(self, value): def __bool__(self): return self.__nonzero__() + def __repr__(self): + return '{klass}({kwargs})'.format( + klass=self.__class__.__name__, + kwargs=bool(self) + ) + class OnOff(SimpleType): ''' diff --git a/tests/fixtures/paragraph_spacing.docx b/tests/fixtures/paragraph_spacing.docx index 9d32f36d0d52afc7b03e1fd121777bb598300e3a..69ed0e3c1b1b50f0215a563110c332718b6246c6 100644 GIT binary patch delta 12181 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 1

-

Heading 2

-

 

+

AAA

+

BBB

+

CCC

+

 

+

DDD

  1. -

    AAA

    -
      -
    1. -

      BBB

      -

      Heading 3

      -
    2. -
    3. -

      CCC

      -

      -  

      -

      Heading - 4

      -

      -  

      -
    4. -
    5. -

      DDD

      -

      Heading - 5

      -
    6. -
    +

    EEE

  2. -

    EEE

    +

    FFF

    +
  3. +
  4. +

    GGG

    +
  5. +
  6. +

    HHH

    +
  7. +
  8. +

    III

    +
  9. +
  10. +

    JJJ

-

 

-

Heading 6

+

 

+ + + + + + + + + + +
+

KKK

+
+

 

+

LLL

+

 

+
+

MMM

+
+

NNN

+
+

OOO

+
+

 

\ No newline at end of file From 525d1a47f637635e56972b9ed0937eea5d1c41ad Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Fri, 10 Mar 2017 15:38:05 +0200 Subject: [PATCH 3/6] Fixed unittests by wrapping all texts in

--- pydocx/export/base.py | 1 - pydocx/export/html.py | 18 +- pydocx/openxml/wordprocessing/paragraph.py | 14 +- tests/export/html/test_field_code.py | 1 + tests/export/html/test_heading.py | 26 +- tests/export/html/test_hyperlink.py | 2 +- .../export/html/test_markup_compatibility.py | 8 +- tests/export/html/test_numbering.py | 350 +++++++++++------- tests/export/html/test_paragraph.py | 28 +- tests/export/html/test_tables.py | 80 ++-- tests/export/html/test_textbox.py | 18 +- tests/export/test_xml.py | 230 ++++++------ tests/fixtures/export_from_googledocs.docx | Bin 4300 -> 11642 bytes tests/fixtures/external_image.docx | Bin 4938 -> 12503 bytes tests/fixtures/fake_subscript.html | 6 +- tests/fixtures/fake_superscript.html | 5 +- tests/fixtures/has_title.html | 3 +- tests/fixtures/justification.html | 30 +- tests/fixtures/list_in_table.docx | Bin 4379 -> 12988 bytes tests/fixtures/list_in_table.html | 7 +- tests/fixtures/lists_with_margins.docx | Bin 13237 -> 13227 bytes tests/fixtures/lists_with_margins.html | 19 +- tests/fixtures/lists_with_styles.html | 19 +- tests/fixtures/nested_lists.html | 39 +- .../nested_lists_different_num_ids.html | 32 +- tests/fixtures/nested_table_rowspan.html | 12 +- tests/fixtures/nested_tables.docx | Bin 3711 -> 12321 bytes tests/fixtures/nested_tables.html | 16 +- tests/fixtures/paragraph_with_margins.html | 17 +- .../read_same_image_multiple_times.docx | Bin 12768 -> 15693 bytes .../read_same_image_multiple_times.html | 9 +- tests/fixtures/shift_enter.html | 28 +- tests/fixtures/simple.html | 30 +- tests/fixtures/simple_lists.html | 8 +- tests/fixtures/simple_table.html | 14 +- tests/fixtures/styled_color.docx | Bin 14048 -> 12498 bytes tests/fixtures/styled_color.html | 19 +- tests/fixtures/table_col_row_span.html | 96 ++--- tests/fixtures/table_with_multi_rowspan.html | 24 +- tests/fixtures/tables_in_lists.html | 28 +- tests/fixtures/track_changes_on.html | 2 + 41 files changed, 764 insertions(+), 475 deletions(-) diff --git a/pydocx/export/base.py b/pydocx/export/base.py index a1985af6..ae1b3330 100644 --- a/pydocx/export/base.py +++ b/pydocx/export/base.py @@ -341,7 +341,6 @@ def export_run(self, run): if self.first_pass: if self.captured_runs is not None: self.captured_runs.append(run) - # TODO squash multiple sequential text nodes into one? results = self.yield_nested(run.children, self.export_node) if run.effective_properties: diff --git a/pydocx/export/html.py b/pydocx/export/html.py index 321d3c6a..e92c5fd9 100644 --- a/pydocx/export/html.py +++ b/pydocx/export/html.py @@ -258,10 +258,12 @@ def export_footnote(self, footnote): return tag.apply(results, allow_empty=False) def get_paragraph_tag(self, paragraph): - if self.in_table_cell and paragraph.parent.properties.is_continue_vertical_merge: - # We ignore such paragraphs here because are added via rowspan - return - elif paragraph.is_empty: + if isinstance(paragraph.parent, wordprocessing.TableCell): + cell_properties = paragraph.parent.properties + if cell_properties and cell_properties.is_continue_vertical_merge: + # We ignore such paragraphs here because are added via rowspan + return + if paragraph.is_empty: return HtmlTag('p', custom_text=HTML_WHITE_SPACE) heading_style = paragraph.heading_style @@ -291,7 +293,7 @@ def export_paragraph(self, paragraph): tag = self.get_paragraph_tag(paragraph) if tag: attrs = self.get_paragraph_styles(paragraph) - tag.attrs = attrs + tag.attrs.update(attrs) results = tag.apply(results) for result in results: @@ -345,6 +347,11 @@ def get_paragraph_property_spacing(self, paragraph): if self.first_pass: return style + try: + current_par_index = self.paragraphs.index(paragraph) + except ValueError: + return style + previous_paragraph = None next_paragraph = None previous_paragraph_spacing = None @@ -353,7 +360,6 @@ def get_paragraph_property_spacing(self, paragraph): spacing_before = None current_paragraph_spacing = paragraph.get_spacing() - current_par_index = self.paragraphs.index(paragraph) if current_par_index > 0: previous_paragraph = self.paragraphs[current_par_index - 1] diff --git a/pydocx/openxml/wordprocessing/paragraph.py b/pydocx/openxml/wordprocessing/paragraph.py index 2a020ba5..4a6ac95c 100644 --- a/pydocx/openxml/wordprocessing/paragraph.py +++ b/pydocx/openxml/wordprocessing/paragraph.py @@ -7,6 +7,7 @@ from pydocx.models import XmlModel, XmlCollection, XmlChild from pydocx.openxml.wordprocessing.bookmark import Bookmark +from pydocx.openxml.wordprocessing.br import Break from pydocx.openxml.wordprocessing.deleted_run import DeletedRun from pydocx.openxml.wordprocessing.hyperlink import Hyperlink from pydocx.openxml.wordprocessing.inserted_run import InsertedRun @@ -48,11 +49,14 @@ def is_empty(self): # we may have cases when a paragraph has a Bookmark with name '_GoBack' # and we should treat it as empty paragraph - if len(self.children) == 1 and \ - isinstance(self.children[0], Bookmark) and \ - self.children[0].name in ('_GoBack',): - return True - + if len(self.children) == 1: + first_child = self.children[0] + if isinstance(first_child, Bookmark) and \ + first_child.name in ('_GoBack',): + return True + # We can have cases when only run properties are defined and no text + elif not first_child.children: + return True return False @property diff --git a/tests/export/html/test_field_code.py b/tests/export/html/test_field_code.py index 77033818..274e011c 100644 --- a/tests/export/html/test_field_code.py +++ b/tests/export/html/test_field_code.py @@ -206,6 +206,7 @@ def test_spanning_multiple_paragraphs(self): expected_html = '''

Link:

+

AAABBB

CCC

DDD.

diff --git a/tests/export/html/test_heading.py b/tests/export/html/test_heading.py index b77dfc2d..f50176cb 100644 --- a/tests/export/html/test_heading.py +++ b/tests/export/html/test_heading.py @@ -274,7 +274,7 @@ def test_heading_in_a_nested_list_numbering_is_preserved_with_strong(self): expected_html = '''
  1. - foo +

    foo

    1. bar @@ -351,10 +351,10 @@ def test_heading_in_nested_sub_list(self): expected_html = '''
      1. - foo -
          -
        1. bar
        2. -
        +

        foo

        +
          +
        1. bar

        2. +

      baz

      @@ -416,8 +416,7 @@ def test_headings_in_list_surrounding_paragraph_stay_in_list_with_strong(self):
      1. foo -
        - bare paragraph +

        bare paragraph

      2. bar @@ -527,7 +526,7 @@ def test_heading_as_new_list_following_bare_paragraph_plus_list(self): expected_html = '''
          -
        1. foo
        2. +
        3. foo

        bare paragraph

          @@ -588,7 +587,10 @@ def test_heading_as_list_following_bare_paragraph_plus_list(self): expected_html = '''
            -
          1. foo
            bare paragraph
          2. +
          3. +

            foo

            +

            bare paragraph

            +
          4. bar
          ''' @@ -662,13 +664,13 @@ def test_list_heading_table_paragraph(self): expected_html = '''
            -
          1. single list item
          2. +
          3. single list item

          actual heading

          before table

          - +
          foo

          foo

          after table

          @@ -739,7 +741,7 @@ def test_single_lvl_list_has_precedence_over_headings(self): expected_html = '''
          1. foo
          2. -
          3. non-heading list item
          4. +
          5. non-heading list item

          6. bar
          ''' diff --git a/tests/export/html/test_hyperlink.py b/tests/export/html/test_hyperlink.py index dbbe4a0c..b8bc3887 100644 --- a/tests/export/html/test_hyperlink.py +++ b/tests/export/html/test_hyperlink.py @@ -86,7 +86,7 @@ def test_no_link_text(self): document.add(MainDocumentPart, document_xml, document_rels) - expected_html = '' + expected_html = '

           

          ' self.assert_document_generates_html(document, expected_html) def test_undefined_relationship(self): diff --git a/tests/export/html/test_markup_compatibility.py b/tests/export/html/test_markup_compatibility.py index 6b89dc25..47efcce5 100644 --- a/tests/export/html/test_markup_compatibility.py +++ b/tests/export/html/test_markup_compatibility.py @@ -155,7 +155,9 @@ def test_fallback_contains_a_table(self):

          AAABBB

          - +
          CCC +

          CCC

          +

          DDDEEE

          @@ -204,7 +206,9 @@ def test_fallback_has_invalid_children(self):

          AAABBB - +
          CCC +

          CCC

          +
          DDDEEE

          diff --git a/tests/export/html/test_numbering.py b/tests/export/html/test_numbering.py index b41dc9de..d567972c 100644 --- a/tests/export/html/test_numbering.py +++ b/tests/export/html/test_numbering.py @@ -78,7 +78,9 @@ def test_lowerLetter_numbering_format_is_handled(self): expected_html = '''
            -
          1. AAA
          2. +
          3. +

            AAA

            +
          ''' self.assert_document_generates_html(document, expected_html) @@ -115,8 +117,12 @@ def test_single_level_list_with_surrounding_paragraphs(self): expected_html = '''

          Foo

            -
          1. AAA
          2. -
          3. BBB
          4. +
          5. +

            AAA

            +
          6. +
          7. +

            BBB

            +

          Bar

          ''' @@ -172,11 +178,15 @@ def test_multi_level_list_with_surrounding_paragraphs(self): expected_html = '''

          Foo

            -
          1. AAA +
          2. +

            AAA

              -
            1. BBB +
            2. +

              BBB

                -
              1. CCC
              2. +
              3. +

                CCC

                +
            @@ -226,10 +236,14 @@ def test_adjacent_lists(self): expected_html = '''

            Foo

              -
            1. AAA
            2. +
            3. +

              AAA

              +
              -
            1. BBB
            2. +
            3. +

              BBB

              +

            Bar

            ''' @@ -293,7 +307,9 @@ def test_basic_list_followed_by_list_that_is_heading_and_paragraph(self): expected_html = '''
              -
            1. AAA
            2. +
            3. +

              AAA

              +
            1. @@ -345,11 +361,11 @@ def test_separate_lists_with_paragraph_in_between_and_after(self): expected_html = '''

              Foo

                -
              1. AAA
              2. +
              3. AAA

              Bar

                -
              1. BBB
              2. +
              3. BBB

              Baz

              ''' @@ -382,7 +398,7 @@ def test_single_list_followed_by_paragraph(self): expected_html = '''
                -
              1. AAA
              2. +
              3. AAA

              Foo

              ''' @@ -421,8 +437,11 @@ def test_single_list_with_bare_paragraph_between_items(self): expected_html = '''
                -
              1. AAA
                Foo
              2. -
              3. BBB
              4. +
              5. +

                AAA

                +

                Foo

                +
              6. +
              7. BBB

              ''' self.assert_document_generates_html(document, expected_html) @@ -545,7 +564,7 @@ def test_paragraph_with_valid_list_level_followed_by_missing_level(self): expected_html = '''
                -
              1. AAA
              2. +
              3. AAA

              foo

              ''' @@ -592,11 +611,12 @@ def test_missing_level_in_between_valid_levels(self): expected_html = '''
              1. - AAA -
                - foo +

                AAA

                +

                foo

                +
              2. +
              3. +

                BBB

              4. -
              5. BBB
              ''' self.assert_document_generates_html(document, expected_html) @@ -628,8 +648,11 @@ def test_empty_paragraph_after_list_item(self): expected_html = '''
                -
              1. AAA
              2. +
              3. +

                AAA

                +
              +

               

              ''' self.assert_document_generates_html(document, expected_html) @@ -666,8 +689,13 @@ def test_empty_paragraph_in_between_list_items(self): expected_html = '''
                -
              1. AAA
              2. -
              3. BBB
              4. +
              5. +

                AAA

                +

                 

                +
              6. +
              7. +

                BBB

                +
              ''' self.assert_document_generates_html(document, expected_html) @@ -707,8 +735,13 @@ def test_paragraph_and_run_with_empty_text_in_between_list_items(self): expected_html = '''
                -
              1. AAA
              2. -
              3. BBB
              4. +
              5. +

                AAA

                +

                +
              6. +
              7. +

                BBB

                +
              ''' self.assert_document_generates_html(document, expected_html) @@ -748,8 +781,13 @@ def test_paragraph_with_empty_run_in_between_list_items(self): expected_html = '''
                -
              1. AAA
              2. -
              3. BBB
              4. +
              5. +

                AAA

                +

                 

                +
              6. +
              7. +

                BBB

                +
              ''' self.assert_document_generates_html(document, expected_html) @@ -792,8 +830,14 @@ def test_paragraph_with_empty_run_followed_by_non_empty_paragraph(self): expected_html = '''
                -
              1. AAA
                BBB
              2. -
              3. CCC
              4. +
              5. +

                AAA

                +

                 

                +

                BBB

                +
              6. +
              7. +

                CCC

                +
              ''' self.assert_document_generates_html(document, expected_html) @@ -842,8 +886,16 @@ def test_paragraph_with_multiple_empty_runs_followed_by_non_empty_paragraph(self expected_html = '''
                -
              1. AAA
                BBB
              2. -
              3. CCC
              4. +
              5. +

                AAA

                +

                 

                +

                 

                +

                 

                +

                BBB

                +
              6. +
              7. +

                CCC

                +
              ''' self.assert_document_generates_html(document, expected_html) @@ -892,8 +944,16 @@ def test_paragraph_empty_run_paragraph_empty_run_paragraph(self): expected_html = '''
                -
              1. AAA
                Foo
                Bar
              2. -
              3. CCC
              4. +
              5. +

                AAA

                +

                 

                +

                Foo

                +

                 

                +

                Bar

                +
              6. +
              7. +

                CCC

                +
              ''' self.assert_document_generates_html(document, expected_html) @@ -933,8 +993,13 @@ def test_paragraph_followed_by_paragraph_with_only_whitespace(self): expected_html = '''
                -
              1. AAA
              2. -
              3. BBB
              4. +
              5. +

                AAA

                +

                +
              6. +
              7. +

                BBB

                +
              ''' self.assert_document_generates_html(document, expected_html) @@ -965,7 +1030,7 @@ def test_empty_item(self): expected_html = '''
                -
              1. +
              ''' self.assert_document_generates_html(document, expected_html) @@ -1058,13 +1123,13 @@ def test_numfmt_None_causes_sub_list_to_be_ignored(self): expected_html = '''
              1. - AAA -
                - BBB -
                - CCC +

                AAA

                +

                BBB

                +

                CCC

                +
              2. +
              3. +

                DDD

              4. -
              5. DDD
              ''' self.assert_document_generates_html(document, expected_html) @@ -1119,8 +1184,8 @@ def test_root_level_numfmt_None_with_sublist(self): expected_html = '''

              AAA

                -
              1. BBB
              2. -
              3. CCC
              4. +
              5. BBB

              6. +
              7. CCC

              DDD

              ''' @@ -1216,11 +1281,15 @@ def test_default_indentation(self): expected_html = '''
                -
              1. AAA +
              2. +

                AAA

                  -
                1. BBB +
                2. +

                  BBB

                    -
                  1. CCC
                  2. +
                  3. +

                    CCC

                    +
                @@ -1287,11 +1356,15 @@ def test_custom_indentation(self): expected_html = '''
                  -
                1. AAA +
                2. +

                  AAA

                    -
                  1. BBB +
                  2. +

                    BBB

                      -
                    1. CCC
                    2. +
                    3. +

                      CCC

                      +
                  @@ -1359,14 +1432,13 @@ def test_custom_hanging_indentation(self): expected_html = '''
                  1. - AAA +

                    AAA

                    1. - BBB +

                      BBB

                      1. - CCC - +

                        CCC

                    2. @@ -1434,11 +1506,13 @@ def test_custom_first_line_indentation(self): expected_html = '''
                        -
                      1. AAA +
                      2. +

                        AAA

                          -
                        1. BBB +
                        2. +

                          BBB

                            -
                          1. CCC
                          2. +
                          3. CCC

                        @@ -1520,15 +1594,19 @@ def test_nested_separated_lists(self): expected_html = '''
                        1. - AAA +

                          AAA

                          1. - BBB +

                            BBB

                              -
                            1. CCC
                            2. +
                            3. +

                              CCC

                              +
                          2. -
                          3. DDD
                          4. +
                          5. +

                            DDD

                            +
                        @@ -1602,13 +1680,17 @@ def test_nested_separated_lists_different_level(self): expected_html = '''
                        1. - AAA +

                          AAA

                            -
                          1. BBB
                          2. -
                          3. CCC
                          4. +
                          5. +

                            BBB

                            +
                          6. +
                          7. +

                            CCC

                            +
                        2. -
                        3. DDD
                        4. +
                        5. DDD

                        ''' self.assert_document_generates_html(document, expected_html) @@ -1632,7 +1714,7 @@ def assert_html(self, list_type, digit_generator): document_xml = ''.join(paragraphs) items = [ - '
                      3. {item}
                      4. '.format(item=item) + '
                      5. {item}

                      6. '.format(item=item) for item in expected_items ] @@ -1707,9 +1789,9 @@ def test_real_list_plus_fake_list(self): expected_html = '''
                          -
                        1. Foo
                        2. -
                        3. Bar
                        4. -
                        5. Baz
                        6. +
                        7. Foo

                        8. +
                        9. Bar

                        10. +
                        11. Baz

                        ''' self.assert_document_generates_html(document, expected_html) @@ -1745,10 +1827,11 @@ def test_real_list_plus_tab_nested_fake_list_with_mixed_formats(self): expected_html = '''
                          -
                        1. AAA +
                        2. +

                          AAA

                            -
                          1. BBB
                          2. -
                          3. CCC
                          4. +
                          5. BBB

                          6. +
                          7. CCC

                        @@ -1788,9 +1871,9 @@ def test_initial_faked_list_plus_real_list(self): expected_html = '''
                          -
                        1. Foo
                        2. -
                        3. Bar
                        4. -
                        5. AAA
                        6. +
                        7. Foo

                        8. +
                        9. Bar

                        10. +
                        11. AAA

                        ''' self.assert_document_generates_html(document, expected_html) @@ -1805,12 +1888,12 @@ def test_one_fake_list_followed_by_another_fake_list_same_format(self): expected_html = '''
                          -
                        1. AA
                        2. -
                        3. AB
                        4. +
                        5. AA

                        6. +
                        7. AB

                          -
                        1. BA
                        2. -
                        3. BB
                        4. +
                        5. BA

                        6. +
                        7. BB

                        ''' @@ -1826,12 +1909,12 @@ def test_one_fake_list_followed_by_another_fake_list_different_format(self): expected_html = '''
                          -
                        1. AA
                        2. -
                        3. AB
                        4. +
                        5. AA

                        6. +
                        7. AB

                          -
                        1. BA
                        2. -
                        3. BB
                        4. +
                        5. BA

                        6. +
                        7. BB

                        ''' @@ -1886,10 +1969,11 @@ def test_real_nested_list_continuation_fake_nested_list_using_indentation(self): expected_html = '''
                          -
                        1. AAA +
                        2. +

                          AAA

                            -
                          1. BBB
                          2. -
                          3. CCC
                          4. +
                          5. BBB

                          6. +
                          7. CCC

                        @@ -1945,12 +2029,13 @@ def test_real_nested_list_continuation_fake_list_using_indentation(self): expected_html = '''
                          -
                        1. AAA +
                        2. +

                          AAA

                            -
                          1. BBB
                          2. +
                          3. BBB

                        3. -
                        4. CCC
                        5. +
                        6. CCC

                        ''' self.assert_document_generates_html(document, expected_html) @@ -1993,19 +2078,21 @@ def test_faked_list_using_indentation(self): expected_html = '''
                          -
                        1. AA +
                        2. +

                          AA

                            -
                          1. AAA
                          2. -
                          3. AAB
                          4. -
                          5. AAC +
                          6. AAA

                          7. +
                          8. AAB

                          9. +
                          10. +

                            AAC

                              -
                            1. AACA
                            2. +
                            3. AACA

                          11. -
                          12. AAD
                          13. +
                          14. AAD

                        3. -
                        4. AB
                        5. +
                        6. AB

                        ''' @@ -2020,8 +2107,8 @@ def test_faked_list_that_skips_numbers(self): expected_html = '''
                          -
                        1. AA
                        2. -
                        3. AB
                        4. +
                        5. AA

                        6. +
                        7. AB

                        4. AC @@ -2065,8 +2152,8 @@ def test_space_after_dot_followed_by_number_is_converted(self): expected_html = '''

                          -
                        1. 1
                        2. -
                        3. 2
                        4. +
                        5. 1

                        6. +
                        7. 2

                        ''' @@ -2102,19 +2189,19 @@ def test_tab_char_is_sufficient_for_space_after_dot(self): expected_html = '''
                          -
                        1. a
                        2. +
                        3. a

                          -
                        1. b
                        2. +
                        3. b

                          -
                        1. c
                        2. +
                        3. c

                          -
                        1. d
                        2. +
                        3. d

                          -
                        1. e
                        2. +
                        3. e

                        ''' @@ -2131,19 +2218,19 @@ def test_single_item_lists(self): expected_html = '''
                          -
                        1. a
                        2. +
                        3. a

                          -
                        1. b
                        2. +
                        3. b

                          -
                        1. c
                        2. +
                        3. c

                          -
                        1. d
                        2. +
                        3. d

                          -
                        1. e
                        2. +
                        3. e

                        ''' @@ -2162,7 +2249,7 @@ def test_trailing_text_is_not_removed(self): expected_html = '''
                          -
                        1. Foo Bar
                        2. +
                        3. Foo Bar

                        ''' @@ -2181,7 +2268,7 @@ def test_leading_text_is_not_removed(self): expected_html = '''
                          -
                        1. Foo Bar
                        2. +
                        3. Foo Bar

                        ''' @@ -2221,8 +2308,8 @@ def test_faked_list_with_list_level_numfmt_None_still_detected(self): expected_html = '''
                          -
                        1. AAA
                        2. -
                        3. BBB
                        4. +
                        5. AAA

                        6. +
                        7. BBB

                        ''' self.assert_document_generates_html(document, expected_html) @@ -2252,8 +2339,8 @@ def test_faked_within_a_table(self):
                          -
                        1. Foo
                        2. -
                        3. Bar
                        4. +
                        5. Foo

                        6. +
                        7. Bar

                        @@ -2396,14 +2483,15 @@ def setUp(self): self.expected_html = '''
                          -
                        1. +
                        2. +

                            -
                          1. -
                          2. +
                          3. +
                        3. -
                        4. +
                        ''' @@ -2488,21 +2576,27 @@ def setUp(self): self.expected_html = '''
                          -
                        1. AA
                        2. -
                        3. AB +
                        4. +

                          AA

                          +
                        5. +
                        6. +

                          AB

                            -
                          1. ABA
                          2. -
                          3. ABB +
                          4. +

                            ABA

                            +
                          5. +
                          6. +

                            ABB

                              -
                            1. ABBA
                            2. -
                            3. ABBB
                            4. -
                            5. ABBC
                            6. +
                            7. ABBA

                            8. +
                            9. ABBB

                            10. +
                            11. ABBC

                          7. -
                          8. ABC
                          9. +
                          10. ABC

                        7. -
                        8. AC
                        9. +
                        10. AC

                        ''' diff --git a/tests/export/html/test_paragraph.py b/tests/export/html/test_paragraph.py index 4cda50d5..e2faa5da 100644 --- a/tests/export/html/test_paragraph.py +++ b/tests/export/html/test_paragraph.py @@ -17,7 +17,7 @@ def test_no_runs_no_text(self): document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                         

                        ' self.assert_document_generates_html(document, expected_html) def test_multiple_runs_with_only_whitespace(self): @@ -34,7 +34,7 @@ def test_multiple_runs_with_only_whitespace(self): document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                        ' self.assert_document_generates_html(document, expected_html) def test_run_with_only_whitespace_styled(self): @@ -51,7 +51,7 @@ def test_run_with_only_whitespace_styled(self): document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                        ' self.assert_document_generates_html(document, expected_html) @@ -154,7 +154,7 @@ def test_single_whitespace_in_text_run_is_preserved(self): expected_html = '

                        Foo Bar

                        ' self.assert_document_generates_html(document, expected_html) - def test_paragraph_with_only_whitespace_is_ignored(self): + def test_paragraph_with_only_whitespace_is_not_ignored(self): document_xml = '''

                        @@ -168,7 +168,7 @@ def test_paragraph_with_only_whitespace_is_ignored(self): document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                        ' self.assert_document_generates_html(document, expected_html) def test_leading_whitespace_is_preserved(self): @@ -205,7 +205,7 @@ def test_multiple_text_tags_in_a_single_run_tag_create_single_paragraph( expected_html = '

                        ABC

                        ' self.assert_document_generates_html(document, expected_html) - def test_empty_text_tag_does_not_create_paragraph(self): + def test_empty_text_tag_does_create_paragraph(self): document_xml = '''

                        @@ -216,7 +216,7 @@ def test_empty_text_tag_does_not_create_paragraph(self): document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                        ' self.assert_document_generates_html(document, expected_html) def test_unicode_character_from_xml_entity(self): @@ -301,7 +301,7 @@ def test_nested_smartTag(self): class ParagraphJustificationTestCase(DocumentGeneratorTestCase): - def test_with_empty_text_does_not_render_paragraph(self): + def test_with_empty_text_does_render_paragraph(self): document_xml = '''

                        @@ -316,10 +316,10 @@ def test_with_empty_text_does_not_render_paragraph(self): document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                        ' self.assert_document_generates_html(document, expected_html) - def test_with_missing_text_does_not_render_paragraph(self): + def test_with_missing_text_does_render_paragraph(self): document_xml = '''

                        @@ -332,7 +332,7 @@ def test_with_missing_text_does_not_render_paragraph(self): document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                         

                        ' self.assert_document_generates_html(document, expected_html) def test_with_blank_space_in_text_does_not_render_paragraph_with_span(self): # noqa @@ -350,7 +350,7 @@ def test_with_blank_space_in_text_does_not_render_paragraph_with_span(self): # document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                        ' self.assert_document_generates_html(document, expected_html) @@ -363,7 +363,7 @@ def get_break_tag(self, br): class IgnoringBreakTagTestCase(DocumentGeneratorTestCase): exporter = IgnoringBreakTagExporter - def test_break_tag_by_itself_yields_no_output(self): + def test_break_tag_by_itself_yields_only_paragraph(self): document_xml = '''

                        @@ -375,7 +375,7 @@ def test_break_tag_by_itself_yields_no_output(self): document = WordprocessingDocumentFactory() document.add(MainDocumentPart, document_xml) - expected_html = '' + expected_html = '

                        ' self.assert_document_generates_html(document, expected_html) def test_break_tag_with_text_break_tag_is_ignored(self): diff --git a/tests/export/html/test_tables.py b/tests/export/html/test_tables.py index 6ee5ebba..b5590270 100644 --- a/tests/export/html/test_tables.py +++ b/tests/export/html/test_tables.py @@ -33,7 +33,7 @@ def test_one_row_one_cell_one_paragraph(self): expected_html = ''' - +
                        Foo

                        Foo

                        ''' @@ -65,7 +65,10 @@ def test_one_row_one_cell_multiple_paragraphs(self): expected_html = ''' - +
                        Foo
                        Bar
                        +

                        Foo

                        +

                        Bar

                        +
                        ''' @@ -115,12 +118,12 @@ def test_two_rows_two_cells_one_paragraph_each(self): expected_html = ''' - - + + - - + +
                        FooBar

                        Foo

                        Bar

                        OneTwo

                        One

                        Two

                        ''' @@ -173,7 +176,11 @@ def test_cell_with_character_styles_applied(self): expected_html = ''' - +
                        Foo +

                        + Foo +

                        +
                        ''' @@ -219,11 +226,13 @@ def test_two_rows_two_cells_with_colspan(self): expected_html = ''' - + - - + +
                        Foo +

                        Foo

                        +
                        OneTwo

                        One

                        Two

                        ''' @@ -274,11 +283,17 @@ def test_two_rows_two_cells_with_rowspan(self): expected_html = ''' - - + + - +
                        FooBar +

                        Foo

                        +
                        +

                        Bar

                        +
                        Two +

                        Two

                        +
                        ''' @@ -302,7 +317,9 @@ def test_one_row_one_cell_with_empty_paragraph(self): expected_html = ''' - +
                        +

                         

                        +
                        ''' @@ -329,7 +346,10 @@ def test_one_row_one_cell_with_empty_paragraph_after_other_paragraph(self): expected_html = ''' - +
                        Foo +

                        Foo

                        +

                         

                        +
                        ''' @@ -356,7 +376,10 @@ def test_one_row_one_cell_with_empty_paragraph_before_other_paragraph(self): expected_html = ''' - +
                        Foo +

                         

                        +

                        Foo

                        +
                        ''' @@ -384,7 +407,10 @@ def test_one_row_one_cell_with_paragraph_that_has_empty_run_before_other_paragra expected_html = ''' - +
                        Foo +

                         

                        +

                        Foo

                        +
                        ''' @@ -412,7 +438,10 @@ def test_one_row_one_cell_with_paragraph_that_has_empty_run_after_other_paragrap expected_html = ''' - +
                        Foo +

                        Foo

                        +

                         

                        +
                        ''' @@ -440,7 +469,10 @@ def test_one_row_one_cell_with_empty_text_before_other_paragraph(self): expected_html = ''' - +
                        Foo +

                        +

                        Foo

                        +
                        ''' @@ -468,7 +500,10 @@ def test_one_row_one_cell_with_empty_text_after_other_paragraph(self): expected_html = ''' - +
                        Foo +

                        Foo

                        +

                        +
                        ''' @@ -496,7 +531,10 @@ def test_one_row_one_cell_with_whitespace_after_other_paragraph(self): expected_html = ''' - +
                        Foo +

                        Foo

                        +

                        +
                        ''' diff --git a/tests/export/html/test_textbox.py b/tests/export/html/test_textbox.py index 7ad847d1..923da46f 100644 --- a/tests/export/html/test_textbox.py +++ b/tests/export/html/test_textbox.py @@ -115,11 +115,15 @@ def test_textbox_with_a_table(self): document.add(MainDocumentPart, document_xml) expected_html = ''' - - - - -
                        AAA
                        +

                        + + + + +
                        +

                        AAA

                        +
                        +

                        ''' self.assert_document_generates_html(document, expected_html) @@ -166,7 +170,9 @@ def test_textbox_with_a_table_and_other_runs(self): AAA - +
                        BBB +

                        BBB

                        +
                        CCC diff --git a/tests/export/test_xml.py b/tests/export/test_xml.py index 2ad17a88..22fd491a 100644 --- a/tests/export/test_xml.py +++ b/tests/export/test_xml.py @@ -131,12 +131,12 @@ class TableTag(TranslationTestCase): expected_output = ''' - - + + - - + +
                        AAABBB

                        AAA

                        BBB

                        CCCDDD

                        CCC

                        DDD

                        ''' @@ -158,11 +158,17 @@ class RowSpanTestCase(TranslationTestCase): expected_output = ''' - - + + - +
                        AAABBB +

                        AAA

                        +
                        +

                        BBB

                        +
                        CCC +

                        CCC

                        +
                        ''' @@ -185,20 +191,20 @@ class NestedTableTag(TranslationTestCase): expected_output = ''' - - + + - + @@ -228,12 +234,12 @@ class TableWithInvalidTag(TranslationTestCase): expected_output = '''
                        AAABBB

                        AAA

                        BBB

                        CCC

                        CCC

                        - - + + - - + +
                        DDDEEE

                        DDD

                        EEE

                        FFFGGG

                        FFF

                        GGG

                        - - + + - +
                        AAABBB

                        AAA

                        BBB

                        DDD

                        DDD

                        ''' @@ -256,11 +262,11 @@ class TableWithListAndParagraph(TranslationTestCase):
                          -
                        1. AAA
                        2. -
                        3. BBB
                        4. +
                        5. AAA

                        6. +
                        7. BBB

                        - CCC
                        - DDD +

                        CCC

                        +

                        DDD

                        @@ -299,9 +305,9 @@ def get_xml(self): class SimpleListTestCase(TranslationTestCase): expected_output = '''
                          -
                        1. AAA
                        2. -
                        3. BBB
                        4. -
                        5. CCC
                        6. +
                        7. AAA

                        8. +
                        9. BBB

                        10. +
                        11. CCC

                        ''' @@ -329,7 +335,7 @@ def get_xml(self): class SingleListItemTestCase(TranslationTestCase): expected_output = '''
                          -
                        1. AAA
                        2. +
                        3. AAA

                        ''' @@ -355,20 +361,24 @@ def get_xml(self): class ListWithContinuationTestCase(TranslationTestCase): expected_output = '''
                          -
                        1. AAA
                          BBB
                        2. -
                        3. CCC +
                        4. +

                          AAA

                          +

                          BBB

                          +
                        5. +
                        6. +

                          CCC

                          - - + + - - + +
                          DDDEEE

                          DDD

                          EEE

                          FFFGGG

                          FFF

                          GGG

                        7. -
                        8. HHH
                        9. +
                        10. HHH

                        ''' @@ -397,19 +407,20 @@ def get_xml(self): class ListWithMultipleContinuationTestCase(TranslationTestCase): expected_output = '''
                          -
                        1. AAA +
                        2. +

                          AAA

                          - +
                          BBB

                          BBB

                          - +
                          CCC

                          CCC

                        3. -
                        4. DDD
                        5. +
                        6. DDD

                        ''' @@ -437,13 +448,13 @@ def get_xml(self): class MangledIlvlTestCase(TranslationTestCase): expected_output = '''
                          -
                        1. AAA
                        2. +
                        3. AAA

                          -
                        1. BBB
                        2. +
                        3. BBB

                          -
                        1. CCC
                        2. +
                        3. CCC

                        ''' @@ -465,13 +476,13 @@ class SeperateListsIntoParentListTestCase(TranslationTestCase): expected_output = '''
                        1. - AAA +

                          AAA

                            -
                          1. BBB
                          2. -
                          3. CCC
                          4. +
                          5. BBB

                          6. +
                          7. CCC

                        2. -
                        3. DDD
                        4. +
                        5. DDD

                        ''' @@ -496,12 +507,13 @@ def get_xml(self): class InvalidIlvlOrderTestCase(TranslationTestCase): expected_output = '''
                          -
                        1. AAA +
                        2. +

                          AAA

                            -
                          1. BBB
                          2. +
                          3. BBB

                        3. -
                        4. CCC
                        5. +
                        6. CCC

                        ''' @@ -617,7 +629,7 @@ def get_xml(self): class RTagWithNoText(TranslationTestCase): - expected_output = '' + expected_output = '

                         

                        ' def get_xml(self): p_tag = DXB.p_tag(None) # No text @@ -634,11 +646,12 @@ class DeleteTagInList(TranslationTestCase): expected_output = '''
                        1. - AAA -
                          - BBB +

                          AAA

                          +

                          + BBB +

                        2. -
                        3. CCC
                        4. +
                        5. CCC

                        ''' @@ -664,11 +677,12 @@ class InsertTagInList(TranslationTestCase): expected_output = '''
                        1. - AAA -
                          - BBB +

                          AAA

                          +

                          + BBB +

                        2. -
                        3. CCC
                        4. +
                        5. CCC

                        ''' @@ -695,11 +709,10 @@ class SmartTagInList(TranslationTestCase): expected_output = '''
                        1. - AAA -
                          - BBB +

                          AAA

                          +

                          BBB

                        2. -
                        3. CCC
                        4. +
                        5. CCC

                        ''' @@ -725,7 +738,7 @@ def get_xml(self): class SingleListItem(TranslationTestCase): expected_output = '''
                          -
                        1. AAA
                        2. +
                        3. AAA

                        BBB

                        ''' @@ -752,19 +765,19 @@ class SimpleTableTest(TranslationTestCase): expected_output = ''' - - - + + + - - - + + + - - - + + +
                        BlankColumn 1Column 2

                        Blank

                        Column 1

                        Column 2

                        Row 1FirstSecond

                        Row 1

                        First

                        Second

                        Row 2ThirdFourth

                        Row 2

                        Third

                        Fourth

                        ''' @@ -790,10 +803,11 @@ def get_xml(self): class MissingIlvl(TranslationTestCase): expected_output = '''
                          -
                        1. AAA
                          - BBB +
                        2. +

                          AAA

                          +

                          BBB

                        3. -
                        4. CCC
                        5. +
                        6. CCC

                        ''' @@ -814,18 +828,19 @@ def get_xml(self): class SameNumIdInTable(TranslationTestCase): expected_output = '''
                          -
                        1. AAA +
                        2. +

                          AAA

                            -
                          1. BBB
                          2. +
                          3. BBB

                        3. -
                        4. CCC
                        5. +
                        6. CCC

                        ''' @@ -858,9 +873,11 @@ def get_xml(self): class SDTTestCase(TranslationTestCase): expected_output = '''
                          -
                        1. AAABBB +
                        2. +

                          AAA

                          +

                          BBB

                        3. -
                        4. CCC
                        5. +
                        6. CCC

                        ''' @@ -1023,16 +1040,23 @@ def get_xml(self): class NestedListTestCase(TranslationTestCase): expected_output = u"""
                          -
                        1. AAA +
                        2. +

                          AAA

                            -
                          1. BBB
                          2. +
                          3. +

                            BBB

                            +
                        3. -
                        4. CCC +
                        5. +

                          CCC

                            -
                          1. DDD +
                          2. +

                            DDD

                              -
                            1. EEE
                            2. +
                            3. +

                              EEE

                              +
                          @@ -1068,58 +1092,58 @@ class MultipleNestedListTestCase(TranslationTestCase): expected_output = u"""
                          1. - AAA +

                            AAA

                            1. - BBB +

                              BBB

                                -
                              1. CCC
                              2. -
                              3. DDD
                              4. +
                              5. CCC

                              6. +
                              7. DDD

                            2. - EEE +

                              EEE

                                -
                              1. FFF
                              2. -
                              3. GGG
                              4. +
                              5. FFF

                              6. +
                              7. GGG

                            3. - HHH +

                              HHH

                                -
                              1. III
                              2. -
                              3. JJJ
                              4. +
                              5. III

                              6. +
                              7. JJJ

                          2. -
                          3. KKK
                          4. +
                          5. KKK

                          1. - LLL +

                            LLL

                              -
                            1. MMM
                            2. -
                            3. NNN
                            4. +
                            5. MMM

                            6. +
                            7. NNN

                          2. - OOO +

                            OOO

                              -
                            1. PPP
                            2. +
                            3. PPP

                            4. - QQQ +

                              QQQ

                                -
                              1. RRR
                              2. +
                              3. RRR

                          3. - SSS +

                            SSS

                              -
                            1. TTT
                            2. -
                            3. UUU
                            4. +
                            5. TTT

                            6. +
                            7. UUU

                          diff --git a/tests/fixtures/export_from_googledocs.docx b/tests/fixtures/export_from_googledocs.docx index 9939ffb7870d42b8dc4a5b631b0e99c0492027bd..a2601f55301c24896dbe955121004a8158e392c4 100644 GIT binary patch literal 11642 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

                          B0e4err;W znxCGKrey1W^BmzMILa)~qC0HM^jcR>n#sF4`t@*BZhXt=tZZaMJiF}${gBvzHW)eS zyQhin`Zk`j&AUpfC;1;VLH$L>7g}mVF^GI?5f1RewJ5%1*3X9Cv8LxL zTR!Q&rh7@5$4L39Z+5AKBDT#?!j|Y_+Y?c2%kAD~^mAC;6O6R5Qts}BszYrTy&)K; z-UAu?SQw|m8VUaC#2{}YOUIkRJgJ+rAmv8o+KJ=GX8IJ@Ekap+@4m8vq3p<~k4fFbu)EyW z7p0u0Dj8dS8}o0FqYvV6DssZ5WP773H{^n!N8mP9cmHxOOP){}63JD#zeSQvro{rn zq7o#LF>gIG$T)8KVYjQmIPm4m&;yMCH7vE;jG}X>95s}8qBMiCftsJwe#WtrC~F5G zbsN*o^QX_FK9}&j8T-_Z6|Ee@U0cmx1FO*~#WHmoMyvNGDBi*qohoW_x2CPwN+i?0 zGo`#&G=jHp(x|4;Ol58r>AtU0vlMNB^%EafQ6XApvs;(p<3CFHeiprl1R(%0O8Rdp z$NHaQV2QMM^}KvG@q|y`6en~$x8k#}G5ZAUVA&1VyaYu`LgU@;Dk_y@X}Drg4*DyN zrF`=woL;jFW;vekfyGja(=Xhw%ae+g@oDO6Xggk8p$Z(CSd`KgOfg+0%n2oDksKL1 zpnH}a`0%0V>n>UwqHvAC(X@1e`UNi4yuiVT`QmxeFS6sGtpbL-Uk8pXrxA=$-CQ>% zavBv@9=X|eQl>H*Llunry!3cpCt`yT?zTrQK8#^+Z<65`qrwHD+cPdibM4>TpYzaU zzf{-r5}erT656=0ckJBfFMFVXsoQFwVSNU{^^z3@6P&Wsoh}zNiw{I0K3xCY)l%TU z_z|V=k%@UPN8KVqNjgL4@vuWqyE}x|d60zjp4tLHZw_<5R|W2i+qJU-v^6;%?%jE_ z&hE`472WBJ&3@qwUdl6m=R~?VTQf}nzaZcg$X zyO}nRGRo^B^RgE^a8whvAC>_6od+#rN~$FqE;cD%9~2-hH>QfWCjT0@jvdgD_w}n< z+K!{ML~}(Iii+1978d$f6}1p92p#)AR{VZaA;r8DtJ5k%iOmY}DMYHdk&>bMYuUa^6F%GmSgat<@9VF{uCL!69cYz+ zNaGk6-A|6AihEK6HY3>_UW*Q|VA5U?hNEMs(oKV2S#$*$(yBN%wTD#6f?q7mIXB2c z@?eofBhK9!?3FwfYBUDzDCHzc2O2@^=_TUNbdrVccPixEY^*5FkefM-JG`zro@VmY zd-eB-PX+6zso+WZeeHjcuiyW4 uHvdog{L>JWzp(pv$Fs@fPy@uR}ReM%bng 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 diff --git a/tests/fixtures/fake_subscript.html b/tests/fixtures/fake_subscript.html index 6bbf5a11..10fade6f 100644 --- a/tests/fixtures/fake_subscript.html +++ b/tests/fixtures/fake_subscript.html @@ -1 +1,5 @@ -

                          H2O

                          +

                          + H + 2 + O +

                          diff --git a/tests/fixtures/fake_superscript.html b/tests/fixtures/fake_superscript.html index 99b80941..583baa36 100644 --- a/tests/fixtures/fake_superscript.html +++ b/tests/fixtures/fake_superscript.html @@ -1 +1,4 @@ -

                          nth

                          +

                          + n + th +

                          \ No newline at end of file diff --git a/tests/fixtures/has_title.html b/tests/fixtures/has_title.html index e54765be..f6c25042 100644 --- a/tests/fixtures/has_title.html +++ b/tests/fixtures/has_title.html @@ -1,2 +1,3 @@

                          Title

                          -

                          Text

                          +

                           

                          +

                          Text

                          diff --git a/tests/fixtures/justification.html b/tests/fixtures/justification.html index d0221649..0881ec23 100644 --- a/tests/fixtures/justification.html +++ b/tests/fixtures/justification.html @@ -1,22 +1,8 @@ -

                          Center Justified

                          -

                          Right justified

                          -

                          - - - Right justified and pushed in from right - - -

                          -

                          - - - Center justified and pushed in from left and it is great and it is the - coolest thing of all time and I like it and I think it is cool - - -

                          -

                          - - Left justified and pushed in from left - -

                          +

                          Center Justified

                          +

                           

                          +

                          Right justified

                          +

                           

                          +

                          Right justified and pushed in from right

                          +

                           

                          +

                          Center justified and pushed in from left and it is great and it is the coolest thing of all time and I like it and I think it is cool

                          +

                          Left justified and pushed in from left

                          \ No newline at end of file diff --git a/tests/fixtures/list_in_table.docx b/tests/fixtures/list_in_table.docx index d1a8738808cc9dab276df085a821a8ff80cba8bb..b0e47e76e5ff316fc1f770c2299d7d15a33419f8 100644 GIT binary patch literal 12988 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 literal 4379 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 z zg%kk+M`9{>-oY%*I0XZ|C;T-9%%ZuT*9^Pl8&Zkg=&W%Qowjy2KIm&}%N*~BoNQ-Y z5^L8)J0B}hZ!kNM9%xWnM4WpHrQuAX`o`+?xx>eBuP+%kQy!T3QMT51Mgpj4Dgo|- zqglbqvTuiG&oz2eI*zsaR8h_#*SuUu}EX&KG~N3*w9_Neet9yDuhG#P(7F>S~^|*j;F)-kKB7lcr6-!$U~Mfnc5>V z95=&9w#YtQ$eI4}8pRV4TH@)3CWY6wb|IR)E1J^o zr4x!yHg7+xI58dXsR;}=%*{2odlx=9P7tKc;wfq^;|G&ibx5<@Y%SUEgUw>a^yTOj z1jR$M;M6OeR>5znO_GQrD_PKscRQ_af0bq~XdC>4vHlAq=3>ESdcYNQGO3y8<*ssM zBEH~=&q=`S6&;Gx2>t7szFVVk=Wnb-bgKo_VPWBsjBN;Yq2t!{SfI+gyJakAwo=?G~|r0 zh^p31f0dV&Laekx_C}d~pu?h}%tYpokcpixR9*&x+Xe|i9Z~ZQV!hAgh$^f~Y-UnQ zIUm-$PG<+kL~%2uAgIRPEwQwL>~3vCBa!DZ>Z@YWrpq#GHQ#4BrsHC4i@2QL^R%m^ z)QyIs?h07s9PS?T#tCgVP-sit>4=4Btil*bDpDl6+xE~hyF|~riBqhPd8@R z7;})&BDToyT}p7}!rMNT#cZaqD#z9*G3qA7M<&t@^Zj*1LWu&FrB#iW3--Iqh zbgfwYA|J)TJk49Xn`6*a3|uUN;H<|!bAzP%`*%Bg8c4i3zD5#7`l)&CYHXnZ6lJ1N z^Mw-s#?=auQqj0tgR&TK7S$cj$#xVc}$ z5zKIRV>hth;T&4Ct$?;>15A3I-HaJXPoi1zb2kFHMmCoXV7Cm^}qJ- z*Zi{<0B3!E#vQDv{F(nRM(Ec!o$crTxe|TCzuxo@1MzGA*+Ujr%|GK4@n898d%$1Q z&*~uVB>owJSY`ZkBR|jOUz5*j3{EP41}FC4_*+;063$<<&sNbtSAKdn`-dw1ntqlS dxKjHW22}sI@Sv*1B)Car*bCP|cTnR-{{j9`F`obc diff --git a/tests/fixtures/list_in_table.html b/tests/fixtures/list_in_table.html index a0bf3824..05be4223 100644 --- a/tests/fixtures/list_in_table.html +++ b/tests/fixtures/list_in_table.html @@ -2,10 +2,11 @@
                            -
                          1. AAA
                          2. -
                          3. BBB
                          4. -
                          5. CCC
                          6. +
                          7. AAA

                          8. +
                          9. BBB

                          10. +
                          11. CCC

                          +

                           

                          \ No newline at end of file diff --git a/tests/fixtures/lists_with_margins.docx b/tests/fixtures/lists_with_margins.docx index a0db187ceaca86633ef5b6859c8d58bc61ae6fb6..b78e60e49cb48fe329e406edd6bac930c028b693 100644 GIT binary patch delta 3187 zcmY+GcRU-47RM7KMAg<9tx*x1#H#JaDz#$As7>sV)E=R>8X;Cut-V`YDXnPK_Ij%} zp{9w@r56buJLXkt(;lpFozO?b%Gw`t3w zCD&HeAlr(pQRQhx2AP2CairO23TjT4(AVssB2U(OaFvw`ExY!4>WGrx^uU?`S|+yQ za`T>sPoOYbs%BIc8R@dp0e|+#lI+eLmknNuIsbzp)$hk6CC-P|e!3le#f-Bl?)kFy z!ZM#fGk(g2lhm}2>y~c*StaND2SxI!#ZFoAly`}Si?d9MkTd@;gM7<%&ZBNtnM?Ic6;`=}c!>jB>Q zQ+e5OM$}JcN!N44P-485H20_!ul@|(7TQ-RVyIakixSHB9IlOvABMh`9By|AyXswS zH6T*n6mUkgc5H3e6155>K+xknHiP()gc#e*mMxStSuSgFxU!FE)*{a;cKlB-4ZN7 zluk-8GaQ zSl_&=Z#ZA;r=y4`suFFrH3tX0#845RqkQU1jtmbEhZSsfjOeM83#j0N z!2~u#pet%*YGw}6M3VehH%?Y7|?QsZJaBX2?B zCM)!>k0nr}cSmYdy%)C}%ug7r?<<+u=+K*A-B5N2>*J;YyDOY22v$6(vNtmwt9H%B zd4J>}x9Q9^Om5w8b=IkWy^C7MMNJVJlx}iK6H?`7(iN+1tO_4m%{A~lZC0)l%_KP6 z@r>Fa@IX{w0n5d0*%8OtVEExe74HN2T_{t$EExXu3}9=`W*l;$k9{++zt`j^!PEhd ze{QLQ3F|CupZdDXj!C#?R(uO_P~oz9Id!0|%2n=w?+fI2{*Bk5G&Y3T2w9b7cZJdy z8`5v8fB;P#1GMNLVAT$~URipxc=ZWi{aoIZ3cyNn-UL1NVGpX}!*7ob=h}?CzANj) zguI&U_T-X~h-0(PV$#0y&@G=H#aZF}ZH1w#lMS`E%6nbXxHMmrL~ln%4i`cKN2H;| zZpFcQCTM+@cHyi!^%`a>fIkV7_pGo%EwYqY7E+f-*74HlX3pD|-4#44{TYEQpX3M%{J_6XxHU zP8Vft2O8fjhoCETfd6s+|dhI1yv5ee_h5SRJJokt- z(nd8~kNnNjw=KL|ht9Ty9To_oxlT_O9Cy-rkt;09<-mzoe~~j=J_<|sXCQeqwG38= zraUp{!SE(mLbC?FOFBHFK%a7vtB%gUcW~T#wrnALVNVX<@LKk%p0d-M?JLyX^!eEUlW!>BjO0Tq}OY z?lFwZw|>kj7P_*BIV=YSk1IeD{l7Y|T#J+polnEBB)yc5lnh3{aT7|(jP%=SX&vgK zn@8yl3DvD$lX_l|F{&=6d3-82vMX2fDE)NcUaWD7)Noz$*GA{cOv|jO=^(S*0=Cuo zNAKRQ1&1q_$Vl@TytG-@&$jz@GWh%UkQ|<8(oK^)+w-?oY5x)CUO11(boU3dE9aZv zNN1uHs#BWwkDND|Xp~eN?AqZ_5g`6gpFucB@*Z7OO74kb8t1j@W_U^h!li|2_=^^{ z!^Ph`cVcTvrr9okRC@a8fy}wGvC7hnRST_KwKaDID-tOBILWevF^1#bK9F`6A&jo( zboXMuGI@CNEbj(*4n)Za7*GN$?!!FTDeiT59vi^B`Vxy5M%c$7bBk{$e&Q<^){+kb zyMSuf-S7Ga8Nr8xL>Nm*sady3bRI`;4UPgz$qYWIDOVn|XwPd!ixj_235dJY%JcY= z&3dKRsuFZ9{!4Y4QExYDf8c)pqGa>jn%PaK9-uSfdf! z1+h!M;P=4~|7GY6#gK4dikYKU`nl}wlKAGG-)N1kw0A{(!-(+5mxS6e@iI-$ zOL^J!nc7;~Y>+#pczudXdJ_5XSV!e(Og_~40f*-_hom5pG3;_d6_riyo_W)8NAIHjR4_IUqRIAGlsCq zJ-PA;zCLR!YbV`HR+=_%c-CeOryxmRS2d zh)x=ty`o3yLP(y#9a>+W7{+^JIK9n;>z9z#m$!wCd)zGFa5TwZUfSa7%74>tE}@kf ztZ>Qk06ejt3^VzjN+V>)oxhYNQ8Oiq>iLLZ5F&Nc6xOmrd8v@UG&jt>)jpa;7lMP_ zgHVmk)-h>GB}I5R@^W~&#J(X|Qu~jzYFYVEgyDo-DqEOSxpc2ieH7b`TQ2L=2JxNc zWlan^oTYB0AHB$f!3GAI`@*`^GOeB(-9BS2JtgQOv9UEFEm3ZbESDrQ_f_Tf-ojT3 zxj#&kwrliyd1)dNY0CC_vZ`UDab=)z_Nzu>j%x^|(;R&u^~7F#i+NECL3;}?La0Su=7(?# zuHKGC_ordT*PB-mO6xuS2<|VDZYxk87mZ4TI1xn|Ki@`r%sZUj&}&TT&Nrh~ake`# z=lr$rSDP#Nib#JiA#G#4SB76ZqqH0lA3x%E#g>&>e9&4w#eESp4TV-dJ*U*q*d2J9 z$n6OSQh2FKzEd~@i`p*7-j;?~**=;hp;sS|5C8hL*(WJ07MOR5Z|)->t|upjZl9n< z*13Wsv1vRR&k}W{&k0HCAG=heE@!OYe?7oLLTehGX@h+6ZPTEsVasSuwfu$`KI=Uc zos|v=Ja#f;KVFm3oH-eZWb@gnv`9RR4gY)vhGKTrDrc&4@Q=!qNUjC(S>CgiMrP2e zrMS1L0TEYPb}h||!|~VsY>f0xy zZyc=!K1nUxX{vBv3N5fKvD|rXvtxX1rvv-+*!b}N&O_KwW&8%pEH ze)UVb)e)2fY*~QbK$e;OP6*EpV9?8L(*VLo_jBE&m<<`k&bIey3O1s*?niXM2JeTA zX}TPKVj+Bq;U9V@Mk7ptZo~#zmaGsI4V3$_exSqb2|V+dm~2o;lIzBLDZaFS>MJbYc0w{2?(z LP6(6-|10=!(w4Tl delta 3255 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 diff --git a/tests/fixtures/lists_with_margins.html b/tests/fixtures/lists_with_margins.html index f06c3c69..552847f1 100644 --- a/tests/fixtures/lists_with_margins.html +++ b/tests/fixtures/lists_with_margins.html @@ -1,15 +1,18 @@
                            -
                          1. AAA
                          2. -
                          3. BBB +
                          4. AAA

                          5. +
                          6. +

                            BBB

                              -
                            1. CCC
                            2. -
                            3. DDD +
                            4. CCC

                            5. +
                            6. +

                              DDD

                                -
                              1. EEE
                              2. -
                              3. FFF +
                              4. EEE

                              5. +
                              6. +

                                FFF

                                  -
                                1. GGG
                                2. -
                                3. HHH
                                4. +
                                5. GGG

                                6. +
                                7. HHH

                              diff --git a/tests/fixtures/lists_with_styles.html b/tests/fixtures/lists_with_styles.html index 72c5c552..ed3e4e15 100644 --- a/tests/fixtures/lists_with_styles.html +++ b/tests/fixtures/lists_with_styles.html @@ -1,13 +1,20 @@
                                -
                              1. AAA
                              2. -
                              3. BBB +
                              4. AAA

                              5. +
                              6. +

                                BBB

                                  -
                                1. CCC
                                2. -
                                3. DDD +
                                4. +

                                  CCC

                                  +
                                5. +
                                6. +

                                  DDD

                                    -
                                  1. EEE +
                                  2. +

                                    EEE

                                      -
                                    1. FFF
                                    2. +
                                    3. +

                                      FFF

                                      +
                                  diff --git a/tests/fixtures/nested_lists.html b/tests/fixtures/nested_lists.html index 6d8221f0..c46c87c4 100644 --- a/tests/fixtures/nested_lists.html +++ b/tests/fixtures/nested_lists.html @@ -1,30 +1,45 @@
                                    -
                                  1. one
                                  2. -
                                  3. two
                                  4. -
                                  5. three +
                                  6. one

                                  7. +
                                  8. two

                                  9. +
                                  10. +

                                    three

                                      -
                                    1. AAA
                                    2. -
                                    3. BBB
                                    4. -
                                    5. CCC +
                                    6. AAA

                                    7. +
                                    8. BBB

                                    9. +
                                    10. +

                                      CCC

                                        -
                                      1. alpha
                                      2. +
                                      3. +

                                        alpha

                                        +
                                  11. -
                                  12. four
                                  13. +
                                  14. +

                                    four

                                    +
                                  +

                                   

                                  +

                                   

                                    -
                                  1. xxx +
                                  2. +

                                    xxx

                                      -
                                    1. yyy
                                    2. +
                                    3. +

                                      yyy

                                      +
                                  +

                                   

                                    -
                                  • www +
                                  • +

                                    www

                                      -
                                    • zzz
                                    • +
                                    • +

                                      zzz

                                      +
                                  diff --git a/tests/fixtures/nested_lists_different_num_ids.html b/tests/fixtures/nested_lists_different_num_ids.html index 9f3562a9..b66ebf15 100644 --- a/tests/fixtures/nested_lists_different_num_ids.html +++ b/tests/fixtures/nested_lists_different_num_ids.html @@ -1,28 +1,30 @@
                                    -
                                  1. one
                                  2. -
                                  3. two +
                                  4. one

                                  5. +
                                  6. +

                                    two

                                      -
                                    • AAA1
                                    • -
                                    • BBB1
                                    • -
                                    • CCC1
                                    • +
                                    • AAA1

                                    • +
                                    • BBB1

                                    • +
                                    • CCC1

                                      -
                                    • CCC11
                                    • -
                                    • CCC12 +
                                    • CCC11

                                    • +
                                    • CCC12

                                        -
                                      • CCC121
                                      • -
                                      • CCC122
                                      • +
                                      • CCC121

                                      • +
                                      • CCC122

                                  7. -
                                  8. three +
                                  9. +

                                    three

                                      -
                                    • AAA2
                                    • -
                                    • BBB2
                                    • -
                                    • CCC2
                                    • +
                                    • AAA2

                                    • +
                                    • BBB2

                                    • +
                                    • CCC2

                                  10. -
                                  11. four
                                  12. -
                                  13. five
                                  14. +
                                  15. four

                                  16. +
                                  17. five

                                  diff --git a/tests/fixtures/nested_table_rowspan.html b/tests/fixtures/nested_table_rowspan.html index 73e9424b..bc429320 100644 --- a/tests/fixtures/nested_table_rowspan.html +++ b/tests/fixtures/nested_table_rowspan.html @@ -1,19 +1,21 @@ - + - +
                                  AAA

                                  AAA

                                  BBB

                                  BBB

                                  - - + + - +
                                  CCCDDD

                                  CCC

                                  DDD

                                  EEE

                                  EEE

                                  +

                                   

                                  +

                                   

                                  \ No newline at end of file diff --git a/tests/fixtures/nested_tables.docx b/tests/fixtures/nested_tables.docx index af704d4d703ea02ae53f380194a551224e5bb2d9..95962fd38f943dfbe2c458d12f3c137b49a9dce3 100644 GIT binary patch literal 12321 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 diff --git a/tests/fixtures/nested_tables.html b/tests/fixtures/nested_tables.html index ad5bf2f6..3919ba24 100644 --- a/tests/fixtures/nested_tables.html +++ b/tests/fixtures/nested_tables.html @@ -1,21 +1,23 @@ - - + + - +
                                  AAABBB

                                  AAA

                                  BBB

                                  CCC

                                  CCC

                                  - - + + - - + +
                                  DDDEEE

                                  DDD

                                  EEE

                                  FFFGGG

                                  FFF

                                  GGG

                                  +

                                   

                                  +

                                   

                                  diff --git a/tests/fixtures/paragraph_with_margins.html b/tests/fixtures/paragraph_with_margins.html index 1b1098c5..40f223fc 100644 --- a/tests/fixtures/paragraph_with_margins.html +++ b/tests/fixtures/paragraph_with_margins.html @@ -1,11 +1,10 @@

                                  Heading1

                                  -

                                  - Heading2 -

                                  -

                                  - - - - Heading3 - +

                                   

                                  +

                                  Heading2

                                  +

                                   

                                  +

                                   

                                  +

                                  + + + Heading3

                                  diff --git a/tests/fixtures/read_same_image_multiple_times.docx b/tests/fixtures/read_same_image_multiple_times.docx index 8166791079a0b38f85933ba9f2b46475e4e121d9..8797a32895c237ffde4e6ab684243bab49947546 100644 GIT binary patch literal 15693 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 R0005_5d)6$3+|s+{|nVz#k2qb literal 12768 zcmeHtWpEr>(yf?fF*91s%uFptiZ~vZE`yqUvN-XWq(FH}8=LfP$d{K|w(Q)gd2<0sUgIufKKejjbH$>E5=bF){#9 zLAb!vCp6)cWh?67zL9HUAzR`rNdM%cld%y7zmxM!RpRL?&{I zy*viQRRz&@%e6O2-b|Ta8K-9~`ZOCsY91sW+1cFCD@pyyO?2|L%Bwi&&}3bW#`SVs z3+?VKSmNPaw9TH}vpC>J&XichM+M7V&(%3T)YipQNUvu&+u9q^I~Y4Un%kH<(79M!)x^libuzrh z-~U9UecS<&r+-_u{UH$14{c0u%`?avM9H#Z!{SoCoW(d29or z`~kT8fPNqBPZEOzO(O-(+_7Zew@OU?295}mAI_)El*kdsOXAESrMB~#Y>Bm#cMDxV z>nVNZCY;uYXb%arOSa``ptA?1G&euHtDvyC(2E}Wpm~xkTuaFv3?D@ytB~|a$YFLo zFt|i#u`a7LGo!Zi>6VBcmy3F}{N6v`)#$U(S1&tXd}DS)NU=PXF5N!h)V?p8`<9X; z)}ipYS;GapYxheR1xSaaBwX_H2sKAM(#g3!ywZKVWigqbl#%mcp`Jm2xHww(wssre zM55pzs+n=Fh9UPsd)NsRHkLA6`pY(AnzsiELijfr3Oty~v z$%Wtz>v)Uyb-@$=;1=&K7Xw;qaWcR_K*#?v7r1}q;vYlQ$kx!w+StbNEhE1T*XGz! z+1Ir6oVtflIH%OM34Gh9gECiB#wP?Uvy43|Y!F>vi#RTDnJeQ`MLZ*WKhN704JTst zz4!l?zFpmCFV!YBYf;SMX{lp_zn`z8QqBM+t!7Z}NlMu(ChIQp()A&Z7ZZtjw>>|0 z1e}B+K#-AsD@eX=fJe8A;VSbg;Qf4UTA;P2`~)t~WA~y{dcxV!){0LzHQ9%*P9R3k zkW3&>yiJ-r`A^Lr^+vANiif)g5E`^%-}_d0zpWD5yg+8B1^m!N?l>8KC!|rx+$Wjh z9`Qg%#AW&&sZpOPJeCFWyN)9nFe59k_CO9(&{+j3Nd8hkoL7eeO$1zVi1y>nJRsH|^bW&9S%=9t0P7$S<^cm!0PZ7y~}a*^c!%xjY(1yxD$&A@bYGb6cJy^OyE2@it&6o&Jwv0~<=m$;2?U){ys zwGK?g+9$oHP9glLZ8xW?qsxWHKH?hgkq03*#@c$t5}fKb=GAOK{Q@K`qi3hi72naq z8Y|O#C(9|~!IL;}d;2)(#J<}G@^CqwR!zrqQsglKX`GM3w1d+e>3a^4Z1CDKqUbnB z-NkilfgsBQdOS0ZdN9exitwI#{kS9J3~>lw60&VZ&fkFu8lNR8zMn(byVj$&C07r% ztio69XR)xSJ^6AM`3<9p0nQ|p7NQ7}D(Q#heAS3^>-3b-rDf_FRA7-nESnads!(jh zOVHJ{{YRed+kGIqn>#fO20oW7=(l(??7>VkyvCdEzl*nxleK}d{cA0Gi+A^j_J~vl z#O51nVgT>YD4=&lG#ZtO(^8r$Dk|3eZLs8o`Z)9C^Ut2)M8FgN@O{YdLzCHen)T1% zc=$Y{JnY)EjKTuj)aUhl&AT?jPK3{PkB#>~2Sf$;P?(|ytBx%B!5jO)>7D z{f`>*2lSa!DmK`C&wAuJT{Z{XwL77=*ODoMj`xmijwtCDXOuZ_H=%8tq5VCDx6c?_ zaCv51i*ZYIFz%|m+xlq(i|BL~MUzQORq{htROWAZND6OR4_yailsjO_e*(sX`GDzl zl668fs(sN}Lv>X0LEWfr)oerA#@0>7HQ}-9u5=;@X%_@Or-_!I*8lUMq3QVHTrEH0 zher1xtx)!{yxr&{tH2SO;}c1nbBOy#o|yH{vF~}yy#2H*ZPg5sTL+eg0vFr85|Flf zD@o!PJp^1$)s64#ySIZ^$;m-426O2Oq#4<<$Y0LN|?R~RCC2HD5($8I({L9dy1kcdXzAv0K%-D zjuBdB=j+au2XDR%=F!W?ogv&6j#K83TigH~0MKh0=NQ(0ieI`}AnzV8?5Iv3K_L^jXbM zSg5lsXf;?uLRv~zQU);EKiud}-C%!>-iMNswE}fgpIcImG5B^}+~s-y1K~Vk&K_ ze!eygUx631W`q+qRLWB$n7N(pf{U}HS8UOk@7=T4KB(`*S9P(wNf)H5Twq}~Qc=w1 z4dsU8xAe6G!h_&^B8i`F;jRMYXOkFmHb&5BX~fwa$9XCA`4HTh67aD2vay_on9Vs2 zj1TrGHq%R~7j)$i1C2ag&Hcn$YJNVoO%6Yay_PLt(#@#buZyG{ff|5s?Uu0MmBq|Z zg%0s%4h9kNvZSn>ztS^{{zOcU1i$c=zGFa|tCSreKQ29LMB_kFA4g1K-Py`oQJ$~0 zG(Av3k-d8(GP+U1pQ${j*tKr30J$OM?)Gpm#efhzu6!aWo?Ll*ax+6?cZR-)rEKGY z($``n0?<8bO0^=N)wP`x!(VA;c-Rg|^bW8y^pwelFfJ33bsnsDb;z1^u)M^;ABzB1 zWA|U^%wfey$o4aJF5?>9XMSW#Ob4d~_bk3fi#|o_?Z}vFei|nt!sHbIf;B~xZ-#SU zk1SKZvm{Wz4;-;isn^mB9IgT4-!Yl@&`URxv9=R5wnAf6cTlcsm6>i;*NGuh^We@k zM;;J&IvUf6kflWuTaM{f^vqx;z`*o)bllxn*(BA%b*72J4^7#K8A=fcWMb3KqmC$t zt_U$!?vGbB6L5Np#jiN;Hkb7;nNvry*}L+=()GZ6eu%7C|mnFX5RP*vv343dh*)Gw+wA)2=Z`jD6(+EkKOAsnpXG(*n>S8n_~8|Hp+L!WCR?OKj#kFw>+}btjj^W z?U)?KDA9&q568uaLySW3Bno{^vXtFRhI7!VQ=|EoQOt&$ts5*8R_Rx8j0|cR{mr&` z8P^~S7w&cfBo>vxb`n?xD=>8kS+sHAm!c7h?zvx~eGUg}o%4CZvcFeo#t1f#3cu^% ztLjbz-5R+C_3G#@^P}5Hc*3}t(0y&bFv!-isd-~cs|}Q87-z(7#C`sJjft%&gp
                                    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 

                                    - + +

                                    +

                                    +

                                    -

                                    - -

                                    diff --git a/tests/fixtures/shift_enter.html b/tests/fixtures/shift_enter.html index 3b534e74..bc5cdb7e 100644 --- a/tests/fixtures/shift_enter.html +++ b/tests/fixtures/shift_enter.html @@ -1,16 +1,32 @@

                                    AAA
                                    BBB

                                    CCC

                                    +

                                     

                                      -
                                    1. DDD
                                      EEE
                                    2. -
                                    3. FFF
                                    4. +
                                    5. +

                                      DDD
                                      EEE

                                      +
                                    6. +
                                    7. +

                                      FFF

                                      +
                                    +

                                     

                                    - - + + - - + +
                                    GGG
                                    HHH
                                    III
                                    JJJ
                                    +

                                    GGG
                                    HHH

                                    +
                                    +

                                    III

                                    +

                                    JJJ

                                    +
                                    KKKLLL +

                                    KKK

                                    +
                                    +

                                    LLL

                                    +
                                    +

                                     

                                    diff --git a/tests/fixtures/simple.html b/tests/fixtures/simple.html index fe179fbb..1913ec62 100644 --- a/tests/fixtures/simple.html +++ b/tests/fixtures/simple.html @@ -1,18 +1,20 @@ -

                                    - Simple text -

                                    +

                                    Simple text

                                    +

                                     

                                      -
                                    1. one
                                    2. -
                                    3. two
                                    4. -
                                    5. three
                                    6. +
                                    7. one

                                    8. +
                                    9. two

                                    10. +
                                    11. three

                                    +

                                     

                                    - - - - - - - - + + + + + + + +
                                    Cell1Cell2
                                    Cell3Cell4

                                    Cell1

                                    Cell2

                                    Cell3

                                    Cell4

                                    +

                                     

                                    + diff --git a/tests/fixtures/simple_lists.html b/tests/fixtures/simple_lists.html index f3029284..fc05e9e5 100644 --- a/tests/fixtures/simple_lists.html +++ b/tests/fixtures/simple_lists.html @@ -1,6 +1,10 @@
                                      -
                                    1. One
                                    2. +
                                    3. +

                                      One

                                      +
                                      -
                                    • two
                                    • +
                                    • +

                                      two

                                      +
                                    diff --git a/tests/fixtures/simple_table.html b/tests/fixtures/simple_table.html index a14b830c..000f5247 100644 --- a/tests/fixtures/simple_table.html +++ b/tests/fixtures/simple_table.html @@ -1,14 +1,18 @@ - - +
                                    - Cell1
                                    - Cell3 +

                                    Cell1

                                    +

                                    Cell3

                                    Cell2
                                    - And I am writing in the table +
                                    +

                                    Cell2

                                    +

                                    And I am writing in the table

                                    Cell4 +

                                    Cell4

                                    +
                                    +

                                     

                                    diff --git a/tests/fixtures/styled_color.docx b/tests/fixtures/styled_color.docx index b7d22abfdaefb3146eff5955d0c9716ee39de39c..871765f4171243ee051d80e1c95bc84ed26d56f0 100644 GIT binary patch literal 12498 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

                                    -

                                    BBB

                                    +

                                    + AAA +

                                    +

                                    + BBB +

                                    +

                                     

                                    - - - + + +
                                    CCC
                                    +

                                    CCC

                                    +
                                    +

                                     

                                    DDD

                                    +

                                     

                                    diff --git a/tests/fixtures/table_col_row_span.html b/tests/fixtures/table_col_row_span.html index 3d70e06d..19a89398 100644 --- a/tests/fixtures/table_col_row_span.html +++ b/tests/fixtures/table_col_row_span.html @@ -1,46 +1,58 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + +
                                    AAA
                                    BBBCCC
                                    DDD
                                    - EEE - FFF
                                    - GGG -
                                    +

                                    AAA

                                    +
                                    +

                                    BBB

                                    +
                                    +

                                    CCC

                                    +
                                    +

                                    DDD

                                    +
                                    +

                                    EEE

                                    +
                                    +

                                    FFF

                                    +
                                    +

                                    GGG

                                    +
                                    +

                                     

                                    - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + +
                                    1234
                                    567
                                    89
                                    10111213

                                    1

                                    2

                                    3

                                    4

                                    5

                                    6

                                    7

                                    8

                                    9

                                    10

                                    11

                                    12

                                    13

                                    +

                                     

                                    diff --git a/tests/fixtures/table_with_multi_rowspan.html b/tests/fixtures/table_with_multi_rowspan.html index 8f7a8396..57b45fb9 100644 --- a/tests/fixtures/table_with_multi_rowspan.html +++ b/tests/fixtures/table_with_multi_rowspan.html @@ -1 +1,23 @@ -
                                    First sectionItem 1
                                    Item 2
                                    Second sectionItem 1
                                    Item 2
                                    Item 3
                                    Imte 4
                                    + + + + + + + + + + + + + + + + + + + + + +

                                    First section

                                    Item 1

                                    Item 2

                                    Second section

                                    Item 1

                                    Item 2

                                    Item 3

                                    Imte 4

                                    +

                                     

                                    diff --git a/tests/fixtures/tables_in_lists.html b/tests/fixtures/tables_in_lists.html index f2ea793f..f230e814 100644 --- a/tests/fixtures/tables_in_lists.html +++ b/tests/fixtures/tables_in_lists.html @@ -1,16 +1,30 @@
                                      -
                                    1. AAA
                                    2. -
                                    3. BBB +
                                    4. +

                                      AAA

                                      +
                                    5. +
                                    6. +

                                      BBB

                                      - - + + - - + +
                                      CCCDDD +

                                      CCC

                                      +
                                      +

                                      DDD

                                      +
                                      EEEFFF +

                                      EEE

                                      +
                                      +

                                      FFF

                                      +
                                      +

                                       

                                      +
                                    7. +
                                    8. +

                                      GGG

                                    9. -
                                    10. GGG
                                    diff --git a/tests/fixtures/track_changes_on.html b/tests/fixtures/track_changes_on.html index 935e97bd..2d6dabad 100644 --- a/tests/fixtures/track_changes_on.html +++ b/tests/fixtures/track_changes_on.html @@ -1 +1,3 @@ +

                                     

                                    +

                                     

                                    This was some content.

                                    From e76f918d1f62800b92314c41406a77c3aaebc77c Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Fri, 10 Mar 2017 18:11:54 +0200 Subject: [PATCH 4/6] Add effective properties for paragraph --- pydocx/export/html.py | 14 +- pydocx/models.py | 2 + .../packaging/style_definitions_part.py | 57 ++++--- pydocx/openxml/wordprocessing/paragraph.py | 142 +++++++++--------- .../wordprocessing/paragraph_properties.py | 2 +- pydocx/openxml/wordprocessing/run.py | 14 +- pydocx/openxml/wordprocessing/style.py | 2 + pydocx/openxml/wordprocessing/styles.py | 7 + pydocx/openxml/wordprocessing/table.py | 20 +-- pydocx/test/testcases.py | 2 + tests/fixtures/has_title.html | 2 +- 11 files changed, 142 insertions(+), 122 deletions(-) diff --git a/pydocx/export/html.py b/pydocx/export/html.py index e92c5fd9..f3e0f50d 100644 --- a/pydocx/export/html.py +++ b/pydocx/export/html.py @@ -188,6 +188,14 @@ def style(self): 'p': { 'margin-top': '0', 'margin-bottom': '0' + }, + 'ol': { + 'margin-top': '0', + 'margin-bottom': '0' + }, + 'ul': { + 'margin-top': '0', + 'margin-bottom': '0' } } @@ -373,7 +381,7 @@ def get_paragraph_property_spacing(self, paragraph): next_before = next_paragraph_spacing['before'] or 0 same_style = current_paragraph_spacing['parent_style'] == \ - next_paragraph_spacing['parent_style'] + next_paragraph_spacing['parent_style'] if same_style: if not current_paragraph_spacing['contextual_spacing']: @@ -393,7 +401,7 @@ def get_paragraph_property_spacing(self, paragraph): prev_after = previous_paragraph_spacing['after'] or 0 same_style = current_paragraph_spacing['parent_style'] == \ - previous_paragraph_spacing['parent_style'] + previous_paragraph_spacing['parent_style'] if same_style: if not current_paragraph_spacing['contextual_spacing']: @@ -490,7 +498,7 @@ def get_paragraph_property_indentation(self, paragraph): include_text_indent=True ) if 'text-indent' in listing_style and \ - listing_style['text-indent'] != '0.00em': + listing_style['text-indent'] != '0.00em': style['text-indent'] = listing_style['text-indent'] if indentation_right: diff --git a/pydocx/models.py b/pydocx/models.py index 3f435be5..cf472cc8 100644 --- a/pydocx/models.py +++ b/pydocx/models.py @@ -308,6 +308,8 @@ def load(cls, element, **load_kwargs): if field.name is not None: attr_name = field.name value = element.attrib.get(attr_name, field.default) + if callable(field.type): + value = field.type(value) kwargs[field_name] = value # Child tag fields may specify a handler/type, which is responsible for diff --git a/pydocx/openxml/packaging/style_definitions_part.py b/pydocx/openxml/packaging/style_definitions_part.py index 7f1cda25..347e0ec0 100644 --- a/pydocx/openxml/packaging/style_definitions_part.py +++ b/pydocx/openxml/packaging/style_definitions_part.py @@ -51,28 +51,39 @@ def get_style_chain_stack(self, style_type, style_id): styleB styleC ''' - visited_styles = set() - visited_styles.add(style_id) + visited_styles = set() styles = self.styles.get_styles_by_type(style_type) - base_style = styles.get(style_id) - - if base_style: - yield base_style - - # Build up the stack of styles to merge together - current_style = base_style - while current_style: - if not current_style.parent_style: - # The current style doesn't have a parent style - break - if current_style.parent_style in visited_styles: - # Loop detected - break - style = styles.get(current_style.parent_style) - if not style: - # Style doesn't exist - break - visited_styles.add(style.style_id) - yield style - current_style = style + styles_to_apply = {} + + def yield_styles_parent_stack(base_style): + if base_style: + yield base_style + + # Build up the stack of styles to merge together + current_style = base_style + while current_style: + if not current_style.parent_style: + # The current style doesn't have a parent style + break + if current_style.parent_style in visited_styles: + # Loop detected + break + style = styles.get(current_style.parent_style) + if not style: + # Style doesn't exist + break + visited_styles.add(style.style_id) + yield style + current_style = style + + if not style_id: + # In this case we need to check the default defined styles + styles_to_apply = self.styles.get_default_styles_by_type(style_type) + else: + styles_to_apply[style_id] = styles.get(style_id) + + for style_id, style in styles_to_apply.items(): + visited_styles.add(style_id) + for s in yield_styles_parent_stack(style): + yield s diff --git a/pydocx/openxml/wordprocessing/paragraph.py b/pydocx/openxml/wordprocessing/paragraph.py index 4a6ac95c..14dd30b9 100644 --- a/pydocx/openxml/wordprocessing/paragraph.py +++ b/pydocx/openxml/wordprocessing/paragraph.py @@ -7,7 +7,6 @@ from pydocx.models import XmlModel, XmlCollection, XmlChild from pydocx.openxml.wordprocessing.bookmark import Bookmark -from pydocx.openxml.wordprocessing.br import Break from pydocx.openxml.wordprocessing.deleted_run import DeletedRun from pydocx.openxml.wordprocessing.hyperlink import Hyperlink from pydocx.openxml.wordprocessing.inserted_run import InsertedRun @@ -18,7 +17,6 @@ from pydocx.openxml.wordprocessing.smart_tag_run import SmartTagRun from pydocx.openxml.wordprocessing.tab_char import TabChar from pydocx.openxml.wordprocessing.text import Text -from pydocx.openxml.wordprocessing.table_cell import TableCell from pydocx.util.memoize import memoized @@ -38,10 +36,6 @@ class Paragraph(XmlModel): Bookmark ) - def __init__(self, **kwargs): - super(Paragraph, self).__init__(**kwargs) - self._effective_properties = None - @property def is_empty(self): if not self.children: @@ -52,20 +46,73 @@ def is_empty(self): if len(self.children) == 1: first_child = self.children[0] if isinstance(first_child, Bookmark) and \ - first_child.name in ('_GoBack',): + first_child.name in ('_GoBack',): return True # We can have cases when only run properties are defined and no text elif not first_child.children: return True return False + def _get_properties_inherited_from_parent_table(self): + from pydocx.openxml.wordprocessing.table import Table + + inherited_properties = {} + + parent_table = self.get_first_ancestor(Table) + if parent_table: + style_stack = parent_table.get_style_chain_stack() + for style in reversed(list(style_stack)): + if style.paragraph_properties: + inherited_properties.update( + dict(style.paragraph_properties.fields), + ) + return inherited_properties + + def _get_inherited_properties_from_parent_style(self): + inherited_properties = {} + style_stack = self.get_style_chain_stack() + for style in reversed(list(style_stack)): + if style.paragraph_properties: + inherited_properties.update( + dict(style.paragraph_properties.fields), + ) + return inherited_properties + + @property + def inherited_properties(self): + properties = {} + + if self.default_doc_styles and \ + getattr(self.default_doc_styles.paragraph, 'properties'): + properties.update( + dict(self.default_doc_styles.paragraph.properties.fields), + ) + properties.update( + self._get_inherited_properties_from_parent_style(), + ) + # Tables can also define custom paragraph pr + properties.update( + self._get_properties_inherited_from_parent_table(), + ) + + # TODO When enable this make sure that you check the paragraph margins logic + # numbering_level = self.get_numbering_level() + # if numbering_level and numbering_level.paragraph_properties: + # properties.update( + # dict(numbering_level.paragraph_properties.fields), + # ) + + return ParagraphProperties(**properties) + @property + @memoized def effective_properties(self): - # TODO need to calculate effective properties like Run - if not self._effective_properties: - properties = self.properties - self._effective_properties = properties - return self._effective_properties + inherited_properties = self.inherited_properties + effective_properties = {} + effective_properties.update(dict(inherited_properties.fields)) + if self.properties: + effective_properties.update(dict(self.properties.fields)) + return ParagraphProperties(**effective_properties) @property def numbering_definition(self): @@ -76,12 +123,9 @@ def has_structured_document_parent(self): return self.has_ancestor(SdtBlock) def get_style_chain_stack(self): - if not self.properties: - return - - parent_style = self.properties.parent_style - if not parent_style: - return + # Even if parent style is not defined we still need to check the default style + # properties applied + parent_style = getattr(self.properties, 'parent_style', None) # TODO the getattr is necessary because of footnotes. From the context # of a footnote, a paragraph's container is the footnote part, which @@ -117,9 +161,9 @@ def get_numbering_definition(self): part = getattr(self.container, 'numbering_definitions_part', None) if not part: return - if not self.effective_properties: + if not self.properties: return - numbering_properties = self.effective_properties.numbering_properties + numbering_properties = self.properties.numbering_properties if not numbering_properties: return return part.numbering.get_numbering_definition( @@ -131,9 +175,9 @@ def get_numbering_level(self): numbering_definition = self.get_numbering_definition() if not numbering_definition: return - if not self.effective_properties: + if not self.properties: return - numbering_properties = self.effective_properties.numbering_properties + numbering_properties = self.properties.numbering_properties if not numbering_properties: return return numbering_definition.get_level( @@ -231,70 +275,26 @@ def get_spacing(self): """Get paragraph spacing according to: ECMA-376, 3rd Edition (June, 2011), Fundamentals and Markup Language Reference § 17.3.1.33. - - Note: Partial implementation for now. """ results = { 'line': None, 'after': None, 'before': None, - 'contextual_spacing': False, - 'parent_style': None + 'contextual_spacing': bool(self.effective_properties.contextual_spacing), + 'parent_style': self.effective_properties.parent_style } - # Get the paragraph_properties from the parent styles - style_paragraph_properties = None - for style in self.get_style_chain_stack(): - if style.paragraph_properties: - style_paragraph_properties = style.paragraph_properties - break + spacing_properties = self.effective_properties.spacing_properties - if style_paragraph_properties: - results['contextual_spacing'] = bool(style_paragraph_properties.contextual_spacing) - - default_paragraph_properties = None - if self.default_doc_styles and self.default_doc_styles.paragraph: - default_paragraph_properties = self.default_doc_styles.paragraph.properties - - # Spacing properties can be defined in multiple places and we need to get some - # kind of order of check - properties_order = [None, None, None] - if self.properties: - properties_order[0] = self.properties - if isinstance(self.parent, TableCell): - properties_order[1] = self.parent.parent_table.get_paragraph_properties() - if not self.properties or not self.properties.spacing_properties: - properties_order[2] = default_paragraph_properties - - spacing_properties = None - contextual_spacing = None - - for properties in properties_order: - if spacing_properties is None: - spacing_properties = getattr(properties, 'spacing_properties', None) - if contextual_spacing is None: - contextual_spacing = getattr(properties, 'contextual_spacing', None) - - if not spacing_properties: + if spacing_properties is None: return results - if contextual_spacing is not None: - results['contextual_spacing'] = bool(contextual_spacing) - - if self.properties: - results['parent_style'] = self.properties.parent_style - spacing_line = spacing_properties.to_int('line') spacing_after = spacing_properties.to_int('after') spacing_before = spacing_properties.to_int('before') - if default_paragraph_properties and spacing_line is None \ - and bool(spacing_properties.after_auto_spacing): - # get the spacing_line from the default definition - spacing_line = default_paragraph_properties.spacing_properties.to_int('line') - if spacing_line: - line = spacing_line / 240.0 + line = float("%.2f" % (spacing_line / 240.0)) # default line spacing is 1 so no need to add attribute if line != 1.0: results['line'] = line diff --git a/pydocx/openxml/wordprocessing/paragraph_properties.py b/pydocx/openxml/wordprocessing/paragraph_properties.py index ce7ce1ac..dd1e6712 100644 --- a/pydocx/openxml/wordprocessing/paragraph_properties.py +++ b/pydocx/openxml/wordprocessing/paragraph_properties.py @@ -69,4 +69,4 @@ def no_indentation(self): self.indentation_hanging, self.indentation_right, self.indentation_first_line, - )) \ No newline at end of file + )) diff --git a/pydocx/openxml/wordprocessing/run.py b/pydocx/openxml/wordprocessing/run.py index 2acdb944..3095ce54 100644 --- a/pydocx/openxml/wordprocessing/run.py +++ b/pydocx/openxml/wordprocessing/run.py @@ -46,12 +46,9 @@ class Run(XmlModel): ) def get_style_chain_stack(self): - if not self.properties: - return - - parent_style = self.properties.parent_style - if not parent_style: - return + # Even if parent style is not defined we still need to check the default style + # properties applied + parent_style = getattr(self.properties, 'parent_style', None) # TODO the getattr is necessary because of footnotes. From the context # of a footnote, a paragraph's container is the footnote part, which @@ -90,6 +87,11 @@ def _get_inherited_properties_from_parent_style(self): @property def inherited_properties(self): properties = {} + if self.default_doc_styles and getattr(self.default_doc_styles.run, 'properties'): + properties.update( + dict(self.default_doc_styles.run.properties.fields), + ) + properties.update( self._get_properties_inherited_from_parent_paragraph(), ) diff --git a/pydocx/openxml/wordprocessing/style.py b/pydocx/openxml/wordprocessing/style.py index faf73749..feefe0c6 100644 --- a/pydocx/openxml/wordprocessing/style.py +++ b/pydocx/openxml/wordprocessing/style.py @@ -5,6 +5,7 @@ unicode_literals, ) +from pydocx.types import OnOff from pydocx.models import XmlModel, XmlChild, XmlAttribute from pydocx.openxml.wordprocessing.run_properties import RunProperties from pydocx.openxml.wordprocessing.paragraph_properties import ParagraphProperties @@ -14,6 +15,7 @@ class Style(XmlModel): XML_TAG = 'style' style_type = XmlAttribute(name='type', default='paragraph') + style_default = XmlAttribute(type=OnOff, name='default', default='0') style_id = XmlAttribute(name='styleId', default='') name = XmlChild(attrname='val', default='') run_properties = XmlChild(type=RunProperties) diff --git a/pydocx/openxml/wordprocessing/styles.py b/pydocx/openxml/wordprocessing/styles.py index 8d1a1d16..c9acf7a7 100644 --- a/pydocx/openxml/wordprocessing/styles.py +++ b/pydocx/openxml/wordprocessing/styles.py @@ -22,9 +22,16 @@ def __init__(self, styles=None, *args, **kwargs): super(Styles, self).__init__(styles=styles, *args, **kwargs) styles_by_type = defaultdict(dict) + default_styles_by_type = defaultdict(dict) for style in self.styles: styles_by_type[style.style_type][style.style_id] = style + if bool(style.style_default): + default_styles_by_type[style.style_type][style.style_id] = style self.styles_by_type = dict(styles_by_type) + self.default_styles_by_type = dict(default_styles_by_type) def get_styles_by_type(self, style_type): return self.styles_by_type.get(style_type, {}) + + def get_default_styles_by_type(self, style_type): + return self.default_styles_by_type.get(style_type, {}) diff --git a/pydocx/openxml/wordprocessing/table.py b/pydocx/openxml/wordprocessing/table.py index 87d105f3..cea35b9b 100644 --- a/pydocx/openxml/wordprocessing/table.py +++ b/pydocx/openxml/wordprocessing/table.py @@ -50,26 +50,12 @@ def calculate_table_cell_spans(self): return dict(cell_to_rowspan_count) def get_style_chain_stack(self): - if not self.properties: - return - - parent_style = self.properties.parent_style - if not parent_style: - return + # Even if parent style is not defined we still need to check the default style + # properties applied + parent_style = getattr(self.properties, 'parent_style', None) part = getattr(self.container, 'style_definitions_part', None) if part: style_stack = part.get_style_chain_stack('table', parent_style) for result in style_stack: yield result - - def get_paragraph_properties(self): - """Get default style paragraph properties for table""" - - paragraph_properties = None - for style in self.get_style_chain_stack(): - if style.paragraph_properties: - paragraph_properties = style.paragraph_properties - break - - return paragraph_properties diff --git a/pydocx/test/testcases.py b/pydocx/test/testcases.py index f2c5158f..0024367a 100644 --- a/pydocx/test/testcases.py +++ b/pydocx/test/testcases.py @@ -50,7 +50,9 @@ '.pydocx-tab {display:inline-block;width:4em}' '.pydocx-underline {text-decoration:underline}' 'body {margin:0px auto;width:51.00em}' + 'ol {margin-bottom:0;margin-top:0}' 'p {margin-bottom:0;margin-top:0}' + 'ul {margin-bottom:0;margin-top:0}' '' ) diff --git a/tests/fixtures/has_title.html b/tests/fixtures/has_title.html index f6c25042..26a3bd34 100644 --- a/tests/fixtures/has_title.html +++ b/tests/fixtures/has_title.html @@ -1,3 +1,3 @@

                                    Title

                                    -

                                     

                                    +

                                     

                                    Text

                                    From 8c4ceeae1d907670479db8ab4a4d09f3b55b82bc Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Wed, 12 Apr 2017 08:19:09 +0300 Subject: [PATCH 5/6] Fixed issue with attribute 'children' --- pydocx/openxml/wordprocessing/paragraph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydocx/openxml/wordprocessing/paragraph.py b/pydocx/openxml/wordprocessing/paragraph.py index 14dd30b9..3b26a46e 100644 --- a/pydocx/openxml/wordprocessing/paragraph.py +++ b/pydocx/openxml/wordprocessing/paragraph.py @@ -49,7 +49,7 @@ def is_empty(self): first_child.name in ('_GoBack',): return True # We can have cases when only run properties are defined and no text - elif not first_child.children: + elif not getattr(first_child, "children", None): return True return False From a8480fdc1f4f182daed0f0094ca2186e6603b344 Mon Sep 17 00:00:00 2001 From: Chirica Gheorghe Date: Fri, 28 Apr 2017 08:17:10 +0300 Subject: [PATCH 6/6] Fixed AttributeError --- pydocx/openxml/wordprocessing/abstract_num.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydocx/openxml/wordprocessing/abstract_num.py b/pydocx/openxml/wordprocessing/abstract_num.py index 01930c4c..63116793 100644 --- a/pydocx/openxml/wordprocessing/abstract_num.py +++ b/pydocx/openxml/wordprocessing/abstract_num.py @@ -41,7 +41,7 @@ def get_indentation_between_levels(self): lvl1_ind = self.levels[1].paragraph_properties.to_int('indentation_left', default=0) ind_step = lvl1_ind - lvl0_ind - except IndexError: + except (IndexError, AttributeError): ind_step = DEFAULT_AUTOMATIC_TAB_STOP_INTERVAL # default one return ind_step