From 1c14ed25d75caf3228a92d8f7292bf0bf040653b Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Thu, 20 Aug 2015 20:34:34 +0100 Subject: Fix: cannot read file objects with name attribute --- NEWS | 4 ++++ mammoth/docx/__init__.py | 4 ++-- mammoth/docx/body_xml.py | 9 ++++++++- mammoth/docx/files.py | 12 +++++++++++- tests/docx/body_xml_tests.py | 1 + tests/mammoth_tests.py | 14 ++++++++++++++ 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 0337367..b251b2d 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +# 0.3.23 + +* Support file objects without a name attribute again (broken since 0.3.20). + # 0.3.22 * Generate warnings for not-understood style mappings and continue, rather than diff --git a/mammoth/docx/__init__.py b/mammoth/docx/__init__.py index 1ca8cb0..c8f4e6e 100644 --- a/mammoth/docx/__init__.py +++ b/mammoth/docx/__init__.py @@ -28,7 +28,7 @@ _namespaces = [ def read(fileobj): zip_file = zipfile.ZipFile(fileobj) - body_readers = _body_readers(getattr(fileobj, "name"), zip_file) + body_readers = _body_readers(getattr(fileobj, "name", None), zip_file) return _read_notes(zip_file, body_readers).bind(lambda notes: _read_document(zip_file, body_readers, notes)) @@ -79,7 +79,7 @@ def _body_readers(document_path, zip_file): relationships=relationships, styles=styles, docx_file=zip_file, - files=Files(os.path.dirname(document_path)), + files=Files(None if document_path is None else os.path.dirname(document_path)), ) return for_name diff --git a/mammoth/docx/body_xml.py b/mammoth/docx/body_xml.py index 9588bfe..b605354 100644 --- a/mammoth/docx/body_xml.py +++ b/mammoth/docx/body_xml.py @@ -4,6 +4,7 @@ from .. import documents from .. import results from .. import lists from .xmlparser import node_types +from .files import InvalidFileReferenceError def reader(numbering=None, @@ -222,7 +223,11 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f return _combine_results(map(lambda blip: _read_blip(blip, alt_text), blips)) def _read_blip(element, alt_text): - image_path, open_image = _read_blip_image(element) + try: + image_path, open_image = _read_blip_image(element) + except InvalidFileReferenceError as error: + return _empty_result_with_messages([results.warning(str(error))]) + content_type = content_types.find_content_type(image_path) image = documents.image(alt_text=alt_text, content_type=content_type, open=open_image) @@ -261,6 +266,8 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f def open_image(): return files.open(image_path) + files.verify(image_path) + return image_path, open_image def note_reference_reader(note_type): diff --git a/mammoth/docx/files.py b/mammoth/docx/files.py index d919de9..7fe3a2c 100644 --- a/mammoth/docx/files.py +++ b/mammoth/docx/files.py @@ -14,12 +14,22 @@ class Files(object): def __init__(self, base): self._base = base + def verify(self, uri): + with self.open(uri): + pass + def open(self, uri): if _is_absolute(uri): return contextlib.closing(urlopen(uri)) - else: + elif self._base is not None: return open(os.path.join(self._base, uri), "rb") + else: + raise InvalidFileReferenceError("could not find external image '{0}', fileobj has no name".format(uri)) def _is_absolute(url): return urlparse(url).scheme != "" + + +class InvalidFileReferenceError(ValueError): + pass diff --git a/tests/docx/body_xml_tests.py b/tests/docx/body_xml_tests.py index 6122706..da662d8 100644 --- a/tests/docx/body_xml_tests.py +++ b/tests/docx/body_xml_tests.py @@ -406,6 +406,7 @@ class ReadXmlElementTests(object): }) files = context.mock() + funk.allows(files).verify("file:///media/hat.png") funk.allows(files).open("file:///media/hat.png").returns(io.BytesIO(image_bytes)) content_types = context.mock() diff --git a/tests/mammoth_tests.py b/tests/mammoth_tests.py index ddcb9a6..89336b3 100644 --- a/tests/mammoth_tests.py +++ b/tests/mammoth_tests.py @@ -2,6 +2,9 @@ from __future__ import unicode_literals +import io +import shutil + from nose.tools import istest, assert_equal from .testing import test_path @@ -67,6 +70,17 @@ def images_stored_outside_of_document_are_included_in_output(): result = mammoth.convert_to_html(fileobj=fileobj) assert_equal("""

""", result.value) assert_equal([], result.messages) + + +@istest +def warn_if_images_stored_outside_of_document_are_specified_when_passing_fileobj_without_name(): + fileobj = io.BytesIO() + with open(test_path("external-picture.docx"), "rb") as source_fileobj: + shutil.copyfileobj(source_fileobj, fileobj) + + result = mammoth.convert_to_html(fileobj=fileobj) + assert_equal("", result.value) + assert_equal([results.warning("could not find external image 'tiny-picture.png', fileobj has no name")], result.messages) @istest -- cgit v1.2.3