Skip to content

Instantly share code, notes, and snippets.

@tomviner
Last active August 29, 2015 14:08
Show Gist options
  • Save tomviner/aac26d5ac93a5d34106c to your computer and use it in GitHub Desktop.
Save tomviner/aac26d5ac93a5d34106c to your computer and use it in GitHub Desktop.
from __future__ import unicode_literals
class Explode():
def __repr__(self):
return '(1/0)'
explode = Explode()
class Expr(object):
def __init__(self, percent_expr, logic_op, bool_expr, percent_first, percent_char):
percent_expr = percent_expr.replace('%', percent_char)
self.percent_expr = '({} {} {})'.format(*percent_expr)
self.logic_op = logic_op
self.bool_expr = bool_expr
self.percent_first = percent_first
self.percent_char = percent_char
def expr(self, explode_per=False):
percent_expr = self.percent_expr
if explode_per:
percent_expr = explode
if not self.percent_first:
return '{} {} {}'.format(percent_expr, self.logic_op, self.bool_expr)
return '{} {} {}'.format(self.bool_expr, self.logic_op, percent_expr)
def asserts_true(self):
return bool(eval(self.expr()))
def percent_is_evaled(self):
try:
eval(self.expr(explode_per=True))
except ZeroDivisionError:
return True
else:
return False
def function_name(self):
return (self.expr().replace('-', 'sub')
.replace(' ', '_') .replace('(', '')
.replace(')', '') .replace('%', 'mod'))
def function_docstring(self):
return 'Asserts: {}. Percent {} evaled'.format(self.asserts_true(),
'*is*' if self.percent_is_evaled() else 'is *not*')
def short_cirtuit_expr(self):
"Trim off unevaled sub-expression"
if self.percent_is_evaled():
return self.expr()
return '({})'.format(self.bool_expr)
def getmsg(self):
if self.asserts_true():
return 'getmsg(f, must_pass=True)'
if not self.percent_is_evaled():
return 'assert getmsg(f) == "assert {}"'.format(self.short_cirtuit_expr())
return """
try:
getmsg(f) == "assert {}"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {{!r}}".format(e))
""".strip().format(self.short_cirtuit_expr())
def __unicode__(self):
return """
def test_{}(self):
"{}"
def f():
assert {}
{}
""".strip('\n').format(self.function_name(), self.function_docstring(), self.expr(), self.getmsg())
def __repr__(self):
return self.expr()
@property
def ordering(self):
return self.percent_char, self.asserts_true(), self.percent_is_evaled()
def __cmp__(self, other):
return cmp(self.ordering, other.ordering)
def __hash__(self):
return hash(self.expr())
def generate_all_cases():
for logic_op in ('and', 'or'):
for percent_first in (True, False):
for bool_expr in ('True', 'False'):
# eval as 1 and 0
for percent_expr in ('3%2', '1%1'):
# repeat all with '-' to check that expressions are correct,
# once the ValueError is fixed.
for percent_char in ('%', '-'):
yield Expr(percent_expr, logic_op, bool_expr, percent_first, percent_char)
def main():
new_tests = '\n'.join(map(unicode,
sorted(generate_all_cases())
))
print new_tests
test_source_in_fn = "pytest-git-remote-2/testing/test_assertrewrite_input.py"
test_source_out_fn = "pytest-git-remote-2/testing/test_assertrewrite_output.py"
test_source = open(test_source_in_fn).read()
test_source = test_source.replace('# percent test here', new_tests)
open(test_source_out_fn, 'w').write(test_source)
def test_unique_cases():
cases = list(generate_all_cases())
assert len(cases) == len(set(cases))
if __name__ == '__main__':
import pytest
fails = pytest.main(__file__)
assert not fails
main()
"""
# generate rewritten code using `meta`, the ast reverse parsing tool:
# https://srossross.github.io/Meta/html/api/asttools.html#meta.asttools.python_source
# edit rewrite in testing/test_assertrewrite.py
def rewrite(src):
tree = ast.parse(src)
rewrite_asserts(tree)
# insert these 2 lines:
import meta
meta.asttools.python_source(tree) # remove '@'s to enable running
return tree
# The test being rewritten here:
class TestAssertionRewriteCompoundAssertWithPercent:
def test_and_or_percent(self):
# issue 615 - ValueError on compound assert with percent
def f():
assert 3 % 2 and False
assert getmsg(f) == "assert ((3 % 2) and False)"
See inline comments below showing how ValueError arises:
"""
import __builtin__ as py_builtins
import _pytest.assertion.rewrite as pytest_ar
def f():
py_assert1 = []
py_assert2 = 3
py_assert4 = 2
py_assert6 = (py_assert2 % py_assert4)
py_assert0 = py_assert6
if py_assert6:
py_assert0 = False
if (not py_assert0):
# as expected py_format7 recieves a `%` here (the `%%` becomes a single `%` after formatting)
py_format7 = ('(%(py3)s %% %(py5)s)' % {'py3':pytest_ar._saferepr(py_assert2), 'py5':pytest_ar._saferepr(py_assert4)})
# py_assert1 here gains the item with the `%`:
py_assert1.append(py_format7)
if py_assert6:
py_format9 = ('%(py8)s' % {'py8':pytest_ar._saferepr(False) if (('False' in py_builtins.locals()) or pytest_ar._should_repr_global_name(False)) else 'False'})
py_assert1.append(py_format9)
# Here pytest_ar._format_boolop(py_assert1, 0) allows the `%` to pass through unescaped
# then ValueErrors when used as a percent format string, which in this case
# should contain no unescaped percents, as an empty formatting dict is supplied.
py_format10 = (pytest_ar._format_boolop(py_assert1, 0) % {})
py_format12 = ('assert %(py11)s' % {'py11':py_format10})
raise AssertionError(pytest_ar._format_explanation(py_format12))
py_assert0 = py_assert1 = py_assert2 = py_assert4 = py_assert6 = None
import pytest
from test_assertrewrite import getmsg
class TestAssertionRewriteCompoundAssertWithPercent:
# start inserted code
# percent test here
# end inserted code
import pytest
from test_assertrewrite import getmsg
class TestAssertionRewriteCompoundAssertWithPercent:
# start inserted code
def test_False_and_3_mod_2(self):
"Asserts: False. Percent is *not* evaled"
def f():
assert False and (3 % 2)
assert getmsg(f) == "assert (False)"
def test_False_and_1_mod_1(self):
"Asserts: False. Percent is *not* evaled"
def f():
assert False and (1 % 1)
assert getmsg(f) == "assert (False)"
def test_True_and_1_mod_1(self):
"Asserts: False. Percent *is* evaled"
def f():
assert True and (1 % 1)
try:
getmsg(f) == "assert True and (1 % 1)"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_1_mod_1_and_True(self):
"Asserts: False. Percent *is* evaled"
def f():
assert (1 % 1) and True
try:
getmsg(f) == "assert (1 % 1) and True"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_3_mod_2_and_False(self):
"Asserts: False. Percent *is* evaled"
def f():
assert (3 % 2) and False
try:
getmsg(f) == "assert (3 % 2) and False"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_1_mod_1_and_False(self):
"Asserts: False. Percent *is* evaled"
def f():
assert (1 % 1) and False
try:
getmsg(f) == "assert (1 % 1) and False"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_False_or_1_mod_1(self):
"Asserts: False. Percent *is* evaled"
def f():
assert False or (1 % 1)
try:
getmsg(f) == "assert False or (1 % 1)"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_1_mod_1_or_False(self):
"Asserts: False. Percent *is* evaled"
def f():
assert (1 % 1) or False
try:
getmsg(f) == "assert (1 % 1) or False"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_True_or_3_mod_2(self):
"Asserts: True. Percent is *not* evaled"
def f():
assert True or (3 % 2)
getmsg(f, must_pass=True)
def test_True_or_1_mod_1(self):
"Asserts: True. Percent is *not* evaled"
def f():
assert True or (1 % 1)
getmsg(f, must_pass=True)
def test_True_and_3_mod_2(self):
"Asserts: True. Percent *is* evaled"
def f():
assert True and (3 % 2)
getmsg(f, must_pass=True)
def test_3_mod_2_and_True(self):
"Asserts: True. Percent *is* evaled"
def f():
assert (3 % 2) and True
getmsg(f, must_pass=True)
def test_False_or_3_mod_2(self):
"Asserts: True. Percent *is* evaled"
def f():
assert False or (3 % 2)
getmsg(f, must_pass=True)
def test_3_mod_2_or_True(self):
"Asserts: True. Percent *is* evaled"
def f():
assert (3 % 2) or True
getmsg(f, must_pass=True)
def test_1_mod_1_or_True(self):
"Asserts: True. Percent *is* evaled"
def f():
assert (1 % 1) or True
getmsg(f, must_pass=True)
def test_3_mod_2_or_False(self):
"Asserts: True. Percent *is* evaled"
def f():
assert (3 % 2) or False
getmsg(f, must_pass=True)
def test_False_and_3_sub_2(self):
"Asserts: False. Percent is *not* evaled"
def f():
assert False and (3 - 2)
assert getmsg(f) == "assert (False)"
def test_False_and_1_sub_1(self):
"Asserts: False. Percent is *not* evaled"
def f():
assert False and (1 - 1)
assert getmsg(f) == "assert (False)"
def test_True_and_1_sub_1(self):
"Asserts: False. Percent *is* evaled"
def f():
assert True and (1 - 1)
try:
getmsg(f) == "assert True and (1 - 1)"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_1_sub_1_and_True(self):
"Asserts: False. Percent *is* evaled"
def f():
assert (1 - 1) and True
try:
getmsg(f) == "assert (1 - 1) and True"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_3_sub_2_and_False(self):
"Asserts: False. Percent *is* evaled"
def f():
assert (3 - 2) and False
try:
getmsg(f) == "assert (3 - 2) and False"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_1_sub_1_and_False(self):
"Asserts: False. Percent *is* evaled"
def f():
assert (1 - 1) and False
try:
getmsg(f) == "assert (1 - 1) and False"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_False_or_1_sub_1(self):
"Asserts: False. Percent *is* evaled"
def f():
assert False or (1 - 1)
try:
getmsg(f) == "assert False or (1 - 1)"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_1_sub_1_or_False(self):
"Asserts: False. Percent *is* evaled"
def f():
assert (1 - 1) or False
try:
getmsg(f) == "assert (1 - 1) or False"
except ValueError as e:
pytest.xfail("issue 615 - ValueError on compound assert with percent: {!r}".format(e))
def test_True_or_3_sub_2(self):
"Asserts: True. Percent is *not* evaled"
def f():
assert True or (3 - 2)
getmsg(f, must_pass=True)
def test_True_or_1_sub_1(self):
"Asserts: True. Percent is *not* evaled"
def f():
assert True or (1 - 1)
getmsg(f, must_pass=True)
def test_True_and_3_sub_2(self):
"Asserts: True. Percent *is* evaled"
def f():
assert True and (3 - 2)
getmsg(f, must_pass=True)
def test_3_sub_2_and_True(self):
"Asserts: True. Percent *is* evaled"
def f():
assert (3 - 2) and True
getmsg(f, must_pass=True)
def test_False_or_3_sub_2(self):
"Asserts: True. Percent *is* evaled"
def f():
assert False or (3 - 2)
getmsg(f, must_pass=True)
def test_3_sub_2_or_True(self):
"Asserts: True. Percent *is* evaled"
def f():
assert (3 - 2) or True
getmsg(f, must_pass=True)
def test_1_sub_1_or_True(self):
"Asserts: True. Percent *is* evaled"
def f():
assert (1 - 1) or True
getmsg(f, must_pass=True)
def test_3_sub_2_or_False(self):
"Asserts: True. Percent *is* evaled"
def f():
assert (3 - 2) or False
getmsg(f, must_pass=True)
# end inserted code
$ tox -e py27 -- testing/test_assertrewrite_output.py -k TestAssertionRewriteCompoundAssertWithPercent -v
GLOB sdist-make: setup.py
py27 inst-nodeps: .tox/dist/pytest-2.7.0.dev1.zip
py27 runtests: PYTHONHASHSEED='2078814091'
py27 runtests: commands[0] | py.test --lsof -rfsxX --junitxml=.tox/py27/log/junit-py27.xml test_assertrewrite_output.py -k TestAssertionRewriteCompoundAssertWithPercent -v
===================================================================== test session starts =====================================================================
platform linux2 -- Python 2.7.6 -- py-1.4.26 -- pytest-2.7.0.dev1 -- .tox/py27/bin/python2.7
collected 32 items
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_and_3_mod_2 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_and_1_mod_1 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_and_1_mod_1 xfail
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_mod_1_and_True xfail
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_mod_2_and_False xfail
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_mod_1_and_False xfail
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_or_1_mod_1 xfail
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_mod_1_or_False xfail
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_or_3_mod_2 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_or_1_mod_1 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_and_3_mod_2 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_mod_2_and_True PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_or_3_mod_2 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_mod_2_or_True PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_mod_1_or_True PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_mod_2_or_False PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_and_3_sub_2 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_and_1_sub_1 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_and_1_sub_1 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_sub_1_and_True PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_sub_2_and_False PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_sub_1_and_False PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_or_1_sub_1 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_sub_1_or_False PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_or_3_sub_2 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_or_1_sub_1 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_True_and_3_sub_2 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_sub_2_and_True PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_False_or_3_sub_2 PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_sub_2_or_True PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_1_sub_1_or_True PASSED
test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::test_3_sub_2_or_False PASSED
-------------------- generated xml file: .tox/py27/log/junit-py27.xml ---------------------
=================================================================== short test summary info ===================================================================
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_True_and_1_mod_1
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 16",)
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_1_mod_1_and_True
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 7",)
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_3_mod_2_and_False
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 7",)
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_1_mod_1_and_False
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 7",)
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_False_or_1_mod_1
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 16",)
XFAIL test_assertrewrite_output.py::TestAssertionRewriteCompoundAssertWithPercent::()::test_1_mod_1_or_False
reason: issue 615 - ValueError on compound assert with percent: ValueError("unsupported format character ')' (0x29) at index 7",)
============================================================ 26 passed, 6 xfailed in 0.74 seconds =============================================================
___________________________________________________________________________ summary ___________________________________________________________________________
py27: commands succeeded
congratulations :)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment