Broken writer with lxml + defusedxml
Created originally on Bitbucket by alexisf (Alexis Fouilhé)
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.