Stub out packed experiment (.pxp) reading.
authorW. Trevor King <wking@tremily.us>
Tue, 17 Jul 2012 11:32:33 +0000 (07:32 -0400)
committerW. Trevor King <wking@tremily.us>
Tue, 17 Jul 2012 11:32:33 +0000 (07:32 -0400)
igor/packed.py [new file with mode: 0644]
test/data/README
test/data/polar-graphs-demo.pxp [new file with mode: 0644]
test/test.py

diff --git a/igor/packed.py b/igor/packed.py
new file mode 100644 (file)
index 0000000..026f917
--- /dev/null
@@ -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
+
index 4f621bf4e0fc6c9e5430ad7b7326c5f391a9f1fb..7ec964614e4bdc40818dff25a75eaff03438e72d 100644 (file)
@@ -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 (file)
index 0000000..63e03cc
Binary files /dev/null and b/test/data/polar-graphs-demo.pxp differ
index bd508c0ea6c62dadc2c3b2ac99c677945a44ca76..efe701934b849121d8dc5bb7c7e08f38251061b4 100644 (file)
@@ -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:
+<UnknownRecord-11 ...>
+record 1:
+<UnknownRecord-12 ...>
+record 2:
+<UnknownRecord-13 ...>
+record 3:
+<UnknownRecord-13 ...>
+record 4:
+<UnknownRecord-13 ...>
+record 5:
+<UnknownRecord-13 ...>
+record 6:
+<UnknownRecord-13 ...>
+record 7:
+<UnknownRecord-13 ...>
+record 8:
+<UnknownRecord-13 ...>
+record 9:
+<UnknownRecord-14 ...>
+record 10:
+<UnknownRecord-15 ...>
+record 11:
+<UnknownRecord-16 ...>
+record 12:
+<UnknownRecord-16 ...>
+record 13:
+<UnknownRecord-17 ...>
+record 14:
+<UnknownRecord-17 ...>
+record 15:
+<UnknownRecord-17 ...>
+record 16:
+<UnknownRecord-17 ...>
+record 17:
+<UnknownRecord-17 ...>
+record 18:
+<UnknownRecord-17 ...>
+record 19:
+<UnknownRecord-16 ...>
+record 20:
+<UnknownRecord-17 ...>
+record 21:
+<UnknownRecord-17 ...>
+record 22:
+<UnknownRecord-17 ...>
+record 23:
+<UnknownRecord-17 ...>
+record 24:
+<UnknownRecord-17 ...>
+record 25:
+<UnknownRecord-17 ...>
+record 26:
+<UnknownRecord-18 ...>
+record 27:
+<UnknownRecord-11 ...>
+record 28:
+<UnknownRecord-26 ...>
+record 29:
+<UnknownRecord-26 ...>
+record 30:
+<VariablesRecord ...>
+record 31:
+<HistoryRecord ...>
+record 32:
+<WaveRecord ...>
+record 33:
+<WaveRecord ...>
+record 34:
+<WaveRecord ...>
+record 35:
+<WaveRecord ...>
+record 36:
+<WaveRecord ...>
+record 37:
+<WaveRecord ...>
+record 38:
+<WaveRecord ...>
+record 39:
+<WaveRecord ...>
+record 40:
+<FolderStartRecord ...>
+record 41:
+<FolderStartRecord ...>
+record 42:
+<VariablesRecord ...>
+record 43:
+<FolderEndRecord ...>
+record 44:
+<FolderStartRecord ...>
+record 45:
+<VariablesRecord ...>
+record 46:
+<FolderEndRecord ...>
+record 47:
+<FolderEndRecord ...>
+record 48:
+<RecreationRecord ...>
+record 49:
+<GetHistoryRecord ...>
+record 50:
+<ProcedureRecord ...>
 """
 
 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]))