diff options
-rw-r--r-- | factory/utils.py | 21 | ||||
-rw-r--r-- | tests/test_utils.py | 51 |
2 files changed, 69 insertions, 3 deletions
diff --git a/factory/utils.py b/factory/utils.py index 48c6eed..b27fd77 100644 --- a/factory/utils.py +++ b/factory/utils.py @@ -20,6 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +from __future__ import unicode_literals + import collections #: String for splitting an attribute name into a @@ -96,11 +98,26 @@ def import_object(module_name, attribute_name): return getattr(module, attribute_name) +def _safe_repr(obj): + try: + obj_repr = repr(obj) + except UnicodeError: + return '<bad_repr object at %s>' % id(obj) + + try: # Convert to "text type" (= unicode) + return '%s' % obj_repr + except UnicodeError: # non-ascii bytes repr on Py2 + return obj_repr.decode('utf-8') + + def log_pprint(args=(), kwargs=None): kwargs = kwargs or {} return ', '.join( - [str(arg) for arg in args] + - ['%s=%r' % item for item in kwargs.items()] + [repr(arg) for arg in args] + + [ + '%s=%s' % (key, _safe_repr(value)) + for key, value in kwargs.items() + ] ) diff --git a/tests/test_utils.py b/tests/test_utils.py index 8c73935..d321c2a 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -20,11 +20,14 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +from __future__ import unicode_literals + + import itertools from factory import utils -from .compat import unittest +from .compat import is_python2, unittest class ExtractDictTestCase(unittest.TestCase): @@ -233,6 +236,52 @@ class ImportObjectTestCase(unittest.TestCase): 'this-is-an-invalid-module', '__name__') +class LogPPrintTestCase(unittest.TestCase): + def test_nothing(self): + txt = utils.log_pprint() + self.assertEqual('', txt) + + def test_only_args(self): + txt = utils.log_pprint((1, 2, 3)) + self.assertEqual('1, 2, 3', txt) + + def test_only_kwargs(self): + txt = utils.log_pprint(kwargs={'a': 1, 'b': 2}) + self.assertIn(txt, ['a=1, b=2', 'b=2, a=1']) + + def test_bytes_args(self): + txt = utils.log_pprint((b'\xe1\xe2',)) + expected = "b'\\xe1\\xe2'" + if is_python2: + expected = expected.lstrip('b') + self.assertEqual(expected, txt) + + def test_text_args(self): + txt = utils.log_pprint(('ŧêßŧ',)) + expected = "'ŧêßŧ'" + if is_python2: + expected = "u'\\u0167\\xea\\xdf\\u0167'" + self.assertEqual(expected, txt) + + def test_bytes_kwargs(self): + txt = utils.log_pprint(kwargs={'x': b'\xe1\xe2', 'y': b'\xe2\xe1'}) + expected1 = "x=b'\\xe1\\xe2', y=b'\\xe2\\xe1'" + expected2 = "y=b'\\xe2\\xe1', x=b'\\xe1\\xe2'" + if is_python2: + expected1 = expected1.replace('b', '') + expected2 = expected2.replace('b', '') + self.assertIn(txt, (expected1, expected2)) + + def test_text_kwargs(self): + txt = utils.log_pprint(kwargs={'x': 'ŧêßŧ', 'y': 'ŧßêŧ'}) + expected1 = "x='ŧêßŧ', y='ŧßêŧ'" + expected2 = "y='ŧßêŧ', x='ŧêßŧ'" + if is_python2: + expected1 = "x=u'\\u0167\\xea\\xdf\\u0167', y=u'\\u0167\\xdf\\xea\\u0167'" + expected2 = "y=u'\\u0167\\xdf\\xea\\u0167', x=u'\\u0167\\xea\\xdf\\u0167'" + self.assertIn(txt, (expected1, expected2)) + + class ResetableIteratorTestCase(unittest.TestCase): def test_no_reset(self): i = utils.ResetableIterator([1, 2, 3]) |