Do not write shed_tool_data_table_config in place

This should prevent errors such as:
```
galaxy.util ERROR 2017-11-17 09:20:12,842 Error parsing file /data/users/mvandenb/gx/config/shed_tool_data_table_conf.xml
Traceback (most recent call last):
  File "lib/galaxy/util/__init__.py", line 217, in parse_xml
    root = tree.parse(fname, parser=ElementTree.XMLParser(target=DoctypeSafeCallbackTarget()))
  File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 657, in parse
    self._root = parser.close()
  File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 1654, in close
    self._raiseerror(v)
  File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 1506, in _raiseerror
    raise err
ParseError: no element found: line 1, column 0
```
reported in https://github.com/galaxyproject/galaxy/issues/5031.
This commit is contained in:
mvdbeek
2017-11-30 13:47:38 +01:00
parent a82d325d18
commit 562ea1d5e2
2 changed files with 44 additions and 1 deletions
+2 -1
View File
@@ -21,6 +21,7 @@ import requests
from galaxy import util
from galaxy.util.dictifiable import Dictifiable
from galaxy.util.odict import odict
from galaxy.util.renamed_temporary_file import RenamedTemporaryFile
log = logging.getLogger(__name__)
@@ -186,7 +187,7 @@ class ToolDataTableManager(object):
# add new elems
out_elems.extend(new_elems)
out_path_is_new = not os.path.exists(full_path)
with open(full_path, 'wb') as out:
with RenamedTemporaryFile(full_path) as out:
out.write('<?xml version="1.0"?>\n<tables>\n')
for elem in out_elems:
out.write(util.xml_to_string(elem, pretty=True))
+42
View File
@@ -0,0 +1,42 @@
"""Safely write file to temporary file and then move file into place."""
# Copied from https://stackoverflow.com/a/12007885.
import os
import tempfile
class RenamedTemporaryFile(object):
"""
A temporary file object which will be renamed to the specified
path on exit.
"""
def __init__(self, final_path, **kwargs):
tmpfile_dir = kwargs.pop('dir', None)
# Put temporary file in the same directory as the location for the
# final file so that an atomic move into place can occur.
if tmpfile_dir is None:
tmpfile_dir = os.path.dirname(final_path)
self.tmpfile = tempfile.NamedTemporaryFile(dir=tmpfile_dir, **kwargs)
self.final_path = final_path
def __getattr__(self, attr):
"""
Delegate attribute access to the underlying temporary file object.
"""
return getattr(self.tmpfile, attr)
def __enter__(self):
self.tmpfile.__enter__()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
self.tmpfile.delete = False
result = self.tmpfile.__exit__(exc_type, exc_val, exc_tb)
os.rename(self.tmpfile.name, self.final_path)
else:
result = self.tmpfile.__exit__(exc_type, exc_val, exc_tb)
return result