Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Text issues when "redirecting" stdout/stderr #4018

Closed
QuLogic opened this issue Jan 20, 2015 · 3 comments
Closed

Text issues when "redirecting" stdout/stderr #4018

QuLogic opened this issue Jan 20, 2015 · 3 comments
Assignees
Milestone

Comments

@QuLogic
Copy link
Member

QuLogic commented Jan 20, 2015

In working out a simpler version of #4010, I managed to isolate a different issue (at least, externally). In ObsPy, there is a CatchOutput context manager that is used by tests to hide output from scripts that are being tested. It redirects stdout and stderr to files. With matplotlib 1.3.1, plots turned out fine using this approach.

x1

With matplotlib 1.4.2, something gets messed up somewhere and text is no longer placed correctly.

x2

I have put together a self-contained example including the context manager. It saves what should be the same image twice as x1.png and x2.png, but the second one appears as above. Some things to note:

  • It works correctly with the TkAgg backend instead of the Agg backend.
  • It works correctly if both plots are within the same CatchOutput context.
  • Quizzically, there are several CatchOutput contexts in the ObsPy tests, but only one pair seem to trigger the bug. Yet this example seems to always trigger the problem and it's much simpler.
  • A bisect points to f4adec7

Now, superficially, the CatchOutput context makes sense to me, and though it is a bit of black magic, it did seem to work alright against matplotlib 1.3.1.

@tacaswell tacaswell added this to the v1.4.x milestone Jan 20, 2015
@tacaswell
Copy link
Member

@mdboom This looks like (yet more) fallout from the conversion to six/py3k compatibility. I had hoped we were past that.

@mdboom mdboom self-assigned this Jan 20, 2015
@mdboom
Copy link
Member

mdboom commented Jan 20, 2015

As you say, CatchOutput does some black magic tinkering with low-level file descriptors. I think it may be where the bug lies. Below, I'm referring to https://gist.github.com/QuLogic/8989e98cc37f26304436

Here's what is happening: CatchOutput creates temporary files to redirect stdout and stderr to. Let's say they are assigned the values 3 and 4. Those fds are cloned into stdout and stderr (thus redirecting), and then they are closed on lines 55/56. This "recycles" those file descriptors to be used again. When the matplotlib code runs, it opens the font using an fd of "3". Then when it's done, the font file is closed on line 81. (Note the code says is it closing the temporary file, but "3" now refers to the font file. There is the error). When the second plot is run, matplotlib reuses the handle to the font file, not realizing that the file has actually been closed out from underneath it. This means it thinks the width of every character is 0, hence the rendering bug you're seeing.

TL;DR: The bug is due to incorrect handling of low-level file handles, and there's not much matplotlib can do to protect against that. I'm calling it not an mpl bug, but feel free to reopen if you have further evidence otherwise.

@QuLogic
Copy link
Member Author

QuLogic commented Jan 20, 2015

Yes, I think you are correct. I've proposed a change to CatchOutput which I think will fix it in ObsPy.

I could have sworn this only happened with one of the test cases, but now I can't seem to not reproduce it with any of them. Darn heisenbugs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants