Skip to content

Commit a38ffd3

Browse files
author
Steve Canny
committed
img: add Image._from_stream()
1 parent 3954b5b commit a38ffd3

File tree

3 files changed

+59
-9
lines changed

3 files changed

+59
-9
lines changed

docx/image/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@
2222
from docx.shared import lazyproperty
2323

2424

25+
def image_cls_that_can_parse(stream):
26+
"""
27+
Return the |Image| subclass that can parse the headers of the image file
28+
contained in *stream*.
29+
"""
30+
raise NotImplementedError
31+
32+
2533
class Image_OLD(object):
2634
"""
2735
A helper object that knows how to analyze an image file.

docx/image/image.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import os
1313

1414
from docx.compat import BytesIO, is_string
15+
from docx.image import image_cls_that_can_parse
1516

1617

1718
class Image(object):
@@ -44,3 +45,5 @@ def _from_stream(cls, stream, blob, filename=None):
4445
Return an instance of the |Image| subclass corresponding to the
4546
format of the image in *stream*.
4647
"""
48+
ImageSubclass = image_cls_that_can_parse(stream)
49+
return ImageSubclass(stream, blob, filename)

tests/image/test_image.py

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
from docx.image.image import Image
1414
from docx.opc.constants import CONTENT_TYPE as CT
1515

16-
from ..unitutil import class_mock, instance_mock, method_mock, test_file
16+
from ..unitutil import (
17+
function_mock, class_mock, instance_mock, loose_mock, method_mock,
18+
test_file
19+
)
1720

1821

1922
class DescribeImage(object):
@@ -26,20 +29,44 @@ def it_can_construct_from_an_image_path(self, from_path_fixture):
2629
_from_stream_.assert_called_once_with(stream_, blob, filename)
2730
assert image is image_
2831

29-
def it_can_construct_from_an_image_stream(self, from_stream_fixture):
30-
image_stream, _from_stream_, blob, image_ = from_stream_fixture
32+
def it_can_construct_from_an_image_file_like(self, from_filelike_fixture):
33+
image_stream, _from_stream_, blob, image_ = from_filelike_fixture
3134
image = Image.from_file(image_stream)
3235
_from_stream_.assert_called_once_with(image_stream, blob, None)
3336
assert image is image_
3437

38+
def it_can_construct_from_an_image_stream(self, from_stream_fixture):
39+
(stream_, blob_, filename_, image_, image_cls_that_can_parse_,
40+
image_cls_) = from_stream_fixture
41+
image = Image._from_stream(stream_, blob_, filename_)
42+
image_cls_that_can_parse_.assert_called_once_with(stream_)
43+
image_cls_.assert_called_once_with(stream_, blob_, filename_)
44+
assert image is image_
45+
3546
# fixtures -------------------------------------------------------
3647

48+
@pytest.fixture
49+
def blob_(self, request):
50+
return instance_mock(request, str)
51+
3752
@pytest.fixture
3853
def BytesIO_(self, request, stream_):
3954
return class_mock(
4055
request, 'docx.image.image.BytesIO', return_value=stream_
4156
)
4257

58+
@pytest.fixture
59+
def filename_(self, request):
60+
return instance_mock(request, str)
61+
62+
@pytest.fixture
63+
def from_filelike_fixture(self, _from_stream_, image_):
64+
image_path = test_file('python-icon.png')
65+
with open(image_path, 'rb') as f:
66+
blob = f.read()
67+
image_stream = BytesIO(blob)
68+
return image_stream, _from_stream_, blob, image_
69+
4370
@pytest.fixture
4471
def from_path_fixture(self, _from_stream_, BytesIO_, stream_, image_):
4572
filename = 'python-icon.png'
@@ -49,12 +76,13 @@ def from_path_fixture(self, _from_stream_, BytesIO_, stream_, image_):
4976
return image_path, _from_stream_, stream_, blob, filename, image_
5077

5178
@pytest.fixture
52-
def from_stream_fixture(self, _from_stream_, image_):
53-
image_path = test_file('python-icon.png')
54-
with open(image_path, 'rb') as f:
55-
blob = f.read()
56-
image_stream = BytesIO(blob)
57-
return image_stream, _from_stream_, blob, image_
79+
def from_stream_fixture(
80+
self, stream_, blob_, filename_, image_,
81+
image_cls_that_can_parse_, image_cls_):
82+
return (
83+
stream_, blob_, filename_, image_, image_cls_that_can_parse_,
84+
image_cls_
85+
)
5886

5987
@pytest.fixture
6088
def _from_stream_(self, request, image_):
@@ -66,6 +94,17 @@ def _from_stream_(self, request, image_):
6694
def image_(self, request):
6795
return instance_mock(request, Image)
6896

97+
@pytest.fixture
98+
def image_cls_(self, request, image_):
99+
return loose_mock(request, return_value=image_)
100+
101+
@pytest.fixture
102+
def image_cls_that_can_parse_(self, request, image_cls_):
103+
return function_mock(
104+
request, 'docx.image.image.image_cls_that_can_parse',
105+
return_value=image_cls_
106+
)
107+
69108
@pytest.fixture
70109
def stream_(self, request):
71110
return instance_mock(request, BytesIO)

0 commit comments

Comments
 (0)