From 0fc4ab84c8cbba1fbe83dc71fb89100b87c54898 Mon Sep 17 00:00:00 2001 From: Paul Wise Date: Sun, 2 Sep 2012 09:43:13 +0800 Subject: [PATCH] Port to Python 3 Not entirely sure about all parts of this but it works in Python 2/3 --- iotop/data.py | 39 +++++++++++++++++++-------------------- iotop/genetlink.py | 4 ++-- iotop/ioprio.py | 4 ++-- iotop/netlink.py | 9 +++++---- iotop/ui.py | 47 +++++++++++++++++++++++++---------------------- 5 files changed, 53 insertions(+), 50 deletions(-) diff --git a/iotop/data.py b/iotop/data.py index b51a083..d817492 100644 --- a/iotop/data.py +++ b/iotop/data.py @@ -49,23 +49,23 @@ else: vm_event_counters = True if not ioaccounting or not has_ctypes or not vm_event_counters: - print 'Could not run iotop as some of the requirements are not met:' + print('Could not run iotop as some of the requirements are not met:') if not ioaccounting or not vm_event_counters: - print '- Linux >= 2.6.20 with' + print('- Linux >= 2.6.20 with') if not ioaccounting: - print ' - I/O accounting support ' \ + print(' - I/O accounting support ' \ '(CONFIG_TASKSTATS, CONFIG_TASK_DELAY_ACCT, ' \ - 'CONFIG_TASK_IO_ACCOUNTING)' + 'CONFIG_TASK_IO_ACCOUNTING)') if not vm_event_counters: - print ' - VM event counters (CONFIG_VM_EVENT_COUNTERS)' + print(' - VM event counters (CONFIG_VM_EVENT_COUNTERS)') if not has_ctypes: - print '- Python >= 2.5 or Python 2.4 with the ctypes module' + print('- Python >= 2.5 or Python 2.4 with the ctypes module') sys.exit(1) from iotop import ioprio, vmstat -from netlink import Connection, NETLINK_GENERIC, U32Attr, NLM_F_REQUEST -from genetlink import Controller, GeNlMessage +from iotop.netlink import Connection, NETLINK_GENERIC, U32Attr, NLM_F_REQUEST +from iotop.genetlink import Controller, GeNlMessage class DumpableObject(object): """Base class for all objects that allows easy introspection when printed""" @@ -154,12 +154,12 @@ class TaskStatsNetlink(object): thread.task_stats_request.send(self.connection) try: reply = GeNlMessage.recv(self.connection) - except OSError, e: + except OSError as e: if e.errno == errno.ESRCH: # OSError: Netlink error: No such process (3) return raise - for attr_type, attr_value in reply.attrs.iteritems(): + for attr_type, attr_value in reply.attrs.items(): if attr_type == TASKSTATS_TYPE_AGGR_PID: reply = attr_value.nested() break @@ -214,6 +214,8 @@ def safe_utf8_decode(s): return s.decode('utf-8') except UnicodeDecodeError: return s.encode('string_escape') + except AttributeError: + return s class ThreadInfo(DumpableObject): """Stats for a single thread""" @@ -285,7 +287,7 @@ class ProcessInfo(DumpableObject): if uid is not None and not self.user: try: self.user = safe_utf8_decode(pwd.getpwuid(uid).pw_name) - except KeyError: + except (KeyError, AttributeError): self.user = str(uid) return self.user or '{none}' @@ -329,7 +331,7 @@ class ProcessInfo(DumpableObject): return False def get_ioprio(self): - priorities = set(t.get_ioprio() for t in self.threads.itervalues()) + priorities = set(t.get_ioprio() for t in self.threads.values()) if len(priorities) == 1: return priorities.pop() return '?dif' @@ -351,10 +353,9 @@ class ProcessInfo(DumpableObject): def update_stats(self): stats_delta = Stats.build_all_zero() for tid, thread in self.threads.items(): - if thread.mark: - del self.threads[tid] - else: + if not thread.mark: stats_delta.accumulate(thread.stats_delta, stats_delta) + self.threads = dict([(tid, thread) for tid, thread in self.threads.items() if not thread.mark]) nr_threads = len(self.threads) if not nr_threads: @@ -442,15 +443,13 @@ class ProcessList(DumpableObject): return self.vmstat.delta() def refresh_processes(self): - for process in self.processes.itervalues(): - for thread in process.threads.itervalues(): + for process in self.processes.values(): + for thread in process.threads.values(): thread.mark = True total_read_and_write = self.update_process_counts() - for pid, process in self.processes.items(): - if not process.update_stats(): - del self.processes[pid] + self.processes = dict([(pid,process) for pid, process in self.processes.items() if process.update_stats()]) return total_read_and_write diff --git a/iotop/genetlink.py b/iotop/genetlink.py index f9abf15..66f3d02 100644 --- a/iotop/genetlink.py +++ b/iotop/genetlink.py @@ -7,8 +7,8 @@ GPLv2+; See copying for details. ''' import struct -from netlink import NLM_F_REQUEST, NLMSG_MIN_TYPE, Message, parse_attributes -from netlink import NulStrAttr, Connection, NETLINK_GENERIC +from iotop.netlink import NLM_F_REQUEST, NLMSG_MIN_TYPE, Message, parse_attributes +from iotop.netlink import NulStrAttr, Connection, NETLINK_GENERIC CTRL_CMD_UNSPEC = 0 CTRL_CMD_NEWFAMILY = 1 diff --git a/iotop/ioprio.py b/iotop/ioprio.py index 86a729f..afe6054 100644 --- a/iotop/ioprio.py +++ b/iotop/ioprio.py @@ -175,6 +175,6 @@ if __name__ == '__main__': pid = int(sys.argv[1]) else: pid = os.getpid() - print 'pid:', pid - print 'ioprio:', get(pid) + print('pid:', pid) + print('ioprio:', get(pid)) diff --git a/iotop/netlink.py b/iotop/netlink.py index 326045a..39f3b92 100644 --- a/iotop/netlink.py +++ b/iotop/netlink.py @@ -102,7 +102,7 @@ class Attr: hdr = struct.pack("HH", len(self.data)+4, self.type) length = len(self.data) pad = ((length + 4 - 1) & ~3 ) - length - return hdr + self.data + '\0' * pad + return hdr + self.data + b'\0' * pad def __repr__(self): return '' % (self.type, repr(self.data)) @@ -124,11 +124,12 @@ class Attr: class StrAttr(Attr): def __init__(self, attr_type, data): - Attr.__init__(self, attr_type, "%ds" % len(data), data) + Attr.__init__(self, attr_type, "%ds" % len(data), data.encode('utf-8')) class NulStrAttr(Attr): def __init__(self, attr_type, data): - Attr.__init__(self, attr_type, "%dsB" % len(data), data, 0) + print(data) + Attr.__init__(self, attr_type, "%dsB" % len(data), data.encode('utf-8'), 0) class U32Attr(Attr): def __init__(self, attr_type, val): @@ -181,7 +182,7 @@ class Message: contents = [] for attr in payload: contents.append(attr._dump()) - self.payload = ''.join(contents) + self.payload = b''.join(contents) else: self.payload = payload diff --git a/iotop/ui.py b/iotop/ui.py index bfec6d8..187ba18 100644 --- a/iotop/ui.py +++ b/iotop/ui.py @@ -16,6 +16,9 @@ # # Copyright (c) 2007 Guillaume Chazarain +# Allow printing with same syntax in Python 2/3 +from __future__ import print_function + import curses import errno import locale @@ -30,8 +33,8 @@ import time from iotop.data import find_uids, TaskStatsNetlink, ProcessList, Stats from iotop.data import ThreadInfo from iotop.version import VERSION -import ioprio -from ioprio import IoprioSetError +import iotop.ioprio +from iotop.ioprio import IoprioSetError # # Utility functions for the UI @@ -82,9 +85,9 @@ def format_stats(options, process, duration): def get_max_pid_width(): try: - return len(file('/proc/sys/kernel/pid_max').read().strip()) - except Exception, e: - print e + return len(open('/proc/sys/kernel/pid_max').read().strip()) + except Exception as e: + print(e) # Reasonable default in case something fails return 5 @@ -160,7 +163,7 @@ class IOTopUI(object): try: events = poll.poll(self.options.delay_seconds * 1000.0) - except select.error, e: + except select.error as e: if e.args and e.args[0] == errno.EINTR: events = 0 else: @@ -315,7 +318,7 @@ class IOTopUI(object): exec_unit.set_ioprio(ioprio_class, ioprio_data) self.process_list.clear() self.process_list.refresh_processes() - except IoprioSetError, e: + except IoprioSetError as e: self.prompt_error('Error setting I/O priority: %s' % e.err) except InvalidPid: self.prompt_error('Invalid process id!') @@ -396,7 +399,7 @@ class IOTopUI(object): return not self.options.only or \ p.did_some_io(self.options.accumulated) - processes = filter(should_format, self.process_list.processes.values()) + processes = list(filter(should_format, self.process_list.processes.values())) key = IOTopUI.sorting_keys[self.sorting_key][0] if self.options.accumulated: stats_lambda = lambda p: p.stats_accum @@ -406,7 +409,7 @@ class IOTopUI(object): reverse=self.sorting_reverse) if not self.options.batch: del processes[self.height - 2:] - return map(format, processes) + return list(map(format, processes)) def refresh_display(self, first_time, total_read, total_write, duration): summary = 'Total DISK READ: %s | Total DISK WRITE: %s' % ( @@ -428,18 +431,18 @@ class IOTopUI(object): summary = current_time + summary if self.options.batch: if self.options.quiet <= 2: - print summary + print(summary) if self.options.quiet <= int(first_time): - print ''.join(titles) + print(''.join(titles)) for l in lines: - print l.encode('utf-8') + print(l.encode('utf-8')) sys.stdout.flush() else: self.win.erase() self.win.addstr(summary[:self.width]) self.win.hline(1, 0, ord(' ') | curses.A_REVERSE, self.width) remaining_cols = self.width - for i in xrange(len(titles)): + for i in range(len(titles)): attr = curses.A_REVERSE title = titles[i] if i == self.sorting_key: @@ -456,9 +459,9 @@ class IOTopUI(object): status_msg = ('CONFIG_TASK_DELAY_ACCT not enabled in kernel, ' 'cannot determine SWAPIN and IO %') num_lines = min(len(lines), self.height - 2 - int(bool(status_msg))) - for i in xrange(num_lines): + for i in range(num_lines): try: - self.win.addstr(i + 2, 0, lines[i].encode('utf-8')) + self.win.addstr(i + 2, 0, lines[i]) except curses.error: pass if status_msg: @@ -479,17 +482,17 @@ def run_iotop(options): return run_iotop_window(None, options) else: return curses.wrapper(run_iotop_window, options) - except OSError, e: + except OSError as e: if e.errno == errno.EPERM: - print >> sys.stderr, e - print >> sys.stderr, (''' + print(e, file=sys.stderr) + print(''' The Linux kernel interfaces that iotop relies on now require root priviliges or the NET_ADMIN capability. This change occured because a security issue (CVE-2011-2494) was found that allows leakage of sensitive data across user boundaries. If you require the ability to run iotop as a non-root user, please configure sudo to allow you to run iotop as root. -Please do not file bugs on iotop about this.''') +Please do not file bugs on iotop about this.''', file=sys.stderr) sys.exit(1) else: raise @@ -503,14 +506,14 @@ def _profile(continuation): try: import cProfile import pstats - print 'Profiling using cProfile' + print('Profiling using cProfile') cProfile.runctx('continuation()', globals(), locals(), prof_file) stats = pstats.Stats(prof_file) except ImportError: import hotshot import hotshot.stats prof = hotshot.Profile(prof_file, lineevents=1) - print 'Profiling using hotshot' + print('Profiling using hotshot') prof.runcall(continuation) prof.close() stats = hotshot.stats.load(prof_file) @@ -540,7 +543,7 @@ def main(): try: locale.setlocale(locale.LC_ALL, '') except locale.Error: - print 'unable to set locale, falling back to the default locale' + print('unable to set locale, falling back to the default locale') parser = optparse.OptionParser(usage=USAGE, version='iotop ' + VERSION) parser.add_option('-o', '--only', action='store_true', dest='only', default=False, -- 2.11.4.GIT