From: W. Trevor King Date: Tue, 17 Jul 2012 11:32:33 +0000 (-0400) Subject: Stub out packed experiment (.pxp) reading. X-Git-Tag: v0.2~40 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=d4799633bbd12ee4e6669a50180dd4900b015a8c;p=igor.git Stub out packed experiment (.pxp) reading. --- diff --git a/igor/packed.py b/igor/packed.py new file mode 100644 index 0000000..026f917 --- /dev/null +++ b/igor/packed.py @@ -0,0 +1,130 @@ +# Copyright + +from .struct import Structure as _Structure +from .struct import Field as _Field + +"Read IGOR Packed Experiment files files into records." + + +class Record (object): + def __init__(self, header, data): + self.header = header + self.data = data + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return '<{} {}>'.format(self.__class__.__name__, id(self)) + + +class UnknownRecord (Record): + def __repr__(self): + return '<{}-{} {}>'.format( + self.__class__.__name__, self.header['recordType'], id(self)) + + +class UnusedRecord (Record): + pass + + +class VariablesRecord (Record): + pass + + +class HistoryRecord (Record): + pass + + +class WaveRecord (Record): + pass + + +class RecreationRecord (Record): + pass + + +class ProcedureRecord (Record): + pass + + +class GetHistoryRecord (Record): + pass + + +class PackedFileRecord (Record): + pass + + +class FolderStartRecord (Record): + pass + + +class FolderEndRecord (Record): + pass + + +# From PackedFile.h +RECORD_TYPE = { + 0: UnusedRecord, + 1: VariablesRecord, + 2: HistoryRecord, + 3: WaveRecord, + 4: RecreationRecord, + 5: ProcedureRecord, + 6: UnusedRecord, + 7: GetHistoryRecord, + 8: PackedFileRecord, + 9: FolderStartRecord, + 10: FolderEndRecord, + } + +# Igor writes other kinds of records in a packed experiment file, for +# storing things like pictures, page setup records, and miscellaneous +# settings. The format for these records is quite complex and is not +# described in PTN003. If you are writing a program to read packed +# files, you must skip any record with a record type that is not +# listed above. + +PackedFileRecordHeader = _Structure( + name='PackedFileRecordHeader', + fields=[ + _Field('H', 'recordType', help='Record type plus superceded flag.'), + _Field('h', 'version', help='Version information depends on the type of record.'), + _Field('l', 'numDataBytes', help='Number of data bytes in the record following this record header.'), + ]) + +#CR_STR = '\x15' (\r) + +PACKEDRECTYPE_MASK = 0x7FFF # Record type = (recordType & PACKEDREC_TYPE_MASK) +SUPERCEDED_MASK = 0x8000 # Bit is set if the record is superceded by + # a later record in the packed file. + + +def load(filename, strict=True, ignore_unknown=True): + records = [] + if hasattr(filename, 'read'): + f = filename # filename is actually a stream object + else: + f = open(filename, 'rb') + try: + while True: + PackedFileRecordHeader.set_byte_order('=') + b = buffer(f.read(PackedFileRecordHeader.size)) + if not b: + break + header = PackedFileRecordHeader.unpack_dict_from(b) + data = f.read(header['numDataBytes']) + record_type = RECORD_TYPE.get( + header['recordType'] & PACKEDRECTYPE_MASK, UnknownRecord) + if record_type in [UnknownRecord, UnusedRecord + ] and not ignore_unknown: + raise KeyError('unkown record type {}'.format( + header['recordType'])) + records.append(record_type(header, data)) + finally: + if not hasattr(filename, 'read'): + f.close() + + return records + diff --git a/test/data/README b/test/data/README index 4f621bf..7ec9646 100644 --- a/test/data/README +++ b/test/data/README @@ -1 +1,4 @@ .ibw samples are from TN003.zip. + +polar-graphs-demo.pxp was distributed with IGOR Pro 5.04 as + Examples/Graphing Techniques/Obsolete/Polar Graphs Demo.pxp diff --git a/test/data/polar-graphs-demo.pxp b/test/data/polar-graphs-demo.pxp new file mode 100644 index 0000000..63e03cc Binary files /dev/null and b/test/data/polar-graphs-demo.pxp differ diff --git a/test/test.py b/test/test.py index bd508c0..efe7019 100644 --- a/test/test.py +++ b/test/test.py @@ -1,6 +1,6 @@ r"""Test the igor module by loading sample files. ->>> dump('mac-double.ibw', strict=False) # doctest: +REPORT_UDIFF +>>> dumpibw('mac-double.ibw', strict=False) # doctest: +REPORT_UDIFF array([ 5., 4., 3., 2., 1.]) {'checksum': 25137, 'note': '', @@ -40,7 +40,7 @@ array([ 5., 4., 3., 2., 1.]) 'xUnits': array(['', '', '', ''], dtype='|S1')} ->>> dump('mac-textWave.ibw') # doctest: +REPORT_UDIFF +>>> dumpibw('mac-textWave.ibw') # doctest: +REPORT_UDIFF array(['Mary', 'had', 'a', 'little', 'lamb'], dtype='|S6') {'checksum': 5554, @@ -106,7 +106,7 @@ array(['Mary', 'had', 'a', 'little', 'lamb'], 'whpad3': 0, 'whpad4': 0} ->>> dump('mac-version2.ibw', strict=False) # doctest: +REPORT_UDIFF +>>> dumpibw('mac-version2.ibw', strict=False) # doctest: +REPORT_UDIFF array([ 5., 4., 3., 2., 1.], dtype=float32) {'checksum': -16803, 'note': 'This is a test.', @@ -146,7 +146,7 @@ array([ 5., 4., 3., 2., 1.], dtype=float32) 'xUnits': array(['', '', '', ''], dtype='|S1')} ->>> dump('mac-version3Dependent.ibw', strict=False) # doctest: +REPORT_UDIFF +>>> dumpibw('mac-version3Dependent.ibw', strict=False) # doctest: +REPORT_UDIFF array([], dtype=int8) {'checksum': 0, 'formula': '', @@ -188,7 +188,7 @@ array([], dtype=int8) 'xUnits': array(['', '', '', ''], dtype='|S1')} ->>> dump('mac-version5.ibw') # doctest: +REPORT_UDIFF +>>> dumpibw('mac-version5.ibw') # doctest: +REPORT_UDIFF array([ 5., 4., 3., 2., 1.], dtype=float32) {'checksum': -12033, 'dataEUnits': '', @@ -252,7 +252,7 @@ array([ 5., 4., 3., 2., 1.], dtype=float32) 'whpad3': 0, 'whpad4': 0} ->>> dump('mac-zeroPointWave.ibw') # doctest: +REPORT_UDIFF +>>> dumpibw('mac-zeroPointWave.ibw') # doctest: +REPORT_UDIFF array([], dtype=float32) {'checksum': -15649, 'dataEUnits': '', @@ -316,7 +316,7 @@ array([], dtype=float32) 'whpad3': 0, 'whpad4': 0} ->>> dump('win-double.ibw') # doctest: +REPORT_UDIFF +>>> dumpibw('win-double.ibw') # doctest: +REPORT_UDIFF array([ 5., 4., 3., 2., 1.]) {'checksum': 28962, 'note': '', @@ -356,7 +356,7 @@ array([ 5., 4., 3., 2., 1.]) 'xUnits': array(['', '', '', ''], dtype='|S1')} ->>> dump('win-textWave.ibw') # doctest: +REPORT_UDIFF +>>> dumpibw('win-textWave.ibw') # doctest: +REPORT_UDIFF array(['Mary', 'had', 'a', 'little', 'lamb'], dtype='|S6') {'checksum': 184, @@ -422,7 +422,7 @@ array(['Mary', 'had', 'a', 'little', 'lamb'], 'whpad3': 0, 'whpad4': 0} ->>> dump('win-version2.ibw') # doctest: +REPORT_UDIFF +>>> dumpibw('win-version2.ibw') # doctest: +REPORT_UDIFF array([ 5., 4., 3., 2., 1.], dtype=float32) {'checksum': 1047, 'note': 'This is a test.', @@ -462,7 +462,7 @@ array([ 5., 4., 3., 2., 1.], dtype=float32) 'xUnits': array(['', '', '', ''], dtype='|S1')} ->>> dump('win-version5.ibw') # doctest: +REPORT_UDIFF +>>> dumpibw('win-version5.ibw') # doctest: +REPORT_UDIFF array([ 5., 4., 3., 2., 1.], dtype=float32) {'checksum': 13214, 'dataEUnits': '', @@ -526,7 +526,7 @@ array([ 5., 4., 3., 2., 1.], dtype=float32) 'whpad3': 0, 'whpad4': 0} ->>> dump('win-zeroPointWave.ibw') # doctest: +REPORT_UDIFF +>>> dumpibw('win-zeroPointWave.ibw') # doctest: +REPORT_UDIFF array([], dtype=float32) {'checksum': 27541, 'dataEUnits': '', @@ -589,6 +589,110 @@ array([], dtype=float32) 'whpad2': 0, 'whpad3': 0, 'whpad4': 0} + +>>> dumppxp('polar-graphs-demo.pxp') # doctest: +REPORT_UDIFF, +ELLIPSIS +record 0: + +record 1: + +record 2: + +record 3: + +record 4: + +record 5: + +record 6: + +record 7: + +record 8: + +record 9: + +record 10: + +record 11: + +record 12: + +record 13: + +record 14: + +record 15: + +record 16: + +record 17: + +record 18: + +record 19: + +record 20: + +record 21: + +record 22: + +record 23: + +record 24: + +record 25: + +record 26: + +record 27: + +record 28: + +record 29: + +record 30: + +record 31: + +record 32: + +record 33: + +record 34: + +record 35: + +record 36: + +record 37: + +record 38: + +record 39: + +record 40: + +record 41: + +record 42: + +record 43: + +record 44: + +record 45: + +record 46: + +record 47: + +record 48: + +record 49: + +record 50: + """ import os.path @@ -596,12 +700,13 @@ from pprint import pformat import sys from igor.binarywave import loadibw +from igor.packed import load as loadpxp _this_dir = os.path.dirname(__file__) _data_dir = os.path.join(_this_dir, 'data') -def dump(filename, strict=True): +def dumpibw(filename, strict=True): sys.stderr.write('Testing {}\n'.format(filename)) path = os.path.join(_data_dir, filename) data,bin_info,wave_info = loadibw(path, strict=strict) @@ -609,6 +714,14 @@ def dump(filename, strict=True): pprint(bin_info) pprint(wave_info) +def dumppxp(filename, strict=True): + sys.stderr.write('Testing {}\n'.format(filename)) + path = os.path.join(_data_dir, filename) + records = loadpxp(path, strict=strict) + for i,record in enumerate(records): + print('record {}:'.format(i)) + pprint(record) + def pprint(data): lines = pformat(data).splitlines() print('\n'.join([line.rstrip() for line in lines]))