[PATCH] Add and use the safe_string module and the SafeStr class
Vratislav Podzimek
vpodzime at redhat.com
Mon Jun 17 10:16:36 UTC 2013
safe_string module provides the 'SafeStr' class which is a class inheriting from
Python's 'str' class and overriding the __add__ method to allow safe appending
of ascii strings, utf-8 encoded unicode strings, unicode strings, binary data
represented by a string and objects with or without __str__ method.
With this class we no longer have to check values for being of type UnicodeType,
and we can handle binary data correctly.
Resolves: rhbz#886983
Resolves: rhbz#974032
Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
meh/dump.py | 13 ++++-------
meh/safe_string.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++
tests/handle_binary.py | 23 +++++++++++++++++++
tests/safe_string_test.py | 38 ++++++++++++++++++++++++++++++++
4 files changed, 121 insertions(+), 9 deletions(-)
create mode 100644 meh/safe_string.py
create mode 100644 tests/handle_binary.py
create mode 100755 tests/safe_string_test.py
diff --git a/meh/dump.py b/meh/dump.py
index cc049c0..f52c051 100644
--- a/meh/dump.py
+++ b/meh/dump.py
@@ -30,6 +30,7 @@ import types
import sys
import codecs
from meh import PackageInfo
+from meh.safe_string import SafeStr
class ExceptionDump(object):
"""This class represents a traceback and contains several useful methods
@@ -292,7 +293,7 @@ class ExceptionDump(object):
not hasattr(instance, "__class__") or \
not hasattr(instance, "__dict__")
- ret = ""
+ ret = SafeStr()
# protect from loops
try:
@@ -360,21 +361,15 @@ class ExceptionDump(object):
first = 0
if type(k) == types.StringType:
ret += "'%s': " % (k,)
- elif type(k) == types.UnicodeType:
- ret += "'%s': " % k.encode("utf-8")
else:
ret += "%s: " % (k,)
if __isSimpleType(v):
- if type(v) == types.UnicodeType:
- v = v.encode("utf-8")
ret += "%s" % (v,)
else:
ret += self._dumpClass(v, level + 1, parentkey = curkey, skipList=skipList)
ret += "}\n"
elif __isSimpleType(value):
- if type(value) == types.UnicodeType:
- value = value.encode("utf-8")
ret += "%s%s: %s\n" % (pad, curkey, value)
else:
ret += "%s%s: " % (pad, curkey)
@@ -392,7 +387,7 @@ class ExceptionDump(object):
written out, except for those mentioned in the attrSkipList.
"""
idSkipList = []
- ret = ""
+ ret = SafeStr()
# We need to augment the environment eval() will run in with the
# bindings that were local when the traceback happened so that the
@@ -493,7 +488,7 @@ class ExceptionDump(object):
"""
- ret = str(self)
+ ret = SafeStr(str(self))
ret += self.dump(obj)
return ret
diff --git a/meh/safe_string.py b/meh/safe_string.py
new file mode 100644
index 0000000..558ebb7
--- /dev/null
+++ b/meh/safe_string.py
@@ -0,0 +1,56 @@
+#
+# Copyright (C) 2013 Red Hat, Inc.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Vratislav Podzimek <vpodzime at redhat.com>
+#
+#
+
+"""
+This module provides a SafeStr class.
+
+ at see: SafeStr
+
+"""
+
+class SafeStr(str):
+ """
+ String class that has a modified __add__ method so that ascii strings,
+ binary data represented as a byte string and unicode objects can be
+ safely appended to it (not causing traceback). BINARY DATA IS OMITTED.
+
+ """
+
+ def __add__(self, other):
+ if not (isinstance(other, str) or isinstance(other, unicode)):
+ if hasattr(other, "__str__"):
+ other = other.__str__()
+ else:
+ other = "OMITTED OBJECT WITHOUT __str__ METHOD"
+
+ if isinstance(other, unicode):
+ ret = SafeStr(str.__add__(self, other.encode("utf-8")))
+ else:
+ try:
+ # try to decode which doesn't cause traceback for utf-8 encoded
+ # non-ascii string and ascii string
+ other.decode("utf-8")
+ ret = SafeStr(str.__add__(self, other))
+ except UnicodeDecodeError:
+ # binary data
+ ret = SafeStr(str.__add__(self, "OMITTED BINARY DATA"))
+
+ return ret
diff --git a/tests/handle_binary.py b/tests/handle_binary.py
new file mode 100644
index 0000000..50f44aa
--- /dev/null
+++ b/tests/handle_binary.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+from tests.baseclass import BaseTestCase
+from meh import Config
+
+BINARY_DATA = "\xff\xfe\xdd"
+
+class BinaryExample(object):
+ def __init__(self):
+ self.bin_data = BINARY_DATA
+
+class HandleBinary_TestCase(BaseTestCase):
+ def runTest(self):
+ binary_example = BinaryExample()
+
+ conf = Config(programName="UnicodeTest",
+ programVersion="1.0")
+
+ # should not raise exception
+ dump = self.dump(conf, binary_example)
+
+ self.assertIn("OMITTED BINARY DATA", dump)
+
diff --git a/tests/safe_string_test.py b/tests/safe_string_test.py
new file mode 100755
index 0000000..a41e289
--- /dev/null
+++ b/tests/safe_string_test.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+
+from tests.baseclass import BaseTestCase
+from meh.safe_string import SafeStr
+
+class TestClass(object):
+ def __str__(self):
+ return "string representation of TestClass instance"
+
+class TestClass2():
+ pass
+
+class SafeStr_TestCase(BaseTestCase):
+ def setUp(self):
+ self.safestr = SafeStr()
+ self.unistr = u"ááááá"
+ self.enc_unistr = self.unistr.encode("utf-8")
+ self.asciistr = "aaaa"
+ self.bindata = '\xff\xff\xfe'
+ self.test_object = TestClass()
+ self.test_object2 = TestClass2()
+
+ def runTest(self):
+ self.safestr += self.asciistr
+ self.safestr += self.enc_unistr
+ self.safestr += self.unistr
+ self.safestr += self.bindata
+ self.safestr += self.test_object
+ self.safestr += self.test_object2
+
+ self.assertIn(self.asciistr, self.safestr)
+
+ # should be included twice -- appended enc_unistr and unistr
+ self.assertIn(2*self.enc_unistr, self.safestr)
+ self.assertIn("OMITTED BINARY DATA", self.safestr)
+ self.assertIn(str(self.test_object), self.safestr)
+ self.assertIn("OMITTED OBJECT WITHOUT __str__ METHOD", self.safestr)
+
--
1.7.11.7
More information about the anaconda-patches
mailing list