import os
import struct
import itertools


TYPEOF_STEP = 'i'
TYPEOF_VAL = 'd'
fmt = TYPEOF_VAL + TYPEOF_STEP
size = struct.calcsize(fmt)


class MetricsBase(object):
    def __init__(self, root):
        self.root = root
        if not os.path.exists(self.root):
            os.makedirs(self.root)

    def _filename(self, key):
        return os.path.join(self.root, key + '.metric')


class MetricsWriter(MetricsBase):
    def write(self, key, val, step):
        with open(self._filename(key), 'ab') as f:
            f.write(struct.pack(fmt, val, step))


class MetricsReader(MetricsBase):
    def read(self, key, offset=None, limit=None):
        table = []
        with open(self._filename(key), 'r+b') as f:

            # Optionally skip.
            if offset:
                f.seek(offset * size)

            for ii, _ in enumerate(itertools.repeat(None)):
                # Terminate if limit.
                if limit and not ii < limit:
                    break

                inp = f.read(size)

                # Terminate if EOF.
                if not inp:
                    break

                row = struct.unpack(fmt, inp)
                table.append(row)
        return table

@@ -3,16 +3,28 @@
 port os%0A
+import math%0A
 import s
@@ -29,16 +29,16 @@
  struct%0A
-
 import i
@@ -646,16 +646,50 @@
 mit=None
+, nan_default=0.0, inf_default=0.0
 ):%0A     
@@ -1137,32 +1137,32 @@
          break%0A%0A
-
                 
@@ -1191,16 +1191,192 @@
 t, inp)%0A
+                if math.isnan(row%5B0%5D):%0A                    row = (nan_default, row%5B1%5D)%0A                elif math.isinf(row%5B0%5D):%0A                    row = (inf_default, row%5B1%5D)%0A
         

Handle inf/nan in metrics reader.