diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index c3611fb4df..3134fcb2eb 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -1312,15 +1312,19 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) { CPPType *underlying_type = TypeManager::unwrap_const(object->_itype._cpptype->as_enum_type()->get_underlying_type()); string cast_to = underlying_type->get_local_name(&parser); - out << "#if PY_VERSION_HEX >= 0x03040000\n\n"; out << " // enum class " << object->_itype.get_scoped_name() << "\n"; out << " {\n"; out << " PyObject *members = PyTuple_New(" << enum_count << ");\n"; out << " PyObject *member;\n"; for (int xx = 0; xx < enum_count; xx++) { out << " member = PyTuple_New(2);\n" - " PyTuple_SET_ITEM(member, 0, PyUnicode_FromString(\"" + "#if PY_MAJOR_VERSION >= 3\n" + " PyTuple_SET_ITEM(member, 0, PyUnicode_FromString(\"" << object->_itype.get_enum_value_name(xx) << "\"));\n" + "#else\n" + " PyTuple_SET_ITEM(member, 0, PyString_FromString(\"" + << object->_itype.get_enum_value_name(xx) << "\"));\n" + "#endif\n" " PyTuple_SET_ITEM(member, 1, Dtool_WrapValue((" << cast_to << ")" << object->_itype.get_scoped_name() << "::" << object->_itype.get_enum_value_name(xx) << "));\n" @@ -1332,7 +1336,6 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) { out << " PyModule_AddObject(module, \"" << object->_itype.get_name() << "\", (PyObject *)Dtool_Ptr_" << safe_name << ");\n"; out << " }\n"; - out << "#endif\n"; } else { out << " // enum " << object->_itype.get_scoped_name() << "\n"; for (int xx = 0; xx < enum_count; xx++) { @@ -3129,27 +3132,30 @@ write_module_class(ostream &out, Object *obj) { int enum_count = nested_obj->_itype.number_of_enum_values(); CPPType *underlying_type = TypeManager::unwrap_const(nested_obj->_itype._cpptype->as_enum_type()->get_underlying_type()); string cast_to = underlying_type->get_local_name(&parser); - out << "#if PY_VERSION_HEX >= 0x03040000\n\n"; out << " // enum class " << nested_obj->_itype.get_scoped_name() << ";\n"; out << " {\n"; out << " PyObject *members = PyTuple_New(" << enum_count << ");\n"; out << " PyObject *member;\n"; for (int xx = 0; xx < enum_count; xx++) { out << " member = PyTuple_New(2);\n" + "#if PY_MAJOR_VERSION >= 3\n" " PyTuple_SET_ITEM(member, 0, PyUnicode_FromString(\"" << nested_obj->_itype.get_enum_value_name(xx) << "\"));\n" + "#else\n" + " PyTuple_SET_ITEM(member, 0, PyString_FromString(\"" + << nested_obj->_itype.get_enum_value_name(xx) << "\"));\n" + "#endif\n" " PyTuple_SET_ITEM(member, 1, Dtool_WrapValue((" << cast_to << ")" << nested_obj->_itype.get_scoped_name() << "::" << nested_obj->_itype.get_enum_value_name(xx) << "));\n" " PyTuple_SET_ITEM(members, " << xx << ", member);\n"; } - out << " Dtool_Ptr_" << safe_name << " = Dtool_EnumType_Create(\"" - << nested_obj->_itype.get_name() << "\", members, \"" - << _def->module_name << "\");\n"; + out << " Dtool_Ptr_" << safe_name << " = Dtool_EnumType_Create(\"" + << nested_obj->_itype.get_name() << "\", members, \"" + << _def->module_name << "\");\n"; out << " PyDict_SetItemString(dict, \"" << nested_obj->_itype.get_name() << "\", (PyObject *)Dtool_Ptr_" << safe_name << ");\n"; out << " }\n"; - out << "#endif\n"; } else if (nested_obj->_itype.is_enum()) { out << " // enum " << nested_obj->_itype.get_scoped_name() << ";\n"; diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx index 9e7563036d..e900ab0e7f 100644 --- a/dtool/src/interrogatedb/py_panda.cxx +++ b/dtool/src/interrogatedb/py_panda.cxx @@ -306,11 +306,39 @@ PyObject *_Dtool_Return(PyObject *value) { return value; } +#if PY_VERSION_HEX < 0x03040000 +static PyObject *Dtool_EnumType_Str(PyObject *self) { + PyObject *name = PyObject_GetAttrString(self, "name"); +#if PY_MAJOR_VERSION >= 3 + PyObject *repr = PyUnicode_FromFormat("%s.%s", Py_TYPE(self)->tp_name, PyString_AS_STRING(name)); +#else + PyObject *repr = PyString_FromFormat("%s.%s", Py_TYPE(self)->tp_name, PyString_AS_STRING(name)); +#endif + Py_DECREF(name); + return repr; +} + +static PyObject *Dtool_EnumType_Repr(PyObject *self) { + PyObject *name = PyObject_GetAttrString(self, "name"); + PyObject *value = PyObject_GetAttrString(self, "value"); +#if PY_MAJOR_VERSION >= 3 + PyObject *repr = PyUnicode_FromFormat("<%s.%s: %ld>", Py_TYPE(self)->tp_name, PyString_AS_STRING(name), PyLongOrInt_AS_LONG(value)); +#else + PyObject *repr = PyString_FromFormat("<%s.%s: %ld>", Py_TYPE(self)->tp_name, PyString_AS_STRING(name), PyLongOrInt_AS_LONG(value)); +#endif + Py_DECREF(name); + Py_DECREF(value); + return repr; +} +#endif + /** - * Creates a Python 3.4-style enum type. Steals reference to 'names'. + * Creates a Python 3.4-style enum type. Steals reference to 'names', which + * should be a tuple of (name, value) pairs. */ PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names, const char *module) { static PyObject *enum_class = nullptr; +#if PY_VERSION_HEX >= 0x03040000 static PyObject *enum_meta = nullptr; static PyObject *enum_create = nullptr; if (enum_meta == nullptr) { @@ -325,6 +353,62 @@ PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names, const cha PyObject *result = PyObject_CallFunction(enum_create, (char *)"OsN", enum_class, name, names); nassertr(result != nullptr, nullptr); +#else + static PyObject *name_str; + static PyObject *name_sunder_str; + static PyObject *value_str; + static PyObject *value_sunder_str; + // Emulate something vaguely like the enum module. + if (enum_class == nullptr) { +#if PY_MAJOR_VERSION >= 3 + name_str = PyUnicode_InternFromString("name"); + value_str = PyUnicode_InternFromString("value"); + name_sunder_str = PyUnicode_InternFromString("_name_"); + value_sunder_str = PyUnicode_InternFromString("_value_"); +#else + name_str = PyString_InternFromString("name"); + value_str = PyString_InternFromString("value"); + name_sunder_str = PyString_InternFromString("_name_"); + value_sunder_str = PyString_InternFromString("_value_"); +#endif + PyObject *name_value_tuple = PyTuple_New(4); + PyTuple_SET_ITEM(name_value_tuple, 0, name_str); + PyTuple_SET_ITEM(name_value_tuple, 1, value_str); + PyTuple_SET_ITEM(name_value_tuple, 2, name_sunder_str); + PyTuple_SET_ITEM(name_value_tuple, 3, value_sunder_str); + Py_INCREF(name_str); + Py_INCREF(value_str); + + PyObject *slots_dict = PyDict_New(); + PyDict_SetItemString(slots_dict, "__slots__", name_value_tuple); + Py_DECREF(name_value_tuple); + + enum_class = PyObject_CallFunction((PyObject *)&PyType_Type, (char *)"s()N", "Enum", slots_dict); + nassertr(enum_class != nullptr, nullptr); + } + PyObject *result = PyObject_CallFunction((PyObject *)&PyType_Type, (char *)"s(O)N", name, enum_class, PyDict_New()); + nassertr(result != nullptr, nullptr); + + ((PyTypeObject *)result)->tp_str = Dtool_EnumType_Str; + ((PyTypeObject *)result)->tp_repr = Dtool_EnumType_Repr; + + // Copy the names as instances of the above to the class dict. + Py_ssize_t size = PyTuple_GET_SIZE(names); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject *item = PyTuple_GET_ITEM(names, i); + PyObject *name = PyTuple_GET_ITEM(item, 0); + PyObject *value = PyTuple_GET_ITEM(item, 1); + PyObject *member = _PyObject_CallNoArg(result); + PyObject_SetAttr(member, name_str, name); + PyObject_SetAttr(member, name_sunder_str, name); + PyObject_SetAttr(member, value_str, value); + PyObject_SetAttr(member, value_sunder_str, value); + PyObject_SetAttr(result, name, member); + Py_DECREF(member); + } + Py_DECREF(names); +#endif + if (module != nullptr) { PyObject *modstr = PyUnicode_FromString(module); PyObject_SetAttrString(result, "__module__", modstr); diff --git a/dtool/src/pystub/pystub.cxx b/dtool/src/pystub/pystub.cxx index cf617cd6f7..ac6586c6ff 100644 --- a/dtool/src/pystub/pystub.cxx +++ b/dtool/src/pystub/pystub.cxx @@ -121,6 +121,7 @@ extern "C" { EXPCL_PYSTUB int PyObject_Repr(...); EXPCL_PYSTUB int PyObject_RichCompareBool(...); EXPCL_PYSTUB int PyObject_SelfIter(...); + EXPCL_PYSTUB int PyObject_SetAttr(...); EXPCL_PYSTUB int PyObject_SetAttrString(...); EXPCL_PYSTUB int PyObject_Str(...); EXPCL_PYSTUB int PyObject_Type(...); @@ -351,6 +352,7 @@ int PyObject_Malloc(...) { return 0; } int PyObject_Repr(...) { return 0; } int PyObject_RichCompareBool(...) { return 0; } int PyObject_SelfIter(...) { return 0; } +int PyObject_SetAttr(...) { return 0; } int PyObject_SetAttrString(...) { return 0; } int PyObject_Str(...) { return 0; } int PyObject_Type(...) { return 0; }