Bug 1296503 - Add an indented_repr function to mozbuild.util. r=ted

This commit is contained in:
Mike Hommey 2016-08-18 18:18:04 +09:00
Родитель 1ff245b181
Коммит 31a17a020e
2 изменённых файлов: 101 добавлений и 0 удалений

Просмотреть файл

@ -1,3 +1,4 @@
# coding: utf-8
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@ -12,6 +13,7 @@ import shutil
import string
import sys
import tempfile
import textwrap
from mozfile.mozfile import NamedTemporaryFile
from mozunit import (
@ -24,6 +26,7 @@ from mozbuild.util import (
FileAvoidWrite,
group_unified_files,
hash_file,
indented_repr,
memoize,
memoized_property,
pair,
@ -887,5 +890,35 @@ class TestEnumString(unittest.TestCase):
with self.assertRaises(ValueError):
type = CompilerType('foo')
class TestIndentedRepr(unittest.TestCase):
def test_indented_repr(self):
data = textwrap.dedent(r'''
{
'a': 1,
'b': b'abc',
b'c': 'xyz',
'd': False,
'e': {
'a': 1,
'b': b'2',
'c': '3',
},
'f': [
1,
b'2',
'3',
],
'pile_of_bytes': b'\xf0\x9f\x92\xa9',
'pile_of_poo': '💩',
'special_chars': '\\\'"\x08\n\t',
'with_accents': 'éàñ',
}''').lstrip()
obj = eval(data)
self.assertEqual(indented_repr(obj), data)
if __name__ == '__main__':
main()

Просмотреть файл

@ -1176,3 +1176,71 @@ class EnumString(unicode):
class EnumStringSubclass(EnumString):
POSSIBLE_VALUES = possible_values
return EnumStringSubclass
def _escape_char(c):
# str.encode('unicode_espace') doesn't escape quotes, presumably because
# quoting could be done with either ' or ".
if c == "'":
return "\\'"
return unicode(c.encode('unicode_escape'))
# Mapping table between raw characters below \x80 and their escaped
# counterpart, when they differ
_INDENTED_REPR_TABLE = {
c: e
for c, e in map(lambda x: (x, _escape_char(x)),
map(unichr, range(128)))
if c != e
}
# Regexp matching all characters to escape.
_INDENTED_REPR_RE = re.compile(
'([' + ''.join(_INDENTED_REPR_TABLE.values()) + ']+)')
def indented_repr(o, indent=4):
'''Similar to repr(), but returns an indented representation of the object
One notable difference with repr is that the returned representation
assumes `from __future__ import unicode_literals`.
'''
one_indent = ' ' * indent
def recurse_indented_repr(o, level):
if isinstance(o, dict):
yield '{\n'
for k, v in sorted(o.items()):
yield one_indent * (level + 1)
for d in recurse_indented_repr(k, level + 1):
yield d
yield ': '
for d in recurse_indented_repr(v, level + 1):
yield d
yield ',\n'
yield one_indent * level
yield '}'
elif isinstance(o, bytes):
yield 'b'
yield repr(o)
elif isinstance(o, unicode):
yield "'"
# We want a readable string (non escaped unicode), but some
# special characters need escaping (e.g. \n, \t, etc.)
for i, s in enumerate(_INDENTED_REPR_RE.split(o)):
if i % 2:
for c in s:
yield _INDENTED_REPR_TABLE[c]
else:
yield s
yield "'"
elif hasattr(o, '__iter__'):
yield '[\n'
for i in o:
yield one_indent * (level + 1)
for d in recurse_indented_repr(i, level + 1):
yield d
yield ',\n'
yield one_indent * level
yield ']'
else:
yield repr(o)
return ''.join(recurse_indented_repr(o, 0))