# Buggy code
def findTTFont(fname):
    def get_family(query):
        data = os.popen('fc-match "%s"' % query, "r").read()
        for line in data.splitlines():
            line = line.strip()
            if not line:
                continue
            fname, family, _, variant = line.split('"')[:4]
            family = family.replace('"', "")
            if family:
                return family
        return None

    def get_fname(query):
        data = os.popen('fc-match -v "%s"' % query, "r").read()
        for line in data.splitlines():
            line = line.strip()
            if line.startswith("file: "):
                return line.split('"')[1]
        return None

    def get_variants(family):
        variants = [
            get_fname(family + ":style=Roman"),
            get_fname(family + ":style=Bold"),
            get_fname(family + ":style=Oblique"),
            get_fname(family + ":style=Bold Oblique"),
        ]
        if variants[2] == variants[0]:
            variants[2] = get_fname(family + ":style=Italic")
        if variants[3] == variants[0]:
            variants[3] = get_fname(family + ":style=Bold Italic")
        if variants[0].endswith(".pfb") or variants[0].endswith(".gz"):
            return None
        return variants

    if os.name != "nt":
        family = get_family(fname)
        if not family:
            log.error("Unknown font: %s", fname)
            return None
        return get_variants(family)
    else:
        # lookup required font in registry lookup, alternative approach
        # is to let loadFont() traverse windows font directory or use
        # ctypes with EnumFontFamiliesEx

        def get_nt_fname(ftname):
            import _winreg as _w

            fontkey = _w.OpenKey(
                _w.HKEY_LOCAL_MACHINE,
                "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts",
            )
            fontname = ftname + " (TrueType)"
            try:
                fname = _w.QueryValueEx(fontkey, fontname)[0]
                if os.path.isabs(fname):
                    fontkey.close()
                    return fname
                fontdir = os.environ.get("SystemRoot", "C:\\Windows")
                fontdir += "\\Fonts"
                fontkey.Close()
                return fontdir + "\\" + fname
            except WindowsError as err:
                fontkey.Close()
                return None

        family, pos = guessFont(fname)
        fontfile = get_nt_fname(fname)
        if not fontfile:
            if pos == 0:
                fontfile = get_nt_fname(family)
            elif pos == 1:
                fontfile = get_nt_fname(family + " Bold")
            elif pos == 2:
                fontfile = get_nt_fname(family + " Italic") or get_nt_fname(
                    family + " Oblique"
                )
            else:
                fontfile = get_nt_fname(family + " Bold Italic") or get_nt_fname(
                    family + " Bold Oblique"
                )

            if not fontfile:
                log.error("Unknown font: %s", fname)
                return None

        family, pos = guessFont(fname)
        variants = [
            get_nt_fname(family) or fontfile,
            get_nt_fname(family + " Bold") or fontfile,
            get_nt_fname(family + " Italic")
            or get_nt_fname(family + " Oblique")
            or fontfile,
            get_nt_fname(family + " Bold Italic")
            or get_nt_fname(family + " Bold Oblique")
            or fontfile,
        ]
        return variants


# Traceback (UnicodeDecodeError)
$ cd doc
$ rst2pdf manual.rst --custom-cover=assets/cover.tmpl -o output/pdf/manual.pdf -s assets/manual.style -b1
Traceback (most recent call last):
File "/Users/rob/.pyenv/versions/rst2pdf/bin/rst2pdf", line 11, in <module>
load_entry_point('rst2pdf', 'console_scripts', 'rst2pdf')()
File "/Users/rob/Projects/python/rst2pdf/rst2pdf/createpdf.py", line 1506, in main
strip_elements_with_classes=options.strip_elements_with_classes,
File "/Users/rob/Projects/python/rst2pdf/rst2pdf/createpdf.py", line 184, in __init__
self.loadStyles(stylesheets)
File "/Users/rob/Projects/python/rst2pdf/rst2pdf/createpdf.py", line 288, in loadStyles
def_dpi=self.def_dpi)
File "/Users/rob/Projects/python/rst2pdf/rst2pdf/styles.py", line 358, in __init__
fontList = findfonts.autoEmbed(style[key])
File "/Users/rob/Projects/python/rst2pdf/rst2pdf/findfonts.py", line 316, in autoEmbed
variants = findTTFont(fname)
File "/Users/rob/Projects/python/rst2pdf/rst2pdf/findfonts.py", line 221, in findTTFont
return get_variants(family)
File "/Users/rob/Projects/python/rst2pdf/rst2pdf/findfonts.py", line 204, in get_variants
get_fname(family + ":style=Roman"),
File "/Users/rob/Projects/python/rst2pdf/rst2pdf/findfonts.py", line 198, in get_fname
if line.startswith("file: "):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 36: ordinal not in range(128)

# Fixed code
def findTTFont(fname):
    def get_family(query):
        data = subprocess.check_output(["fc-match", query])
        if six.PY2:
            data = data.decode("UTF-8")
        for line in data.splitlines():
            line = line.strip()
            if not line:
                continue
            fname, family, _, variant = line.split('"')[:4]
            family = family.replace('"', "")
            if family:
                return family
        return None

    def get_fname(query):
        data = subprocess.check_output(["fc-match", "-v", query])
        if six.PY2:
            data = data.decode("UTF-8")
        for line in data.splitlines():
            line = line.strip()
            if line.startswith("file: "):
                return line.split('"')[1]
        return None

    def get_variants(family):
        variants = [
            get_fname(family + ":style=Roman"),
            get_fname(family + ":style=Bold"),
            get_fname(family + ":style=Oblique"),
            get_fname(family + ":style=Bold Oblique"),
        ]
        if variants[2] == variants[0]:
            variants[2] = get_fname(family + ":style=Italic")
        if variants[3] == variants[0]:
            variants[3] = get_fname(family + ":style=Bold Italic")
        if variants[0].endswith(".pfb") or variants[0].endswith(".gz"):
            return None
        return variants

    if os.name != "nt":
        family = get_family(fname)
        if not family:
            log.error("Unknown font: %s", fname)
            return None
        return get_variants(family)
    else:
        # lookup required font in registry lookup, alternative approach
        # is to let loadFont() traverse windows font directory or use
        # ctypes with EnumFontFamiliesEx

        def get_nt_fname(ftname):
            import _winreg as _w

            fontkey = _w.OpenKey(
                _w.HKEY_LOCAL_MACHINE,
                "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts",
            )
            fontname = ftname + " (TrueType)"
            try:
                fname = _w.QueryValueEx(fontkey, fontname)[0]
                if os.path.isabs(fname):
                    fontkey.close()
                    return fname
                fontdir = os.environ.get("SystemRoot", "C:\\Windows")
                fontdir += "\\Fonts"
                fontkey.Close()
                return fontdir + "\\" + fname
            except WindowsError as err:
                fontkey.Close()
                return None

        family, pos = guessFont(fname)
        fontfile = get_nt_fname(fname)
        if not fontfile:
            if pos == 0:
                fontfile = get_nt_fname(family)
            elif pos == 1:
                fontfile = get_nt_fname(family + " Bold")
            elif pos == 2:
                fontfile = get_nt_fname(family + " Italic") or get_nt_fname(
                    family + " Oblique"
                )
            else:
                fontfile = get_nt_fname(family + " Bold Italic") or get_nt_fname(
                    family + " Bold Oblique"
                )

            if not fontfile:
                log.error("Unknown font: %s", fname)
                return None

        family, pos = guessFont(fname)
        variants = [
            get_nt_fname(family) or fontfile,
            get_nt_fname(family + " Bold") or fontfile,
            get_nt_fname(family + " Italic")
            or get_nt_fname(family + " Oblique")
            or fontfile,
            get_nt_fname(family + " Bold Italic")
            or get_nt_fname(family + " Bold Oblique")
            or fontfile,
        ]
        return variants