question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

different ClassDef values between python 2 and 3

See original GitHub issue

It turns out that fonts built with python 2 and 3 may end up having different GPOS tables, because of the non-deterministic way ClassDef class definition tables are encoded in feaLib/otlLib.

The following patch: https://github.com/fonttools/fonttools/compare/issue-766?expand=1

… produces different test outputs, in a seemingly random fashion: https://travis-ci.org/fonttools/fonttools/jobs/183647027

I think the problem lies in this line, where a list of sets of (glyph names) strings is sorted by the length of the sets: https://github.com/fonttools/fonttools/blob/f81e1411b3fb1ca402065fbd9a3c53907d205b58/Lib/fontTools/otlLib/builder.py#L622

If two sets have the same length the order of the set list is not guaranteed to be the same all the time, as they might be hashed differently by different implementations, sometimes even by the same one at different times.

We need to find a better way to sort the ClassDef.

/cc @brawer

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
anthrotypecommented, Dec 30, 2016
0reactions
anthrotypecommented, Dec 31, 2016

otlLib.ClassDefBuilder only receives sets in its own unit tests (otlLib.builder_test), whereas it gets tuples when used from feaLib. I wouldn’t like to modify the tests (by replacing sets with tuples) just to make them green…

I wonder whether I should do this instead: ie. allow both (unordered) sets and ordered sequences as input to ClassDefBuilder:

diff --git a/Lib/fontTools/otlLib/builder.py b/Lib/fontTools/otlLib/builder.py
index c7b753b..891c987 100644
--- a/Lib/fontTools/otlLib/builder.py
+++ b/Lib/fontTools/otlLib/builder.py
@@ -589,7 +589,10 @@ class ClassDefBuilder(object):
         self.useClass0_ = useClass0
 
     def canAdd(self, glyphs):
-        glyphs = tuple(glyphs)
+        if isinstance(glyphs, (set, frozenset)):
+            glyphs = tuple(sorted(glyphs))
+        elif not isinstance(glyphs, tuple):
+            glyphs = tuple(glyphs)
         if glyphs in self.classes_:
             return True
         for glyph in glyphs:
@@ -598,7 +601,10 @@ class ClassDefBuilder(object):
         return True
 
     def add(self, glyphs):
-        glyphs = tuple(glyphs)
+        if isinstance(glyphs, (set, frozenset)):
+            glyphs = tuple(sorted(glyphs))
+        elif not isinstance(glyphs, tuple):
+            glyphs = tuple(glyphs)
         if glyphs in self.classes_:
             return
         self.classes_.add(glyphs)
Read more comments on GitHub >

github_iconTop Results From Across the Web

New-Style Classes - The Conservative Python 3 Porting Guide
Python 2 had two styles of classes: “old-style” and “new-style”. Old-style classes were defined without a superclass (or by deriving from other old-style...
Read more >
9. Classes — Python 3.11.1 documentation
Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances...
Read more >
Difference Between Python 2 and 3 - InterviewBit
The value of variables never changes in Python 3. In Python 2, the xrange() function has been defined for iterations.
Read more >
Python 2 Vs. Python 3: Key Difference Between 2.x & 3.x
Python 3 value of variables never changes whereas in Python 2 value of the global variable will be changed while using it inside...
Read more >
Python Tutorial: classes and instances - 2021 - BogoToBogo
For example, if we create two Student instances with different id values, ... So, Python follows the link from instance to class to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found