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