class StaticStringField (_DynamicField):
_null_terminated = False
_array_size_field = None
+ def __init__(self, *args, **kwargs):
+ if 'array' not in kwargs:
+ kwargs['array'] = True
+ super(StaticStringField, self).__init__(*args, **kwargs)
+
def post_unpack(self, parents, data):
wave_structure = parents[-1]
wave_data = self._get_structure_data(parents, data, wave_structure)
_Field('l', 'formulaSize', help='The size of the dependency formula, if any.'),
_Field('l', 'noteSize', help='The size of the note text.'),
_Field('l', 'dataEUnitsSize', help='The size of optional extended data units.'),
- _Field('l', 'dimEUnitsSize', help='The size of optional extended dimension units.', count=MAXDIMS),
- _Field('l', 'dimLabelsSize', help='The size of optional dimension labels.', count=MAXDIMS),
+ _Field('l', 'dimEUnitsSize', help='The size of optional extended dimension units.', count=MAXDIMS, array=True),
+ _Field('l', 'dimLabelsSize', help='The size of optional dimension labels.', count=MAXDIMS, array=True),
_Field('l', 'sIndicesSize', help='The size of string indicies if this is a text wave.'),
_Field('l', 'optionsSize1', default=0, help='Reserved. Write zero. Ignore on read.'),
_Field('l', 'optionsSize2', default=0, help='Reserved. Write zero. Ignore on read.'),
_Field('h', 'whVersion', default=0, help='Write 0. Ignore on read.'),
_Field('h', 'srcFldr', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('P', 'fileName', default=0, help='Used in memory only. Write zero. Ignore on read.'),
- _Field('c', 'dataUnits', default=0, help='Natural data units go here - null if none.', count=MAX_UNIT_CHARS+1),
- _Field('c', 'xUnits', default=0, help='Natural x-axis units go here - null if none.', count=MAX_UNIT_CHARS+1),
+ _Field('c', 'dataUnits', default=0, help='Natural data units go here - null if none.', count=MAX_UNIT_CHARS+1, array=True),
+ _Field('c', 'xUnits', default=0, help='Natural x-axis units go here - null if none.', count=MAX_UNIT_CHARS+1, array=True),
_Field('l', 'npnts', help='Number of data points in wave.'),
_Field('h', 'aModified', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('d', 'hsA', help='X value for point p = hsA*p + hsB'),
_Field('P', 'formula', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('l', 'depID', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('L', 'creationDate', help='DateTime of creation. Not used in version 1 files.'),
- _Field('c', 'wUnused', default=0, help='Reserved. Write zero. Ignore on read.', count=2),
+ _Field('c', 'wUnused', default=0, help='Reserved. Write zero. Ignore on read.', count=2, array=True),
_Field('L', 'modDate', help='DateTime of last modification.'),
_Field('P', 'waveNoteH', help='Used in memory only. Write zero. Ignore on read.'),
])
_Field('l', 'npnts', help='Total number of points (multiply dimensions up to first zero).'),
_Field('h', 'type', help='See types (e.g. NT_FP64) above. Zero for text waves.'),
_Field('h', 'dLock', default=0, help='Reserved. Write zero. Ignore on read.'),
- _Field('c', 'whpad1', default=0, help='Reserved. Write zero. Ignore on read.', count=6),
+ _Field('c', 'whpad1', default=0, help='Reserved. Write zero. Ignore on read.', count=6, array=True),
_Field('h', 'whVersion', default=1, help='Write 1. Ignore on read.'),
NullStaticStringField('c', 'bname', help='Name of wave plus trailing null.', count=MAX_WAVE_NAME5+1),
_Field('l', 'whpad2', default=0, help='Reserved. Write zero. Ignore on read.'),
_Field('P', 'dFolder', default=0, help='Used in memory only. Write zero. Ignore on read.'),
# Dimensioning info. [0] == rows, [1] == cols etc
- _Field('l', 'nDim', help='Number of of items in a dimension -- 0 means no data.', count=MAXDIMS),
- _Field('d', 'sfA', help='Index value for element e of dimension d = sfA[d]*e + sfB[d].', count=MAXDIMS),
- _Field('d', 'sfB', help='Index value for element e of dimension d = sfA[d]*e + sfB[d].', count=MAXDIMS),
+ _Field('l', 'nDim', help='Number of of items in a dimension -- 0 means no data.', count=MAXDIMS, array=True),
+ _Field('d', 'sfA', help='Index value for element e of dimension d = sfA[d]*e + sfB[d].', count=MAXDIMS, array=True),
+ _Field('d', 'sfB', help='Index value for element e of dimension d = sfA[d]*e + sfB[d].', count=MAXDIMS, array=True),
# SI units
- _Field('c', 'dataUnits', default=0, help='Natural data units go here - null if none.', count=MAX_UNIT_CHARS+1),
- _Field('c', 'dimUnits', default=0, help='Natural dimension units go here - null if none.', count=(MAXDIMS, MAX_UNIT_CHARS+1)),
+ _Field('c', 'dataUnits', default=0, help='Natural data units go here - null if none.', count=MAX_UNIT_CHARS+1, array=True),
+ _Field('c', 'dimUnits', default=0, help='Natural dimension units go here - null if none.', count=(MAXDIMS, MAX_UNIT_CHARS+1), array=True),
_Field('h', 'fsValid', help='TRUE if full scale values have meaning.'),
_Field('h', 'whpad3', default=0, help='Reserved. Write zero. Ignore on read.'),
_Field('d', 'topFullScale', help='The max and max full scale value for wave'), # sic, probably "max and min"
_Field('d', 'botFullScale', help='The max and max full scale value for wave.'), # sic, probably "max and min"
_Field('P', 'dataEUnits', default=0, help='Used in memory only. Write zero. Ignore on read.'),
- _Field('P', 'dimEUnits', default=0, help='Used in memory only. Write zero. Ignore on read.', count=MAXDIMS),
- _Field('P', 'dimLabels', default=0, help='Used in memory only. Write zero. Ignore on read.', count=MAXDIMS),
+ _Field('P', 'dimEUnits', default=0, help='Used in memory only. Write zero. Ignore on read.', count=MAXDIMS, array=True),
+ _Field('P', 'dimLabels', default=0, help='Used in memory only. Write zero. Ignore on read.', count=MAXDIMS, array=True),
_Field('P', 'waveNoteH', default=0, help='Used in memory only. Write zero. Ignore on read.'),
- _Field('l', 'whUnused', default=0, help='Reserved. Write zero. Ignore on read.', count=16),
+ _Field('l', 'whUnused', default=0, help='Reserved. Write zero. Ignore on read.', count=16, array=True),
# The following stuff is considered private to Igor.
_Field('h', 'aModified', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('h', 'wModified', default=0, help='Used in memory only. Write zero. Ignore on read.'),
fields=[
_Field(BinHeader1, 'bin_header', help='Binary wave header'),
_Field(WaveHeader2, 'wave_header', help='Wave header'),
- DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0),
+ DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0, array=True),
])
Wave2 = _DynamicStructure(
fields=[
_Field(BinHeader2, 'bin_header', help='Binary wave header'),
_Field(WaveHeader2, 'wave_header', help='Wave header'),
- DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0),
- _Field('x', 'padding', help='16 bytes of padding in versions 2 and 3.', count=16),
- DynamicWaveNoteField('c', 'note', help='Optional wave note data', count=0),
+ DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0, array=True),
+ _Field('x', 'padding', help='16 bytes of padding in versions 2 and 3.', count=16, array=True),
+ DynamicWaveNoteField('c', 'note', help='Optional wave note data', count=0, array=True),
])
Wave3 = _DynamicStructure(
fields=[
_Field(BinHeader3, 'bin_header', help='Binary wave header'),
_Field(WaveHeader2, 'wave_header', help='Wave header'),
- DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0),
- _Field('x', 'padding', help='16 bytes of padding in versions 2 and 3.', count=16),
- DynamicWaveNoteField('c', 'note', help='Optional wave note data', count=0),
- DynamicDependencyFormulaField('c', 'formula', help='Optional wave dependency formula', count=0),
+ DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0, array=True),
+ _Field('x', 'padding', help='16 bytes of padding in versions 2 and 3.', count=16, array=True),
+ DynamicWaveNoteField('c', 'note', help='Optional wave note data', count=0, array=True),
+ DynamicDependencyFormulaField('c', 'formula', help='Optional wave dependency formula', count=0, array=True),
])
Wave5 = _DynamicStructure(
fields=[
_Field(BinHeader5, 'bin_header', help='Binary wave header'),
_Field(WaveHeader5, 'wave_header', help='Wave header'),
- DynamicWaveDataField5('f', 'wData', help='The start of the array of waveform data.', count=0),
- DynamicDependencyFormulaField('c', 'formula', help='Optional wave dependency formula.', count=0),
- DynamicWaveNoteField('c', 'note', help='Optional wave note data.', count=0),
- DynamicDataUnitsField('c', 'data_units', help='Optional extended data units data.', count=0),
- DynamicDimensionUnitsField('c', 'dimension_units', help='Optional dimension label data', count=0),
- DynamicLabelsField('c', 'labels', help="Optional dimension label data", count=0),
- DynamicStringIndicesDataField('P', 'sIndices', help='Dynamic string indices for text waves.', count=0),
+ DynamicWaveDataField5('f', 'wData', help='The start of the array of waveform data.', count=0, array=True),
+ DynamicDependencyFormulaField('c', 'formula', help='Optional wave dependency formula.', count=0, array=True),
+ DynamicWaveNoteField('c', 'note', help='Optional wave note data.', count=0, array=True),
+ DynamicDataUnitsField('c', 'data_units', help='Optional extended data units data.', count=0, array=True),
+ DynamicDimensionUnitsField('c', 'dimension_units', help='Optional dimension label data', count=0, array=True),
+ DynamicLabelsField('c', 'labels', help="Optional dimension label data", count=0, array=True),
+ DynamicStringIndicesDataField('P', 'sIndices', help='Dynamic string indices for text waves.', count=0, array=True),
])
Wave = _DynamicStructure(
Example of a multi-dimensional float field:
>>> data = Field(
- ... 'f', 'data', help='example data', count=(2,3,4))
+ ... 'f', 'data', help='example data', count=(2,3,4), array=True)
>>> data.arg_count
24
>>> list(data.indexes()) # doctest: +ELLIPSIS
Example of a nested structure field:
>>> run = Structure('run', fields=[time, data])
- >>> runs = Field(run, 'runs', help='pair of runs', count=2)
+ >>> runs = Field(run, 'runs', help='pair of runs', count=2, array=True)
>>> runs.arg_count # = 2 * (1 + 24)
50
>>> data1 = numpy.arange(data.arg_count).reshape(data.count)
--------
Structure
"""
- def __init__(self, format, name, default=None, help=None, count=1):
+ def __init__(self, format, name, default=None, help=None, count=1,
+ array=False):
self.format = format
self.name = name
self.default = default
self.help = help
self.count = count
+ self.array = array
self.setup()
def setup(self):
"""
_LOG.debug('setup {}'.format(self))
self.item_count = _numpy.prod(self.count) # number of item repeats
+ if not self.array and self.item_count != 1:
+ raise ValueError(
+ '{} must be an array field to have a count of {}'.format(
+ self, self.count))
if isinstance(self.format, Structure):
self.structure_count = sum(
f.arg_count for f in self.format.fields)
def indexes(self):
"""Iterate through indexes to a possibly multi-dimensional array"""
- assert self.item_count > 1, self
+ assert self.array, self
try:
i = [0] * len(self.count)
except TypeError: # non-iterable count
If the field is repeated (count > 1), the incoming data should
be iterable with each iteration returning a single item.
"""
- if self.item_count > 1:
+ if self.array:
if data is None:
data = []
if hasattr(data, 'flat'): # take advantage of numpy's ndarray.flat
item = None
for arg in self.pack_item(item):
yield arg
- elif self.item_count:
+ else:
for arg in self.pack_item(data):
yield arg
count = self.count
else:
count = 0 # padding bytes, etc.
- if count == 1:
+ if not self.array:
+ assert count == 1, (self, self.count)
return unpacked[0]
if isinstance(self.format, Structure):
try:
>>> time = Field('I', 'time', default=0, help='POSIX time')
>>> data = Field(
- ... 'h', 'data', default=0, help='example data', count=(2,3))
+ ... 'h', 'data', default=0, help='example data', count=(2,3),
+ ... array=True)
>>> run = Structure('run', fields=[time, data])
>>> version = Field(
... 'H', 'version', default=1, help='example version')
- >>> runs = Field(run, 'runs', help='pair of runs', count=2)
+ >>> runs = Field(run, 'runs', help='pair of runs', count=2, array=True)
>>> experiment = Structure('experiment', fields=[version, runs])
The structures automatically calculate the flattened data format:
If you set ``count=0``, the field is ignored.
>>> experiment2 = Structure('experiment', fields=[
- ... version, Field('f', 'ignored', count=0), runs], byte_order='>')
+ ... version, Field('f', 'ignored', count=0, array=True), runs],
+ ... byte_order='>')
>>> experiment2.format
'>HIhhhhhhIhhhhhh'
>>> d = experiment2.unpack(b)
>>> dynamic_length_vector = DynamicStructure('vector',
... fields=[
... DynamicLengthField('I', 'length'),
- ... Field('h', 'data', count=0),
+ ... Field('h', 'data', count=0, array=True),
... ],
... byte_order='>')
>>> class DynamicDataField (DynamicField):
>>> dynamic_data_vector = DynamicStructure('vector',
... fields=[
... Field('I', 'length'),
- ... DynamicDataField('h', 'data', count=0),
+ ... DynamicDataField('h', 'data', count=0, array=True),
... ],
... byte_order='>')
f.setup()
f.format.setup()
if isinstance(f.format, DynamicStructure):
- if f.item_count == 1:
- # TODO, fix in case we *want* an array
- d[f.name] = {}
- f.format.unpack_stream(
- stream, parents=parents, data=data, d=d[f.name])
- else:
+ if f.array:
d[f.name] = []
for i in range(f.item_count):
x = {}
d[f.name].append(x)
f.format.unpack_stream(
stream, parents=parents, data=data, d=x)
+ else:
+ assert f.item_count == 1, (f, f.count)
+ d[f.name] = {}
+ f.format.unpack_stream(
+ stream, parents=parents, data=data, d=d[f.name])
if hasattr(f, 'post_unpack'):
_LOG.debug('post-unpack {}'.format(f))
repeat = f.post_unpack(parents=parents, data=data)
f.setup()
f.format.setup()
x = [f.format.unpack_from(b) for b in bs]
- if len(x) == 1: # TODO, fix in case we *want* an array
+ if not f.array:
+ assert len(x) == 1, (f, f.count, x)
x = x[0]
return x
else: