Skip to content

Commit

Permalink
allow pickling xdr trajectory readers
Browse files Browse the repository at this point in the history
the low level __reduce__ function is used by the pickle protocol as a recipe
to reconstruct this class.
  • Loading branch information
kain88-de committed Oct 12, 2017
1 parent d5dec2b commit 5ccd046
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
1 change: 1 addition & 0 deletions package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Enhancements
the `moltype` selection keyword is added (Issue #1555)
* about 20% speed improvements for GNM analysis. (PR #1579)
* added support for Tinker TXYZ and ARC files
* libmdaxdr classes can now be pickled (PR #1680)

Deprecations

Expand Down
43 changes: 43 additions & 0 deletions package/MDAnalysis/lib/formats/libmdaxdr.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,39 @@ cdef class _XDRFile:
raise IOError('No file currently opened')
return self.offsets.size

def __reduce__(self):
"""low level pickle function. It gives instructions for unpickling which class
should be created with arguments to `__cinit__` and the current state
"""
return (self.__class__, (self.fname.decode(), self.mode),
self.__getstate__())

def __getstate__(self):
"""
current state
"""
return (self.is_open, self.current_frame, self._offsets,
self._has_offsets)

def __setstate__(self, state):
"""
reset state offsets and current frame
"""
is_open = state[0]
# by default the file is open
if not is_open:
self.close()
return

# set them now to avoid recalculation
self._offsets = state[2]
self._has_offsets = state[3]

# where was I
current_frame = state[1]
self.seek(current_frame)

def seek(self, frame):
"""Seek to Frame.
Expand Down Expand Up @@ -402,6 +435,11 @@ cdef class TRRFile(_XDRFile):
>>> with TRRFile('foo.trr') as f:
>>> for frame in f:
>>> print(frame.x)
Notes
-----
This class can be pickled. The pickle will store filename, mode, current
frame and offsets
"""

def _calc_natoms(self, fname):
Expand Down Expand Up @@ -614,6 +652,11 @@ cdef class XTCFile(_XDRFile):
>>> with XTCFile('foo.trr') as f:
>>> for frame in f:
>>> print(frame.x)
Notes
-----
This class can be pickled. The pickle will store filename, mode, current
frame and offsets
"""
cdef float precision

Expand Down
20 changes: 20 additions & 0 deletions testsuite/MDAnalysisTests/formats/test_libmdaxdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787
#
from __future__ import print_function, absolute_import
from six.moves import cPickle as pickle

import numpy as np

Expand Down Expand Up @@ -115,6 +116,25 @@ def test_read_write_mode_file(self, xdr, tmpdir, fname):
with pytest.raises(IOError):
f.read()

def test_pickle(self, reader):
reader.seek(len(reader) - 1)
dump = pickle.dumps(reader)
new_reader = pickle.loads(dump)

assert reader.fname == new_reader.fname
assert reader.tell() == new_reader.tell()
assert_almost_equal(reader.offsets, new_reader.offsets)

def test_pickle_closed(self, reader):
reader.seek(len(reader) - 1)
reader.close()
dump = pickle.dumps(reader)
new_reader = pickle.loads(dump)

assert reader.fname == new_reader.fname
assert reader.tell() != new_reader.tell()



@pytest.mark.parametrize("xdrfile, fname, offsets",
((XTCFile, XTC_multi_frame, XTC_OFFSETS),
Expand Down

0 comments on commit 5ccd046

Please sign in to comment.