Search code examples
pythonxmlelementtree

"TypeError: write() argument must be str, not bytes" when trying to write an ElementTree to an XML file


I'm trying to write some XML as a byte string (to wit, a response from the Zillow API) to an XML file using the ElementTree.write method. Here is an example of what I'm trying to do:

from xml.etree import ElementTree

content = b'<?xml version="1.0" encoding="utf-8"?><Comps:comps xsi:schemaLocation="http://www.zillow.com/static/xsd/Comps.xsd https://www.zillowstatic.com/vstatic/b20c067/static/xsd/Comps.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:Comps="http://www.zillow.com/static/xsd/Comps.xsd"><request><zpid>48789177</zpid><count>1</count></request><message><text>Request successfully processed</text><code>0</code></message><response><properties><principal><zpid>48789177</zpid><links><homedetails>https://www.zillow.com/homedetails/1614-E-Columbia-St-Seattle-WA-98122/48789177_zpid/</homedetails><graphsanddata>http://www.zillow.com/homedetails/1614-E-Columbia-St-Seattle-WA-98122/48789177_zpid/#charts-and-data</graphsanddata><mapthishome>http://www.zillow.com/homes/48789177_zpid/</mapthishome><comparables>http://www.zillow.com/homes/comps/48789177_zpid/</comparables></links><address><street>1614 E Columbia St</street><zipcode>98122</zipcode><city>SEATTLE</city><state>WA</state><latitude>47.609388</latitude><longitude>-122.310834</longitude></address><taxAssessmentYear>2016</taxAssessmentYear><taxAssessment>528000.0</taxAssessment><yearBuilt>1907</yearBuilt><lotSizeSqFt>2613</lotSizeSqFt><finishedSqFt>2430</finishedSqFt><bathrooms>2.0</bathrooms><bedrooms>4</bedrooms><zestimate><amount currency="USD">900186</amount><last-updated>04/13/2018</last-updated><oneWeekChange deprecated="true"></oneWeekChange><valueChange duration="30" currency="USD">112285</valueChange><valuationRange><low currency="USD">783162</low><high currency="USD">1053218</high></valuationRange><percentile>90</percentile></zestimate><localRealEstate><region name="Minor" id="271921" type="neighborhood"><zindexValue>588,800</zindexValue><links><overview>http://www.zillow.com/local-info/WA-Seattle/Minor/r_271921/</overview><forSaleByOwner>http://www.zillow.com/minor-seattle-wa/fsbo/</forSaleByOwner><forSale>http://www.zillow.com/minor-seattle-wa/</forSale></links></region></localRealEstate></principal><comparables><comp score="7.0"><zpid>89822967</zpid><links><homedetails>https://www.zillow.com/homedetails/1711-E-Fir-St-Seattle-WA-98122/89822967_zpid/</homedetails><graphsanddata>http://www.zillow.com/homedetails/1711-E-Fir-St-Seattle-WA-98122/89822967_zpid/#charts-and-data</graphsanddata><mapthishome>http://www.zillow.com/homes/89822967_zpid/</mapthishome><comparables>http://www.zillow.com/homes/comps/89822967_zpid/</comparables></links><address><street>1711 E Fir St</street><zipcode>98122</zipcode><city>SEATTLE</city><state>WA</state><latitude>47.602463</latitude><longitude>-122.309743</longitude></address><taxAssessmentYear>2016</taxAssessmentYear><taxAssessment>513000.0</taxAssessment><yearBuilt>2008</yearBuilt><lotSizeSqFt>1306</lotSizeSqFt><finishedSqFt>1490</finishedSqFt><bathrooms>3.0</bathrooms><bedrooms>3</bedrooms><lastSoldDate>03/15/2018</lastSoldDate><lastSoldPrice currency="USD">783000</lastSoldPrice><zestimate><amount currency="USD">791686</amount><last-updated>04/13/2018</last-updated><oneWeekChange deprecated="true"></oneWeekChange><valueChange duration="30" currency="USD">-8370</valueChange><valuationRange><low currency="USD">752102</low><high currency="USD">831270</high></valuationRange><percentile>87</percentile></zestimate><localRealEstate><region name="Minor" id="271921" type="neighborhood"><zindexValue>588,800</zindexValue><links><overview>http://www.zillow.com/local-info/WA-Seattle/Minor/r_271921/</overview><forSaleByOwner>http://www.zillow.com/minor-seattle-wa/fsbo/</forSaleByOwner><forSale>http://www.zillow.com/minor-seattle-wa/</forSale></links></region></localRealEstate></comp></comparables></properties></response></Comps:comps><!-- H:042  T:99ms  S:2011  R:Sun Apr 15 09:01:05 PDT 2018  B:5.0.53029.1-hotfix_ADAT-2519.69881bc~hotfix-platform-for-2018-04-11.319b04e -->'
root = ElementTree.fromstring(content)
tree = ElementTree.ElementTree(root)

with open(f"comparables.xml", 'w+') as fp:
    tree.write(fp)

However, if I run this (in iPython) I get a TypeError:

In [3]: exec(open('zillow_api.py').read())
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-23b53830497c> in <module>()
----> 1 exec(open('zillow_api.py').read())

<string> in <module>()

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/xml/etree/ElementTree.py in write(self, file_or_filename, encoding, xml_declaration, default_namespace, method, short_empty_elements)
    774                 serialize = _serialize[method]
    775                 serialize(write, self._root, qnames, namespaces,
--> 776                           short_empty_elements=short_empty_elements)
    777 
    778     def write_c14n(self, file):

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/contextlib.py in __exit__(self, type, value, traceback)
     86         if type is None:
     87             try:
---> 88                 next(self.gen)
     89             except StopIteration:
     90                 return False

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/xml/etree/ElementTree.py in _get_writer(file_or_filename, encoding)
    833                 # destroyed
    834                 stack.callback(file.detach)
--> 835                 yield file.write
    836 
    837 def _namespaces(elem, default_namespace=None):

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/contextlib.py in __exit__(self, *exc_details)
    378                 # set-up context
    379                 fixed_ctx = exc_details[1].__context__
--> 380                 raise exc_details[1]
    381             except BaseException:
    382                 exc_details[1].__context__ = fixed_ctx

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/contextlib.py in __exit__(self, *exc_details)
    363             cb = self._exit_callbacks.pop()
    364             try:
--> 365                 if cb(*exc_details):
    366                     suppressed_exc = True
    367                     pending_raise = False

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/contextlib.py in _exit_wrapper(exc_type, exc, tb)
    312         """
    313         def _exit_wrapper(exc_type, exc, tb):
--> 314             callback(*args, **kwds)
    315         # We changed the signature, so using @wraps is not appropriate, but
    316         # setting __wrapped__ may still help with introspection

TypeError: write() argument must be str, not bytes

Is what I'm passing in not a "file object opened for writing" as specified in the docs?

I've tried following the solution in ElementTree TypeError "write() argument must be str, not bytes" in Python3, but the tostring method appears to no longer be contained in the xml.etree module.


Solution

  • It turns out that the argument to tree.write() should just be the name of the file you want to create:

    tree.write("comparables.xml")
    

    which creates comparables.xml in my current directory.