Skip to content

Commit 57e86cb

Browse files
author
Steve Canny
committed
img: add _IfdEntry.from_stream()
1 parent f017469 commit 57e86cb

File tree

2 files changed

+66
-6
lines changed

2 files changed

+66
-6
lines changed

docx/image/tiff.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,15 +171,34 @@ class _IfdEntry(object):
171171
Base class for IFD entry classes. Subclasses are differentiated by value
172172
type, e.g. ASCII, long int, etc.
173173
"""
174+
def __init__(self, tag_code, value):
175+
super(_IfdEntry, self).__init__()
176+
self._tag_code = tag_code
177+
self._value = value
178+
174179
@classmethod
175180
def from_stream(cls, stream_rdr, offset):
176181
"""
177-
Return an |_IfdEntry| subclass instance parsed from *stream_rdr* at
178-
*offset*. Note this method is common to all subclasses. Override the
179-
``_parse_value()`` method to provide distinctive behavior based on
180-
field type.
182+
Return an |_IfdEntry| subclass instance containing the tag and value
183+
of the tag parsed from *stream_rdr* at *offset*. Note this method is
184+
common to all subclasses. Override the ``_parse_value()`` method to
185+
provide distinctive behavior based on field type.
181186
"""
182-
raise NotImplementedError
187+
tag_code = stream_rdr.read_short(offset, 0)
188+
value_count = stream_rdr.read_long(offset, 4)
189+
value_offset = stream_rdr.read_long(offset, 8)
190+
value = cls._parse_value(
191+
stream_rdr, offset, value_count, value_offset
192+
)
193+
return cls(tag_code, value)
194+
195+
@classmethod
196+
def _parse_value(cls, stream_rdr, offset, value_count, value_offset):
197+
"""
198+
Return the value of this field parsed from *stream_rdr* at *offset*.
199+
Intended to be overridden by subclasses.
200+
"""
201+
return 'UNIMPLEMENTED FIELD TYPE'
183202

184203
@property
185204
def tag(self):

tests/image/test_tiff.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
)
1818

1919
from ..unitutil import (
20-
function_mock, class_mock, initializer_mock, instance_mock, method_mock
20+
function_mock, class_mock, initializer_mock, instance_mock, loose_mock,
21+
method_mock
2122
)
2223

2324

@@ -328,3 +329,43 @@ def _RationalIfdEntry_(self, request, ifd_entry_):
328329
@pytest.fixture
329330
def offset_(self, request):
330331
return instance_mock(request, int)
332+
333+
334+
class Describe_IfdEntry(object):
335+
336+
def it_can_construct_from_a_stream_and_offset(self, from_stream_fixture):
337+
(stream_rdr, offset, _parse_value_, value_count, value_offset,
338+
_IfdEntry__init_, tag_code, value_) = from_stream_fixture
339+
ifd_entry = _IfdEntry.from_stream(stream_rdr, offset)
340+
_parse_value_.assert_called_once_with(
341+
stream_rdr, offset, value_count, value_offset
342+
)
343+
_IfdEntry__init_.assert_called_once_with(tag_code, value_)
344+
assert isinstance(ifd_entry, _IfdEntry)
345+
346+
# fixtures -------------------------------------------------------
347+
348+
@pytest.fixture
349+
def from_stream_fixture(
350+
self, _parse_value_, _IfdEntry__init_, value_):
351+
bytes_ = b'\x00\x01\x66\x66\x00\x00\x00\x02\x00\x00\x00\x03'
352+
stream_rdr = StreamReader(BytesIO(bytes_), BIG_ENDIAN)
353+
offset, tag_code, value_count, value_offset = 0, 1, 2, 3
354+
return (
355+
stream_rdr, offset, _parse_value_, value_count, value_offset,
356+
_IfdEntry__init_, tag_code, value_
357+
)
358+
359+
@pytest.fixture
360+
def _IfdEntry__init_(self, request):
361+
return initializer_mock(request, _IfdEntry)
362+
363+
@pytest.fixture
364+
def _parse_value_(self, request, value_):
365+
return method_mock(
366+
request, _IfdEntry, '_parse_value', return_value=value_
367+
)
368+
369+
@pytest.fixture
370+
def value_(self, request):
371+
return loose_mock(request)

0 commit comments

Comments
 (0)