def table_fixture(self, table_, _shape_factory_): shapes = SlideShapes(element('p:spTree'), None) rows, cols, x, y, cx, cy = 1, 2, 10, 11, 12, 13 _shape_factory_.return_value = table_ expected_xml = ( '<p:spTree xmlns:p="http://schemas.openxmlformats.org/presentati' 'onml/2006/main">\n <p:graphicFrame xmlns:a="http://schemas.ope' 'nxmlformats.org/drawingml/2006/main">\n <p:nvGraphicFramePr>' '\n <p:cNvPr id="1" name="Table 0"/>\n <p:cNvGraphicFr' 'amePr>\n <a:graphicFrameLocks noGrp="1"/>\n </p:cNv' 'GraphicFramePr>\n <p:nvPr/>\n </p:nvGraphicFramePr>\n ' ' <p:xfrm>\n <a:off x="10" y="11"/>\n <a:ext cx="12" ' 'cy="13"/>\n </p:xfrm>\n <a:graphic>\n <a:graphicData' ' uri="http://schemas.openxmlformats.org/drawingml/2006/table">' '\n <a:tbl>\n <a:tblPr firstRow="1" bandRow="1">' '\n <a:tableStyleId>{5C22544A-7EE6-4342-B048-85BDC9FD' '1C3A}</a:tableStyleId>\n </a:tblPr>\n <a:tblG' 'rid>\n <a:gridCol w="6"/>\n <a:gridCol w=' '"6"/>\n </a:tblGrid>\n <a:tr h="13">\n ' ' <a:tc>\n <a:txBody>\n <a:bodyP' 'r/>\n <a:lstStyle/>\n <a:p/>\n ' ' </a:txBody>\n <a:tcPr/>\n </' 'a:tc>\n <a:tc>\n <a:txBody>\n ' ' <a:bodyPr/>\n <a:lstStyle/>\n ' ' <a:p/>\n </a:txBody>\n <a:tcPr/>\n' ' </a:tc>\n </a:tr>\n </a:tbl>\n ' ' </a:graphicData>\n </a:graphic>\n </p:graphicFrame>\n</p:s' 'pTree>' ) return shapes, rows, cols, x, y, cx, cy, table_, expected_xml
def title_fixture(self, request, _shape_factory_, shape_): spTree_cxml, found = request.param spTree = element(spTree_cxml) shapes = SlideShapes(spTree, None) calls = [call(shapes, spTree.xpath('p:sp')[1])] if found else [] _shape_ = shape_ if found else None return shapes, _shape_factory_, calls, _shape_
def picture_fixture( self, picture_, part_prop_, image_part_, _shape_factory_): shapes = SlideShapes(element('p:spTree'), None) image_file, x, y, cx, cy = 'foobar.png', 1, 2, 3, 4 expected_xml = ( '<p:spTree xmlns:p="http://schemas.openxmlformats.org/presentati' 'onml/2006/main">\n <p:pic xmlns:a="http://schemas.openxmlforma' 'ts.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlform' 'ats.org/officeDocument/2006/relationships">\n <p:nvPicPr>\n ' ' <p:cNvPr id="1" name="Picture 0" descr="Image Description"' '/>\n <p:cNvPicPr>\n <a:picLocks noChangeAspect="1"/' '>\n </p:cNvPicPr>\n <p:nvPr/>\n </p:nvPicPr>\n ' '<p:blipFill>\n <a:blip r:embed="rId42"/>\n <a:stretch' '>\n <a:fillRect/>\n </a:stretch>\n </p:blipFill>' '\n <p:spPr>\n <a:xfrm>\n <a:off x="1" y="2"/>\n ' ' <a:ext cx="101" cy="102"/>\n </a:xfrm>\n <a:pr' 'stGeom prst="rect">\n <a:avLst/>\n </a:prstGeom>\n ' ' </p:spPr>\n </p:pic>\n</p:spTree>' ) slide_part_ = part_prop_.return_value get_or_add_image_part_ = slide_part_.get_or_add_image_part get_or_add_image_part_.return_value = image_part_, 'rId42' image_part_.scale.return_value = 101, 102 image_part_.desc = 'Image Description' _shape_factory_.return_value = picture_ return ( shapes, image_file, x, y, cx, cy, picture_, expected_xml )
def ph_name_fixture(self, request): ph_type, sp_id, orient, expected_name = request.param spTree = element( 'p:spTree/(p:cNvPr{name=Title 1},p:cNvPr{name=Table Placeholder ' '3})' ) shapes = SlideShapes(spTree, None) return shapes, ph_type, sp_id, orient, expected_name
def index_fixture(self, request, shape_): idx = request.param spTree = element('p:spTree/(p:sp,p:sp,p:sp)') sps = spTree.xpath('p:sp') shapes = SlideShapes(spTree, None) shape_.element = sps[idx] expected_value = idx return shapes, shape_, expected_value
def clone_fixture( self, slide_layout_, _clone_layout_placeholder_, placeholder_): shapes = SlideShapes(None, None) calls = [call(shapes, placeholder_)] slide_layout_.iter_cloneable_placeholders.return_value = ( iter([placeholder_]) ) return shapes, slide_layout_, calls
def sp_fixture(self, _left_prop_, _top_prop_, _width_prop_, _height_prop_): origin_x, origin_y = 42, 24 spTree = element("p:spTree") shapes = SlideShapes(spTree, None) _left_prop_.return_value, _top_prop_.return_value = 12, 34 _width_prop_.return_value, _height_prop_.return_value = 56, 78 builder = FreeformBuilder(shapes, None, None, None, None) expected_xml = snippet_seq("freeform")[0] return builder, origin_x, origin_y, spTree, expected_xml
def add_chart_fixture( self, chart_data_, _add_chart_graphic_frame_, graphic_frame_, part_prop_): shapes = SlideShapes(None, None) chart_type = 0 rId, x, y, cx, cy = 'rId42', 1, 2, 3, 4 part_prop_.return_value.add_chart_part.return_value = rId return ( shapes, chart_type, x, y, cx, cy, chart_data_, rId, graphic_frame_ )
def change_shapes(collection, change, data, handler, **kwargs): ''' Apply changes to a collection of shapes in the context of data. ``collection`` is a slide.shapes or group shapes. ``change`` is typically a dict of <shape-name>: commands. ``data`` is a dictionary passed to the template engine. ''' prs = kwargs.get('prs') new_slide = kwargs.get('new_slide') copy_slide = kwargs.get('copy_slide', False) source_slide = kwargs.get('source_slide') dest = prs.slides.add_slide(new_slide) if copy_slide else None mapping = {} for shape in collection: if shape.name not in change: copy_slide_elem(shape, dest) continue spec = change[shape.name] if shape.name not in mapping: mapping[shape.name] = 0 if spec.get('data'): if not isinstance(spec['data'], (dict,)): spec['data'] = {'function': '{}'.format(spec['data']) if not isinstance( spec['data'], (str, six.string_types,)) else spec['data']} shape_data = build_transform( spec['data'], vars={'data': None, 'handler': None})(data=data, handler=handler)[0] else: if isinstance(data, (dict, AttrDict,)) and 'handler' in data: data.pop('handler') shape_data = copy.deepcopy(data) if isinstance(shape_data, (dict, AttrDict,)): shape_data['handler'] = handler if spec.get('stack'): shape_data = shape_data[mapping[shape.name]] mapping[shape.name] = mapping[shape.name] + 1 # If the shape is a group, apply spec to each sub-shape if is_group(shape): sub_shapes = SlideShapes(shape.element, collection) change_shapes(sub_shapes, spec, shape_data, handler) # Add args to shape_data if hasattr(handler, 'args'): args = {k: v[0] for k, v in handler.args.items() if len(v) > 0} shape_data['args'] = args # Run commands in the spec for cmd, method in COMMANDS_LIST.items(): if cmd in spec: method(shape, spec, shape_data) copy_slide_elem(shape, dest) add_new_slide(dest, source_slide)
def connector_fixture(self, _add_cxnSp_, _shape_factory_, connector_): shapes = SlideShapes(element('p:spTree'), None) connector_type = MSO_CONNECTOR.STRAIGHT begin_x, begin_y, end_x, end_y = 1, 2, 3, 4 cxnSp = element('p:cxnSp') _add_cxnSp_.return_value = cxnSp _shape_factory_.return_value = connector_ return ( shapes, connector_type, begin_x, begin_y, end_x, end_y, cxnSp, connector_ )
def apply_commands(rule: Dict[str, dict], shapes, data: dict): ''' Apply commands in rule to change shapes using data. :arg dict rule: a dict of shape names, and commands to apply on each. e.g. ``{"Oval 1": {"fill": "red"}, "Oval 2": {"text": "OK"}}`` :arg Shapes shapes: a slide.shapes or group.shapes object on which the rule should be applied :arg dict data: data context for the commands in the rule ''' # Apply every rule to every pattern -- as long as the rule key matches the shape name for pattern, spec in rule.items(): if pattern in rule_cmdlist: continue shape_matched = False for shape in shapes: if not fnmatchcase(shape.name, pattern): continue shape_matched = True # Clone all slides into the `clones` list BEFORE applying any command. Ensures that # commands applied to the shape don't propagate into its clones clones = [] clone_seq = iterate_on(spec.get('clone-shape', [None]), data) parent_clone = data.get('clone', None) for i, (clone_key, clone_val) in enumerate(clone_seq): if i > 0: # This copies only a shape, group or image. Not table, chart, media, equation, # or zoom. But we don't see a need for these yet. el = copy.deepcopy(shape.element) shape.element.addnext(el) shape = pptx.shapes.autoshape.Shape(el, None) clones.append(AttrDict(pos=i, key=clone_key, val=clone_val, shape=shape, parent=parent_clone)) # Run commands in the spec on all cloned shapes is_group = shape.element.tag.endswith('}grpSp') for i, clone in enumerate(clones): # Include shape-level `data:`. Add shape, clone as variables shape_data = load_data( spec.get('data', {}), _default_key='function', shape=shape, clone=clone, **{k: v for k, v in data.items() if k not in {'shape', 'clone'}}) for cmd in spec: if cmd in commands.cmdlist: commands.cmdlist[cmd](clone.shape, spec[cmd], shape_data) # Warn on unknown commands. But don't warn on groups -- they have sub-shapes elif cmd not in special_cmdlist and not is_group: app_log.warn('pptgen2: Unknown command: %s on shape: %s', cmd, pattern) # If the shape is a group, apply spec to each sub-shape if is_group: apply_commands(spec, SlideShapes(clone.shape.element, shapes), shape_data) # Warn if the pattern is neither a shape nor a command if (not shape_matched and pattern not in special_cmdlist and pattern not in commands.cmdlist): app_log.warn('pptgen2: No shape matches pattern: %s', pattern)
def add_cxnSp_fixture(self, request): begin_x, begin_y, end_x, end_y, spPr_cxml = request.param shapes = SlideShapes(element('p:spTree'), None) connector_type = MSO_CONNECTOR.STRAIGHT tmpl_cxml = ( 'p:cxnSp/(p:nvCxnSpPr/(p:cNvPr{id=1,name=Connector 0},p:cNvCxnSp' 'Pr,p:nvPr),%s,a:prstGeom{prst=line}/a:avLst),p:style/(a:lnRef{i' 'dx=2}/a:schemeClr{val=accent1},a:fillRef{idx=0}/a:schemeClr{val' '=accent1},a:effectRef{idx=1}/a:schemeClr{val=accent1},a:fontRef' '{idx=minor}/a:schemeClr{val=tx1}))' ) expected_xml = xml(tmpl_cxml % spPr_cxml) return ( shapes, connector_type, begin_x, begin_y, end_x, end_y, expected_xml )
def clone_ph_fixture(self, placeholder_): shapes = SlideShapes(element('p:spTree'), None) expected_xml = ( '<p:spTree xmlns:p="http://schemas.openxmlformats.org/presentati' 'onml/2006/main">\n <p:sp xmlns:a="http://schemas.openxmlformat' 's.org/drawingml/2006/main">\n <p:nvSpPr>\n <p:cNvPr id=' '"1" name="Vertical Chart Placeholder 0"/>\n <p:cNvSpPr>\n ' ' <a:spLocks noGrp="1"/>\n </p:cNvSpPr>\n <p:nvP' 'r>\n <p:ph type="chart" idx="42" orient="vert" sz="half"' '/>\n </p:nvPr>\n </p:nvSpPr>\n <p:spPr/>\n </p:sp>' '\n</p:spTree>' ) placeholder_.ph_type = PP_PLACEHOLDER.CHART placeholder_.idx = 42 placeholder_.orient = 'vert' placeholder_.sz = 'half' return shapes, placeholder_, expected_xml
def textbox_fixture(self, textbox_, _shape_factory_): shapes = SlideShapes(element('p:spTree'), None) x, y, cx, cy = 1, 2, 3, 4 expected_xml = ( '<p:spTree xmlns:p="http://schemas.openxmlformats.org/presentati' 'onml/2006/main">\n <p:sp xmlns:a="http://schemas.openxmlformat' 's.org/drawingml/2006/main">\n <p:nvSpPr>\n <p:cNvPr id=' '"1" name="TextBox 0"/>\n <p:cNvSpPr txBox="1"/>\n <p:' 'nvPr/>\n </p:nvSpPr>\n <p:spPr>\n <a:xfrm>\n ' '<a:off x="1" y="2"/>\n <a:ext cx="3" cy="4"/>\n </a' ':xfrm>\n <a:prstGeom prst="rect">\n <a:avLst/>\n ' ' </a:prstGeom>\n <a:noFill/>\n </p:spPr>\n <p:txBo' 'dy>\n <a:bodyPr wrap="none">\n <a:spAutoFit/>\n ' ' </a:bodyPr>\n <a:lstStyle/>\n <a:p/>\n </p:txBod' 'y>\n </p:sp>\n</p:spTree>' ) _shape_factory_.return_value = textbox_ return shapes, x, y, cx, cy, textbox_, expected_xml
def add_cht_gr_frm_fixture(self, graphic_frame_, _shape_factory_): shapes = SlideShapes(element('p:spTree'), None) rId, x, y, cx, cy = 'rId42', 1, 2, 3, 4 expected_xml = ( '<p:spTree xmlns:p="http://schemas.openxmlformats.org/presentati' 'onml/2006/main">\n <p:graphicFrame xmlns:a="http://schemas.ope' 'nxmlformats.org/drawingml/2006/main">\n <p:nvGraphicFramePr>' '\n <p:cNvPr id="1" name="Chart 0"/>\n <p:cNvGraphicFr' 'amePr>\n <a:graphicFrameLocks noGrp="1"/>\n </p:cNv' 'GraphicFramePr>\n <p:nvPr/>\n </p:nvGraphicFramePr>\n ' ' <p:xfrm>\n <a:off x="1" y="2"/>\n <a:ext cx="3" cy=' '"4"/>\n </p:xfrm>\n <a:graphic>\n <a:graphicData uri' '="http://schemas.openxmlformats.org/drawingml/2006/chart">\n ' ' <c:chart xmlns:c="http://schemas.openxmlformats.org/drawin' 'gml/2006/chart" xmlns:r="http://schemas.openxmlformats.org/offi' 'ceDocument/2006/relationships" r:id="rId42"/>\n </a:graphi' 'cData>\n </a:graphic>\n </p:graphicFrame>\n</p:spTree>' ) _shape_factory_.return_value = graphic_frame_ return shapes, rId, x, y, cx, cy, graphic_frame_, expected_xml
def test_group_and_image(self): # Test case for group objects. for img in [ self.image, 'https://gramener.com/uistatic/img/store-supply-chain.png' ]: try: target = pptgen.pptgen(source=self.input, only=5, group_test={ 'slide-title': 'Group Test', 'Group 1': { 'Caption': { 'text': 'New caption' }, 'Picture': { 'image': img } } }) except requests.ConnectionError: raise SkipTest( 'No internet connection. Skipping HTTPS image test') eq_(len(target.slides), 1) grp_shape = self.get_shape(target, 'Group 1')[0] for shape in SlideShapes(grp_shape.element, grp_shape): if shape.name == 'Caption': eq_(shape.text, 'New caption') if shape.name == 'Picture': if urlparse(img).netloc: r = requests.get(img) with tempfile.NamedTemporaryFile( delete=False) as handle: handle.write(r.content) with open(handle.name, 'rb') as f: blob = f.read() os.unlink(handle.name) else: with open(img, 'rb') as f: blob = f.read() eq_(shape.image.blob, blob)
def autoshape_fixture(self, _shape_factory_, shape_): shapes = SlideShapes(element('p:spTree'), None) autoshape_type_id = MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE x, y, cx, cy = 1, 2, 3, 4 expected_xml = ( '<p:spTree xmlns:p="http://schemas.openxmlformats.org/presentati' 'onml/2006/main">\n <p:sp xmlns:a="http://schemas.openxmlformat' 's.org/drawingml/2006/main">\n <p:nvSpPr>\n <p:cNvPr id=' '"1" name="Rounded Rectangle 0"/>\n <p:cNvSpPr/>\n <p:' 'nvPr/>\n </p:nvSpPr>\n <p:spPr>\n <a:xfrm>\n ' '<a:off x="1" y="2"/>\n <a:ext cx="3" cy="4"/>\n </a' ':xfrm>\n <a:prstGeom prst="roundRect">\n <a:avLst/>' '\n </a:prstGeom>\n </p:spPr>\n <p:style>\n <a:l' 'nRef idx="1">\n <a:schemeClr val="accent1"/>\n </a:' 'lnRef>\n <a:fillRef idx="3">\n <a:schemeClr val="ac' 'cent1"/>\n </a:fillRef>\n <a:effectRef idx="2">\n ' ' <a:schemeClr val="accent1"/>\n </a:effectRef>\n <' 'a:fontRef idx="minor">\n <a:schemeClr val="lt1"/>\n ' ' </a:fontRef>\n </p:style>\n <p:txBody>\n <a:bodyPr ' 'rtlCol="0" anchor="ctr"/>\n <a:lstStyle/>\n <a:p>\n ' ' <a:pPr algn="ctr"/>\n </a:p>\n </p:txBody>\n </p' ':sp>\n</p:spTree>' ) return shapes, autoshape_type_id, x, y, cx, cy, shape_, expected_xml
def index_raises_fixture(self, shape_): spTree = element('p:spTree/(p:sp,p:sp,p:sp)') shapes = SlideShapes(spTree, None) shape_.element = element('p:sp') return shapes, shape_
def shapes(self): """ Instance of |SlideShapes| containing sequence of shape objects appearing on this slide. """ return SlideShapes(self._element.spTree, self)
def factory_fixture(self, SlideShapeFactory_, shape_): shapes = SlideShapes(None, None) sp = element('p:sp') return shapes, sp, SlideShapeFactory_, shape_