From 81b0876ee447fa9fbdd6d555616b4a1dd7412b41 Mon Sep 17 00:00:00 2001 From: Yoan Tournade Date: Sat, 30 Jun 2018 23:58:47 +0200 Subject: [PATCH 1/6] Fix pip install closes #3 Thanks to @rr- --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 7dbace8..2a1a743 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,14 @@ import os from setuptools import setup -description="Python cffi bridge to fontconfig's FcFontList/FcFontMatch", +description="Python cffi bridge to fontconfig's FcFontList/FcFontMatch" if os.path.exists('README.md'): long_description = open('README.md').read() else: long_description = description setup(name='fclist', - version='1.1.1', + version='1.1.2', description=description, long_description=long_description, url='http://github.com/tarruda/python-fclist', From dcc5b38eb7c3528f18077a353cee454e2c5698df Mon Sep 17 00:00:00 2001 From: Yoan Tournade Date: Sat, 30 Jun 2018 23:59:28 +0200 Subject: [PATCH 2/6] Add tests Add .travis.yml for CI --- .editorconfig | 17 +++++++++++++++++ .gitignore | 5 +++++ .travis.yml | 12 ++++++++++++ Makefile | 14 ++++++++++++++ Pipfile | 13 +++++++++++++ fclist.py | 4 ++++ tests/fclist_test.py | 20 ++++++++++++++++++++ 7 files changed, 85 insertions(+) create mode 100644 .editorconfig create mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 Pipfile create mode 100644 tests/fclist_test.py diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8cd9a75 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 4 + +[Makefile] +indent_style = tab + +[*.yml] +indent_size = 2 diff --git a/.gitignore b/.gitignore index 3feb78a..172df1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ *.egg-info/ +Pipfile.lock +.pytest_cache +build +dist +.vscode diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d8a2500 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: python +python: + - '2.6' + - '2.7' + - '3.5' + - '3.6' +install: + - pip install pipenv + - make install-dev + - make install-package-in-venv +script: + - make test diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8eb9dba --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +install: + pipenv install + +install-dev: + pipenv install --dev + +test: + pipenv run pytest -vv + +install-package-in-venv: + pipenv uninstall fclist + pipenv run python setup.py install + +test-package-in-venv: install-package-in-venv test diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..0fa02f1 --- /dev/null +++ b/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +cffi = "*" + +[dev-packages] +pytest = "*" + +[requires] +python_version = "3" diff --git a/fclist.py b/fclist.py index eaae988..a75bcfc 100644 --- a/fclist.py +++ b/fclist.py @@ -199,3 +199,7 @@ def fcmatch(pat_str): for key, (ffi_key, extract,) in keys.items(): extract(font, key, ffi_key, data, ptrs[extract]) return Font(data) + +if __name__ == "__main__": + for font in fclist(): + print(font.family, font.style, font.file) diff --git a/tests/fclist_test.py b/tests/fclist_test.py new file mode 100644 index 0000000..278cb39 --- /dev/null +++ b/tests/fclist_test.py @@ -0,0 +1,20 @@ +import types +from fclist import fclist, Font + +def test_list_fonts(): + """ + The fclist() function list system fonts. + """ + fonts = fclist() + assert isinstance(fonts, types.GeneratorType) is True + nb_fonts = 1 + for font in fonts: + nb_fonts += 1 + assert isinstance(font, Font) is True + assert 'family' in dir(font) + assert 'fullname' in dir(font) + assert 'style' in dir(font) + assert 'file' in dir(font) + assert 'fontformat' in dir(font) + assert 'foundry' in dir(font) + assert nb_fonts > 2 From 9ce346d184f38b3b4780d6df50847897c32ed281 Mon Sep 17 00:00:00 2001 From: Kyle Falconer Date: Sat, 23 Mar 2019 14:13:59 -0700 Subject: [PATCH 3/6] Fix for #1, Attribute error on fonts without styles --- .gitignore | 2 ++ README.md | 12 +++++++++--- fclist.py | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 172df1d..647e9c4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ Pipfile.lock build dist .vscode +.idea/ +*__pycache__/ diff --git a/README.md b/README.md index 146ec33..158aa6e 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -###Python cffi bridge to fontconfig's FcFontList/FcFontMatch +### Python cffi bridge to fontconfig's FcFontList/FcFontMatch Useful for python programs that need to query information about fonts installed in the system(use this instead of parsing fc-list output). Requires the -fontconfig shared library installed in a directory that the cffi module can +fontconfig shared library installed in a directory that the [cffi module] can find. -###Usage +### Usage ```python from fclist import fclist, fcmatch @@ -24,3 +24,9 @@ fontconfig.h. `fcmatch` receives the same pattern that is normally passed to `fc-match`, but it doesn't support the --all/--sort options(only returns a single font object). + +### Tests +Tests are written to use [pytest]. + +[cffi module]: https://cffi.readthedocs.io/en/latest/ +[pytest]: https://docs.pytest.org diff --git a/fclist.py b/fclist.py index a75bcfc..c3adeb2 100644 --- a/fclist.py +++ b/fclist.py @@ -146,7 +146,8 @@ def __init__(self, data): if isinstance(value, bytes): value = value.decode() setattr(self, key, value) - self.style = set(self.style.split()) + if self.style is not None: + self.style = set(self.style.split()) def __repr__(self): return 'family: {family}, style: {style}'.format(**self.__dict__) From 7c2aac723cf8487ed63f810ace4ba3b65b443a44 Mon Sep 17 00:00:00 2001 From: Yoan Tournade Date: Mon, 1 Jun 2020 08:16:19 +0200 Subject: [PATCH 4/6] Format with black --- Makefile | 3 + Pipfile | 1 + fclist.py | 138 ++++++++++++++++++++++++------------------- tests/fclist_test.py | 13 ++-- 4 files changed, 88 insertions(+), 67 deletions(-) diff --git a/Makefile b/Makefile index 8eb9dba..ab61f23 100644 --- a/Makefile +++ b/Makefile @@ -12,3 +12,6 @@ install-package-in-venv: pipenv run python setup.py install test-package-in-venv: install-package-in-venv test + +format: + pipenv run black . diff --git a/Pipfile b/Pipfile index 0fa02f1..1457d8f 100644 --- a/Pipfile +++ b/Pipfile @@ -8,6 +8,7 @@ cffi = "*" [dev-packages] pytest = "*" +black = "*" [requires] python_version = "3" diff --git a/fclist.py b/fclist.py index c3adeb2..6c80216 100644 --- a/fclist.py +++ b/fclist.py @@ -2,10 +2,13 @@ import cffi -__all__ = ('fclist', 'fcmatch',) +__all__ = ( + "fclist", + "fcmatch", +) -API = ''' +API = """ typedef enum { FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId, FcResultOutOfMemory @@ -42,30 +45,30 @@ void FcObjectSetDestroy(void *os); void FcFontSetDestroy(void *fs); void free(void *ptr); -''' +""" ffi = cffi.FFI() ffi.cdef(API) -fc = ffi.dlopen('fontconfig') +fc = ffi.dlopen("fontconfig") keys = {} def get_bool(font, key, ffi_key, data, ptr): - ptr = ffi.new('int *') + ptr = ffi.new("int *") if fc.FcPatternGetBool(font, ffi_key, 0, ptr) == fc.FcResultMatch: data[key] = bool(ptr[0]) def get_double(font, key, ffi_key, data, ptr): - ptr = ffi.new('double *') + ptr = ffi.new("double *") if fc.FcPatternGetDouble(font, ffi_key, 0, ptr) == fc.FcResultMatch: data[key] = ptr[0] def get_int(font, key, ffi_key, data, ptr): - ptr = ffi.new('int *') + ptr = ffi.new("int *") if fc.FcPatternGetInteger(font, ffi_key, 0, ptr) == fc.FcResultMatch: data[key] = ptr[0] @@ -77,62 +80,74 @@ def get_string(font, key, ffi_key, data, ptr): def build_fc_key_table(): bool_keys = [ - 'antialias', - 'hinting', - 'verticallayout', - 'autohint', - 'globaladvance', - 'outline', - 'scalable', - 'minspace', - 'embolden', - 'embeddedbitmap', - 'decorative', + "antialias", + "hinting", + "verticallayout", + "autohint", + "globaladvance", + "outline", + "scalable", + "minspace", + "embolden", + "embeddedbitmap", + "decorative", ] int_keys = [ - 'spacing', - 'hintstyle', - 'width', - 'index', - 'rgba', - 'fontversion', - 'lcdfilter', + "spacing", + "hintstyle", + "width", + "index", + "rgba", + "fontversion", + "lcdfilter", ] double_keys = [ - 'size', - 'aspect', - 'pixelsize', - 'scale', - 'dpi', + "size", + "aspect", + "pixelsize", + "scale", + "dpi", ] string_keys = [ - 'family', - 'style', - 'aspect', - 'foundry', - 'file', - 'rasterizer', - 'charset', - 'lang', - 'fullname', - 'familylang', - 'stylelang', - 'fullnamelang', - 'capability', - 'fontformat', + "family", + "style", + "aspect", + "foundry", + "file", + "rasterizer", + "charset", + "lang", + "fullname", + "familylang", + "stylelang", + "fullnamelang", + "capability", + "fontformat", ] for key in bool_keys: - keys[key] = (ffi.new('char[]', str.encode(key)), get_bool,) + keys[key] = ( + ffi.new("char[]", str.encode(key)), + get_bool, + ) for key in int_keys: - keys[key] = (ffi.new('char[]', str.encode(key)), get_int,) + keys[key] = ( + ffi.new("char[]", str.encode(key)), + get_int, + ) for key in double_keys: - keys[key] = (ffi.new('char[]', str.encode(key)), get_double,) + keys[key] = ( + ffi.new("char[]", str.encode(key)), + get_double, + ) for key in string_keys: - keys[key] = (ffi.new('char[]', str.encode(key)), get_string,) + keys[key] = ( + ffi.new("char[]", str.encode(key)), + get_string, + ) build_fc_key_table() @@ -150,7 +165,7 @@ def __init__(self, data): self.style = set(self.style.split()) def __repr__(self): - return 'family: {family}, style: {style}'.format(**self.__dict__) + return "family: {family}, style: {style}".format(**self.__dict__) def fclist(**query): @@ -162,18 +177,18 @@ def fclist(**query): the fontconfig.h header. """ config = ffi.gc(fc.FcInitLoadConfigAndFonts(), fc.FcConfigDestroy) - pat_str = ''.join([':{0}={1}'.format(k, v) for k, v in query.items()]) + pat_str = "".join([":{0}={1}".format(k, v) for k, v in query.items()]) pat = ffi.gc(fc.FcNameParse(str.encode(pat_str)), fc.FcPatternDestroy) pat_str = ffi.string(ffi.gc(fc.FcNameUnparse(pat), fc.free)) - if pat_str == '' and len(query): - raise Exception('Invalid search query') + if pat_str == "" and len(query): + raise Exception("Invalid search query") os = ffi.gc(fc.FcObjectSetBuild(*osb_args), fc.FcObjectSetDestroy) fs = ffi.gc(fc.FcFontList(config, pat, os), fc.FcFontSetDestroy) ptrs = { - get_bool: ffi.new('int *'), - get_int: ffi.new('int *'), - get_double: ffi.new('double *'), - get_string: ffi.new('char **'), + get_bool: ffi.new("int *"), + get_int: ffi.new("int *"), + get_double: ffi.new("double *"), + get_string: ffi.new("char **"), } for i in range(fs.nfont): data = {} @@ -188,19 +203,20 @@ def fcmatch(pat_str): pat = ffi.gc(fc.FcNameParse(str.encode(pat_str)), fc.FcPatternDestroy) fc.FcConfigSubstitute(config, pat, fc.FcMatchPattern) fc.FcDefaultSubstitute(pat) - res = ffi.new('FcResult *') + res = ffi.new("FcResult *") font = ffi.gc(fc.FcFontMatch(config, pat, res), fc.FcPatternDestroy) ptrs = { - get_bool: ffi.new('int *'), - get_int: ffi.new('int *'), - get_double: ffi.new('double *'), - get_string: ffi.new('char **'), + get_bool: ffi.new("int *"), + get_int: ffi.new("int *"), + get_double: ffi.new("double *"), + get_string: ffi.new("char **"), } data = {} for key, (ffi_key, extract,) in keys.items(): extract(font, key, ffi_key, data, ptrs[extract]) return Font(data) + if __name__ == "__main__": for font in fclist(): print(font.family, font.style, font.file) diff --git a/tests/fclist_test.py b/tests/fclist_test.py index 278cb39..d1db151 100644 --- a/tests/fclist_test.py +++ b/tests/fclist_test.py @@ -1,6 +1,7 @@ import types from fclist import fclist, Font + def test_list_fonts(): """ The fclist() function list system fonts. @@ -11,10 +12,10 @@ def test_list_fonts(): for font in fonts: nb_fonts += 1 assert isinstance(font, Font) is True - assert 'family' in dir(font) - assert 'fullname' in dir(font) - assert 'style' in dir(font) - assert 'file' in dir(font) - assert 'fontformat' in dir(font) - assert 'foundry' in dir(font) + assert "family" in dir(font) + assert "fullname" in dir(font) + assert "style" in dir(font) + assert "file" in dir(font) + assert "fontformat" in dir(font) + assert "foundry" in dir(font) assert nb_fonts > 2 From 1a3a73476789f0840baa67dbf6bdbd0c713ed6b9 Mon Sep 17 00:00:00 2001 From: Yoan Tournade Date: Mon, 1 Jun 2020 08:17:28 +0200 Subject: [PATCH 5/6] Prepare for pip publishing --- LICENSE | 1 + README.md | 9 +++++++++ setup.py | 32 +++++++++++++++++--------------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/LICENSE b/LICENSE index 79257a7..f4a5598 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ Copyright (c) 2014 Thiago de Arruda +Copyright (c) 2020 Yoan Tournade Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/README.md b/README.md index 158aa6e..4e66101 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,18 @@ ### Python cffi bridge to fontconfig's FcFontList/FcFontMatch +Note: this is [a plublished](https://pypi.org/project/fclist-cffi/) fork of tarruda [`python-fclist`](https://github.com/tarruda/python-fclist). + Useful for python programs that need to query information about fonts installed in the system(use this instead of parsing fc-list output). Requires the fontconfig shared library installed in a directory that the [cffi module] can find. +### Installing + +```sh +pip install fclist-cffi +``` + ### Usage ```python @@ -26,6 +34,7 @@ fontconfig.h. it doesn't support the --all/--sort options(only returns a single font object). ### Tests + Tests are written to use [pytest]. [cffi module]: https://cffi.readthedocs.io/en/latest/ diff --git a/setup.py b/setup.py index 2a1a743..eea5af2 100644 --- a/setup.py +++ b/setup.py @@ -1,21 +1,23 @@ import os from setuptools import setup -description="Python cffi bridge to fontconfig's FcFontList/FcFontMatch" -if os.path.exists('README.md'): - long_description = open('README.md').read() +description = "Python cffi bridge to fontconfig's FcFontList/FcFontMatch" +if os.path.exists("README.md"): + long_description = open("README.md").read() else: long_description = description -setup(name='fclist', - version='1.1.2', - description=description, - long_description=long_description, - url='http://github.com/tarruda/python-fclist', - download_url='https://github.com/tarruda/python-fclist/archive/1.1.1.tar.gz', - author='Thiago de Arruda', - author_email='tpadilha84@gmail.com', - license='MIT', - py_modules=['fclist'], - install_requires=['cffi'], - zip_safe=False) +setup( + name="fclist-cffi", + version="1.1.2", + description=description, + long_description=long_description, + url="https://github.com/MonsieurV/python-fclist", + download_url="https://github.com/MonsieurV/python-fclist/archive/1.1.2.tar.gz", + author="Yoan Tournade", + author_email="y@yoantournade.com", + license="MIT", + py_modules=["fclist"], + install_requires=["cffi"], + zip_safe=False, +) From 6c14f70d6c2ebfa35da73db2ac539d454f5eb8cb Mon Sep 17 00:00:00 2001 From: Yoan Tournade Date: Mon, 1 Jun 2020 08:23:11 +0200 Subject: [PATCH 6/6] Add content-type markdown + twine for publishing --- Makefile | 6 ++++++ Pipfile | 1 + README.md | 6 ++---- setup.py | 13 ++++++------- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index ab61f23..8ff71b3 100644 --- a/Makefile +++ b/Makefile @@ -15,3 +15,9 @@ test-package-in-venv: install-package-in-venv test format: pipenv run black . + +release: + pipenv run python setup.py sdist + pipenv run python setup.py bdist_wheel --universal + pipenv run twine check dist/* + pipenv run twine upload dist/* diff --git a/Pipfile b/Pipfile index 1457d8f..1f6d56e 100644 --- a/Pipfile +++ b/Pipfile @@ -9,6 +9,7 @@ cffi = "*" [dev-packages] pytest = "*" black = "*" +twine = "*" [requires] python_version = "3" diff --git a/README.md b/README.md index 4e66101..5af0990 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,8 @@ Note: this is [a plublished](https://pypi.org/project/fclist-cffi/) fork of tarruda [`python-fclist`](https://github.com/tarruda/python-fclist). -Useful for python programs that need to query information about fonts installed -in the system(use this instead of parsing fc-list output). Requires the -fontconfig shared library installed in a directory that the [cffi module] can -find. +Useful for python programs that need to query information about fonts installed in the system(use this instead of parsing fc-list output). +Requires the fontconfig shared library installed in a directory that the [cffi module] can find. ### Installing diff --git a/setup.py b/setup.py index eea5af2..4ae0971 100644 --- a/setup.py +++ b/setup.py @@ -1,17 +1,16 @@ import os from setuptools import setup -description = "Python cffi bridge to fontconfig's FcFontList/FcFontMatch" -if os.path.exists("README.md"): - long_description = open("README.md").read() -else: - long_description = description +readme_markdown = None +with open("README.md") as f: + readme_markdown = f.read() setup( name="fclist-cffi", version="1.1.2", - description=description, - long_description=long_description, + description="Python cffi bridge to fontconfig's FcFontList/FcFontMatch", + long_description=readme_markdown, + long_description_content_type="text/markdown", url="https://github.com/MonsieurV/python-fclist", download_url="https://github.com/MonsieurV/python-fclist/archive/1.1.2.tar.gz", author="Yoan Tournade",