Date: Friday, January 3, 2020 @ 11:59:11 Author: heftig Revision: 372504
0.200-1 Added: cantarell-fonts/trunk/PKGBUILD.prebuilt cantarell-fonts/trunk/cattrs.diff Modified: cantarell-fonts/trunk/PKGBUILD -------------------+ PKGBUILD | 16 +- PKGBUILD.prebuilt | 25 +++ cattrs.diff | 415 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 450 insertions(+), 6 deletions(-) Modified: PKGBUILD =================================================================== --- PKGBUILD 2020-01-03 10:00:53 UTC (rev 372503) +++ PKGBUILD 2020-01-03 11:59:11 UTC (rev 372504) @@ -1,7 +1,7 @@ # Maintainer: Jan Alexander Steffens (heftig) <jan.steff...@gmail.com> pkgname=cantarell-fonts -pkgver=0.111 +pkgver=0.200 pkgrel=1 epoch=1 pkgdesc="Humanist sans serif font" @@ -9,9 +9,11 @@ arch=(any) license=(custom:SIL) makedepends=(meson appstream-glib git) -_commit=9c0eb3dc8c0b2e0d5b9e4dfcd48ca1b9531baaa9 # tags/v0.111^0 -source=("git+https://gitlab.gnome.org/GNOME/cantarell-fonts.git#commit=$_commit") -sha256sums=('SKIP') +_commit=b4f71a432aec52c250c2b7af4692376659cb085c # tags/v0.200^0 +source=("git+https://gitlab.gnome.org/GNOME/cantarell-fonts.git#commit=$_commit" + cattrs.diff) +sha256sums=('SKIP' + 'e6e8cce13fbce7e6923425b6a5de81dd50eadf7ea4b7d6d096cb91648535b214') pkgver() { cd $pkgname @@ -20,8 +22,10 @@ prepare() { python -m venv venv - venv/bin/pip install fontmake psautohint - cd $pkgname + venv/bin/pip install -r $pkgname/requirements.txt + + # https://github.com/Tinche/cattrs/compare/v0.9.0..v1.0.0 + patch -d venv/lib/python3.8/site-packages -Np2 < cattrs.diff } build() { Added: PKGBUILD.prebuilt =================================================================== --- PKGBUILD.prebuilt (rev 0) +++ PKGBUILD.prebuilt 2020-01-03 11:59:11 UTC (rev 372504) @@ -0,0 +1,25 @@ +# Maintainer: Jan Alexander Steffens (heftig) <jan.steff...@gmail.com> + +pkgname=cantarell-fonts +pkgver=0.200 +pkgrel=1 +epoch=1 +pkgdesc="Humanist sans serif font" +url="https://gitlab.gnome.org/GNOME/cantarell-fonts" +arch=(any) +license=(custom:SIL) +makedepends=(meson appstream-glib git) +source=("https://download.gnome.org/sources/$pkgname/$pkgver/$pkgname-$pkgver.tar.xz") +sha256sums=('a30131f7ab9d78e70415a7f601cbcc443ff5bcc44b0332ddc84d8624ba177661') + +build() { + arch-meson $pkgname-$pkgver build -D useprebuilt=true + ninja -C build +} + +package() { + DESTDIR="$pkgdir" meson install -C build + install -Dt "$pkgdir/usr/share/licenses/$pkgname" -m644 $pkgname-$pkgver/COPYING +} + +# vim:set ts=2 sw=2 et: Added: cattrs.diff =================================================================== --- cattrs.diff (rev 0) +++ cattrs.diff 2020-01-03 11:59:11 UTC (rev 372504) @@ -0,0 +1,415 @@ +diff --git a/src/cattr/_compat.py b/src/cattr/_compat.py +index 73d81d5..7cd4c54 100644 +--- a/src/cattr/_compat.py ++++ b/src/cattr/_compat.py +@@ -13,20 +13,21 @@ version_info = sys.version_info[0:3] + is_py2 = version_info[0] == 2 + is_py3 = version_info[0] == 3 + is_py37 = version_info[:2] == (3, 7) ++is_py38 = version_info[:2] == (3, 8) + + if is_py2: + from functools32 import lru_cache + from singledispatch import singledispatch + + unicode = unicode # noqa + bytes = str + else: + from functools import lru_cache, singledispatch # noqa + + unicode = str + bytes = bytes + +-if is_py37: ++if is_py37 or is_py38: + from typing import List, Union, _GenericAlias + + def is_union_type(obj): +@@ -96,7 +97,11 @@ else: + return issubclass(type, MutableSet) + + def is_sequence(type): +- return issubclass(type, Sequence) ++ if is_py2: ++ is_string = issubclass(type, basestring) # noqa:F821 ++ else: ++ is_string = issubclass(type, str) ++ return issubclass(type, Sequence) and not is_string + + def is_tuple(type): + return issubclass(type, Tuple) +diff --git a/src/cattr/converters.py b/src/cattr/converters.py +index 57b9f4d..24b039c 100644 +--- a/src/cattr/converters.py ++++ b/src/cattr/converters.py +@@ -1,5 +1,17 @@ + from enum import Enum +-from typing import Mapping, Sequence, Optional, TypeVar, Any ++from typing import ( # noqa: F401, imported for Mypy. ++ Any, ++ Callable, ++ Dict, ++ FrozenSet, ++ Mapping, ++ Optional, ++ Sequence, ++ Set, ++ Tuple, ++ Type, ++ TypeVar, ++) + from ._compat import ( + bytes, + is_bare, +@@ -79,6 +91,8 @@ class Converter(object): + [ + (_subclass(Mapping), self._unstructure_mapping), + (_subclass(Sequence), self._unstructure_seq), ++ (_subclass(Set), self._unstructure_seq), ++ (_subclass(FrozenSet), self._unstructure_seq), + (_subclass(Enum), self._unstructure_enum), + (_is_attrs_class, self._unstructure_attrs), + ] +@@ -121,95 +135,96 @@ class Converter(object): + self._union_registry = {} + + def unstructure(self, obj): ++ # type: (Any) -> Any + return self._unstructure_func.dispatch(obj.__class__)(obj) + + @property + def unstruct_strat(self): + # type: () -> UnstructureStrategy + """The default way of unstructuring ``attrs`` classes.""" + return ( + UnstructureStrategy.AS_DICT + if self._unstructure_attrs == self.unstructure_attrs_asdict + else UnstructureStrategy.AS_TUPLE + ) + + def register_unstructure_hook(self, cls, func): + # type: (Type[T], Callable[[T], Any]) -> None + """Register a class-to-primitive converter function for a class. + + The converter function should take an instance of the class and return + its Python equivalent. + """ + self._unstructure_func.register_cls_list([(cls, func)]) + + def register_unstructure_hook_func(self, check_func, func): + """Register a class-to-primitive converter function for a class, using + a function to check if it's a match. + """ +- # type: (Callable[Any], Callable[T], Any]) -> None + self._unstructure_func.register_func_list([(check_func, func)]) + + def register_structure_hook(self, cl, func): + """Register a primitive-to-class converter function for a type. + + The converter function should take two arguments: + * a Python object to be converted, + * the type to convert to + + and return the instance of the class. The type may seem redundant, but + is sometimes needed (for example, when dealing with generic classes). + """ +- # type: (Type[T], Callable[[Any, Type], T) -> None + if is_union_type(cl): + self._union_registry[cl] = func + else: + self._structure_func.register_cls_list([(cl, func)]) + + def register_structure_hook_func(self, check_func, func): +- # type: (Callable[Any], Callable[T], Any]) -> None ++ # type: (Callable[[Any], Any], Callable[[T], Any]) -> None + """Register a class-to-primitive converter function for a class, using + a function to check if it's a match. + """ + self._structure_func.register_func_list([(check_func, func)]) + + def structure(self, obj, cl): ++ # type: (Any, Type[T]) -> T + """Convert unstructured Python data structures to structured data.""" +- # type: (Any, Type) -> Any ++ + return self._structure_func.dispatch(cl)(obj, cl) + + # Classes to Python primitives. + def unstructure_attrs_asdict(self, obj): ++ # type: (Any) -> Dict[str, Any] + """Our version of `attrs.asdict`, so we can call back to us.""" + attrs = obj.__class__.__attrs_attrs__ + dispatch = self._unstructure_func.dispatch + rv = self._dict_factory() + for a in attrs: + name = a.name + v = getattr(obj, name) + rv[name] = dispatch(v.__class__)(v) + return rv + + def unstructure_attrs_astuple(self, obj): ++ # type: (Any) -> Tuple + """Our version of `attrs.astuple`, so we can call back to us.""" + attrs = obj.__class__.__attrs_attrs__ + return tuple(self.unstructure(getattr(obj, a.name)) for a in attrs) + + def _unstructure_enum(self, obj): + """Convert an enum to its value.""" + return obj.value + + def _unstructure_identity(self, obj): + """Just pass it through.""" + return obj + + def _unstructure_seq(self, seq): + """Convert a sequence to primitive equivalents.""" + # We can reuse the sequence class, so tuples stay tuples. + dispatch = self._unstructure_func.dispatch + return seq.__class__(dispatch(e.__class__)(e) for e in seq) + + def _unstructure_mapping(self, mapping): +- # type: (Mapping) -> Any + """Convert a mapping of attr classes to primitive equivalents.""" + + # We can reuse the mapping class, so dicts stay dicts and OrderedDicts +@@ -258,159 +273,159 @@ class Converter(object): + # Attrs classes. + + def structure_attrs_fromtuple(self, obj, cl): +- # type: (Sequence[Any], Type) -> Any ++ # type: (Tuple, Type[T]) -> T + """Load an attrs class from a sequence (tuple).""" + conv_obj = [] # A list of converter parameters. +- for a, value in zip(cl.__attrs_attrs__, obj): ++ for a, value in zip(cl.__attrs_attrs__, obj): # type: ignore + # We detect the type by the metadata. + converted = self._structure_attr_from_tuple(a, a.name, value) + conv_obj.append(converted) + +- return cl(*conv_obj) ++ return cl(*conv_obj) # type: ignore + + def _structure_attr_from_tuple(self, a, name, value): + """Handle an individual attrs attribute.""" + type_ = a.type + if type_ is None: + # No type metadata. + return value + return self._structure_func.dispatch(type_)(value, type_) + + def structure_attrs_fromdict(self, obj, cl): +- # type: (Mapping, Type) -> Any ++ # type: (Mapping[str, Any], Type[T]) -> T + """Instantiate an attrs class from a mapping (dict).""" + # For public use. +- conv_obj = obj.copy() # Dict of converted parameters. ++ conv_obj = {} # Start with a fresh dict, to ignore extra keys. + dispatch = self._structure_func.dispatch +- for a in cl.__attrs_attrs__: ++ for a in cl.__attrs_attrs__: # type: ignore + # We detect the type by metadata. + type_ = a.type +- if type_ is None: +- # No type. +- continue + name = a.name ++ + try: + val = obj[name] + except KeyError: + continue +- conv_obj[name] = dispatch(type_)(val, type_) + +- return cl(**conv_obj) ++ if name[0] == "_": ++ name = name[1:] ++ ++ conv_obj[name] = ( ++ dispatch(type_)(val, type_) if type_ is not None else val ++ ) ++ ++ return cl(**conv_obj) # type: ignore + + def _structure_list(self, obj, cl): +- # type: (Type[GenericMeta], Iterable[T]) -> List[T] + """Convert an iterable to a potentially generic list.""" + if is_bare(cl) or cl.__args__[0] is Any: + return [e for e in obj] + else: + elem_type = cl.__args__[0] + return [ + self._structure_func.dispatch(elem_type)(e, elem_type) + for e in obj + ] + + def _structure_set(self, obj, cl): +- # type: (Type[GenericMeta], Iterable[T]) -> MutableSet[T] + """Convert an iterable into a potentially generic set.""" + if is_bare(cl) or cl.__args__[0] is Any: + return set(obj) + else: + elem_type = cl.__args__[0] + return { + self._structure_func.dispatch(elem_type)(e, elem_type) + for e in obj + } + + def _structure_frozenset(self, obj, cl): +- # type: (Type[GenericMeta], Iterable[T]) -> FrozenSet[T] + """Convert an iterable into a potentially generic frozenset.""" + if is_bare(cl) or cl.__args__[0] is Any: + return frozenset(obj) + else: + elem_type = cl.__args__[0] + dispatch = self._structure_func.dispatch + return frozenset(dispatch(elem_type)(e, elem_type) for e in obj) + + def _structure_dict(self, obj, cl): +- # type: (Type[GenericMeta], Mapping[T, V]) -> Dict[T, V] + """Convert a mapping into a potentially generic dict.""" + if is_bare(cl) or cl.__args__ == (Any, Any): + return dict(obj) + else: + key_type, val_type = cl.__args__ + if key_type is Any: + val_conv = self._structure_func.dispatch(val_type) + return {k: val_conv(v, val_type) for k, v in obj.items()} + elif val_type is Any: + key_conv = self._structure_func.dispatch(key_type) + return {key_conv(k, key_type): v for k, v in obj.items()} + else: + key_conv = self._structure_func.dispatch(key_type) + val_conv = self._structure_func.dispatch(val_type) + return { + key_conv(k, key_type): val_conv(v, val_type) + for k, v in obj.items() + } + + def _structure_union(self, obj, union): +- # type: (_Union, Any): -> Any + """Deal with converting a union.""" + # Unions with NoneType in them are basically optionals. + # We check for NoneType early and handle the case of obj being None, + # so disambiguation functions don't need to handle NoneType. + union_params = union.__args__ +- if NoneType in union_params: ++ if NoneType in union_params: # type: ignore + if obj is None: + return None + if len(union_params) == 2: + # This is just a NoneType and something else. + other = ( + union_params[0] +- if union_params[1] is NoneType ++ if union_params[1] is NoneType # type: ignore + else union_params[1] + ) + # We can't actually have a Union of a Union, so this is safe. + return self._structure_func.dispatch(other)(obj, other) + + # Check the union registry first. + handler = self._union_registry.get(union) + if handler is not None: + return handler(obj, union) + + # Getting here means either this is not an optional, or it's an + # optional with more than one parameter. + # Let's support only unions of attr classes for now. + cl = self._dis_func_cache(union)(obj) + return self._structure_func.dispatch(cl)(obj, cl) + + def _structure_tuple(self, obj, tup): +- # type: (Type[Tuple], Iterable) -> Any + """Deal with converting to a tuple.""" + tup_params = tup.__args__ + has_ellipsis = tup_params and tup_params[-1] is Ellipsis + if tup_params is None or (has_ellipsis and tup_params[0] is Any): + # Just a Tuple. (No generic information.) + return tuple(obj) + if has_ellipsis: + # We're dealing with a homogenous tuple, Tuple[int, ...] + tup_type = tup_params[0] + conv = self._structure_func.dispatch(tup_type) + return tuple(conv(e, tup_type) for e in obj) + else: + # We're dealing with a heterogenous tuple. + return tuple( + self._structure_func.dispatch(t)(e, t) + for t, e in zip(tup_params, obj) + ) + + def _get_dis_func(self, union): + # type: (Type) -> Callable[..., Type] + """Fetch or try creating a disambiguation function for a union.""" + union_types = union.__args__ +- if NoneType in union_types: ++ if NoneType in union_types: # type: ignore + # We support unions of attrs classes and NoneType higher in the + # logic. +- union_types = tuple(e for e in union_types if e is not NoneType) ++ union_types = tuple( ++ e for e in union_types if e is not NoneType # type: ignore ++ ) + + if not all(hasattr(e, "__attrs_attrs__") for e in union_types): + raise ValueError( +diff --git a/src/cattr/disambiguators.py b/src/cattr/disambiguators.py +index 4daa078..765a630 100644 +--- a/src/cattr/disambiguators.py ++++ b/src/cattr/disambiguators.py +@@ -3,42 +3,48 @@ from collections import OrderedDict + from functools import reduce + from operator import or_ + +-from typing import Mapping ++from typing import ( # noqa: F401, imported for Mypy. ++ Callable, ++ Dict, ++ Mapping, ++ Optional, ++ Type, ++) + + from attr import fields + + +-def create_uniq_field_dis_func(*cls): +- # type: (*Sequence[Type]) -> Callable ++def create_uniq_field_dis_func(*classes): ++ # type: (*Type) -> Callable + """Given attr classes, generate a disambiguation function. + + The function is based on unique fields.""" +- if len(cls) < 2: ++ if len(classes) < 2: + raise ValueError("At least two classes required.") +- cls_and_attrs = [(cl, set(at.name for at in fields(cl))) for cl in cls] ++ cls_and_attrs = [(cl, set(at.name for at in fields(cl))) for cl in classes] + if len([attrs for _, attrs in cls_and_attrs if len(attrs) == 0]) > 1: + raise ValueError("At least two classes have no attributes.") + # TODO: Deal with a single class having no required attrs. + # For each class, attempt to generate a single unique required field. +- uniq_attrs_dict = OrderedDict() ++ uniq_attrs_dict = OrderedDict() # type: Dict[str, Type] + cls_and_attrs.sort(key=lambda c_a: -len(c_a[1])) + + fallback = None # If none match, try this. + + for i, (cl, cl_reqs) in enumerate(cls_and_attrs): + other_classes = cls_and_attrs[i + 1 :] + if other_classes: + other_reqs = reduce(or_, (c_a[1] for c_a in other_classes)) + uniq = cl_reqs - other_reqs + if not uniq: + m = "{} has no usable unique attributes.".format(cl) + raise ValueError(m) + uniq_attrs_dict[next(iter(uniq))] = cl + else: + fallback = cl + + def dis_func(data): +- # type: (Mapping) -> Union ++ # type: (Mapping) -> Optional[Type] + if not isinstance(data, Mapping): + raise ValueError("Only input mappings are supported.") + for k, v in uniq_attrs_dict.items():