Skip to content

Commit 4013041

Browse files
committed
Implements #2, add symmetric equality operators
1 parent e546578 commit 4013041

File tree

5 files changed

+137
-16
lines changed

5 files changed

+137
-16
lines changed

doc/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ sphinxcontrib-htmlhelp==2.0.0; python_version >= "3.5"
66
sphinxcontrib-jsmath==1.0.1; python_version >= "3.5"
77
sphinxcontrib-qthelp==1.0.3; python_version >= "3.5"
88
sphinxcontrib-serializinghtml==1.1.5; python_version >= "3.5"
9-
enum-properties==1.0.2
9+
enum-properties==1.1.0

doc/source/usage.rst

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ property symmetry. To mark a property as symmetric, use
6868
class Color(EnumProperties, s('rgb'), s('hex', case_fold=True)):
6969
7070
# name value rgb hex
71-
RED = auto(), (1, 0, 0), 'ff0000'
72-
GREEN = auto(), (0, 1, 0), '00ff00'
73-
BLUE = auto(), (0, 0, 1), '0000ff'
71+
RED = auto(), (1, 0, 0), '0xff0000'
72+
GREEN = auto(), (0, 1, 0), '0x00ff00'
73+
BLUE = auto(), (0, 0, 1), '0x0000ff'
7474
75-
Color.RED == Color((1, 0, 0)) == Color('FF0000') == Color('ff0000')
75+
Color.RED == Color((1, 0, 0)) == Color('0xFF0000') == Color('0xff0000')
7676
7777
Symmetric string properties are by default case sensitive. To mark a property
7878
as case insensitive, use the `case_fold=True` parameter on the
@@ -88,7 +88,13 @@ equivalent to this:
8888
from enum_properties import EnumPropertiesMeta, SymmetricMixin, s
8989
from enum import Enum, auto
9090
91-
class Color(SymmetricMixin, Enum, s('rgb'), s('hex', case_fold=True), metaclass=EnumPropertiesMeta):
91+
class Color(
92+
SymmetricMixin,
93+
Enum,
94+
s('rgb'),
95+
s('hex', case_fold=True),
96+
metaclass=EnumPropertiesMeta
97+
):
9298
...
9399
94100
.. warning::
@@ -105,7 +111,15 @@ value. Tuples are hashable and are treated as singular property values. See the
105111
enumeration values from objects. Type coercion to all potential value types
106112
will be attempted before giving up. For instance, if we have a color object
107113
that is coercible to a string hex value we could instantiate our Color
108-
enumeration from it:
114+
enumeration from it and perform equality comparisons:
115+
116+
.. code:: python
117+
118+
# str(hex(16711680)) == '0xff0000'
119+
Color.RED == Color(hex(16711680)) == hex(16711680)
120+
Color.RED == (1, 0, 0)
121+
Color.RED != (0, 1, 0)
122+
Color.RED == '0xFF0000'
109123
110124
111125
Conflicts and Precedence

enum_properties/__init__.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from collections.abc import Hashable
2121
from enum import Enum, EnumMeta
2222

23-
VERSION = (1, 0, 2)
23+
VERSION = (1, 1, 0)
2424

2525
__title__ = 'Enum Properties'
2626
__version__ = '.'.join(str(i) for i in VERSION)
@@ -111,6 +111,19 @@ class SymmetricMixin: # pylint: disable=R0903
111111
_ep_isymmetric_map_ = {}
112112
_symmetric_builtins_ = ['name']
113113

114+
def __eq__(self, value):
115+
"""Symmetric equality - try to coerce value before failure"""
116+
if isinstance(value, self.__class__):
117+
return self.value == value.value
118+
try:
119+
return self.value == self.__class__(value).value
120+
except (ValueError, TypeError):
121+
return False
122+
123+
def __ne__(self, value):
124+
"""Symmetric inequality is the inverse of symmetric equality"""
125+
return not self.__eq__(value)
126+
114127
@classmethod
115128
def _missing_(cls, value):
116129
"""

enum_properties/tests/tests.py

Lines changed: 101 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,33 @@ class Color(
107107
self.assertEqual(Color.RED, Color('RED'))
108108
self.assertEqual(Color.RED, Color['RED'])
109109
self.assertEqual(Color.RED, Color(1))
110+
111+
# test symmetric equality
112+
self.assertEqual(Color.RED, (1, 0, 0))
113+
self.assertEqual(Color.RED, 'ff0000')
114+
self.assertEqual(Color.RED, 'FF0000')
115+
self.assertEqual(Color.RED, 'RED')
116+
self.assertEqual(Color.RED, 1)
117+
118+
self.assertTrue(Color.RED != (1, 1, 0))
119+
self.assertTrue(Color.RED != '00ff00')
120+
self.assertTrue(Color.RED != 'EE0000')
121+
self.assertTrue(Color.RED != 'GRAY')
122+
self.assertTrue(Color.RED != 3)
123+
124+
self.assertFalse(Color.RED != (1, 0, 0))
125+
self.assertFalse(Color.RED != 'ff0000')
126+
self.assertFalse(Color.RED != 'FF0000')
127+
self.assertFalse(Color.RED != 'RED')
128+
self.assertFalse(Color.RED != 1)
129+
130+
self.assertNotEqual(Color.RED, (1, 1, 0))
131+
self.assertNotEqual(Color.RED, 'EE0000')
132+
self.assertNotEqual(Color.RED, '00ff00')
133+
self.assertNotEqual(Color.RED, 'GREEN')
134+
self.assertNotEqual(Color.RED, 5)
135+
############################
136+
110137
self.assertEqual(Color.RED.value, 1)
111138
self.assertEqual(Color.RED.spanish, 'Roja')
112139
self.assertEqual(Color.RED.hex, 'ff0000')
@@ -125,6 +152,13 @@ class Color(
125152
self.assertRaises(ValueError, Color, 'Verde')
126153
self.assertRaises(ValueError, Color, 'Green')
127154

155+
# test symmetric equality
156+
self.assertEqual(Color.GREEN, (0, 1, 0))
157+
self.assertEqual(Color.GREEN, '00ff00')
158+
self.assertEqual(Color.GREEN, '00FF00')
159+
self.assertEqual(Color.GREEN, 'GREEN')
160+
self.assertEqual(Color.GREEN, 2)
161+
self.assertNotEqual(Color.GREEN, (1, 1, 0))
128162

129163
self.assertEqual(Color.BLUE, Color((0, 0, 1)))
130164
self.assertEqual(Color.BLUE, Color('0000ff'))
@@ -133,10 +167,20 @@ class Color(
133167
self.assertEqual(Color.BLUE, Color['BLUE'])
134168
self.assertEqual(Color.BLUE, Color(3))
135169
self.assertEqual(Color.BLUE.value, 3)
170+
self.assertEqual(Color.BLUE, 3)
136171
self.assertEqual(Color.BLUE.spanish, 'Azul')
137172
self.assertEqual(Color.BLUE.hex, '0000ff')
138173
self.assertRaises(ValueError, Color, 'Azul')
139174
self.assertRaises(ValueError, Color, 'Blue')
175+
176+
# test symmetric equality
177+
self.assertEqual(Color.BLUE, (0, 0, 1))
178+
self.assertEqual(Color.BLUE, '0000ff')
179+
self.assertEqual(Color.BLUE, '0000FF')
180+
self.assertEqual(Color.BLUE, 'BLUE')
181+
self.assertEqual(Color.BLUE, 3)
182+
self.assertNotEqual(Color.BLUE, '00EE00')
183+
140184
else: # pragma: no cover
141185
def test_properties_and_symmetry(self):
142186

@@ -162,6 +206,32 @@ class Color(
162206
self.assertRaises(ValueError, Color, 'Roja')
163207
self.assertRaises(ValueError, Color, 'Red')
164208

209+
# test symmetric equality
210+
self.assertEqual(Color.RED, (1, 0, 0))
211+
self.assertEqual(Color.RED, 'ff0000')
212+
self.assertEqual(Color.RED, 'FF0000')
213+
self.assertEqual(Color.RED, 'RED')
214+
self.assertEqual(Color.RED, 1)
215+
216+
self.assertTrue(Color.RED != (1, 1, 0))
217+
self.assertTrue(Color.RED != '00ff00')
218+
self.assertTrue(Color.RED != 'EE0000')
219+
self.assertTrue(Color.RED != 'GRAY')
220+
self.assertTrue(Color.RED != 3)
221+
222+
self.assertFalse(Color.RED != (1, 0, 0))
223+
self.assertFalse(Color.RED != 'ff0000')
224+
self.assertFalse(Color.RED != 'FF0000')
225+
self.assertFalse(Color.RED != 'RED')
226+
self.assertFalse(Color.RED != 1)
227+
228+
self.assertNotEqual(Color.RED, (1, 1, 0))
229+
self.assertNotEqual(Color.RED, 'EE0000')
230+
self.assertNotEqual(Color.RED, '00ff00')
231+
self.assertNotEqual(Color.RED, 'GREEN')
232+
self.assertNotEqual(Color.RED, 5)
233+
############################
234+
165235
self.assertEqual(Color.GREEN, Color((0, 1, 0)))
166236
self.assertEqual(Color.GREEN, Color('00ff00'))
167237
self.assertEqual(Color.GREEN, Color('00FF00'))
@@ -174,6 +244,14 @@ class Color(
174244
self.assertRaises(ValueError, Color, 'Verde')
175245
self.assertRaises(ValueError, Color, 'Green')
176246

247+
# test symmetric equality
248+
self.assertEqual(Color.GREEN, (0, 1, 0))
249+
self.assertEqual(Color.GREEN, '00ff00')
250+
self.assertEqual(Color.GREEN, '00FF00')
251+
self.assertEqual(Color.GREEN, 'GREEN')
252+
self.assertEqual(Color.GREEN, 2)
253+
self.assertNotEqual(Color.GREEN, 'EE0000')
254+
177255
self.assertEqual(Color.BLUE, Color((0, 0, 1)))
178256
self.assertEqual(Color.BLUE, Color('0000ff'))
179257
self.assertEqual(Color.BLUE, Color('0000FF'))
@@ -186,6 +264,14 @@ class Color(
186264
self.assertRaises(ValueError, Color, 'Azul')
187265
self.assertRaises(ValueError, Color, 'Blue')
188266

267+
# test symmetric equality
268+
self.assertEqual(Color.BLUE, (0, 0, 1))
269+
self.assertEqual(Color.BLUE, '0000ff')
270+
self.assertEqual(Color.BLUE, '0000FF')
271+
self.assertEqual(Color.BLUE, 'BLUE')
272+
self.assertEqual(Color.BLUE, 3)
273+
self.assertNotEqual(Color.BLUE, (0, 1, 1))
274+
189275
def test_property_lists(self):
190276

191277
class Color(
@@ -598,19 +684,27 @@ class Color(EnumProperties, p('rgb'), p('hex')):
598684
self.assertEqual(Color.GREEN.hex, '00ff00')
599685
self.assertEqual(Color.BLUE.hex, '0000ff')
600686

601-
class Color(EnumProperties, s('rgb'), s('hex')):
687+
class Color(EnumProperties, s('rgb'), s('hex', case_fold=True)):
602688

603-
RED = auto(), (1, 0, 0), 'ff0000'
604-
GREEN = auto(), (0, 1, 0), '00ff00'
605-
BLUE = auto(), (0, 0, 1), '0000ff'
689+
RED = auto(), (1, 0, 0), '0xff0000'
690+
GREEN = auto(), (0, 1, 0), '0x00ff00'
691+
BLUE = auto(), (0, 0, 1), '0x0000ff'
606692

607693
self.assertEqual(Color.RED, Color((1, 0, 0)))
608694
self.assertEqual(Color.GREEN, Color((0, 1, 0)))
609695
self.assertEqual(Color.BLUE, Color((0, 0, 1)))
610696

611-
self.assertEqual(Color.RED, Color('ff0000'))
612-
self.assertEqual(Color.GREEN, Color('00ff00'))
613-
self.assertEqual(Color.BLUE, Color('0000ff'))
697+
self.assertEqual(Color.RED, Color('0xff0000'))
698+
self.assertEqual(Color.GREEN, Color('0x00ff00'))
699+
self.assertEqual(Color.BLUE, Color('0x0000ff'))
700+
701+
self.assertTrue(Color.RED == Color(hex(16711680)) == hex(16711680) == '0xff0000' == Color.RED)
702+
self.assertTrue(Color.RED == (1, 0, 0))
703+
self.assertTrue((1, 0, 0) == Color.RED)
704+
self.assertTrue(Color.RED != (0, 1, 0))
705+
self.assertTrue((0, 1, 0) != Color.RED)
706+
self.assertTrue(Color.RED == '0xFF0000')
707+
self.assertTrue('0xFF0000' == Color.RED)
614708

615709
class MapBoxStyle(
616710
EnumProperties,

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "enum-properties"
3-
version = "1.0.2"
3+
version = "1.1.0"
44
description = "Add properties to Python enumeration values with a simple declarative syntax."
55
authors = ["Brian Kohan <[email protected]>"]
66
license = "MIT"

0 commit comments

Comments
 (0)