From 0b663ddd6541321cd5ecac7f99207f24ce29c3d0 Mon Sep 17 00:00:00 2001 From: Yen Chi Hsuan Date: Wed, 6 Jul 2016 02:45:02 +0800 Subject: [PATCH] Python 3 support --- logcat-color | 28 ++++++++++++++++++---------- logcatcolor/column.py | 7 ++++--- logcatcolor/config.py | 5 ++++- logcatcolor/format.py | 5 +++-- logcatcolor/layout.py | 3 ++- logcatcolor/profile.py | 1 + logcatcolor/reader.py | 15 ++++++++++----- setup.py | 8 +++++--- test/common.py | 10 +++++++--- test/config_test.py | 1 + test/format_test.py | 1 + test/logcat_color_test.py | 24 ++++++++++++++---------- test/mock-adb | 5 +++-- test/profile_test.py | 1 + test/test.py | 1 + 15 files changed, 75 insertions(+), 40 deletions(-) diff --git a/logcat-color b/logcat-color index 84dadfc..86e8da7 100755 --- a/logcat-color +++ b/logcat-color @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import print_function, unicode_literals """ logcat-color @@ -136,13 +137,19 @@ class LogcatColor(object): if options.config and not os.path.isfile(options.config): parser.error("Config file does not exist: %s" % options.config) - self.input = sys.stdin + try: + self.input = sys.stdin.buffer + except AttributeError: + self.input = sys.stdin if options.input: - self.input = open(options.input, "r") + self.input = open(options.input, "rb") - self.output = sys.stdout + try: + self.output = sys.stdout.buffer + except AttributeError: + self.output = sys.stdout if options.output: - self.output = open(options.output, "w") + self.output = open(options.output, "wb") self.adb_device = options.adb_device self.logcat_args = options.logcat_args or [] @@ -208,16 +215,17 @@ class LogcatColor(object): adb_command.extend(self.get_logcat_args()) try: self.input = Popen(adb_command, stdout=PIPE).stdout - except OSError, e: + except OSError as e: if e.errno == errno.ENOENT: - print >>sys.stderr, \ + print( 'Error, adb could not be found using: "%s"\n' \ 'To fix this: \n' \ ' 1) Add the directory containing adb to your PATH\n' \ ' 2) Set the ADB environment variable\n' \ - ' 3) Set "adb" in ~/.logcat-color' % adb_command[0] + ' 3) Set "adb" in ~/.logcat-color' % adb_command[0], + file=sys.stderr) else: - print >>sys.stderr, 'Could not run ADB: %s' % str(e) + print('Could not run ADB: %s' % str(e), file=sys.stderr) sys.exit(e.errno) def init_reader(self): @@ -242,7 +250,7 @@ class LogcatColor(object): self.wait_for_device() self.start_logcat() self.init_reader() - except KeyboardInterrupt, e: + except KeyboardInterrupt as e: pass WAIT_FOR_DEVICE = Fore.WHITE + Back.BLACK + Style.DIM + \ @@ -258,7 +266,7 @@ class LogcatColor(object): if self.adb_device: device_str = "\"%s\" " % self.adb_device - print self.WAIT_FOR_DEVICE % device_str + print(self.WAIT_FOR_DEVICE % device_str) check_call(command) if __name__ == "__main__": diff --git a/logcatcolor/column.py b/logcatcolor/column.py index 4b4bf0c..b7a5c5b 100644 --- a/logcatcolor/column.py +++ b/logcatcolor/column.py @@ -6,9 +6,10 @@ Columns for displaying logcat log data """ +from __future__ import unicode_literals import colorama from colorama import Fore, Back, Style -import StringIO +from io import StringIO colorama.init() @@ -73,7 +74,7 @@ def __init__(self, layout): tag_colors = layout.profile.tag_colors self.tag_colors = tag_colors or {} - self.last_used = self.COLOR_MAP.values()[:] + self.last_used = list(self.COLOR_MAP.values()) # This will allocate a unique format for the given tag since we dont have # very many colors, we always keep track of the LRU @@ -134,7 +135,7 @@ def format(self, message): if not self.width: return message - messagebuf = StringIO.StringIO() + messagebuf = StringIO() current = 0 while current < len(message): next = min(current + self.width, len(message)) diff --git a/logcatcolor/config.py b/logcatcolor/config.py index 56f3b37..7d895d3 100644 --- a/logcatcolor/config.py +++ b/logcatcolor/config.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from logcatcolor.column import TagColumn from logcatcolor.profile import Profile import os @@ -27,7 +28,9 @@ def __init__(self, options): if os.path.exists(self.path) and os.path.isfile(self.path): # config file is just a python script that globals are imported from try: - execfile(self.path, self.config) + with open(self.path) as f: + code = compile(f.read(), os.path.basename(self.path), 'exec') + exec(code, self.config) except: self.report_config_error() sys.exit(1) diff --git a/logcatcolor/format.py b/logcatcolor/format.py index 0a50f92..df83900 100644 --- a/logcatcolor/format.py +++ b/logcatcolor/format.py @@ -7,6 +7,7 @@ Support for reading various logcat logging formats into an easier to consume data map. """ +from __future__ import unicode_literals import re def format(cls): @@ -32,7 +33,7 @@ def match(self, line): if not match: return False - for name, value in match.groupdict().iteritems(): + for name, value in match.groupdict().items(): self.data[name] = value.strip() return True @@ -130,7 +131,7 @@ def detect_format(lines): if Format.MARKER_REGEX.match(line): continue - for name, regex in Format.REGEXES.iteritems(): + for name, regex in Format.REGEXES.items(): if regex.match(line): return name diff --git a/logcatcolor/layout.py b/logcatcolor/layout.py index bc7201a..818ab1b 100644 --- a/logcatcolor/layout.py +++ b/logcatcolor/layout.py @@ -6,11 +6,12 @@ Layouts for mapping logcat log data into a colorful terminal interface """ +from __future__ import unicode_literals from colorama import Fore, Back, Style from logcatcolor.column import * from logcatcolor.format import Format import re -from cStringIO import StringIO +from io import StringIO def layout(cls): Layout.TYPES[cls.NAME] = cls diff --git a/logcatcolor/profile.py b/logcatcolor/profile.py index 409a975..7def202 100644 --- a/logcatcolor/profile.py +++ b/logcatcolor/profile.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import re RegexType = type(re.compile("")) diff --git a/logcatcolor/reader.py b/logcatcolor/reader.py index 5e5a99b..40cc7f7 100644 --- a/logcatcolor/reader.py +++ b/logcatcolor/reader.py @@ -6,9 +6,10 @@ Logcat I/O stream readers and helpers """ +from __future__ import unicode_literals import asyncore import asynchat -from cStringIO import StringIO +from io import StringIO import fcntl import inspect from logcatcolor.format import Format, detect_format @@ -19,7 +20,7 @@ # Parts copied from asyncore.file_dispatcher class FileLineReader(asynchat.async_chat): - LINE_TERMINATOR = "\n" + LINE_TERMINATOR = b"\n" def __init__(self, fd): asynchat.async_chat.__init__(self) @@ -45,7 +46,7 @@ def set_file(self, fd): fcntl.fcntl(fd, fcntl.F_SETFL, flags) def collect_incoming_data(self, data): - self.log_buffer.write(data) + self.log_buffer.write(data.decode('utf-8')) def found_terminator(self): line = self.log_buffer.getvalue() @@ -71,6 +72,10 @@ def __init__(self, file, config, profile=None, format=None, layout=None, self.profile = profile self.width = width self.writer = writer or sys.stdout + try: + self.writer = self.writer.buffer + except AttributeError: + pass self.format = None if format is not None: @@ -121,7 +126,7 @@ def layout_line(self, line): if Format.MARKER_REGEX.match(line): result = self.layout.layout_marker(line) if result: - self.writer.write(result) + self.writer.write(result.encode('utf-8')) return try: @@ -132,6 +137,6 @@ def layout_line(self, line): if not result: return - self.writer.write(result + "\n") + self.writer.write((result + "\n").encode('utf-8')) finally: self.format.data.clear() diff --git a/setup.py b/setup.py index 02b3107..38975f0 100644 --- a/setup.py +++ b/setup.py @@ -2,13 +2,15 @@ import codecs import json +import sys from setuptools import setup, find_packages setup_data = json.load(open("setup.json", "r")) -# real classy distutils, name / version have to be ascii encoded :( -for ascii_key in ("name", "version"): - setup_data[ascii_key] = setup_data[ascii_key].encode("ascii") +if sys.version_info[0] == 2: + # real classy distutils, name / version have to be ascii encoded :( + for ascii_key in ("name", "version"): + setup_data[ascii_key] = setup_data[ascii_key].encode("ascii") setup_data["packages"] = find_packages() setup(**setup_data) diff --git a/test/common.py b/test/common.py index 24074e3..ea5adb0 100644 --- a/test/common.py +++ b/test/common.py @@ -1,17 +1,20 @@ +from __future__ import unicode_literals import json import os +import sys this_dir = os.path.abspath(os.path.dirname(__file__)) top_dir = os.path.dirname(this_dir) logcat_color = os.path.join(top_dir, "logcat-color") -execfile(logcat_color) +with open(logcat_color) as f: + exec(compile(f.read(), "logcat-color", 'exec')) filter_results = os.path.join(this_dir, ".filter_results") mock_adb = os.path.join(this_dir, "mock-adb") class MockObject(object): def __init__(self, **kwargs): - for key, value in kwargs.iteritems(): + for key, value in kwargs.items(): setattr(self, key, value) class MockAdbLogcatColor(LogcatColor): @@ -25,6 +28,7 @@ def __init__(self, log, results, args=None, max_wait_count=None): def get_adb_args(self): adb_args = LogcatColor.get_adb_args(self) adb_args[0:1] = [mock_adb, "--log", self.log, "--results", self.results] + adb_args = [sys.executable] + adb_args return adb_args def wait_for_device(self): @@ -56,6 +60,6 @@ def save_filter_results(name, data, result): def read_filter_results(): results = {} if os.path.exists(filter_results): - results = json.loads(open(filter_results, "r").read()) + results = json.loads(open(filter_results, "rt").read()) return results diff --git a/test/config_test.py b/test/config_test.py index 0c4c62e..21077e3 100644 --- a/test/config_test.py +++ b/test/config_test.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from common import * from logcatcolor.column import * from logcatcolor.config import * diff --git a/test/format_test.py b/test/format_test.py index a0ae55e..a88647a 100644 --- a/test/format_test.py +++ b/test/format_test.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from common import * from logcatcolor.format import * import unittest diff --git a/test/logcat_color_test.py b/test/logcat_color_test.py index a6cc320..1e2e0b2 100644 --- a/test/logcat_color_test.py +++ b/test/logcat_color_test.py @@ -1,7 +1,8 @@ +from __future__ import print_function, unicode_literals import common import json import os -from StringIO import StringIO +from io import StringIO from subprocess import Popen, PIPE import sys import tempfile @@ -50,29 +51,32 @@ def start_logcat_color(self, *args, **kwargs): piped_path = None if "piped" in kwargs: piped_path = kwargs["piped"] - piped = open(piped_path, "r").read() + piped = open(piped_path, "rb").read() del kwargs["piped"] elif "input" in kwargs: piped = None args[1:1] = ["--input", kwargs["input"]] del kwargs["input"] + args = [sys.executable] + args + if self.DEBUG: piped_debug = "" if piped_path: piped_debug = " < %s" % piped_path - print " ".join(args) + piped_debug + print(" ".join(args) + piped_debug) self.proc = Popen(args, stdout=PIPE, stderr=PIPE, stdin=PIPE, **kwargs) self.out, self.err = self.proc.communicate(piped) + self.out = self.out.decode('utf-8') self.filter_results = common.read_filter_results() if os.path.exists(common.filter_results): os.unlink(common.filter_results) if self.DEBUG and self.err: - print >>sys.stderr, self.err + print(self.err, file=sys.stderr) @logcat_color_test(piped=BRIEF_LOG) def test_piped_input(self): @@ -85,7 +89,7 @@ def test_invalid_config(self): @logcat_color_test("--plain", input=BRIEF_LOG) def test_plain_logging(self): self.assertEqual(self.proc.returncode, 0) - brief_data = open(BRIEF_LOG, "r").read() + brief_data = open(BRIEF_LOG, "rt").read() self.assertEqual(self.out, brief_data) @logcat_color_test("--plain", "brief_filter_fn", @@ -132,8 +136,8 @@ def test_plain_logging_with_tag_filter(self): @logcat_color_test("--plain", "--output", tmpout, input=BRIEF_LOG) def test_file_output(self): self.assertEqual(self.proc.returncode, 0) - brief_data = open(BRIEF_LOG, "r").read() - out_data = open(tmpout, "r").read() + brief_data = open(BRIEF_LOG, "rt").read() + out_data = open(tmpout, "rt").read() self.assertEqual(out_data, brief_data) def test_logcat_options_with_filters(self): @@ -168,13 +172,13 @@ def test_stay_connected(self): lc.loop() self.assertEqual(lc.wait_count, 3) - results = json.loads(open(tmpout, "r").read()) + results = json.loads(open(tmpout, "rt").read()) self.assertEqual(len(results), 6) - logcat_results = filter(lambda d: d["command"] == "logcat", results) + logcat_results = list(filter(lambda d: d["command"] == "logcat", results)) self.assertEqual(len(logcat_results), 3) - wait_results = filter(lambda d: d["command"] == "wait-for-device", results) + wait_results = list(filter(lambda d: d["command"] == "wait-for-device", results)) self.assertEquals(len(wait_results), 3) for r in results: diff --git a/test/mock-adb b/test/mock-adb index f930092..ea18461 100755 --- a/test/mock-adb +++ b/test/mock-adb @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import unicode_literals import argparse import json import os @@ -8,7 +9,7 @@ import time class MockAdb(object): def __init__(self, args, command_args): self.results_data = {} - for attr, value in args.__dict__.iteritems(): + for attr, value in args.__dict__.items(): setattr(self, attr, value) self.results_data[attr] = value @@ -34,7 +35,7 @@ class MockAdb(object): time.sleep(0.1) def logcat(self): - print open(self.log, "r").read() + print(open(self.log, "r").read()) def main(): parser = argparse.ArgumentParser() diff --git a/test/profile_test.py b/test/profile_test.py index 4f715f6..06b4f35 100644 --- a/test/profile_test.py +++ b/test/profile_test.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from common import * from logcatcolor.column import * from logcatcolor.config import * diff --git a/test/test.py b/test/test.py index aedeeb9..87b14db 100755 --- a/test/test.py +++ b/test/test.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import unicode_literals import os import sys import unittest