File I/O improvements - safely closing PyARC files at all exit points
Currently, PyARC writes messages to files by saving open file objects as attributes in the UserObject. When PyARC crashes or aborts due to errors/exceptions, these files are left open, which seems to cause memory allocation issues. This is what I see when PyARC catches errors in the DASSH input via prechecks (it reports this for every open file):
/Users/matz/anaconda3/lib/python3.8/unittest/case.py:633: ResourceWarning: unclosed file <_io.TextIOWrapper name='warn_messages.txt' mode='w' encoding='UTF-8'>
method()
ResourceWarning: Enable tracemalloc to get the object allocation traceback
I propose that we add a "close_all()" method to the PyARC object. We would call this at every PyARC exit point, before any exceptions are raised that would abort PyARC execution. That way, all files can be closed safely.
To exemplify this, I'll use the DASSH precheck example. DASSH prechecks are to be called early within PyARC.execute. Here's a code snippet of the current implementation:
if calculations.dassh is not None:
if self.dassh:
self.user_object.invoke_dassh(True)
if self.dassh.precheck():
raise RuntimeError("Failed checking DASSH input")
What I'm envisioning is something like the following:
if calculations.dassh is not None:
if self.dassh:
self.user_object.invoke_dassh(True)
if self.dassh.precheck():
self.close_all() # closes self attributes: vers_msgs, err_msgs, warn_msgs, info_msgs, dakota_msgs
raise RuntimeError("Failed checking DASSH input")
An alternative is that we could write our own custom exception. For example, we could have a PyARC.raise_error()
method that first closes all open files, then raises the requested exception with the specified message:
def raise_exception_and_abort(self, exception, msg):
"""Raise Python exception and exit PyARC"""
self.vers_msgs.close()
self.err_msgs.close()
self.warn_msgs.close()
self.info_msgs.close()
self.dakota_msgs.close()
# ...
raise exception(msg)
Usage: self.raise_exception_and_abort(RuntimeError, "Failed checking DASSH input")
Thoughts?