1""" 2These are Python 3.6+-only and keyword-only APIs that call `attr.s` and 3`attr.ib` with different default values. 4""" 5 6from functools import partial 7 8from attr.exceptions import UnannotatedAttributeError 9 10from . import setters 11from ._make import NOTHING, _frozen_setattrs, attrib, attrs 12 13 14def define( 15 maybe_cls=None, 16 *, 17 these=None, 18 repr=None, 19 hash=None, 20 init=None, 21 slots=True, 22 frozen=False, 23 weakref_slot=True, 24 str=False, 25 auto_attribs=None, 26 kw_only=False, 27 cache_hash=False, 28 auto_exc=True, 29 eq=None, 30 order=False, 31 auto_detect=True, 32 getstate_setstate=None, 33 on_setattr=None, 34 field_transformer=None, 35): 36 r""" 37 The only behavioral differences are the handling of the *auto_attribs* 38 option: 39 40 :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves 41 exactly like `attr.s`. If left `None`, `attr.s` will try to guess: 42 43 1. If any attributes are annotated and no unannotated `attr.ib`\ s 44 are found, it assumes *auto_attribs=True*. 45 2. Otherwise it assumes *auto_attribs=False* and tries to collect 46 `attr.ib`\ s. 47 48 and that mutable classes (``frozen=False``) validate on ``__setattr__``. 49 50 .. versionadded:: 20.1.0 51 """ 52 53 def do_it(cls, auto_attribs): 54 return attrs( 55 maybe_cls=cls, 56 these=these, 57 repr=repr, 58 hash=hash, 59 init=init, 60 slots=slots, 61 frozen=frozen, 62 weakref_slot=weakref_slot, 63 str=str, 64 auto_attribs=auto_attribs, 65 kw_only=kw_only, 66 cache_hash=cache_hash, 67 auto_exc=auto_exc, 68 eq=eq, 69 order=order, 70 auto_detect=auto_detect, 71 collect_by_mro=True, 72 getstate_setstate=getstate_setstate, 73 on_setattr=on_setattr, 74 field_transformer=field_transformer, 75 ) 76 77 def wrap(cls): 78 """ 79 Making this a wrapper ensures this code runs during class creation. 80 81 We also ensure that frozen-ness of classes is inherited. 82 """ 83 nonlocal frozen, on_setattr 84 85 had_on_setattr = on_setattr not in (None, setters.NO_OP) 86 87 # By default, mutable classes validate on setattr. 88 if frozen is False and on_setattr is None: 89 on_setattr = setters.validate 90 91 # However, if we subclass a frozen class, we inherit the immutability 92 # and disable on_setattr. 93 for base_cls in cls.__bases__: 94 if base_cls.__setattr__ is _frozen_setattrs: 95 if had_on_setattr: 96 raise ValueError( 97 "Frozen classes can't use on_setattr " 98 "(frozen-ness was inherited)." 99 ) 100 101 on_setattr = setters.NO_OP 102 break 103 104 if auto_attribs is not None: 105 return do_it(cls, auto_attribs) 106 107 try: 108 return do_it(cls, True) 109 except UnannotatedAttributeError: 110 return do_it(cls, False) 111 112 # maybe_cls's type depends on the usage of the decorator. It's a class 113 # if it's used as `@attrs` but ``None`` if used as `@attrs()`. 114 if maybe_cls is None: 115 return wrap 116 else: 117 return wrap(maybe_cls) 118 119 120mutable = define 121frozen = partial(define, frozen=True, on_setattr=None) 122 123 124def field( 125 *, 126 default=NOTHING, 127 validator=None, 128 repr=True, 129 hash=None, 130 init=True, 131 metadata=None, 132 converter=None, 133 factory=None, 134 kw_only=False, 135 eq=None, 136 order=None, 137 on_setattr=None, 138): 139 """ 140 Identical to `attr.ib`, except keyword-only and with some arguments 141 removed. 142 143 .. versionadded:: 20.1.0 144 """ 145 return attrib( 146 default=default, 147 validator=validator, 148 repr=repr, 149 hash=hash, 150 init=init, 151 metadata=metadata, 152 converter=converter, 153 factory=factory, 154 kw_only=kw_only, 155 eq=eq, 156 order=order, 157 on_setattr=on_setattr, 158 ) 159