Skip to content

Commit 7f32a65

Browse files
committed
hdr: add BaseStoryPart.new_pic_inline()
This is essentially migrated "up" from DocumentPart, which now subclasses BaseStoryPart.
1 parent db72fe7 commit 7f32a65

File tree

5 files changed

+65
-45
lines changed

5 files changed

+65
-45
lines changed

docx/parts/document.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@
66

77
from docx.document import Document
88
from docx.opc.constants import RELATIONSHIP_TYPE as RT
9-
from docx.opc.part import XmlPart
10-
from docx.oxml.shape import CT_Inline
119
from docx.parts.hdrftr import FooterPart, HeaderPart
1210
from docx.parts.numbering import NumberingPart
1311
from docx.parts.settings import SettingsPart
12+
from docx.parts.story import BaseStoryPart
1413
from docx.parts.styles import StylesPart
1514
from docx.shape import InlineShapes
1615
from docx.shared import lazyproperty
1716

1817

19-
class DocumentPart(XmlPart):
18+
class DocumentPart(BaseStoryPart):
2019
"""Main document part of a WordprocessingML (WML) package, aka a .docx file.
2120
2221
Acts as broker to other parts such as image, core properties, and style parts. It
@@ -104,17 +103,6 @@ def inline_shapes(self):
104103
"""
105104
return InlineShapes(self._element.body, self)
106105

107-
def new_pic_inline(self, image_descriptor, width, height):
108-
"""Return a newly-created `w:inline` element.
109-
110-
The element contains the image specified by *image_descriptor* and is scaled
111-
based on the values of *width* and *height*.
112-
"""
113-
rId, image = self.get_or_add_image(image_descriptor)
114-
cx, cy = image.scaled_dimensions(width, height)
115-
shape_id, filename = self.next_id, image.filename
116-
return CT_Inline.new_pic_inline(shape_id, rId, filename, cx, cy)
117-
118106
@property
119107
def next_id(self):
120108
"""Next available positive integer id value in this document.

docx/parts/story.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from __future__ import absolute_import, division, print_function, unicode_literals
66

77
from docx.opc.part import XmlPart
8+
from docx.oxml.shape import CT_Inline
89
from docx.shared import lazyproperty
910

1011

@@ -16,6 +17,16 @@ class BaseStoryPart(XmlPart):
1617
`.add_paragraph()`, `.add_table()` etc.
1718
"""
1819

20+
def get_or_add_image(self, image_descriptor):
21+
"""Return (rId, image) pair for image identified by *image_descriptor*.
22+
23+
*rId* is the str key (often like "rId7") for the relationship between this story
24+
part and the image part, reused if already present, newly created if not.
25+
*image* is an |Image| instance providing access to the properties of the image,
26+
such as dimensions and image type.
27+
"""
28+
raise NotImplementedError
29+
1930
def get_style(self, style_id, style_type):
2031
"""Return the style in this document matching *style_id*.
2132
@@ -33,6 +44,27 @@ def get_style_id(self, style_or_name, style_type):
3344
"""
3445
return self._document_part.get_style_id(style_or_name, style_type)
3546

47+
def new_pic_inline(self, image_descriptor, width, height):
48+
"""Return a newly-created `w:inline` element.
49+
50+
The element contains the image specified by *image_descriptor* and is scaled
51+
based on the values of *width* and *height*.
52+
"""
53+
rId, image = self.get_or_add_image(image_descriptor)
54+
cx, cy = image.scaled_dimensions(width, height)
55+
shape_id, filename = self.next_id, image.filename
56+
return CT_Inline.new_pic_inline(shape_id, rId, filename, cx, cy)
57+
58+
@property
59+
def next_id(self):
60+
"""Next available positive integer id value in this story XML document.
61+
62+
The value is determined by incrementing the maximum existing id value. Gaps in
63+
the existing id sequence are not filled. The id attribute value is unique in the
64+
document, without regard to the element type it appears on.
65+
"""
66+
raise NotImplementedError
67+
3668
@lazyproperty
3769
def _document_part(self):
3870
"""|DocumentPart| object for this package."""

tests/parts/test_document.py

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
from ..oxml.parts.unitdata.document import a_body, a_document
2525
from ..oxml.unitdata.text import a_p
26-
from ..unitutil.file import snippet_text
2726
from ..unitutil.mock import class_mock, instance_mock, method_mock, property_mock
2827

2928

@@ -154,21 +153,6 @@ def it_knows_the_next_available_xml_id(self, next_id_fixture):
154153
document, expected_id = next_id_fixture
155154
assert document.next_id == expected_id
156155

157-
def it_can_create_a_new_pic_inline(self, image_, get_or_add_image_, next_id_prop_):
158-
path, width, height, rId = 'foo/bar.png', 111, 222, 'rId42'
159-
expected_xml = snippet_text('inline')
160-
get_or_add_image_.return_value = rId, image_
161-
image_.scaled_dimensions.return_value = 444, 888
162-
image_.filename = 'bar.png'
163-
next_id_prop_.return_value = 24
164-
document_part = DocumentPart(None, None, None, None)
165-
166-
inline = document_part.new_pic_inline(path, width, height)
167-
168-
get_or_add_image_.assert_called_once_with(document_part, path)
169-
image_.scaled_dimensions.assert_called_once_with(width, height)
170-
assert inline.xml == expected_xml
171-
172156
def it_can_get_a_style_by_id(self, styles_prop_, styles_, style_):
173157
styles_prop_.return_value = styles_
174158
styles_.get_by_id.return_value = style_
@@ -315,10 +299,6 @@ def FooterPart_(self, request):
315299
def footer_part_(self, request):
316300
return instance_mock(request, FooterPart)
317301

318-
@pytest.fixture
319-
def get_or_add_image_(self, request):
320-
return method_mock(request, DocumentPart, 'get_or_add_image')
321-
322302
@pytest.fixture
323303
def HeaderPart_(self, request):
324304
return class_mock(request, 'docx.parts.document.HeaderPart')
@@ -339,10 +319,6 @@ def image_part_(self, request):
339319
def InlineShapes_(self, request):
340320
return class_mock(request, 'docx.parts.document.InlineShapes')
341321

342-
@pytest.fixture
343-
def next_id_prop_(self, request):
344-
return property_mock(request, DocumentPart, 'next_id')
345-
346322
@pytest.fixture
347323
def NumberingPart_(self, request):
348324
return class_mock(request, 'docx.parts.document.NumberingPart')

tests/parts/test_story.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
import pytest
88

99
from docx.enum.style import WD_STYLE_TYPE
10+
from docx.image.image import Image
1011
from docx.package import Package
1112
from docx.parts.document import DocumentPart
1213
from docx.parts.story import BaseStoryPart
1314
from docx.styles.style import BaseStyle
1415

15-
from ..unitutil.mock import instance_mock, property_mock
16+
from ..unitutil.file import snippet_text
17+
from ..unitutil.mock import instance_mock, method_mock, property_mock
1618

1719

1820
class DescribeBaseStoryPart(object):
@@ -44,6 +46,20 @@ def it_can_get_a_style_id_by_style_or_name_and_type(
4446
document_part_.get_style_id.assert_called_once_with(style_, style_type)
4547
assert style_id == "BodyText"
4648

49+
def it_can_create_a_new_pic_inline(self, get_or_add_image_, image_, next_id_prop_):
50+
get_or_add_image_.return_value = "rId42", image_
51+
image_.scaled_dimensions.return_value = 444, 888
52+
image_.filename = "bar.png"
53+
next_id_prop_.return_value = 24
54+
expected_xml = snippet_text("inline")
55+
story_part = BaseStoryPart(None, None, None, None)
56+
57+
inline = story_part.new_pic_inline("foo/bar.png", width=100, height=200)
58+
59+
get_or_add_image_.assert_called_once_with(story_part, "foo/bar.png")
60+
image_.scaled_dimensions.assert_called_once_with(100, 200)
61+
assert inline.xml == expected_xml
62+
4763
def it_knows_the_main_document_part_to_help(self, package_, document_part_):
4864
package_.main_document_part = document_part_
4965
story_part = BaseStoryPart(None, None, None, package_)
@@ -62,6 +78,18 @@ def document_part_(self, request):
6278
def _document_part_prop_(self, request):
6379
return property_mock(request, BaseStoryPart, "_document_part")
6480

81+
@pytest.fixture
82+
def get_or_add_image_(self, request):
83+
return method_mock(request, BaseStoryPart, "get_or_add_image")
84+
85+
@pytest.fixture
86+
def image_(self, request):
87+
return instance_mock(request, Image)
88+
89+
@pytest.fixture
90+
def next_id_prop_(self, request):
91+
return property_mock(request, BaseStoryPart, "next_id")
92+
6593
@pytest.fixture
6694
def package_(self, request):
6795
return instance_mock(request, Package)

tests/text/test_run.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
# encoding: utf-8
22

3-
"""
4-
Test suite for the docx.text.run module
5-
"""
3+
"""Test suite for the docx.text.run module"""
64

7-
from __future__ import (
8-
absolute_import, division, print_function, unicode_literals
9-
)
5+
from __future__ import absolute_import, division, print_function, unicode_literals
106

117
from docx.enum.style import WD_STYLE_TYPE
128
from docx.enum.text import WD_BREAK, WD_UNDERLINE

0 commit comments

Comments
 (0)