bpo-44559: [Enum] restore fixes lost in 3.9 reversion (GH-29114)

- fix exception leaks
- re-add deprecation warnings
diff --git a/Lib/enum.py b/Lib/enum.py
index db79e66..f5657a6 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -44,10 +44,11 @@ def _is_sunder(name):
 def _is_private(cls_name, name):
     # do not use `re` as `re` imports `enum`
     pattern = '_%s__' % (cls_name, )
+    pat_len = len(pattern)
     if (
-            len(name) >= 5
+            len(name) > pat_len
             and name.startswith(pattern)
-            and name[len(pattern)] != '_'
+            and name[pat_len:pat_len+1] != ['_']
             and (name[-1] != '_' or name[-2] != '_')
         ):
         return True
@@ -392,12 +393,19 @@ def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, s
                 start=start,
                 )
 
-    def __contains__(cls, member):
-        if not isinstance(member, Enum):
+    def __contains__(cls, obj):
+        if not isinstance(obj, Enum):
+            import warnings
+            warnings.warn(
+                    "in 3.12 __contains__ will no longer raise TypeError, but will return True if\n"
+                    "obj is a member or a member's value",
+                    DeprecationWarning,
+                    stacklevel=2,
+                    )
             raise TypeError(
                 "unsupported operand type(s) for 'in': '%s' and '%s'" % (
-                    type(member).__qualname__, cls.__class__.__qualname__))
-        return isinstance(member, cls) and member._name_ in cls._member_map_
+                    type(obj).__qualname__, cls.__class__.__qualname__))
+        return isinstance(obj, cls) and obj._name_ in cls._member_map_
 
     def __delattr__(cls, attr):
         # nicer error message when someone tries to delete an attribute
@@ -580,7 +588,7 @@ def _get_mixins_(class_name, bases):
             return object, Enum
 
         def _find_data_type(bases):
-            data_types = []
+            data_types = set()
             for chain in bases:
                 candidate = None
                 for base in chain.__mro__:
@@ -588,19 +596,19 @@ def _find_data_type(bases):
                         continue
                     elif issubclass(base, Enum):
                         if base._member_type_ is not object:
-                            data_types.append(base._member_type_)
+                            data_types.add(base._member_type_)
                             break
                     elif '__new__' in base.__dict__:
                         if issubclass(base, Enum):
                             continue
-                        data_types.append(candidate or base)
+                        data_types.add(candidate or base)
                         break
                     else:
                         candidate = candidate or base
             if len(data_types) > 1:
                 raise TypeError('%r: too many data types: %r' % (class_name, data_types))
             elif data_types:
-                return data_types[0]
+                return data_types.pop()
             else:
                 return None
 
@@ -693,19 +701,25 @@ def __new__(cls, value):
         except Exception as e:
             exc = e
             result = None
-        if isinstance(result, cls):
-            return result
-        else:
-            ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
-            if result is None and exc is None:
-                raise ve_exc
-            elif exc is None:
-                exc = TypeError(
-                        'error in %s._missing_: returned %r instead of None or a valid member'
-                        % (cls.__name__, result)
-                        )
-            exc.__context__ = ve_exc
-            raise exc
+        try:
+            if isinstance(result, cls):
+                return result
+            else:
+                ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
+                if result is None and exc is None:
+                    raise ve_exc
+                elif exc is None:
+                    exc = TypeError(
+                            'error in %s._missing_: returned %r instead of None or a valid member'
+                            % (cls.__name__, result)
+                            )
+                if not isinstance(exc, ValueError):
+                    exc.__context__ = ve_exc
+                raise exc
+        finally:
+            # ensure all variables that could hold an exception are destroyed
+            exc = None
+            ve_exc = None
 
     def _generate_next_value_(name, start, count, last_values):
         """