Merge branch 'util_open' into 'development'

centralize opening of text files

See merge request damask/DAMASK!555
This commit is contained in:
Philip Eisenlohr 2022-03-27 17:10:31 +00:00
commit 1f98b04d44
6 changed files with 38 additions and 31 deletions

View File

@ -2,7 +2,6 @@ import os
import json
import functools
import colorsys
from pathlib import Path
from typing import Union, TextIO
import numpy as np
@ -325,12 +324,7 @@ class Colormap(mpl.colors.ListedColormap):
File handle with write access.
"""
if fname is None:
return open(self.name.replace(' ','_')+suffix, 'w', newline='\n')
elif isinstance(fname, (str, Path)):
return open(Path(fname).expanduser(), 'w', newline='\n')
else:
return fname
return util.open_text(self.name.replace(' ','_')+suffix if fname is None else fname, 'w')
def save_paraview(self,

View File

@ -2,7 +2,6 @@ import copy
from io import StringIO
from collections.abc import Iterable
import abc
from pathlib import Path
from typing import Union, Dict, Any, Type, TypeVar
import numpy as np
@ -10,6 +9,7 @@ import yaml
from ._typehints import FileHandle
from . import Rotation
from . import util
MyType = TypeVar('MyType', bound='Config')
@ -144,10 +144,7 @@ class Config(dict):
Configuration from file.
"""
fhandle = open(Path(fname).expanduser(),newline='\n') if isinstance(fname, (str, Path)) else \
fname
return cls(yaml.safe_load(fhandle))
return cls(yaml.safe_load(util.open_text(fname)))
def save(self,
fname: FileHandle,
@ -163,9 +160,6 @@ class Config(dict):
Keyword arguments parsed to yaml.dump.
"""
fhandle = open(Path(fname).expanduser(),'w',newline='\n') if isinstance(fname, (str, Path)) else \
fname
if 'width' not in kwargs:
kwargs['width'] = 256
if 'default_flow_style' not in kwargs:
@ -173,6 +167,7 @@ class Config(dict):
if 'sort_keys' not in kwargs:
kwargs['sort_keys'] = False
fhandle = util.open_text(fname,'w')
try:
fhandle.write(yaml.dump(self,Dumper=NiceDumper,**kwargs))
except TypeError: # compatibility with old pyyaml

View File

@ -1538,7 +1538,7 @@ class Result:
np.prod(shape))}
data_items[-1].text = f'{os.path.split(self.fname)[1]}:{name}'
with open(self.fname.with_suffix('.xdmf').name,'w',newline='\n') as f:
with util.open_text(self.fname.with_suffix('.xdmf').name,'w') as f:
f.write(xml.dom.minidom.parseString(ET.tostring(xdmf).decode()).toprettyxml())
@ -1803,7 +1803,7 @@ class Result:
if type(obj) == h5py.Dataset and _match(output,[name]):
d = obj.attrs['description'] if h5py3 else obj.attrs['description'].decode()
if not Path(name).exists() or overwrite:
with open(name,'w',newline='\n') as f_out: f_out.write(obj[0].decode())
with util.open_text(name,'w') as f_out: f_out.write(obj[0].decode())
print(f'Exported {d} to "{name}".')
else:
print(f'"{name}" exists, {d} not exported.')

View File

@ -1,6 +1,5 @@
import re
import copy
from pathlib import Path
from typing import Union, Tuple, List
import pandas as pd
@ -260,7 +259,7 @@ class Table:
Table data from file.
"""
f = open(Path(fname).expanduser(),newline='\n') if isinstance(fname, (str, Path)) else fname
f = util.open_text(fname)
f.seek(0)
comments = []
@ -281,7 +280,7 @@ class Table:
else:
shapes[label] = (1,)
data = pd.read_csv(f,names=list(range(len(labels))),sep=r'\s+',lineterminator='\n')
data = pd.read_csv(f,names=list(range(len(labels))),sep=r'\s+')
return Table(shapes,data,comments)
@ -312,7 +311,7 @@ class Table:
Table data from file.
"""
f = open(Path(fname).expanduser(),newline='\n') if isinstance(fname, (str, Path)) else fname
f = util.open_text(fname)
f.seek(0)
content = f.readlines()
@ -594,7 +593,7 @@ class Table:
labels += [f'{util.srepr(self.shapes[l],"x")}:{i+1}_{l}' \
for i in range(np.prod(self.shapes[l]))]
f = open(Path(fname).expanduser(),'w',newline='\n') if isinstance(fname, (str, Path)) else fname
f = util.open_text(fname,'w')
f.write('\n'.join([f'# {c}' for c in self.comments] + [' '.join(labels)])+('\n' if labels else ''))
self.data.to_csv(f,sep=' ',na_rep='nan',index=False,header=False,line_terminator='\n')

View File

@ -10,20 +10,21 @@ import signal
import fractions
from collections import abc
from functools import reduce, partial
from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any, Collection
from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any, Collection, TextIO
from pathlib import Path
import numpy as np
import h5py
from . import version
from ._typehints import FloatSequence, NumpyRngSeed, IntCollection
from ._typehints import FloatSequence, NumpyRngSeed, IntCollection, FileHandle
# limit visibility
__all__=[
'srepr',
'emph', 'deemph', 'warn', 'strikeout',
'run',
'open_text',
'natural_sort',
'show_progress',
'scale_to_coprime',
@ -206,7 +207,25 @@ def run(cmd: str,
return stdout, stderr
execute = run
def open_text(fname: FileHandle,
mode: Literal['r','w'] = 'r') -> TextIO:
"""
Open a text file.
Parameters
----------
fname : file, str, or pathlib.Path
Name or handle of file.
mode: {'r','w'}, optional
Access mode: 'r'ead or 'w'rite, defaults to 'r'.
Returns
-------
f : file handle
"""
return fname if not isinstance(fname, (str,Path)) else \
open(Path(fname).expanduser(),mode,newline=('\n' if mode == 'w' else None))
def natural_sort(key: str) -> List[Union[int, str]]:

View File

@ -12,19 +12,19 @@ from damask import util
class TestUtil:
@pytest.mark.xfail(sys.platform == 'win32', reason='echo is not a Windows command')
def test_execute_direct(self):
out,err = util.execute('echo test')
def test_run_direct(self):
out,err = util.run('echo test')
assert out=='test\n' and err==''
@pytest.mark.xfail(sys.platform == 'win32', reason='echo is not a Windows command')
def test_execute_env(self):
out,err = util.execute('sh -c "echo $test_for_execute"',env={'test_for_execute':'test'})
def test_run_env(self):
out,err = util.run('sh -c "echo $test_for_execute"',env={'test_for_execute':'test'})
assert out=='test\n' and err==''
@pytest.mark.xfail(sys.platform == 'win32', reason='false is not a Windows command')
def test_execute_runtime_error(self):
def test_run_runtime_error(self):
with pytest.raises(RuntimeError):
util.execute('false')
util.run('false')
@pytest.mark.parametrize('input,output',
[