Mercurial > public > mercurial-scm > hg
comparison mercurial/thirdparty/attr/_cmp.py @ 49643:e1c586b9a43c
attr: vendor 22.1.0
The previous version was 5 years old, and pytype 2022.06.30 started complaining
about various uses (e.g. seeing `mercurial.thirdparty.attr._make._CountingAttr`
instead of `bytearray`). Hopefully this helps. Additionally, this has official
python 3.11 support.
The `attrs` package is left out, because it is simply a bunch of *.pyi stubs and
`from attr.X import *`, and that's not how they've been used up to this point.
We'd probably need to customize those anyway to
`from mercurial.thirdparty.attr import *`.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Mon, 21 Nov 2022 15:04:42 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
49642:7e6f3c69c0fb | 49643:e1c586b9a43c |
---|---|
1 # SPDX-License-Identifier: MIT | |
2 | |
3 | |
4 import functools | |
5 import types | |
6 | |
7 from ._make import _make_ne | |
8 | |
9 | |
10 _operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} | |
11 | |
12 | |
13 def cmp_using( | |
14 eq=None, | |
15 lt=None, | |
16 le=None, | |
17 gt=None, | |
18 ge=None, | |
19 require_same_type=True, | |
20 class_name="Comparable", | |
21 ): | |
22 """ | |
23 Create a class that can be passed into `attr.ib`'s ``eq``, ``order``, and | |
24 ``cmp`` arguments to customize field comparison. | |
25 | |
26 The resulting class will have a full set of ordering methods if | |
27 at least one of ``{lt, le, gt, ge}`` and ``eq`` are provided. | |
28 | |
29 :param Optional[callable] eq: `callable` used to evaluate equality | |
30 of two objects. | |
31 :param Optional[callable] lt: `callable` used to evaluate whether | |
32 one object is less than another object. | |
33 :param Optional[callable] le: `callable` used to evaluate whether | |
34 one object is less than or equal to another object. | |
35 :param Optional[callable] gt: `callable` used to evaluate whether | |
36 one object is greater than another object. | |
37 :param Optional[callable] ge: `callable` used to evaluate whether | |
38 one object is greater than or equal to another object. | |
39 | |
40 :param bool require_same_type: When `True`, equality and ordering methods | |
41 will return `NotImplemented` if objects are not of the same type. | |
42 | |
43 :param Optional[str] class_name: Name of class. Defaults to 'Comparable'. | |
44 | |
45 See `comparison` for more details. | |
46 | |
47 .. versionadded:: 21.1.0 | |
48 """ | |
49 | |
50 body = { | |
51 "__slots__": ["value"], | |
52 "__init__": _make_init(), | |
53 "_requirements": [], | |
54 "_is_comparable_to": _is_comparable_to, | |
55 } | |
56 | |
57 # Add operations. | |
58 num_order_functions = 0 | |
59 has_eq_function = False | |
60 | |
61 if eq is not None: | |
62 has_eq_function = True | |
63 body["__eq__"] = _make_operator("eq", eq) | |
64 body["__ne__"] = _make_ne() | |
65 | |
66 if lt is not None: | |
67 num_order_functions += 1 | |
68 body["__lt__"] = _make_operator("lt", lt) | |
69 | |
70 if le is not None: | |
71 num_order_functions += 1 | |
72 body["__le__"] = _make_operator("le", le) | |
73 | |
74 if gt is not None: | |
75 num_order_functions += 1 | |
76 body["__gt__"] = _make_operator("gt", gt) | |
77 | |
78 if ge is not None: | |
79 num_order_functions += 1 | |
80 body["__ge__"] = _make_operator("ge", ge) | |
81 | |
82 type_ = types.new_class( | |
83 class_name, (object,), {}, lambda ns: ns.update(body) | |
84 ) | |
85 | |
86 # Add same type requirement. | |
87 if require_same_type: | |
88 type_._requirements.append(_check_same_type) | |
89 | |
90 # Add total ordering if at least one operation was defined. | |
91 if 0 < num_order_functions < 4: | |
92 if not has_eq_function: | |
93 # functools.total_ordering requires __eq__ to be defined, | |
94 # so raise early error here to keep a nice stack. | |
95 raise ValueError( | |
96 "eq must be define is order to complete ordering from " | |
97 "lt, le, gt, ge." | |
98 ) | |
99 type_ = functools.total_ordering(type_) | |
100 | |
101 return type_ | |
102 | |
103 | |
104 def _make_init(): | |
105 """ | |
106 Create __init__ method. | |
107 """ | |
108 | |
109 def __init__(self, value): | |
110 """ | |
111 Initialize object with *value*. | |
112 """ | |
113 self.value = value | |
114 | |
115 return __init__ | |
116 | |
117 | |
118 def _make_operator(name, func): | |
119 """ | |
120 Create operator method. | |
121 """ | |
122 | |
123 def method(self, other): | |
124 if not self._is_comparable_to(other): | |
125 return NotImplemented | |
126 | |
127 result = func(self.value, other.value) | |
128 if result is NotImplemented: | |
129 return NotImplemented | |
130 | |
131 return result | |
132 | |
133 method.__name__ = "__%s__" % (name,) | |
134 method.__doc__ = "Return a %s b. Computed by attrs." % ( | |
135 _operation_names[name], | |
136 ) | |
137 | |
138 return method | |
139 | |
140 | |
141 def _is_comparable_to(self, other): | |
142 """ | |
143 Check whether `other` is comparable to `self`. | |
144 """ | |
145 for func in self._requirements: | |
146 if not func(self, other): | |
147 return False | |
148 return True | |
149 | |
150 | |
151 def _check_same_type(self, other): | |
152 """ | |
153 Return True if *self* and *other* are of the same type, False otherwise. | |
154 """ | |
155 return other.value.__class__ is self.value.__class__ |