Skip to content

Commit c777d4e

Browse files
committed
isolated CCP4 byteorder detection
- should help with debugging #50 - added test that checks that the test ccp4 file byteorder is properly detected
1 parent 84368d4 commit c777d4e

2 files changed

Lines changed: 28 additions & 11 deletions

File tree

gridData/CCP4.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,14 @@ def __init__(self, filename=None):
198198

199199
def read(self, filename):
200200
"""Populate the instance from the ccp4 file *filename*."""
201-
from struct import calcsize, unpack
202201
if filename is not None:
203202
self.filename = filename
204203
with open(self.filename, 'rb') as ccp4:
205204
h = self.header = self._read_header(ccp4)
206205
nentries = h['nc'] * h['nr'] * h['ns']
207206
# Quick and dirty... slurp it all in one go.
208207
datafmt = h['bsaflag'] + str(nentries) + self._data_bintype
209-
a = np.array(unpack(datafmt, ccp4.read(calcsize(datafmt))))
208+
a = np.array(struct.unpack(datafmt, ccp4.read(struct.calcsize(datafmt))))
210209
self.header['filename'] = self.filename
211210
# TODO: Account for the possibility that y-axis is fastest or
212211
# slowest index, which unfortunately is possible in CCP4.
@@ -237,13 +236,20 @@ def _delta(self):
237236
delta = lengths / self.shape
238237
return np.diag(delta)
239238

240-
def _read_header(self, ccp4file):
241-
"""Read header bytes, try all possibilities for byte
242-
order/size/alignment."""
243-
# Try all endinaness and alignment options until we find
244-
# something that looks sensible. The machst field could be
245-
# used to obtain endianness, but it does not specify
246-
# alignment.
239+
@staticmethod
240+
def _detect_byteorder(ccp4file):
241+
"""Detect the byteorder of stream `ccp4file` and return format character.
242+
243+
Try all endinaness and alignment options until we find
244+
something that looks sensible ("MAPS " in the first 4 bytes).
245+
246+
(The ``machst`` field could be used to obtain endianness, but
247+
it does not specify alignment.)
248+
249+
.. SeeAlso::
250+
251+
:mod:`struct`
252+
"""
247253
bsaflag = None
248254
ccp4file.seek(52 * 4)
249255
mapbin = ccp4file.read(4)
@@ -252,10 +258,16 @@ def _read_header(self, ccp4file):
252258
if mapstr.upper() == 'MAP ':
253259
bsaflag = flag
254260
break # Only possible value according to spec.
255-
if bsaflag is None:
261+
else:
256262
raise TypeError(
257263
"Cannot decode header --- corrupted or wrong format?")
258264
ccp4file.seek(0)
265+
return bsaflag
266+
267+
def _read_header(self, ccp4file):
268+
"""Read header bytes"""
269+
270+
bsaflag = self._detect_byteorder(ccp4file)
259271

260272
# Parse the top of the header (4-byte words, 1 to 25).
261273
nheader = struct.calcsize(self._headerfmt)

gridData/tests/test_ccp4.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from numpy.testing import (assert_almost_equal,
55
assert_equal)
66

7-
from gridData import Grid
7+
from gridData import Grid, CCP4
88

99
from . import datafiles
1010

@@ -15,3 +15,8 @@ def test_ccp4():
1515
assert_equal(g.grid.size, POINTS)
1616
assert_almost_equal(g.delta, [3./4, .5, 2./3])
1717
assert_equal(g.origin, np.zeros(3))
18+
19+
def test_byteorder():
20+
with open(datafiles.CCP4, 'rb') as ccp4file:
21+
flag = CCP4.CCP4._detect_byteorder(ccp4file)
22+
assert flag in ("@", "=", "<"), "flag {} is not '<'".format(flag)

0 commit comments

Comments
 (0)