You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm opening this as an issue separate from #6586 to better document the investigation into the root cause. This affects both the v2.0.x and master branches.
We can make the failures a bit more reproducible by repeating the tests a bit. What I did was the following:
Choose one of the mathtext/mathfont tests (e.g. mathfont_*_08)
Modify test_mathtext.py to drop the other tests and run only 08 100 times over.
Edit Text._get_layout to print out whether the cache hit worked or failed.
In the end, you will get about 2 or 3 failures out of the 500. On the failures, the cache returns a value. It turns out that every once in a while, the renderer will have the same ID (or be the same one, I don't know). Since the cache key does not include the mathtext fontset, the cached value will be for some other one and thus be in the wrong place.
I'm not sure how to easily fix this. Ideally, the fontset would be part of the key, but it's not actually used by Text objects, but the MathTextParser. According to #7107, baking the rcParam directly into initialization is a hard problem. Maybe we should find a way to disable the cache during test?
Both use hash(prop) as part of the cache key. What the hash function guarantees is that if two objects are equal they have the same hash value, not the other way around. Could we be getting an occasional hash collision?
In these tests, the FontProperties are exactly the same across the 5 fontsets. It's only the mathtext.fontsetrcParam that changes, but it's only checked in mathtext.py while the cached layout is found in text.py.
The fix looks like it is give renderers some sort of unique id (uuid4 or just a random number) and use that instead of using id. Maybe also put it first so that it fails-fast if on a different renderer.
add _uid attribute to backend_bases.py:RendererBase
change Text.get_prop_tuple to use that _uid instead of id() to identify the renderer. This needs to account for the renderers being None and be back compatible with non-derived-from-us renderers, something like getatter(renderer, '_id', None) or getattr(self._renderer, '_id) or id(renderer or self._renderer)
Any progress here? It seems to me that around half of the daily wheel build / test runs fail with one of these errors - I mean, there's one run in the build matrix that fails, meaning I have to go and restart that build manually.
I've added pytest-rerunfailures to the wheel building repo, as workaround. But, I guess this issue is also going to come up for people running tests on their own machine.
I suspect that this failure is rare in real life as it is a consequence of running a somewhat pathological test where all of these values are the same:
return (x, y, self.get_text(), self._color,
self._verticalalignment, self._horizontalalignment,
hash(self._fontproperties),
self._rotation, self._rotation_mode,
self.figure.dpi, id(renderer or self._renderer),
self._linespacing
)
but with different renderers and rapidly changing rcParams.
For what ever reason, these collisions seem to happen far more often on travis than on my machines. I assume this has something to do with travis being all VMs and / or low memory?
Ah, I thought you were already using the rerunfailures plugin; that's what cut down on the failures on master. #7107 is marked as hard, so I'm not sure why this issue is new-contributor-friendly, but perhaps there's some way to modify only the tests to work nicely.
It's a bit of a hack, but what if we empty Text._cached at the end of each of these tests? The shear number of these tests is already a bit of a time sink, so this may or may not be a good idea.
Activity
jkseppan commentedon Jan 22, 2017
I'm not sure I follow this 100%, but just a thought looking at the caching in text.py and mathtext.py:
Both use
hash(prop)as part of the cache key. What thehashfunction guarantees is that if two objects are equal they have the same hash value, not the other way around. Could we be getting an occasional hash collision?QuLogic commentedon Jan 22, 2017
In these tests, the
FontPropertiesare exactly the same across the 5 fontsets. It's only themathtext.fontsetrcParamthat changes, but it's only checked inmathtext.pywhile the cached layout is found intext.py.TST: Mark mathtext tests as flaky.
TST: Mark mathtext tests as flaky.
tacaswell commentedon Mar 23, 2017
Suspect it as a new render which has the same id ( https://stackoverflow.com/questions/20753364/why-is-the-id-of-a-python-class-not-unique-when-called-quickly and I have hit this at my day-job).
The fix looks like it is give renderers some sort of unique id (
uuid4or just a random number) and use that instead of usingid. Maybe also put it first so that it fails-fast if on a different renderer.tacaswell commentedon Mar 23, 2017
Exact work:
_uidattribute tobackend_bases.py:RendererBaseText.get_prop_tupleto use that_uidinstead ofid()to identify the renderer. This needs to account for the renderers beingNoneand be back compatible with non-derived-from-us renderers, something likegetatter(renderer, '_id', None) or getattr(self._renderer, '_id) or id(renderer or self._renderer)tacaswell commentedon Mar 23, 2017
Testing this is hard given that it relies on triggering a race condition inside of cpython.
TST: Mark mathtext tests as flaky.
TST: Mark mathtext tests as flaky.
TST: Mark mathtext tests as flaky.
TST: Mark mathtext tests as flaky.
TST: Mark mathtext tests as flaky.
TST: Mark mathtext tests as flaky.
matthew-brett commentedon May 13, 2017
Any progress here? It seems to me that around half of the daily wheel build / test runs fail with one of these errors - I mean, there's one run in the build matrix that fails, meaning I have to go and restart that build manually.
QuLogic commentedon May 13, 2017
On
master? They should be marked to re-run on failure.matthew-brett commentedon May 13, 2017
Yes, on master. This is using pytest.
matthew-brett commentedon May 22, 2017
Errors continue, at or around 50% of build runs. Here's the latest build matrix:
https://travis-ci.org/MacPython/matplotlib-wheels/builds/234736344
Failure build log:
https://travis-ci.org/MacPython/matplotlib-wheels/jobs/234736346
This is another plea for a progress update, it's tiring to restart builds by hand every other day.
Add pytest-rerunfailures
matthew-brett commentedon May 22, 2017
I've added
pytest-rerunfailuresto the wheel building repo, as workaround. But, I guess this issue is also going to come up for people running tests on their own machine.tacaswell commentedon May 22, 2017
I suspect that this failure is rare in real life as it is a consequence of running a somewhat pathological test where all of these values are the same:
but with different renderers and rapidly changing rcParams.
For what ever reason, these collisions seem to happen far more often on travis than on my machines. I assume this has something to do with travis being all VMs and / or low memory?
QuLogic commentedon May 23, 2017
Ah, I thought you were already using the rerunfailures plugin; that's what cut down on the failures on
master. #7107 is marked as hard, so I'm not sure why this issue is new-contributor-friendly, but perhaps there's some way to modify only the tests to work nicely.It's a bit of a hack, but what if we empty
Text._cachedat the end of each of these tests? The shear number of these tests is already a bit of a time sink, so this may or may not be a good idea.