Blob Blame History Raw
From ce8cacdd515bf7270daef62648d5f994f111cded Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Thu, 2 Dec 2021 16:52:10 -0500
Subject: [PATCH 1/2] python-linux-procfs: Various clean-ups

- Replace f=open with 'with' (context managers), except in try-except blocks
- Reformat lines that are too long, especially in comments
- Use min() instead of if construct
- Use bool instead of complicated and True or False constructs
- Reorder imports

Signed-off-by: John Kacur <jkacur@redhat.com>
---
 procfs/procfs.py | 292 +++++++++++++++++++++++------------------------
 1 file changed, 142 insertions(+), 150 deletions(-)

diff --git a/procfs/procfs.py b/procfs/procfs.py
index a0e9977214fe..a78bac5376e3 100755
--- a/procfs/procfs.py
+++ b/procfs/procfs.py
@@ -19,10 +19,10 @@
 #
 
 import os
-import time
-from functools import reduce
 import platform
 import re
+import time
+from functools import reduce
 from six.moves import range
 from procfs.utilist import bitmasklist
 
@@ -37,8 +37,9 @@ def is_s390():
 
 def process_cmdline(pid_info):
     """
-    Returns the process command line, if available in the given `process' class, if
-    not available, falls back to using the comm (short process name) in its pidstat key.
+    Returns the process command line, if available in the given `process' class,
+    if not available, falls back to using the comm (short process name) in its
+    pidstat key.
     """
     if pid_info["cmdline"]:
         return reduce(lambda a, b: a + " %s" % b, pid_info["cmdline"]).strip()
@@ -47,10 +48,12 @@ def process_cmdline(pid_info):
 
 
 class pidstat:
-    """Provides a dictionary to access the fields in the per process /proc/PID/stat
-       files.
+    """
+    Provides a dictionary to access the fields in the
+    per process /proc/PID/stat files.
 
-       One can obtain the available fields asking for the keys of the dictionary, e.g.:
+    One can obtain the available fields by asking for the keys of the
+    dictionary, e.g.:
 
         >>> p = procfs.pidstat(1)
         >>> print p.keys()
@@ -182,8 +185,7 @@ class pidstat:
         Returns true if this process has a fixed smp affinity mask,
                 not allowing it to be moved to a different set of CPUs.
         """
-        return self.fields["flags"] & self.PF_THREAD_BOUND and \
-            True or False
+        return bool(self.fields["flags"] & self.PF_THREAD_BOUND)
 
     def process_flags(self):
         """
@@ -193,33 +195,34 @@ class pidstat:
 
         As of v4.2-rc7 these include (from include/linux/sched.h comments):
 
-            PF_EXITING       Getting shut down
-            PF_EXITPIDONE       Pi exit done on shut down
+            PF_EXITING        Getting shut down
+            PF_EXITPIDONE     Pi exit done on shut down
             PF_VCPU           I'm a virtual CPU
-            PF_WQ_WORKER       I'm a workqueue worker
-            PF_FORKNOEXEC       Forked but didn't exec
-            PF_MCE_PROCESS       Process policy on mce errors
-            PF_SUPERPRIV       Used super-user privileges
+            PF_WQ_WORKER      I'm a workqueue worker
+            PF_FORKNOEXEC     Forked but didn't exec
+            PF_MCE_PROCESS    Process policy on mce errors
+            PF_SUPERPRIV      Used super-user privileges
             PF_DUMPCORE       Dumped core
             PF_SIGNALED       Killed by a signal
             PF_MEMALLOC       Allocating memory
-            PF_NPROC_EXCEEDED  Set_user noticed that RLIMIT_NPROC was exceeded
-            PF_USED_MATH       If unset the fpu must be initialized before use
-            PF_USED_ASYNC       Used async_schedule*(), used by module init
+            PF_NPROC_EXCEEDED Set_user noticed that RLIMIT_NPROC was exceeded
+            PF_USED_MATH      If unset the fpu must be initialized before use
+            PF_USED_ASYNC     Used async_schedule*(), used by module init
             PF_NOFREEZE       This thread should not be frozen
-            PF_FROZEN       Frozen for system suspend
-            PF_FSTRANS       Inside a filesystem transaction
-            PF_KSWAPD       I am kswapd
+            PF_FROZEN          Frozen for system suspend
+            PF_FSTRANS         Inside a filesystem transaction
+            PF_KSWAPD          I am kswapd
             PF_MEMALLOC_NOIO   Allocating memory without IO involved
             PF_LESS_THROTTLE   Throttle me less: I clean memory
-            PF_KTHREAD       I am a kernel thread
+            PF_KTHREAD         I am a kernel thread
             PF_RANDOMIZE       Randomize virtual address space
             PF_SWAPWRITE       Allowed to write to swap
             PF_NO_SETAFFINITY  Userland is not allowed to meddle with cpus_allowed
             PF_MCE_EARLY       Early kill for mce process policy
-            PF_MUTEX_TESTER       Thread belongs to the rt mutex tester
-            PF_FREEZER_SKIP       Freezer should not count it as freezable
-            PF_SUSPEND_TASK       This thread called freeze_processes and should not be frozen
+            PF_MUTEX_TESTER    Thread belongs to the rt mutex tester
+            PF_FREEZER_SKIP    Freezer should not count it as freezable
+            PF_SUSPEND_TASK    This thread called freeze_processes and
+                               should not be frozen
 
         """
         sflags = []
@@ -236,8 +239,8 @@ class pidstat:
 def cannot_set_affinity(self, pid):
     PF_NO_SETAFFINITY = 0x04000000
     try:
-        return int(self.processes[pid]["stat"]["flags"]) & \
-            PF_NO_SETAFFINITY and True or False
+        return bool(int(self.processes[pid]["stat"]["flags"]) &
+                    PF_NO_SETAFFINITY)
     except:
         return True
 
@@ -245,19 +248,21 @@ def cannot_set_affinity(self, pid):
 def cannot_set_thread_affinity(self, pid, tid):
     PF_NO_SETAFFINITY = 0x04000000
     try:
-        return int(self.processes[pid].threads[tid]["stat"]["flags"]) & \
-            PF_NO_SETAFFINITY and True or False
+        return bool(int(self.processes[pid].threads[tid]["stat"]["flags"]) &
+                    PF_NO_SETAFFINITY)
     except:
         return True
 
 
 class pidstatus:
     """
-    Provides a dictionary to access the fields in the per process /proc/PID/status
-    files. This provides additional information about processes and threads to what
-    can be obtained with the procfs.pidstat() class.
+    Provides a dictionary to access the fields
+    in the per process /proc/PID/status files.
+    This provides additional information about processes and threads to
+    what can be obtained with the procfs.pidstat() class.
 
-    One can obtain the available fields asking for the keys of the dictionary, e.g.:
+    One can obtain the available fields by asking for the keys of the
+    dictionary, e.g.:
 
         >>> import procfs
         >>> p = procfs.pidstatus(1)
@@ -312,19 +317,18 @@ class pidstatus:
         return fieldname in self.fields
 
     def load(self, basedir="/proc"):
-        f = open("%s/%d/status" % (basedir, self.pid))
         self.fields = {}
-        for line in f.readlines():
-            fields = line.split(":")
-            if len(fields) != 2:
-                continue
-            name = fields[0]
-            value = fields[1].strip()
-            try:
-                self.fields[name] = int(value)
-            except:
-                self.fields[name] = value
-        f.close()
+        with open("%s/%d/status" % (basedir, self.pid)) as f:
+            for line in f.readlines():
+                fields = line.split(":")
+                if len(fields) != 2:
+                    continue
+                name = fields[0]
+                value = fields[1].strip()
+                try:
+                    self.fields[name] = int(value)
+                except:
+                    self.fields[name] = value
 
 
 class process:
@@ -380,14 +384,13 @@ class process:
         del self.threads[self.pid]
 
     def load_cgroups(self):
-        f = open("/proc/%d/cgroup" % self.pid)
         self.cgroups = ""
-        for line in reversed(f.readlines()):
-            if len(self.cgroups) != 0:
-                self.cgroups = self.cgroups + "," + line[:-1]
-            else:
-                self.cgroups = line[:-1]
-        f.close()
+        with open("/proc/%d/cgroup" % self.pid) as f:
+            for line in reversed(f.readlines()):
+                if len(self.cgroups) != 0:
+                    self.cgroups = self.cgroups + "," + line[:-1]
+                else:
+                    self.cgroups = line[:-1]
 
     def load_environ(self):
         """
@@ -416,12 +419,11 @@ class process:
         >>>
         """
         self.environ = {}
-        f = open("/proc/%d/environ" % self.pid)
-        for x in f.readline().split('\0'):
-            if len(x) > 0:
-                y = x.split('=')
-                self.environ[y[0]] = y[1]
-        f.close()
+        with open("/proc/%d/environ" % self.pid) as f:
+            for x in f.readline().split('\0'):
+                if len(x) > 0:
+                    y = x.split('=')
+                    self.environ[y[0]] = y[1]
 
 
 class pidstats:
@@ -465,18 +467,18 @@ class pidstats:
 
     def reload(self):
         """
-        This operation will throw away the current dictionary contents, if any, and
-        read all the pid files from /proc/, instantiating a 'process' instance for
-        each of them.
+        This operation will throw away the current dictionary contents,
+        if any, and read all the pid files from /proc/, instantiating a
+        'process' instance for each of them.
 
-        This is a high overhead operation, and should be avoided if the perf python
-        binding can be used to detect when new threads appear and existing ones
-        terminate.
+        This is a high overhead operation, and should be avoided if the
+        perf python binding can be used to detect when new threads appear
+        and existing ones terminate.
 
         In RHEL it is found in the python-perf rpm package.
 
-        More information about the perf facilities can be found in the 'perf_event_open'
-        man page.
+        More information about the perf facilities can be found in the
+        'perf_event_open' man page.
         """
         del self.processes
         self.processes = {}
@@ -643,24 +645,21 @@ class interrupts:
     def reload(self):
         del self.interrupts
         self.interrupts = {}
-        f = open("/proc/interrupts")
-
-        for line in f.readlines():
-            line = line.strip()
-            fields = line.split()
-            if fields[0][:3] == "CPU":
-                self.nr_cpus = len(fields)
-                continue
-            irq = fields[0].strip(":")
-            self.interrupts[irq] = {}
-            self.interrupts[irq] = self.parse_entry(fields[1:], line)
-            try:
-                nirq = int(irq)
-            except:
-                continue
-            self.interrupts[irq]["affinity"] = self.parse_affinity(nirq)
-
-        f.close()
+        with open("/proc/interrupts") as f:
+            for line in f.readlines():
+                line = line.strip()
+                fields = line.split()
+                if fields[0][:3] == "CPU":
+                    self.nr_cpus = len(fields)
+                    continue
+                irq = fields[0].strip(":")
+                self.interrupts[irq] = {}
+                self.interrupts[irq] = self.parse_entry(fields[1:], line)
+                try:
+                    nirq = int(irq)
+                except:
+                    continue
+                self.interrupts[irq]["affinity"] = self.parse_affinity(nirq)
 
     def parse_entry(self, fields, line):
         dict = {}
@@ -681,9 +680,8 @@ class interrupts:
 
     def parse_affinity(self, irq):
         try:
-            f = open("/proc/irq/%s/smp_affinity" % irq)
-            line = f.readline()
-            f.close()
+            with open("/proc/irq/%s/smp_affinity" % irq) as f:
+                line = f.readline()
             return bitmasklist(line, self.nr_cpus)
         except IOError:
             return [0, ]
@@ -741,11 +739,11 @@ class cmdline:
     """
     Parses the kernel command line (/proc/cmdline), turning it into a dictionary."
 
-    Useful to figure out if some kernel boolean knob has been turned on, as well
-    as to find the value associated to other kernel knobs.
+    Useful to figure out if some kernel boolean knob has been turned on,
+    as well as to find the value associated to other kernel knobs.
 
-    It can also be used to find out about parameters passed to the init process,
-    such as 'BOOT_IMAGE', etc.
+    It can also be used to find out about parameters passed to the
+    init process, such as 'BOOT_IMAGE', etc.
 
     E.g.:
     >>> import procfs
@@ -762,15 +760,13 @@ class cmdline:
         self.parse()
 
     def parse(self):
-        f = open("/proc/cmdline")
-        for option in f.readline().strip().split():
-            fields = option.split("=")
-            if len(fields) == 1:
-                self.options[fields[0]] = True
-            else:
-                self.options[fields[0]] = fields[1]
-
-        f.close()
+        with open("/proc/cmdline") as f:
+            for option in f.readline().strip().split():
+                fields = option.split("=")
+                if len(fields) == 1:
+                    self.options[fields[0]] = True
+                else:
+                    self.options[fields[0]] = fields[1]
 
     def __getitem__(self, key):
         return self.options[key]
@@ -790,9 +786,9 @@ class cpuinfo:
     Dictionary with information about CPUs in the system.
 
     Please refer to 'man procfs(5)' for further information about the
-        '/proc/cpuinfo' file, that is the source of the information provided by this
-        class. The 'man lscpu(1)' also has information about a program that uses
-    the '/proc/cpuinfo' file.
+    '/proc/cpuinfo' file, that is the source of the information provided
+    by this class. The 'man lscpu(1)' also has information about a program that
+    uses the '/proc/cpuinfo' file.
 
     Using this class one can obtain the number of CPUs in a system:
 
@@ -801,14 +797,14 @@ class cpuinfo:
           4
 
     It is also possible to figure out aspects of the CPU topology, such as
-    how many CPU physical sockets exists, i.e. groups of CPUs sharing components
-    such as CPU memory caches:
+    how many CPU physical sockets exists, i.e. groups of CPUs sharing
+    components such as CPU memory caches:
 
       >>> print len(cpus.sockets)
       1
 
-    Additionally dictionary with information common to all CPUs in the system is
-    available:
+    Additionally dictionary with information common to all CPUs in the system
+    is available:
 
       >>> print cpus["model name"]
           Intel(R) Core(TM) i7-3667U CPU @ 2.00GHz
@@ -836,28 +832,26 @@ class cpuinfo:
         return self.tags
 
     def parse(self, filename):
-        f = open(filename)
-        for line in f.readlines():
-            line = line.strip()
-            if not line:
-                continue
-            fields = line.split(":")
-            tagname = fields[0].strip().lower()
-            if tagname == "processor":
-                self.nr_cpus += 1
-                continue
-            if is_s390() and tagname == "cpu number":
-                self.nr_cpus += 1
-                continue
-            if tagname == "core id":
-                continue
-            self.tags[tagname] = fields[1].strip()
-            if tagname == "physical id":
-                socket_id = self.tags[tagname]
-                if socket_id not in self.sockets:
-                    self.sockets.append(socket_id)
-
-        f.close()
+        with open(filename) as f:
+            for line in f.readlines():
+                line = line.strip()
+                if not line:
+                    continue
+                fields = line.split(":")
+                tagname = fields[0].strip().lower()
+                if tagname == "processor":
+                    self.nr_cpus += 1
+                    continue
+                if is_s390() and tagname == "cpu number":
+                    self.nr_cpus += 1
+                    continue
+                if tagname == "core id":
+                    continue
+                self.tags[tagname] = fields[1].strip()
+                if tagname == "physical id":
+                    socket_id = self.tags[tagname]
+                    if socket_id not in self.sockets:
+                        self.sockets.append(socket_id)
         self.nr_sockets = self.sockets and len(self.sockets) or \
             (self.nr_cpus /
              ("siblings" in self.tags and int(self.tags["siblings"]) or 1))
@@ -870,7 +864,8 @@ class smaps_lib:
     Representation of an mmap in place for a process. Can be used to figure
     out which processes have an library mapped, etc.
 
-    The 'perm' member can be used to figure out executable mmaps, i.e. libraries.
+    The 'perm' member can be used to figure out executable mmaps,
+    i.e. libraries.
 
     The 'vm_start' and 'vm_end' in turn can be used when trying to resolve
     processor instruction pointer addresses to a symbol name in a library.
@@ -967,13 +962,12 @@ class smaps:
         return self.entries[index]
 
     def reload(self):
-        f = open("/proc/%d/smaps" % self.pid)
         line = None
-        while True:
-            line = self.parse_entry(f, line)
-            if not line:
-                break
-        f.close()
+        with("/proc/%d/smaps" % self.pid) as f:
+            while True:
+                line = self.parse_entry(f, line)
+                if not line:
+                    break
         self.nr_entries = len(self.entries)
 
     def find_by_name_fragment(self, fragment):
@@ -1055,18 +1049,17 @@ class cpusstats:
     def reload(self):
         last_entries = self.entries
         self.entries = {}
-        f = open(self.filename)
-        for line in f.readlines():
-            fields = line.strip().split()
-            if fields[0][:3].lower() != "cpu":
-                continue
-            c = cpustat(fields)
-            if c.name == "cpu":
-                idx = 0
-            else:
-                idx = int(c.name[3:]) + 1
-            self.entries[idx] = c
-        f.close()
+        with open(self.filename) as f:
+            for line in f.readlines():
+                fields = line.strip().split()
+                if fields[0][:3].lower() != "cpu":
+                    continue
+                c = cpustat(fields)
+                if c.name == "cpu":
+                    idx = 0
+                else:
+                    idx = int(c.name[3:]) + 1
+                self.entries[idx] = c
         last_time = self.time
         self.time = time.time()
         if last_entries:
@@ -1082,8 +1075,7 @@ class cpusstats:
                     (curr.nice - prev.nice) + \
                     (curr.system - prev.system)
                 curr.usage = (delta / interval_hz) * 100
-                if curr.usage > 100:
-                    curr.usage = 100
+                curr.usage = min(curr.usage, 100)
 
 
 if __name__ == '__main__':
-- 
2.31.1