Browse Source

[trunk] -> [extra] 'cantarell-fonts-1:0.200-1' add

master
alium 2 years ago
parent
commit
d65febfac5
No known key found for this signature in database
GPG Key ID: 7FB6B7C6B7DAD63D
  1. 16
      cantarell-fonts/repos/extra-any/PKGBUILD
  2. 25
      cantarell-fonts/repos/extra-any/PKGBUILD.prebuilt
  3. 415
      cantarell-fonts/repos/extra-any/cattrs.diff
  4. 16
      cantarell-fonts/trunk/PKGBUILD
  5. 25
      cantarell-fonts/trunk/PKGBUILD.prebuilt
  6. 415
      cantarell-fonts/trunk/cattrs.diff

16
cantarell-fonts/repos/extra-any/PKGBUILD

@ -1,7 +1,7 @@
# Maintainer: Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
pkgname=cantarell-fonts
pkgver=0.111
pkgver=0.200
pkgrel=1
epoch=1
pkgdesc="Humanist sans serif font"
@ -9,9 +9,11 @@ url="https://gitlab.gnome.org/GNOME/cantarell-fonts"
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 @@ pkgver() {
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() {

25
cantarell-fonts/repos/extra-any/PKGBUILD.prebuilt

@ -0,0 +1,25 @@
# Maintainer: Jan Alexander Steffens (heftig) <jan.steffens@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:

415
cantarell-fonts/repos/extra-any/cattrs.diff

@ -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():

16
cantarell-fonts/trunk/PKGBUILD

@ -1,7 +1,7 @@
# Maintainer: Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
pkgname=cantarell-fonts
pkgver=0.111
pkgver=0.200
pkgrel=1
epoch=1
pkgdesc="Humanist sans serif font"
@ -9,9 +9,11 @@ url="https://gitlab.gnome.org/GNOME/cantarell-fonts"
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 @@ pkgver() {
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() {

25
cantarell-fonts/trunk/PKGBUILD.prebuilt

@ -0,0 +1,25 @@
# Maintainer: Jan Alexander Steffens (heftig) <jan.steffens@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:

415
cantarell-fonts/trunk/cattrs.diff

@ -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():
Loading…
Cancel
Save