1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
from pypy.interpreter.gateway import unwrap_spec
def saferepr(space, w_obj):
"""Get a safe repr of an object for assertion error messages.
The assertion formatting (util.format_explanation()) requires
newlines to be escaped since they are a special character for it.
Normally assertion.util.format_explanation() does this but for a
custom repr it is possible to contain one of the special escape
sequences, especially '\n{' and '\n}' are likely to be present in
JSON reprs.
"""
return space.newtext(space.text_w(space.repr(w_obj)).replace('\n', '\\n'))
def format_assertmsg(space, __args__):
"""Format the custom assertion message given.
For strings this simply replaces newlines with '\n~' so that
util.format_explanation() will preserve them instead of escaping
newlines. For other objects py.io.saferepr() is used first.
"""
# XXX
return obj.replace("\n", "\n~").replace("%", "%%")
def _split_explanation(explanation):
"""Return a list of individual lines in the explanation
This will return a list of lines split on '\n{', '\n}' and '\n~'.
Any other newlines will be escaped and appear in the line as the
literal '\n' characters.
"""
raw_lines = (explanation or '').split('\n')
lines = [raw_lines[0]]
for values in raw_lines[1:]:
if values and values[0] in ['{', '}', '~', '>']:
lines.append(values)
else:
lines[-1] += '\\n' + values
return lines
def _format_lines(lines):
"""Format the individual lines
This will replace the '{', '}' and '~' characters of our mini
formatting language with the proper 'where ...', 'and ...' and ' +
...' text, taking care of indentation along the way.
Return a list of formatted lines.
"""
result = lines[:1]
stack = [0]
stackcnt = [0]
for line in lines[1:]:
if line.startswith('{'):
if stackcnt[-1]:
s = 'and '
else:
s = 'where '
stack.append(len(result))
stackcnt[-1] += 1
stackcnt.append(0)
result.append(' +' + ' ' * (len(stack) - 1) + s + line[1:])
elif line.startswith('}'):
stack.pop()
stackcnt.pop()
result[stack[-1]] += line[1:]
else:
assert line[0] in ['~', '>']
stack[-1] += 1
indent = len(stack) if line.startswith('~') else len(stack) - 1
result.append(' ' * indent + line[1:])
assert len(stack) == 1
return result
@unwrap_spec(explanation="text")
def format_explanation(space, explanation):
"""This formats an explanation
Normally all embedded newlines are escaped, however there are
three exceptions: \n{, \n} and \n~. The first two are intended
cover nested explanations, see function and attribute explanations
for examples (.visit_Call(), visit_Attribute()). The last one is
for when one explanation needs to span multiple lines, e.g. when
displaying diffs.
"""
lines = _split_explanation(explanation)
result = _format_lines(lines)
return space.newtext('\n'.join(result))
def should_repr_global_name(space, w_obj):
return space.newbool(
space.findattr(w_obj, space.newtext("__name__")) is None and
not space.callable_w(w_obj))
@unwrap_spec(is_or=bool)
def format_boolop(space, w_explanations, is_or):
explanations_w = space.unpackiterable(w_explanations)
explanation = "(" + (is_or and " or " or " and ").join([space.text_w(w_e) for w_e in explanations_w]) + ")"
return space.newtext(explanation.replace('%', '%%'))
def call_reprcompare(space, w_ops, w_results, w_expls, w_each_obj):
ops_w = space.unpackiterable(w_ops)
results_w = space.unpackiterable(w_results)
expls_w = space.unpackiterable(w_expls)
each_obj_w = space.unpackiterable(w_each_obj)
for i, w_res, w_expl in zip(range(len(ops_w)), results_w, expls_w):
try:
done = space.is_true(space.not_(w_res))
except Exception:
done = True
if done:
break
# XXX disabled for now
#w_custom = callbinrepr(ops_w[i], each_obj_w[i], each_obj_w[i + 1])
#if w_custom is not None:
# return w_custom
return w_expl
|