Package: boost1.38
Version: 1.38.0-3
Tags: patch

boost.python does not work with enums that have the same value, e.g.
wrapping the following enum using boost.python:

enum { red = 123, green = 123 };

Only either "red" or "green" will be available on the Python module,
because internally, boost maps this to a dictionary indexed by the
enum value.

More details on the upstream bug report:
https://svn.boost.org/trac/boost/ticket/2744

I'd propose applying the latest version (v2.3) of the patch on the bug
report, attached to this report for convenience (just cleaned up to
remove some UTF-8 characters in the diff headers). No more comments
were made about it since then, and it works for me.
Index: libs/python/test/enum.py
===================================================================
--- libs/python/test/enum.py	(revision 51792)
+++ libs/python/test/enum.py	(working copy)
@@ -4,8 +4,8 @@
 '''
 >>> from enum_ext import *
 
->>> identity(color.red)
-enum_ext.color.red
+>>> identity(color.red) # in case of duplicated enums it always take the last enum
+enum_ext.color.blood
 
 >>> identity(color.green)
 enum_ext.color.green
@@ -13,8 +13,8 @@
 >>> identity(color.blue)
 enum_ext.color.blue
 
->>> identity(color(1))
-enum_ext.color.red
+>>> identity(color(1)) # in case of duplicated enums it always take the last enum
+enum_ext.color.blood
 
 >>> identity(color(2))
 enum_ext.color.green
@@ -28,7 +28,7 @@
   --- check export to scope ---
 
 >>> identity(red)
-enum_ext.color.red
+enum_ext.color.blood
 
 >>> identity(green)
 enum_ext.color.green
@@ -42,10 +42,18 @@
 
 >>> c = colorized()
 >>> c.x
-enum_ext.color.red
+enum_ext.color.blood
 >>> c.x = green
 >>> c.x
 enum_ext.color.green
+>>> red == blood
+True
+>>> red == green
+False
+>>> hash(red) == hash(blood)
+True
+>>> hash(red) == hash(green)
+False
 '''
 
 # pickling of enums only works with Python 2.3 or higher
Index: libs/python/test/enum.cpp
===================================================================
--- libs/python/test/enum.cpp	(revision 51792)
+++ libs/python/test/enum.cpp	(working copy)
@@ -12,7 +12,7 @@
 #endif 
 using namespace boost::python;
 
-enum color { red = 1, green = 2, blue = 4 };
+enum color { red = 1, green = 2, blue = 4, blood = 1 };
 
 #if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
 namespace boost  // Pro7 has a hard time detecting enums
@@ -34,6 +34,7 @@
         .value("red", red)
         .value("green", green)
         .value("blue", blue)
+        .value("blood", blood)
         .export_values()
         ;
     
Index: libs/python/src/object/enum.cpp
===================================================================
--- libs/python/src/object/enum.cpp	(revision 51792)
+++ libs/python/src/object/enum.cpp	(working copy)
@@ -14,7 +14,7 @@
 #include <boost/python/object_protocol.hpp>
 #include <structmember.h>
 
-namespace boost { namespace python { namespace objects { 
+namespace boost { namespace python { namespace objects {
 
 struct enum_object
 {
@@ -43,7 +43,7 @@
             char* name = PyString_AsString(self->name);
             if (name == 0)
                 return 0;
-            
+
             return PyString_FromFormat("%s.%s.%s", mod, self_->ob_type->tp_name, name);
         }
     }
@@ -139,15 +139,16 @@
       dict d;
       d["__slots__"] = tuple();
       d["values"] = dict();
+      d["names"] = dict();
 
       object module_name = module_prefix();
       if (module_name)
          d["__module__"] = module_name;
       if (doc)
          d["__doc__"] = doc;
-      
+
       object result = (object(metatype))(name, make_tuple(base), d);
-      
+
       scope().attr(name) = result;
 
       return result;
@@ -167,7 +168,7 @@
     converter::registration& converters
         = const_cast<converter::registration&>(
             converter::registry::lookup(id));
-            
+
     converters.m_class_object = downcast<PyTypeObject>(this->ptr());
     converter::registry::insert(to_python, id);
     converter::registry::insert(convertible, construct, id);
@@ -186,23 +187,24 @@
 
     dict d = extract<dict>(this->attr("values"))();
     d[value] = x;
-    
+
     // Set the name field in the new enum instanec
     enum_object* p = downcast<enum_object>(x.ptr());
     Py_XDECREF(p->name);
     p->name = incref(name.ptr());
+
+    dict names_dict = extract<dict>(this->attr("names"))();
+    names_dict[x.attr("name")] = x;
 }
 
 void enum_base::export_values()
 {
-    dict d = extract<dict>(this->attr("values"))();
-    list values = d.values();
+    dict d = extract<dict>(this->attr("names"))();
+    list items = d.items();
     scope current;
-    
-    for (unsigned i = 0, max = len(values); i < max; ++i)
-    {
-        api::setattr(current, object(values[i].attr("name")), values[i]);
-    }
+
+    for (unsigned i = 0, max = len(items); i < max; ++i)
+        api::setattr(current, items[i][0], items[i][1]);
  }
 
 PyObject* enum_base::to_python(PyTypeObject* type_, long x)

Reply via email to