Saturday, July 9, 2011

Behind the scenes of py.test's new assertion rewriting

py.test 2.1 was just released. py.test, which uses the Python assert statement to check test conditions, has long had support for displaying intermediate values in subexpressions of a failing assert statement. This feature is called assertion introspection. Historically, py.test performed assertion introspection by reinterpreting failed assertions in order to glean information about subexpressions. In assertion reinterpreting, py.test actually reruns the assertion noting intermediate values during interpretation. This works pretty well but is subject to several problems, most importantly that assert statements with side-effects can produce strange results because they are evaluated twice on failure. py.test 2.1's main new feature, which I wrote (with generous sponsorship from Merlinux GmbH), is a new assertion introspection technique called assertion rewriting. Assertion rewriting modifies the AST of test modules to produce subexpression information when assertions fail. This blog post will give a peek into how this is done and what the rewritten tests look like.

py.test tries to rewrite every module that it collects as a test module. Assertion rewriting uses a PEP 302 import hook to capture test modules for rewriting. I'm happy to report doing this was easier than I expected. Most of the code in the import hook I had to write was dealing with detecting test modules rather than supporting import's extremely complicated API. Rewriting has a non-zero cost during test collection, so py.test compiles rewritten modules to bytecode and caches them in the PEP 3147 PYC repository, __pycache__. One major thing I did have to account for was the possibility that multiple py.test processes would be writing PYC files. (This is a very real possibility when the xdist plugin is being used. Therefore, py.test uses only atomic operations on the rewritten PYC file. Windows, lacking atomic rename, was a pain here.

I'm now going to demonstrate what py.test's rewriting phase does to a test module. Let's dive in with a failing test for a (broken) function that is supposed to create empty files:

import os

def make_empty_file(name):
with open(name, "w") as fp:
fp.write("hello")

def test_make_empty_file():
name = "/tmp/empty_test"
make_empty_file(name)
with open(name, "r") as fp:
assert not fp.read()


This test nicely demonstrates the problem with py.test's old assertion method mentioned in the first paragraph. If we force the old assertion interpretation mode with --assert=reinterp, we see:


def test_make_empty_file():
name = "/tmp/empty_test"
make_empty_file(name)
with open(name, "r") as fp:
> assert not fp.read()
E AssertionError: (assertion failed, but when it was re-run for printing intermediate values, it did not fail. Suggestions: compute assert expression before the assert or use --no-assert)

test_empty_file.py:11: AssertionError


The problem is that assert statement has the side-effect of reading the file. When py.test reinterprets the assert statement, it uses the same file object, now at EOF, and read() returns an empty string. py.test's new rewriting mode fixes this by scanning the assert for introspection information before executing the test. Running py.test with assertion rewriting enabled gives the desired result:


def test_make_empty_file():
name = "/tmp/empty_test"
make_empty_file(name)
with open(name, "r") as fp:
> assert not fp.read()
E assert not 'hello'
E + where 'hello' = ()
E + where = .read

test_empty_file.py:11: AssertionError


So what magic has py.test worked to display such nice debugging information? This is what Python is actually executing:

def test_make_empty_file():
name = '/tmp/empty_test'
make_empty_file(name)
with open(name, 'r') as fp:
@py_assert1 = fp.read
@py_assert3 = @py_assert1()
@py_assert5 = (not @py_assert3)
if (not @py_assert5):
@py_format6 = ('assert not %(py4)s\n{%(py4)s = %(py2)s\n{%(py2)s = %(py0)s.read\n}()\n}' %
{'py0': (@pytest_ar._saferepr(fp) if ('fp' in @py_builtins.locals() is not @py_builtins.globals()) else 'fp'),
'py2': @pytest_ar._saferepr(@py_assert1),
'py4': @pytest_ar._saferepr(@py_assert3)})
raise AssertionError(@pytest_ar._format_explanation(@py_format6))
del @py_assert5, @py_assert1, @py_assert3


As you can see, it's not going to be winning any awards for beautiful Python! (Ideally, though, you'll never have to see or think about it.) Examining the rewritten code, we see a lot of internal variables starting with "@" have been created. The "@", invalid in Python identifiers, is to make sure internal names don't conflict with any user-defined names which might be in the scope. In the first four written lines under the with statement, the test of the assert statement has been expanded into its component subexpressions. This allows py.test to display the values of subexpressions should the assertion fail. If the assertion fails, the if statement in the fifth line of rewriting evaluates to True and a AssertionError will be raised. Under the if statement is the real mess. This is where the helpful error message is generated. The line starting with @py_format6 is simply does string formatting (with %) on a template generated from the structure of the assert statement. This template is filled in with the intermediate values of the expressions collected above. @py_builtins is the builtins module, used in case the test is shadowing builtins the rewriting code uses. The @pytest_ar variable is a special module of assertion formatting helpers. For example, @pytest_ar._saferepr is like builtin repr but gracefully handles long reprs and __repr__ methods that raise exceptions. A non-obvious trick in the format dict is the expression @pytest_ar._saferepr(fp) if ('fp' in @py_builtins.locals() is not @py_builtins.globals()) else 'fp'. This checks whether fp is a local variable or not and customizes the display accordingly. After the initial formatting, the helper function _format_explanation is called. This function produces the indentation and "+" you see in the error message. Finally, we note that if the assertion doesn't fail, py.test cleans up after itself by deleting temporary variables.

The example above is a fairly tame (and luckily also typical) assertion. Rewriting gets more "exciting" when boolean operations and comparisons enter because they require short circuit evaluation, which complicates both the expansion of expressions and formatting (think lots of nested ifs).

In conclusion, py.test's new assertion rewriting fixes some long standing issues with assertion introspection and continues py.test's long tradition of excellent debugging support. (There are now three(!) assertion introspection methods in py.test: two reinterpretation implementations as well as rewriting) I just hope I haven't scared you completely off py.test! :)

65 comments:

Michael Foord said...

How easy do you think it would be to abstract out the assertion rewriting and reuse it with other test frameworks?

Could it even be done as a standalone library?

Benjamin Peterson said...

@Michael The assertion stuff is not very dependent on py.test internals, so it should be easy to separate them out if you wanted to. In fact, until recently, assertion introspection code was in the pylib, a separate library than py.test.

gps said...

Nice.

Though I strongly discourage people from using the assert statement in most non-trivial cases in Python due to its syntax oddity and the common error of using ()s that changes the assert into an assert of an always true tuple.

Benjamin Peterson said...

@gps In recent versions of Python, the compiler will give you a warning if you make a vacuous assert statement.

$ python3
Python 3.1.3 (r313:86834, Feb 27 2011, 22:48:24)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> assert (3, "msg")
:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?

Zooko said...

People interested in this should also check out "bindann":

http://tahoe-lafs.org/trac/bindann

It inspects the stack and the source code to extract the values that are relevant to the failing exception. Very cool! I feel like it should have gotten a lot more attention than it did when it was first created.

Disclosure: my brother invented it while staying rent free in my house, and he is super awesome and I love him, so I might be a tad bit biased.

Peterino said...

@Zooko sounds promising, but where is it gone? The link is broken.

Interesting also your own quote from September 14, 2007 in commit 8fd98624:

don't try to use bindann

It causes a mysterious misbehavior in Python import which causes the previous patch to fail (the patch to not run trial tests if dependencies can't be imported)

Xyore said...

Amazing tutorial

latesttechnologyblogs said...

I like your blog, I read this blog please update more content on python, further check it once at python online training

mrkdvsn said...

Sometime few educational blogs become very helpful while getting relevant and new information related to your targeted area. As I found this blog and appreciate the information delivered to my database.medium cursus

Repairtech Solutions said...

The next time I read a blog, I hope that it does not disappoint me as much as this one. I mean, Yes, it was my choice to read, but I really thought you would probably have something interesting to talk about. All I hear is a bunch of whining about something that you can fix if you weren't too busy searching for attention. onsite mobile repair bangalore Spot on with this write-up, I absolutely believe this site needs a lot more attention. I’ll probably be back again to read more, thanks for the information! asus display replacement You are so cool! I don't suppose I've truly read anything like this before. So wonderful to discover somebody with original thoughts on this subject. Really.. thank you for starting this up. This web site is something that is required on the web, someone with a little originality! huawei display repair bangalore

Repairtech Solutions said...

After looking at a few of the blog posts on your web page, I really appreciate your technique of blogging. I added it to my bookmark site list and will be checking back soon. Please visit my website as well and tell me what you think. vivo charging port replacement This site really has all of the info I needed about this subject and didn’t know who to ask. lg service center Bangalore There's definately a great deal to learn about this issue. I really like all the points you've made. motorola display repair bangalore

Raj Sharma said...

Nice Post. I like your blog. Thanks for Sharing.
Python Training Institute in Noida

meritstep1 said...

I just loved your article on the beginners guide to starting a blog.If somebody take this blog article seriously in their life, he/she can earn his living by doing blogging.thank you for thizs article. python online training

Angular expert said...

I really like it whenever people come together and share views. Great blog, keep it up!

Best Advanced Java Training In Bangalore Marathahalli

Advanced Java Courses In Bangalore Marathahalli

Advanced Java Training in Bangalore Marathahalli

Advanced Java Training Center In Bangalore

Advanced Java Institute In Marathahalli

Angular expert said...

Very good information. Lucky me I ran across your site by accident (stumbleupon). I have saved it for later!


Selenium Courses in Marathahalli

selenium institutes in Marathahalli

selenium training in Bangalore

Selenium Courses in Bangalore

best selenium training institute in Bangalore

selenium training institute in Bangalore

svr technologies said...


Hello, I have gone through your post Its really awesome.Thats a great article. I am also want to share about python online course and advanced python training. thank you

mrkdvsn said...

creativity of writer is purely impressive. It has touched to the level of expertise with his writing. Everything is up to the mark. Written perfectly and I can use such information for my coming assignment.cursus mediumschap

Shivani said...

Spot on with this write-up, I actually think this amazing site needs a great deal more attention. I’ll probably be returning to read through more, thanks for the advice!


Selenium Courses in Marathahalli

selenium institutes in Marathahalli

selenium training in Bangalore

Selenium Courses in Bangalore

best selenium training institute in Bangalore

selenium training institute in Bangalore

Gayatri said...

Awesome Post
Blockchain training in Bangalore
best React JS Training course in Bangalore
python certification training in Bangalore

Shivani said...

Hi! I just wish to offer you a big thumbs up for your great info you have right here on this post. I will be coming back to your site for more soon.

Best Advanced Java Training In Bangalore Marathahalli

Advanced Java Courses In Bangalore Marathahalli

Advanced Java Training in Bangalore Marathahalli

Advanced Java Training Center In Bangalore

Advanced Java Institute In Marathahalli

meritstep Technology said...

Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
welcome to akilmanati
akilmanati

meritstep Technology said...

Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
welcome to akilmanati
akilmanati

MS Dynamics said...

The Best of the Blogs You have Mentioned here.
Python Online Training in Hyderabad

Python Institute in Hyderabad

Python Course in Hyderabad

rent a data center said...

if you want to pop up your website then you need office 365 download

sathishkumar said...

Thanks for provide great informatic and looking beautiful blog

python training in bangalore | python online training
aws training in bangalore | aws online training
artificial intelligence training in bangalore | artificial intelligence online training
machine learning training in bangalore | machine learning online training
blockchain training in bangalore | blockchain online training
uipath training in bangalore | uipath online training

sathishkumar said...

Thanks for provide great informatic and looking beautiful blog

python training in bangalore | python online training
aws training in bangalore | aws online training
artificial intelligence training in bangalore | artificial intelligence online training
machine learning training in bangalore | machine learning online training
blockchain training in bangalore | blockchain online training
uipath training in bangalore | uipath online training

Fuel Digital Marketing said...

great article blog. keep posting like this with us.We offer the most budget-friendly quotes on all your digital requirements. We are available to our clients when they lookout for any help or to clear queries.

Best SEO Services in Chennai | digital marketing agencies in chennai | Best seo company in chennai | digital marketing consultants in chennai | Website designers in chennai

bhanu said...

best online course for python machine learning

Shanejo said...

It's very useful blog post with informative and insightful content and i had good experience with this information.I have gone through CRS Info Solutions Home which really nice. Learn more details About Us of CRS info solutions. Here you can see the Courses CRS Info Solutions full list.Find the best Hadoop Training with great faculty. Go to know about crs info solutions Workday Training program.

keerthana said...

Really it is very useful for us.....This information seems to be more unique and interesting.
Thanks for sharing.PHP Training in Chennai

PHP Online Training in Chennai

Machine Learning Training in Chennai

iOT Training in Chennai

Blockchain Training in Chennai

Open Stack Training in Chennai

Anonymous said...

I like the valuable info you provide on your articles. I will bookmark your weblog and check again here frequently. I'm fairly sure I will learn many new stuff right here! Good luck for the following! If you want to enjoy entertainment don't forget to visit สล็อต

meritstep Technology said...

Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
workday studio online training
best workday studio online training
top workday studio online training

meritstep Technology said...

Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
welcome to akilmanati
akilmanati

Free DoFollow Travel Blog Commenting Sites said...

Thanks for sharing nice information. I likes your post. They are so amazing article share.

Free DoFollow Travel Blog Commenting Sites

rocky said...

Thanks for provide great informatic and looking beautiful blog, really nice required information & the things i never imagined and i would request, wright more blog and blog post like that for us. Thanks you once agian
python training in bangalore

python training in hyderabad

python online training

python training

python flask training

python flask online training

python training in coimbatore

pavi said...

I feel really happy to have seen your webpage.I am feeling grateful to read this.you gave a nice information for us.please updating more stuff content...keep up!!

Data Science Training In Chennai

Data Science Online Training In Chennai

Data Science Training In Bangalore

Data Science Training In Hyderabad

Data Science Training In Coimbatore

Data Science Training

Data Science Online Training

dhinesh said...

Full Stack Course Chennai
Full Stack Training in Bangalore

Full Stack Course in Bangalore

Full Stack Training in Hyderabad

Full Stack Course in Hyderabad

Full Stack Training

Full Stack Course

Full Stack Online Training

Full Stack Online Course


sharath said...

Hi Thanks for reading this article – I hope you found it helpful. I have read your blog very good information in this article. it was good knowledge article website your blog. Your blog is a good inspiration for this topic. Thanks read more...
Java Training in Chennai

Java Training in Bangalore

Java Training in Hyderabad

Java Training
Java Training in Coimbatore


Revathi said...

Great post, Thanks for provide a great informatic and looking beautiful blog, really nice required information & the things i never imagined and i would request, wright more blog and blog post like that for us. Thanks you once agian.

ajith said...

thank you for the information

angular js course in chennai

angular course in chennai

angular js online course in chennai

angular js course in bangalore

angular js course in hyderabad

angular js course in coimbatore

angular js course

angular js online course


Pankaj Singh said...

Great blog, thanks for sharing with us. Ogen Infosystem is a leading web designing service provider in Delhi, India.
Website Designing Company

BTree Systems, Software (IT) Training Institute said...


Software Training Institute in Chennai offers best IT Training Courses for Java, Android, PHP, .NET, DevOps, Oracle with 100% placements.
aws training in chennai
Python training in Chennai
data science training in chennai
hadoop training in chennai
machine learning training chennai

Tenride Cab Services said...


Book Tenride call taxi in Chennai at most affordable taxi fare for Local or Outstation rides. Get multiple car options with our Chennai cab service
chennai to bangalore cab
bangalore to chennai cab
hyderabad to bangalore cab
bangalore to hyderabad cab
kochi to chennai cab

fueldigital said...

Thank you for sharing such an informative post
I would highly appreciate if you guide me through this.
water tank level indicator in chennai.
simple water level indicator with a buzzer.
water tank level indicator in chennai.
Dry run timer. double motor sequential timer
Advantages of the product | LED indication
best water level controller suppliers in coimbatore..
best water level controller suppliers in madurai..
best water level controller suppliers in trichy and tirunelveli.

unknow said...

I really enjoyed your blog Thanks for sharing such an informative post.
https://www.login4ites.com/

unknow said...

I really enjoyed your blog Thanks for sharing such an informative post.
https://www.login4ites.com/

Unknown said...

It is really amazing blog, Thanks for sharing.
pincode of bawana

Tenride Cab Services said...

chennai to bangalore cab
bangalore to chennai cab
hyderabad to bangalore cab
bangalore to hyderabad cab
kochi to chennai cab

Nino Nurmadi , S.Kom said...

Nino Nurmadi, S.Kom
Nino Nurmadi, S.Kom
Nino Nurmadi, S.Kom
Nino Nurmadi, S.Kom
Nino Nurmadi, S.Kom
Nino Nurmadi, S.Kom
Nino Nurmadi, S.Kom
Nino Nurmadi, S.Kom
Nino Nurmadi, S.Kom

meritstep123 said...

I just loved your article on the beginners guide to starting a blog.If somebody take this blog article seriously
in their life, he/she can earn his living by doing blogging.Thank you for this article.
tibco sportfire online training

meritstep said...

I just loved your article on the beginners guide to starting a blog.If somebody take this blog article seriously
in their life, he/she can earn his living by doing blogging.Thank you for this article.
best tibco sportfire online training

You and Me said...

Organic chemistry tutor
Organic chemistry tutor
Organic chemistry tutor
Organic chemistry tutor
Organic chemistry tutor

bhanu said...

best online course for python machine learning

meritstep Technology said...

Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
workday online training
best workday online training
top workday online training

Fuel Digi said...

We are the Best Digital Marketing Agency in Chennai.Our team consists of very best of programmers,web developers,SEO experts and many others. we offer all digital marketing service at affordable cost.
Thanks for the article…
Best SEO analytics in chennai
Website Designing Company in chennai
Social Media marketing

Alex leo said...

thanks for sharing this blog buy marijuana online and pills, Buy clonazepam powder online

Buy clonazepam powder online
Buy 2-nmc online
Buy adderall online
Buy actavis-promethazine-codeine online

Buy marijuana online online
Buy Wiz Khalifa OG online
Buy Green Crack online
Buy Girl Scout Cookies online
Buy AK-47 online
Buy Moon Rocks online

meritstep Technology said...

Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
blockchain online training
best blockchain online training
top blockchain online training

Python said...

Thanks for Sharing.
python Online Training

meritstep said...

I just loved your article on the beginners guide to starting a blog.If somebody take this blog article seriously
in their life, he/she can earn his living by doing blogging.Thank you for this article.
best tibco sportfire online training

Python said...

Thanks for Sharing.
python Online Training

Unknown said...

bach flower ,sujok therapy,cosmo Energy Healing ,cosmo spiritual healing

meritstep Technology said...

Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
workday online training
best workday online training
top workday online training

ravisynit said...

great java tips At SynergisticIT we offer the best java bootcamp

meritstep123 said...

I just loved your article on the beginners guide to starting a blog.If somebody take this blog article seriously
in their life, he/she can earn his living by doing blogging.Thank you for this article.
top tibco sportfire online training

meritstep123 said...

I just loved your article on the beginners guide to starting a blog.If somebody take this blog article seriously
in their life, he/she can earn his living by doing blogging.Thank you for this article.
top java online training