Skip to content

Commit 492b5c0

Browse files
author
Steve Canny
committed
add PackageReader.from_file()
1 parent be5d26c commit 492b5c0

3 files changed

Lines changed: 118 additions & 0 deletions

File tree

opc/phys_pkg.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,16 @@ class ZipPkgReader(object):
2424
"""
2525
Implements |PhysPkgReader| interface for a zip file OPC package.
2626
"""
27+
def __init__(self, pkg_file):
28+
super(ZipPkgReader, self).__init__()
29+
30+
def close(self):
31+
"""
32+
Close the zip archive, releasing any resources it is using.
33+
"""
34+
35+
@property
36+
def content_types_xml(self):
37+
"""
38+
Return the `[Content_Types].xml` blob from the zip package.
39+
"""

opc/pkgreader.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,55 @@
1212
(OPC) package.
1313
"""
1414

15+
from opc.packuri import PACKAGE_URI
16+
from opc.phys_pkg import PhysPkgReader
17+
1518

1619
class PackageReader(object):
1720
"""
1821
Provides access to the contents of a zip-format OPC package via its
1922
:attr:`serialized_parts` and :attr:`pkg_srels` attributes.
2023
"""
24+
def __init__(self, content_types, pkg_srels, sparts):
25+
super(PackageReader, self).__init__()
26+
2127
@staticmethod
2228
def from_file(pkg_file):
2329
"""
2430
Return a |PackageReader| instance loaded with contents of *pkg_file*.
2531
"""
32+
phys_reader = PhysPkgReader(pkg_file)
33+
content_types = _ContentTypeMap.from_xml(phys_reader.content_types_xml)
34+
pkg_srels = PackageReader._srels_for(phys_reader, PACKAGE_URI)
35+
sparts = PackageReader._load_serialized_parts(phys_reader, pkg_srels,
36+
content_types)
37+
phys_reader.close()
38+
return PackageReader(content_types, pkg_srels, sparts)
39+
40+
@staticmethod
41+
def _load_serialized_parts(phys_reader, pkg_srels, content_types):
42+
"""
43+
Return a list of |_SerializedPart| instances corresponding to the
44+
parts in *phys_reader* accessible by walking the relationship graph
45+
starting with *pkg_srels*.
46+
"""
47+
48+
@staticmethod
49+
def _srels_for(phys_reader, source_uri):
50+
"""
51+
Return |_SerializedRelationshipCollection| instance populated with
52+
relationships for source identified by *source_uri*.
53+
"""
54+
55+
56+
class _ContentTypeMap(object):
57+
"""
58+
Value type providing dictionary semantics for looking up content type by
59+
part name, e.g. ``content_type = cti['/ppt/presentation.xml']``.
60+
"""
61+
@staticmethod
62+
def from_xml(content_types_xml):
63+
"""
64+
Return a new |_ContentTypeMap| instance populated with the contents
65+
of *content_types_xml*.
66+
"""

tests/test_pkgreader.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# test_pkgreader.py
4+
#
5+
# Copyright (C) 2013 Steve Canny scanny@cisco.com
6+
#
7+
# This module is part of python-pptx and is released under the MIT License:
8+
# http://www.opensource.org/licenses/mit-license.php
9+
10+
"""Test suite for opc.pkgreader module."""
11+
12+
import pytest
13+
14+
from mock import Mock, patch
15+
16+
from opc.phys_pkg import ZipPkgReader
17+
from opc.pkgreader import _ContentTypeMap, PackageReader
18+
19+
from .unitutil import initializer_mock, method_mock
20+
21+
22+
class DescribePackageReader(object):
23+
24+
@pytest.fixture
25+
def from_xml(self, request):
26+
return method_mock(_ContentTypeMap, 'from_xml', request)
27+
28+
@pytest.fixture
29+
def init(self, request):
30+
return initializer_mock(PackageReader, request)
31+
32+
@pytest.fixture
33+
def _load_serialized_parts(self, request):
34+
return method_mock(PackageReader, '_load_serialized_parts', request)
35+
36+
@pytest.fixture
37+
def PhysPkgReader_(self, request):
38+
_patch = patch('opc.pkgreader.PhysPkgReader', spec_set=ZipPkgReader)
39+
request.addfinalizer(_patch.stop)
40+
return _patch.start()
41+
42+
@pytest.fixture
43+
def _srels_for(self, request):
44+
return method_mock(PackageReader, '_srels_for', request)
45+
46+
def it_can_construct_from_pkg_file(self, init, PhysPkgReader_, from_xml,
47+
_srels_for, _load_serialized_parts):
48+
# mockery ----------------------
49+
phys_reader = PhysPkgReader_.return_value
50+
content_types = from_xml.return_value
51+
pkg_srels = _srels_for.return_value
52+
sparts = _load_serialized_parts.return_value
53+
pkg_file = Mock(name='pkg_file')
54+
# exercise ---------------------
55+
pkg_reader = PackageReader.from_file(pkg_file)
56+
# verify -----------------------
57+
PhysPkgReader_.assert_called_once_with(pkg_file)
58+
from_xml.assert_called_once_with(phys_reader.content_types_xml)
59+
_srels_for.assert_called_once_with(phys_reader, '/')
60+
_load_serialized_parts.assert_called_once_with(phys_reader, pkg_srels,
61+
content_types)
62+
phys_reader.close.assert_called_once_with()
63+
init.assert_called_once_with(content_types, pkg_srels, sparts)
64+
assert isinstance(pkg_reader, PackageReader)

0 commit comments

Comments
 (0)