Skip to content

Commit bb8e602

Browse files
author
Steve Canny
committed
img: add ImagePart part class selector
Added part_class_selector function that selects ImagePart class for parts with reltype RT.IMAGE.
1 parent 64d6a55 commit bb8e602

File tree

5 files changed

+77
-8
lines changed

5 files changed

+77
-8
lines changed

docx/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,20 @@
77

88
# register custom Part classes with opc package reader
99

10-
from docx.opc.constants import CONTENT_TYPE as CT
10+
from docx.opc.constants import CONTENT_TYPE as CT, RELATIONSHIP_TYPE as RT
1111
from docx.opc.package import PartFactory
1212

1313
from docx.parts.document import DocumentPart
14+
from docx.parts.image import ImagePart
1415

16+
17+
def part_class_selector(content_type, reltype):
18+
if reltype == RT.IMAGE:
19+
return ImagePart
20+
return None
21+
22+
23+
PartFactory.part_class_selector = part_class_selector
1524
PartFactory.part_type_for[CT.WML_DOCUMENT_MAIN] = DocumentPart
1625

17-
del CT, DocumentPart, PartFactory
26+
del CT, DocumentPart, PartFactory, part_class_selector

docx/opc/package.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ class PartFactory(object):
334334
def __new__(cls, partname, content_type, reltype, blob, package):
335335
PartClass = None
336336
if cls.part_class_selector is not None:
337-
PartClass = cls.part_class_selector(content_type, reltype)
337+
part_class_selector = cls.part_class_selector.__func__
338+
PartClass = part_class_selector(content_type, reltype)
338339
if PartClass is None:
339340
PartClass = cls._part_cls_for(content_type)
340341
return PartClass.load(partname, content_type, blob, package)

tests/opc/test_package.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,9 @@ def it_constructs_part_from_selector_if_defined(
390390
PartFactory.part_class_selector = cls_selector_fn_
391391
part = PartFactory(partname, content_type, reltype, blob, package)
392392
# verify -----------------------
393-
cls_selector_fn_.assert_called_once_with(content_type, reltype)
393+
cls_selector_fn_.__func__.assert_called_once_with(
394+
content_type, reltype
395+
)
394396
CustomPartClass_.load.assert_called_once_with(
395397
partname, content_type, blob, package
396398
)
@@ -444,7 +446,11 @@ def reset_part_class_selector():
444446

445447
@pytest.fixture
446448
def cls_selector_fn_(self, request, CustomPartClass_):
447-
return loose_mock(request, return_value=CustomPartClass_)
449+
cls_selector_fn_ = loose_mock(request)
450+
cls_selector_fn_.__func__ = loose_mock(
451+
request, name='__func__', return_value=CustomPartClass_
452+
)
453+
return cls_selector_fn_
448454

449455
@pytest.fixture
450456
def content_type_(self, request):

tests/parts/test_document.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def oxml_fromstring_(self, request):
219219
return function_mock(request, 'docx.parts.document.oxml_fromstring')
220220

221221
@pytest.fixture
222-
def package_(self, request, image_parts_):
222+
def package_(self, request):
223223
return instance_mock(request, Package)
224224

225225
@pytest.fixture

tests/parts/test_image.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@
66

77
from __future__ import absolute_import, print_function, unicode_literals
88

9-
from docx.parts.image import Image
9+
import pytest
1010

11-
from ..unitutil import test_file
11+
from docx.opc.constants import CONTENT_TYPE as CT, RELATIONSHIP_TYPE as RT
12+
from docx.opc.package import PartFactory
13+
from docx.opc.packuri import PackURI
14+
from docx.package import Package
15+
from docx.parts.image import Image, ImagePart
16+
17+
from ..unitutil import instance_mock, method_mock, test_file
1218

1319

1420
class DescribeImage(object):
@@ -27,3 +33,50 @@ def it_can_construct_from_an_image_stream(self):
2733
assert isinstance(image, Image)
2834
assert image.sha1 == '79769f1e202add2e963158b532e36c2c0f76a70c'
2935
assert image.filename is None
36+
37+
38+
class DescribeImagePart(object):
39+
40+
def it_is_used_by_PartFactory_to_construct_image_part(self, load_fixture):
41+
# fixture ----------------------
42+
image_part_load_, partname_, blob_, package_, image_part_ = (
43+
load_fixture
44+
)
45+
content_type = CT.JPEG
46+
reltype = RT.IMAGE
47+
# exercise ---------------------
48+
part = PartFactory(partname_, content_type, reltype, blob_, package_)
49+
# verify -----------------------
50+
image_part_load_.assert_called_once_with(
51+
partname_, content_type, blob_, package_
52+
)
53+
assert part is image_part_
54+
55+
# fixtures -------------------------------------------------------
56+
57+
@pytest.fixture
58+
def blob_(self, request):
59+
return instance_mock(request, str)
60+
61+
@pytest.fixture
62+
def image_part_(self, request):
63+
return instance_mock(request, ImagePart)
64+
65+
@pytest.fixture
66+
def image_part_load_(self, request, image_part_):
67+
return method_mock(
68+
request, ImagePart, 'load', return_value=image_part_
69+
)
70+
71+
@pytest.fixture
72+
def load_fixture(
73+
self, image_part_load_, partname_, blob_, package_, image_part_):
74+
return image_part_load_, partname_, blob_, package_, image_part_
75+
76+
@pytest.fixture
77+
def package_(self, request):
78+
return instance_mock(request, Package)
79+
80+
@pytest.fixture
81+
def partname_(self, request):
82+
return instance_mock(request, PackURI)

0 commit comments

Comments
 (0)