Font with missing family causes test failure on OS X

Issue #312 closed
Thomas Kluyver
created an issue

From @Caleb Hattingh on #107:

======================================================================
FAIL: test_get_fonts (pygame.tests.font_test.FontModuleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/calebhattingh/temp/pygamewheel/env/lib/python3.5/site-packages/pygame/tests/font_test.py", line 94, in test_get_fonts
    self.failUnless(name.islower(), name)
AssertionError: False is not true :

======================================================================
FAIL: test_get_fonts (pygame.tests.font_test.FontModuleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/calebhattingh/temp/pygamewheel/env/lib/python3.5/site-packages/pygame/tests/font_test.py", line 94, in test_get_fonts
    self.failUnless(name.islower(), name)
AssertionError: False is not true :

----------------------------------------------------------------------
Ran 677 tests in 24.531s

FAILED (failures=2)

Ok, I figured out why that font test is failing. One of the fonts on my system has a missing family field (GeezaPro.ttc). In pygame/sysfont.py, the output of /usr/bin/fc-list is parsed and when this font is processed, the family field is blank:

def initsysfonts_unix(path="fc-list"):
    """use the fc-list from fontconfig to get a list of fonts"""
    fonts = {}

    try:
        # note, we capture stderr so if fc-list isn't there to stop stderr
        # printing.
        flout, flerr = subprocess.Popen('%s : file family style' % path, shell=True,
                                        stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                        close_fds=True).communicate()
    except Exception:
        return fonts

   entries = toascii(flout)
    try:
        for line in entries.split('\n'):   # <--- line = '/System/Library/Fonts/GeezaPro.ttc: :style=Regular,,Ordinr,Normal,Normaali,Regolare,,,Regulier,,,'

            try:
                filename, family, style = line.split(':', 2)  # <--- filename = ''/System/Library/Fonts/GeezaPro.ttc', family = '', style = 'style=Regular,,Ordinr,Normal,Normaali,Regolare,,,Regulier,,,'
                if splitext(filename)[1].lower() in OpenType_extensions:
                    bold = 'Bold' in style
                    italic = 'Italic' in style
                    oblique = 'Oblique' in style
                    for name in family.split(','):
                        if name:
                            break
                    else:
                        name = splitext(basename(filename))[0]

                    _addfont(
                        _simplename(name), bold, italic or oblique, filename, fonts)

            except Exception:
                # try the next one.
                pass

    except Exception:
        pass

    return fonts

The family becomes the key in the Sysfonts dict. In font_tests.py, function test_get_fonts() calls pygame_font.get_fonts(), which creates a list out of the Sysfonts keys, one of which is now an empty string. As a result, self.failUnless(name.islower(), name) fails.

So basically, when building the Sysfonts dict, fonts with missing families should maybe be filtered out? Or given a generic name? I've no idea what the recommended behaviour for pygame might be.

Comments (6)

  1. Thomas Kluyver reporter

    It looks like fonts without a family name should get a name from the filename (i.e. GeezaPro in this case). Could it actually be getting the family name as ' ' (i.e. a space), instead of an empty string?

  2. Caleb Hattingh

    Yes, that's correct, sorry for the confusion:

    >>> s = '/System/Library/Fonts/GeezaPro.ttc: :style=Regular,,Ordinr,Normal,Normaali,Regolare,,,Regulier,,,'
    >>> filename, family, style = s.split(':', 2)
    >>> filename, family, style
    ('/System/Library/Fonts/GeezaPro.ttc', ' ', 'style=Regular,,Ordinr,Normal,Normaali,Regolare,,,Regulier,,,')
    
  3. Log in to comment