X Tutup
Skip to content

Commit aa84f3b

Browse files
author
Steve Canny
committed
pkg: add Package._gather_image_parts()
1 parent 13e928f commit aa84f3b

File tree

9 files changed

+89
-1
lines changed

9 files changed

+89
-1
lines changed

docx/opc/package.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,28 @@ def after_unmarshal(self):
3333
# subclass
3434
pass
3535

36+
def iter_rels(self):
37+
"""
38+
Generate exactly one reference to each relationship in the package by
39+
performing a depth-first traversal of the rels graph.
40+
"""
41+
def walk_rels(source, visited=None):
42+
visited = [] if visited is None else visited
43+
for rel in source.rels.values():
44+
yield rel
45+
if rel.is_external:
46+
continue
47+
part = rel.target_part
48+
if part in visited:
49+
continue
50+
visited.append(part)
51+
new_source = part
52+
for rel in walk_rels(new_source, visited):
53+
yield rel
54+
55+
for rel in walk_rels(self):
56+
yield rel
57+
3658
def iter_parts(self):
3759
"""
3860
Generate exactly one reference to each of the parts in the package by

docx/package.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,61 @@
66

77
from __future__ import absolute_import, print_function, unicode_literals
88

9+
from docx.opc.constants import RELATIONSHIP_TYPE as RT
910
from docx.opc.package import OpcPackage
11+
from docx.shared import lazyproperty
1012

1113

1214
class Package(OpcPackage):
1315
"""
1416
Customizations specific to a WordprocessingML package.
1517
"""
16-
@property
18+
def after_unmarshal(self):
19+
"""
20+
Called by loading code after all parts and relationships have been
21+
loaded, to afford the opportunity for any required post-processing.
22+
"""
23+
self._gather_image_parts()
24+
25+
@lazyproperty
1726
def image_parts(self):
1827
"""
1928
Collection of all image parts in this package.
2029
"""
30+
return ImageParts()
31+
32+
def _gather_image_parts(self):
33+
"""
34+
Load the image part collection with all the image parts in package.
35+
"""
36+
for rel in self.iter_rels():
37+
if rel.is_external:
38+
continue
39+
if rel.reltype != RT.IMAGE:
40+
continue
41+
if rel.target_part in self.image_parts:
42+
continue
43+
self.image_parts.append(rel.target_part)
2144

2245

2346
class ImageParts(object):
2447
"""
2548
Collection of |ImagePart| instances containing all the image parts in the
2649
package.
2750
"""
51+
def __init__(self):
52+
super(ImageParts, self).__init__()
53+
self._image_parts = []
54+
55+
def __contains__(self, item):
56+
return self._image_parts.__contains__(item)
57+
58+
def __len__(self):
59+
return self._image_parts.__len__()
60+
61+
def append(self, item):
62+
self._image_parts.append(item)
63+
2864
def get_or_add_image_part(self, image_descriptor):
2965
"""
3066
Return an |ImagePart| instance containing the image identified by
130 KB
Binary file not shown.

tests/test_files/monty-truth.png

62.8 KB
Loading

tests/test_files/python-icon.jpeg

3.2 KB
Loading
5.97 KB
Loading

tests/test_files/python.bmp

44.2 KB
Binary file not shown.

tests/test_package.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Test suite for docx.package module
5+
"""
6+
7+
from __future__ import absolute_import, print_function, unicode_literals
8+
9+
from docx.package import Package
10+
11+
from .unitutil import docx_path
12+
13+
14+
class DescribePackage(object):
15+
16+
def it_gathers_package_image_parts_after_unmarshalling(self):
17+
package = Package.open(docx_path('having-images'))
18+
assert len(package.image_parts) == 3

tests/unitutil.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ def absjoin(*paths):
2828
return os.path.abspath(os.path.join(*paths))
2929

3030

31+
def docx_path(name):
32+
"""
33+
Return the absolute path to test .docx file with root name *name*.
34+
"""
35+
return absjoin(_thisdir, 'test_files', '%s.docx' % name)
36+
37+
38+
# ===========================================================================
39+
# pytest mocking helpers
40+
# ===========================================================================
41+
42+
3143
def class_mock(request, q_class_name, autospec=True, **kwargs):
3244
"""
3345
Return a mock patching the class with qualified name *q_class_name*.

0 commit comments

Comments
 (0)
X Tutup