2022-10-20 15:23:15 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
from pathlib import Path
|
|
|
|
import struct
|
|
|
|
|
|
|
|
from ..Qt import QtCore
|
|
|
|
from .asciireader import QAsciiReader
|
|
|
|
from .hdfreader import QHdfViewer
|
|
|
|
from .bdsreader import QBDSReader
|
|
|
|
from .gracereader import QGraceReader
|
|
|
|
from .dscreader import QDSCReader
|
|
|
|
from .nmrreader import QNMRReader
|
|
|
|
|
|
|
|
|
|
|
|
class QFileReader(QtCore.QObject):
|
|
|
|
data_read = QtCore.pyqtSignal([list], [dict])
|
|
|
|
|
|
|
|
def __init__(self, manager=None):
|
|
|
|
QtCore.QObject.__init__(self)
|
|
|
|
|
|
|
|
self.select = 'all'
|
|
|
|
self.data = []
|
|
|
|
self.filenames = None
|
|
|
|
self.extensions = set()
|
|
|
|
|
|
|
|
self.reader = {}
|
|
|
|
|
|
|
|
for ext, reader in [
|
|
|
|
('txt', QAsciiReader), ('dsc', QDSCReader), ('agr', QGraceReader),
|
|
|
|
('bds', QBDSReader), ('hdf', QHdfViewer), ('nmr', QNMRReader)
|
|
|
|
]:
|
|
|
|
self.register(ext, reader)
|
|
|
|
|
2022-10-20 15:23:15 +00:00
|
|
|
def __call__(self, files: list[str] | str) -> list:
|
2022-03-08 09:27:40 +00:00
|
|
|
self.data = []
|
|
|
|
if isinstance(files, str):
|
|
|
|
self.filenames = [files]
|
|
|
|
else:
|
|
|
|
self.filenames = files
|
|
|
|
|
|
|
|
return self.readfiles(files)
|
|
|
|
|
2022-10-20 15:23:15 +00:00
|
|
|
def readfiles(self, fname: list[str] | str) -> list:
|
2022-11-28 14:10:07 +00:00
|
|
|
# clear old data
|
|
|
|
self.data = []
|
|
|
|
|
2022-03-08 09:27:40 +00:00
|
|
|
if not isinstance(fname, list):
|
|
|
|
fname = [fname]
|
|
|
|
|
|
|
|
for f in fname:
|
|
|
|
f = Path(f)
|
|
|
|
dtype = self.guess_type(f)
|
|
|
|
if dtype in self.reader:
|
|
|
|
r = self.reader[dtype]
|
|
|
|
else:
|
|
|
|
raise ValueError(f'Unknown type for file {f}')
|
|
|
|
|
2022-12-30 13:07:38 +00:00
|
|
|
try:
|
2022-03-08 09:27:40 +00:00
|
|
|
# If QAsciiReader.skip = True it accepts automatically and returns None
|
|
|
|
r(f).exec()
|
2023-01-14 16:05:29 +00:00
|
|
|
except ImportError:
|
2022-12-30 13:07:38 +00:00
|
|
|
pass
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
self.data_read.emit(self.data)
|
|
|
|
|
2022-12-30 13:07:38 +00:00
|
|
|
self.reader['txt'].skip = False
|
2022-03-08 09:27:40 +00:00
|
|
|
|
|
|
|
return self.data
|
|
|
|
|
|
|
|
def readtnt(self, fname):
|
|
|
|
""" Special treatment for tnt. If data is a single measurement, skip dialog """
|
|
|
|
raise NotImplementedError
|
|
|
|
# tntreader = self.reader[2]
|
|
|
|
# tntreader(fname)
|
|
|
|
# if not tntreader.reader.onedimensional:
|
|
|
|
# tntreader.exec()
|
|
|
|
|
|
|
|
@QtCore.pyqtSlot(list)
|
|
|
|
def _update_dic(self, other: list):
|
|
|
|
self.data.extend(other)
|
|
|
|
|
|
|
|
def register(self, key, new_reader):
|
|
|
|
if key in self.reader:
|
|
|
|
return self.reader[key]
|
|
|
|
r = new_reader()
|
|
|
|
self.reader[key] = r
|
|
|
|
r.data_read.connect(self._update_dic)
|
|
|
|
self.extensions.update(r.file_ext)
|
|
|
|
|
|
|
|
return r
|
|
|
|
|
|
|
|
def guess_type(self, fname: Path) -> str:
|
|
|
|
ext = fname.suffix.lower()
|
|
|
|
|
|
|
|
if ext in self.extensions:
|
|
|
|
if ext in ('.dat', '.txt'):
|
|
|
|
with fname.open('r', encoding='iso-8859-15') as fp:
|
|
|
|
line = fp.readline()
|
|
|
|
if line.strip().startswith('Filename: C:\\'):
|
|
|
|
return 'dsc'
|
|
|
|
|
|
|
|
return 'txt'
|
|
|
|
|
|
|
|
if ext in ('.h5', '.hdf', '.hdf5'):
|
|
|
|
return 'hdf'
|
|
|
|
|
|
|
|
if ext == '.eps':
|
|
|
|
return 'bds'
|
|
|
|
|
|
|
|
return ext[1:] # remove dot
|
|
|
|
|
|
|
|
else:
|
|
|
|
with fname.open('rb') as fp:
|
|
|
|
s16 = fp.read(16)
|
|
|
|
|
|
|
|
# copied from whichdb (Python 2.7) to look for magic value of dbhash
|
|
|
|
(magic,) = struct.unpack("=l", s16[-4:])
|
|
|
|
if magic in (0x00061561, 0x61150600):
|
|
|
|
return 'nmr'
|
|
|
|
|
|
|
|
else:
|
|
|
|
ret_types = ('nmr', 'bds', 'tnt', 'agr', 'dsc')
|
|
|
|
strings = (b'NMREVAL', b'NOVOCONTROL', b'TNT1.005', b'# Grace project', b'Filename:\tC:')
|
|
|
|
|
|
|
|
(magic,) = struct.unpack('<16s', s16)
|
|
|
|
for dtype, startstring in zip(ret_types, strings):
|
|
|
|
if magic.startswith(startstring):
|
|
|
|
return dtype
|
|
|
|
|
|
|
|
# nothing matched, text file is best guess
|
|
|
|
return 'txt'
|