-
Notifications
You must be signed in to change notification settings - Fork 674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Reader that does not need open file handles (#239) #926
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,11 +126,12 @@ | |
|
||
from six.moves import range | ||
import six | ||
|
||
import warnings | ||
|
||
import numpy as np | ||
from contextlib import contextmanager | ||
import copy | ||
import itertools | ||
import numpy as np | ||
import os.path | ||
import warnings | ||
import weakref | ||
|
||
from .. import ( | ||
|
@@ -141,6 +142,7 @@ | |
from ..core import flags | ||
from .. import units | ||
from ..lib.util import asiterable, Namespace | ||
from ..lib import util | ||
from . import core | ||
from .. import NoDataError | ||
|
||
|
@@ -1630,6 +1632,100 @@ def __del__(self): | |
self.close() | ||
|
||
|
||
class NewReader(ProtoReader): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the plan to have this class completely replace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's just a temporary thing while I try and see what's possible... hopefully it will be the new Reader class across everything |
||
"""Super top secret magical class that fixes all known (and unknown) bugs""" | ||
def __init__(self, filename, convert_units=None, **kwargs): | ||
self.filename = filename | ||
self._last_fh_pos = 0 # last known position of file handle | ||
|
||
if convert_units is None: | ||
convert_units = flags['convert_lengths'] | ||
self.convert_units = convert_units | ||
|
||
self._auxs = {} | ||
ts_kwargs = {} | ||
for att in ('dt', 'time_offset'): | ||
try: | ||
val = kwargs[att] | ||
except KeyError: | ||
pass | ||
else: | ||
ts_kwargs[att] = val | ||
|
||
self._ts_kwargs = ts_kwargs | ||
|
||
def _full_iter(self): | ||
self._reopen() | ||
with util.openany(self.filename, 'r') as self._file: | ||
while True: | ||
try: | ||
ts = self._read_next_timestep() | ||
for auxname in self.aux_list: | ||
ts = self._auxs[auxname].update_ts(ts) | ||
yield ts | ||
except (EOFError, IOError): | ||
# goto start of file | ||
self._read_frame_with_aux(0) | ||
self._last_fh_pos = self._file.tell() | ||
raise StopIteration | ||
|
||
def _sliced_iter(self, start, stop, step): | ||
with util.openany(self.filename, 'r') as self._file: | ||
for f in range(start, stop, step): | ||
yield self._read_frame_with_aux(f) | ||
|
||
self._read_frame_with_aux(0) | ||
self._last_fh_pos = self._file.tell() | ||
raise StopIteration | ||
|
||
def _goto_frame(self, i): | ||
with util.openany(self.filename, 'r') as self._file: | ||
ts = self._read_frame_with_aux(i) | ||
return ts | ||
|
||
def __iter__(self): | ||
return self._full_iter() | ||
|
||
def __getitem__(self, item): | ||
def apply_limits(frame): | ||
if frame < 0: | ||
frame += len(self) | ||
if frame < 0 or frame >= len(self): | ||
raise IndexError("Index {} exceeds length of trajectory ({})." | ||
"".format(frame, len(self))) | ||
return frame | ||
|
||
if isinstance(item, int): | ||
return self._goto_frame(apply_limits(item)) | ||
elif isinstance(item, (list, np.ndarray)): | ||
return self._sliced_iter(item) | ||
elif isinstance(item, slice): # TODO Fix me! | ||
start, stop, step = self.check_slice_indices( | ||
item.start, item.stop, item.step) | ||
|
||
return self._sliced_iter(start, stop, step) | ||
|
||
def __next__(self): | ||
with util.openany(self.filename, 'r') as self._file: | ||
try: | ||
self._file.seek(self._last_fh_pos) | ||
ts = self._read_next_timestep() | ||
except (EOFError, IOError): | ||
self.rewind() | ||
raise StopIteration | ||
else: | ||
self._last_fh_pos = self._file.tell() | ||
for auxname in self.aux_list: | ||
ts = self._auxs[auxname].update_ts(ts) | ||
return ts | ||
|
||
next = __next__ | ||
|
||
def close(self): | ||
# "close" by moving last position to start | ||
self._last_fh_pos = 0 | ||
|
||
|
||
class _Writermeta(type): | ||
# Auto register upon class creation | ||
def __init__(cls, name, bases, classdict): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -122,20 +122,23 @@ cdef class _XDRFile: | |
This class can't be initialized use one of the subclasses XTCFile, TRRFile | ||
""" | ||
cdef readonly int n_atoms | ||
cdef int is_open | ||
cdef readonly int is_open | ||
cdef int reached_eof | ||
cdef XDRFILE *xfp | ||
cdef readonly fname | ||
cdef int current_frame | ||
cdef str _mode | ||
cdef str mode | ||
cdef np.ndarray box | ||
cdef np.ndarray _offsets | ||
cdef int _has_offsets | ||
|
||
def __cinit__(self, fname, mode='r'): | ||
self.fname = fname.encode('utf-8') | ||
self._mode = mode | ||
self.is_open = False | ||
self.open(self.fname, mode) | ||
self.open() # to read natoms | ||
self.close() | ||
|
||
def __dealloc__(self): | ||
self.close() | ||
|
@@ -210,6 +213,7 @@ cdef class _XDRFile: | |
|
||
def __enter__(self): | ||
"""Support context manager""" | ||
self.open(self.fname, self._mode) | ||
return self | ||
|
||
def __exit__(self, exc_type, exc_val, exc_tb): | ||
|
@@ -318,7 +322,10 @@ cdef class _XDRFile: | |
set_offsets | ||
""" | ||
if not self._has_offsets: | ||
# wrap this in try/except to ensure it gets closed? | ||
self.open(self.fname, self._mode) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not with self:
... that might work and should close the file when an IOError is thrown |
||
self._offsets = self.calc_offsets() | ||
self.close() | ||
self._has_offsets = True | ||
return self._offsets | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For python 3 compatibility this should be
next(self)
.