diff options
author | Sergei Trofimov <sergei.trofimov@arm.com> | 2018-05-30 13:58:49 +0100 |
---|---|---|
committer | Marc Bonnici <marc.bonnici@arm.com> | 2018-06-07 14:48:40 +0100 |
commit | b3de85455a872cd269187fb36263a17390f14d9c (patch) | |
tree | 6f958313086eaebfe64c27699c2c7527fb5facaf /wa/utils | |
parent | c3ddb31d4d8ce58251b4876882a757cd643c097f (diff) |
Add support for Python 3
Add support for running under Python 3, while maintaining compatibility
with Python 2.
See http://python-future.org/compatible_idioms.html for more details
behind these changes.
Diffstat (limited to 'wa/utils')
-rwxr-xr-x | wa/utils/cpustates.py | 30 | ||||
-rw-r--r-- | wa/utils/diff.py | 23 | ||||
-rw-r--r-- | wa/utils/doc.py | 16 | ||||
-rw-r--r-- | wa/utils/exec_control.py | 8 | ||||
-rw-r--r-- | wa/utils/log.py | 4 | ||||
-rw-r--r-- | wa/utils/misc.py | 45 | ||||
-rw-r--r-- | wa/utils/revent.py | 10 | ||||
-rw-r--r-- | wa/utils/serializer.py | 28 | ||||
-rw-r--r-- | wa/utils/terminalsize.py | 2 | ||||
-rw-r--r-- | wa/utils/trace_cmd.py | 8 | ||||
-rw-r--r-- | wa/utils/types.py | 101 |
11 files changed, 150 insertions, 125 deletions
diff --git a/wa/utils/cpustates.py b/wa/utils/cpustates.py index 494b747e..c2557cd4 100755 --- a/wa/utils/cpustates.py +++ b/wa/utils/cpustates.py @@ -13,16 +13,17 @@ # limitations under the License. # -from __future__ import division + import os import sys -import csv import re import logging from ctypes import c_int32 from collections import defaultdict import argparse +from devlib.utils.csvutil import create_writer, csvwriter + from wa.utils.trace_cmd import TraceCmdParser, trace_has_marker, TRACE_MARKER_START, TRACE_MARKER_STOP @@ -114,7 +115,7 @@ class SystemPowerState(object): self.timestamp = None self.cpus = [] idle_state = -1 if no_idle else None - for _ in xrange(num_cores): + for _ in range(num_cores): self.cpus.append(CpuPowerState(idle_state=idle_state)) def copy(self): @@ -331,8 +332,7 @@ class PowerStateTransitions(object): def __init__(self, output_directory): self.filepath = os.path.join(output_directory, 'state-transitions-timeline.csv') - self._wfh = open(self.filepath, 'w') - self.writer = csv.writer(self._wfh) + self.writer, self._wfh = create_writer(self.filepath) headers = ['timestamp', 'cpu_id', 'frequency', 'idle_state'] self.writer.writerow(headers) @@ -360,8 +360,7 @@ class PowerStateTimeline(object): def __init__(self, output_directory, cpus): self.filepath = os.path.join(output_directory, 'power-state-timeline.csv') self.idle_state_names = {cpu.id: [s.name for s in cpu.cpuidle.states] for cpu in cpus} - self._wfh = open(self.filepath, 'w') - self.writer = csv.writer(self._wfh) + self.writer, self._wfh = create_writer(self.filepath) headers = ['ts'] + ['{} CPU{}'.format(cpu.name, cpu.id) for cpu in cpus] self.writer.writerow(headers) @@ -405,7 +404,7 @@ class ParallelStats(object): clusters.append(cpu.cpufreq.related_cpus) for i, clust in enumerate(clusters): - self.clusters[i] = set(clust) + self.clusters[str(i)] = set(clust) self.clusters['all'] = set([cpu.id for cpu in cpus]) self.first_timestamp = None @@ -419,7 +418,7 @@ class ParallelStats(object): delta = timestamp - self.last_timestamp active_cores = [i for i, c in enumerate(self.previous_states) if c and c[0] == -1] - for cluster, cluster_cores in self.clusters.iteritems(): + for cluster, cluster_cores in self.clusters.items(): clust_active_cores = len(cluster_cores.intersection(active_cores)) self.parallel_times[cluster][clust_active_cores] += delta if clust_active_cores: @@ -438,7 +437,7 @@ class ParallelStats(object): total_time = self.last_timestamp - self.first_timestamp for cluster in sorted(self.parallel_times): running_time = self.running_times[cluster] - for n in xrange(len(self.clusters[cluster]) + 1): + for n in range(len(self.clusters[cluster]) + 1): time = self.parallel_times[cluster][n] time_pc = time / total_time if not self.use_ratios: @@ -474,8 +473,7 @@ class ParallelReport(object): self.values.append(value) def write(self): - with open(self.filepath, 'w') as wfh: - writer = csv.writer(wfh) + with csvwriter(self.filepath) as writer: writer.writerow(['cluster', 'number_of_cores', 'total_time', '%time', '%running_time']) writer.writerows(self.values) @@ -520,7 +518,7 @@ class PowerStateStats(object): total_time = self.last_timestamp - self.first_timestamp state_stats = defaultdict(lambda: [None] * len(self.core_names)) - for cpu, states in self.cpu_states.iteritems(): + for cpu, states in self.cpu_states.items(): for state in states: time = states[state] time_pc = time / total_time @@ -543,8 +541,7 @@ class PowerStateStatsReport(object): self.precision = precision def write(self): - with open(self.filepath, 'w') as wfh: - writer = csv.writer(wfh) + with csvwriter(self.filepath) as writer: headers = ['state'] + ['{} CPU{}'.format(c, i) for i, c in enumerate(self.core_names)] writer.writerow(headers) @@ -561,8 +558,7 @@ class CpuUtilizationTimeline(object): def __init__(self, output_directory, cpus): self.filepath = os.path.join(output_directory, 'utilization-timeline.csv') - self._wfh = open(self.filepath, 'w') - self.writer = csv.writer(self._wfh) + self.writer, self._wfh = create_writer(self.filepath) headers = ['ts'] + ['{} CPU{}'.format(cpu.name, cpu.id) for cpu in cpus] self.writer.writerow(headers) diff --git a/wa/utils/diff.py b/wa/utils/diff.py index 9318f15c..c1bf3e67 100644 --- a/wa/utils/diff.py +++ b/wa/utils/diff.py @@ -1,11 +1,18 @@ -from wa.utils.misc import write_table +import os +import re + +from future.moves.itertools import zip_longest + +from wa.utils.misc import as_relative, diff_tokens, write_table +from wa.utils.misc import ensure_file_directory_exists as _f +from wa.utils.misc import ensure_directory_exists as _d def diff_interrupt_files(before, after, result): # pylint: disable=R0914 output_lines = [] with open(before) as bfh: with open(after) as ofh: - for bline, aline in izip(bfh, ofh): + for bline, aline in zip(bfh, ofh): bchunks = bline.strip().split() while True: achunks = aline.strip().split() @@ -20,7 +27,7 @@ def diff_interrupt_files(before, after, result): # pylint: disable=R0914 diffchunks = ['>'] + achunks output_lines.append(diffchunks) try: - aline = ofh.next() + aline = next(ofh) except StopIteration: break @@ -45,11 +52,9 @@ def diff_interrupt_files(before, after, result): # pylint: disable=R0914 def diff_sysfs_dirs(before, after, result): # pylint: disable=R0914 before_files = [] - os.path.walk(before, - lambda arg, dirname, names: arg.extend([os.path.join(dirname, f) for f in names]), - before_files - ) - before_files = filter(os.path.isfile, before_files) + for root, dirs, files in os.walk(before): + before_files.extend([os.path.join(root, f) for f in files]) + before_files = list(filter(os.path.isfile, before_files)) files = [os.path.relpath(f, before) for f in before_files] after_files = [os.path.join(after, f) for f in files] diff_files = [os.path.join(result, f) for f in files] @@ -61,7 +66,7 @@ def diff_sysfs_dirs(before, after, result): # pylint: disable=R0914 with open(bfile) as bfh, open(afile) as afh: # pylint: disable=C0321 with open(_f(dfile), 'w') as dfh: - for i, (bline, aline) in enumerate(izip_longest(bfh, afh), 1): + for i, (bline, aline) in enumerate(zip_longest(bfh, afh), 1): if aline is None: logger.debug('Lines missing from {}'.format(afile)) break diff --git a/wa/utils/doc.py b/wa/utils/doc.py index f20cf39d..c0589e66 100644 --- a/wa/utils/doc.py +++ b/wa/utils/doc.py @@ -164,16 +164,16 @@ def format_simple_table(rows, headers=None, align='>', show_borders=True, border """Formats a simple table.""" if not rows: return '' - rows = [map(str, r) for r in rows] + rows = [list(map(str, r)) for r in rows] num_cols = len(rows[0]) # cycle specified alignments until we have num_cols of them. This is # consitent with how such cases are handled in R, pandas, etc. it = cycle(align) - align = [it.next() for _ in xrange(num_cols)] + align = [next(it) for _ in range(num_cols)] - cols = zip(*rows) - col_widths = [max(map(len, c)) for c in cols] + cols = list(zip(*rows)) + col_widths = [max(list(map(len, c))) for c in cols] if headers: col_widths = [max(len(h), cw) for h, cw in zip(headers, col_widths)] row_format = ' '.join(['{:%s%s}' % (align[i], w) for i, w in enumerate(col_widths)]) @@ -259,12 +259,12 @@ def indent(text, spaces=4): def format_literal(lit): - if isinstance(lit, basestring): + if isinstance(lit, str): return '``\'{}\'``'.format(lit) elif hasattr(lit, 'pattern'): # regex return '``r\'{}\'``'.format(lit.pattern) elif isinstance(lit, dict): - content = indent(',\n'.join("{}: {}".format(key,val) for (key,val) in lit.iteritems())) + content = indent(',\n'.join("{}: {}".format(key,val) for (key,val) in lit.items())) return '::\n\n{}'.format(indent('{{\n{}\n}}'.format(content))) else: return '``{}``'.format(lit) @@ -287,7 +287,7 @@ def get_params_rst(parameters): text += indent('\nconstraint: ``{}``\n'.format(get_type_name(param.constraint))) if param.default: value = param.default - if isinstance(value, basestring) and value.startswith(USER_HOME): + if isinstance(value, str) and value.startswith(USER_HOME): value = value.replace(USER_HOME, '~') text += indent('\ndefault: {}\n'.format(format_literal(value))) text += '\n' @@ -298,7 +298,7 @@ def get_aliases_rst(aliases): text = '' for alias in aliases: param_str = ', '.join(['{}={}'.format(n, format_literal(v)) - for n, v in alias.params.iteritems()]) + for n, v in alias.params.items()]) text += '{}\n{}\n\n'.format(alias.name, indent(param_str)) return text diff --git a/wa/utils/exec_control.py b/wa/utils/exec_control.py index b98e8a06..a23336a4 100644 --- a/wa/utils/exec_control.py +++ b/wa/utils/exec_control.py @@ -12,7 +12,7 @@ def activate_environment(name): #pylint: disable=W0603 global __active_environment - if name not in __environments.keys(): + if name not in list(__environments.keys()): init_environment(name) __active_environment = name @@ -24,7 +24,7 @@ def init_environment(name): :raises: ``ValueError`` if an environment with name ``name`` already exists. """ - if name in __environments.keys(): + if name in list(__environments.keys()): msg = "Environment {} already exists".format(name) raise ValueError(msg) __environments[name] = [] @@ -39,7 +39,7 @@ def reset_environment(name=None): """ if name is not None: - if name not in __environments.keys(): + if name not in list(__environments.keys()): msg = "Environment {} does not exist".format(name) raise ValueError(msg) __environments[name] = [] @@ -75,7 +75,7 @@ def once_per_class(method): if __active_environment is None: activate_environment('default') - func_id = repr(method.func_name) + repr(args[0].__class__) + func_id = repr(method.__name__) + repr(args[0].__class__) if func_id in __environments[__active_environment]: return diff --git a/wa/utils/log.py b/wa/utils/log.py index a254374e..1012e7ab 100644 --- a/wa/utils/log.py +++ b/wa/utils/log.py @@ -128,13 +128,13 @@ def disable(logs): def __enable_logger(logger): - if isinstance(logger, basestring): + if isinstance(logger, str): logger = logging.getLogger(logger) logger.propagate = True def __disable_logger(logger): - if isinstance(logger, basestring): + if isinstance(logger, str): logger = logging.getLogger(logger) logger.propagate = False diff --git a/wa/utils/misc.py b/wa/utils/misc.py index 9caf7b3b..bb9ab546 100644 --- a/wa/utils/misc.py +++ b/wa/utils/misc.py @@ -18,7 +18,7 @@ Miscellaneous functions that don't fit anywhere else. """ -from __future__ import division + import os import sys import re @@ -30,9 +30,13 @@ import traceback import logging import random import hashlib +import sys from datetime import datetime, timedelta from operator import mul -from StringIO import StringIO +if sys.version_info[0] == 3: + from io import StringIO +else: + from io import BytesIO as StringIO from itertools import chain, cycle from distutils.spawn import find_executable @@ -83,11 +87,11 @@ def diff_tokens(before_token, after_token): def prepare_table_rows(rows): """Given a list of lists, make sure they are prepared to be formatted into a table by making sure each row has the same number of columns and stringifying all values.""" - rows = [map(str, r) for r in rows] - max_cols = max(map(len, rows)) + rows = [list(map(str, r)) for r in rows] + max_cols = max(list(map(len, rows))) for row in rows: pad = max_cols - len(row) - for _ in xrange(pad): + for _ in range(pad): row.append('') return rows @@ -102,10 +106,10 @@ def write_table(rows, wfh, align='>', headers=None): # pylint: disable=R0914 # cycle specified alignments until we have max_cols of them. This is # consitent with how such cases are handled in R, pandas, etc. it = cycle(align) - align = [it.next() for _ in xrange(num_cols)] + align = [next(it) for _ in range(num_cols)] - cols = zip(*rows) - col_widths = [max(map(len, c)) for c in cols] + cols = list(zip(*rows)) + col_widths = [max(list(map(len, c))) for c in cols] row_format = ' '.join(['{:%s%s}' % (align[i], w) for i, w in enumerate(col_widths)]) row_format += '\n' @@ -144,7 +148,7 @@ def _check_remove_item(the_list, item): """Helper function for merge_lists that implements checking wether an items should be removed from the list and doing so if needed. Returns ``True`` if the item has been removed and ``False`` otherwise.""" - if not isinstance(item, basestring): + if not isinstance(item, str): return False if not item.startswith('~'): return False @@ -275,7 +279,7 @@ def get_article(word): def get_random_string(length): """Returns a random ASCII string of the specified length).""" - return ''.join(random.choice(string.ascii_letters + string.digits) for _ in xrange(length)) + return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length)) class LoadSyntaxError(Exception): @@ -307,9 +311,9 @@ def load_struct_from_python(filepath=None, text=None): while modname in sys.modules: # highly unlikely, but... modname = get_random_string(RAND_MOD_NAME_LEN) mod = imp.new_module(modname) - exec text in mod.__dict__ # pylint: disable=exec-used + exec(text, mod.__dict__) # pylint: disable=exec-used return dict((k, v) - for k, v in mod.__dict__.iteritems() + for k, v in mod.__dict__.items() if not k.startswith('_')) except SyntaxError as e: raise LoadSyntaxError(e.message, filepath, e.lineno) @@ -404,7 +408,7 @@ def istextfile(fileobj, blocksize=512): def categorize(v): if hasattr(v, 'merge_with') and hasattr(v, 'merge_into'): return 'o' - elif hasattr(v, 'iteritems'): + elif hasattr(v, 'items'): return 'm' elif isiterable(v): return 's' @@ -515,13 +519,14 @@ def merge_sequencies(s1, s2): return type(s2)(unique(chain(s1, s2))) + def merge_maps(m1, m2): - return type(m2)(chain(m1.iteritems(), m2.iteritems())) + return type(m2)(chain(iter(m1.items()), iter(m2.items()))) def merge_dicts_simple(base, other): result = base.copy() - for key, value in (other or {}).iteritems(): + for key, value in (other or {}).items(): result[key] = merge_config_values(result.get(key), value) return result @@ -534,11 +539,11 @@ def touch(path): def get_object_name(obj): if hasattr(obj, 'name'): return obj.name - elif hasattr(obj, 'im_func'): - return '{}.{}'.format(get_object_name(obj.im_class), - obj.im_func.func_name) + elif hasattr(obj, '__func__') and hasattr(obj, '__self__'): + return '{}.{}'.format(get_object_name(obj.__self__.__class__), + obj.__func__.__name__) elif hasattr(obj, 'func_name'): - return obj.func_name + return obj.__name__ elif hasattr(obj, '__name__'): return obj.__name__ elif hasattr(obj, '__class__'): @@ -557,7 +562,7 @@ def resolve_cpus(name, target): - 'all' - returns all cpus - '' - Empty name will also return all cpus """ - cpu_list = range(target.number_of_cpus) + cpu_list = list(range(target.number_of_cpus)) # Support for passing cpu no directly if isinstance(name, int): diff --git a/wa/utils/revent.py b/wa/utils/revent.py index 22839b97..50552277 100644 --- a/wa/utils/revent.py +++ b/wa/utils/revent.py @@ -13,7 +13,7 @@ # limitations under the License. # -from __future__ import division + import os import struct import signal @@ -88,7 +88,7 @@ class UinputDeviceInfo(object): self.abs_bits = bytearray(parts[3]) self.num_absinfo = parts[4] self.absinfo = [absinfo(*read_struct(fh, absinfo_struct)) - for _ in xrange(self.num_absinfo)] + for _ in range(self.num_absinfo)] def __str__(self): return 'UInputInfo({})'.format(self.__dict__) @@ -145,7 +145,7 @@ class ReventRecording(object): if self.stream: events = self._iter_events() try: - first = last = events.next() + first = last = next(events) except StopIteration: self._duration = 0 for last in events: @@ -230,7 +230,7 @@ class ReventRecording(object): def _read_devices(self, fh): num_devices, = read_struct(fh, u32_struct) - for _ in xrange(num_devices): + for _ in range(num_devices): self.device_paths.append(read_string(fh)) def _read_gamepad_info(self, fh): @@ -243,7 +243,7 @@ class ReventRecording(object): raise RuntimeError(msg) self.fh.seek(self._events_start) if self.version >= 2: - for _ in xrange(self.num_events): + for _ in range(self.num_events): yield ReventEvent(self.fh) else: file_size = os.path.getsize(self.filepath) diff --git a/wa/utils/serializer.py b/wa/utils/serializer.py index 514d757e..1b7c1a74 100644 --- a/wa/utils/serializer.py +++ b/wa/utils/serializer.py @@ -71,7 +71,7 @@ POD_TYPES = [ dict, set, str, - unicode, + str, int, float, bool, @@ -104,7 +104,7 @@ class WAJSONDecoder(_json.JSONDecoder): d = _json.JSONDecoder.decode(self, s, **kwargs) def try_parse_object(v): - if isinstance(v, basestring): + if isinstance(v, str): if v.startswith('REGEX:'): _, flags, pattern = v.split(':', 2) return re.compile(pattern, int(flags or 0)) @@ -122,8 +122,8 @@ class WAJSONDecoder(_json.JSONDecoder): def load_objects(d): pairs = [] - for k, v in d.iteritems(): - if hasattr(v, 'iteritems'): + for k, v in d.items(): + if hasattr(v, 'items'): pairs.append((k, load_objects(v))) elif isiterable(v): pairs.append((k, [try_parse_object(i) for i in v])) @@ -160,13 +160,13 @@ class json(object): _mapping_tag = _yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG -_regex_tag = u'tag:wa:regex' -_level_tag = u'tag:wa:level' -_cpu_mask_tag = u'tag:wa:cpu_mask' +_regex_tag = 'tag:wa:regex' +_level_tag = 'tag:wa:level' +_cpu_mask_tag = 'tag:wa:cpu_mask' def _wa_dict_representer(dumper, data): - return dumper.represent_mapping(_mapping_tag, data.iteritems()) + return dumper.represent_mapping(_mapping_tag, iter(data.items())) def _wa_regex_representer(dumper, data): @@ -248,17 +248,17 @@ class python(object): def loads(s, *args, **kwargs): pod = {} try: - exec s in pod # pylint: disable=exec-used + exec(s, pod) # pylint: disable=exec-used except SyntaxError as e: raise SerializerSyntaxError(e.message, e.lineno) - for k in pod.keys(): + for k in list(pod.keys()): if k.startswith('__'): del pod[k] return pod def read_pod(source, fmt=None): - if isinstance(source, basestring): + if isinstance(source, str): with open(source) as fh: return _read_pod(fh, fmt) elif hasattr(source, 'read') and (hasattr(source, 'name') or fmt): @@ -269,7 +269,7 @@ def read_pod(source, fmt=None): def write_pod(pod, dest, fmt=None): - if isinstance(dest, basestring): + if isinstance(dest, str): with open(dest, 'w') as wfh: return _write_pod(pod, wfh, fmt) elif hasattr(dest, 'write') and (hasattr(dest, 'name') or fmt): @@ -323,8 +323,8 @@ def _write_pod(pod, wfh, fmt=None): def is_pod(obj): if type(obj) not in POD_TYPES: return False - if hasattr(obj, 'iteritems'): - for k, v in obj.iteritems(): + if hasattr(obj, 'items'): + for k, v in obj.items(): if not (is_pod(k) and is_pod(v)): return False elif isiterable(obj): diff --git a/wa/utils/terminalsize.py b/wa/utils/terminalsize.py index 828ca3e6..f211b795 100644 --- a/wa/utils/terminalsize.py +++ b/wa/utils/terminalsize.py @@ -89,5 +89,5 @@ def _get_terminal_size_linux(): if __name__ == "__main__": sizex, sizey = get_terminal_size() - print 'width =', sizex, 'height =', sizey + print('width =', sizex, 'height =', sizey) diff --git a/wa/utils/trace_cmd.py b/wa/utils/trace_cmd.py index 8eaf4d59..65900c79 100644 --- a/wa/utils/trace_cmd.py +++ b/wa/utils/trace_cmd.py @@ -114,7 +114,7 @@ class DroppedEventsEvent(object): def try_convert_to_numeric(v): try: if isiterable(v): - return map(numeric, v) + return list(map(numeric, v)) else: return numeric(v) except ValueError: @@ -153,13 +153,13 @@ def regex_body_parser(regex, flags=0): If regex is a pre-compiled object, flags will be ignored. """ - if isinstance(regex, basestring): + if isinstance(regex, str): regex = re.compile(regex, flags) def regex_parser_func(event, text): match = regex.search(text) if match: - for k, v in match.groupdict().iteritems(): + for k, v in match.groupdict().items(): try: event.fields[k] = int(v) except ValueError: @@ -321,7 +321,7 @@ class TraceCmdParser(object): continue body_parser = EVENT_PARSER_MAP.get(event_name, default_body_parser) - if isinstance(body_parser, basestring) or isinstance(body_parser, re._pattern_type): # pylint: disable=protected-access + if isinstance(body_parser, str) or isinstance(body_parser, re._pattern_type): # pylint: disable=protected-access body_parser = regex_body_parser(body_parser) yield TraceCmdEvent(parser=body_parser, **match.groupdict()) diff --git a/wa/utils/types.py b/wa/utils/types.py index 29d8cf49..6256b9c9 100644 --- a/wa/utils/types.py +++ b/wa/utils/types.py @@ -29,10 +29,19 @@ import os import re import numbers import shlex +import sys from bisect import insort -from urllib import quote, unquote +if sys.version_info[0] == 3: + from urllib.parse import quote, unquote + from past.builtins import basestring + long = int +else: + from urllib import quote, unquote from collections import defaultdict, MutableMapping from copy import copy +from functools import total_ordering + +from future.utils import with_metaclass from devlib.utils.types import identifier, boolean, integer, numeric, caseless_string @@ -47,7 +56,7 @@ def list_of_strs(value): """ if not isiterable(value): raise ValueError(value) - return map(str, value) + return list(map(str, value)) list_of_strings = list_of_strs @@ -59,7 +68,7 @@ def list_of_ints(value): """ if not isiterable(value): raise ValueError(value) - return map(int, value) + return list(map(int, value)) list_of_integers = list_of_ints @@ -72,7 +81,7 @@ def list_of_numbers(value): """ if not isiterable(value): raise ValueError(value) - return map(numeric, value) + return list(map(numeric, value)) def list_of_bools(value, interpret_strings=True): @@ -88,9 +97,9 @@ def list_of_bools(value, interpret_strings=True): if not isiterable(value): raise ValueError(value) if interpret_strings: - return map(boolean, value) + return list(map(boolean, value)) else: - return map(bool, value) + return list(map(bool, value)) def list_of(type_): @@ -98,16 +107,16 @@ def list_of(type_): attempts to convert all elements in the passed value to the specifed ``type_``, raising ``ValueError`` on error.""" def __init__(self, values): - list.__init__(self, map(type_, values)) + list.__init__(self, list(map(type_, values))) def append(self, value): list.append(self, type_(value)) def extend(self, other): - list.extend(self, map(type_, other)) + list.extend(self, list(map(type_, other))) def from_pod(cls, pod): - return cls(map(type_, pod)) + return cls(list(map(type_, pod))) def _to_pod(self): return self @@ -132,7 +141,7 @@ def list_or_string(value): a one-element list with stringified value will be returned. """ - if isinstance(value, basestring): + if isinstance(value, str): return [value] else: try: @@ -147,11 +156,11 @@ def list_or_caseless_string(value): not iterable a one-element list with stringified value will be returned. """ - if isinstance(value, basestring): + if isinstance(value, str): return [caseless_string(value)] else: try: - return map(caseless_string, value) + return list(map(caseless_string, value)) except ValueError: return [caseless_string(value)] @@ -229,8 +238,8 @@ class arguments(list): def __init__(self, value=None): if isiterable(value): - super(arguments, self).__init__(map(str, value)) - elif isinstance(value, basestring): + super(arguments, self).__init__(list(map(str, value))) + elif isinstance(value, str): posix = os.name != 'nt' super(arguments, self).__init__(shlex.split(value, posix=posix)) elif value is None: @@ -242,7 +251,7 @@ class arguments(list): return super(arguments, self).append(str(value)) def extend(self, values): - return super(arguments, self).extend(map(str, values)) + return super(arguments, self).extend(list(map(str, values))) def __str__(self): return ' '.join(self) @@ -288,7 +297,7 @@ class prioritylist(object): self.__delitem__(index) def _priority_index(self, element): - for priority, elements in self.elements.iteritems(): + for priority, elements in self.elements.items(): if element in elements: return (priority, elements.index(element)) raise IndexError(element) @@ -333,7 +342,7 @@ class prioritylist(object): else: index_range = [index] elif isinstance(index, slice): - index_range = range(index.start or 0, index.stop, index.step or 1) + index_range = list(range(index.start or 0, index.stop, index.step or 1)) else: raise ValueError('Invalid index {}'.format(index)) current_global_offset = 0 @@ -391,7 +400,7 @@ class toggle_set(set): def __init__(self, *args): if args: value = args[0] - if isinstance(value, basestring): + if isinstance(value, str): msg = 'invalid type for toggle_set: "{}"' raise TypeError(msg.format(type(value))) set.__init__(self, *args) @@ -507,12 +516,15 @@ class obj_dict(MutableMapping): raise AttributeError("No such attribute: " + name) def __getattr__(self, name): + if 'dict' not in self.__dict__: + raise AttributeError("No such attribute: " + name) if name in self.__dict__['dict']: return self.__dict__['dict'][name] else: raise AttributeError("No such attribute: " + name) +@total_ordering class level(object): """ A level has a name and behaves like a string when printed, however it also @@ -538,11 +550,8 @@ class level(object): def __repr__(self): return '{}({})'.format(self.name, self.value) - def __cmp__(self, other): - if isinstance(other, level): - return cmp(self.value, other.value) - else: - return cmp(self.value, other) + def __hash__(self): + return hash(self.name) def __eq__(self, other): if isinstance(other, level): @@ -552,13 +561,24 @@ class level(object): else: return self.value == other - def __ne__(self, other): + def __lt__(self, other): if isinstance(other, level): - return self.value != other.value + return self.value < other.value elif isinstance(other, basestring): - return self.name != other + return self.name < other else: - return self.value != other + return self.value < other + + +class _EnumMeta(type): + + def __str__(cls): + return str(cls.levels) + + def __getattr__(self, name): + name = name.lower() + if name in self.__dict__: + return self.__dict__[name] def enum(args, start=0, step=1): @@ -583,11 +603,7 @@ def enum(args, start=0, step=1): """ - class Enum(object): - - class __metaclass__(type): - def __str__(cls): - return str(cls.levels) + class Enum(with_metaclass(_EnumMeta, object)): @classmethod def from_pod(cls, pod): @@ -642,14 +658,14 @@ class ParameterDict(dict): # Function to determine the appropriate prefix based on the parameters type @staticmethod def _get_prefix(obj): - if isinstance(obj, basestring): + if isinstance(obj, str): prefix = 's' elif isinstance(obj, float): prefix = 'f' - elif isinstance(obj, long): - prefix = 'd' elif isinstance(obj, bool): prefix = 'b' + elif isinstance(obj, long): + prefix = 'i' elif isinstance(obj, int): prefix = 'i' elif obj is None: @@ -686,7 +702,7 @@ class ParameterDict(dict): elif value_type == 'b': return boolean(value) elif value_type == 'd': - return long(value) + return int(value) elif value_type == 'f': return float(value) elif value_type == 'i': @@ -700,7 +716,7 @@ class ParameterDict(dict): raise ValueError('Unknown {} {}'.format(type(string), string)) def __init__(self, *args, **kwargs): - for k, v in kwargs.iteritems(): + for k, v in kwargs.items(): self.__setitem__(k, v) dict.__init__(self, *args) @@ -714,7 +730,7 @@ class ParameterDict(dict): return dict.__contains__(self, self._encode(item)) def __iter__(self): - return iter((k, self._decode(v)) for (k, v) in self.items()) + return iter((k, self._decode(v)) for (k, v) in list(self.items())) def iteritems(self): return self.__iter__() @@ -730,7 +746,10 @@ class ParameterDict(dict): return (key, self._decode(value)) def iter_encoded_items(self): - return dict.iteritems(self) + if sys.version_info[0] == 3: + return dict.items(self) + else: + return dict.iteritems(self) def get_encoded_value(self, name): return dict.__getitem__(self, name) @@ -743,7 +762,7 @@ class ParameterDict(dict): if isinstance(d, ParameterDict): dict.update(self, d) else: - for k, v in d.iteritems(): + for k, v in d.items(): self[k] = v @@ -762,7 +781,7 @@ class cpu_mask(object): self._mask = 0 if isinstance(cpus, int): self._mask = cpus - elif isinstance(cpus, basestring): + elif isinstance(cpus, str): if cpus[:2] == '0x' or cpus[:2] == '0X': self._mask = int(cpus, 16) else: |