Skip to content

Text issues when "redirecting" stdout/stderr #4018

Closed

Description

@QuLogic

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.

Activity

  1. added this to the v1.4.x milestone on Jan 20, 2015
  2. tacaswell commented on Jan 20, 2015

    @tacaswell
    Member

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

  3. self-assigned this
    on Jan 20, 2015
  4. mdboom commented on Jan 20, 2015

    @mdboom
    Member

    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.

  5. QuLogic commented on Jan 20, 2015

    @QuLogic
    MemberAuthor

    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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions