Skip to content

Commit

Permalink
Do not write shed_tool_data_table_config in place
Browse files Browse the repository at this point in the history
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 #5031.
  • Loading branch information
mvdbeek committed Dec 1, 2017
1 parent 4dd05fc commit f7820e8
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
3 changes: 2 additions & 1 deletion lib/galaxy/tools/data/__init__.py
Expand Up @@ -21,6 +21,7 @@
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__)

Expand Down Expand Up @@ -186,7 +187,7 @@ def to_xml_file(self, shed_tool_data_table_config, new_elems=None, remove_elems=
# 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))
Expand Down
42 changes: 42 additions & 0 deletions lib/galaxy/util/renamed_temporary_file.py
@@ -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

0 comments on commit f7820e8

Please sign in to comment.