From bc696e5ab5f9958364be5f5f4ce53e37afa79d94 Mon Sep 17 00:00:00 2001 From: looooo Date: Fri, 2 Jun 2017 11:53:39 +0200 Subject: [PATCH] py3: change of getattr -> getattro issue 0000995 --- src/App/FeaturePythonPyImp.h | 6 +- src/App/FeaturePythonPyImp.inl | 58 ++++++--- src/Base/PyObjectBase.cpp | 111 +++++++++++----- src/Base/PyObjectBase.h | 14 +-- .../templateClassPyExport.py | 118 +++++++++++++----- 5 files changed, 215 insertions(+), 92 deletions(-) diff --git a/src/App/FeaturePythonPyImp.h b/src/App/FeaturePythonPyImp.h index 47fafa6f92..bcec0c5276 100644 --- a/src/App/FeaturePythonPyImp.h +++ b/src/App/FeaturePythonPyImp.h @@ -101,10 +101,10 @@ public: /** @name callbacks and implementers for the python object methods */ //@{ - static int __setattr(PyObject *PyObj, char *attr, PyObject *value); + static int __setattro(PyObject *PyObj, PyObject *attro, PyObject *value); //@} - PyObject *_getattr(char *attr); // __getattr__ function - int _setattr(char *attr, PyObject *value); // __setattr__ function + PyObject *_getattro(PyObject *attr); // __getattr__ function + int _setattro(PyObject *attro, PyObject *value); // __setattr__ function protected: PyObject * dict_methods; diff --git a/src/App/FeaturePythonPyImp.inl b/src/App/FeaturePythonPyImp.inl index cc6e2acffc..9de1184957 100644 --- a/src/App/FeaturePythonPyImp.inl +++ b/src/App/FeaturePythonPyImp.inl @@ -27,16 +27,15 @@ namespace App /// Type structure of FeaturePythonPyT template PyTypeObject FeaturePythonPyT::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(&PyType_Type,0) "FeaturePython", /*tp_name*/ sizeof(FeaturePythonPyT), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ FeaturePyT::PyDestructor, /*tp_dealloc*/ 0, /*tp_print*/ - FeaturePyT::__getattr, /*tp_getattr*/ - __setattr, /*tp_setattr*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ @@ -45,12 +44,16 @@ PyTypeObject FeaturePythonPyT::Type = { 0, /*tp_hash*/ 0, /*tp_call */ 0, /*tp_str */ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ + FeaturePyT::__getattro, /*tp_getattro*/ + __setattro, /*tp_setattro*/ /* --- Functions to access object as input/output buffer ---------*/ 0, /* tp_as_buffer */ /* --- Flags to define presence of optional/expanded features */ +#if PY_MAJOR_VERSION >= 3 + Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT, /*tp_flags */ +#else Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_CLASS, /*tp_flags */ +#endif "This is the father of all Feature classes", /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ @@ -58,7 +61,7 @@ PyTypeObject FeaturePythonPyT::Type = { 0, /*tp_weaklistoffset */ 0, /*tp_iter */ 0, /*tp_iternext */ - 0, /*tp_methods */ + App::FeaturePythonPyT::Methods, /*tp_methods */ 0, /*tp_members */ 0, /*tp_getset */ &FeaturePyT::Type, /*tp_base */ @@ -78,6 +81,9 @@ PyTypeObject FeaturePythonPyT::Type = { 0, /*tp_weaklist */ 0, /*tp_del */ 0 /*tp_version_tag */ +#if PY_MAJOR_VERSION >= 3 + ,0 /*tp_finalize */ +#endif }; template @@ -96,38 +102,56 @@ FeaturePythonPyT::~FeaturePythonPyT() } template -int FeaturePythonPyT::__setattr(PyObject *obj, char *attr, PyObject *value) +int FeaturePythonPyT::__setattro(PyObject *obj, PyObject *attro, PyObject *value) { + char *attr; +#if PY_MAJOR_VERSION >= 3 + attr = PyUnicode_AsUTF8(attro); +#else + attr = PyString_AsString(attro); +#endif // This overwrites PyObjectBase::__setattr because this actively disallows to delete an attribute // + if (!static_cast(obj)->isValid()){ PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr); return -1; } - int ret = static_cast(obj)->_setattr(attr, value); + int ret = static_cast(obj)->_setattro(attro, value); if (ret == 0) { static_cast(obj)->startNotify(); } return ret; } + template -int FeaturePythonPyT::_setattr(char *attr, PyObject *value) +int FeaturePythonPyT::_setattro(PyObject *attro, PyObject *value) { + char *attr; +#if PY_MAJOR_VERSION >= 3 + attr = PyUnicode_AsUTF8(attro); +#else + attr = PyString_AsString(attro); +#endif App::Property *prop = FeaturePyT::getPropertyContainerPtr()->getPropertyByName(attr); if (prop && !value) { PyErr_Format(PyExc_AttributeError, "Cannot delete attribute: '%s'", attr); return -1; } - int returnValue = FeaturePyT::_setattr(attr, value); + int returnValue = FeaturePyT::_setattro(attro, value); if (returnValue == -1) { PyObject* dict_item = value; if (value) { if (PyFunction_Check(value)) { PyErr_Clear(); +#if PY_MAJOR_VERSION < 3 dict_item = PyMethod_New(value, this, 0); +#else + dict_item = PyMethod_New(value, this); +#endif returnValue = PyDict_SetItemString(dict_methods, attr, dict_item); Py_XDECREF(dict_item); } @@ -144,8 +168,14 @@ int FeaturePythonPyT::_setattr(char *attr, PyObject *value) } template -PyObject *FeaturePythonPyT::_getattr(char *attr) +PyObject *FeaturePythonPyT::_getattro(PyObject *attro) { + char *attr; +#if PY_MAJOR_VERSION >= 3 + attr = PyUnicode_AsUTF8(attro); +#else + attr = PyString_AsString(attro); +#endif // See CallTipsList::extractTips if (Base::streq(attr, "__fc_template__")) { Py_INCREF(Py_None); @@ -162,7 +192,7 @@ PyObject *FeaturePythonPyT::_getattr(char *attr) return 0; } - PyObject* dict = FeaturePyT::_getattr(attr); + PyObject* dict = FeaturePyT::_getattro(attro); if (dict && PyDict_CheckExact(dict)) { PyObject* dict_old = dict; dict = PyDict_Copy(dict_old); @@ -182,7 +212,7 @@ PyObject *FeaturePythonPyT::_getattr(char *attr) // search for the attribute in the base class PyErr_Clear(); - return FeaturePyT::_getattr(attr); + return FeaturePyT::_getattro(attro); } } //namespace App diff --git a/src/Base/PyObjectBase.cpp b/src/Base/PyObjectBase.cpp index bbf1887ca7..d2a435422e 100644 --- a/src/Base/PyObjectBase.cpp +++ b/src/Base/PyObjectBase.cpp @@ -40,7 +40,7 @@ PyObject* Base::BaseExceptionFreeCADError = 0; PyObjectBase::PyObjectBase(void* p,PyTypeObject *T) : _pcTwinPointer(p), attrDict(0) { - this->ob_type = T; + Py_TYPE(this) = T; _Py_NewReference(this); #ifdef FC_LOGPYOBJECTS Base::Console().Log("PyO+: %s (%p)\n",T->tp_name, this); @@ -54,7 +54,7 @@ PyObjectBase::~PyObjectBase() { PyGILStateLocker lock; #ifdef FC_LOGPYOBJECTS - Base::Console().Log("PyO-: %s (%p)\n",this->ob_type->tp_name, this); + Base::Console().Log("PyO-: %s (%p)\n",Py_TYPE(this)->tp_name, this); #endif Py_XDECREF(attrDict); } @@ -73,16 +73,15 @@ PyObjectBase::~PyObjectBase() */ PyTypeObject PyObjectBase::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(&PyType_Type,0) "PyObjectBase", /*tp_name*/ sizeof(PyObjectBase), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* --- methods ---------------------------------------------- */ PyDestructor, /*tp_dealloc*/ 0, /*tp_print*/ - __getattr, /*tp_getattr*/ - __setattr, /*tp_setattr*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ 0, /*tp_compare*/ __repr, /*tp_repr*/ 0, /*tp_as_number*/ @@ -91,12 +90,12 @@ PyTypeObject PyObjectBase::Type = { 0, /*tp_hash*/ 0, /*tp_call */ 0, /*tp_str */ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ + __getattro, /*tp_getattro*/ + __setattro, /*tp_setattro*/ /* --- Functions to access object as input/output buffer ---------*/ 0, /* tp_as_buffer */ /* --- Flags to define presence of optional/expanded features */ - Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_CLASS, /*tp_flags */ + Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT, /*tp_flags */ "The most base class for Python binding", /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ @@ -124,6 +123,9 @@ PyTypeObject PyObjectBase::Type = { 0, /*tp_weaklist */ 0, /*tp_del */ 0 /*tp_version_tag */ +#if PY_MAJOR_VERSION >= 3 + ,0 /*tp_finalize */ +#endif }; /*------------------------------ @@ -133,8 +135,16 @@ PyMethodDef PyObjectBase::Methods[] = { {NULL, NULL, 0, NULL} /* Sentinel */ }; -PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr) +PyObject* PyObjectBase::__getattro(PyObject * obj, PyObject *attro) { + char *attr; +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_Check(attro)) + attr = PyUnicode_AsUTF8(attro); +#else + if (PyString_Check(attro)) + attr = PyString_AsString(attro); +#endif // This should be the entry in Type PyObjectBase* pyObj = static_cast(obj); if (!pyObj->isValid()){ @@ -152,7 +162,7 @@ PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr) } } - PyObject* value = pyObj->_getattr(attr); + PyObject* value = pyObj->_getattro(attro); #if 1 if (value && PyObject_TypeCheck(value, &(PyObjectBase::Type))) { if (!static_cast(value)->isConst()) { @@ -180,10 +190,18 @@ PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr) return value; } -int PyObjectBase::__setattr(PyObject *obj, char *attr, PyObject *value) +int PyObjectBase::__setattro(PyObject *obj, PyObject *attro, PyObject *value) { + char *attr; +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_Check(attro)) + attr = PyUnicode_AsUTF8(attro); +#else + if (PyString_Check(attro)) + attr = PyString_AsString(attro); +#endif //FIXME: In general we don't allow to delete attributes (i.e. value=0). However, if we want to allow - //we must check then in _setattr() of all subclasses whether value is 0. + //we must check then in _setattro() of all subclasses whether value is 0. if ( value==0 ) { PyErr_Format(PyExc_AttributeError, "Cannot delete attribute: '%s'", attr); return -1; @@ -204,7 +222,7 @@ int PyObjectBase::__setattr(PyObject *obj, char *attr, PyObject *value) } } - int ret = static_cast(obj)->_setattr(attr, value); + int ret = static_cast(obj)->_setattro(attro, value); #if 1 if (ret == 0) { static_cast(obj)->startNotify(); @@ -216,13 +234,21 @@ int PyObjectBase::__setattr(PyObject *obj, char *attr, PyObject *value) /*------------------------------ * PyObjectBase attributes -- attributes ------------------------------*/ -PyObject *PyObjectBase::_getattr(char *attr) +PyObject *PyObjectBase::_getattro(PyObject *attro) { + char *attr; +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_Check(attro)) + attr = PyUnicode_AsUTF8(attro); +#else + if (PyString_Check(attro)) + attr = PyString_AsString(attro); +#endif if (streq(attr, "__class__")) { // Note: We must return the type object here, // so that our own types feel as really Python objects - Py_INCREF(this->ob_type); - return (PyObject *)(this->ob_type); + Py_INCREF(Py_TYPE(this)); + return (PyObject *)(Py_TYPE(this)); } else if (streq(attr, "__members__")) { // Use __dict__ instead as __members__ is deprecated @@ -230,7 +256,7 @@ PyObject *PyObjectBase::_getattr(char *attr) } else if (streq(attr,"__dict__")) { // Return the default dict - PyTypeObject *tp = this->ob_type; + PyTypeObject *tp = Py_TYPE(this); Py_XINCREF(tp->tp_dict); return tp->tp_dict; } @@ -240,36 +266,39 @@ PyObject *PyObjectBase::_getattr(char *attr) } else { // As fallback solution use Python's default method to get generic attributes - PyObject *w, *res; - w = PyString_InternFromString(attr); - if (w != NULL) { - res = PyObject_GenericGetAttr(this, w); - Py_XDECREF(w); + PyObject *res; + if (attro != NULL) { + res = PyObject_GenericGetAttr(this, attro); return res; } else { // Throw an exception for unknown attributes - PyTypeObject *tp = this->ob_type; + PyTypeObject *tp = Py_TYPE(this); PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr); return NULL; } } } -int PyObjectBase::_setattr(char *attr, PyObject *value) +int PyObjectBase::_setattro(PyObject *attro, PyObject *value) { + char *attr; +#if PY_MAJOR_VERSION >= 3 + if (PyUnicode_Check(attro)) + attr = PyUnicode_AsUTF8(attro); +#else + if (PyString_Check(attro)) + attr = PyString_AsString(attro); +#endif if (streq(attr,"softspace")) return -1; // filter out softspace - PyObject *w; // As fallback solution use Python's default method to get generic attributes - w = PyString_InternFromString(attr); // new reference - if (w != NULL) { + if (attro != NULL) { // call methods from tp_getset if defined - int res = PyObject_GenericSetAttr(this, w, value); - Py_DECREF(w); + int res = PyObject_GenericSetAttr(this, attro, value); return res; } else { // Throw an exception for unknown attributes - PyTypeObject *tp = this->ob_type; + PyTypeObject *tp = Py_TYPE(this); PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr); return -1; } @@ -293,8 +322,13 @@ void PyObjectBase::resetAttribute() if (attrDict) { // This is the attribute name to the parent structure // which we search for in the dict +#if PY_MAJOR_VERSION < 3 PyObject* key1 = PyString_FromString("__attribute_of_parent__"); PyObject* key2 = PyString_FromString("__instance_of_parent__"); +#else + PyObject* key1 = PyBytes_FromString("__attribute_of_parent__"); + PyObject* key2 = PyBytes_FromString("__instance_of_parent__"); +#endif PyObject* attr = PyDict_GetItem(attrDict, key1); PyObject* inst = PyDict_GetItem(attrDict, key2); if (attr) { @@ -313,10 +347,14 @@ void PyObjectBase::setAttributeOf(const char* attr, PyObject* par) if (!attrDict) { attrDict = PyDict_New(); } - +#if PY_MAJOR_VERSION < 3 PyObject* key1 = PyString_FromString("__attribute_of_parent__"); PyObject* key2 = PyString_FromString("__instance_of_parent__"); - PyObject* attro = PyString_FromString(attr); +#else + PyObject* key1 = PyBytes_FromString("__attribute_of_parent__"); + PyObject* key2 = PyBytes_FromString("__instance_of_parent__"); +#endif + PyObject* attro = PyUnicode_FromString(attr); PyDict_SetItem(attrDict, key1, attro); PyDict_SetItem(attrDict, key2, par); Py_DECREF(attro); @@ -332,8 +370,13 @@ void PyObjectBase::startNotify() if (attrDict) { // This is the attribute name to the parent structure // which we search for in the dict +#if PY_MAJOR_VERSION < 3 PyObject* key1 = PyString_FromString("__attribute_of_parent__"); PyObject* key2 = PyString_FromString("__instance_of_parent__"); +#else + PyObject* key1 = PyBytes_FromString("__attribute_of_parent__"); + PyObject* key2 = PyBytes_FromString("__instance_of_parent__"); +#endif PyObject* attr = PyDict_GetItem(attrDict, key1); PyObject* parent = PyDict_GetItem(attrDict, key2); if (attr && parent) { @@ -345,7 +388,7 @@ void PyObjectBase::startNotify() Py_INCREF(attr); Py_INCREF(this); - __setattr(parent, PyString_AsString(attr), this); + __setattro(parent, attr, this); Py_DECREF(parent); // might be destroyed now Py_DECREF(attr); // might be destroyed now diff --git a/src/Base/PyObjectBase.h b/src/Base/PyObjectBase.h index e0263314e8..7cdc14dc27 100644 --- a/src/Base/PyObjectBase.h +++ b/src/Base/PyObjectBase.h @@ -222,13 +222,13 @@ public: * If you want to implement attributes in your class, reimplement * this method. * You have to call the method of the base class. - * Note: if you reimplement _gettattr() in a inheriting class you + * Note: if you reimplement _gettattro() in a inheriting class you * need to call the method of the base class! Otherwise even the * methods of the object will disappear! */ - virtual PyObject *_getattr(char *attr); - /// static wrapper for pythons _getattr() - static PyObject *__getattr(PyObject * PyObj, char *attr); + virtual PyObject *_getattro(PyObject *attro); + /// static wrapper for pythons _getattro() + static PyObject *__getattro(PyObject * PyObj, PyObject *attro); /** SetAttribute implementation * This method implements the setting of object attributes. @@ -236,9 +236,9 @@ public: * this method. * You have to call the method of the base class. */ - virtual int _setattr(char *attr, PyObject *value); // _setattr method - /// static wrapper for pythons _setattr(). // This should be the entry in Type. - static int __setattr(PyObject *PyObj, char *attr, PyObject *value); + virtual int _setattro(PyObject *attro, PyObject *value); // _setattro method + /// static wrapper for pythons _setattro(). // This should be the entry in Type. + static int __setattro(PyObject *PyObj, PyObject *attro, PyObject *value); /** _repr method * Override this method to return a string object with some diff --git a/src/Tools/generateTemplates/templateClassPyExport.py b/src/Tools/generateTemplates/templateClassPyExport.py index 69a8b5f51d..761259f871 100644 --- a/src/Tools/generateTemplates/templateClassPyExport.py +++ b/src/Tools/generateTemplates/templateClassPyExport.py @@ -2,7 +2,9 @@ # -*- coding: utf-8 -*- # (c) 2006 Juergen Riegel -import template,os,sys +from __future__ import print_function # this allows py2 to print(str1,str2) correctly +from . import template +import os,sys import generateBase.generateModel_Module import generateBase.generateTools @@ -11,20 +13,29 @@ class TemplateClassPyExport (template.ModelTemplate): #self.ParentNamespace = "Base" #self.Namespace = "Base" encoding = sys.getfilesystemencoding() - path = self.path.decode(encoding) - exportName = self.export.Name.decode(encoding) - dirname = self.dirname.decode(encoding) - print "TemplateClassPyExport",path + exportName + path = self.path + if hasattr(path,"decode"): # this is python2. Otherwise this is unicode already + path = path.decode(encoding) + exportName = self.export.Name + if hasattr(exportName,"decode"): # this is python2. Otherwise this is unicode already + exportName = exportName.decode(encoding) + dirname = self.dirname + if hasattr(dirname,"decode"): # this is python2. Otherwise this is unicode already + dirname = dirname.decode(encoding) + print("TemplateClassPyExport",path + exportName) # Imp.cpp must not exist, neither in path nor in dirname if(not os.path.exists(path + exportName + "Imp.cpp")): if(not os.path.exists(dirname + exportName + "Imp.cpp")): - file = open(path + exportName + "Imp.cpp",'w') + file = open(path + exportName + "Imp.cpp",'wb') generateBase.generateTools.replace(self.TemplateImplement,locals(),file) - file = open(path + exportName + ".cpp",'w') + file.close() + file = open(path + exportName + ".cpp",'wb') generateBase.generateTools.replace(self.TemplateModule,locals(),file) - file = open(path + exportName + ".h",'w') + file.close() + file = open(path + exportName + ".h",'wb') generateBase.generateTools.replace(self.TemplateHeader,locals(),file) #file.write( generateBase.generateTools.replace(self.Template,locals())) + file.close() TemplateHeader = """ // This file is generated by src/Tools/generateTemaplates/templateClassPyExport.py out of the XML file @@ -104,8 +115,10 @@ public: static PyObject * number_subtract_handler (PyObject *self, PyObject *other); /// callback for the number_multiply_handler static PyObject * number_multiply_handler (PyObject *self, PyObject *other); +#if PY_MAJOR_VERSION < 3 /// callback for the number_divide_handler static PyObject * number_divide_handler (PyObject *self, PyObject *other); +#endif /// callback for the number_remainder_handler static PyObject * number_remainder_handler (PyObject *self, PyObject *other); /// callback for the number_divmod_handler @@ -132,18 +145,24 @@ public: static PyObject * number_xor_handler (PyObject *self, PyObject *other); /// callback for the number_or_handler static PyObject * number_or_handler (PyObject *self, PyObject *other); +#if PY_MAJOR_VERSION < 3 /// callback for the number_coerce_handler static int number_coerce_handler (PyObject **self, PyObject **other); +#endif /// callback for the number_int_handler static PyObject * number_int_handler (PyObject *self); +#if PY_MAJOR_VERSION < 3 /// callback for the number_long_handler static PyObject * number_long_handler (PyObject *self); +#endif /// callback for the number_float_handler static PyObject * number_float_handler (PyObject *self); +#if PY_MAJOR_VERSION < 3 /// callback for the number_oct_handler static PyObject * number_oct_handler (PyObject *self); /// callback for the number_hex_handler static PyObject * number_hex_handler (PyObject *self); +#endif //@} - + if (self.export.Sequence): @@ -206,8 +225,8 @@ public: /// setter for special attributes (e.g. dynamic ones) /// Output: Success=1, Failure=-1, Ignore=0 int setCustomAttributes(const char* attr, PyObject *obj); - PyObject *_getattr(char *attr); // __getattr__ function - int _setattr(char *attr, PyObject *value); // __setattr__ function + PyObject *_getattro(PyObject *attro); // __getattr__ function + int _setattro(PyObject *attro, PyObject *value); // __setattr__ function - /// getter for the object handled by this class @@ -245,8 +264,7 @@ using namespace @self.export.Namespace@; /// Type structure of @self.export.Name@ PyTypeObject @self.export.Name@::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(&PyType_Type,0) + if (self.export.PythonName): "@self.export.PythonName@", /*tp_name*/ = else: @@ -257,8 +275,8 @@ PyTypeObject @self.export.Name@::Type = { /* methods */ PyDestructor, /*tp_dealloc*/ 0, /*tp_print*/ - __getattr, /*tp_getattr*/ - __setattr, /*tp_setattr*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ 0, /*tp_compare*/ __repr, /*tp_repr*/ + if (self.export.NumberProtocol): @@ -275,20 +293,24 @@ PyTypeObject @self.export.Name@::Type = { 0, /*tp_hash*/ 0, /*tp_call */ 0, /*tp_str */ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ + __getattro, /*tp_getattro*/ + __setattro, /*tp_setattro*/ /* --- Functions to access object as input/output buffer ---------*/ 0, /* tp_as_buffer */ /* --- Flags to define presence of optional/expanded features */ +#if PY_MAJOR_VERSION >= 3 + Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT, /*tp_flags */ +#else + if (self.export.RichCompare and self.export.NumberProtocol): - Py_TPFLAGS_HAVE_CLASS|Py_TPFLAGS_HAVE_RICHCOMPARE|Py_TPFLAGS_CHECKTYPES, /*tp_flags */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_RICHCOMPARE|Py_TPFLAGS_CHECKTYPES, /*tp_flags */ = elif (self.export.RichCompare): - Py_TPFLAGS_HAVE_CLASS|Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags */ = elif (self.export.NumberProtocol): - Py_TPFLAGS_HAVE_CLASS|Py_TPFLAGS_CHECKTYPES, /*tp_flags */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, /*tp_flags */ = else: - Py_TPFLAGS_HAVE_CLASS, /*tp_flags */ + Py_TPFLAGS_DEFAULT, /*tp_flags */ - +#endif "@self.export.Documentation.UserDocu.replace('\\n','\\\\n\\"\\n \\"')@", /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ @@ -320,6 +342,9 @@ PyTypeObject @self.export.Name@::Type = { 0, /*tp_weaklist */ 0, /*tp_del */ 0 /*tp_version_tag */ +#if PY_MAJOR_VERSION >= 3 + ,0 /*tp_finalize */ +#endif }; /// Methods structure of @self.export.Name@ @@ -343,7 +368,9 @@ PyNumberMethods @self.export.Name@::Number[] = { { number_add_handler, number_subtract_handler, number_multiply_handler, +#if PY_MAJOR_VERSION < 3 number_divide_handler, +#endif number_remainder_handler, number_divmod_handler, number_power_handler, @@ -357,12 +384,20 @@ PyNumberMethods @self.export.Name@::Number[] = { { number_and_handler, number_xor_handler, number_or_handler, +#if PY_MAJOR_VERSION < 3 number_coerce_handler, +#endif number_int_handler, +#if PY_MAJOR_VERSION < 3 number_long_handler, +#else + 0, +#endif number_float_handler, +#if PY_MAJOR_VERSION < 3 number_oct_handler, number_hex_handler, +#endif NULL, NULL, NULL, @@ -379,6 +414,9 @@ PyNumberMethods @self.export.Name@::Number[] = { { NULL, NULL, NULL +#if PY_MAJOR_VERSION >= 3 + ,NULL /*nb_inplace_matrix_multiply*/ +#endif } }; - @@ -674,8 +712,14 @@ PyObject *@self.export.Name@::_repr(void) //-------------------------------------------------------------------------- // @self.export.Name@ Attributes //-------------------------------------------------------------------------- -PyObject *@self.export.Name@::_getattr(char *attr) // __getattr__ function: note only need to handle new state +PyObject *@self.export.Name@::_getattro(PyObject *attro) // __getattr__ function: note only need to handle new state { + char *attr; +#if PY_MAJOR_VERSION >= 3 + attr = PyUnicode_AsUTF8(attro); +#else + attr = PyString_AsString(attro); +#endif try { // getter method for special Attributes (e.g. dynamic ones) PyObject *r = getCustomAttributes(attr); @@ -694,7 +738,7 @@ PyObject *@self.export.Name@::_getattr(char *attr) // __getattr__ function: n catch(const std::exception& e) // catch other c++ exceptions { std::string str; - str += "FC++ exception thrown ("; + str += "C++ exception thrown ("; str += e.what(); str += ")"; Base::Console().Error(str.c_str()); @@ -729,20 +773,26 @@ PyObject *@self.export.Name@::_getattr(char *attr) // __getattr__ function: n } #endif // DONT_CATCH_CXX_EXCEPTIONS - PyObject *rvalue = Py_FindMethod(Methods, this, attr); - if (rvalue == NULL) - { - PyErr_Clear(); - return @self.export.Father@::_getattr(attr); - } - else - { - return rvalue; + PyMethodDef *ml = Methods; + for (; ml->ml_name != NULL; ml++) { + if (attr[0] == ml->ml_name[0] && + strcmp(attr+1, ml->ml_name+1) == 0) + return PyCFunction_New(ml, this); } + + PyErr_Clear(); + return @self.export.Father@::_getattro(attro); } -int @self.export.Name@::_setattr(char *attr, PyObject *value) // __setattr__ function: note only need to handle new state +int @self.export.Name@::_setattro(PyObject *attro, PyObject *value) // __setattr__ function: note only need to handle new state + { + char *attr; +#if PY_MAJOR_VERSION >= 3 + attr = PyUnicode_AsUTF8(attro); +#else + attr = PyString_AsString(attro); +#endif try { // setter for special Attributes (e.g. dynamic ones) int r = setCustomAttributes(attr, value); @@ -768,7 +818,7 @@ int @self.export.Name@::_setattr(char *attr, PyObject *value) // __setattr__ fun catch(const std::exception& e) // catch other c++ exceptions { std::string str; - str += "FC++ exception thrown ("; + str += "C++ exception thrown ("; str += e.what(); str += ")"; Base::Console().Error(str.c_str()); @@ -802,7 +852,7 @@ int @self.export.Name@::_setattr(char *attr, PyObject *value) // __setattr__ fun } #endif // DONT_CATCH_CXX_EXCEPTIONS - return @self.export.Father@::_setattr(attr, value); + return @self.export.Father@::_setattro(attro, value); } -