Skip to content

Commit

Permalink
Merge pull request #14 from kyamagu/add-object-set-iterator
Browse files Browse the repository at this point in the history
Add indexing operators to ObjectSet and FontSet
  • Loading branch information
kyamagu committed Sep 4, 2023
2 parents 9fabdff + c8fff46 commit c3abba9
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 10 deletions.
49 changes: 43 additions & 6 deletions src/fontconfig/fontconfig.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import atexit
import logging
from typing import Any, Dict, Iterable, Iterator, List, Tuple

from cython.cimports.libc.stdlib import free
cimport fontconfig._fontconfig as c_impl


Expand Down Expand Up @@ -239,10 +238,9 @@ cdef class Config:
def font_sort(self, p: Pattern, trim: bool) -> Optional[FontSet]:
"""Return list of matching fonts"""
cdef c_impl.FcResult result
cdef c_impl.FcCharSet* csp = NULL
cdef c_impl.FcFontSet* ptr = c_impl.FcFontSort(
self._ptr, p._ptr, <c_impl.FcBool>trim, &csp, &result)
# TODO: Return csp
self._ptr, p._ptr, <c_impl.FcBool>trim, NULL, &result)
# TODO: Support csp
if result == c_impl.FcResultMatch:
return FontSet(<intptr_t>ptr)
elif result == c_impl.FcResultNoMatch:
Expand Down Expand Up @@ -513,9 +511,12 @@ cdef class Pattern:
if result is NULL:
raise ValueError("Invalid format: %s" % fmt)
py_str = <bytes>(result).decode("utf-8")
free(result)
c_impl.FcStrFree(result)
return py_str

def __repr__(self) -> str:
return dict(self).__repr__()


cdef void _ObjectToFcValue(object value, c_impl.FcValue* fc_value):
assert fc_value is not NULL
Expand Down Expand Up @@ -676,14 +677,37 @@ cdef class ObjectSet:

def add(self, value: str) -> bool:
"""Add to an object set"""
return c_impl.FcObjectSetAdd(self._ptr, value.encode("utf-8"))
cdef bytes value_ = value.encode("utf-8")
cdef c_impl.FcObjectType* object_type = c_impl.FcNameGetObjectType(value_)
if object_type is NULL:
raise KeyError("Invalid value: %s" % value)
elif object_type.type == c_impl.FcTypeUnknown:
raise KeyError("Unknown value: %s" % value)
return <bint>c_impl.FcObjectSetAdd(self._ptr, value_)

def build(self, values: Iterable[str]) -> None:
"""Build object set from iterable"""
for value in values:
if not self.add(value):
raise MemoryError()

def __iter__(self) -> Iterator[str]:
for i in range(self._ptr.nobject):
yield <bytes>(self._ptr.objects[i]).decode("utf-8")

def __repr__(self) -> str:
return list(self).__repr__()

def __len__(self) -> int:
return self._ptr.nobject

def __getitem__(self, index: int) -> str:
if index >= self._ptr.nobject or index <= -self._ptr.nobject:
raise IndexError("Invalid index: %d" % index)
if index < 0:
index += self._ptr.nobject
return <bytes>(self._ptr.objects[index]).decode("utf-8")


cdef class FontSet:
"""A FontSet simply holds a list of patterns; these are used to return
Expand Down Expand Up @@ -723,6 +747,19 @@ cdef class FontSet:
for i in range(self._ptr.nfont):
yield Pattern(<intptr_t>(self._ptr.fonts[i]), owner=False)

def __repr__(self) -> str:
return list(self).__repr__()

def __len__(self) -> int:
return self._ptr.nfont

def __getitem__(self, index: int) -> Pattern:
if index >= self._ptr.nfont or index <= -self._ptr.nfont:
raise IndexError("Invalid index: %d" % index)
if index < 0:
index += self._ptr.nfont
return Pattern(<intptr_t>self._ptr.fonts[index], owner=False)


def query(where: str = "", select: Iterable[str] = ("family",)) -> List[Dict[str, Any]]:
"""
Expand Down
31 changes: 27 additions & 4 deletions tests/test_fontconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,6 @@ def test_Pattern_remove() -> None:
assert isinstance(pattern.remove("aspect", 0), bool)


def test_Pattern_iter(pattern: fontconfig.Pattern) -> None:
dict(pattern)


def test_Pattern_unparse(pattern: fontconfig.Pattern) -> None:
assert isinstance(pattern.unparse(), str)

Expand All @@ -263,13 +259,40 @@ def test_Pattern_default_format(pattern: fontconfig.Pattern) -> None:
assert isinstance(pattern.format("%{lang}"), str)


def test_Pattern_iter(pattern: fontconfig.Pattern) -> None:
dict(pattern)


def test_Pattern_repr(pattern) -> None:
repr(pattern)


@pytest.fixture
def object_set():
object_set = fontconfig.ObjectSet.create()
object_set.build(["family", "style", "slant", "weight", "size", "aspect", "lang"])
yield object_set


def test_ObjectSet_add(object_set) -> None:
assert isinstance(object_set.add("familylang"), bool)


def test_ObjectSet_iter(object_set) -> None:
for item in object_set:
assert isinstance(item, str)


def test_ObjectSet_getitem(object_set) -> None:
for i in range(len(object_set)):
assert isinstance(object_set[i], str)
assert isinstance(object_set[-1], str)


def test_ObjectSet_repr(object_set) -> None:
repr(object_set)


def test_query() -> None:
result = fontconfig.query(
where=":lang=en:family=Arial",
Expand Down

0 comments on commit c3abba9

Please sign in to comment.