From cec5c0d7768aceb04bf9df457351bc00141f48b6 Mon Sep 17 00:00:00 2001
From: Toshio Kuratomi <toshio@fedoraproject.org>
Date: Thu, 11 Apr 2013 15:21:06 -0700
Subject: [PATCH 1/3] Few changes to support running on python3
---
q.py | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/q.py b/q.py
index c81a371..abe5b1e 100644
--- a/q.py
+++ b/q.py
@@ -70,11 +70,11 @@ class FileWriter(object):
def __init__(self, path):
self.path = path
- self.open = file
+ self.open = open
# App Engine's dev_appserver patches 'open' to simulate security
# restrictions in production; we circumvent this to write output.
- if file.__name__ == 'FakeFile': # dev_appserver's patched 'file'
- self.open = file.__bases__[0] # the original built-in 'file'
+ if open.__name__ == 'FakeFile': # dev_appserver's patched 'file'
+ self.open = open.__bases__[0] # the original built-in 'file'
def write(self, mode, content):
try:
@@ -130,7 +130,7 @@ def newline(self):
def add(self, items, sep='', wrap=True):
"""Adds a list of strings that are to be printed on one line."""
- items = map(str, items)
+ items = list(map(str, items))
size = sum([len(x) for x in items if not x.startswith('\x1b')])
if (wrap and self.column > self.indent and
self.column + len(sep) + size > self.width):
@@ -155,17 +155,29 @@ def unindent(self, lines):
indent = min(len(self.re.match(r'^ *', line).group()) for line in lines)
return [line[indent:].rstrip() for line in lines]
+ def _isbasestring(self, value):
+ if self.sys.version_info >= (3,):
+ return isinstance(value, (str, bytes))
+ else:
+ return isinstance(value, basestring)
+
+ def _istext(self, value):
+ if self.sys.version_info >= (3,):
+ return isinstance(value, str)
+ else:
+ return isinstance(value, unicode)
+
def safe_repr(self, value):
# TODO: Use colour to distinguish '...' elision from actual '...' chars.
# TODO: Show a nicer repr for SRE.Match objects.
# TODO: Show a nicer repr for big multiline strings.
result = self.TEXT_REPR.repr(value)
- if isinstance(value, basestring) and len(value) > 80:
+ if self._isbasestring(value) and len(value) > 80:
# If the string is big, save it to a file for later examination.
- if isinstance(value, unicode):
+ if self._istext(value):
value = value.encode('utf-8')
path = self.OUTPUT_PATH + '%08d.txt' % self.random.randrange(1e8)
- self.FileWriter(path).write('w', value)
+ self.FileWriter(path).write('wb', value)
result += ' (file://' + path + ')'
return result
@@ -284,11 +296,13 @@ def __call__(self, *args):
self.show(info.function, args, labels)
return args and args[0]
- def __div__(self, arg): # a tight-binding operator
+ def __truediv__(self, arg): # a tight-binding operator
"""Prints out and returns the argument."""
info = self.inspect.getframeinfo(self.sys._getframe(1))
self.show(info.function, [arg])
return arg
+ # Compat for Python 2 without from future import __division__ turned on
+ __div__ = __truediv__
__or__ = __div__ # a loose-binding operator
q = __call__ # backward compatibility with @q.q
--
1.8.1.6
From d809647541025ac79b54ed6079272c11afd2daf0 Mon Sep 17 00:00:00 2001
From: Toshio Kuratomi <toshio@fedoraproject.org>
Date: Thu, 11 Apr 2013 17:16:23 -0700
Subject: [PATCH 2/3] Encode to utf-8 at the FileWriter level so that we catch
all undecodable strings
---
q.py | 35 ++++++++++++++++++++---------------
1 file changed, 20 insertions(+), 15 deletions(-)
diff --git a/q.py b/q.py
index abe5b1e..3a99d2b 100644
--- a/q.py
+++ b/q.py
@@ -67,6 +67,7 @@ class Q(object):
class FileWriter(object):
"""An object that appends to or overwrites a single file."""
+ import sys
def __init__(self, path):
self.path = path
@@ -76,7 +77,23 @@ def __init__(self, path):
if open.__name__ == 'FakeFile': # dev_appserver's patched 'file'
self.open = open.__bases__[0] # the original built-in 'file'
+ def _isbasestring(self, value):
+ if self.sys.version_info >= (3,):
+ return isinstance(value, (str, bytes))
+ else:
+ return isinstance(value, basestring)
+
+ def _istext(self, value):
+ if self.sys.version_info >= (3,):
+ return isinstance(value, str)
+ else:
+ return isinstance(value, unicode)
+
def write(self, mode, content):
+ if 'b' not in mode:
+ mode = '%sb' % mode
+ if self._isbasestring(content) and self._istext(content):
+ content = content.encode('utf-8')
try:
f = self.open(self.path, mode)
f.write(content)
@@ -155,29 +172,17 @@ def unindent(self, lines):
indent = min(len(self.re.match(r'^ *', line).group()) for line in lines)
return [line[indent:].rstrip() for line in lines]
- def _isbasestring(self, value):
- if self.sys.version_info >= (3,):
- return isinstance(value, (str, bytes))
- else:
- return isinstance(value, basestring)
-
- def _istext(self, value):
- if self.sys.version_info >= (3,):
- return isinstance(value, str)
- else:
- return isinstance(value, unicode)
-
def safe_repr(self, value):
# TODO: Use colour to distinguish '...' elision from actual '...' chars.
# TODO: Show a nicer repr for SRE.Match objects.
# TODO: Show a nicer repr for big multiline strings.
result = self.TEXT_REPR.repr(value)
- if self._isbasestring(value) and len(value) > 80:
+ if self.writer.file_writer._isbasestring(value) and len(value) > 80:
# If the string is big, save it to a file for later examination.
- if self._istext(value):
+ if self.writer.file_writer._istext(value):
value = value.encode('utf-8')
path = self.OUTPUT_PATH + '%08d.txt' % self.random.randrange(1e8)
- self.FileWriter(path).write('wb', value)
+ self.FileWriter(path).write('w', value)
result += ' (file://' + path + ')'
return result
--
1.8.1.6
From 20cf7bcd4587a603497781bd1cfa140b58950e27 Mon Sep 17 00:00:00 2001
From: Toshio Kuratomi <toshio@fedoraproject.org>
Date: Mon, 6 May 2013 09:21:14 -0700
Subject: [PATCH 3/3] Switch from functions to variables to encapsulate
python2/3 differences
---
q.py | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/q.py b/q.py
index 3a99d2b..9136313 100644
--- a/q.py
+++ b/q.py
@@ -44,6 +44,8 @@
__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
+import sys
+
# WARNING: Horrible abuse of sys.modules, __call__, __div__, __or__, inspect,
# sys._getframe, and more! q's behaviour changes depending on the text of the
# source code near its call site. Don't ever do this in real code!
@@ -51,6 +53,14 @@
# These are reused below in both Q and Writer.
ESCAPE_SEQUENCES = ['\x1b[0m'] + ['\x1b[3%dm' % i for i in range(1, 7)]
+if sys.version_info >= (3,):
+ BASESTRING_TYPES = (str, bytes)
+ TEXT_TYPES = (str,)
+else:
+ BASESTRING_TYPES = (basestring,)
+ TEXT_TYPES = (unicode,)
+
+
# When we insert Q() into sys.modules, all the globals become None, so we
# have to keep everything we use inside the Q class.
class Q(object):
@@ -65,9 +75,16 @@ class Q(object):
NORMAL, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN = ESCAPE_SEQUENCES
TEXT_REPR = pydoc.TextRepr()
+ # For portably converting strings between python2 and python3
+ BASESTRING_TYPES = BASESTRING_TYPES
+ TEXT_TYPES = TEXT_TYPES
+
class FileWriter(object):
"""An object that appends to or overwrites a single file."""
import sys
+ # For portably converting strings between python2 and python3
+ BASESTRING_TYPES = BASESTRING_TYPES
+ TEXT_TYPES = TEXT_TYPES
def __init__(self, path):
self.path = path
@@ -77,22 +94,10 @@ def __init__(self, path):
if open.__name__ == 'FakeFile': # dev_appserver's patched 'file'
self.open = open.__bases__[0] # the original built-in 'file'
- def _isbasestring(self, value):
- if self.sys.version_info >= (3,):
- return isinstance(value, (str, bytes))
- else:
- return isinstance(value, basestring)
-
- def _istext(self, value):
- if self.sys.version_info >= (3,):
- return isinstance(value, str)
- else:
- return isinstance(value, unicode)
-
def write(self, mode, content):
if 'b' not in mode:
mode = '%sb' % mode
- if self._isbasestring(content) and self._istext(content):
+ if isinstance(content, self.BASESTRING_TYPES) and isinstance(content, self.TEXT_TYPES):
content = content.encode('utf-8')
try:
f = self.open(self.path, mode)
@@ -177,9 +182,9 @@ def safe_repr(self, value):
# TODO: Show a nicer repr for SRE.Match objects.
# TODO: Show a nicer repr for big multiline strings.
result = self.TEXT_REPR.repr(value)
- if self.writer.file_writer._isbasestring(value) and len(value) > 80:
+ if isinstance(value, self.BASESTRING_TYPES) and len(value) > 80:
# If the string is big, save it to a file for later examination.
- if self.writer.file_writer._istext(value):
+ if isinstance(value, self.TEXT_TYPES):
value = value.encode('utf-8')
path = self.OUTPUT_PATH + '%08d.txt' % self.random.randrange(1e8)
self.FileWriter(path).write('w', value)
@@ -339,5 +344,4 @@ def d(self, depth=1):
# Install the Q() object in sys.modules so that "import q" gives a callable q.
-import sys
sys.modules['q'] = Q()
--
1.8.1.6