Ejemplo n.º 1
0
 def it_can_calculate_relative_ref_value(self):
     cases = (
         ('/', '/ppt/presentation.xml', 'ppt/presentation.xml'),
         ('/ppt', '/ppt/slideMasters/slideMaster1.xml',
          'slideMasters/slideMaster1.xml'),
         ('/ppt/slides', '/ppt/slideLayouts/slideLayout1.xml',
          '../slideLayouts/slideLayout1.xml'),
     )
     for baseURI, uri_str, expected_relative_ref in cases:
         pack_uri = PackURI(uri_str)
         assert pack_uri.relative_ref(baseURI) == expected_relative_ref
Ejemplo n.º 2
0
 def it_can_calculate_relative_ref_value(self):
     cases = (
         ("/", "/ppt/presentation.xml", "ppt/presentation.xml"),
         (
             "/ppt",
             "/ppt/slideMasters/slideMaster1.xml",
             "slideMasters/slideMaster1.xml",
         ),
         (
             "/ppt/slides",
             "/ppt/slideLayouts/slideLayout1.xml",
             "../slideLayouts/slideLayout1.xml",
         ),
     )
     for baseURI, uri_str, expected_relative_ref in cases:
         pack_uri = PackURI(uri_str)
         assert pack_uri.relative_ref(baseURI) == expected_relative_ref
Ejemplo n.º 3
0
    def but_it_returns_None_when_the_part_has_no_rels(self,
                                                      _blob_reader_prop_):
        _blob_reader_prop_.return_value = {
            "/ppt/_rels/presentation.xml.rels": b"blob"
        }
        package_reader = PackageReader(None)

        assert package_reader.rels_xml_for(
            PackURI("/ppt/slides.slide1.xml")) is None
Ejemplo n.º 4
0
 def it_can_add_a_new_slide(self, slides, slidelayout_, Slide_, slide_):
     slide = slides.add_slide(slidelayout_)
     Slide_.new.assert_called_once_with(
         slidelayout_, PackURI('/ppt/slides/slide3.xml'),
         slides._prs.package
     )
     slides._prs.relate_to.assert_called_once_with(slide_, RT.SLIDE)
     slides._sldIdLst.add_sldId.assert_called_once_with(ANY)
     assert slide is slide_
Ejemplo n.º 5
0
 def _new(cls, package):
     """
     Create and return a standalone, default notes master part based on
     the built-in template (without any related parts, such as theme).
     """
     partname = PackURI("/ppt/notesMasters/notesMaster1.xml")
     content_type = CT.PML_NOTES_MASTER
     notesMaster = CT_NotesMaster.new_default()
     return NotesMasterPart(partname, content_type, notesMaster, package)
Ejemplo n.º 6
0
 def test_construction_from_file(self):
     """Image(path) constructor produces correct attribute values"""
     # exercise ---------------------
     partname = PackURI('/ppt/media/image1.jpeg')
     image = Image.new(partname, test_image_path)
     # verify -----------------------
     assert image.ext == 'jpeg'
     assert image.content_type == 'image/jpeg'
     assert len(image._blob) == 3277
     assert image._desc == 'python-icon.jpeg'
Ejemplo n.º 7
0
 def test_construction_from_file(self):
     """Image(path) constructor produces correct attribute values"""
     # exercise ---------------------
     partname = PackURI('/ppt/media/image1.jpeg')
     image = Image.new(partname, test_image_path)
     # verify -----------------------
     assert_that(image.ext, is_(equal_to('jpeg')))
     assert_that(image.content_type, is_(equal_to('image/jpeg')))
     assert_that(len(image._blob), is_(equal_to(3277)))
     assert_that(image._desc, is_(equal_to('python-icon.jpeg')))
Ejemplo n.º 8
0
 def _rename_images(self):
     """
     Assign partnames like ``/ppt/media/image9.png`` to all images in the
     collection. The name portion is always ``image``. The number part
     forms a continuous sequence starting at 1 (e.g. 1, 2, 3, ...). The
     extension is preserved during renaming.
     """
     for idx, image in enumerate(self._values):
         partname_str = '/ppt/media/image%d.%s' % (idx + 1, image.ext)
         image.partname = PackURI(partname_str)
Ejemplo n.º 9
0
 def it_should_have_relative_ref_for_internal_rel(self):
     """
     Internal relationships (TargetMode == 'Internal' in the XML) should
     have a relative ref, e.g. '../slideLayouts/slideLayout1.xml', for
     the target_ref attribute.
     """
     part = Mock(name="part", partname=PackURI("/ppt/media/image1.png"))
     baseURI = "/ppt/slides"
     rel = _Relationship(None, None, part, baseURI)  # external=False
     assert rel.target_ref == "../media/image1.png"
Ejemplo n.º 10
0
 def test_add_part_preserves_sort_order(self):
     partname1 = PackURI('/ppt/slides/slide1.xml')
     partname2 = PackURI('/ppt/slides/slide2.xml')
     partname3 = PackURI('/ppt/slides/slide3.xml')
     part1 = Mock(name='part1')
     part1.partname = partname1
     part2 = Mock(name='part2')
     part2.partname = partname2
     part3 = Mock(name='part3')
     part3.partname = partname3
     parts = PartCollection()
     # exercise ---------------------
     parts.add_part(part2)
     parts.add_part(part3)
     parts.add_part(part1)
     # verify -----------------------
     expected = [partname1, partname2, partname3]
     actual = [part.partname for part in parts]
     msg = "expected %s, got %s" % (expected, actual)
     self.assertEqual(expected, actual, msg)
Ejemplo n.º 11
0
 def _new(cls, package):
     """
     Create and return a standalone, default notes master part based on
     the built-in template (without any related parts, such as theme).
     """
     return NotesMasterPart(
         PackURI("/ppt/notesMasters/notesMaster1.xml"),
         CT.PML_NOTES_MASTER,
         package,
         CT_NotesMaster.new_default(),
     )
 def cases(self, expected_values):
     """
     Return list of tuples zipped from uri_str cases and
     *expected_values*. Raise if lengths don't match.
     """
     uri_str_cases = ["/", "/ppt/presentation.xml", "/ppt/slides/slide1.xml"]
     if len(expected_values) != len(uri_str_cases):
         msg = "len(expected_values) differs from len(uri_str_cases)"
         raise AssertionError(msg)
     pack_uris = [PackURI(uri_str) for uri_str in uri_str_cases]
     return zip(pack_uris, expected_values)
Ejemplo n.º 13
0
 def add_part(self, part):
     """
     Insert a new part into the collection such that list remains sorted
     in logical partname order (e.g. slide10.xml comes after slide9.xml).
     """
     new_partidx = part.partname.idx
     for idx, seq_part in enumerate(self._values):
         partidx = PackURI(seq_part.partname).idx
         if partidx > new_partidx:
             self._values.insert(idx, part)
             return
     self._values.append(part)
Ejemplo n.º 14
0
    def rename_slide_parts(self, rIds):
        """Assign incrementing partnames to the slide parts identified by `rIds`.

        Partnames are like `/ppt/slides/slide9.xml` and are assigned in the order their
        id appears in the `rIds` sequence. The name portion is always ``slide``. The
        number part forms a continuous sequence starting at 1 (e.g. 1, 2, ... 10, ...).
        The extension is always ``.xml``.
        """
        for idx, rId in enumerate(rIds):
            slide_part = self.related_part(rId)
            slide_part.partname = PackURI("/ppt/slides/slide%d.xml" %
                                          (idx + 1))
Ejemplo n.º 15
0
 def test_construction_from_stream(self):
     """Image(stream) construction produces correct attribute values"""
     # exercise ---------------------
     partname = PackURI('/ppt/media/image1.jpeg')
     with open(test_image_path, 'rb') as f:
         stream = StringIO(f.read())
     image = Image.new(partname, stream)
     # verify -----------------------
     assert image.ext == 'jpg'
     assert image.content_type == 'image/jpeg'
     assert len(image._blob) == 3277
     assert image._desc == 'image.jpg'
 def next_partname_fixture(self, request, iter_parts_):
     existing_partname_numbers, next_partname_number = request.param
     package = OpcPackage()
     parts = [
         instance_mock(
             request, Part, name="part[%d]" % idx, partname="/foo/bar/baz%d.xml" % n
         )
         for idx, n in enumerate(existing_partname_numbers)
     ]
     iter_parts_.return_value = iter(parts)
     partname_template = "/foo/bar/baz%d.xml"
     expected_partname = PackURI("/foo/bar/baz%d.xml" % next_partname_number)
     return package, partname_template, expected_partname
Ejemplo n.º 17
0
 def add_fixture(self, package_, slide_part_, notes_master_part_,
                 notes_slide_part_, NotesSlidePart_, new_):
     partname = PackURI('/ppt/notesSlides/notesSlide42.xml')
     content_type = CT.PML_NOTES_SLIDE
     notes = element('p:notes')
     calls = [
         call(notes_master_part_, RT.NOTES_MASTER),
         call(slide_part_, RT.SLIDE),
     ]
     package_.next_partname.return_value = partname
     new_.return_value = notes
     return (package_, slide_part_, notes_master_part_, notes_slide_part_,
             NotesSlidePart_, partname, content_type, notes, calls)
Ejemplo n.º 18
0
 def test__scale_calculates_correct_dimensions(self):
     """Image._scale() calculates correct dimensions"""
     # setup ------------------------
     test_cases = (((None, None), (Px(204), Px(204))), ((1000, None),
                                                        (1000, 1000)),
                   ((None, 3000), (3000, 3000)), ((3337, 9999), (3337,
                                                                 9999)))
     partname = PackURI('/ppt/media/image1.png')
     image = Image.new(partname, test_image_path)
     # verify -----------------------
     for params, expected in test_cases:
         width, height = params
         assert image._scale(width, height) == expected
Ejemplo n.º 19
0
 def next_partname(self, tmpl):
     """
     Return a |PackURI| instance representing the next available partname
     matching *tmpl*, which is a printf (%)-style template string
     containing a single replacement item, a '%d' to be used to insert the
     integer portion of the partname. Example: '/ppt/slides/slide%d.xml'
     """
     partnames = [part.partname for part in self.iter_parts()]
     for n in range(1, len(partnames) + 2):
         candidate_partname = tmpl % n
         if candidate_partname not in partnames:
             return PackURI(candidate_partname)
     raise Exception("ProgrammingError: ran out of candidate_partnames")
Ejemplo n.º 20
0
 def iter_valid_rels():
     """Filter out broken relationships such as those pointing to NULL."""
     for rel_elm in xml_rels.relationship_lst:
         # --- Occasionally a PowerPoint plugin or other client will "remove"
         # --- a relationship simply by "voiding" its Target value, like making
         # --- it "/ppt/slides/NULL". Skip any relationships linking to a
         # --- partname that is not present in the package.
         if rel_elm.targetMode == RTM.INTERNAL:
             partname = PackURI.from_rel_ref(base_uri,
                                             rel_elm.target_ref)
             if partname not in parts:
                 continue
         yield _Relationship.from_xml(base_uri, rel_elm, parts)
Ejemplo n.º 21
0
    def it_can_create_a_new_slide_part(self, request, package_, relate_to_):
        partname = PackURI("/foobar.xml")
        SlidePart_init_ = initializer_mock(request, SlidePart)
        slide_layout_part_ = instance_mock(request, SlideLayoutPart)
        CT_Slide_ = class_mock(request, "pptx.parts.slide.CT_Slide")
        CT_Slide_.new.return_value = sld = element("c:sld")

        slide_part = SlidePart.new(partname, package_, slide_layout_part_)

        SlidePart_init_.assert_called_once_with(partname, CT.PML_SLIDE, sld,
                                                package_)
        slide_part.relate_to.assert_called_once_with(slide_part,
                                                     slide_layout_part_,
                                                     RT.SLIDE_LAYOUT)
        assert isinstance(slide_part, SlidePart)
Ejemplo n.º 22
0
        def load_rels(source_partname, rels):
            """Populate `xml_rels` dict by traversing relationships depth-first."""
            xml_rels[source_partname] = rels
            visited_partnames.add(source_partname)
            base_uri = source_partname.baseURI

            # --- recursion stops when there are no unvisited partnames in rels ---
            for rel in rels:
                if rel.targetMode == RTM.EXTERNAL:
                    continue
                target_partname = PackURI.from_rel_ref(base_uri,
                                                       rel.target_ref)
                if target_partname in visited_partnames:
                    continue
                load_rels(target_partname, self._xml_rels_for(target_partname))
 def it_can_write_a_blob(self, pkg_file):
     # setup ------------------------
     pack_uri = PackURI("/part/name.xml")
     blob = "<BlobbityFooBlob/>".encode("utf-8")
     # exercise ---------------------
     pkg_writer = PhysPkgWriter(pkg_file)
     pkg_writer.write(pack_uri, blob)
     pkg_writer.close()
     # verify -----------------------
     written_blob_sha1 = hashlib.sha1(blob).hexdigest()
     zipf = ZipFile(pkg_file, "r")
     retrieved_blob = zipf.read(pack_uri.membername)
     zipf.close()
     retrieved_blob_sha1 = hashlib.sha1(retrieved_blob).hexdigest()
     assert retrieved_blob_sha1 == written_blob_sha1
Ejemplo n.º 24
0
    def it_can_rename_related_slide_parts(self, request, related_part_):
        rIds = tuple("rId%d" % n for n in range(5, 0, -1))
        slide_parts = tuple(
            instance_mock(request, SlidePart) for _ in range(5))
        related_part_.side_effect = iter(slide_parts)
        prs_part = PresentationPart(None, None, None, None)

        prs_part.rename_slide_parts(rIds)

        assert related_part_.call_args_list == [
            call(prs_part, rId) for rId in rIds
        ]
        assert [s.partname for s in slide_parts] == [
            PackURI("/ppt/slides/slide%d.xml" % (i + 1))
            for i in range(len(rIds))
        ]
Ejemplo n.º 25
0
 def add_image(self, file):
     """
     Return image part containing the image in *file*, which is either a
     path to an image file or a file-like object containing an image. If an
     image instance containing this same image already exists, that
     instance is returned. If it does not yet exist, a new one is created.
     """
     # use Image constructor to validate and characterize image file
     partname = PackURI('/ppt/media/image1.jpeg')  # dummy just for baseURI
     image = Image.new(partname, file)
     # return matching image if found
     for existing_image in self._values:
         if existing_image._sha1 == image._sha1:
             return existing_image
     # otherwise add it to collection and return new image
     self._values.append(image)
     self._rename_images()
     return image
Ejemplo n.º 26
0
    def next_partname(self, tmpl):
        """Return |PackURI| next available partname matching `tmpl`.

        `tmpl` is a printf (%)-style template string containing a single replacement
        item, a '%d' to be used to insert the integer portion of the partname.
        Example: '/ppt/slides/slide%d.xml'
        """
        # --- expected next partname is tmpl % n where n is one greater than the number
        # --- of existing partnames that match tmpl. Speed up finding the next one
        # --- (maybe) by searching from the end downward rather than from 1 upward.
        prefix = tmpl[:(tmpl % 42).find("42")]
        partnames = set(p.partname for p in self.iter_parts()
                        if p.partname.startswith(prefix))
        for n in range(len(partnames) + 1, 0, -1):
            candidate_partname = tmpl % n
            if candidate_partname not in partnames:
                return PackURI(candidate_partname)
        raise Exception(  # pragma: no cover
            "ProgrammingError: ran out of candidate_partnames")
Ejemplo n.º 27
0
    def it_can_write_a_sequence_of_parts(self, request, phys_writer_):
        parts_ = (instance_mock(
            request,
            Part,
            partname=PackURI("/ppt/%s.xml" % x),
            blob="blob_%s" % x,
            rels=instance_mock(request, _Relationships, xml="rels_xml_%s" % x),
        ) for x in ("a", "b", "c"))
        package_writer = PackageWriter(None, None, parts_)

        package_writer._write_parts(phys_writer_)

        assert phys_writer_.write.call_args_list == [
            call("/ppt/a.xml", "blob_a"),
            call("/ppt/_rels/a.xml.rels", "rels_xml_a"),
            call("/ppt/b.xml", "blob_b"),
            call("/ppt/_rels/b.xml.rels", "rels_xml_b"),
            call("/ppt/c.xml", "blob_c"),
            call("/ppt/_rels/c.xml.rels", "rels_xml_c"),
        ]
Ejemplo n.º 28
0
    def next_media_partname(self, ext):
        """Return |PackURI| instance for next available media partname.

        Partname is first available, starting at sequence number 1. Empty
        sequence numbers are reused. *ext* is used as the extension on the
        returned partname.
        """
        def first_available_media_idx():
            media_idxs = sorted([
                part.partname.idx for part in self.iter_parts()
                if part.partname.startswith("/ppt/media/media")
            ])
            for i, media_idx in enumerate(media_idxs):
                idx = i + 1
                if idx < media_idx:
                    return idx
            return len(media_idxs) + 1

        idx = first_available_media_idx()
        return PackURI("/ppt/media/media%d.%s" % (idx, ext))
Ejemplo n.º 29
0
    def next_image_partname(self, ext):
        """
        Return a |PackURI| instance representing the next available image
        partname, by sequence number. *ext* is used as the extention on the
        returned partname.
        """
        def first_available_image_idx():
            image_idxs = sorted([
                part.partname.idx for part in self.iter_parts()
                if part.partname.startswith("/ppt/media/image")
                and part.partname.idx is not None
            ])
            for i, image_idx in enumerate(image_idxs):
                idx = i + 1
                if idx < image_idx:
                    return idx
            return len(image_idxs) + 1

        idx = first_available_image_idx()
        return PackURI("/ppt/media/image%d.%s" % (idx, ext))
Ejemplo n.º 30
0
    def it_creates_a_new_theme_part_to_help(self, request, package_, theme_part_):
        XmlPart_ = class_mock(
            request, "pptx.parts.slide.XmlPart", return_value=theme_part_
        )
        theme_elm = element("p:theme")
        method_mock(
            request,
            CT_OfficeStyleSheet,
            "new_default",
            autospec=False,
            return_value=theme_elm,
        )
        pn_tmpl = "/ppt/theme/theme%d.xml"
        partname = PackURI("/ppt/theme/theme2.xml")
        package_.next_partname.return_value = partname

        theme_part = NotesMasterPart._new_theme_part(package_)

        package_.next_partname.assert_called_once_with(pn_tmpl)
        CT_OfficeStyleSheet.new_default.assert_called_once_with()
        XmlPart_.assert_called_once_with(partname, CT.OFC_THEME, package_, theme_elm)
        assert theme_part is theme_part_
Ejemplo n.º 31
0
    def it_can_construct_from_chart_type_and_data(self, request):
        chart_data_ = instance_mock(request, ChartData, xlsx_blob=b"xlsx-blob")
        chart_data_.xml_bytes.return_value = b"chart-blob"
        package_ = instance_mock(request, OpcPackage)
        package_.next_partname.return_value = PackURI("/ppt/charts/chart42.xml")
        chart_part_ = instance_mock(request, ChartPart)
        # --- load() must have autospec turned off to work in Python 2.7 mock ---
        load_ = method_mock(
            request, ChartPart, "load", autospec=False, return_value=chart_part_
        )

        chart_part = ChartPart.new(XCT.RADAR, chart_data_, package_)

        package_.next_partname.assert_called_once_with("/ppt/charts/chart%d.xml")
        chart_data_.xml_bytes.assert_called_once_with(XCT.RADAR)
        load_.assert_called_once_with(
            "/ppt/charts/chart42.xml", CT.DML_CHART, package_, b"chart-blob"
        )
        chart_part_.chart_workbook.update_from_xlsx_blob.assert_called_once_with(
            b"xlsx-blob"
        )
        assert chart_part is chart_part_
Ejemplo n.º 32
0
    def it_can_add_a_new_slide(self, request, package_, slide_part_, slide_,
                               relate_to_):
        slide_layout_ = instance_mock(request, SlideLayout)
        partname = PackURI("/ppt/slides/slide9.xml")
        property_mock(request,
                      PresentationPart,
                      "_next_slide_partname",
                      return_value=partname)
        SlidePart_ = class_mock(request, "pptx.parts.presentation.SlidePart")
        SlidePart_.new.return_value = slide_part_
        relate_to_.return_value = "rId42"
        slide_layout_part_ = slide_layout_.part
        slide_part_.slide = slide_
        prs_part = PresentationPart(None, None, package_, None)

        rId, slide = prs_part.add_slide(slide_layout_)

        SlidePart_.new.assert_called_once_with(partname, package_,
                                               slide_layout_part_)
        prs_part.relate_to.assert_called_once_with(prs_part, slide_part_,
                                                   RT.SLIDE)
        assert rId == "rId42"
        assert slide is slide_
Ejemplo n.º 33
0
 def it_can_construct_from_relative_ref(self):
     baseURI = '/ppt/slides'
     relative_ref = '../slideLayouts/slideLayout1.xml'
     pack_uri = PackURI.from_rel_ref(baseURI, relative_ref)
     assert pack_uri == '/ppt/slideLayouts/slideLayout1.xml'