]> granicus.if.org Git - python/commitdiff
Close issue20653: improve functional API docs; minor code changes
authorEthan Furman <ethan@stoneleaf.us>
Mon, 3 Mar 2014 20:42:52 +0000 (12:42 -0800)
committerEthan Furman <ethan@stoneleaf.us>
Mon, 3 Mar 2014 20:42:52 +0000 (12:42 -0800)
Doc/library/enum.rst
Lib/enum.py

index b5fc4b68eed3a8b54378934990eb50c13bf5d0e4..eb5bdd9809470a87c9132f693e50567eb92e29ae 100644 (file)
@@ -374,6 +374,9 @@ from that module.
     With pickle protocol version 4 it is possible to easily pickle enums
     nested in other classes.
 
+It is possible to modify how Enum members are pickled/unpickled by defining
+:meth:`__reduce_ex__` in the enumeration class.
+
 
 Functional API
 --------------
@@ -420,6 +423,12 @@ The solution is to specify the module name explicitly as follows::
 
     >>> Animals = Enum('Animals', 'ant bee cat dog', module=__name__)
 
+.. warning::
+
+    If :param module: is not supplied, and Enum cannot determine what it is,
+    the new Enum members will not be unpicklable; to keep errors closer to
+    the source, pickling will be disabled.
+
 The new pickle protocol 4 also, in some circumstances, relies on
 :attr:`__qualname__` being set to the location where pickle will be able
 to find the class.  For example, if the class was made available in class
@@ -427,6 +436,31 @@ SomeData in the global scope::
 
     >>> Animals = Enum('Animals', 'ant bee cat dog', qualname='SomeData.Animals')
 
+The complete signature is::
+
+    Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>)
+
+:param value: What the new Enum class will record as its name.
+
+:param names: The Enum members.  This can be a whitespace or comma seperated
+string::
+
+    'red green blue', 'red,green,blue', 'red, green, blue'
+
+(values will start at 1), or an iterator of name, value pairs::
+
+    [('cyan', 4), ('magenta', 5), ('yellow', 6)]
+
+or a mapping::
+
+    {'chartruese': 7, 'sea_green': 11, 'rosemary': 42}
+
+:param module: name of module where new Enum class can be found.
+
+:param qualname: where in module new Enum class can be found.
+
+:param type: type to mix in to new Enum class.
+
 
 Derived Enumerations
 --------------------
index c9bd7c047c50cd15fea6289b6397c66fa00ccee9..844a95690f23112daa61662cc052d3c3e166c630 100644 (file)
@@ -115,14 +115,21 @@ class EnumMeta(type):
         # Reverse value->name map for hashable values.
         enum_class._value2member_map_ = {}
 
-        # check for a supported pickle protocols, and if not present sabotage
-        # pickling, since it won't work anyway.
-        # if new class implements its own __reduce_ex__, do not sabotage
-        if classdict.get('__reduce_ex__') is None:
+        # 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
+        # from the source, sabotage the pickle protocol for this class so
+        # that pickle.dumps also fails.
+        #
+        # However, if the new class implements its own __reduce_ex__, do not
+        # sabotage -- it's on them to make sure it works correctly.  We use
+        # __reduce_ex__ instead of any of the others as it is preferred by
+        # pickle over __reduce__, and it handles all pickle protocols.
+        if '__reduce_ex__' not in classdict:
             if member_type is not object:
                 methods = ('__getnewargs_ex__', '__getnewargs__',
                         '__reduce_ex__', '__reduce__')
-                if not any(map(member_type.__dict__.get, methods)):
+                if not any(m in member_type.__dict__ for m in methods):
                     _make_class_unpicklable(enum_class)
 
         # instantiate them, checking for duplicates as we go
@@ -193,14 +200,22 @@ class EnumMeta(type):
         to an enumeration member (i.e. Color(3)) and for the functional API
         (i.e. Color = Enum('Color', names='red green blue')).
 
-        When used for the functional API: `module`, if set, will be stored in
-        the new class' __module__ attribute; `qualname`, if set, will be stored
-        in the new class' __qualname__ attribute; `type`, if set, will be mixed
-        in as the first base class.
+        When used for the functional API:
 
-        Note: if `module` is not set this routine will attempt to discover the
-        calling module by walking the frame stack; if this is unsuccessful
-        the resulting class will not be pickleable.
+        `value` will be the name of the new class.
+
+        `names` should be either a string of white-space/comma delimited names
+        (values will start at 1), or an iterator/mapping of name, value pairs.
+
+        `module` should be set to the module this class is being created in;
+        if it is not set, an attempt to find that module will be made, but if
+        it fails the class will not be picklable.
+
+        `qualname` should be set to the actual location this class can be found
+        at in its module; by default it is set to the global scope.  If this is
+        not correct, unpickling will fail in some circumstances.
+
+        `type`, if set, will be mixed in as the first base class.
 
         """
         if names is None:  # simple value lookup