Skip to content

Add slides parameter to replace_text function to avoid using multiple TextReplacer objects #13

@davsaunders

Description

@davsaunders

Currently, in order to write to certain slides only, one has to create a TextReplacer object for those slides only, call replace_text and then save the new presentation to a file. For example, say you have a dataframe df and you create a powerpoint where each row/record in the dataframe corresponds to a slide and each column name/value pair in that row is a replacee/replacement tuple:

# create a new slide for each row in the dataframe based off a template file
pres = Presentation(template_file_name)
for _ in range(len(df) - 1):
    duplicate_slide(pres, 0)
pres.save(file_name)

# loop though each row of the dataframe
for i, row in df.iterrows():
    # create the replacer tuples for each column value of that row
    replacements = [(str(k), str(v)) for k, v in row.items()]
    # create a text replace object for the corresponding slide
    replacer = TextReplacer(file_name, tables=True, slides=f'{i+1}')
    # make the replacements
    replacer.replace_text(replacements, quiet=True)
    # save the updated powerpoint
    replacer.write_presentation_to_file(file_name)

This works fine for powerpoints with a small number of slides, however, for larger jobs this leads to a large increase in processing time that I believe due to the constant opening, saving, and closing of the powerpoint. An ideal usage in my opinion would be:

...
# create a text replace object for the entire presentation
replacer = TextReplacer(file_name, tables=True)

# loop though each row of the dataframe
for i, row in df.iterrows():
    # create the replacer tuples for each column value of that row
    replacements = [(str(k), str(v)) for k, v in row.items()]
    # make the replacements for a given slide(s)
    replacer.replace_text(replacements, quiet=True, slides=f'{i+1}')

# save the updated powerpoint after making all the replacements, instead of after each slide
replacer.write_presentation_to_file(file_name)

It seems the replace_text function already basically does this by looping over all the slides and comparing it to the _slides variable set in the constructor:

# loop through all slides
        self._current_slide_idx = 0
        if self._verbose:
            print("Presentation[%s]" % (self._presentation_file_name))
        for slide in self._presentation.slides:
            if self._verbose:
                print("  Slide[%s, id=%s] with title '%s'" % ( self._current_slide_idx+1, slide.slide_id, "<no title>" if slide.shapes.title is None else slide.shapes.title.text ))
            if self._slides[self._current_slide_idx]: 
            # if self._slides[self._current_slide_idx] or slides_from_parameter[self._current_slide_idx]: 
                self._process_shapes(2, slide)
            else:
                if self._verbose:
                    print("    ... skipped")
            self._current_slide_idx += 1

so if it could compare it to a _slides object created off a parameter passed into the replace_text function instead that could allow for this functionality I believe. I also wonder if there is a way to access the desired slide(s) directly though the index vs looping over all the slides and comparing, but my knowledge of manipulating powerpoints in python is limited (which is why I am so grateful for this package!)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions