tests: Add a socket timeout
[vpp.git] / src / vpp-api / python / vpp_papi / vpp_stats.py
index 0b1c701..aa9ff85 100755 (executable)
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
 # limitations under the License.
 #
 
-'''
+"""
 This module implement Python access to the VPP statistics segment. It
 accesses the data structures directly in shared memory.
 VPP uses optimistic locking, so data structures may change underneath
 This module implement Python access to the VPP statistics segment. It
 accesses the data structures directly in shared memory.
 VPP uses optimistic locking, so data structures may change underneath
@@ -39,7 +39,7 @@ stat['/if/rx'][:, 1].sum_packets() - returns the sum of packet counters for
                                      interface 1 on all threads
 stat['/if/rx-miss'][:, 1].sum() - returns the sum of packet counters for
                                   interface 1 on all threads for simple counters
                                      interface 1 on all threads
 stat['/if/rx-miss'][:, 1].sum() - returns the sum of packet counters for
                                   interface 1 on all threads for simple counters
-'''
+"""
 
 import os
 import socket
 
 import os
 import socket
@@ -50,31 +50,36 @@ import time
 import unittest
 import re
 
 import unittest
 import re
 
+
 def recv_fd(sock):
 def recv_fd(sock):
-    '''Get file descriptor for memory map'''
-    fds = array.array("i")   # Array of ints
-    _, ancdata, _, _ = sock.recvmsg(0, socket.CMSG_LEN(4))
+    """Get file descriptor for memory map"""
+    fds = array.array("i")  # Array of ints
+    _, ancdata, _, _ = sock.recvmsg(0, socket.CMSG_SPACE(4))
     for cmsg_level, cmsg_type, cmsg_data in ancdata:
         if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
     for cmsg_level, cmsg_type, cmsg_data in ancdata:
         if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
-            fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
+            fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
     return list(fds)[0]
 
     return list(fds)[0]
 
-VEC_LEN_FMT = Struct('I')
+
+VEC_LEN_FMT = Struct("I")
+
+
 def get_vec_len(stats, vector_offset):
 def get_vec_len(stats, vector_offset):
-    '''Equivalent to VPP vec_len()'''
+    """Equivalent to VPP vec_len()"""
     return VEC_LEN_FMT.unpack_from(stats.statseg, vector_offset - 8)[0]
 
     return VEC_LEN_FMT.unpack_from(stats.statseg, vector_offset - 8)[0]
 
+
 def get_string(stats, ptr):
 def get_string(stats, ptr):
-    '''Get a string from a VPP vector'''
+    """Get a string from a VPP vector"""
     namevector = ptr - stats.base
     namevectorlen = get_vec_len(stats, namevector)
     if namevector + namevectorlen >= stats.size:
     namevector = ptr - stats.base
     namevectorlen = get_vec_len(stats, namevector)
     if namevector + namevectorlen >= stats.size:
-        raise IOError('String overruns stats segment')
-    return stats.statseg[namevector:namevector+namevectorlen-1].decode('ascii')
+        raise IOError("String overruns stats segment")
+    return stats.statseg[namevector : namevector + namevectorlen - 1].decode("ascii")
 
 
 class StatsVector:
 
 
 class StatsVector:
-    '''A class representing a VPP vector'''
+    """A class representing a VPP vector"""
 
     def __init__(self, stats, ptr, fmt):
         self.vec_start = ptr - stats.base
 
     def __init__(self, stats, ptr, fmt):
         self.vec_start = ptr - stats.base
@@ -86,28 +91,35 @@ class StatsVector:
         self.stats = stats
 
         if self.vec_start + self.vec_len * self.elementsize >= stats.size:
         self.stats = stats
 
         if self.vec_start + self.vec_len * self.elementsize >= stats.size:
-            raise IOError('Vector overruns stats segment')
+            raise IOError("Vector overruns stats segment")
 
     def __iter__(self):
         with self.stats.lock:
 
     def __iter__(self):
         with self.stats.lock:
-            return self.struct.iter_unpack(self.statseg[self.vec_start:self.vec_start +
-                                                        self.elementsize*self.vec_len])
+            return self.struct.iter_unpack(
+                self.statseg[
+                    self.vec_start : self.vec_start + self.elementsize * self.vec_len
+                ]
+            )
 
     def __getitem__(self, index):
         if index > self.vec_len:
 
     def __getitem__(self, index):
         if index > self.vec_len:
-            raise IOError('Index beyond end of vector')
+            raise IOError("Index beyond end of vector")
         with self.stats.lock:
             if self.fmtlen == 1:
         with self.stats.lock:
             if self.fmtlen == 1:
-                return self.struct.unpack_from(self.statseg, self.vec_start +
-                                               (index * self.elementsize))[0]
-            return self.struct.unpack_from(self.statseg, self.vec_start +
-                                           (index * self.elementsize))
+                return self.struct.unpack_from(
+                    self.statseg, self.vec_start + (index * self.elementsize)
+                )[0]
+            return self.struct.unpack_from(
+                self.statseg, self.vec_start + (index * self.elementsize)
+            )
+
+
+class VPPStats:
+    """Main class implementing Python access to the VPP statistics segment"""
 
 
-class VPPStats():
-    '''Main class implementing Python access to the VPP statistics segment'''
     # pylint: disable=too-many-instance-attributes
     # pylint: disable=too-many-instance-attributes
-    shared_headerfmt = Struct('QPQQPP')
-    default_socketname = '/run/vpp/stats.sock'
+    shared_headerfmt = Struct("QPQQPP")
+    default_socketname = "/run/vpp/stats.sock"
 
     def __init__(self, socketname=default_socketname, timeout=10):
         self.socketname = socketname
 
     def __init__(self, socketname=default_socketname, timeout=10):
         self.socketname = socketname
@@ -120,71 +132,80 @@ class VPPStats():
         self.statseg = 0
 
     def connect(self):
         self.statseg = 0
 
     def connect(self):
-        '''Connect to stats segment'''
+        """Connect to stats segment"""
         if self.connected:
             return
         sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
         if self.connected:
             return
         sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+
+        # Our connect races the corresponding recv_fds call in VPP, if we beat
+        # VPP then we will try (unsuccessfully) to receive file descriptors and
+        # will have gone away before VPP can respond to our connect.  A short
+        # timeout here stops this error occurring.
+        sock.settimeout(1)
         sock.connect(self.socketname)
 
         mfd = recv_fd(sock)
         sock.close()
 
         stat_result = os.fstat(mfd)
         sock.connect(self.socketname)
 
         mfd = recv_fd(sock)
         sock.close()
 
         stat_result = os.fstat(mfd)
-        self.statseg = mmap.mmap(mfd, stat_result.st_size, mmap.PROT_READ, mmap.MAP_SHARED)
+        self.statseg = mmap.mmap(
+            mfd, stat_result.st_size, mmap.PROT_READ, mmap.MAP_SHARED
+        )
         os.close(mfd)
 
         self.size = stat_result.st_size
         if self.version != 2:
         os.close(mfd)
 
         self.size = stat_result.st_size
         if self.version != 2:
-            raise Exception('Incompatbile stat segment version {}'
-                            .format(self.version))
+            raise Exception("Incompatbile stat segment version {}".format(self.version))
 
         self.refresh()
         self.connected = True
 
     def disconnect(self):
 
         self.refresh()
         self.connected = True
 
     def disconnect(self):
-        '''Disconnect from stats segment'''
+        """Disconnect from stats segment"""
         if self.connected:
             self.statseg.close()
             self.connected = False
 
     @property
     def version(self):
         if self.connected:
             self.statseg.close()
             self.connected = False
 
     @property
     def version(self):
-        '''Get version of stats segment'''
+        """Get version of stats segment"""
         return self.shared_headerfmt.unpack_from(self.statseg)[0]
 
     @property
     def base(self):
         return self.shared_headerfmt.unpack_from(self.statseg)[0]
 
     @property
     def base(self):
-        '''Get base pointer of stats segment'''
+        """Get base pointer of stats segment"""
         return self.shared_headerfmt.unpack_from(self.statseg)[1]
 
     @property
     def epoch(self):
         return self.shared_headerfmt.unpack_from(self.statseg)[1]
 
     @property
     def epoch(self):
-        '''Get current epoch value from stats segment'''
+        """Get current epoch value from stats segment"""
         return self.shared_headerfmt.unpack_from(self.statseg)[2]
 
     @property
     def in_progress(self):
         return self.shared_headerfmt.unpack_from(self.statseg)[2]
 
     @property
     def in_progress(self):
-        '''Get value of in_progress from stats segment'''
+        """Get value of in_progress from stats segment"""
         return self.shared_headerfmt.unpack_from(self.statseg)[3]
 
     @property
     def directory_vector(self):
         return self.shared_headerfmt.unpack_from(self.statseg)[3]
 
     @property
     def directory_vector(self):
-        '''Get pointer of directory vector'''
+        """Get pointer of directory vector"""
         return self.shared_headerfmt.unpack_from(self.statseg)[4]
 
         return self.shared_headerfmt.unpack_from(self.statseg)[4]
 
-    elementfmt = 'IQ128s'
+    elementfmt = "IQ128s"
 
     def refresh(self, blocking=True):
 
     def refresh(self, blocking=True):
-        '''Refresh directory vector cache (epoch changed)'''
+        """Refresh directory vector cache (epoch changed)"""
         directory = {}
         directory_by_idx = {}
         while True:
             try:
                 with self.lock:
                     self.last_epoch = self.epoch
         directory = {}
         directory_by_idx = {}
         while True:
             try:
                 with self.lock:
                     self.last_epoch = self.epoch
-                    for i, direntry in enumerate(StatsVector(self, self.directory_vector, self.elementfmt)):
-                        path_raw = direntry[2].find(b'\x00')
-                        path = direntry[2][:path_raw].decode('ascii')
+                    for i, direntry in enumerate(
+                        StatsVector(self, self.directory_vector, self.elementfmt)
+                    ):
+                        path_raw = direntry[2].find(b"\x00")
+                        path = direntry[2][:path_raw].decode("ascii")
                         directory[path] = StatsEntry(direntry[0], direntry[1])
                         directory_by_idx[i] = path
                     self.directory = directory
                         directory[path] = StatsEntry(direntry[0], direntry[1])
                         directory_by_idx[i] = path
                     self.directory = directory
@@ -210,14 +231,12 @@ class VPPStats():
     def __iter__(self):
         return iter(self.directory.items())
 
     def __iter__(self):
         return iter(self.directory.items())
 
-
     def set_errors(self, blocking=True):
     def set_errors(self, blocking=True):
-        '''Return dictionary of error counters > 0'''
+        """Return dictionary of error counters > 0"""
         if not self.connected:
             self.connect()
 
         if not self.connected:
             self.connect()
 
-        errors = {k: v for k, v in self.directory.items()
-                  if k.startswith("/err/")}
+        errors = {k: v for k, v in self.directory.items() if k.startswith("/err/")}
         result = {}
         for k in errors:
             try:
         result = {}
         for k in errors:
             try:
@@ -229,23 +248,23 @@ class VPPStats():
         return result
 
     def set_errors_str(self, blocking=True):
         return result
 
     def set_errors_str(self, blocking=True):
-        '''Return all errors counters > 0 pretty printed'''
-        error_string = ['ERRORS:']
+        """Return all errors counters > 0 pretty printed"""
+        error_string = ["ERRORS:"]
         error_counters = self.set_errors(blocking)
         for k in sorted(error_counters):
         error_counters = self.set_errors(blocking)
         for k in sorted(error_counters):
-            error_string.append('{:<60}{:>10}'.format(k, error_counters[k]))
-        return '%s\n' % '\n'.join(error_string)
+            error_string.append("{:<60}{:>10}".format(k, error_counters[k]))
+        return "%s\n" % "\n".join(error_string)
 
     def get_counter(self, name, blocking=True):
 
     def get_counter(self, name, blocking=True):
-        '''Alternative call to __getitem__'''
+        """Alternative call to __getitem__"""
         return self.__getitem__(name, blocking)
 
     def get_err_counter(self, name, blocking=True):
         return self.__getitem__(name, blocking)
 
     def get_err_counter(self, name, blocking=True):
-        '''Alternative call to __getitem__'''
+        """Alternative call to __getitem__"""
         return self.__getitem__(name, blocking).sum()
 
     def ls(self, patterns):
         return self.__getitem__(name, blocking).sum()
 
     def ls(self, patterns):
-        '''Returns list of counters matching pattern'''
+        """Returns list of counters matching pattern"""
         # pylint: disable=invalid-name
         if not self.connected:
             self.connect()
         # pylint: disable=invalid-name
         if not self.connected:
             self.connect()
@@ -255,20 +274,24 @@ class VPPStats():
         if self.last_epoch != self.epoch:
             self.refresh()
 
         if self.last_epoch != self.epoch:
             self.refresh()
 
-        return [k for k, v in self.directory.items()
-                if any(re.match(pattern, k) for pattern in regex)]
+        return [
+            k
+            for k, v in self.directory.items()
+            if any(re.match(pattern, k) for pattern in regex)
+        ]
 
     def dump(self, counters, blocking=True):
 
     def dump(self, counters, blocking=True):
-        '''Given a list of counters return a dictionary of results'''
+        """Given a list of counters return a dictionary of results"""
         if not self.connected:
             self.connect()
         result = {}
         for cnt in counters:
         if not self.connected:
             self.connect()
         result = {}
         for cnt in counters:
-            result[cnt] = self.__getitem__(cnt,blocking)
+            result[cnt] = self.__getitem__(cnt, blocking)
         return result
 
         return result
 
-class StatsLock():
-    '''Stat segment optimistic locking'''
+
+class StatsLock:
+    """Stat segment optimistic locking"""
 
     def __init__(self, stats):
         self.stats = stats
 
     def __init__(self, stats):
         self.stats = stats
@@ -283,7 +306,7 @@ class StatsLock():
         self.release()
 
     def acquire(self, blocking=True, timeout=-1):
         self.release()
 
     def acquire(self, blocking=True, timeout=-1):
-        '''Acquire the lock. Await in progress to go false. Record epoch.'''
+        """Acquire the lock. Await in progress to go false. Record epoch."""
         self.epoch = self.stats.epoch
         if timeout > 0:
             start = time.monotonic()
         self.epoch = self.stats.epoch
         if timeout > 0:
             start = time.monotonic()
@@ -296,46 +319,49 @@ class StatsLock():
         return True
 
     def release(self):
         return True
 
     def release(self):
-        '''Check if data read while locked is valid'''
+        """Check if data read while locked is valid"""
         if self.stats.in_progress or self.stats.epoch != self.epoch:
         if self.stats.in_progress or self.stats.epoch != self.epoch:
-            raise IOError('Optimistic lock failed, retry')
+            raise IOError("Optimistic lock failed, retry")
 
     def locked(self):
 
     def locked(self):
-        '''Not used'''
+        """Not used"""
 
 
 class StatsCombinedList(list):
 
 
 class StatsCombinedList(list):
-    '''Column slicing for Combined counters list'''
+    """Column slicing for Combined counters list"""
 
     def __getitem__(self, item):
 
     def __getitem__(self, item):
-        '''Supports partial numpy style 2d support. Slice by column [:,1]'''
+        """Supports partial numpy style 2d support. Slice by column [:,1]"""
         if isinstance(item, int):
             return list.__getitem__(self, item)
         return CombinedList([row[item[1]] for row in self])
 
         if isinstance(item, int):
             return list.__getitem__(self, item)
         return CombinedList([row[item[1]] for row in self])
 
+
 class CombinedList(list):
 class CombinedList(list):
-    '''Combined Counters 2-dimensional by thread by index of packets/octets'''
+    """Combined Counters 2-dimensional by thread by index of packets/octets"""
 
     def packets(self):
 
     def packets(self):
-        '''Return column (2nd dimension). Packets for all threads'''
+        """Return column (2nd dimension). Packets for all threads"""
         return [pair[0] for pair in self]
 
     def octets(self):
         return [pair[0] for pair in self]
 
     def octets(self):
-        '''Return column (2nd dimension). Octets for all threads'''
+        """Return column (2nd dimension). Octets for all threads"""
         return [pair[1] for pair in self]
 
     def sum_packets(self):
         return [pair[1] for pair in self]
 
     def sum_packets(self):
-        '''Return column (2nd dimension). Sum of all packets for all threads'''
+        """Return column (2nd dimension). Sum of all packets for all threads"""
         return sum(self.packets())
 
     def sum_octets(self):
         return sum(self.packets())
 
     def sum_octets(self):
-        '''Return column (2nd dimension). Sum of all octets for all threads'''
+        """Return column (2nd dimension). Sum of all octets for all threads"""
         return sum(self.octets())
 
         return sum(self.octets())
 
+
 class StatsTuple(tuple):
 class StatsTuple(tuple):
-    '''A Combined vector tuple (packets, octets)'''
+    """A Combined vector tuple (packets, octets)"""
+
     def __init__(self, data):
     def __init__(self, data):
-        self.dictionary = {'packets': data[0], 'bytes': data[1]}
+        self.dictionary = {"packets": data[0], "bytes": data[1]}
         super().__init__()
 
     def __repr__(self):
         super().__init__()
 
     def __repr__(self):
@@ -344,28 +370,32 @@ class StatsTuple(tuple):
     def __getitem__(self, item):
         if isinstance(item, int):
             return tuple.__getitem__(self, item)
     def __getitem__(self, item):
         if isinstance(item, int):
             return tuple.__getitem__(self, item)
-        if item == 'packets':
+        if item == "packets":
             return tuple.__getitem__(self, 0)
         return tuple.__getitem__(self, 1)
 
             return tuple.__getitem__(self, 0)
         return tuple.__getitem__(self, 1)
 
+
 class StatsSimpleList(list):
 class StatsSimpleList(list):
-    '''Simple Counters 2-dimensional by thread by index of packets'''
+    """Simple Counters 2-dimensional by thread by index of packets"""
 
     def __getitem__(self, item):
 
     def __getitem__(self, item):
-        '''Supports partial numpy style 2d support. Slice by column [:,1]'''
+        """Supports partial numpy style 2d support. Slice by column [:,1]"""
         if isinstance(item, int):
             return list.__getitem__(self, item)
         return SimpleList([row[item[1]] for row in self])
 
         if isinstance(item, int):
             return list.__getitem__(self, item)
         return SimpleList([row[item[1]] for row in self])
 
+
 class SimpleList(list):
 class SimpleList(list):
-    '''Simple counter'''
+    """Simple counter"""
 
     def sum(self):
 
     def sum(self):
-        '''Sum the vector'''
+        """Sum the vector"""
         return sum(self)
 
         return sum(self)
 
-class StatsEntry():
-    '''An individual stats entry'''
+
+class StatsEntry:
+    """An individual stats entry"""
+
     # pylint: disable=unused-argument,no-self-use
 
     def __init__(self, stattype, statvalue):
     # pylint: disable=unused-argument,no-self-use
 
     def __init__(self, stattype, statvalue):
@@ -386,115 +416,128 @@ class StatsEntry():
             self.function = self.illegal
 
     def illegal(self, stats):
             self.function = self.illegal
 
     def illegal(self, stats):
-        '''Invalid or unknown counter type'''
+        """Invalid or unknown counter type"""
         return None
 
     def scalar(self, stats):
         return None
 
     def scalar(self, stats):
-        '''Scalar counter'''
+        """Scalar counter"""
         return self.value
 
     def simple(self, stats):
         return self.value
 
     def simple(self, stats):
-        '''Simple counter'''
+        """Simple counter"""
         counter = StatsSimpleList()
         counter = StatsSimpleList()
-        for threads in StatsVector(stats, self.value, 'P'):
-            clist = [v[0] for v in StatsVector(stats, threads[0], 'Q')]
+        for threads in StatsVector(stats, self.value, "P"):
+            clist = [v[0] for v in StatsVector(stats, threads[0], "Q")]
             counter.append(clist)
         return counter
 
     def combined(self, stats):
             counter.append(clist)
         return counter
 
     def combined(self, stats):
-        '''Combined counter'''
+        """Combined counter"""
         counter = StatsCombinedList()
         counter = StatsCombinedList()
-        for threads in StatsVector(stats, self.value, 'P'):
-            clist = [StatsTuple(cnt) for cnt in StatsVector(stats, threads[0], 'QQ')]
+        for threads in StatsVector(stats, self.value, "P"):
+            clist = [StatsTuple(cnt) for cnt in StatsVector(stats, threads[0], "QQ")]
             counter.append(clist)
         return counter
 
     def name(self, stats):
             counter.append(clist)
         return counter
 
     def name(self, stats):
-        '''Name counter'''
+        """Name counter"""
         counter = []
         counter = []
-        for name in StatsVector(stats, self.value, 'P'):
+        for name in StatsVector(stats, self.value, "P"):
             if name[0]:
                 counter.append(get_string(stats, name[0]))
         return counter
 
             if name[0]:
                 counter.append(get_string(stats, name[0]))
         return counter
 
-    SYMLINK_FMT1 = Struct('II')
-    SYMLINK_FMT2 = Struct('Q')
+    SYMLINK_FMT1 = Struct("II")
+    SYMLINK_FMT2 = Struct("Q")
+
     def symlink(self, stats):
     def symlink(self, stats):
-        '''Symlink counter'''
+        """Symlink counter"""
         b = self.SYMLINK_FMT2.pack(self.value)
         index1, index2 = self.SYMLINK_FMT1.unpack(b)
         name = stats.directory_by_idx[index1]
         b = self.SYMLINK_FMT2.pack(self.value)
         index1, index2 = self.SYMLINK_FMT1.unpack(b)
         name = stats.directory_by_idx[index1]
-        return stats[name][:,index2]
+        return stats[name][:, index2]
 
     def get_counter(self, stats):
 
     def get_counter(self, stats):
-        '''Return a list of counters'''
+        """Return a list of counters"""
         if stats:
             return self.function(stats)
 
         if stats:
             return self.function(stats)
 
+
 class TestStats(unittest.TestCase):
 class TestStats(unittest.TestCase):
-    '''Basic statseg tests'''
+    """Basic statseg tests"""
 
     def setUp(self):
 
     def setUp(self):
-        '''Connect to statseg'''
+        """Connect to statseg"""
         self.stat = VPPStats()
         self.stat.connect()
         self.profile = cProfile.Profile()
         self.profile.enable()
 
     def tearDown(self):
         self.stat = VPPStats()
         self.stat.connect()
         self.profile = cProfile.Profile()
         self.profile.enable()
 
     def tearDown(self):
-        '''Disconnect from statseg'''
+        """Disconnect from statseg"""
         self.stat.disconnect()
         profile = Stats(self.profile)
         profile.strip_dirs()
         self.stat.disconnect()
         profile = Stats(self.profile)
         profile.strip_dirs()
-        profile.sort_stats('cumtime')
+        profile.sort_stats("cumtime")
         profile.print_stats()
         print("\n--->>>")
 
     def test_counters(self):
         profile.print_stats()
         print("\n--->>>")
 
     def test_counters(self):
-        '''Test access to statseg'''
-
-        print('/err/abf-input-ip4/missed', self.stat['/err/abf-input-ip4/missed'])
-        print('/sys/heartbeat', self.stat['/sys/heartbeat'])
-        print('/if/names', self.stat['/if/names'])
-        print('/if/rx-miss', self.stat['/if/rx-miss'])
-        print('/if/rx-miss', self.stat['/if/rx-miss'][1])
-        print('/nat44-ed/out2in/slowpath/drops', self.stat['/nat44-ed/out2in/slowpath/drops'])
+        """Test access to statseg"""
+
+        print("/err/abf-input-ip4/missed", self.stat["/err/abf-input-ip4/missed"])
+        print("/sys/heartbeat", self.stat["/sys/heartbeat"])
+        print("/if/names", self.stat["/if/names"])
+        print("/if/rx-miss", self.stat["/if/rx-miss"])
+        print("/if/rx-miss", self.stat["/if/rx-miss"][1])
+        print(
+            "/nat44-ed/out2in/slowpath/drops",
+            self.stat["/nat44-ed/out2in/slowpath/drops"],
+        )
         with self.assertRaises(KeyError):
         with self.assertRaises(KeyError):
-            print('NO SUCH COUNTER', self.stat['foobar'])
-        print('/if/rx', self.stat.get_counter('/if/rx'))
-        print('/err/ethernet-input/no_error',
-              self.stat.get_counter('/err/ethernet-input/no_error'))
+            print("NO SUCH COUNTER", self.stat["foobar"])
+        print("/if/rx", self.stat.get_counter("/if/rx"))
+        print(
+            "/err/ethernet-input/no_error",
+            self.stat.get_counter("/err/ethernet-input/no_error"),
+        )
 
     def test_column(self):
 
     def test_column(self):
-        '''Test column slicing'''
-
-        print('/if/rx-miss', self.stat['/if/rx-miss'])
-        print('/if/rx', self.stat['/if/rx'])  # All interfaces for thread #1
-        print('/if/rx thread #1', self.stat['/if/rx'][0])  # All interfaces for thread #1
-        print('/if/rx thread #1, interface #1',
-              self.stat['/if/rx'][0][1])  # All interfaces for thread #1
-        print('/if/rx if_index #1', self.stat['/if/rx'][:, 1])
-        print('/if/rx if_index #1 packets', self.stat['/if/rx'][:, 1].packets())
-        print('/if/rx if_index #1 packets', self.stat['/if/rx'][:, 1].sum_packets())
-        print('/if/rx if_index #1 packets', self.stat['/if/rx'][:, 1].octets())
-        print('/if/rx-miss', self.stat['/if/rx-miss'])
-        print('/if/rx-miss if_index #1 packets', self.stat['/if/rx-miss'][:, 1].sum())
-        print('/if/rx if_index #1 packets', self.stat['/if/rx'][0][1]['packets'])
+        """Test column slicing"""
+
+        print("/if/rx-miss", self.stat["/if/rx-miss"])
+        print("/if/rx", self.stat["/if/rx"])  # All interfaces for thread #1
+        print(
+            "/if/rx thread #1", self.stat["/if/rx"][0]
+        )  # All interfaces for thread #1
+        print(
+            "/if/rx thread #1, interface #1", self.stat["/if/rx"][0][1]
+        )  # All interfaces for thread #1
+        print("/if/rx if_index #1", self.stat["/if/rx"][:, 1])
+        print("/if/rx if_index #1 packets", self.stat["/if/rx"][:, 1].packets())
+        print("/if/rx if_index #1 packets", self.stat["/if/rx"][:, 1].sum_packets())
+        print("/if/rx if_index #1 packets", self.stat["/if/rx"][:, 1].octets())
+        print("/if/rx-miss", self.stat["/if/rx-miss"])
+        print("/if/rx-miss if_index #1 packets", self.stat["/if/rx-miss"][:, 1].sum())
+        print("/if/rx if_index #1 packets", self.stat["/if/rx"][0][1]["packets"])
 
     def test_nat44(self):
 
     def test_nat44(self):
-        '''Test the nat counters'''
+        """Test the nat counters"""
 
 
-        print('/nat44-ei/ha/del-event-recv', self.stat['/nat44-ei/ha/del-event-recv'])
-        print('/err/nat44-ei-ha/pkts-processed', self.stat['/err/nat44-ei-ha/pkts-processed'].sum())
+        print("/nat44-ei/ha/del-event-recv", self.stat["/nat44-ei/ha/del-event-recv"])
+        print(
+            "/err/nat44-ei-ha/pkts-processed",
+            self.stat["/err/nat44-ei-ha/pkts-processed"].sum(),
+        )
 
     def test_legacy(self):
 
     def test_legacy(self):
-        '''Legacy interface'''
+        """Legacy interface"""
         directory = self.stat.ls(["^/if", "/err/ip4-input", "/sys/node/ip4-input"])
         data = self.stat.dump(directory)
         print(data)
         directory = self.stat.ls(["^/if", "/err/ip4-input", "/sys/node/ip4-input"])
         data = self.stat.dump(directory)
         print(data)
-        print('Looking up sys node')
+        print("Looking up sys node")
         directory = self.stat.ls(["^/sys/node"])
         directory = self.stat.ls(["^/sys/node"])
-        print('Dumping sys node')
+        print("Dumping sys node")
         data = self.stat.dump(directory)
         print(data)
         directory = self.stat.ls(["^/foobar"])
         data = self.stat.dump(directory)
         print(data)
         directory = self.stat.ls(["^/foobar"])
@@ -502,18 +545,19 @@ class TestStats(unittest.TestCase):
         print(data)
 
     def test_sys_nodes(self):
         print(data)
 
     def test_sys_nodes(self):
-        '''Test /sys/nodes'''
-        counters = self.stat.ls('^/sys/node')
-        print('COUNTERS:', counters)
-        print('/sys/node', self.stat.dump(counters))
-        print('/net/route/to', self.stat['/net/route/to'])
+        """Test /sys/nodes"""
+        counters = self.stat.ls("^/sys/node")
+        print("COUNTERS:", counters)
+        print("/sys/node", self.stat.dump(counters))
+        print("/net/route/to", self.stat["/net/route/to"])
 
     def test_symlink(self):
 
     def test_symlink(self):
-        '''Symbolic links'''
-        print('/interface/local0/rx', self.stat['/interfaces/local0/rx'])
-        print('/sys/nodes/unix-epoll-input', self.stat['/nodes/unix-epoll-input/calls'])
+        """Symbolic links"""
+        print("/interface/local0/rx", self.stat["/interfaces/local0/rx"])
+        print("/sys/nodes/unix-epoll-input", self.stat["/nodes/unix-epoll-input/calls"])
+
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     import cProfile
     from pstats import Stats
 
     import cProfile
     from pstats import Stats