Broken writer with lxml + defusedxml

Issue #1373 resolved
Alexis Fouilhé created an issue

Release 3.0.2 broke the following test script, when run in an environment containing both lxml and defusedxml.

import openpyxl
import openpyxl.writer.excel


def _main():
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.cell(row=1, column=1, value="a")
    openpyxl.writer.excel.save_virtual_workbook(wb)


if __name__ == "__main__":
    _main()

It works without problem on Openpyxl 3.0.1 and crashes on Openpyxl 3.0.2 with the following trace.

Traceback (most recent call last):
  File "t.py", line 13, in <module>
    _main()
  File "t.py", line 9, in _main
    openpyxl.writer.excel.save_virtual_workbook(wb)
  File "/Users/alexisfouilhe/e/lib/python3.6/site-packages/openpyxl/compat/__init__.py", line 38, in new_func1
    return func1(*args, **kwargs)
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/writer/excel.py", line 304, in save_virtual_workbook
    writer.save()
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/writer/excel.py", line 275, in save
    self.write_data()
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/writer/excel.py", line 75, in write_data
    self._write_worksheets()
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/writer/excel.py", line 215, in _write_worksheets
    self.write_worksheet(ws)
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/writer/excel.py", line 200, in write_worksheet
    writer.write()
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/worksheet/_writer.py", line 354, in write
    self.write_top()
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/worksheet/_writer.py", line 98, in write_top
    self.write_properties()
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/worksheet/_writer.py", line 60, in write_properties
    self.xf.send(props.to_tree())
  File "/Users/a/e/lib/python3.6/site-packages/openpyxl/worksheet/_writer.py", line 294, in get_stream
    xf.write(el)
  File "src/lxml/serializer.pxi", line 1652, in lxml.etree._IncrementalFileWriter.write
TypeError: got invalid input value of type <class 'xml.etree.ElementTree.Element'>, expected string or Element

The script works, as a workaround, when called with OPENPYXL_LXML=0 or OPENPYXL_DEFUSEDXML=0 in the environment.

My guess is that the commit below introduced the breaking change.

https://bitbucket.org/openpyxl/openpyxl/commits/5b1290f571af7e6f93c3417bbb679d735a67c1c1?at=3.0.2

When both LXML and DEFUSEDXML are True, the if on line 50 leads to a setup where lxml is used with objects from xml.etree.

Note: I am using Python 3.6.5, lxml 4.4.2 and defusedxml 0.6.0 on macOS.

Comments (13)

  1. CharlieC

    Thanks for the report. Yes, it is broken because defusedxml deprecated their support for lxml, which led to lots of people complaining about the warnings. I tried to fix this by defaulting to the standard library.

    It’s going to take a while to fix properly this so in the meantime you’ll have to stick with 3.0.1 or remove defusedxml.

  2. Alexis Fouilhé reporter

    @CharlieC I do confirm that branch 3.0 has the issue fixed. Thank you!

    As @Michael Hooreman said, having the fix released would be great, so that I can unpin openpyxl to 3.0.1.

  3. Log in to comment