-
Notifications
You must be signed in to change notification settings - Fork 99
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
Avoid mutation of TTFont
to fix issues with concurrent tests
#4835
Avoid mutation of TTFont
to fix issues with concurrent tests
#4835
Conversation
Although this mutation is reversed, it could still interfere with TTFont instances being used concurrently by other tests. Possible fix for fonttools#4834
Failing pytest appears to be unrelated; has a dependency bumped somewhere? |
Undrafting as the PR appears to fix the race condition for me locally (although I may have just gotten lucky) |
# This function mutates the TTF; deep copy to avoid this, and so avoid | ||
# issues with concurrent tests that also use ttFont. | ||
# See https://github.com/fonttools/fontbakery/issues/4834 | ||
ttFont = deepcopy(ttFont) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll admit that I'm a bit unsure about this. By assigning a deepcopy of ttFont to itself aren' t we still overwriting the original object? I suppose we may need to use a different name. Something like my_ttFont = deepcopy(ttFont)
. Does it make sense? I'm not sure if that's exactly how this works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that Python gives function parameters their own independent variable to store their reference to an object, but agree that it's 100% worth double-checking; I had a look just now to be safe, and it looks like we're all good 🎉
from dataclasses import dataclass
@dataclass
class Wrapper:
value: int
def replacer(parameter: Wrapper) -> None:
parameter = Wrapper(value=2)
outside = Wrapper(value=1)
print(outside) # prints Wrapper(value=1)
replacer(outside)
print(outside) # prints Wrapper(value=1) ✅
I considered giving the variable a new name, but thought that reusing it would avoid extra refactoring and would have the bonus of making it impossible for the rest of the function to use the pre-copied object by mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I've just pushed a few commits changing the names, but I had not seen these messages before doing so. I think I'll revert my additional commit, then.
Failing pytest appears to be unrelated;
Just to be sure we're on the same page, what was the pytest failure message in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries, thanks for taking a look Felipe! 🚀
Yes, reverting sounds good - the test that I am seeing ERROR locally is unreachable_glyphs
, which appears to be the one upsetting the CI too, with full error:
AttributeError: 'TTFont' object has no attribute 'glyphOrder'. Did you mean: 'getGlyphOrder'?
I thought it was unrelated before, but now I see that it is one of the checks that we have touched in this PR.
I think what might be happening is that the check previously populated .glyphOrder
as a side-effect, but now that we deepcopy it is not happening any more; this is probably a good thing, so I think the pytest just needs to be updated to call .getGlyphOrder()
instead of trying to access the raw property to accommodate this :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turned out to be a little more complicated because the test relied on certain context to remove a glyph; I think I have a full fix with fe7ab5e though (fuller explanation there too)
f96b1da
to
8958834
Compare
The previous approach relied on the `glyphOrder` property being populated as a side-effect of the "unreachable-glyphs" check, but this no longer happens now that the accidental mutation in the check has been removed. This commit avoids using the internal property entirely by using the `setGlyphOrder()` function, and ensuring that the font is fully loaded prior to this to avoid the glyph being referenced during a later load after it has already been removed from the order. If this causes issues again, it may be more resilient for us to use fontTools' subsetter library to implement this pytest. (PR fonttools#4835)
fe7ab5e
to
b35e3ab
Compare
Although the mutation is reversed, it could still have interfered with
TTFont
instances being used concurrently by other tests.Before undrafting, I will test to see if this fixes #4834.
(even if not, the change may prevent similar issues in the future, and so we may wish to merge anyway)
Checklist
CHANGELOG.md