Hello community,

here is the log from the commit of package python-aenum for openSUSE:Factory 
checked in at 2019-12-12 23:17:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-aenum (Old)
 and      /work/SRC/openSUSE:Factory/.python-aenum.new.4691 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-aenum"

Thu Dec 12 23:17:57 2019 rev:4 rq:755836 version:2.2.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-aenum/python-aenum.changes        
2019-07-30 12:39:02.866937105 +0200
+++ /work/SRC/openSUSE:Factory/.python-aenum.new.4691/python-aenum.changes      
2019-12-12 23:18:03.934214008 +0100
@@ -1,0 +2,6 @@
+Wed Dec 11 11:56:29 UTC 2019 - Tomáš Chvátal <tchva...@suse.com>
+
+- Update to 2.2.3:
+  * Various minor fixes
+
+-------------------------------------------------------------------

Old:
----
  aenum-2.2.1.tar.gz

New:
----
  aenum-2.2.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-aenum.spec ++++++
--- /var/tmp/diff_new_pack.IjvYEy/_old  2019-12-12 23:18:05.342213882 +0100
+++ /var/tmp/diff_new_pack.IjvYEy/_new  2019-12-12 23:18:05.354213880 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-aenum
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,12 +18,12 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-aenum
-Version:        2.2.1
+Version:        2.2.3
 Release:        0
 Summary:        Advanced Enumerations, NamedTuples, and NamedConstants
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
-Url:            https://bitbucket.org/stoneleaf/aenum
+URL:            https://bitbucket.org/stoneleaf/aenum
 Source:         
https://files.pythonhosted.org/packages/source/a/aenum/aenum-%{version}.tar.gz
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes

++++++ aenum-2.2.1.tar.gz -> aenum-2.2.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aenum-2.2.1/PKG-INFO new/aenum-2.2.3/PKG-INFO
--- old/aenum-2.2.1/PKG-INFO    2019-07-24 23:22:43.000000000 +0200
+++ new/aenum-2.2.3/PKG-INFO    2019-11-10 02:43:09.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: aenum
-Version: 2.2.1
+Version: 2.2.3
 Summary: Advanced Enumerations (compatible with Python's stdlib Enum), 
NamedTuples, and NamedConstants
 Home-page: https://bitbucket.org/stoneleaf/aenum
 Author: Ethan Furman
@@ -46,6 +46,9 @@
         
         - enum: helper class for creating members with keywords
         
+        - enum_property: property to enable enum members to have same named 
attributes
+                         (e.g. `name` and `value`)
+        
         - export: helper to insert Enum members into a namespace (usually 
globals())
         
         - extend_enum: add new members to enumerations after creation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aenum-2.2.1/aenum/CHANGES 
new/aenum-2.2.3/aenum/CHANGES
--- old/aenum-2.2.1/aenum/CHANGES       2019-07-24 23:22:37.000000000 +0200
+++ new/aenum-2.2.3/aenum/CHANGES       2019-11-10 02:43:02.000000000 +0100
@@ -1,3 +1,48 @@
+2.2.3
+=====
+
+use member type's methods __str__, __repr__, __format__, and
+__reduce_ex__ if directly assigned in Enum class body; i.e.:
+
+    --> class Color(str, Enum):
+    ...     red = 'red'
+    ...     green = 'green'
+    ...     blue = 'blue'
+    ...     __str__ = str.__str__
+
+    --> print(repr(Color.green))
+    <Color.green: 'green'>
+
+    --> print(Color.green)
+    green
+
+
+2.2.2
+=====
+
+replace _RouteClassAttributeToGetattr with enum_property (it is still
+available as an alias)
+
+support constant() and auto() being used together:
+
+    --> class Fruit(Flag):
+    ...    _order_ = 'apple banana lemon orange'
+    ...    apple = auto()
+    ...    banana = auto()
+    ...    lemon = auto()
+    ...    orange = auto()
+    ...    CitrusTypes = constant(lemon | orange)
+
+    --> list(Fruit)
+    [Fruit.apple, Fruit.banana, Fruit.lemon, Fruit.orange]
+
+    --> list(Fruit.CitrusTypes)
+    [Fruit.orange, Fruit.lemon]
+
+    --> Fruit.orange in Fruit.CitrusTypes
+    True
+
+
 2.2.1
 =====
 
@@ -19,14 +64,14 @@
 
 allow Enum name use while constructing Enum (Python 3.4+ only)
 
-    class Color(Enum):
-        _order_ = 'BLACK WHITE'
-        BLACK = Color('black', '#000')
-        WHITE = Color('white', '#fff')
-
-        def __init__(self, label, hex):
-            self.label = label
-            self.hex = hex
+    --> class Color(Enum):
+    ...     _order_ = 'BLACK WHITE'
+    ...     BLACK = Color('black', '#000')
+    ...     WHITE = Color('white', '#fff')
+    ...     #
+    ...     def __init__(self, label, hex):
+    ...         self.label = label
+    ...         self.hex = hex
 
 
 2.2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aenum-2.2.1/aenum/__init__.py 
new/aenum-2.2.3/aenum/__init__.py
--- old/aenum-2.2.1/aenum/__init__.py   2019-07-24 23:22:37.000000000 +0200
+++ new/aenum-2.2.3/aenum/__init__.py   2019-11-10 02:43:03.000000000 +0100
@@ -40,13 +40,13 @@
         'Enum', 'IntEnum', 'AutoNumberEnum', 'OrderedEnum', 'UniqueEnum',
         'Flag', 'IntFlag',
         'AutoNumber', 'MultiValue', 'NoAlias', 'Unique',
-        'enum', 'extend_enum', 'unique',
+        'enum', 'extend_enum', 'unique', 'enum_property',
         'NamedTuple', 'SqliteEnum',
         ]
 if sqlite3 is None:
     __all__.remove('SqliteEnum')
 
-version = 2, 2, 1
+version = 2, 2, 3
 
 try:
     any
@@ -97,23 +97,32 @@
 # will be exported later
 AutoValue = AutoNumber = MultiValue = NoAlias = Unique = None
 
-class _RouteClassAttributeToGetattr(object):
-    """Route attribute access on a class to __getattr__.
-
-    This is a descriptor, used to define attributes that act differently when
-    accessed through an instance and through a class.  Instance access remains
-    normal, but access to an attribute through a class will be routed to the
-    class's __getattr__ method; this is done by raising AttributeError.
+class enum_property(object):
+    """
+    This is a descriptor, used to define attributes that act differently
+    when accessed through an enum member and through an enum class.
+    Instance access is the same as property(), but access to an attribute
+    through the enum class will look in the class' _member_map_.
     """
+
     name = None  # set by metaclass
 
-    def __init__(self, fget=None):
+    def __init__(self, fget=None, doc=None):
         self.fget = fget
+        self.__doc__ = doc or fget.__doc__
+
+    def __call__(self, func, doc=None):
+        self.fget = func
+        self.__doc__ = self.__doc__ or doc or func.__doc__
 
     def __get__(self, instance, ownerclass=None):
         if instance is None:
-            raise AttributeError()
-        return self.fget(instance)
+            try:
+                return ownerclass._member_map_[self.name]
+            except KeyError:
+                raise AttributeError(self.name)
+        else:
+            return self.fget(instance)
 
     def __set__(self, instance, value):
         raise AttributeError("can't set attribute %r" % (self.name, ))
@@ -121,6 +130,7 @@
     def __delete__(self, instance):
         raise AttributeError("can't delete attribute %r" % (self.name, ))
 
+_RouteClassAttributeToGetattr = enum_property
 
 class NonMember(object):
     """
@@ -1391,7 +1401,14 @@
                     _init_.pop(0)
                 self._init = _init_
             elif key == '_generate_next_value_':
-                setattr(self, '_generate_next_value', value)
+                if isinstance(value, staticmethod):
+                    gnv = value.__func__
+                elif isinstance(value, classmethod):
+                    raise TypeError('_generate_next_value should be a 
staticmethod, not a classmethod')
+                else:
+                    gnv = value
+                    value = staticmethod(value)
+                setattr(self, '_generate_next_value', gnv)
                 self._auto_args = _check_auto_args(value)
         elif _is_dunder(key):
             if key == '__order__':
@@ -1444,8 +1461,6 @@
                 source_values = len(value)
                 if target_values != source_values:
                     gnv = self._generate_next_value
-                    if isinstance(gnv, staticmethod):
-                        gnv = gnv.__func__
                     if self._auto_args:
                         value = gnv(
                                 key, 1,
@@ -1518,6 +1533,12 @@
                 else:
                     if value.value == _auto_null:
                         gnv = self._generate_next_value
+                        prev_values = []
+                        for v in self._last_values:
+                            if isinstance(v, auto):
+                                prev_values.append(v.value)
+                            else:
+                                prev_values.append(v)
                         if isinstance(gnv, staticmethod):
                             gnv = gnv.__func__
                         if self._auto_args:
@@ -1525,7 +1546,7 @@
                                     key,
                                     1,
                                     len(self._member_names),
-                                    self._last_values[:],
+                                    prev_values,
                                     *value.args,
                                     **value.kwds
                                     )
@@ -1534,9 +1555,8 @@
                                     key,
                                     1,
                                     len(self._member_names),
-                                    self._last_values[:],
+                                    prev_values,
                                     )
-                    value = value.value
             elif isinstance(value, enum):
                 value.name = key
             else:
@@ -1754,7 +1774,7 @@
         for name, obj in clsdict.items():
             if isinstance(obj, nonmember):
                 dict.__setitem__(clsdict, name, obj.value)
-            elif isinstance(obj, _RouteClassAttributeToGetattr):
+            elif isinstance(obj, enum_property):
                 obj.name = name
         # check for illegal enum names (any others?)
         invalid_names = set(enum_members) & set(['mro', ''])
@@ -1787,6 +1807,8 @@
             __new__ = enum_class.__new__
         for member_name in clsdict._member_names:
             value = enum_members[member_name]
+            if isinstance(value, auto):
+                value = value.value
             kwds = {}
             new_args = ()
             init_args = ()
@@ -1877,9 +1899,19 @@
                                 (cls, ';  '.join(message))
                             )
             # performance boost for any member that would not shadow
-            # a DynamicClassAttribute (aka _RouteClassAttributeToGetattr)
+            # an enum_property
             if member_name not in base_attributes:
                 setattr(enum_class, member_name, enum_member)
+            else:
+                # otherwise make sure the thing being shadowed /is/ an
+                # enum_property
+                for parent in enum_class.mro()[1:]:
+                    if member_name in parent.__dict__:
+                        obj = parent.__dict__[member_name]
+                        if not isinstance(obj, enum_property):
+                            raise TypeError('%r already used: %r' % 
(member_name, obj))
+                        # we're good
+                        break
             # now add to _member_map_
             enum_class._member_map_[member_name] = enum_member
             values = (value, ) + extra_mv_args
@@ -1900,8 +1932,10 @@
                     enum_class._value2member_map_[value] = enum_member
                 except TypeError:
                     enum_class._value2member_seq_ += ((value, enum_member), )
-
-
+        # check for constants with auto() values
+        for k, v in enum_class.__dict__.items():
+            if isinstance(v, constant) and isinstance(v.value, auto):
+                v.value = enum_class(v.value.value)
         # If a custom type is mixed into the Enum, and it does not know how
         # to pickle itself, pickle.dumps will succeed but pickle.loads will
         # fail.  Rather than have the error show up later and possibly far
@@ -1921,10 +1955,14 @@
                     _make_class_unpicklable(enum_class)
                     unpicklable = True
 
-
         # double check that repr and friends are not the mixin's or various
         # things break (such as pickle)
+
         for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
+            enum_class_method = enum_class.__dict__.get(name, None)
+            if enum_class_method:
+                # class has defined/imported/copied the method
+                continue
             class_method = getattr(enum_class, name)
             obj_method = getattr(member_type, name, None)
             enum_method = getattr(first_enum, name, None)
@@ -1933,7 +1971,6 @@
                     continue
                 setattr(enum_class, name, enum_method)
 
-
         # method resolution and int's are not playing nice
         # Python's less than 2.6 use __cmp__
 
@@ -1977,7 +2014,7 @@
                 # create ordered list for comparison
                 _order_ = [m.name for m in sorted(enum_class, key=_order_)]
             if _order_ != enum_class._member_names_:
-                raise TypeError('member order does not match _order_')
+                raise TypeError('member order does not match _order_: %r %r' % 
(enum_class._member_names_, enum_class._member_map_.items()))
         return enum_class
 
     def __bool__(cls):
@@ -2039,21 +2076,6 @@
         """
         return cls._member_map_.copy()
 
-    def __getattr__(cls, name):
-        """Return the enum member matching `name`
-
-        We use __getattr__ instead of descriptors or inserting into the enum
-        class' __dict__ in order to support `name` and `value` being both
-        properties for enum members (which live in the class' __dict__) and
-        enum members themselves.
-        """
-        if _is_dunder(name):
-            raise AttributeError(name)
-        try:
-            return cls._member_map_[name]
-        except KeyError:
-            raise AttributeError(name)
-
     def __getitem__(cls, name):
         try:
             return cls._member_map_[name]
@@ -2569,29 +2591,29 @@
 temp_enum_dict['_convert'] = classmethod(_convert)
 del _convert
 
-# _RouteClassAttributeToGetattr is used to provide access to the `name`
-# and `value` properties of enum members while keeping some measure of
-# protection from modification, while still allowing for an enumeration
-# to have members named `name` and `value`.  This works because enumeration
-# members are not set directly on the enum class -- __getattr__ is
-# used to look them up.
+# enum_property is used to provide access to the `name`, `value', etc.,
+# properties of enum members while keeping some measure of protection
+# from modification, while still allowing for an enumeration to have
+# members named `name`, `value`, etc..  This works because enumeration
+# members are not set directly on the enum class -- enum_property will
+# look them up in _member_map_.
 #
-# This method is also very slow, so EnumMeta will add members directly to the
-# Enum class if it won't shadow other instance attributes
+# This method is also very slow, so EnumMeta will add members directlyi
+# to the Enum class if it won't shadow other instance attributes
 
-@_RouteClassAttributeToGetattr
+@enum_property
 def name(self):
     return self._name_
 temp_enum_dict['name'] = name
 del name
 
-@_RouteClassAttributeToGetattr
+@enum_property
 def value(self):
     return self._value_
 temp_enum_dict['value'] = value
 del value
 
-@_RouteClassAttributeToGetattr
+@enum_property
 def values(self):
     return self._values_
 temp_enum_dict['values'] = values
@@ -2794,14 +2816,27 @@
     if _no_alias_:
         # unless NoAlias was specified
         _member_names_.append(name)
+        _member_map_[name] = new_member
     else:
         for canonical_member in _member_map_.values():
             _values_ = getattr(canonical_member, '_values_', 
[canonical_member._value_])
             for canonical_value in _values_:
                 if canonical_value == new_member._value_:
+                    # name is an alias
                     if _unique_ or _multi_value_:
                         # aliases not allowed if Unique specified
                         raise ValueError('%s is a duplicate of %s' % (name, 
canonical_member.name))
+                    if name not in base_attributes:
+                        setattr(enumeration, name, canonical_member)
+                    else:
+                        # check type of name
+                        for parent in enumeration.mro()[1:]:
+                            if name in parent.__dict__:
+                                obj = parent.__dict__[name]
+                                if not isinstance(obj, enum_property):
+                                    raise TypeError('%r already used: %r' % 
(name, obj))
+                                break
+                    # Aliases don't appear in member names (only in 
__members__ and _member_map_).
                     _member_map_[new_member._name_] = canonical_member
                     new_member = canonical_member
                     is_alias = True
@@ -2809,34 +2844,41 @@
             if is_alias:
                 break
         else:
-            # Aliases don't appear in member names (only in __members__).
+            # not an alias
+            values = (value, ) + more_values
+            new_member._values_ = values
+            for value in (value, ) + more_values:
+                # first check if value has already been used
+                if _multi_value_ and (
+                        value in _value2member_map_
+                        or any(v == value for (v, m) in _value2member_seq_)
+                        ):
+                    raise ValueError('%r has already been used' % (value, ))
+                try:
+                    # This may fail if value is not hashable. We can't add the 
value
+                    # to the map, and by-value lookups for this value will be
+                    # linear.
+                    if _no_alias_:
+                        raise TypeError('cannot use dict to store value')
+                    _value2member_map_[value] = new_member
+                except TypeError:
+                    _value2member_seq_ += ((value, new_member), )
+            if name not in base_attributes:
+                setattr(enumeration, name, new_member)
+            else:
+                # check type of name
+                for parent in enumeration.mro()[1:]:
+                    if name in parent.__dict__:
+                        obj = parent.__dict__[name]
+                        if not isinstance(obj, enum_property):
+                            raise TypeError('%r already used: %r' % (name, 
obj))
+                        break
             _member_names_.append(name)
-    if not is_alias:
-        values = (value, ) + more_values
-        new_member._values_ = values
-        for value in (value, ) + more_values:
-            # first check if value has already been used
-            if _multi_value_ and (
-                    value in _value2member_map_
-                    or any(v == value for (v, m) in _value2member_seq_)
-                    ):
-                raise ValueError('%r has already been used' % (value, ))
+            _member_map_[name] = new_member
             try:
-                # This may fail if value is not hashable. We can't add the 
value
-                # to the map, and by-value lookups for this value will be
-                # linear.
-                if _no_alias_:
-                    raise TypeError('cannot use dict to store value')
                 _value2member_map_[value] = new_member
             except TypeError:
-                _value2member_seq_ += ((value, new_member), )
-        if name not in base_attributes:
-            setattr(enumeration, name, new_member)
-        _member_map_[name] = new_member
-        try:
-            _value2member_map_[value] = new_member
-        except TypeError:
-            pass
+                pass
 
 def unique(enumeration):
     """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aenum-2.2.1/aenum/doc/aenum.pdf 
new/aenum-2.2.3/aenum/doc/aenum.pdf
--- old/aenum-2.2.1/aenum/doc/aenum.pdf 2019-07-24 23:22:43.000000000 +0200
+++ new/aenum-2.2.3/aenum/doc/aenum.pdf 2019-11-10 02:43:09.000000000 +0100
@@ -357,7 +357,7 @@
 endobj
 45 0 obj
 <<
-/Author () /CreationDate (D:20190724142242+08'00') /Creator (\(unspecified\)) 
/Keywords () /ModDate (D:20190724142242+08'00') /Producer (ReportLab PDF 
Library - www.reportlab.com) 
+/Author () /CreationDate (D:20191109174308+08'00') /Creator (\(unspecified\)) 
/Keywords () /ModDate (D:20191109174308+08'00') /Producer (ReportLab PDF 
Library - www.reportlab.com) 
   /Subject (\(unspecified\)) /Title (aenum --- support for advanced 
enumerations, namedtuples, and constants) /Trapped /False
 >>
 endobj
@@ -4882,7 +4882,7 @@
 trailer
 <<
 /ID 
-[<af725aae5768dc69b62d14f1504864a7><af725aae5768dc69b62d14f1504864a7>]
+[<82bdf423791213d84b7c3b54f91ad929><82bdf423791213d84b7c3b54f91ad929>]
 % ReportLab generated PDF document -- digest (http://www.reportlab.com)
 
 /Info 45 0 R
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aenum-2.2.1/aenum/test.py 
new/aenum-2.2.3/aenum/test.py
--- old/aenum-2.2.1/aenum/test.py       2019-07-24 23:22:37.000000000 +0200
+++ new/aenum-2.2.3/aenum/test.py       2019-11-10 02:43:02.000000000 +0100
@@ -1990,6 +1990,33 @@
             yellow = 6
         self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
 
+    def test_extending4(self):
+        class hohum(object):
+            def cyan(self):
+                "cyanize a color"
+                return self.value
+        with self.assertRaises(TypeError):
+            class Color(hohum, Enum):
+                red = 1
+                green = 2
+                blue = 3
+                cyan = 4
+
+    def test_extending5(self):
+        class Color(Enum):
+            _order_ = 'red green blue value'
+            red = 1
+            green = 2
+            blue = 3
+            value = 4
+        self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, 
Color.value])
+        self.assertEqual(Color.value.name, 'value')
+        self.assertEqual(Color.value.value, 4)
+        self.assertTrue(Color.value in Color)
+        self.assertEqual(Color(4), Color.value)
+        self.assertEqual(Color['value'], Color.value)
+        self.assertEqual(Color.red.value, 1)
+
     if StdlibEnum is not None:
 
         def test_extend_enum_stdlib(self):
@@ -2068,6 +2095,20 @@
         self.assertEqual(len(Color), 4)
         self.assertEqual(Color.red.value, 1)
 
+    def test_extend_enum_shadow_base(self):
+        class hohum(object):
+            def cyan(self):
+                "cyanize a color"
+                return self.value
+        class Color(hohum, UniqueEnum):
+            red = 1
+            green = 2
+            blue = 3
+        with self.assertRaises(TypeError):
+            extend_enum(Color, 'cyan', 4)
+        self.assertEqual(len(Color), 3)
+        self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
+
     def test_extend_enum_multivalue(self):
         class Color(MultiValueEnum):
             red = 1, 4, 7
@@ -2820,6 +2861,7 @@
 
     def test_member_with_external_functions(self):
         class Func(Enum):
+            _order_ = 'an_int a_str'
             an_int = member(int)
             a_str = member(str)
             @classproperty
@@ -2837,6 +2879,7 @@
 
     def test_member_with_internal_functions(self):
         class Func(Enum):
+            _order_ = 'haha hehe'
             @member
             def haha():
                 return 'haha'
@@ -2871,6 +2914,30 @@
         self.assertEqual(Universe.PI, 3.141596)
         self.assertEqual(Universe.TAU, 2 * Universe.PI)
 
+    def test_constant_with_auto_is_updated(self):
+        class Fruit(Flag):
+            _order_ = 'apple banana lemon orange'
+            apple = auto()
+            banana = auto()
+            lemon = auto()
+            orange = auto()
+            CitrusTypes = constant(lemon | orange)
+        self.assertEqual(list(Fruit), [Fruit.apple, Fruit.banana, Fruit.lemon, 
Fruit.orange])
+        self.assertEqual(list(Fruit.CitrusTypes), [Fruit.orange, Fruit.lemon])
+        self.assertTrue(Fruit.orange in Fruit.CitrusTypes)
+
+    def test_constant_with_enum_is_updated(self):
+        class Fruit(Flag):
+            _order_ = 'apple banana lemon orange'
+            apple = auto()
+            banana = auto()
+            lemon = auto()
+            orange = auto()
+            CitrusTypes = constant(lemon | orange)
+        self.assertEqual(list(Fruit), [Fruit.apple, Fruit.banana, Fruit.lemon, 
Fruit.orange])
+        self.assertEqual(list(Fruit.CitrusTypes), [Fruit.orange, Fruit.lemon])
+        self.assertTrue(Fruit.orange in Fruit.CitrusTypes)
+
     def test_order_as_function(self):
         # first with _init_
         class TestSequence(Enum):
@@ -3330,6 +3397,64 @@
         BLUE = 4
         PURPLE = RED|BLUE
 
+    class TermColor(str, Flag):
+        _settings_ = AutoValue
+
+        def __new__(cls, value, code):
+            str_value = '\x1b[%sm' % code
+            obj = str.__new__(cls, str_value)
+            obj._value_ = value
+            obj.code = code
+            return obj
+
+        @classmethod
+        def _create_pseudo_member_values_(cls, members, *values):
+            code = ';'.join(m.code for m in members)
+            return values + (code, )
+
+        AllReset = '0'           # ESC [ 0 m       # reset all (colors and 
brightness)
+        Bright = '1'          # ESC [ 1 m       # bright
+        Dim = '2'             # ESC [ 2 m       # dim (looks same as normal 
brightness)
+        Underline = '4'
+        Normal = '22'         # ESC [ 22 m      # normal brightness
+                            #
+                            # # FOREGROUND - 30s  BACKGROUND - 40s:
+        FG_Black = '30'           # ESC [ 30 m      # black
+        FG_Red = '31'             # ESC [ 31 m      # red
+        FG_Green = '32'           # ESC [ 32 m      # green
+        FG_Yellow = '33'          # ESC [ 33 m      # yellow
+        FG_Blue = '34'            # ESC [ 34 m      # blue
+        FG_Magenta = '35'         # ESC [ 35 m      # magenta
+        FG_Cyan = '36'            # ESC [ 36 m      # cyan
+        FG_White = '37'           # ESC [ 37 m      # white
+        FG_Reset = '39'           # ESC [ 39 m      # reset
+                                #
+        BG_Black = '40'           # ESC [ 30 m      # black
+        BG_Red = '41'             # ESC [ 31 m      # red
+        BG_Green = '42'           # ESC [ 32 m      # green
+        BG_Yellow = '43'          # ESC [ 33 m      # yellow
+        BG_Blue = '44'            # ESC [ 34 m      # blue
+        BG_Magenta = '45'         # ESC [ 35 m      # magenta
+        BG_Cyan = '46'            # ESC [ 36 m      # cyan
+        BG_White = '47'           # ESC [ 37 m      # white
+        BG_Reset = '49'           # ESC [ 39 m      # reset
+
+        __str__ = str.__str__
+
+        def __repr__(self):
+            if self._name_ is not None:
+                return '<%s.%s>' % (self.__class__.__name__, self._name_)
+            else:
+                return '<%s: %s>' % (self.__class__.__name__, '|'.join([m.name 
for m in Flag.__iter__(self)]))
+
+        def __enter__(self):
+            print(self.AllReset, end='', verbose=0)
+            return self
+
+        def __exit__(self, *args):
+            print(self.AllReset, end='', verbose=0)
+
+
     class Open(Flag):
         RO = 0
         WO = 1
@@ -3337,6 +3462,15 @@
         AC = 3
         CE = 1<<19
 
+    def test_str_is_str_str(self):
+        red, white = self.TermColor.FG_Red, self.TermColor.BG_White
+        barber = red | white
+        self.assertEqual(barber, '\x1b[47;31m')
+        self.assertEqual(barber.value, red.value | white.value)
+        self.assertEqual(barber.code, ';'.join([white.code, red.code]))
+        self.assertEqual(repr(barber), '<TermColor: BG_White|FG_Red>')
+        self.assertEqual(str(barber), '\x1b[47;31m')
+
     def test_membership(self):
         Color = self.Color
         Open = self.Open
@@ -4087,10 +4221,16 @@
             RED = 1
             GREEN = 2
             BLUE = 4
-        extend_enum(Color, 'PURPLE', 5)
-        self.assertTrue(Color(5) is Color.PURPLE)
+        extend_enum(Color, 'MAGENTA')
+        self.assertTrue(Color(8) is Color.MAGENTA)
+        self.assertTrue(isinstance(Color.MAGENTA, Color))
+        self.assertEqual(Color.MAGENTA.value, 8)
+        extend_enum(Color, 'PURPLE', 11)
+        self.assertTrue(Color(11) is Color.PURPLE)
         self.assertTrue(isinstance(Color.PURPLE, Color))
-        self.assertEqual(Color.PURPLE.value, 5)
+        self.assertEqual(Color.PURPLE.value, 11)
+        self.assertTrue(issubclass(Color, Flag))
+        print(list(Color))
 
     def test_extend_flag_subclass(self):
         class Color(str, Flag):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aenum-2.2.1/aenum.egg-info/PKG-INFO 
new/aenum-2.2.3/aenum.egg-info/PKG-INFO
--- old/aenum-2.2.1/aenum.egg-info/PKG-INFO     2019-07-24 23:22:43.000000000 
+0200
+++ new/aenum-2.2.3/aenum.egg-info/PKG-INFO     2019-11-10 02:43:09.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: aenum
-Version: 2.2.1
+Version: 2.2.3
 Summary: Advanced Enumerations (compatible with Python's stdlib Enum), 
NamedTuples, and NamedConstants
 Home-page: https://bitbucket.org/stoneleaf/aenum
 Author: Ethan Furman
@@ -46,6 +46,9 @@
         
         - enum: helper class for creating members with keywords
         
+        - enum_property: property to enable enum members to have same named 
attributes
+                         (e.g. `name` and `value`)
+        
         - export: helper to insert Enum members into a namespace (usually 
globals())
         
         - extend_enum: add new members to enumerations after creation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aenum-2.2.1/setup.py new/aenum-2.2.3/setup.py
--- old/aenum-2.2.1/setup.py    2019-07-24 23:22:37.000000000 +0200
+++ new/aenum-2.2.3/setup.py    2019-11-10 02:43:03.000000000 +0100
@@ -46,6 +46,9 @@
 
 - enum: helper class for creating members with keywords
 
+- enum_property: property to enable enum members to have same named attributes
+                 (e.g. `name` and `value`)
+
 - export: helper to insert Enum members into a namespace (usually globals())
 
 - extend_enum: add new members to enumerations after creation
@@ -62,7 +65,7 @@
 
 data = dict(
        name='aenum',
-       version='2.2.1',
+       version='2.2.3',
        url='https://bitbucket.org/stoneleaf/aenum',
        packages=['aenum'],
        package_data={
@@ -104,7 +107,7 @@
 
 if __name__ == '__main__':
     if 'install' in sys.argv:
-        import os, sys, shutil
+        import os, sys
         if sys.version_info[0] != 2:
             for file in py2_only:
                 try:


Reply via email to