252 lines
4.3 KiB
Python
252 lines
4.3 KiB
Python
import re
|
|
|
|
from typing import Any, Dict, List, Tuple, Union
|
|
|
|
import attr
|
|
|
|
|
|
# Typing via "type" Argument ---
|
|
|
|
|
|
@attr.s
|
|
class C:
|
|
a = attr.ib(type=int)
|
|
|
|
|
|
c = C(1)
|
|
C(a=1)
|
|
|
|
|
|
@attr.s
|
|
class D:
|
|
x = attr.ib(type=List[int])
|
|
|
|
|
|
@attr.s
|
|
class E:
|
|
y = attr.ib(type="List[int]")
|
|
|
|
|
|
@attr.s
|
|
class F:
|
|
z = attr.ib(type=Any)
|
|
|
|
|
|
# Typing via Annotations ---
|
|
|
|
|
|
@attr.s
|
|
class CC:
|
|
a: int = attr.ib()
|
|
|
|
|
|
cc = CC(1)
|
|
CC(a=1)
|
|
|
|
|
|
@attr.s
|
|
class DD:
|
|
x: List[int] = attr.ib()
|
|
|
|
|
|
@attr.s
|
|
class EE:
|
|
y: "List[int]" = attr.ib()
|
|
|
|
|
|
@attr.s
|
|
class FF:
|
|
z: Any = attr.ib()
|
|
|
|
|
|
# Inheritance --
|
|
|
|
|
|
@attr.s
|
|
class GG(DD):
|
|
y: str = attr.ib()
|
|
|
|
|
|
GG(x=[1], y="foo")
|
|
|
|
|
|
@attr.s
|
|
class HH(DD, EE):
|
|
z: float = attr.ib()
|
|
|
|
|
|
HH(x=[1], y=[], z=1.1)
|
|
|
|
|
|
# same class
|
|
c == cc
|
|
|
|
|
|
# Exceptions
|
|
@attr.s(auto_exc=True)
|
|
class Error(Exception):
|
|
x: int = attr.ib()
|
|
|
|
|
|
try:
|
|
raise Error(1)
|
|
except Error as e:
|
|
e.x
|
|
e.args
|
|
str(e)
|
|
|
|
|
|
# Converters
|
|
# XXX: Currently converters can only be functions so none of this works
|
|
# although the stubs should be correct.
|
|
|
|
# @attr.s
|
|
# class ConvCOptional:
|
|
# x: Optional[int] = attr.ib(converter=attr.converters.optional(int))
|
|
|
|
|
|
# ConvCOptional(1)
|
|
# ConvCOptional(None)
|
|
|
|
|
|
# @attr.s
|
|
# class ConvCDefaultIfNone:
|
|
# x: int = attr.ib(converter=attr.converters.default_if_none(42))
|
|
|
|
|
|
# ConvCDefaultIfNone(1)
|
|
# ConvCDefaultIfNone(None)
|
|
|
|
|
|
# Validators
|
|
@attr.s
|
|
class Validated:
|
|
a = attr.ib(
|
|
type=List[C],
|
|
validator=attr.validators.deep_iterable(
|
|
attr.validators.instance_of(C), attr.validators.instance_of(list)
|
|
),
|
|
)
|
|
a = attr.ib(
|
|
type=Tuple[C],
|
|
validator=attr.validators.deep_iterable(
|
|
attr.validators.instance_of(C), attr.validators.instance_of(tuple)
|
|
),
|
|
)
|
|
b = attr.ib(
|
|
type=List[C],
|
|
validator=attr.validators.deep_iterable(
|
|
attr.validators.instance_of(C)
|
|
),
|
|
)
|
|
c = attr.ib(
|
|
type=Dict[C, D],
|
|
validator=attr.validators.deep_mapping(
|
|
attr.validators.instance_of(C),
|
|
attr.validators.instance_of(D),
|
|
attr.validators.instance_of(dict),
|
|
),
|
|
)
|
|
d = attr.ib(
|
|
type=Dict[C, D],
|
|
validator=attr.validators.deep_mapping(
|
|
attr.validators.instance_of(C), attr.validators.instance_of(D)
|
|
),
|
|
)
|
|
e: str = attr.ib(validator=attr.validators.matches_re(r"foo"))
|
|
f: str = attr.ib(
|
|
validator=attr.validators.matches_re(r"foo", flags=42, func=re.search)
|
|
)
|
|
|
|
# Test different forms of instance_of
|
|
g: int = attr.ib(validator=attr.validators.instance_of(int))
|
|
h: int = attr.ib(validator=attr.validators.instance_of((int,)))
|
|
j: Union[int, str] = attr.ib(
|
|
validator=attr.validators.instance_of((int, str))
|
|
)
|
|
k: Union[int, str, C] = attr.ib(
|
|
validator=attr.validators.instance_of((int, C, str))
|
|
)
|
|
|
|
|
|
# Custom repr()
|
|
@attr.s
|
|
class WithCustomRepr:
|
|
a: int = attr.ib(repr=True)
|
|
b: str = attr.ib(repr=False)
|
|
c: str = attr.ib(repr=lambda value: "c is for cookie")
|
|
d: bool = attr.ib(repr=str)
|
|
|
|
|
|
# Check some of our own types
|
|
@attr.s(eq=True, order=False)
|
|
class OrderFlags:
|
|
a: int = attr.ib(eq=False, order=False)
|
|
b: int = attr.ib(eq=True, order=True)
|
|
|
|
|
|
# on_setattr hooks
|
|
@attr.s(on_setattr=attr.setters.validate)
|
|
class ValidatedSetter:
|
|
a: int
|
|
b: str = attr.ib(on_setattr=attr.setters.NO_OP)
|
|
c: bool = attr.ib(on_setattr=attr.setters.frozen)
|
|
d: int = attr.ib(on_setattr=[attr.setters.convert, attr.setters.validate])
|
|
e: bool = attr.ib(
|
|
on_setattr=attr.setters.pipe(
|
|
attr.setters.convert, attr.setters.validate
|
|
)
|
|
)
|
|
|
|
|
|
# field_transformer
|
|
def ft_hook(cls: type, attribs: List[attr.Attribute]) -> List[attr.Attribute]:
|
|
return attribs
|
|
|
|
|
|
@attr.s(field_transformer=ft_hook)
|
|
class TransformedAttrs:
|
|
x: int
|
|
|
|
|
|
# Auto-detect
|
|
# XXX: needs support in mypy
|
|
# @attr.s(auto_detect=True)
|
|
# class AutoDetect:
|
|
# x: int
|
|
|
|
# def __init__(self, x: int):
|
|
# self.x = x
|
|
|
|
# Provisional APIs
|
|
@attr.define(order=True)
|
|
class NGClass:
|
|
x: int = attr.field(default=42)
|
|
|
|
|
|
# XXX: needs support in mypy
|
|
# ngc = NGClass(1)
|
|
|
|
|
|
@attr.mutable(slots=False)
|
|
class NGClass2:
|
|
x: int
|
|
|
|
|
|
# XXX: needs support in mypy
|
|
# ngc2 = NGClass2(1)
|
|
|
|
|
|
@attr.frozen(str=True)
|
|
class NGFrozen:
|
|
x: int
|
|
|
|
|
|
# XXX: needs support in mypy
|
|
# ngf = NGFrozen(1)
|
|
|
|
|
|
@attr.s(collect_by_mro=True)
|
|
class MRO:
|
|
pass
|