Python-docx: feature: Paragraph.delete()

Created on 3 Apr 2014  路  8Comments  路  Source: python-openxml/python-docx

In order to modify an existing document
As a developer using python-pptx
I need a way to delete a paragraph

Need to account for the possibility the paragraph contains the last reference to a relationship, such as might a hyperlink or inline picture.

text

Most helpful comment

You should be able to do this for the simple case with this code:

def delete_paragraph(paragraph):
    p = paragraph._element
    p.getparent().remove(p)
    p._p = p._element = None

Any subsequent access to the "deleted" paragraph object will raise AttributeError, so you should be careful not to keep the reference hanging around, including as a member of a stored value of Document.paragraphs.

The reason it's not in the library yet is because the general case is much trickier, in particular needing to detect and handle the variety of linked items that can be present in a paragraph; things like a picture, a hyperlink, or chart etc.

But if you know for sure none of those are present, these few lines should get the job done.

All 8 comments

Would like to see this available for python-docx. It would be very useful in populating a document full of placeholders given that it would allow the placeholder paragraph to be deleted if the value to populate the placeholder is None.

You should be able to do this for the simple case with this code:

def delete_paragraph(paragraph):
    p = paragraph._element
    p.getparent().remove(p)
    p._p = p._element = None

Any subsequent access to the "deleted" paragraph object will raise AttributeError, so you should be careful not to keep the reference hanging around, including as a member of a stored value of Document.paragraphs.

The reason it's not in the library yet is because the general case is much trickier, in particular needing to detect and handle the variety of linked items that can be present in a paragraph; things like a picture, a hyperlink, or chart etc.

But if you know for sure none of those are present, these few lines should get the job done.

That works! Thank you!!

Glad it worked out Jeff :)

Steve, thanks so much. I was having trouble after merging cells in a table which left extra empty paragraphs. Used your function and worked great, which let the cells shrink back by getting rid of empty space. Used it in a nested loop as follows:

    delete_paragraph(table.rows[rx].cells[cx].paragraphs[-1])

thanks - wayne (retired HW designer, having fun with python while hopefully helping out the non-profit I volunteer for)

Hi @scanny
Why not implement the feature and close the issue?

You should be able to do this for the simple case with this code:

def delete_paragraph(paragraph):
    p = paragraph._element
    p.getparent().remove(p)
    p._p = p._element = None

Any subsequent access to the "deleted" paragraph object will raise AttributeError, so you should be careful not to keep the reference hanging around, including as a member of a stored value of Document.paragraphs.

The reason it's not in the library yet is because the general case is much trickier, in particular needing to detect and handle the variety of linked items that can be present in a paragraph; things like a picture, a hyperlink, or chart etc.

But if you know for sure none of those are present, these few lines should get the job done.

What's the difference compared to this solution?

def delete_element(el):
    el._element.getparent().remove(el._element)

Well, in fact, on review, there is an error in that code. The last line should be:

paragraph._p = paragraph._element = None

But as for the rest of it:

  1. delete_element and el are misleading name choices in my view. A Paragraph object is an _element-proxy_ object which _composes_ an element object; it is not itself an element. So in general we reserve the name element and its derivatives for the XML element objects themselves.

  2. The core code is essentially the first two lines combined into one, so that's a matter of taste; the operation is the same. I would personally probably choose something like yours in my own code, but for someone learning, sometimes breaking things down more step-by-step eases figuring out what the underlying process is, like first get the element from the proxy, then do this thing with the element, etc.

  3. The (previously incorrect) last line is setting the _p and _element attributes of the "host" Paragraph proxy object to None so the now-deleted (or actually only orphaned) element is not accidentally accessed in later code and also is freed up for garbage collection. Removing an element in lxml does not delete it, it only breaks its relationship with its parent. So the original Paragraph object could still make changes to it and the user might puzzle for quite a while to figure out why their code wasn't working but wasn't raising an error. So you can think of it as preventative medicine.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JiyhonLiu picture JiyhonLiu  路  3Comments

madphysicist picture madphysicist  路  3Comments

evbo picture evbo  路  3Comments

carlosmtz2106 picture carlosmtz2106  路  7Comments

norecces picture norecces  路  7Comments