From 181e101a605bdb9b628c6781abff7b3276aca635 Mon Sep 17 00:00:00 2001 From: wpbonelli Date: Mon, 16 Sep 2024 11:46:58 -0400 Subject: [PATCH] fix(binaryfile): accommodate windows drives for in-place reversal (#2312) The reverse() methods on HeadFile and CellBudgetFile would fail on an in-place reversal if the system temp dir occupied a different drive than the original file. Use shutil.move() instead of Path.replace() to accommodate the cross-drive move. --- flopy/utils/binaryfile.py | 66 +++++++++++++++++++----------------- flopy/utils/datafile.py | 2 +- flopy/utils/formattedfile.py | 6 ++-- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/flopy/utils/binaryfile.py b/flopy/utils/binaryfile.py index fb71410926..ce95d500f8 100644 --- a/flopy/utils/binaryfile.py +++ b/flopy/utils/binaryfile.py @@ -13,6 +13,7 @@ import tempfile import warnings from pathlib import Path +from shutil import move from typing import List, Optional, Union import numpy as np @@ -460,9 +461,9 @@ class BinaryLayerFile(LayerFile): """ def __init__( - self, filename: Union[str, os.PathLike], precision, verbose, kwargs + self, filename: Union[str, os.PathLike], precision, verbose, **kwargs ): - super().__init__(filename, precision, verbose, kwargs) + super().__init__(filename, precision, verbose, **kwargs) def _build_index(self): """ @@ -661,7 +662,7 @@ def __init__( self.header_dtype = BinaryHeader.set_dtype( bintype="Head", precision=precision ) - super().__init__(filename, precision, verbose, kwargs) + super().__init__(filename, precision, verbose, **kwargs) def reverse(self, filename: Optional[os.PathLike] = None): """ @@ -733,10 +734,18 @@ def reverse_header(header): header["pertim"] = perlen - header["pertim"] return header - # reverse record order and write to temporary file - temp_dir_path = Path(tempfile.gettempdir()) - temp_file_path = temp_dir_path / filename.name - with open(temp_file_path, "wb") as f: + target = filename + + # if rewriting the same file, write + # temp file then copy it into place + inplace = filename == self.filename + if inplace: + temp_dir_path = Path(tempfile.gettempdir()) + temp_file_path = temp_dir_path / filename.name + target = temp_file_path + + # reverse record order + with open(target, "wb") as f: for i in range(len(self) - 1, -1, -1): header = self.recordarray[i].copy() header = reverse_header(header) @@ -752,16 +761,10 @@ def reverse_header(header): ilay=ilay, ) - # if we're rewriting the original file, close it first - if filename == self.filename: - self.close() - - # move temp file to destination - temp_file_path.replace(filename) - # if we rewrote the original file, reinitialize - if filename == self.filename: - super().__init__(self.filename, self.precision, self.verbose, {}) + if inplace: + move(target, filename) + super().__init__(filename, self.precision, self.verbose) class UcnFile(BinaryLayerFile): @@ -828,7 +831,7 @@ def __init__( self.header_dtype = BinaryHeader.set_dtype( bintype="Ucn", precision=precision ) - super().__init__(filename, precision, verbose, kwargs) + super().__init__(filename, precision, verbose, **kwargs) return @@ -898,7 +901,7 @@ def __init__( self.header_dtype = BinaryHeader.set_dtype( bintype="Head", precision=precision ) - super().__init__(filename, precision, verbose, kwargs) + super().__init__(filename, precision, verbose, **kwargs) def _get_data_array(self, totim=0.0): """ @@ -2325,10 +2328,17 @@ def reverse(self, filename: Optional[os.PathLike] = None): # get number of records nrecords = len(self) - # open backward budget file - temp_dir_path = Path(tempfile.gettempdir()) - temp_file_path = temp_dir_path / filename.name - with open(temp_file_path, "wb") as f: + target = filename + + # if rewriting the same file, write + # temp file then copy it into place + inplace = filename == self.filename + if inplace: + temp_dir_path = Path(tempfile.gettempdir()) + temp_file_path = temp_dir_path / filename.name + target = temp_file_path + + with open(target, "wb") as f: # loop over budget file records in reverse order for idx in range(nrecords - 1, -1, -1): # load header array @@ -2415,13 +2425,7 @@ def reverse(self, filename: Optional[os.PathLike] = None): # Write data data.tofile(f) - # if we're rewriting the original file, close it first - if filename == self.filename: - self.close() - - # move temp file to destination - temp_file_path.replace(filename) - # if we rewrote the original file, reinitialize - if filename == self.filename: - self.__init__(self.filename, self.precision, self.verbose) + if inplace: + move(target, filename) + self.__init__(filename, self.precision, self.verbose) diff --git a/flopy/utils/datafile.py b/flopy/utils/datafile.py index ca922c516e..5c32b72920 100644 --- a/flopy/utils/datafile.py +++ b/flopy/utils/datafile.py @@ -157,7 +157,7 @@ class LayerFile: """ def __init__( - self, filename: Union[str, os.PathLike], precision, verbose, kwargs + self, filename: Union[str, os.PathLike], precision, verbose, **kwargs ): from ..discretization.structuredgrid import StructuredGrid diff --git a/flopy/utils/formattedfile.py b/flopy/utils/formattedfile.py index ca9436ed21..8d87cf6464 100644 --- a/flopy/utils/formattedfile.py +++ b/flopy/utils/formattedfile.py @@ -110,8 +110,8 @@ class FormattedLayerFile(LayerFile): """ - def __init__(self, filename, precision, verbose, kwargs): - super().__init__(filename, precision, verbose, kwargs) + def __init__(self, filename, precision, verbose, **kwargs): + super().__init__(filename, precision, verbose, **kwargs) def _build_index(self): """ @@ -376,7 +376,7 @@ def __init__( **kwargs, ): self.text = text - super().__init__(filename, precision, verbose, kwargs) + super().__init__(filename, precision, verbose, **kwargs) def _get_text_header(self): """