[pytest-dev] Enabling viewing of rewritten AST trees as Python

Tom Viner tom at viner.tv
Sun Feb 21 16:30:09 EST 2016


To update on this topic, I've now published a pytest plugin to display the
rewritten AST as Python:
https://github.com/tomviner/pytest-ast-back-to-python

Not sure if it will ever come in handy, but it was interesting to create my
first pytest plugin anyway! Keep it in mind as an option, if we get any
bugs with assertion rewriting.

It works like this:

As an example take a trivial test like:

def test_simple():
    a = 1
    b = 2
    assert 1 + 2 == 3

View the rewritten AST as Python like this:

$ py.test --show-ast-as-python test_simple.py
======================================== test session starts
========================================
plugins: ast-back-to-python-0.1.0, cov-2.2.1
collected 1 items

test_simple.py .
======================================== Rewritten AST as Python
========================================
import builtins as @py_builtins
import _pytest.assertion.rewrite as @pytest_ar

def test_simple():
    a = 1
    b = 2
    @py_assert0 = 1
    @py_assert2 = 2
    @py_assert4 = @py_assert0 + @py_assert2
    @py_assert6 = 3
    @py_assert5 = @py_assert4 == @py_assert6
    if not @py_assert5:
        @py_format8 = @pytest_ar._call_reprcompare(('==',), (@py_assert5,),
('(%(py1)s + %(py3)s) == %(py7)s',), (@py_assert4, @py_assert6)) % {'py3':
@pytest_ar._saferepr(@py_assert2), 'py1':
@pytest_ar._saferepr(@py_assert0), 'py7': @pytest_ar._saferepr(@py_assert6)}
        @py_format10 = ('' + 'assert %(py9)s') % {'py9': @py_format8}
        raise AssertionError(@pytest_ar._format_explanation(@py_format10))
    @py_assert0 = @py_assert2 = @py_assert4 = @py_assert5 = @py_assert6 =
None

On 2 March 2015 at 09:06, Tom Viner <tom at viner.tv> wrote:

> One extra note:
>
> `py.test -s` is required to see rewritten AST output, even for failing
> tests, because the output comes while
> tests are being collected and rewritten, not during the execution of a
> test. So pytest's "show output upon
> fail" cannot help here.
>
> If anyone knows how to tie the output to particular tests, that would be
> great.
>
>
> On 1 March 2015 at 23:01, Tom Viner <tom at viner.tv> wrote:
>
>> Thanks for your ideas Floris, I've managed to get it working with
>> your pytest_configure suggestion.
>>
>> The only extra bit was having to disable reading the cached pyc files
>> that pytest writes, as these skip my monkeypatch.
>>
>> Take a look, it's simple to use:
>> https://gist.github.com/tomviner/c3537c2f2b2b8172f83e
>>
>> If there's any demand, I could easily make this a pip installable pytest
>> plugin.
>>
>> On 13 November 2014 at 23:34, Floris Bruynooghe <flub at devork.be> wrote:
>>
>>> Hi Tom,
>>>
>>> On 9 November 2014 19:18, Tom Viner <tom at viner.tv> wrote:
>>> > The four options I can think of to gain access to this variable:
>>> > - monkey patch rewrite.rewrite_asserts
>>> > - edit rewrite_asserts and paste in the logging code above:
>>> >     -- temporarily, by each developer, on each occasion required
>>> >     -- permanently, but only running when a certain debug flag is
>>> active
>>> > - expose the rewritten AST via a new hook
>>> >
>>> > monkey patch is my preferred option, because if I can make it work, a
>>> plugin
>>> > could be written. I just need some help to find an appropriate hook to
>>> do
>>> > the monkey patching before pytest gets going with the
>>> AssertionRewritingHook
>>> > and calls rewrite_asserts. Without knowledge of an early-running hook,
>>> I
>>> > could only get this working by patching rewrite_asserts then calling
>>> > pytest.main myself, see
>>> > https://gist.github.com/tomviner/13c95cdb1e159028fc0b
>>>
>>> Would this work by using monkeypatching, but using a method on
>>> _pytest.pytester.TmpTestDir which wraps around inline_run or
>>> inline_runsource?  That would seem like a fairly reasonable approach.
>>> It could simply skip with an appropriate message if the meta lib is
>>> importable and print the reversed python code to stdout for capsys to
>>> collect.
>>>
>>> If you would like to go the full plugin way I believe you just need to
>>> hook in before collection happens.  I imagine pytest_configure would
>>> be a reasonable hook for that, but have to admit I haven't tried it.
>>>
>>>
>>> Regards,
>>> Floris
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/pytest-dev/attachments/20160221/7a9b38e1/attachment.html>


More information about the pytest-dev mailing list