Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/attr/_make.py: 69%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

959 statements  

1# SPDX-License-Identifier: MIT 

2 

3import contextlib 

4import copy 

5import enum 

6import functools 

7import inspect 

8import itertools 

9import linecache 

10import sys 

11import types 

12import typing 

13 

14from operator import itemgetter 

15 

16# We need to import _compat itself in addition to the _compat members to avoid 

17# having the thread-local in the globals here. 

18from . import _compat, _config, setters 

19from ._compat import ( 

20 PY310, 

21 PY_3_8_PLUS, 

22 _AnnotationExtractor, 

23 get_generic_base, 

24) 

25from .exceptions import ( 

26 DefaultAlreadySetError, 

27 FrozenInstanceError, 

28 NotAnAttrsClassError, 

29 UnannotatedAttributeError, 

30) 

31 

32 

33# This is used at least twice, so cache it here. 

34_obj_setattr = object.__setattr__ 

35_init_converter_pat = "__attr_converter_%s" 

36_init_factory_pat = "__attr_factory_%s" 

37_classvar_prefixes = ( 

38 "typing.ClassVar", 

39 "t.ClassVar", 

40 "ClassVar", 

41 "typing_extensions.ClassVar", 

42) 

43# we don't use a double-underscore prefix because that triggers 

44# name mangling when trying to create a slot for the field 

45# (when slots=True) 

46_hash_cache_field = "_attrs_cached_hash" 

47 

48_empty_metadata_singleton = types.MappingProxyType({}) 

49 

50# Unique object for unequivocal getattr() defaults. 

51_sentinel = object() 

52 

53_ng_default_on_setattr = setters.pipe(setters.convert, setters.validate) 

54 

55 

56class _Nothing(enum.Enum): 

57 """ 

58 Sentinel to indicate the lack of a value when ``None`` is ambiguous. 

59 

60 If extending attrs, you can use ``typing.Literal[NOTHING]`` to show 

61 that a value may be ``NOTHING``. 

62 

63 .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. 

64 .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant. 

65 """ 

66 

67 NOTHING = enum.auto() 

68 

69 def __repr__(self): 

70 return "NOTHING" 

71 

72 def __bool__(self): 

73 return False 

74 

75 

76NOTHING = _Nothing.NOTHING 

77""" 

78Sentinel to indicate the lack of a value when ``None`` is ambiguous. 

79""" 

80 

81 

82class _CacheHashWrapper(int): 

83 """ 

84 An integer subclass that pickles / copies as None 

85 

86 This is used for non-slots classes with ``cache_hash=True``, to avoid 

87 serializing a potentially (even likely) invalid hash value. Since ``None`` 

88 is the default value for uncalculated hashes, whenever this is copied, 

89 the copy's value for the hash should automatically reset. 

90 

91 See GH #613 for more details. 

92 """ 

93 

94 def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008 

95 return _none_constructor, _args 

96 

97 

98def attrib( 

99 default=NOTHING, 

100 validator=None, 

101 repr=True, 

102 cmp=None, 

103 hash=None, 

104 init=True, 

105 metadata=None, 

106 type=None, 

107 converter=None, 

108 factory=None, 

109 kw_only=False, 

110 eq=None, 

111 order=None, 

112 on_setattr=None, 

113 alias=None, 

114): 

115 """ 

116 Create a new attribute on a class. 

117 

118 .. warning:: 

119 

120 Does *not* do anything unless the class is also decorated with `attr.s` 

121 / `attrs.define` / and so on! 

122 

123 Please consider using `attrs.field` in new code (``attr.ib`` will *never* 

124 go away, though). 

125 

126 :param default: A value that is used if an *attrs*-generated ``__init__`` 

127 is used and no value is passed while instantiating or the attribute is 

128 excluded using ``init=False``. 

129 

130 If the value is an instance of `attrs.Factory`, its callable will be 

131 used to construct a new value (useful for mutable data types like lists 

132 or dicts). 

133 

134 If a default is not set (or set manually to `attrs.NOTHING`), a value 

135 *must* be supplied when instantiating; otherwise a `TypeError` will be 

136 raised. 

137 

138 The default can also be set using decorator notation as shown below. 

139 

140 .. seealso:: `defaults` 

141 

142 :param callable factory: Syntactic sugar for 

143 ``default=attr.Factory(factory)``. 

144 

145 :param validator: `callable` that is called by *attrs*-generated 

146 ``__init__`` methods after the instance has been initialized. They 

147 receive the initialized instance, the :func:`~attrs.Attribute`, and the 

148 passed value. 

149 

150 The return value is *not* inspected so the validator has to throw an 

151 exception itself. 

152 

153 If a `list` is passed, its items are treated as validators and must all 

154 pass. 

155 

156 Validators can be globally disabled and re-enabled using 

157 `attrs.validators.get_disabled` / `attrs.validators.set_disabled`. 

158 

159 The validator can also be set using decorator notation as shown below. 

160 

161 .. seealso:: :ref:`validators` 

162 

163 :type validator: `callable` or a `list` of `callable`\\ s. 

164 

165 :param repr: Include this attribute in the generated ``__repr__`` method. 

166 If ``True``, include the attribute; if ``False``, omit it. By default, 

167 the built-in ``repr()`` function is used. To override how the attribute 

168 value is formatted, pass a ``callable`` that takes a single value and 

169 returns a string. Note that the resulting string is used as-is, i.e. it 

170 will be used directly *instead* of calling ``repr()`` (the default). 

171 :type repr: a `bool` or a `callable` to use a custom function. 

172 

173 :param eq: If ``True`` (default), include this attribute in the generated 

174 ``__eq__`` and ``__ne__`` methods that check two instances for 

175 equality. To override how the attribute value is compared, pass a 

176 ``callable`` that takes a single value and returns the value to be 

177 compared. 

178 

179 .. seealso:: `comparison` 

180 :type eq: a `bool` or a `callable`. 

181 

182 :param order: If ``True`` (default), include this attributes in the 

183 generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To 

184 override how the attribute value is ordered, pass a ``callable`` that 

185 takes a single value and returns the value to be ordered. 

186 

187 .. seealso:: `comparison` 

188 :type order: a `bool` or a `callable`. 

189 

190 :param cmp: Setting *cmp* is equivalent to setting *eq* and *order* to the 

191 same value. Must not be mixed with *eq* or *order*. 

192 

193 .. seealso:: `comparison` 

194 :type cmp: a `bool` or a `callable`. 

195 

196 :param bool | None hash: Include this attribute in the generated 

197 ``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This 

198 is the correct behavior according the Python spec. Setting this value 

199 to anything else than ``None`` is *discouraged*. 

200 

201 .. seealso:: `hashing` 

202 :param bool init: Include this attribute in the generated ``__init__`` 

203 method. It is possible to set this to ``False`` and set a default 

204 value. In that case this attributed is unconditionally initialized 

205 with the specified default value or factory. 

206 

207 .. seealso:: `init` 

208 :param callable converter: `callable` that is called by *attrs*-generated 

209 ``__init__`` methods to convert attribute's value to the desired 

210 format. It is given the passed-in value, and the returned value will 

211 be used as the new value of the attribute. The value is converted 

212 before being passed to the validator, if any. 

213 

214 .. seealso:: :ref:`converters` 

215 :param dict | None metadata: An arbitrary mapping, to be used by 

216 third-party components. See `extending-metadata`. 

217 

218 :param type: The type of the attribute. Nowadays, the preferred method to 

219 specify the type is using a variable annotation (see :pep:`526`). This 

220 argument is provided for backward compatibility. Regardless of the 

221 approach used, the type will be stored on ``Attribute.type``. 

222 

223 Please note that *attrs* doesn't do anything with this metadata by 

224 itself. You can use it as part of your own code or for `static type 

225 checking <types>`. 

226 :param bool kw_only: Make this attribute keyword-only in the generated 

227 ``__init__`` (if ``init`` is ``False``, this parameter is ignored). 

228 :param on_setattr: Allows to overwrite the *on_setattr* setting from 

229 `attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used. 

230 Set to `attrs.setters.NO_OP` to run **no** `setattr` hooks for this 

231 attribute -- regardless of the setting in `attr.s`. 

232 :type on_setattr: `callable`, or a list of callables, or `None`, or 

233 `attrs.setters.NO_OP` 

234 :param str | None alias: Override this attribute's parameter name in the 

235 generated ``__init__`` method. If left `None`, default to ``name`` 

236 stripped of leading underscores. See `private-attributes`. 

237 

238 .. versionadded:: 15.2.0 *convert* 

239 .. versionadded:: 16.3.0 *metadata* 

240 .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. 

241 .. versionchanged:: 17.1.0 

242 *hash* is ``None`` and therefore mirrors *eq* by default. 

243 .. versionadded:: 17.3.0 *type* 

244 .. deprecated:: 17.4.0 *convert* 

245 .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated 

246 *convert* to achieve consistency with other noun-based arguments. 

247 .. versionadded:: 18.1.0 

248 ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. 

249 .. versionadded:: 18.2.0 *kw_only* 

250 .. versionchanged:: 19.2.0 *convert* keyword argument removed. 

251 .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. 

252 .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. 

253 .. versionadded:: 19.2.0 *eq* and *order* 

254 .. versionadded:: 20.1.0 *on_setattr* 

255 .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 

256 .. versionchanged:: 21.1.0 

257 *eq*, *order*, and *cmp* also accept a custom callable 

258 .. versionchanged:: 21.1.0 *cmp* undeprecated 

259 .. versionadded:: 22.2.0 *alias* 

260 """ 

261 eq, eq_key, order, order_key = _determine_attrib_eq_order( 

262 cmp, eq, order, True 

263 ) 

264 

265 if hash is not None and hash is not True and hash is not False: 

266 msg = "Invalid value for hash. Must be True, False, or None." 

267 raise TypeError(msg) 

268 

269 if factory is not None: 

270 if default is not NOTHING: 

271 msg = ( 

272 "The `default` and `factory` arguments are mutually exclusive." 

273 ) 

274 raise ValueError(msg) 

275 if not callable(factory): 

276 msg = "The `factory` argument must be a callable." 

277 raise ValueError(msg) 

278 default = Factory(factory) 

279 

280 if metadata is None: 

281 metadata = {} 

282 

283 # Apply syntactic sugar by auto-wrapping. 

284 if isinstance(on_setattr, (list, tuple)): 

285 on_setattr = setters.pipe(*on_setattr) 

286 

287 if validator and isinstance(validator, (list, tuple)): 

288 validator = and_(*validator) 

289 

290 if converter and isinstance(converter, (list, tuple)): 

291 converter = pipe(*converter) 

292 

293 return _CountingAttr( 

294 default=default, 

295 validator=validator, 

296 repr=repr, 

297 cmp=None, 

298 hash=hash, 

299 init=init, 

300 converter=converter, 

301 metadata=metadata, 

302 type=type, 

303 kw_only=kw_only, 

304 eq=eq, 

305 eq_key=eq_key, 

306 order=order, 

307 order_key=order_key, 

308 on_setattr=on_setattr, 

309 alias=alias, 

310 ) 

311 

312 

313def _compile_and_eval(script, globs, locs=None, filename=""): 

314 """ 

315 "Exec" the script with the given global (globs) and local (locs) variables. 

316 """ 

317 bytecode = compile(script, filename, "exec") 

318 eval(bytecode, globs, locs) 

319 

320 

321def _make_method(name, script, filename, globs): 

322 """ 

323 Create the method with the script given and return the method object. 

324 """ 

325 locs = {} 

326 

327 # In order of debuggers like PDB being able to step through the code, 

328 # we add a fake linecache entry. 

329 count = 1 

330 base_filename = filename 

331 while True: 

332 linecache_tuple = ( 

333 len(script), 

334 None, 

335 script.splitlines(True), 

336 filename, 

337 ) 

338 old_val = linecache.cache.setdefault(filename, linecache_tuple) 

339 if old_val == linecache_tuple: 

340 break 

341 

342 filename = f"{base_filename[:-1]}-{count}>" 

343 count += 1 

344 

345 _compile_and_eval(script, globs, locs, filename) 

346 

347 return locs[name] 

348 

349 

350def _make_attr_tuple_class(cls_name, attr_names): 

351 """ 

352 Create a tuple subclass to hold `Attribute`s for an `attrs` class. 

353 

354 The subclass is a bare tuple with properties for names. 

355 

356 class MyClassAttributes(tuple): 

357 __slots__ = () 

358 x = property(itemgetter(0)) 

359 """ 

360 attr_class_name = f"{cls_name}Attributes" 

361 attr_class_template = [ 

362 f"class {attr_class_name}(tuple):", 

363 " __slots__ = ()", 

364 ] 

365 if attr_names: 

366 for i, attr_name in enumerate(attr_names): 

367 attr_class_template.append( 

368 f" {attr_name} = _attrs_property(_attrs_itemgetter({i}))" 

369 ) 

370 else: 

371 attr_class_template.append(" pass") 

372 globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property} 

373 _compile_and_eval("\n".join(attr_class_template), globs) 

374 return globs[attr_class_name] 

375 

376 

377# Tuple class for extracted attributes from a class definition. 

378# `base_attrs` is a subset of `attrs`. 

379_Attributes = _make_attr_tuple_class( 

380 "_Attributes", 

381 [ 

382 # all attributes to build dunder methods for 

383 "attrs", 

384 # attributes that have been inherited 

385 "base_attrs", 

386 # map inherited attributes to their originating classes 

387 "base_attrs_map", 

388 ], 

389) 

390 

391 

392def _is_class_var(annot): 

393 """ 

394 Check whether *annot* is a typing.ClassVar. 

395 

396 The string comparison hack is used to avoid evaluating all string 

397 annotations which would put attrs-based classes at a performance 

398 disadvantage compared to plain old classes. 

399 """ 

400 annot = str(annot) 

401 

402 # Annotation can be quoted. 

403 if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): 

404 annot = annot[1:-1] 

405 

406 return annot.startswith(_classvar_prefixes) 

407 

408 

409def _has_own_attribute(cls, attrib_name): 

410 """ 

411 Check whether *cls* defines *attrib_name* (and doesn't just inherit it). 

412 """ 

413 attr = getattr(cls, attrib_name, _sentinel) 

414 if attr is _sentinel: 

415 return False 

416 

417 for base_cls in cls.__mro__[1:]: 

418 a = getattr(base_cls, attrib_name, None) 

419 if attr is a: 

420 return False 

421 

422 return True 

423 

424 

425def _get_annotations(cls): 

426 """ 

427 Get annotations for *cls*. 

428 """ 

429 if _has_own_attribute(cls, "__annotations__"): 

430 return cls.__annotations__ 

431 

432 return {} 

433 

434 

435def _collect_base_attrs(cls, taken_attr_names): 

436 """ 

437 Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. 

438 """ 

439 base_attrs = [] 

440 base_attr_map = {} # A dictionary of base attrs to their classes. 

441 

442 # Traverse the MRO and collect attributes. 

443 for base_cls in reversed(cls.__mro__[1:-1]): 

444 for a in getattr(base_cls, "__attrs_attrs__", []): 

445 if a.inherited or a.name in taken_attr_names: 

446 continue 

447 

448 a = a.evolve(inherited=True) # noqa: PLW2901 

449 base_attrs.append(a) 

450 base_attr_map[a.name] = base_cls 

451 

452 # For each name, only keep the freshest definition i.e. the furthest at the 

453 # back. base_attr_map is fine because it gets overwritten with every new 

454 # instance. 

455 filtered = [] 

456 seen = set() 

457 for a in reversed(base_attrs): 

458 if a.name in seen: 

459 continue 

460 filtered.insert(0, a) 

461 seen.add(a.name) 

462 

463 return filtered, base_attr_map 

464 

465 

466def _collect_base_attrs_broken(cls, taken_attr_names): 

467 """ 

468 Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. 

469 

470 N.B. *taken_attr_names* will be mutated. 

471 

472 Adhere to the old incorrect behavior. 

473 

474 Notably it collects from the front and considers inherited attributes which 

475 leads to the buggy behavior reported in #428. 

476 """ 

477 base_attrs = [] 

478 base_attr_map = {} # A dictionary of base attrs to their classes. 

479 

480 # Traverse the MRO and collect attributes. 

481 for base_cls in cls.__mro__[1:-1]: 

482 for a in getattr(base_cls, "__attrs_attrs__", []): 

483 if a.name in taken_attr_names: 

484 continue 

485 

486 a = a.evolve(inherited=True) # noqa: PLW2901 

487 taken_attr_names.add(a.name) 

488 base_attrs.append(a) 

489 base_attr_map[a.name] = base_cls 

490 

491 return base_attrs, base_attr_map 

492 

493 

494def _transform_attrs( 

495 cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer 

496): 

497 """ 

498 Transform all `_CountingAttr`s on a class into `Attribute`s. 

499 

500 If *these* is passed, use that and don't look for them on the class. 

501 

502 *collect_by_mro* is True, collect them in the correct MRO order, otherwise 

503 use the old -- incorrect -- order. See #428. 

504 

505 Return an `_Attributes`. 

506 """ 

507 cd = cls.__dict__ 

508 anns = _get_annotations(cls) 

509 

510 if these is not None: 

511 ca_list = list(these.items()) 

512 elif auto_attribs is True: 

513 ca_names = { 

514 name 

515 for name, attr in cd.items() 

516 if isinstance(attr, _CountingAttr) 

517 } 

518 ca_list = [] 

519 annot_names = set() 

520 for attr_name, type in anns.items(): 

521 if _is_class_var(type): 

522 continue 

523 annot_names.add(attr_name) 

524 a = cd.get(attr_name, NOTHING) 

525 

526 if not isinstance(a, _CountingAttr): 

527 a = attrib() if a is NOTHING else attrib(default=a) 

528 ca_list.append((attr_name, a)) 

529 

530 unannotated = ca_names - annot_names 

531 if len(unannotated) > 0: 

532 raise UnannotatedAttributeError( 

533 "The following `attr.ib`s lack a type annotation: " 

534 + ", ".join( 

535 sorted(unannotated, key=lambda n: cd.get(n).counter) 

536 ) 

537 + "." 

538 ) 

539 else: 

540 ca_list = sorted( 

541 ( 

542 (name, attr) 

543 for name, attr in cd.items() 

544 if isinstance(attr, _CountingAttr) 

545 ), 

546 key=lambda e: e[1].counter, 

547 ) 

548 

549 own_attrs = [ 

550 Attribute.from_counting_attr( 

551 name=attr_name, ca=ca, type=anns.get(attr_name) 

552 ) 

553 for attr_name, ca in ca_list 

554 ] 

555 

556 if collect_by_mro: 

557 base_attrs, base_attr_map = _collect_base_attrs( 

558 cls, {a.name for a in own_attrs} 

559 ) 

560 else: 

561 base_attrs, base_attr_map = _collect_base_attrs_broken( 

562 cls, {a.name for a in own_attrs} 

563 ) 

564 

565 if kw_only: 

566 own_attrs = [a.evolve(kw_only=True) for a in own_attrs] 

567 base_attrs = [a.evolve(kw_only=True) for a in base_attrs] 

568 

569 attrs = base_attrs + own_attrs 

570 

571 # Mandatory vs non-mandatory attr order only matters when they are part of 

572 # the __init__ signature and when they aren't kw_only (which are moved to 

573 # the end and can be mandatory or non-mandatory in any order, as they will 

574 # be specified as keyword args anyway). Check the order of those attrs: 

575 had_default = False 

576 for a in (a for a in attrs if a.init is not False and a.kw_only is False): 

577 if had_default is True and a.default is NOTHING: 

578 msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}" 

579 raise ValueError(msg) 

580 

581 if had_default is False and a.default is not NOTHING: 

582 had_default = True 

583 

584 if field_transformer is not None: 

585 attrs = field_transformer(cls, attrs) 

586 

587 # Resolve default field alias after executing field_transformer. 

588 # This allows field_transformer to differentiate between explicit vs 

589 # default aliases and supply their own defaults. 

590 attrs = [ 

591 a.evolve(alias=_default_init_alias_for(a.name)) if not a.alias else a 

592 for a in attrs 

593 ] 

594 

595 # Create AttrsClass *after* applying the field_transformer since it may 

596 # add or remove attributes! 

597 attr_names = [a.name for a in attrs] 

598 AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) 

599 

600 return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map)) 

601 

602 

603def _make_cached_property_getattr( 

604 cached_properties, 

605 original_getattr, 

606 cls, 

607): 

608 lines = [ 

609 # Wrapped to get `__class__` into closure cell for super() 

610 # (It will be replaced with the newly constructed class after construction). 

611 "def wrapper():", 

612 " __class__ = _cls", 

613 " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):", 

614 " func = cached_properties.get(item)", 

615 " if func is not None:", 

616 " result = func(self)", 

617 " _setter = _cached_setattr_get(self)", 

618 " _setter(item, result)", 

619 " return result", 

620 ] 

621 if original_getattr is not None: 

622 lines.append( 

623 " return original_getattr(self, item)", 

624 ) 

625 else: 

626 lines.extend( 

627 [ 

628 " if hasattr(super(), '__getattr__'):", 

629 " return super().__getattr__(item)", 

630 " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"", 

631 " raise AttributeError(original_error)", 

632 ] 

633 ) 

634 

635 lines.extend( 

636 [ 

637 " return __getattr__", 

638 "__getattr__ = wrapper()", 

639 ] 

640 ) 

641 

642 unique_filename = _generate_unique_filename(cls, "getattr") 

643 

644 glob = { 

645 "cached_properties": cached_properties, 

646 "_cached_setattr_get": _obj_setattr.__get__, 

647 "_cls": cls, 

648 "original_getattr": original_getattr, 

649 } 

650 

651 return _make_method( 

652 "__getattr__", 

653 "\n".join(lines), 

654 unique_filename, 

655 glob, 

656 ) 

657 

658 

659def _frozen_setattrs(self, name, value): 

660 """ 

661 Attached to frozen classes as __setattr__. 

662 """ 

663 if isinstance(self, BaseException) and name in ( 

664 "__cause__", 

665 "__context__", 

666 "__traceback__", 

667 ): 

668 BaseException.__setattr__(self, name, value) 

669 return 

670 

671 raise FrozenInstanceError() 

672 

673 

674def _frozen_delattrs(self, name): 

675 """ 

676 Attached to frozen classes as __delattr__. 

677 """ 

678 raise FrozenInstanceError() 

679 

680 

681class _ClassBuilder: 

682 """ 

683 Iteratively build *one* class. 

684 """ 

685 

686 __slots__ = ( 

687 "_attr_names", 

688 "_attrs", 

689 "_base_attr_map", 

690 "_base_names", 

691 "_cache_hash", 

692 "_cls", 

693 "_cls_dict", 

694 "_delete_attribs", 

695 "_frozen", 

696 "_has_pre_init", 

697 "_pre_init_has_args", 

698 "_has_post_init", 

699 "_is_exc", 

700 "_on_setattr", 

701 "_slots", 

702 "_weakref_slot", 

703 "_wrote_own_setattr", 

704 "_has_custom_setattr", 

705 ) 

706 

707 def __init__( 

708 self, 

709 cls, 

710 these, 

711 slots, 

712 frozen, 

713 weakref_slot, 

714 getstate_setstate, 

715 auto_attribs, 

716 kw_only, 

717 cache_hash, 

718 is_exc, 

719 collect_by_mro, 

720 on_setattr, 

721 has_custom_setattr, 

722 field_transformer, 

723 ): 

724 attrs, base_attrs, base_map = _transform_attrs( 

725 cls, 

726 these, 

727 auto_attribs, 

728 kw_only, 

729 collect_by_mro, 

730 field_transformer, 

731 ) 

732 

733 self._cls = cls 

734 self._cls_dict = dict(cls.__dict__) if slots else {} 

735 self._attrs = attrs 

736 self._base_names = {a.name for a in base_attrs} 

737 self._base_attr_map = base_map 

738 self._attr_names = tuple(a.name for a in attrs) 

739 self._slots = slots 

740 self._frozen = frozen 

741 self._weakref_slot = weakref_slot 

742 self._cache_hash = cache_hash 

743 self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) 

744 self._pre_init_has_args = False 

745 if self._has_pre_init: 

746 # Check if the pre init method has more arguments than just `self` 

747 # We want to pass arguments if pre init expects arguments 

748 pre_init_func = cls.__attrs_pre_init__ 

749 pre_init_signature = inspect.signature(pre_init_func) 

750 self._pre_init_has_args = len(pre_init_signature.parameters) > 1 

751 self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) 

752 self._delete_attribs = not bool(these) 

753 self._is_exc = is_exc 

754 self._on_setattr = on_setattr 

755 

756 self._has_custom_setattr = has_custom_setattr 

757 self._wrote_own_setattr = False 

758 

759 self._cls_dict["__attrs_attrs__"] = self._attrs 

760 

761 if frozen: 

762 self._cls_dict["__setattr__"] = _frozen_setattrs 

763 self._cls_dict["__delattr__"] = _frozen_delattrs 

764 

765 self._wrote_own_setattr = True 

766 elif on_setattr in ( 

767 _ng_default_on_setattr, 

768 setters.validate, 

769 setters.convert, 

770 ): 

771 has_validator = has_converter = False 

772 for a in attrs: 

773 if a.validator is not None: 

774 has_validator = True 

775 if a.converter is not None: 

776 has_converter = True 

777 

778 if has_validator and has_converter: 

779 break 

780 if ( 

781 ( 

782 on_setattr == _ng_default_on_setattr 

783 and not (has_validator or has_converter) 

784 ) 

785 or (on_setattr == setters.validate and not has_validator) 

786 or (on_setattr == setters.convert and not has_converter) 

787 ): 

788 # If class-level on_setattr is set to convert + validate, but 

789 # there's no field to convert or validate, pretend like there's 

790 # no on_setattr. 

791 self._on_setattr = None 

792 

793 if getstate_setstate: 

794 ( 

795 self._cls_dict["__getstate__"], 

796 self._cls_dict["__setstate__"], 

797 ) = self._make_getstate_setstate() 

798 

799 def __repr__(self): 

800 return f"<_ClassBuilder(cls={self._cls.__name__})>" 

801 

802 if PY310: 

803 import abc 

804 

805 def build_class(self): 

806 """ 

807 Finalize class based on the accumulated configuration. 

808 

809 Builder cannot be used after calling this method. 

810 """ 

811 if self._slots is True: 

812 return self._create_slots_class() 

813 

814 return self.abc.update_abstractmethods( 

815 self._patch_original_class() 

816 ) 

817 

818 else: 

819 

820 def build_class(self): 

821 """ 

822 Finalize class based on the accumulated configuration. 

823 

824 Builder cannot be used after calling this method. 

825 """ 

826 if self._slots is True: 

827 return self._create_slots_class() 

828 

829 return self._patch_original_class() 

830 

831 def _patch_original_class(self): 

832 """ 

833 Apply accumulated methods and return the class. 

834 """ 

835 cls = self._cls 

836 base_names = self._base_names 

837 

838 # Clean class of attribute definitions (`attr.ib()`s). 

839 if self._delete_attribs: 

840 for name in self._attr_names: 

841 if ( 

842 name not in base_names 

843 and getattr(cls, name, _sentinel) is not _sentinel 

844 ): 

845 # An AttributeError can happen if a base class defines a 

846 # class variable and we want to set an attribute with the 

847 # same name by using only a type annotation. 

848 with contextlib.suppress(AttributeError): 

849 delattr(cls, name) 

850 

851 # Attach our dunder methods. 

852 for name, value in self._cls_dict.items(): 

853 setattr(cls, name, value) 

854 

855 # If we've inherited an attrs __setattr__ and don't write our own, 

856 # reset it to object's. 

857 if not self._wrote_own_setattr and getattr( 

858 cls, "__attrs_own_setattr__", False 

859 ): 

860 cls.__attrs_own_setattr__ = False 

861 

862 if not self._has_custom_setattr: 

863 cls.__setattr__ = _obj_setattr 

864 

865 return cls 

866 

867 def _create_slots_class(self): 

868 """ 

869 Build and return a new class with a `__slots__` attribute. 

870 """ 

871 cd = { 

872 k: v 

873 for k, v in self._cls_dict.items() 

874 if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") 

875 } 

876 

877 # If our class doesn't have its own implementation of __setattr__ 

878 # (either from the user or by us), check the bases, if one of them has 

879 # an attrs-made __setattr__, that needs to be reset. We don't walk the 

880 # MRO because we only care about our immediate base classes. 

881 # XXX: This can be confused by subclassing a slotted attrs class with 

882 # XXX: a non-attrs class and subclass the resulting class with an attrs 

883 # XXX: class. See `test_slotted_confused` for details. For now that's 

884 # XXX: OK with us. 

885 if not self._wrote_own_setattr: 

886 cd["__attrs_own_setattr__"] = False 

887 

888 if not self._has_custom_setattr: 

889 for base_cls in self._cls.__bases__: 

890 if base_cls.__dict__.get("__attrs_own_setattr__", False): 

891 cd["__setattr__"] = _obj_setattr 

892 break 

893 

894 # Traverse the MRO to collect existing slots 

895 # and check for an existing __weakref__. 

896 existing_slots = {} 

897 weakref_inherited = False 

898 for base_cls in self._cls.__mro__[1:-1]: 

899 if base_cls.__dict__.get("__weakref__", None) is not None: 

900 weakref_inherited = True 

901 existing_slots.update( 

902 { 

903 name: getattr(base_cls, name) 

904 for name in getattr(base_cls, "__slots__", []) 

905 } 

906 ) 

907 

908 base_names = set(self._base_names) 

909 

910 names = self._attr_names 

911 if ( 

912 self._weakref_slot 

913 and "__weakref__" not in getattr(self._cls, "__slots__", ()) 

914 and "__weakref__" not in names 

915 and not weakref_inherited 

916 ): 

917 names += ("__weakref__",) 

918 

919 if PY_3_8_PLUS: 

920 cached_properties = { 

921 name: cached_property.func 

922 for name, cached_property in cd.items() 

923 if isinstance(cached_property, functools.cached_property) 

924 } 

925 else: 

926 # `functools.cached_property` was introduced in 3.8. 

927 # So can't be used before this. 

928 cached_properties = {} 

929 

930 # Collect methods with a `__class__` reference that are shadowed in the new class. 

931 # To know to update them. 

932 additional_closure_functions_to_update = [] 

933 if cached_properties: 

934 # Add cached properties to names for slotting. 

935 names += tuple(cached_properties.keys()) 

936 

937 for name in cached_properties: 

938 # Clear out function from class to avoid clashing. 

939 del cd[name] 

940 

941 class_annotations = _get_annotations(self._cls) 

942 for name, func in cached_properties.items(): 

943 annotation = inspect.signature(func).return_annotation 

944 if annotation is not inspect.Parameter.empty: 

945 class_annotations[name] = annotation 

946 

947 original_getattr = cd.get("__getattr__") 

948 if original_getattr is not None: 

949 additional_closure_functions_to_update.append(original_getattr) 

950 

951 cd["__getattr__"] = _make_cached_property_getattr( 

952 cached_properties, original_getattr, self._cls 

953 ) 

954 

955 # We only add the names of attributes that aren't inherited. 

956 # Setting __slots__ to inherited attributes wastes memory. 

957 slot_names = [name for name in names if name not in base_names] 

958 

959 # There are slots for attributes from current class 

960 # that are defined in parent classes. 

961 # As their descriptors may be overridden by a child class, 

962 # we collect them here and update the class dict 

963 reused_slots = { 

964 slot: slot_descriptor 

965 for slot, slot_descriptor in existing_slots.items() 

966 if slot in slot_names 

967 } 

968 slot_names = [name for name in slot_names if name not in reused_slots] 

969 cd.update(reused_slots) 

970 if self._cache_hash: 

971 slot_names.append(_hash_cache_field) 

972 

973 cd["__slots__"] = tuple(slot_names) 

974 

975 cd["__qualname__"] = self._cls.__qualname__ 

976 

977 # Create new class based on old class and our methods. 

978 cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) 

979 

980 # The following is a fix for 

981 # <https://github.com/python-attrs/attrs/issues/102>. 

982 # If a method mentions `__class__` or uses the no-arg super(), the 

983 # compiler will bake a reference to the class in the method itself 

984 # as `method.__closure__`. Since we replace the class with a 

985 # clone, we rewrite these references so it keeps working. 

986 for item in itertools.chain( 

987 cls.__dict__.values(), additional_closure_functions_to_update 

988 ): 

989 if isinstance(item, (classmethod, staticmethod)): 

990 # Class- and staticmethods hide their functions inside. 

991 # These might need to be rewritten as well. 

992 closure_cells = getattr(item.__func__, "__closure__", None) 

993 elif isinstance(item, property): 

994 # Workaround for property `super()` shortcut (PY3-only). 

995 # There is no universal way for other descriptors. 

996 closure_cells = getattr(item.fget, "__closure__", None) 

997 else: 

998 closure_cells = getattr(item, "__closure__", None) 

999 

1000 if not closure_cells: # Catch None or the empty list. 

1001 continue 

1002 for cell in closure_cells: 

1003 try: 

1004 match = cell.cell_contents is self._cls 

1005 except ValueError: # noqa: PERF203 

1006 # ValueError: Cell is empty 

1007 pass 

1008 else: 

1009 if match: 

1010 cell.cell_contents = cls 

1011 return cls 

1012 

1013 def add_repr(self, ns): 

1014 self._cls_dict["__repr__"] = self._add_method_dunders( 

1015 _make_repr(self._attrs, ns, self._cls) 

1016 ) 

1017 return self 

1018 

1019 def add_str(self): 

1020 repr = self._cls_dict.get("__repr__") 

1021 if repr is None: 

1022 msg = "__str__ can only be generated if a __repr__ exists." 

1023 raise ValueError(msg) 

1024 

1025 def __str__(self): 

1026 return self.__repr__() 

1027 

1028 self._cls_dict["__str__"] = self._add_method_dunders(__str__) 

1029 return self 

1030 

1031 def _make_getstate_setstate(self): 

1032 """ 

1033 Create custom __setstate__ and __getstate__ methods. 

1034 """ 

1035 # __weakref__ is not writable. 

1036 state_attr_names = tuple( 

1037 an for an in self._attr_names if an != "__weakref__" 

1038 ) 

1039 

1040 def slots_getstate(self): 

1041 """ 

1042 Automatically created by attrs. 

1043 """ 

1044 return {name: getattr(self, name) for name in state_attr_names} 

1045 

1046 hash_caching_enabled = self._cache_hash 

1047 

1048 def slots_setstate(self, state): 

1049 """ 

1050 Automatically created by attrs. 

1051 """ 

1052 __bound_setattr = _obj_setattr.__get__(self) 

1053 if isinstance(state, tuple): 

1054 # Backward compatibility with attrs instances pickled with 

1055 # attrs versions before v22.2.0 which stored tuples. 

1056 for name, value in zip(state_attr_names, state): 

1057 __bound_setattr(name, value) 

1058 else: 

1059 for name in state_attr_names: 

1060 if name in state: 

1061 __bound_setattr(name, state[name]) 

1062 

1063 # The hash code cache is not included when the object is 

1064 # serialized, but it still needs to be initialized to None to 

1065 # indicate that the first call to __hash__ should be a cache 

1066 # miss. 

1067 if hash_caching_enabled: 

1068 __bound_setattr(_hash_cache_field, None) 

1069 

1070 return slots_getstate, slots_setstate 

1071 

1072 def make_unhashable(self): 

1073 self._cls_dict["__hash__"] = None 

1074 return self 

1075 

1076 def add_hash(self): 

1077 self._cls_dict["__hash__"] = self._add_method_dunders( 

1078 _make_hash( 

1079 self._cls, 

1080 self._attrs, 

1081 frozen=self._frozen, 

1082 cache_hash=self._cache_hash, 

1083 ) 

1084 ) 

1085 

1086 return self 

1087 

1088 def add_init(self): 

1089 self._cls_dict["__init__"] = self._add_method_dunders( 

1090 _make_init( 

1091 self._cls, 

1092 self._attrs, 

1093 self._has_pre_init, 

1094 self._pre_init_has_args, 

1095 self._has_post_init, 

1096 self._frozen, 

1097 self._slots, 

1098 self._cache_hash, 

1099 self._base_attr_map, 

1100 self._is_exc, 

1101 self._on_setattr, 

1102 attrs_init=False, 

1103 ) 

1104 ) 

1105 

1106 return self 

1107 

1108 def add_match_args(self): 

1109 self._cls_dict["__match_args__"] = tuple( 

1110 field.name 

1111 for field in self._attrs 

1112 if field.init and not field.kw_only 

1113 ) 

1114 

1115 def add_attrs_init(self): 

1116 self._cls_dict["__attrs_init__"] = self._add_method_dunders( 

1117 _make_init( 

1118 self._cls, 

1119 self._attrs, 

1120 self._has_pre_init, 

1121 self._pre_init_has_args, 

1122 self._has_post_init, 

1123 self._frozen, 

1124 self._slots, 

1125 self._cache_hash, 

1126 self._base_attr_map, 

1127 self._is_exc, 

1128 self._on_setattr, 

1129 attrs_init=True, 

1130 ) 

1131 ) 

1132 

1133 return self 

1134 

1135 def add_eq(self): 

1136 cd = self._cls_dict 

1137 

1138 cd["__eq__"] = self._add_method_dunders( 

1139 _make_eq(self._cls, self._attrs) 

1140 ) 

1141 cd["__ne__"] = self._add_method_dunders(_make_ne()) 

1142 

1143 return self 

1144 

1145 def add_order(self): 

1146 cd = self._cls_dict 

1147 

1148 cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( 

1149 self._add_method_dunders(meth) 

1150 for meth in _make_order(self._cls, self._attrs) 

1151 ) 

1152 

1153 return self 

1154 

1155 def add_setattr(self): 

1156 if self._frozen: 

1157 return self 

1158 

1159 sa_attrs = {} 

1160 for a in self._attrs: 

1161 on_setattr = a.on_setattr or self._on_setattr 

1162 if on_setattr and on_setattr is not setters.NO_OP: 

1163 sa_attrs[a.name] = a, on_setattr 

1164 

1165 if not sa_attrs: 

1166 return self 

1167 

1168 if self._has_custom_setattr: 

1169 # We need to write a __setattr__ but there already is one! 

1170 msg = "Can't combine custom __setattr__ with on_setattr hooks." 

1171 raise ValueError(msg) 

1172 

1173 # docstring comes from _add_method_dunders 

1174 def __setattr__(self, name, val): 

1175 try: 

1176 a, hook = sa_attrs[name] 

1177 except KeyError: 

1178 nval = val 

1179 else: 

1180 nval = hook(self, a, val) 

1181 

1182 _obj_setattr(self, name, nval) 

1183 

1184 self._cls_dict["__attrs_own_setattr__"] = True 

1185 self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) 

1186 self._wrote_own_setattr = True 

1187 

1188 return self 

1189 

1190 def _add_method_dunders(self, method): 

1191 """ 

1192 Add __module__ and __qualname__ to a *method* if possible. 

1193 """ 

1194 with contextlib.suppress(AttributeError): 

1195 method.__module__ = self._cls.__module__ 

1196 

1197 with contextlib.suppress(AttributeError): 

1198 method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" 

1199 

1200 with contextlib.suppress(AttributeError): 

1201 method.__doc__ = ( 

1202 "Method generated by attrs for class " 

1203 f"{self._cls.__qualname__}." 

1204 ) 

1205 

1206 return method 

1207 

1208 

1209def _determine_attrs_eq_order(cmp, eq, order, default_eq): 

1210 """ 

1211 Validate the combination of *cmp*, *eq*, and *order*. Derive the effective 

1212 values of eq and order. If *eq* is None, set it to *default_eq*. 

1213 """ 

1214 if cmp is not None and any((eq is not None, order is not None)): 

1215 msg = "Don't mix `cmp` with `eq' and `order`." 

1216 raise ValueError(msg) 

1217 

1218 # cmp takes precedence due to bw-compatibility. 

1219 if cmp is not None: 

1220 return cmp, cmp 

1221 

1222 # If left None, equality is set to the specified default and ordering 

1223 # mirrors equality. 

1224 if eq is None: 

1225 eq = default_eq 

1226 

1227 if order is None: 

1228 order = eq 

1229 

1230 if eq is False and order is True: 

1231 msg = "`order` can only be True if `eq` is True too." 

1232 raise ValueError(msg) 

1233 

1234 return eq, order 

1235 

1236 

1237def _determine_attrib_eq_order(cmp, eq, order, default_eq): 

1238 """ 

1239 Validate the combination of *cmp*, *eq*, and *order*. Derive the effective 

1240 values of eq and order. If *eq* is None, set it to *default_eq*. 

1241 """ 

1242 if cmp is not None and any((eq is not None, order is not None)): 

1243 msg = "Don't mix `cmp` with `eq' and `order`." 

1244 raise ValueError(msg) 

1245 

1246 def decide_callable_or_boolean(value): 

1247 """ 

1248 Decide whether a key function is used. 

1249 """ 

1250 if callable(value): 

1251 value, key = True, value 

1252 else: 

1253 key = None 

1254 return value, key 

1255 

1256 # cmp takes precedence due to bw-compatibility. 

1257 if cmp is not None: 

1258 cmp, cmp_key = decide_callable_or_boolean(cmp) 

1259 return cmp, cmp_key, cmp, cmp_key 

1260 

1261 # If left None, equality is set to the specified default and ordering 

1262 # mirrors equality. 

1263 if eq is None: 

1264 eq, eq_key = default_eq, None 

1265 else: 

1266 eq, eq_key = decide_callable_or_boolean(eq) 

1267 

1268 if order is None: 

1269 order, order_key = eq, eq_key 

1270 else: 

1271 order, order_key = decide_callable_or_boolean(order) 

1272 

1273 if eq is False and order is True: 

1274 msg = "`order` can only be True if `eq` is True too." 

1275 raise ValueError(msg) 

1276 

1277 return eq, eq_key, order, order_key 

1278 

1279 

1280def _determine_whether_to_implement( 

1281 cls, flag, auto_detect, dunders, default=True 

1282): 

1283 """ 

1284 Check whether we should implement a set of methods for *cls*. 

1285 

1286 *flag* is the argument passed into @attr.s like 'init', *auto_detect* the 

1287 same as passed into @attr.s and *dunders* is a tuple of attribute names 

1288 whose presence signal that the user has implemented it themselves. 

1289 

1290 Return *default* if no reason for either for or against is found. 

1291 """ 

1292 if flag is True or flag is False: 

1293 return flag 

1294 

1295 if flag is None and auto_detect is False: 

1296 return default 

1297 

1298 # Logically, flag is None and auto_detect is True here. 

1299 for dunder in dunders: 

1300 if _has_own_attribute(cls, dunder): 

1301 return False 

1302 

1303 return default 

1304 

1305 

1306def attrs( 

1307 maybe_cls=None, 

1308 these=None, 

1309 repr_ns=None, 

1310 repr=None, 

1311 cmp=None, 

1312 hash=None, 

1313 init=None, 

1314 slots=False, 

1315 frozen=False, 

1316 weakref_slot=True, 

1317 str=False, 

1318 auto_attribs=False, 

1319 kw_only=False, 

1320 cache_hash=False, 

1321 auto_exc=False, 

1322 eq=None, 

1323 order=None, 

1324 auto_detect=False, 

1325 collect_by_mro=False, 

1326 getstate_setstate=None, 

1327 on_setattr=None, 

1328 field_transformer=None, 

1329 match_args=True, 

1330 unsafe_hash=None, 

1331): 

1332 r""" 

1333 A class decorator that adds :term:`dunder methods` according to the 

1334 specified attributes using `attr.ib` or the *these* argument. 

1335 

1336 Please consider using `attrs.define` / `attrs.frozen` in new code 

1337 (``attr.s`` will *never* go away, though). 

1338 

1339 :param these: A dictionary of name to `attr.ib` mappings. This is useful 

1340 to avoid the definition of your attributes within the class body 

1341 because you can't (e.g. if you want to add ``__repr__`` methods to 

1342 Django models) or don't want to. 

1343 

1344 If *these* is not ``None``, *attrs* will *not* search the class body 

1345 for attributes and will *not* remove any attributes from it. 

1346 

1347 The order is deduced from the order of the attributes inside *these*. 

1348 

1349 :type these: `dict` of `str` to `attr.ib` 

1350 

1351 :param str repr_ns: When using nested classes, there's no way in Python 2 

1352 to automatically detect that. Therefore it's possible to set the 

1353 namespace explicitly for a more meaningful ``repr`` output. 

1354 :param bool auto_detect: Instead of setting the *init*, *repr*, *eq*, 

1355 *order*, and *hash* arguments explicitly, assume they are set to 

1356 ``True`` **unless any** of the involved methods for one of the 

1357 arguments is implemented in the *current* class (i.e. it is *not* 

1358 inherited from some base class). 

1359 

1360 So for example by implementing ``__eq__`` on a class yourself, *attrs* 

1361 will deduce ``eq=False`` and will create *neither* ``__eq__`` *nor* 

1362 ``__ne__`` (but Python classes come with a sensible ``__ne__`` by 

1363 default, so it *should* be enough to only implement ``__eq__`` in most 

1364 cases). 

1365 

1366 .. warning:: 

1367 

1368 If you prevent *attrs* from creating the ordering methods for you 

1369 (``order=False``, e.g. by implementing ``__le__``), it becomes 

1370 *your* responsibility to make sure its ordering is sound. The best 

1371 way is to use the `functools.total_ordering` decorator. 

1372 

1373 

1374 Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*, *cmp*, 

1375 or *hash* overrides whatever *auto_detect* would determine. 

1376 

1377 :param bool repr: Create a ``__repr__`` method with a human readable 

1378 representation of *attrs* attributes.. 

1379 :param bool str: Create a ``__str__`` method that is identical to 

1380 ``__repr__``. This is usually not necessary except for `Exception`\ s. 

1381 :param bool | None eq: If ``True`` or ``None`` (default), add ``__eq__`` 

1382 and ``__ne__`` methods that check two instances for equality. 

1383 

1384 They compare the instances as if they were tuples of their *attrs* 

1385 attributes if and only if the types of both classes are *identical*! 

1386 

1387 .. seealso:: `comparison` 

1388 :param bool | None order: If ``True``, add ``__lt__``, ``__le__``, 

1389 ``__gt__``, and ``__ge__`` methods that behave like *eq* above and 

1390 allow instances to be ordered. If ``None`` (default) mirror value of 

1391 *eq*. 

1392 

1393 .. seealso:: `comparison` 

1394 :param bool | None cmp: Setting *cmp* is equivalent to setting *eq* and 

1395 *order* to the same value. Must not be mixed with *eq* or *order*. 

1396 

1397 .. seealso:: `comparison` 

1398 :param bool | None unsafe_hash: If ``None`` (default), the ``__hash__`` 

1399 method is generated according how *eq* and *frozen* are set. 

1400 

1401 1. If *both* are True, *attrs* will generate a ``__hash__`` for you. 

1402 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set to 

1403 None, marking it unhashable (which it is). 

1404 3. If *eq* is False, ``__hash__`` will be left untouched meaning the 

1405 ``__hash__`` method of the base class will be used (if base class is 

1406 ``object``, this means it will fall back to id-based hashing.). 

1407 

1408 Although not recommended, you can decide for yourself and force *attrs* 

1409 to create one (e.g. if the class is immutable even though you didn't 

1410 freeze it programmatically) by passing ``True`` or not. Both of these 

1411 cases are rather special and should be used carefully. 

1412 

1413 .. seealso:: 

1414 

1415 - Our documentation on `hashing`, 

1416 - Python's documentation on `object.__hash__`, 

1417 - and the `GitHub issue that led to the default \ 

1418 behavior <https://github.com/python-attrs/attrs/issues/136>`_ for 

1419 more details. 

1420 

1421 :param bool | None hash: Alias for *unsafe_hash*. *unsafe_hash* takes 

1422 precedence. 

1423 :param bool init: Create a ``__init__`` method that initializes the *attrs* 

1424 attributes. Leading underscores are stripped for the argument name. If 

1425 a ``__attrs_pre_init__`` method exists on the class, it will be called 

1426 before the class is initialized. If a ``__attrs_post_init__`` method 

1427 exists on the class, it will be called after the class is fully 

1428 initialized. 

1429 

1430 If ``init`` is ``False``, an ``__attrs_init__`` method will be injected 

1431 instead. This allows you to define a custom ``__init__`` method that 

1432 can do pre-init work such as ``super().__init__()``, and then call 

1433 ``__attrs_init__()`` and ``__attrs_post_init__()``. 

1434 

1435 .. seealso:: `init` 

1436 :param bool slots: Create a :term:`slotted class <slotted classes>` that's 

1437 more memory-efficient. Slotted classes are generally superior to the 

1438 default dict classes, but have some gotchas you should know about, so 

1439 we encourage you to read the :term:`glossary entry <slotted classes>`. 

1440 :param bool frozen: Make instances immutable after initialization. If 

1441 someone attempts to modify a frozen instance, 

1442 `attrs.exceptions.FrozenInstanceError` is raised. 

1443 

1444 .. note:: 

1445 

1446 1. This is achieved by installing a custom ``__setattr__`` method 

1447 on your class, so you can't implement your own. 

1448 

1449 2. True immutability is impossible in Python. 

1450 

1451 3. This *does* have a minor a runtime performance `impact 

1452 <how-frozen>` when initializing new instances. In other words: 

1453 ``__init__`` is slightly slower with ``frozen=True``. 

1454 

1455 4. If a class is frozen, you cannot modify ``self`` in 

1456 ``__attrs_post_init__`` or a self-written ``__init__``. You can 

1457 circumvent that limitation by using ``object.__setattr__(self, 

1458 "attribute_name", value)``. 

1459 

1460 5. Subclasses of a frozen class are frozen too. 

1461 

1462 :param bool weakref_slot: Make instances weak-referenceable. This has no 

1463 effect unless ``slots`` is also enabled. 

1464 :param bool auto_attribs: If ``True``, collect :pep:`526`-annotated 

1465 attributes from the class body. 

1466 

1467 In this case, you **must** annotate every field. If *attrs* encounters 

1468 a field that is set to an `attr.ib` but lacks a type annotation, an 

1469 `attr.exceptions.UnannotatedAttributeError` is raised. Use 

1470 ``field_name: typing.Any = attr.ib(...)`` if you don't want to set a 

1471 type. 

1472 

1473 If you assign a value to those attributes (e.g. ``x: int = 42``), that 

1474 value becomes the default value like if it were passed using 

1475 ``attr.ib(default=42)``. Passing an instance of `attrs.Factory` also 

1476 works as expected in most cases (see warning below). 

1477 

1478 Attributes annotated as `typing.ClassVar`, and attributes that are 

1479 neither annotated nor set to an `attr.ib` are **ignored**. 

1480 

1481 .. warning:: 

1482 For features that use the attribute name to create decorators (e.g. 

1483 :ref:`validators <validators>`), you still *must* assign `attr.ib` 

1484 to them. Otherwise Python will either not find the name or try to 

1485 use the default value to call e.g. ``validator`` on it. 

1486 

1487 These errors can be quite confusing and probably the most common bug 

1488 report on our bug tracker. 

1489 

1490 :param bool kw_only: Make all attributes keyword-only in the generated 

1491 ``__init__`` (if ``init`` is ``False``, this parameter is ignored). 

1492 :param bool cache_hash: Ensure that the object's hash code is computed only 

1493 once and stored on the object. If this is set to ``True``, hashing 

1494 must be either explicitly or implicitly enabled for this class. If the 

1495 hash code is cached, avoid any reassignments of fields involved in hash 

1496 code computation or mutations of the objects those fields point to 

1497 after object creation. If such changes occur, the behavior of the 

1498 object's hash code is undefined. 

1499 :param bool auto_exc: If the class subclasses `BaseException` (which 

1500 implicitly includes any subclass of any exception), the following 

1501 happens to behave like a well-behaved Python exceptions class: 

1502 

1503 - the values for *eq*, *order*, and *hash* are ignored and the 

1504 instances compare and hash by the instance's ids (N.B. *attrs* will 

1505 *not* remove existing implementations of ``__hash__`` or the equality 

1506 methods. It just won't add own ones.), 

1507 - all attributes that are either passed into ``__init__`` or have a 

1508 default value are additionally available as a tuple in the ``args`` 

1509 attribute, 

1510 - the value of *str* is ignored leaving ``__str__`` to base classes. 

1511 :param bool collect_by_mro: Setting this to `True` fixes the way *attrs* 

1512 collects attributes from base classes. The default behavior is 

1513 incorrect in certain cases of multiple inheritance. It should be on by 

1514 default but is kept off for backward-compatibility. 

1515 

1516 .. seealso:: 

1517 Issue `#428 <https://github.com/python-attrs/attrs/issues/428>`_ 

1518 

1519 :param bool | None getstate_setstate: 

1520 .. note:: 

1521 This is usually only interesting for slotted classes and you should 

1522 probably just set *auto_detect* to `True`. 

1523 

1524 If `True`, ``__getstate__`` and ``__setstate__`` are generated and 

1525 attached to the class. This is necessary for slotted classes to be 

1526 pickleable. If left `None`, it's `True` by default for slotted classes 

1527 and ``False`` for dict classes. 

1528 

1529 If *auto_detect* is `True`, and *getstate_setstate* is left `None`, and 

1530 **either** ``__getstate__`` or ``__setstate__`` is detected directly on 

1531 the class (i.e. not inherited), it is set to `False` (this is usually 

1532 what you want). 

1533 

1534 :param on_setattr: A callable that is run whenever the user attempts to set 

1535 an attribute (either by assignment like ``i.x = 42`` or by using 

1536 `setattr` like ``setattr(i, "x", 42)``). It receives the same arguments 

1537 as validators: the instance, the attribute that is being modified, and 

1538 the new value. 

1539 

1540 If no exception is raised, the attribute is set to the return value of 

1541 the callable. 

1542 

1543 If a list of callables is passed, they're automatically wrapped in an 

1544 `attrs.setters.pipe`. 

1545 :type on_setattr: `callable`, or a list of callables, or `None`, or 

1546 `attrs.setters.NO_OP` 

1547 

1548 :param callable | None field_transformer: 

1549 A function that is called with the original class object and all fields 

1550 right before *attrs* finalizes the class. You can use this, e.g., to 

1551 automatically add converters or validators to fields based on their 

1552 types. 

1553 

1554 .. seealso:: `transform-fields` 

1555 

1556 :param bool match_args: 

1557 If `True` (default), set ``__match_args__`` on the class to support 

1558 :pep:`634` (Structural Pattern Matching). It is a tuple of all 

1559 non-keyword-only ``__init__`` parameter names on Python 3.10 and later. 

1560 Ignored on older Python versions. 

1561 

1562 .. versionadded:: 16.0.0 *slots* 

1563 .. versionadded:: 16.1.0 *frozen* 

1564 .. versionadded:: 16.3.0 *str* 

1565 .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. 

1566 .. versionchanged:: 17.1.0 

1567 *hash* supports ``None`` as value which is also the default now. 

1568 .. versionadded:: 17.3.0 *auto_attribs* 

1569 .. versionchanged:: 18.1.0 

1570 If *these* is passed, no attributes are deleted from the class body. 

1571 .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. 

1572 .. versionadded:: 18.2.0 *weakref_slot* 

1573 .. deprecated:: 18.2.0 

1574 ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a 

1575 `DeprecationWarning` if the classes compared are subclasses of 

1576 each other. ``__eq`` and ``__ne__`` never tried to compared subclasses 

1577 to each other. 

1578 .. versionchanged:: 19.2.0 

1579 ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider 

1580 subclasses comparable anymore. 

1581 .. versionadded:: 18.2.0 *kw_only* 

1582 .. versionadded:: 18.2.0 *cache_hash* 

1583 .. versionadded:: 19.1.0 *auto_exc* 

1584 .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. 

1585 .. versionadded:: 19.2.0 *eq* and *order* 

1586 .. versionadded:: 20.1.0 *auto_detect* 

1587 .. versionadded:: 20.1.0 *collect_by_mro* 

1588 .. versionadded:: 20.1.0 *getstate_setstate* 

1589 .. versionadded:: 20.1.0 *on_setattr* 

1590 .. versionadded:: 20.3.0 *field_transformer* 

1591 .. versionchanged:: 21.1.0 

1592 ``init=False`` injects ``__attrs_init__`` 

1593 .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` 

1594 .. versionchanged:: 21.1.0 *cmp* undeprecated 

1595 .. versionadded:: 21.3.0 *match_args* 

1596 .. versionadded:: 22.2.0 

1597 *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). 

1598 """ 

1599 eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) 

1600 

1601 # unsafe_hash takes precedence due to PEP 681. 

1602 if unsafe_hash is not None: 

1603 hash = unsafe_hash 

1604 

1605 if isinstance(on_setattr, (list, tuple)): 

1606 on_setattr = setters.pipe(*on_setattr) 

1607 

1608 def wrap(cls): 

1609 is_frozen = frozen or _has_frozen_base_class(cls) 

1610 is_exc = auto_exc is True and issubclass(cls, BaseException) 

1611 has_own_setattr = auto_detect and _has_own_attribute( 

1612 cls, "__setattr__" 

1613 ) 

1614 

1615 if has_own_setattr and is_frozen: 

1616 msg = "Can't freeze a class with a custom __setattr__." 

1617 raise ValueError(msg) 

1618 

1619 builder = _ClassBuilder( 

1620 cls, 

1621 these, 

1622 slots, 

1623 is_frozen, 

1624 weakref_slot, 

1625 _determine_whether_to_implement( 

1626 cls, 

1627 getstate_setstate, 

1628 auto_detect, 

1629 ("__getstate__", "__setstate__"), 

1630 default=slots, 

1631 ), 

1632 auto_attribs, 

1633 kw_only, 

1634 cache_hash, 

1635 is_exc, 

1636 collect_by_mro, 

1637 on_setattr, 

1638 has_own_setattr, 

1639 field_transformer, 

1640 ) 

1641 if _determine_whether_to_implement( 

1642 cls, repr, auto_detect, ("__repr__",) 

1643 ): 

1644 builder.add_repr(repr_ns) 

1645 if str is True: 

1646 builder.add_str() 

1647 

1648 eq = _determine_whether_to_implement( 

1649 cls, eq_, auto_detect, ("__eq__", "__ne__") 

1650 ) 

1651 if not is_exc and eq is True: 

1652 builder.add_eq() 

1653 if not is_exc and _determine_whether_to_implement( 

1654 cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") 

1655 ): 

1656 builder.add_order() 

1657 

1658 builder.add_setattr() 

1659 

1660 nonlocal hash 

1661 if ( 

1662 hash is None 

1663 and auto_detect is True 

1664 and _has_own_attribute(cls, "__hash__") 

1665 ): 

1666 hash = False 

1667 

1668 if hash is not True and hash is not False and hash is not None: 

1669 # Can't use `hash in` because 1 == True for example. 

1670 msg = "Invalid value for hash. Must be True, False, or None." 

1671 raise TypeError(msg) 

1672 

1673 if hash is False or (hash is None and eq is False) or is_exc: 

1674 # Don't do anything. Should fall back to __object__'s __hash__ 

1675 # which is by id. 

1676 if cache_hash: 

1677 msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." 

1678 raise TypeError(msg) 

1679 elif hash is True or ( 

1680 hash is None and eq is True and is_frozen is True 

1681 ): 

1682 # Build a __hash__ if told so, or if it's safe. 

1683 builder.add_hash() 

1684 else: 

1685 # Raise TypeError on attempts to hash. 

1686 if cache_hash: 

1687 msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." 

1688 raise TypeError(msg) 

1689 builder.make_unhashable() 

1690 

1691 if _determine_whether_to_implement( 

1692 cls, init, auto_detect, ("__init__",) 

1693 ): 

1694 builder.add_init() 

1695 else: 

1696 builder.add_attrs_init() 

1697 if cache_hash: 

1698 msg = "Invalid value for cache_hash. To use hash caching, init must be True." 

1699 raise TypeError(msg) 

1700 

1701 if ( 

1702 PY310 

1703 and match_args 

1704 and not _has_own_attribute(cls, "__match_args__") 

1705 ): 

1706 builder.add_match_args() 

1707 

1708 return builder.build_class() 

1709 

1710 # maybe_cls's type depends on the usage of the decorator. It's a class 

1711 # if it's used as `@attrs` but ``None`` if used as `@attrs()`. 

1712 if maybe_cls is None: 

1713 return wrap 

1714 

1715 return wrap(maybe_cls) 

1716 

1717 

1718_attrs = attrs 

1719""" 

1720Internal alias so we can use it in functions that take an argument called 

1721*attrs*. 

1722""" 

1723 

1724 

1725def _has_frozen_base_class(cls): 

1726 """ 

1727 Check whether *cls* has a frozen ancestor by looking at its 

1728 __setattr__. 

1729 """ 

1730 return cls.__setattr__ is _frozen_setattrs 

1731 

1732 

1733def _generate_unique_filename(cls, func_name): 

1734 """ 

1735 Create a "filename" suitable for a function being generated. 

1736 """ 

1737 return ( 

1738 f"<attrs generated {func_name} {cls.__module__}." 

1739 f"{getattr(cls, '__qualname__', cls.__name__)}>" 

1740 ) 

1741 

1742 

1743def _make_hash(cls, attrs, frozen, cache_hash): 

1744 attrs = tuple( 

1745 a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) 

1746 ) 

1747 

1748 tab = " " 

1749 

1750 unique_filename = _generate_unique_filename(cls, "hash") 

1751 type_hash = hash(unique_filename) 

1752 # If eq is custom generated, we need to include the functions in globs 

1753 globs = {} 

1754 

1755 hash_def = "def __hash__(self" 

1756 hash_func = "hash((" 

1757 closing_braces = "))" 

1758 if not cache_hash: 

1759 hash_def += "):" 

1760 else: 

1761 hash_def += ", *" 

1762 

1763 hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):" 

1764 hash_func = "_cache_wrapper(" + hash_func 

1765 closing_braces += ")" 

1766 

1767 method_lines = [hash_def] 

1768 

1769 def append_hash_computation_lines(prefix, indent): 

1770 """ 

1771 Generate the code for actually computing the hash code. 

1772 Below this will either be returned directly or used to compute 

1773 a value which is then cached, depending on the value of cache_hash 

1774 """ 

1775 

1776 method_lines.extend( 

1777 [ 

1778 indent + prefix + hash_func, 

1779 indent + f" {type_hash},", 

1780 ] 

1781 ) 

1782 

1783 for a in attrs: 

1784 if a.eq_key: 

1785 cmp_name = f"_{a.name}_key" 

1786 globs[cmp_name] = a.eq_key 

1787 method_lines.append( 

1788 indent + f" {cmp_name}(self.{a.name})," 

1789 ) 

1790 else: 

1791 method_lines.append(indent + f" self.{a.name},") 

1792 

1793 method_lines.append(indent + " " + closing_braces) 

1794 

1795 if cache_hash: 

1796 method_lines.append(tab + f"if self.{_hash_cache_field} is None:") 

1797 if frozen: 

1798 append_hash_computation_lines( 

1799 f"object.__setattr__(self, '{_hash_cache_field}', ", tab * 2 

1800 ) 

1801 method_lines.append(tab * 2 + ")") # close __setattr__ 

1802 else: 

1803 append_hash_computation_lines( 

1804 f"self.{_hash_cache_field} = ", tab * 2 

1805 ) 

1806 method_lines.append(tab + f"return self.{_hash_cache_field}") 

1807 else: 

1808 append_hash_computation_lines("return ", tab) 

1809 

1810 script = "\n".join(method_lines) 

1811 return _make_method("__hash__", script, unique_filename, globs) 

1812 

1813 

1814def _add_hash(cls, attrs): 

1815 """ 

1816 Add a hash method to *cls*. 

1817 """ 

1818 cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False) 

1819 return cls 

1820 

1821 

1822def _make_ne(): 

1823 """ 

1824 Create __ne__ method. 

1825 """ 

1826 

1827 def __ne__(self, other): 

1828 """ 

1829 Check equality and either forward a NotImplemented or 

1830 return the result negated. 

1831 """ 

1832 result = self.__eq__(other) 

1833 if result is NotImplemented: 

1834 return NotImplemented 

1835 

1836 return not result 

1837 

1838 return __ne__ 

1839 

1840 

1841def _make_eq(cls, attrs): 

1842 """ 

1843 Create __eq__ method for *cls* with *attrs*. 

1844 """ 

1845 attrs = [a for a in attrs if a.eq] 

1846 

1847 unique_filename = _generate_unique_filename(cls, "eq") 

1848 lines = [ 

1849 "def __eq__(self, other):", 

1850 " if other.__class__ is not self.__class__:", 

1851 " return NotImplemented", 

1852 ] 

1853 

1854 # We can't just do a big self.x = other.x and... clause due to 

1855 # irregularities like nan == nan is false but (nan,) == (nan,) is true. 

1856 globs = {} 

1857 if attrs: 

1858 lines.append(" return (") 

1859 others = [" ) == ("] 

1860 for a in attrs: 

1861 if a.eq_key: 

1862 cmp_name = f"_{a.name}_key" 

1863 # Add the key function to the global namespace 

1864 # of the evaluated function. 

1865 globs[cmp_name] = a.eq_key 

1866 lines.append(f" {cmp_name}(self.{a.name}),") 

1867 others.append(f" {cmp_name}(other.{a.name}),") 

1868 else: 

1869 lines.append(f" self.{a.name},") 

1870 others.append(f" other.{a.name},") 

1871 

1872 lines += [*others, " )"] 

1873 else: 

1874 lines.append(" return True") 

1875 

1876 script = "\n".join(lines) 

1877 

1878 return _make_method("__eq__", script, unique_filename, globs) 

1879 

1880 

1881def _make_order(cls, attrs): 

1882 """ 

1883 Create ordering methods for *cls* with *attrs*. 

1884 """ 

1885 attrs = [a for a in attrs if a.order] 

1886 

1887 def attrs_to_tuple(obj): 

1888 """ 

1889 Save us some typing. 

1890 """ 

1891 return tuple( 

1892 key(value) if key else value 

1893 for value, key in ( 

1894 (getattr(obj, a.name), a.order_key) for a in attrs 

1895 ) 

1896 ) 

1897 

1898 def __lt__(self, other): 

1899 """ 

1900 Automatically created by attrs. 

1901 """ 

1902 if other.__class__ is self.__class__: 

1903 return attrs_to_tuple(self) < attrs_to_tuple(other) 

1904 

1905 return NotImplemented 

1906 

1907 def __le__(self, other): 

1908 """ 

1909 Automatically created by attrs. 

1910 """ 

1911 if other.__class__ is self.__class__: 

1912 return attrs_to_tuple(self) <= attrs_to_tuple(other) 

1913 

1914 return NotImplemented 

1915 

1916 def __gt__(self, other): 

1917 """ 

1918 Automatically created by attrs. 

1919 """ 

1920 if other.__class__ is self.__class__: 

1921 return attrs_to_tuple(self) > attrs_to_tuple(other) 

1922 

1923 return NotImplemented 

1924 

1925 def __ge__(self, other): 

1926 """ 

1927 Automatically created by attrs. 

1928 """ 

1929 if other.__class__ is self.__class__: 

1930 return attrs_to_tuple(self) >= attrs_to_tuple(other) 

1931 

1932 return NotImplemented 

1933 

1934 return __lt__, __le__, __gt__, __ge__ 

1935 

1936 

1937def _add_eq(cls, attrs=None): 

1938 """ 

1939 Add equality methods to *cls* with *attrs*. 

1940 """ 

1941 if attrs is None: 

1942 attrs = cls.__attrs_attrs__ 

1943 

1944 cls.__eq__ = _make_eq(cls, attrs) 

1945 cls.__ne__ = _make_ne() 

1946 

1947 return cls 

1948 

1949 

1950def _make_repr(attrs, ns, cls): 

1951 unique_filename = _generate_unique_filename(cls, "repr") 

1952 # Figure out which attributes to include, and which function to use to 

1953 # format them. The a.repr value can be either bool or a custom 

1954 # callable. 

1955 attr_names_with_reprs = tuple( 

1956 (a.name, (repr if a.repr is True else a.repr), a.init) 

1957 for a in attrs 

1958 if a.repr is not False 

1959 ) 

1960 globs = { 

1961 name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr 

1962 } 

1963 globs["_compat"] = _compat 

1964 globs["AttributeError"] = AttributeError 

1965 globs["NOTHING"] = NOTHING 

1966 attribute_fragments = [] 

1967 for name, r, i in attr_names_with_reprs: 

1968 accessor = ( 

1969 "self." + name if i else 'getattr(self, "' + name + '", NOTHING)' 

1970 ) 

1971 fragment = ( 

1972 "%s={%s!r}" % (name, accessor) 

1973 if r == repr 

1974 else "%s={%s_repr(%s)}" % (name, name, accessor) 

1975 ) 

1976 attribute_fragments.append(fragment) 

1977 repr_fragment = ", ".join(attribute_fragments) 

1978 

1979 if ns is None: 

1980 cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' 

1981 else: 

1982 cls_name_fragment = ns + ".{self.__class__.__name__}" 

1983 

1984 lines = [ 

1985 "def __repr__(self):", 

1986 " try:", 

1987 " already_repring = _compat.repr_context.already_repring", 

1988 " except AttributeError:", 

1989 " already_repring = {id(self),}", 

1990 " _compat.repr_context.already_repring = already_repring", 

1991 " else:", 

1992 " if id(self) in already_repring:", 

1993 " return '...'", 

1994 " else:", 

1995 " already_repring.add(id(self))", 

1996 " try:", 

1997 f" return f'{cls_name_fragment}({repr_fragment})'", 

1998 " finally:", 

1999 " already_repring.remove(id(self))", 

2000 ] 

2001 

2002 return _make_method( 

2003 "__repr__", "\n".join(lines), unique_filename, globs=globs 

2004 ) 

2005 

2006 

2007def _add_repr(cls, ns=None, attrs=None): 

2008 """ 

2009 Add a repr method to *cls*. 

2010 """ 

2011 if attrs is None: 

2012 attrs = cls.__attrs_attrs__ 

2013 

2014 cls.__repr__ = _make_repr(attrs, ns, cls) 

2015 return cls 

2016 

2017 

2018def fields(cls): 

2019 """ 

2020 Return the tuple of *attrs* attributes for a class. 

2021 

2022 The tuple also allows accessing the fields by their names (see below for 

2023 examples). 

2024 

2025 :param type cls: Class to introspect. 

2026 

2027 :raise TypeError: If *cls* is not a class. 

2028 :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* 

2029 class. 

2030 

2031 :rtype: tuple (with name accessors) of `attrs.Attribute` 

2032 

2033 .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields 

2034 by name. 

2035 .. versionchanged:: 23.1.0 Add support for generic classes. 

2036 """ 

2037 generic_base = get_generic_base(cls) 

2038 

2039 if generic_base is None and not isinstance(cls, type): 

2040 msg = "Passed object must be a class." 

2041 raise TypeError(msg) 

2042 

2043 attrs = getattr(cls, "__attrs_attrs__", None) 

2044 

2045 if attrs is None: 

2046 if generic_base is not None: 

2047 attrs = getattr(generic_base, "__attrs_attrs__", None) 

2048 if attrs is not None: 

2049 # Even though this is global state, stick it on here to speed 

2050 # it up. We rely on `cls` being cached for this to be 

2051 # efficient. 

2052 cls.__attrs_attrs__ = attrs 

2053 return attrs 

2054 msg = f"{cls!r} is not an attrs-decorated class." 

2055 raise NotAnAttrsClassError(msg) 

2056 

2057 return attrs 

2058 

2059 

2060def fields_dict(cls): 

2061 """ 

2062 Return an ordered dictionary of *attrs* attributes for a class, whose 

2063 keys are the attribute names. 

2064 

2065 :param type cls: Class to introspect. 

2066 

2067 :raise TypeError: If *cls* is not a class. 

2068 :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* 

2069 class. 

2070 

2071 :rtype: dict 

2072 

2073 .. versionadded:: 18.1.0 

2074 """ 

2075 if not isinstance(cls, type): 

2076 msg = "Passed object must be a class." 

2077 raise TypeError(msg) 

2078 attrs = getattr(cls, "__attrs_attrs__", None) 

2079 if attrs is None: 

2080 msg = f"{cls!r} is not an attrs-decorated class." 

2081 raise NotAnAttrsClassError(msg) 

2082 return {a.name: a for a in attrs} 

2083 

2084 

2085def validate(inst): 

2086 """ 

2087 Validate all attributes on *inst* that have a validator. 

2088 

2089 Leaves all exceptions through. 

2090 

2091 :param inst: Instance of a class with *attrs* attributes. 

2092 """ 

2093 if _config._run_validators is False: 

2094 return 

2095 

2096 for a in fields(inst.__class__): 

2097 v = a.validator 

2098 if v is not None: 

2099 v(inst, a, getattr(inst, a.name)) 

2100 

2101 

2102def _is_slot_cls(cls): 

2103 return "__slots__" in cls.__dict__ 

2104 

2105 

2106def _is_slot_attr(a_name, base_attr_map): 

2107 """ 

2108 Check if the attribute name comes from a slot class. 

2109 """ 

2110 return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name]) 

2111 

2112 

2113def _make_init( 

2114 cls, 

2115 attrs, 

2116 pre_init, 

2117 pre_init_has_args, 

2118 post_init, 

2119 frozen, 

2120 slots, 

2121 cache_hash, 

2122 base_attr_map, 

2123 is_exc, 

2124 cls_on_setattr, 

2125 attrs_init, 

2126): 

2127 has_cls_on_setattr = ( 

2128 cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP 

2129 ) 

2130 

2131 if frozen and has_cls_on_setattr: 

2132 msg = "Frozen classes can't use on_setattr." 

2133 raise ValueError(msg) 

2134 

2135 needs_cached_setattr = cache_hash or frozen 

2136 filtered_attrs = [] 

2137 attr_dict = {} 

2138 for a in attrs: 

2139 if not a.init and a.default is NOTHING: 

2140 continue 

2141 

2142 filtered_attrs.append(a) 

2143 attr_dict[a.name] = a 

2144 

2145 if a.on_setattr is not None: 

2146 if frozen is True: 

2147 msg = "Frozen classes can't use on_setattr." 

2148 raise ValueError(msg) 

2149 

2150 needs_cached_setattr = True 

2151 elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: 

2152 needs_cached_setattr = True 

2153 

2154 unique_filename = _generate_unique_filename(cls, "init") 

2155 

2156 script, globs, annotations = _attrs_to_init_script( 

2157 filtered_attrs, 

2158 frozen, 

2159 slots, 

2160 pre_init, 

2161 pre_init_has_args, 

2162 post_init, 

2163 cache_hash, 

2164 base_attr_map, 

2165 is_exc, 

2166 needs_cached_setattr, 

2167 has_cls_on_setattr, 

2168 attrs_init, 

2169 ) 

2170 if cls.__module__ in sys.modules: 

2171 # This makes typing.get_type_hints(CLS.__init__) resolve string types. 

2172 globs.update(sys.modules[cls.__module__].__dict__) 

2173 

2174 globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) 

2175 

2176 if needs_cached_setattr: 

2177 # Save the lookup overhead in __init__ if we need to circumvent 

2178 # setattr hooks. 

2179 globs["_cached_setattr_get"] = _obj_setattr.__get__ 

2180 

2181 init = _make_method( 

2182 "__attrs_init__" if attrs_init else "__init__", 

2183 script, 

2184 unique_filename, 

2185 globs, 

2186 ) 

2187 init.__annotations__ = annotations 

2188 

2189 return init 

2190 

2191 

2192def _setattr(attr_name, value_var, has_on_setattr): 

2193 """ 

2194 Use the cached object.setattr to set *attr_name* to *value_var*. 

2195 """ 

2196 return f"_setattr('{attr_name}', {value_var})" 

2197 

2198 

2199def _setattr_with_converter(attr_name, value_var, has_on_setattr): 

2200 """ 

2201 Use the cached object.setattr to set *attr_name* to *value_var*, but run 

2202 its converter first. 

2203 """ 

2204 return "_setattr('%s', %s(%s))" % ( 

2205 attr_name, 

2206 _init_converter_pat % (attr_name,), 

2207 value_var, 

2208 ) 

2209 

2210 

2211def _assign(attr_name, value, has_on_setattr): 

2212 """ 

2213 Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise 

2214 relegate to _setattr. 

2215 """ 

2216 if has_on_setattr: 

2217 return _setattr(attr_name, value, True) 

2218 

2219 return f"self.{attr_name} = {value}" 

2220 

2221 

2222def _assign_with_converter(attr_name, value_var, has_on_setattr): 

2223 """ 

2224 Unless *attr_name* has an on_setattr hook, use normal assignment after 

2225 conversion. Otherwise relegate to _setattr_with_converter. 

2226 """ 

2227 if has_on_setattr: 

2228 return _setattr_with_converter(attr_name, value_var, True) 

2229 

2230 return "self.%s = %s(%s)" % ( 

2231 attr_name, 

2232 _init_converter_pat % (attr_name,), 

2233 value_var, 

2234 ) 

2235 

2236 

2237def _attrs_to_init_script( 

2238 attrs, 

2239 frozen, 

2240 slots, 

2241 pre_init, 

2242 pre_init_has_args, 

2243 post_init, 

2244 cache_hash, 

2245 base_attr_map, 

2246 is_exc, 

2247 needs_cached_setattr, 

2248 has_cls_on_setattr, 

2249 attrs_init, 

2250): 

2251 """ 

2252 Return a script of an initializer for *attrs* and a dict of globals. 

2253 

2254 The globals are expected by the generated script. 

2255 

2256 If *frozen* is True, we cannot set the attributes directly so we use 

2257 a cached ``object.__setattr__``. 

2258 """ 

2259 lines = [] 

2260 if pre_init: 

2261 lines.append("self.__attrs_pre_init__()") 

2262 

2263 if needs_cached_setattr: 

2264 lines.append( 

2265 # Circumvent the __setattr__ descriptor to save one lookup per 

2266 # assignment. 

2267 # Note _setattr will be used again below if cache_hash is True 

2268 "_setattr = _cached_setattr_get(self)" 

2269 ) 

2270 

2271 if frozen is True: 

2272 if slots is True: 

2273 fmt_setter = _setattr 

2274 fmt_setter_with_converter = _setattr_with_converter 

2275 else: 

2276 # Dict frozen classes assign directly to __dict__. 

2277 # But only if the attribute doesn't come from an ancestor slot 

2278 # class. 

2279 # Note _inst_dict will be used again below if cache_hash is True 

2280 lines.append("_inst_dict = self.__dict__") 

2281 

2282 def fmt_setter(attr_name, value_var, has_on_setattr): 

2283 if _is_slot_attr(attr_name, base_attr_map): 

2284 return _setattr(attr_name, value_var, has_on_setattr) 

2285 

2286 return f"_inst_dict['{attr_name}'] = {value_var}" 

2287 

2288 def fmt_setter_with_converter( 

2289 attr_name, value_var, has_on_setattr 

2290 ): 

2291 if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): 

2292 return _setattr_with_converter( 

2293 attr_name, value_var, has_on_setattr 

2294 ) 

2295 

2296 return "_inst_dict['%s'] = %s(%s)" % ( 

2297 attr_name, 

2298 _init_converter_pat % (attr_name,), 

2299 value_var, 

2300 ) 

2301 

2302 else: 

2303 # Not frozen. 

2304 fmt_setter = _assign 

2305 fmt_setter_with_converter = _assign_with_converter 

2306 

2307 args = [] 

2308 kw_only_args = [] 

2309 attrs_to_validate = [] 

2310 

2311 # This is a dictionary of names to validator and converter callables. 

2312 # Injecting this into __init__ globals lets us avoid lookups. 

2313 names_for_globals = {} 

2314 annotations = {"return": None} 

2315 

2316 for a in attrs: 

2317 if a.validator: 

2318 attrs_to_validate.append(a) 

2319 

2320 attr_name = a.name 

2321 has_on_setattr = a.on_setattr is not None or ( 

2322 a.on_setattr is not setters.NO_OP and has_cls_on_setattr 

2323 ) 

2324 # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not 

2325 # explicitly provided 

2326 arg_name = a.alias 

2327 

2328 has_factory = isinstance(a.default, Factory) 

2329 maybe_self = "self" if has_factory and a.default.takes_self else "" 

2330 

2331 if a.init is False: 

2332 if has_factory: 

2333 init_factory_name = _init_factory_pat % (a.name,) 

2334 if a.converter is not None: 

2335 lines.append( 

2336 fmt_setter_with_converter( 

2337 attr_name, 

2338 init_factory_name + f"({maybe_self})", 

2339 has_on_setattr, 

2340 ) 

2341 ) 

2342 conv_name = _init_converter_pat % (a.name,) 

2343 names_for_globals[conv_name] = a.converter 

2344 else: 

2345 lines.append( 

2346 fmt_setter( 

2347 attr_name, 

2348 init_factory_name + f"({maybe_self})", 

2349 has_on_setattr, 

2350 ) 

2351 ) 

2352 names_for_globals[init_factory_name] = a.default.factory 

2353 elif a.converter is not None: 

2354 lines.append( 

2355 fmt_setter_with_converter( 

2356 attr_name, 

2357 f"attr_dict['{attr_name}'].default", 

2358 has_on_setattr, 

2359 ) 

2360 ) 

2361 conv_name = _init_converter_pat % (a.name,) 

2362 names_for_globals[conv_name] = a.converter 

2363 else: 

2364 lines.append( 

2365 fmt_setter( 

2366 attr_name, 

2367 f"attr_dict['{attr_name}'].default", 

2368 has_on_setattr, 

2369 ) 

2370 ) 

2371 elif a.default is not NOTHING and not has_factory: 

2372 arg = f"{arg_name}=attr_dict['{attr_name}'].default" 

2373 if a.kw_only: 

2374 kw_only_args.append(arg) 

2375 else: 

2376 args.append(arg) 

2377 

2378 if a.converter is not None: 

2379 lines.append( 

2380 fmt_setter_with_converter( 

2381 attr_name, arg_name, has_on_setattr 

2382 ) 

2383 ) 

2384 names_for_globals[ 

2385 _init_converter_pat % (a.name,) 

2386 ] = a.converter 

2387 else: 

2388 lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) 

2389 

2390 elif has_factory: 

2391 arg = f"{arg_name}=NOTHING" 

2392 if a.kw_only: 

2393 kw_only_args.append(arg) 

2394 else: 

2395 args.append(arg) 

2396 lines.append(f"if {arg_name} is not NOTHING:") 

2397 

2398 init_factory_name = _init_factory_pat % (a.name,) 

2399 if a.converter is not None: 

2400 lines.append( 

2401 " " 

2402 + fmt_setter_with_converter( 

2403 attr_name, arg_name, has_on_setattr 

2404 ) 

2405 ) 

2406 lines.append("else:") 

2407 lines.append( 

2408 " " 

2409 + fmt_setter_with_converter( 

2410 attr_name, 

2411 init_factory_name + "(" + maybe_self + ")", 

2412 has_on_setattr, 

2413 ) 

2414 ) 

2415 names_for_globals[ 

2416 _init_converter_pat % (a.name,) 

2417 ] = a.converter 

2418 else: 

2419 lines.append( 

2420 " " + fmt_setter(attr_name, arg_name, has_on_setattr) 

2421 ) 

2422 lines.append("else:") 

2423 lines.append( 

2424 " " 

2425 + fmt_setter( 

2426 attr_name, 

2427 init_factory_name + "(" + maybe_self + ")", 

2428 has_on_setattr, 

2429 ) 

2430 ) 

2431 names_for_globals[init_factory_name] = a.default.factory 

2432 else: 

2433 if a.kw_only: 

2434 kw_only_args.append(arg_name) 

2435 else: 

2436 args.append(arg_name) 

2437 

2438 if a.converter is not None: 

2439 lines.append( 

2440 fmt_setter_with_converter( 

2441 attr_name, arg_name, has_on_setattr 

2442 ) 

2443 ) 

2444 names_for_globals[ 

2445 _init_converter_pat % (a.name,) 

2446 ] = a.converter 

2447 else: 

2448 lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) 

2449 

2450 if a.init is True: 

2451 if a.type is not None and a.converter is None: 

2452 annotations[arg_name] = a.type 

2453 elif a.converter is not None: 

2454 # Try to get the type from the converter. 

2455 t = _AnnotationExtractor(a.converter).get_first_param_type() 

2456 if t: 

2457 annotations[arg_name] = t 

2458 

2459 if attrs_to_validate: # we can skip this if there are no validators. 

2460 names_for_globals["_config"] = _config 

2461 lines.append("if _config._run_validators is True:") 

2462 for a in attrs_to_validate: 

2463 val_name = "__attr_validator_" + a.name 

2464 attr_name = "__attr_" + a.name 

2465 lines.append(f" {val_name}(self, {attr_name}, self.{a.name})") 

2466 names_for_globals[val_name] = a.validator 

2467 names_for_globals[attr_name] = a 

2468 

2469 if post_init: 

2470 lines.append("self.__attrs_post_init__()") 

2471 

2472 # because this is set only after __attrs_post_init__ is called, a crash 

2473 # will result if post-init tries to access the hash code. This seemed 

2474 # preferable to setting this beforehand, in which case alteration to 

2475 # field values during post-init combined with post-init accessing the 

2476 # hash code would result in silent bugs. 

2477 if cache_hash: 

2478 if frozen: 

2479 if slots: # noqa: SIM108 

2480 # if frozen and slots, then _setattr defined above 

2481 init_hash_cache = "_setattr('%s', %s)" 

2482 else: 

2483 # if frozen and not slots, then _inst_dict defined above 

2484 init_hash_cache = "_inst_dict['%s'] = %s" 

2485 else: 

2486 init_hash_cache = "self.%s = %s" 

2487 lines.append(init_hash_cache % (_hash_cache_field, "None")) 

2488 

2489 # For exceptions we rely on BaseException.__init__ for proper 

2490 # initialization. 

2491 if is_exc: 

2492 vals = ",".join(f"self.{a.name}" for a in attrs if a.init) 

2493 

2494 lines.append(f"BaseException.__init__(self, {vals})") 

2495 

2496 args = ", ".join(args) 

2497 pre_init_args = args 

2498 if kw_only_args: 

2499 args += "%s*, %s" % ( 

2500 ", " if args else "", # leading comma 

2501 ", ".join(kw_only_args), # kw_only args 

2502 ) 

2503 pre_init_kw_only_args = ", ".join( 

2504 ["%s=%s" % (kw_arg, kw_arg) for kw_arg in kw_only_args] 

2505 ) 

2506 pre_init_args += ( 

2507 ", " if pre_init_args else "" 

2508 ) # handle only kwargs and no regular args 

2509 pre_init_args += pre_init_kw_only_args 

2510 

2511 if pre_init and pre_init_has_args: 

2512 # If pre init method has arguments, pass same arguments as `__init__` 

2513 lines[0] = "self.__attrs_pre_init__(%s)" % pre_init_args 

2514 

2515 return ( 

2516 "def %s(self, %s):\n %s\n" 

2517 % ( 

2518 ("__attrs_init__" if attrs_init else "__init__"), 

2519 args, 

2520 "\n ".join(lines) if lines else "pass", 

2521 ), 

2522 names_for_globals, 

2523 annotations, 

2524 ) 

2525 

2526 

2527def _default_init_alias_for(name: str) -> str: 

2528 """ 

2529 The default __init__ parameter name for a field. 

2530 

2531 This performs private-name adjustment via leading-unscore stripping, 

2532 and is the default value of Attribute.alias if not provided. 

2533 """ 

2534 

2535 return name.lstrip("_") 

2536 

2537 

2538class Attribute: 

2539 """ 

2540 *Read-only* representation of an attribute. 

2541 

2542 .. warning:: 

2543 

2544 You should never instantiate this class yourself. 

2545 

2546 The class has *all* arguments of `attr.ib` (except for ``factory`` 

2547 which is only syntactic sugar for ``default=Factory(...)`` plus the 

2548 following: 

2549 

2550 - ``name`` (`str`): The name of the attribute. 

2551 - ``alias`` (`str`): The __init__ parameter name of the attribute, after 

2552 any explicit overrides and default private-attribute-name handling. 

2553 - ``inherited`` (`bool`): Whether or not that attribute has been inherited 

2554 from a base class. 

2555 - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The callables 

2556 that are used for comparing and ordering objects by this attribute, 

2557 respectively. These are set by passing a callable to `attr.ib`'s ``eq``, 

2558 ``order``, or ``cmp`` arguments. See also :ref:`comparison customization 

2559 <custom-comparison>`. 

2560 

2561 Instances of this class are frequently used for introspection purposes 

2562 like: 

2563 

2564 - `fields` returns a tuple of them. 

2565 - Validators get them passed as the first argument. 

2566 - The :ref:`field transformer <transform-fields>` hook receives a list of 

2567 them. 

2568 - The ``alias`` property exposes the __init__ parameter name of the field, 

2569 with any overrides and default private-attribute handling applied. 

2570 

2571 

2572 .. versionadded:: 20.1.0 *inherited* 

2573 .. versionadded:: 20.1.0 *on_setattr* 

2574 .. versionchanged:: 20.2.0 *inherited* is not taken into account for 

2575 equality checks and hashing anymore. 

2576 .. versionadded:: 21.1.0 *eq_key* and *order_key* 

2577 .. versionadded:: 22.2.0 *alias* 

2578 

2579 For the full version history of the fields, see `attr.ib`. 

2580 """ 

2581 

2582 __slots__ = ( 

2583 "name", 

2584 "default", 

2585 "validator", 

2586 "repr", 

2587 "eq", 

2588 "eq_key", 

2589 "order", 

2590 "order_key", 

2591 "hash", 

2592 "init", 

2593 "metadata", 

2594 "type", 

2595 "converter", 

2596 "kw_only", 

2597 "inherited", 

2598 "on_setattr", 

2599 "alias", 

2600 ) 

2601 

2602 def __init__( 

2603 self, 

2604 name, 

2605 default, 

2606 validator, 

2607 repr, 

2608 cmp, # XXX: unused, remove along with other cmp code. 

2609 hash, 

2610 init, 

2611 inherited, 

2612 metadata=None, 

2613 type=None, 

2614 converter=None, 

2615 kw_only=False, 

2616 eq=None, 

2617 eq_key=None, 

2618 order=None, 

2619 order_key=None, 

2620 on_setattr=None, 

2621 alias=None, 

2622 ): 

2623 eq, eq_key, order, order_key = _determine_attrib_eq_order( 

2624 cmp, eq_key or eq, order_key or order, True 

2625 ) 

2626 

2627 # Cache this descriptor here to speed things up later. 

2628 bound_setattr = _obj_setattr.__get__(self) 

2629 

2630 # Despite the big red warning, people *do* instantiate `Attribute` 

2631 # themselves. 

2632 bound_setattr("name", name) 

2633 bound_setattr("default", default) 

2634 bound_setattr("validator", validator) 

2635 bound_setattr("repr", repr) 

2636 bound_setattr("eq", eq) 

2637 bound_setattr("eq_key", eq_key) 

2638 bound_setattr("order", order) 

2639 bound_setattr("order_key", order_key) 

2640 bound_setattr("hash", hash) 

2641 bound_setattr("init", init) 

2642 bound_setattr("converter", converter) 

2643 bound_setattr( 

2644 "metadata", 

2645 ( 

2646 types.MappingProxyType(dict(metadata)) # Shallow copy 

2647 if metadata 

2648 else _empty_metadata_singleton 

2649 ), 

2650 ) 

2651 bound_setattr("type", type) 

2652 bound_setattr("kw_only", kw_only) 

2653 bound_setattr("inherited", inherited) 

2654 bound_setattr("on_setattr", on_setattr) 

2655 bound_setattr("alias", alias) 

2656 

2657 def __setattr__(self, name, value): 

2658 raise FrozenInstanceError() 

2659 

2660 @classmethod 

2661 def from_counting_attr(cls, name, ca, type=None): 

2662 # type holds the annotated value. deal with conflicts: 

2663 if type is None: 

2664 type = ca.type 

2665 elif ca.type is not None: 

2666 msg = "Type annotation and type argument cannot both be present" 

2667 raise ValueError(msg) 

2668 inst_dict = { 

2669 k: getattr(ca, k) 

2670 for k in Attribute.__slots__ 

2671 if k 

2672 not in ( 

2673 "name", 

2674 "validator", 

2675 "default", 

2676 "type", 

2677 "inherited", 

2678 ) # exclude methods and deprecated alias 

2679 } 

2680 return cls( 

2681 name=name, 

2682 validator=ca._validator, 

2683 default=ca._default, 

2684 type=type, 

2685 cmp=None, 

2686 inherited=False, 

2687 **inst_dict, 

2688 ) 

2689 

2690 # Don't use attrs.evolve since fields(Attribute) doesn't work 

2691 def evolve(self, **changes): 

2692 """ 

2693 Copy *self* and apply *changes*. 

2694 

2695 This works similarly to `attrs.evolve` but that function does not work 

2696 with `Attribute`. 

2697 

2698 It is mainly meant to be used for `transform-fields`. 

2699 

2700 .. versionadded:: 20.3.0 

2701 """ 

2702 new = copy.copy(self) 

2703 

2704 new._setattrs(changes.items()) 

2705 

2706 return new 

2707 

2708 # Don't use _add_pickle since fields(Attribute) doesn't work 

2709 def __getstate__(self): 

2710 """ 

2711 Play nice with pickle. 

2712 """ 

2713 return tuple( 

2714 getattr(self, name) if name != "metadata" else dict(self.metadata) 

2715 for name in self.__slots__ 

2716 ) 

2717 

2718 def __setstate__(self, state): 

2719 """ 

2720 Play nice with pickle. 

2721 """ 

2722 self._setattrs(zip(self.__slots__, state)) 

2723 

2724 def _setattrs(self, name_values_pairs): 

2725 bound_setattr = _obj_setattr.__get__(self) 

2726 for name, value in name_values_pairs: 

2727 if name != "metadata": 

2728 bound_setattr(name, value) 

2729 else: 

2730 bound_setattr( 

2731 name, 

2732 types.MappingProxyType(dict(value)) 

2733 if value 

2734 else _empty_metadata_singleton, 

2735 ) 

2736 

2737 

2738_a = [ 

2739 Attribute( 

2740 name=name, 

2741 default=NOTHING, 

2742 validator=None, 

2743 repr=True, 

2744 cmp=None, 

2745 eq=True, 

2746 order=False, 

2747 hash=(name != "metadata"), 

2748 init=True, 

2749 inherited=False, 

2750 alias=_default_init_alias_for(name), 

2751 ) 

2752 for name in Attribute.__slots__ 

2753] 

2754 

2755Attribute = _add_hash( 

2756 _add_eq( 

2757 _add_repr(Attribute, attrs=_a), 

2758 attrs=[a for a in _a if a.name != "inherited"], 

2759 ), 

2760 attrs=[a for a in _a if a.hash and a.name != "inherited"], 

2761) 

2762 

2763 

2764class _CountingAttr: 

2765 """ 

2766 Intermediate representation of attributes that uses a counter to preserve 

2767 the order in which the attributes have been defined. 

2768 

2769 *Internal* data structure of the attrs library. Running into is most 

2770 likely the result of a bug like a forgotten `@attr.s` decorator. 

2771 """ 

2772 

2773 __slots__ = ( 

2774 "counter", 

2775 "_default", 

2776 "repr", 

2777 "eq", 

2778 "eq_key", 

2779 "order", 

2780 "order_key", 

2781 "hash", 

2782 "init", 

2783 "metadata", 

2784 "_validator", 

2785 "converter", 

2786 "type", 

2787 "kw_only", 

2788 "on_setattr", 

2789 "alias", 

2790 ) 

2791 __attrs_attrs__ = ( 

2792 *tuple( 

2793 Attribute( 

2794 name=name, 

2795 alias=_default_init_alias_for(name), 

2796 default=NOTHING, 

2797 validator=None, 

2798 repr=True, 

2799 cmp=None, 

2800 hash=True, 

2801 init=True, 

2802 kw_only=False, 

2803 eq=True, 

2804 eq_key=None, 

2805 order=False, 

2806 order_key=None, 

2807 inherited=False, 

2808 on_setattr=None, 

2809 ) 

2810 for name in ( 

2811 "counter", 

2812 "_default", 

2813 "repr", 

2814 "eq", 

2815 "order", 

2816 "hash", 

2817 "init", 

2818 "on_setattr", 

2819 "alias", 

2820 ) 

2821 ), 

2822 Attribute( 

2823 name="metadata", 

2824 alias="metadata", 

2825 default=None, 

2826 validator=None, 

2827 repr=True, 

2828 cmp=None, 

2829 hash=False, 

2830 init=True, 

2831 kw_only=False, 

2832 eq=True, 

2833 eq_key=None, 

2834 order=False, 

2835 order_key=None, 

2836 inherited=False, 

2837 on_setattr=None, 

2838 ), 

2839 ) 

2840 cls_counter = 0 

2841 

2842 def __init__( 

2843 self, 

2844 default, 

2845 validator, 

2846 repr, 

2847 cmp, 

2848 hash, 

2849 init, 

2850 converter, 

2851 metadata, 

2852 type, 

2853 kw_only, 

2854 eq, 

2855 eq_key, 

2856 order, 

2857 order_key, 

2858 on_setattr, 

2859 alias, 

2860 ): 

2861 _CountingAttr.cls_counter += 1 

2862 self.counter = _CountingAttr.cls_counter 

2863 self._default = default 

2864 self._validator = validator 

2865 self.converter = converter 

2866 self.repr = repr 

2867 self.eq = eq 

2868 self.eq_key = eq_key 

2869 self.order = order 

2870 self.order_key = order_key 

2871 self.hash = hash 

2872 self.init = init 

2873 self.metadata = metadata 

2874 self.type = type 

2875 self.kw_only = kw_only 

2876 self.on_setattr = on_setattr 

2877 self.alias = alias 

2878 

2879 def validator(self, meth): 

2880 """ 

2881 Decorator that adds *meth* to the list of validators. 

2882 

2883 Returns *meth* unchanged. 

2884 

2885 .. versionadded:: 17.1.0 

2886 """ 

2887 if self._validator is None: 

2888 self._validator = meth 

2889 else: 

2890 self._validator = and_(self._validator, meth) 

2891 return meth 

2892 

2893 def default(self, meth): 

2894 """ 

2895 Decorator that allows to set the default for an attribute. 

2896 

2897 Returns *meth* unchanged. 

2898 

2899 :raises DefaultAlreadySetError: If default has been set before. 

2900 

2901 .. versionadded:: 17.1.0 

2902 """ 

2903 if self._default is not NOTHING: 

2904 raise DefaultAlreadySetError() 

2905 

2906 self._default = Factory(meth, takes_self=True) 

2907 

2908 return meth 

2909 

2910 

2911_CountingAttr = _add_eq(_add_repr(_CountingAttr)) 

2912 

2913 

2914class Factory: 

2915 """ 

2916 Stores a factory callable. 

2917 

2918 If passed as the default value to `attrs.field`, the factory is used to 

2919 generate a new value. 

2920 

2921 :param callable factory: A callable that takes either none or exactly one 

2922 mandatory positional argument depending on *takes_self*. 

2923 :param bool takes_self: Pass the partially initialized instance that is 

2924 being initialized as a positional argument. 

2925 

2926 .. versionadded:: 17.1.0 *takes_self* 

2927 """ 

2928 

2929 __slots__ = ("factory", "takes_self") 

2930 

2931 def __init__(self, factory, takes_self=False): 

2932 self.factory = factory 

2933 self.takes_self = takes_self 

2934 

2935 def __getstate__(self): 

2936 """ 

2937 Play nice with pickle. 

2938 """ 

2939 return tuple(getattr(self, name) for name in self.__slots__) 

2940 

2941 def __setstate__(self, state): 

2942 """ 

2943 Play nice with pickle. 

2944 """ 

2945 for name, value in zip(self.__slots__, state): 

2946 setattr(self, name, value) 

2947 

2948 

2949_f = [ 

2950 Attribute( 

2951 name=name, 

2952 default=NOTHING, 

2953 validator=None, 

2954 repr=True, 

2955 cmp=None, 

2956 eq=True, 

2957 order=False, 

2958 hash=True, 

2959 init=True, 

2960 inherited=False, 

2961 ) 

2962 for name in Factory.__slots__ 

2963] 

2964 

2965Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) 

2966 

2967 

2968def make_class( 

2969 name, attrs, bases=(object,), class_body=None, **attributes_arguments 

2970): 

2971 r""" 

2972 A quick way to create a new class called *name* with *attrs*. 

2973 

2974 :param str name: The name for the new class. 

2975 

2976 :param attrs: A list of names or a dictionary of mappings of names to 

2977 `attr.ib`\ s / `attrs.field`\ s. 

2978 

2979 The order is deduced from the order of the names or attributes inside 

2980 *attrs*. Otherwise the order of the definition of the attributes is 

2981 used. 

2982 :type attrs: `list` or `dict` 

2983 

2984 :param tuple bases: Classes that the new class will subclass. 

2985 

2986 :param dict class_body: An optional dictionary of class attributes for the new class. 

2987 

2988 :param attributes_arguments: Passed unmodified to `attr.s`. 

2989 

2990 :return: A new class with *attrs*. 

2991 :rtype: type 

2992 

2993 .. versionadded:: 17.1.0 *bases* 

2994 .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. 

2995 .. versionchanged:: 23.2.0 *class_body* 

2996 """ 

2997 if isinstance(attrs, dict): 

2998 cls_dict = attrs 

2999 elif isinstance(attrs, (list, tuple)): 

3000 cls_dict = {a: attrib() for a in attrs} 

3001 else: 

3002 msg = "attrs argument must be a dict or a list." 

3003 raise TypeError(msg) 

3004 

3005 pre_init = cls_dict.pop("__attrs_pre_init__", None) 

3006 post_init = cls_dict.pop("__attrs_post_init__", None) 

3007 user_init = cls_dict.pop("__init__", None) 

3008 

3009 body = {} 

3010 if class_body is not None: 

3011 body.update(class_body) 

3012 if pre_init is not None: 

3013 body["__attrs_pre_init__"] = pre_init 

3014 if post_init is not None: 

3015 body["__attrs_post_init__"] = post_init 

3016 if user_init is not None: 

3017 body["__init__"] = user_init 

3018 

3019 type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body)) 

3020 

3021 # For pickling to work, the __module__ variable needs to be set to the 

3022 # frame where the class is created. Bypass this step in environments where 

3023 # sys._getframe is not defined (Jython for example) or sys._getframe is not 

3024 # defined for arguments greater than 0 (IronPython). 

3025 with contextlib.suppress(AttributeError, ValueError): 

3026 type_.__module__ = sys._getframe(1).f_globals.get( 

3027 "__name__", "__main__" 

3028 ) 

3029 

3030 # We do it here for proper warnings with meaningful stacklevel. 

3031 cmp = attributes_arguments.pop("cmp", None) 

3032 ( 

3033 attributes_arguments["eq"], 

3034 attributes_arguments["order"], 

3035 ) = _determine_attrs_eq_order( 

3036 cmp, 

3037 attributes_arguments.get("eq"), 

3038 attributes_arguments.get("order"), 

3039 True, 

3040 ) 

3041 

3042 return _attrs(these=cls_dict, **attributes_arguments)(type_) 

3043 

3044 

3045# These are required by within this module so we define them here and merely 

3046# import into .validators / .converters. 

3047 

3048 

3049@attrs(slots=True, hash=True) 

3050class _AndValidator: 

3051 """ 

3052 Compose many validators to a single one. 

3053 """ 

3054 

3055 _validators = attrib() 

3056 

3057 def __call__(self, inst, attr, value): 

3058 for v in self._validators: 

3059 v(inst, attr, value) 

3060 

3061 

3062def and_(*validators): 

3063 """ 

3064 A validator that composes multiple validators into one. 

3065 

3066 When called on a value, it runs all wrapped validators. 

3067 

3068 :param callables validators: Arbitrary number of validators. 

3069 

3070 .. versionadded:: 17.1.0 

3071 """ 

3072 vals = [] 

3073 for validator in validators: 

3074 vals.extend( 

3075 validator._validators 

3076 if isinstance(validator, _AndValidator) 

3077 else [validator] 

3078 ) 

3079 

3080 return _AndValidator(tuple(vals)) 

3081 

3082 

3083def pipe(*converters): 

3084 """ 

3085 A converter that composes multiple converters into one. 

3086 

3087 When called on a value, it runs all wrapped converters, returning the 

3088 *last* value. 

3089 

3090 Type annotations will be inferred from the wrapped converters', if 

3091 they have any. 

3092 

3093 :param callables converters: Arbitrary number of converters. 

3094 

3095 .. versionadded:: 20.1.0 

3096 """ 

3097 

3098 def pipe_converter(val): 

3099 for converter in converters: 

3100 val = converter(val) 

3101 

3102 return val 

3103 

3104 if not converters: 

3105 # If the converter list is empty, pipe_converter is the identity. 

3106 A = typing.TypeVar("A") 

3107 pipe_converter.__annotations__ = {"val": A, "return": A} 

3108 else: 

3109 # Get parameter type from first converter. 

3110 t = _AnnotationExtractor(converters[0]).get_first_param_type() 

3111 if t: 

3112 pipe_converter.__annotations__["val"] = t 

3113 

3114 # Get return type from last converter. 

3115 rt = _AnnotationExtractor(converters[-1]).get_return_type() 

3116 if rt: 

3117 pipe_converter.__annotations__["return"] = rt 

3118 

3119 return pipe_converter