Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 87 additions & 33 deletions bilby/core/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def _determine_file_name(filename, outdir, label, extension, gzip):
return result_file_name(outdir, label, extension, gzip)


def read_in_result(filename=None, outdir=None, label=None, extension='json', gzip=False, result_class=None):
def read_in_result(filename=None, outdir=None, label=None, extension=None, gzip=False, result_class=None):
""" Reads in a stored bilby result object

Parameters
Expand All @@ -92,33 +92,67 @@ def read_in_result(filename=None, outdir=None, label=None, extension='json', gzi
outdir, label, extension: str
Name of the output directory, label and extension used for the default
naming scheme.
extension: str, optional
The file extension to use. If not given, the extension is inferred from
the filename if provided. If the filename is not given, defaults to
'json'.
result_class: bilby.core.result.Result, or child of
The result class to use. By default, `bilby.core.result.Result` is used,
but objects which inherit from this class can be given providing
additional methods.
"""
filename = _determine_file_name(filename, outdir, label, extension, gzip)
filename = _determine_file_name(
filename, outdir, label, extension or "json", gzip
)

if result_class is None:
result_class = Result
elif not issubclass(result_class, Result):
raise ValueError(f"Input result_class={result_class} not understood")

# Get the actual extension (may differ from the default extension if the filename is given)
extension = os.path.splitext(filename)[1].lstrip('.')
if extension is None:
ext = os.path.splitext(filename)[1][1:]
extension = ext if ext else None
if extension == 'gz': # gzipped file
extension = os.path.splitext(os.path.splitext(filename)[0])[1].lstrip('.')

if 'json' in extension:
result = result_class.from_json(filename=filename)
elif ('hdf5' in extension) or ('h5' in extension):
result = result_class.from_hdf5(filename=filename)
elif ("pkl" in extension) or ("pickle" in extension):
result = result_class.from_pickle(filename=filename)
elif extension is None:
raise ValueError("No filetype extension provided")
else:
raise ValueError("Filetype {} not understood".format(extension))
if extension is None:
raise ValueError("No filetype extension provided and could not be inferred from filename")

extension = extension.lower()
read_functions = {
'json': result_class.from_json,
'hdf5': result_class.from_hdf5,
'h5': result_class.from_hdf5,
'pkl': result_class.from_pickle,
'pickle': result_class.from_pickle,
}
if extension not in read_functions:
raise ValueError(
f"Filetype {extension} not understood, known types are {list(read_functions.keys())}"
)

func = read_functions[extension]

# Raise IO errors since this is what the caching relies on
# Catch all other exceptions and raise a FileLoadError
try:
result = func(filename=filename)
except IOError as e:
raise IOError(
f"Failed to read in file {filename} using "
f"`{result_class.__name__}.{func.__name__}` "
f"(extension={extension}). "
"This is likely because the file does not exist or is not a valid bilby result."
f"The error was: {e}"
) from e
except Exception as e:
raise FileLoadError(
f"Failed to read in file {filename} using "
f"`{result_class.__name__}.{func.__name__}` "
f"(extension={extension}). The error was: {e}"
) from e
return result


Expand Down Expand Up @@ -777,7 +811,8 @@ def save_to_file(self, filename=None, overwrite=False, outdir=None,
Parameters
==========
filename: optional,
Filename to write to (overwrites the default)
Filename to write to (overwrites the default). Assumed to include the
file extension.
overwrite: bool, optional
Whether or not to overwrite an existing result file.
default=False
Expand All @@ -794,24 +829,39 @@ def save_to_file(self, filename=None, overwrite=False, outdir=None,

_outdir = None
if filename is not None:
_outdir, base_filename = os.path.split(filename)
# Overwrite the full filename with the base filename
# Well append the outdir later on
_outdir, filename = os.path.split(filename)
_outdir = None if _outdir == "" else _outdir
base, ext = os.path.splitext(base_filename)
if extension is None:
extension = ext[1:] if ext else "json"
filename = base_filename
elif extension is True:
message = "Result.save_to_file called with extension=True. "
if len(ext) > 0:
message += f"Overwriting extension to json from {ext}, this"
else:
message += "This"
message += " behaviour is deprecated and will be removed."
logger.warning(message)
extension = "json"
filename = base_filename
filename = f"{base}.{extension}"
if extension is None or extension is True:
_, ext = os.path.splitext(filename)
ext = ext[1:] if ext else None
# If the extension has not been set, try to infer it from the filename
# if not, it will fall back to the default
if ext in EXTENSIONS:
if extension is None:
logger.debug(
f"Inferred extension '{ext}' from filename '{filename}'. "
"Using this extension for saving."
)
extension = ext
elif ext != extension:
message = (
f"The specified extension '{ext}' "
f"does not match the provided extension '{extension}'. "
)
logger.warning(message)

if extension is None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're adding logging, it would be good to add an info like "No file extension specified, defaulting to JSON."

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I've added a couple more statements.

logger.info("No extension given, defaulting to JSON.")
extension = 'json'

if extension is True:
message = (
"Result.save_to_file called with extension=True. "
"This will default to json, and ignore the extension from the filename. "
"This behaviour is deprecated and will be removed. "
)
logger.warning(message)
extension = 'json'

outdir = _outdir if outdir is None else outdir
Expand Down Expand Up @@ -845,13 +895,13 @@ def save_to_file(self, filename=None, overwrite=False, outdir=None,
else:
with open(output_path, 'w') as file:
json.dump(dictionary, file, indent=2, cls=BilbyJsonEncoder)
elif extension == 'hdf5':
elif extension in ['hdf5', 'h5']:
import h5py
dictionary["__module__"] = self.__module__
dictionary["__name__"] = self.__class__.__name__
with h5py.File(output_path, 'w') as h5file:
recursively_save_dict_contents_to_group(h5file, '/', dictionary)
elif extension == 'pkl':
elif extension in ['pkl', 'pickle']:
safe_file_dump(self, output_path, "dill")
else:
raise ValueError(f"Extension type {extension} not understood")
Expand Down Expand Up @@ -2291,3 +2341,7 @@ class ResultListError(ResultError):

class FileMovedError(ResultError):
""" Exceptions that occur when files have been moved """


class FileLoadError(ResultError):
""" Exceptions that occur when files cannot be loaded """
Loading
Loading