#! python
# -*- coding: utf-8 -*-
# (c) 2006 Juergen Riegel 

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

class TemplateClassPyExport (template.ModelTemplate):
	def Generate(self):
		#self.ParentNamespace = "Base"
		#self.Namespace = "Base"
		encoding = sys.getfilesystemencoding()
		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",'wb')
				generateBase.generateTools.replace(self.TemplateImplement,locals(),file)
				file.close()
		with open(path + exportName + ".cpp", 'wb') as file:
			generateBase.generateTools.replace(self.TemplateModule,locals(),file)
		with open(path + exportName + ".h", 'wb') as file:
			generateBase.generateTools.replace(self.TemplateHeader,locals(),file)
			#file.write( generateBase.generateTools.replace(self.Template,locals()))

	TemplateHeader = """
// This file is generated by src/Tools/generateTemplates/templateClassPyExport.py out of the XML file
// Every change you make here gets lost in the next full rebuild!
#ifndef @self.export.Namespace.upper().replace("::", "_")@_@self.export.Name.upper()@_H
#define @self.export.Namespace.upper().replace("::", "_")@_@self.export.Name.upper()@_H

#include <@self.export.FatherInclude@>
#include <@self.export.Include@>
#include <string>

+ if(self.export.ForwardDeclarations != ""):
// Forward declarations
@self.export.ForwardDeclarations@
-

namespace @self.export.Namespace.replace("::"," { namespace ")@
{

//===========================================================================
// @self.export.Name@ - Python wrapper
//===========================================================================

/** The python export class for @self.export.Twin@
 */
class @self.export.Namespace.replace("::","_")@Export @self.export.Name@ : public @self.export.FatherNamespace@::@self.export.Father@
{
protected:
    ~@self.export.Name@();

public:
    static PyTypeObject   Type;
    static PyMethodDef    Methods[];
+ if (self.export.NumberProtocol):
    static PyNumberMethods Number[];
-
+ if (self.export.Sequence):
    static PySequenceMethods Sequence[];
    static PyMappingMethods Mapping[];
-
+ if (self.export.RichCompare):
    static PyObject * richCompare(PyObject *v, PyObject *w, int op);
-
    static PyGetSetDef    GetterSetter[];
    virtual PyTypeObject *GetType() {return &Type;}

public:
    @self.export.Name@(@self.export.TwinPointer@ *pcObject, PyTypeObject *T = &Type);
    static PyObject *PyMake(struct _typeobject *, PyObject *, PyObject *);
    virtual int PyInit(PyObject* args, PyObject*k);

+ if (self.export.Initialization):
    int initialization();
    int finalization();
-

    typedef @self.export.TwinPointer@* PointerType ;

    virtual PyObject *_repr();        // the representation
    std::string representation() const;

    /** @name callbacks and implementers for the python object methods */
    //@{
+ for i in self.export.Methode:
+ if i.Keyword:
    /// callback for the @i.Name@() method
    static PyObject * staticCallback_@i.Name@ (PyObject *self, PyObject *args, PyObject *kwd);
+ if i.Static:
    /// implementer for the @i.Name@() method
    static PyObject*  @i.Name@(PyObject *args, PyObject *kwd);
= elif i.Class:
    /// implementer for the @i.Name@() method
    static PyObject*  @i.Name@(PyObject *self, PyObject *args, PyObject *kwd);
= else:
    /// implementer for the @i.Name@() method
    PyObject*  @i.Name@(PyObject *args, PyObject *kwd);
-
= else:
    /// callback for the @i.Name@() method
    static PyObject * staticCallback_@i.Name@ (PyObject *self, PyObject *args);
+ if i.Static:
    /// implementer for the @i.Name@() method
    static PyObject*  @i.Name@(PyObject *args);
= elif i.Class:
    /// implementer for the @i.Name@() method
    static PyObject*  @i.Name@(PyObject *self, PyObject *args);
= else:
    /// implementer for the @i.Name@() method
    PyObject*  @i.Name@(PyObject *args);
-
-
-
    //@}

+ if (self.export.NumberProtocol):
    /** @name callbacks and implementers for the python object number protocol */
    //@{
    /// callback for the number_add_handler
    static PyObject * number_add_handler (PyObject *self, PyObject *other);
    /// callback for the number_subtract_handler
    static PyObject * number_subtract_handler (PyObject *self, PyObject *other);
    /// callback for the number_multiply_handler
    static PyObject * number_multiply_handler (PyObject *self, PyObject *other);
    /// callback for the number_divide_handler
    static PyObject * number_divide_handler (PyObject *self, PyObject *other);
    /// callback for the number_remainder_handler
    static PyObject * number_remainder_handler (PyObject *self, PyObject *other);
    /// callback for the number_divmod_handler
    static PyObject * number_divmod_handler (PyObject *self, PyObject *other);
    /// callback for the number_power_handler
    static PyObject * number_power_handler (PyObject *self, PyObject *other, PyObject *modulo);
    /// callback for the number_negative_handler
    static PyObject * number_negative_handler (PyObject *self);
    /// callback for the number_positive_handler
    static PyObject * number_positive_handler (PyObject *self);
    /// callback for the number_absolute_handler
    static PyObject * number_absolute_handler (PyObject *self);
    /// callback for the number_nonzero_handler
    static int number_nonzero_handler (PyObject *self);
    /// callback for the number_invert_handler
    static PyObject * number_invert_handler (PyObject *self);
    /// callback for the number_lshift_handler
    static PyObject * number_lshift_handler (PyObject *self, PyObject *other);
    /// callback for the number_rshift_handler
    static PyObject * number_rshift_handler (PyObject *self, PyObject *other);
    /// callback for the number_and_handler
    static PyObject * number_and_handler (PyObject *self, PyObject *other);
    /// callback for the number_xor_handler
    static PyObject * number_xor_handler (PyObject *self, PyObject *other);
    /// callback for the number_or_handler
    static PyObject * number_or_handler (PyObject *self, PyObject *other);
    /// callback for the number_int_handler
    static PyObject * number_int_handler (PyObject *self);
    /// callback for the number_float_handler
    static PyObject * number_float_handler (PyObject *self);
    //@}
-
+ if (self.export.Sequence):
    /** @name callbacks and implementers for the python object sequence protocol */
    //@{
+ if (self.export.Sequence.sq_length):
    static Py_ssize_t sequence_length(PyObject *);
-
+ if (self.export.Sequence.sq_concat):
    static PyObject* sequence_concat(PyObject *, PyObject *);
-
+ if (self.export.Sequence.sq_repeat):
    static PyObject * sequence_repeat(PyObject *, Py_ssize_t);
-
+ if (self.export.Sequence.sq_item):
    static PyObject * sequence_item(PyObject *, Py_ssize_t);
-
+ if (self.export.Sequence.mp_subscript):
    static PyObject * mapping_subscript(PyObject *, PyObject *);
-
+ if (self.export.Sequence.sq_ass_item):
    static int sequence_ass_item(PyObject *, Py_ssize_t, PyObject *);
-
+ if (self.export.Sequence.mp_ass_subscript):
    static int mapping_ass_subscript(PyObject *, PyObject *, PyObject *);
-
+ if (self.export.Sequence.sq_contains):
    static int sequence_contains(PyObject *, PyObject *);
-
+ if (self.export.Sequence.sq_inplace_concat):
    static PyObject* sequence_inplace_concat(PyObject *, PyObject *);
-
+ if (self.export.Sequence.sq_inplace_repeat):
    static PyObject * sequence_inplace_repeat(PyObject *, Py_ssize_t);
-
    //@}
-

    /** @name callbacks and implementers for the python object attributes */
    //@{
+ for i in self.export.Attribute:
    ///getter callback for the @i.Name@ attribute
    static PyObject * staticCallback_get@i.Name@ (PyObject *self, void *closure);
    /// getter for the @i.Name@ attribute
    Py::@i.Parameter.Type@ get@i.Name@() const;
    /// setter callback for the @i.Name@ attribute
    static int staticCallback_set@i.Name@ (PyObject *self, PyObject *value, void *closure);
+ if (i.ReadOnly):
    // no setter method,  @i.Name@ is read only!
= else:
    /// setter for the @i.Name@ attribute
    void set@i.Name@(Py::@i.Parameter.Type@ arg);
-
-
    //@}

+ if(self.export.CustomAttributes != None):
    /// getter method for special attributes (e.g. dynamic ones)
    PyObject *getCustomAttributes(const char* attr) const;
    /// setter for special attributes (e.g. dynamic ones)
    /// Output: Success=1, Failure=-1, Ignore=0
    int setCustomAttributes(const char* attr, PyObject *obj);
    PyObject *_getattr(const char *attr);              // __getattr__ function
    int _setattr(const char *attr, PyObject *value);        // __setattr__ function
-

    /// getter for the object handled by this class
    @self.export.TwinPointer@ *get@self.export.Twin@Ptr() const;

+ if(self.export.ClassDeclarations != ""):
    /** @name additional declarations and methods for the wrapper class */
    //@{
@self.export.ClassDeclarations@
    //@}
-
};

@"}"*len(self.export.Namespace.split("::"))@  //namespace @self.export.Namespace@

#endif  // @self.export.Namespace.upper().replace("::", "_")@_@self.export.Name.upper()@_H

"""

	TemplateModule = """
// This file is generated by src/Tools/generateTemplates/templateClassPyExport.py out of the .XML file
// Every change you make here gets lost in the next full rebuild!
// This File is normally built as an include in @self.export.Name@Imp.cpp! It's not intended to be in a project!

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/exception.hpp>
#include <Base/PyObjectBase.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <CXX/Objects.hxx>

#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif

using Base::streq;
using namespace @self.export.Namespace@;

/// Type structure of @self.export.Name@
PyTypeObject @self.export.Name@::Type = {
    PyVarObject_HEAD_INIT(&PyType_Type,0)
+ if (self.export.PythonName):
    "@self.export.PythonName@",     /*tp_name*/
= else:
    "@self.export.Namespace@.@self.export.Twin@",     /*tp_name*/
-
    sizeof(@self.export.Name@),                       /*tp_basicsize*/
    0,                                                /*tp_itemsize*/
    /* methods */
    PyDestructor,                                     /*tp_dealloc*/
#if PY_VERSION_HEX >= 0x03080000
    0,                                                /*tp_vectorcall_offset*/
#else
    nullptr,                                          /*tp_print*/
#endif
    nullptr,                                          /*tp_getattr*/
    nullptr,                                          /*tp_setattr*/
    nullptr,                                          /*tp_compare*/
    __repr,                                           /*tp_repr*/
+ if (self.export.NumberProtocol):
    @self.export.Namespace@::@self.export.Name@::Number,      /*tp_as_number*/
= else:
    nullptr,                                          /*tp_as_number*/
-
+ if (self.export.Sequence):
    @self.export.Namespace@::@self.export.Name@::Sequence,      /*tp_as_sequence*/
    @self.export.Namespace@::@self.export.Name@::Mapping,       /*tp_as_mapping*/
= else:
    nullptr,                                          /*tp_as_sequence*/
    nullptr,                                          /*tp_as_mapping*/
-
    nullptr,                                          /*tp_hash*/
    nullptr,                                          /*tp_call */
    nullptr,                                          /*tp_str  */
    __getattro,                                       /*tp_getattro*/
    __setattro,                                       /*tp_setattro*/
    /* --- Functions to access object as input/output buffer ---------*/
    nullptr,                                          /* tp_as_buffer */
    /* --- Flags to define presence of optional/expanded features */
    Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT,        /*tp_flags */
    "@self.export.Documentation.UserDocu.replace('\\n','\\\\n\\"\\n    \\"')@",           /*tp_doc */
    nullptr,                                          /*tp_traverse */
    nullptr,                                          /*tp_clear */
+ if (self.export.RichCompare):
    @self.export.Namespace@::@self.export.Name@::richCompare,      /*tp_richcompare*/
= else:
    nullptr,                                          /*tp_richcompare */
-
    0,                                                /*tp_weaklistoffset */
    nullptr,                                          /*tp_iter */
    nullptr,                                          /*tp_iternext */
    @self.export.Namespace@::@self.export.Name@::Methods,                     /*tp_methods */
    nullptr,                                          /*tp_members */
    @self.export.Namespace@::@self.export.Name@::GetterSetter,                     /*tp_getset */
    &@self.export.FatherNamespace@::@self.export.Father@::Type,                        /*tp_base */
    nullptr,                                          /*tp_dict */
    nullptr,                                          /*tp_descr_get */
    nullptr,                                          /*tp_descr_set */
    0,                                                /*tp_dictoffset */
    __PyInit,                                         /*tp_init */
    nullptr,                                          /*tp_alloc */
    @self.export.Namespace@::@self.export.Name@::PyMake,/*tp_new */
    nullptr,                                          /*tp_free   Low-level free-memory routine */
    nullptr,                                          /*tp_is_gc  For PyObject_IS_GC */
    nullptr,                                          /*tp_bases */
    nullptr,                                          /*tp_mro    method resolution order */
    nullptr,                                          /*tp_cache */
    nullptr,                                          /*tp_subclasses */
    nullptr,                                          /*tp_weaklist */
    nullptr,                                          /*tp_del */
    0,                                                /*tp_version_tag */
    nullptr                                           /*tp_finalize */
#if PY_VERSION_HEX >= 0x03090000
    ,nullptr                                          /*tp_vectorcall */
#elif PY_VERSION_HEX >= 0x03080000
    ,nullptr                                          /*tp_vectorcall */
    /* bpo-37250: kept for backwards compatibility in CPython 3.8 only */
    ,nullptr                                          /*tp_print */
#endif
};

/// Methods structure of @self.export.Name@
PyMethodDef @self.export.Name@::Methods[] = {
+ for i in self.export.Methode:
    {"@i.Name@",
+ if i.Keyword:
+ if i.Class:
        reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>( staticCallback_@i.Name@ )),
        METH_VARARGS|METH_KEYWORDS|METH_CLASS,
= elif i.Static:
        reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>( staticCallback_@i.Name@ )),
        METH_VARARGS|METH_KEYWORDS|METH_STATIC,
= else:
        reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>( staticCallback_@i.Name@ )),
        METH_VARARGS|METH_KEYWORDS,
-
= elif i.Class:
        reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>( staticCallback_@i.Name@ )),
        METH_VARARGS|METH_CLASS,
= elif i.Static:
        reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>( staticCallback_@i.Name@ )),
        METH_VARARGS|METH_STATIC,
= else:
        reinterpret_cast<PyCFunction>( staticCallback_@i.Name@ ),
        METH_VARARGS,
-
        "@i.Documentation.UserDocu.replace('\\n','\\\\n')@"
    },
-
    {nullptr, nullptr, 0, nullptr}		/* Sentinel */
};

+ if (self.export.NumberProtocol):
PyNumberMethods @self.export.Name@::Number[] = { {
    number_add_handler,
    number_subtract_handler,
    number_multiply_handler,
    number_remainder_handler,
    number_divmod_handler,
    number_power_handler,
    number_negative_handler,
    number_positive_handler,
    number_absolute_handler,
    number_nonzero_handler,
    number_invert_handler,
    number_lshift_handler,
    number_rshift_handler,
    number_and_handler,
    number_xor_handler,
    number_or_handler,
    number_int_handler,
    nullptr,
    number_float_handler,
    nullptr,    /*nb_inplace_add*/
    nullptr,    /*nb_inplace_subtract*/
    nullptr,    /*nb_inplace_multiply*/
    nullptr,    /*nb_inplace_remainder*/
    nullptr,    /*nb_inplace_power*/
    nullptr,    /*nb_inplace_lshift*/
    nullptr,    /*nb_inplace_rshift*/
    nullptr,    /*nb_inplace_and*/
    nullptr,    /*nb_inplace_xor*/
    nullptr,    /*nb_inplace_or*/
    nullptr,    /*nb_floor_divide*/
    number_divide_handler,    /*nb_true_divide*/
    nullptr,    /*nb_inplace_floor_divide*/
    nullptr,    /*nb_inplace_true_divide*/
    nullptr     /*nb_index*/
#if PY_VERSION_HEX >= 0x03050000
   ,nullptr     /*nb_matrix_multiply*/
   ,nullptr     /*nb_inplace_matrix_multiply*/
#endif
} };
-

+ if (self.export.Sequence):
PySequenceMethods @self.export.Name@::Sequence[] = { {
+ if (self.export.Sequence.sq_length):
    sequence_length,
= else:
    nullptr,
-
+ if (self.export.Sequence.sq_concat):
    sequence_concat,
= else:
    nullptr,
-
+ if (self.export.Sequence.sq_repeat):
    sequence_repeat,
= else:
    nullptr,
-
+ if (self.export.Sequence.sq_item):
    sequence_item,
= else:
    nullptr,
-
    nullptr,
+ if (self.export.Sequence.sq_ass_item):
    sequence_ass_item,
= else:
    nullptr,
-
    nullptr,
+ if (self.export.Sequence.sq_contains):
    sequence_contains,
= else:
    nullptr,
-
+ if (self.export.Sequence.sq_inplace_concat):
    sequence_inplace_concat,
= else:
    nullptr,
-
+ if (self.export.Sequence.sq_inplace_repeat):
    sequence_inplace_repeat,
= else:
    nullptr
-
} };

PyMappingMethods @self.export.Name@::Mapping[] = { {
+ if (self.export.Sequence.sq_length):
    sequence_length,
= else:
    nullptr,
-
+ if (self.export.Sequence.mp_subscript):
    mapping_subscript,
= else:
    nullptr,
-
+ if (self.export.Sequence.mp_ass_subscript):
    mapping_ass_subscript,
= else:
    nullptr,
-
} };
-

/// Attribute structure of @self.export.Name@
PyGetSetDef @self.export.Name@::GetterSetter[] = {
+ for i in self.export.Attribute:
    {"@i.Name@",
        (getter) staticCallback_get@i.Name@,
        (setter) staticCallback_set@i.Name@, 
        "@i.Documentation.UserDocu.replace('\\n','\\\\n')@",
        nullptr
    },
-
    {nullptr, nullptr, nullptr, nullptr, nullptr}		/* Sentinel */
};

+ for i in self.export.Methode:
// @i.Name@() callback and implementer
// PyObject*  @self.export.Name@::@i.Name@(PyObject *args){};
// has to be implemented in @self.export.Name@Imp.cpp
+ if i.Keyword:
PyObject * @self.export.Name@::staticCallback_@i.Name@ (PyObject *self, PyObject *args, PyObject * kwd)
= else:
PyObject * @self.export.Name@::staticCallback_@i.Name@ (PyObject *self, PyObject *args)
-
{
+ if not i.Static and not i.Class:
    // make sure that not a null pointer is passed
    if (!self) {
        PyErr_SetString(PyExc_TypeError, "descriptor '@i.Name@' of '@self.export.Namespace@.@self.export.Twin@' object needs an argument");
        return nullptr;
    }

    // test if twin object isn't already deleted
    if (!static_cast<PyObjectBase*>(self)->isValid()) {
        PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
        return nullptr;
    }

+   if (not i.Const):
    // test if object is set Const
    if (static_cast<PyObjectBase*>(self)->isConst()) {
        PyErr_SetString(PyExc_ReferenceError, "This object is immutable, you can not set any attribute or call a non const method");
        return nullptr;
    }
-

-
    try { // catches all exceptions coming up from c++ and generate a python exception
+ if i.Keyword:
+ if i.Static:
        (void)self;
        PyObject* ret = @self.export.Name@::@i.Name@(args, kwd);
= elif i.Class:
        PyObject* ret = @self.export.Name@::@i.Name@(self, args, kwd);
= else:
        PyObject* ret = static_cast<@self.export.Name@*>(self)->@i.Name@(args, kwd);
-
= else:
+ if i.Static:
        (void)self;
        PyObject* ret = @self.export.Name@::@i.Name@(args);
= elif i.Class:
        PyObject* ret = @self.export.Name@::@i.Name@(self, args);
= else:
        PyObject* ret = static_cast<@self.export.Name@*>(self)->@i.Name@(args);
-
-
+ if not i.Static and not i.Class:
+   if (not i.Const):
        if (ret != 0)
            static_cast<@self.export.Name@*>(self)->startNotify();
-
-
        return ret;
    } // Please sync the following catch implementation with PY_CATCH
    catch(Base::Exception &e)
    {
        auto pye = e.getPyExceptionType();
        if(!pye)
            pye = Base::PyExc_FC_GeneralError;
        PyErr_SetObject(pye, e.getPyObject());
        return nullptr;
    }
    catch(const std::exception &e)
    {
        PyErr_SetString(Base::PyExc_FC_GeneralError, e.what());
        return nullptr;
    }
    catch(const Py::Exception&)
    {
        // The exception text is already set
        return nullptr;
    }
#ifndef DONT_CATCH_CXX_EXCEPTIONS
    catch(...)
    {
        PyErr_SetString(Base::PyExc_FC_GeneralError, "Unknown C++ exception");
        return nullptr;
    }
#endif
}

-
+ for i in self.export.Attribute:
// @i.Name@() callback and implementer
// PyObject*  @self.export.Name@::@i.Name@(PyObject *args){};
// has to be implemented in @self.export.Name@Imp.cpp
PyObject * @self.export.Name@::staticCallback_get@i.Name@ (PyObject *self, void * /*closure*/)
{
    if (!static_cast<PyObjectBase*>(self)->isValid()){
        PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
        return nullptr;
    }

    try {
        return Py::new_reference_to(static_cast<@self.export.Name@*>(self)->get@i.Name@());
    } catch (const Py::Exception&) {
        // The exception text is already set
        return nullptr;
    } catch (...) {
        PyErr_SetString(Base::PyExc_FC_GeneralError, "Unknown exception while reading attribute '@i.Name@' of object '@self.export.Twin@'");
        return nullptr;
    }
}

+ if (i.ReadOnly):
int @self.export.Name@::staticCallback_set@i.Name@ (PyObject *self, PyObject * /*value*/, void * /*closure*/)
{
    if (!static_cast<PyObjectBase*>(self)->isValid()){
        PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
        return -1;
    }

    PyErr_SetString(PyExc_AttributeError, "Attribute '@i.Name@' of object '@self.export.Twin@' is read-only");
    return -1;
}
= else:
int @self.export.Name@::staticCallback_set@i.Name@ (PyObject *self, PyObject *value, void * /*closure*/)
{
    if (!static_cast<PyObjectBase*>(self)->isValid()){
        PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
        return -1;
    }
    if (static_cast<PyObjectBase*>(self)->isConst()){
        PyErr_SetString(PyExc_ReferenceError, "This object is immutable, you can not set any attribute or call a method");
        return -1;
    }

    try {
+ if (i.Parameter.Type == "Float"):
        static_cast<@self.export.Name@*>(self)->set@i.Name@(Py::@i.Parameter.Type@(PyNumber_Float(value),true));
= else:
        static_cast<@self.export.Name@*>(self)->set@i.Name@(Py::@i.Parameter.Type@(value,false));
-
        return 0;
    } catch (const Py::Exception&) {
        // The exception text is already set
        return -1;
    } catch (...) {
        PyErr_SetString(Base::PyExc_FC_GeneralError, "Unknown exception while writing attribute '@i.Name@' of object '@self.export.Twin@'");
        return -1;
    }
}
-

-



//--------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------
@self.export.Name@::@self.export.Name@(@self.export.TwinPointer@ *pcObject, PyTypeObject *T)
    : @self.export.Father@(static_cast<@self.export.Father@::PointerType>(pcObject), T)
{
+ if (self.export.Reference):
    pcObject->ref();
-
+ if (self.export.Initialization):
    initialization();
-
+ if (self.export.DisableNotify):
    this->setShouldNotify(false);
-
}

+ if not (self.export.Constructor):
PyObject *@self.export.Name@::PyMake(struct _typeobject *, PyObject *, PyObject *)  // Python wrapper
{
    // never create such objects with the constructor
    PyErr_SetString(PyExc_RuntimeError, "You cannot create directly an instance of '@self.export.Name@'.");
 
    return nullptr;
}

int @self.export.Name@::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
    return 0;
}
-

//--------------------------------------------------------------------------
// destructor
//--------------------------------------------------------------------------
@self.export.Name@::~@self.export.Name@()                                // Everything handled in parent
{
+ if (self.export.Reference):
    get@self.export.Twin@Ptr()->unref();
-
+ if (self.export.Delete):
    // delete the handled object when the PyObject dies
    @self.export.Name@::PointerType ptr = static_cast<@self.export.Name@::PointerType>(_pcTwinPointer);
    delete ptr;
-
+ if (self.export.Initialization):
    finalization();
-
}

//--------------------------------------------------------------------------
// @self.export.Name@ representation
//--------------------------------------------------------------------------
PyObject *@self.export.Name@::_repr()
{
    return Py_BuildValue("s", representation().c_str());
}

+ if(self.export.CustomAttributes != None):
//--------------------------------------------------------------------------
// @self.export.Name@ Attributes
//--------------------------------------------------------------------------
PyObject *@self.export.Name@::_getattr(const char *attr)			// __getattr__ function: note only need to handle new state
{
    try {
        // getter method for special Attributes (e.g. dynamic ones)
        PyObject *r = getCustomAttributes(attr);
        if(r) return r;
    } // Please sync the following catch implementation with PY_CATCH
    catch(Base::Exception &e)
    {
        auto pye = e.getPyExceptionType();
        if(!pye)
            pye = Base::PyExc_FC_GeneralError;
        PyErr_SetObject(pye, e.getPyObject());
        return nullptr;
    }
    catch(const std::exception &e)
    {
        PyErr_SetString(Base::PyExc_FC_GeneralError, e.what());
        return nullptr;
    }
    catch(const Py::Exception&)
    {
        // The exception text is already set
        return nullptr;
    }
#ifndef DONT_CATCH_CXX_EXCEPTIONS
    catch(...)
    {
        PyErr_SetString(Base::PyExc_FC_GeneralError,"Unknown C++ exception");
        return nullptr;
    }
#endif

    PyMethodDef *ml = Methods;
    for (; ml->ml_name != nullptr; 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@::_getattr(attr);
}

int @self.export.Name@::_setattr(const char *attr, PyObject *value) // __setattr__ function: note only need to handle new state
{
    try {
        // setter for special Attributes (e.g. dynamic ones)
        int r = setCustomAttributes(attr, value);
        // r = 1: handled
        // r = -1: error
        // r = 0: ignore
        if (r == 1)
            return 0;
        else if (r == -1)
            return -1;
    } // Please sync the following catch implementation with PY_CATCH
    catch(Base::Exception &e)
    {
        auto pye = e.getPyExceptionType();
        if(!pye)
            pye = Base::PyExc_FC_GeneralError;
        PyErr_SetObject(pye, e.getPyObject());
        return -1;
    }
    catch(const std::exception &e)
    {
        PyErr_SetString(Base::PyExc_FC_GeneralError, e.what());
        return -1;
    }
    catch(const Py::Exception&)
    {
        // The exception text is already set
        return -1;
    }
#ifndef DONT_CATCH_CXX_EXCEPTIONS
    catch(...)
    {
        PyErr_SetString(Base::PyExc_FC_GeneralError, "Unknown C++ exception");
        return -1;
    }
#endif

    return @self.export.Father@::_setattr(attr, value);
}
-

@self.export.TwinPointer@ *@self.export.Name@::get@self.export.Twin@Ptr() const
{
    return static_cast<@self.export.TwinPointer@ *>(_pcTwinPointer);
}

#if defined(__clang__)
# pragma clang diagnostic pop
#endif

#if 0
/* From here on come the methods you have to implement, but NOT in this module. Implement in @self.export.Name@Imp.cpp! This prototypes 
 * are just for convenience when you add a new method.
 */

+ if (self.export.Constructor):
PyObject *@self.export.Name@::PyMake(struct _typeobject *, PyObject *, PyObject *)  // Python wrapper
{
    // create a new instance of @self.export.Name@ and the Twin object 
    return new @self.export.Name@(new @self.export.TwinPointer@);
}

// constructor method
int @self.export.Name@::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
    return 0;
}
-

+ if (self.export.Initialization):
int @self.export.Name@::initialization()
{
    return 0;
}
int @self.export.Name@::finalization()
{
    return 0;
}
-

// returns a string which represents the object e.g. when printed in python
std::string @self.export.Name@::representation() const
{
    return std::string("<@self.export.Twin@ object>");
}
+ for i in self.export.Methode:

+ if i.Keyword:
+ if i.Class:
PyObject* @self.export.Name@::@i.Name@(PyObject *self, PyObject *args, PyObject *kwds)
= else:
PyObject* @self.export.Name@::@i.Name@(PyObject *args, PyObject *kwds)
-
= else:
+ if i.Class:
PyObject* @self.export.Name@::@i.Name@(PyObject *self, PyObject *args)
= else:
PyObject* @self.export.Name@::@i.Name@(PyObject *args)
-
-
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-

+ if (self.export.NumberProtocol):
PyObject* @self.export.Name@::number_add_handler(PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject* @self.export.Name@::number_subtract_handler(PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject* @self.export.Name@::number_multiply_handler(PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_divide_handler (PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_remainder_handler (PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_divmod_handler (PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_power_handler (PyObject* /*self*/, PyObject* /*other*/, PyObject* /*modulo*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_negative_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_positive_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_absolute_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

int @self.export.Name@::number_nonzero_handler (PyObject* /*self*/)
{
    return 1;
}

PyObject * @self.export.Name@::number_invert_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_lshift_handler (PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_rshift_handler (PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_and_handler (PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_xor_handler (PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_or_handler (PyObject* /*self*/, PyObject* /*other*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

int @self.export.Name@::number_coerce_handler (PyObject** /*self*/, PyObject** /*other*/)
{
    return 1;
}

PyObject * @self.export.Name@::number_int_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_long_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_float_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_oct_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_hex_handler (PyObject* /*self*/)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}
-
+ if (self.export.Sequence):
+ if (self.export.Sequence.sq_length):

Py_ssize_t @self.export.Name@::sequence_length(PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return -1;
}
-
+ if (self.export.Sequence.sq_concat):

PyObject* @self.export.Name@::sequence_concat(PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.sq_repeat):

PyObject * @self.export.Name@::sequence_repeat(PyObject *, Py_ssize_t)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.sq_item):

PyObject * @self.export.Name@::sequence_item(PyObject *, Py_ssize_t)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.mp_subscript):

PyObject * @self.export.Name@::mapping_subscript(PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.sq_ass_item):

int @self.export.Name@::sequence_ass_item(PyObject *, Py_ssize_t, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return -1;
}
-
+ if (self.export.Sequence.mp_ass_subscript):

int @self.export.Name@::mapping_ass_subscript(PyObject *, PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return -1;
}
-
+ if (self.export.Sequence.sq_contains):

int @self.export.Name@::sequence_contains(PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return -1;
}
-
+ if (self.export.Sequence.sq_inplace_concat):

PyObject* @self.export.Name@::sequence_inplace_concat(PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.sq_inplace_repeat):

PyObject * @self.export.Name@::sequence_inplace_repeat(PyObject *, Py_ssize_t)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
-

+ if (self.export.RichCompare):
PyObject* @self.export.Name@::richCompare(PyObject *v, PyObject *w, int op)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ for i in self.export.Attribute:

Py::@i.Parameter.Type@ @self.export.Name@::get@i.Name@() const
{
    //return Py::@i.Parameter.Type@();
    throw Py::AttributeError("Not yet implemented");
}
+ if (i.ReadOnly):
= else:

void  @self.export.Name@::set@i.Name@(Py::@i.Parameter.Type@ arg)
{
    throw Py::AttributeError("Not yet implemented");
}
-
-
+ if(self.export.CustomAttributes != None):

PyObject *@self.export.Name@::getCustomAttributes(const char* /*attr*/) const
{
    return nullptr;
}

int @self.export.Name@::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
    return 0; 
}
-
#endif


"""	

	# Here's the template for the user part of the implementation. This does NOT get overridden if it already exists.
	TemplateImplement = """
#include "PreCompiled.h"

#include "@self.export.Include@"

// inclusion of the generated files (generated out of @self.export.Name@.xml)
#include "@self.export.Name@.h"
#include "@self.export.Name@.cpp"

using namespace @self.export.Namespace@;

// returns a string which represents the object e.g. when printed in python
std::string @self.export.Name@::representation() const
{
    return std::string("<@self.export.Twin@ object>");
}

+ if (self.export.Constructor):
PyObject *@self.export.Name@::PyMake(struct _typeobject *, PyObject *, PyObject *)  // Python wrapper
{
    // create a new instance of @self.export.Name@ and the Twin object 
    return new @self.export.Name@(new @self.export.TwinPointer@);
}

// constructor method
int @self.export.Name@::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
    return 0;
}
-
+ if (self.export.Initialization):
int @self.export.Name@::initialization()
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return 0;
}
int @self.export.Name@::finalization()
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return 0;
}
-

+ for i in self.export.Methode:

+ if i.Keyword:
+ if i.Class:
PyObject* @self.export.Name@::@i.Name@(PyObject * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
= else:
PyObject* @self.export.Name@::@i.Name@(PyObject * /*args*/, PyObject * /*kwds*/)
-
= else:
+ if i.Class:
PyObject* @self.export.Name@::@i.Name@(PyObject * /*self*/, PyObject * /*args*/)
= else:
PyObject* @self.export.Name@::@i.Name@(PyObject * /*args*/)
-
-
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-

+ if (self.export.NumberProtocol):
PyObject* @self.export.Name@::number_add_handler(PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject* @self.export.Name@::number_subtract_handler(PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject* @self.export.Name@::number_multiply_handler(PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_divide_handler (PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_remainder_handler (PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_divmod_handler (PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_power_handler (PyObject *self, PyObject *other, PyObject *modulo)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_negative_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_positive_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_absolute_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

int @self.export.Name@::number_nonzero_handler (PyObject *self)
{
    return 1;
}

PyObject * @self.export.Name@::number_invert_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_lshift_handler (PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_rshift_handler (PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_and_handler (PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_xor_handler (PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_or_handler (PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

int @self.export.Name@::number_coerce_handler (PyObject **self, PyObject **other)
{
    return 1;
}

PyObject * @self.export.Name@::number_int_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_long_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_float_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_oct_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}

PyObject * @self.export.Name@::number_hex_handler (PyObject *self)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented");
    return nullptr;
}
-

+ if (self.export.Sequence):
+ if (self.export.Sequence.sq_length):

Py_ssize_t @self.export.Name@::sequence_length(PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return -1;
}
-
+ if (self.export.Sequence.sq_concat):

PyObject* @self.export.Name@::sequence_concat(PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.sq_repeat):

PyObject * @self.export.Name@::sequence_repeat(PyObject *, Py_ssize_t)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.sq_item):

PyObject * @self.export.Name@::sequence_item(PyObject *, Py_ssize_t)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.mp_subscript):

PyObject * @self.export.Name@::mapping_subscript(PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.sq_ass_item):

int @self.export.Name@::sequence_ass_item(PyObject *, Py_ssize_t, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return -1;
}
-
+ if (self.export.Sequence.mp_ass_subscript):

int @self.export.Name@::mapping_ass_subscript(PyObject *, PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return -1;
}
-
+ if (self.export.Sequence.sq_contains):

int @self.export.Name@::sequence_contains(PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return -1;
}
-
+ if (self.export.Sequence.sq_inplace_concat):

PyObject* @self.export.Name@::sequence_inplace_concat(PyObject *, PyObject *)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
+ if (self.export.Sequence.sq_inplace_repeat):

PyObject * @self.export.Name@::sequence_inplace_repeat(PyObject *, Py_ssize_t)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-
-

+ if (self.export.RichCompare):
PyObject* @self.export.Name@::richCompare(PyObject *v, PyObject *w, int op)
{
    PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
    return nullptr;
}
-

+ for i in self.export.Attribute:

Py::@i.Parameter.Type@ @self.export.Name@::get@i.Name@() const
{
    //return Py::@i.Parameter.Type@();
    throw Py::AttributeError("Not yet implemented");
}
+ if (i.ReadOnly):
= else:

void @self.export.Name@::set@i.Name@(Py::@i.Parameter.Type@ /*arg*/)
{
    throw Py::AttributeError("Not yet implemented");
}
-
-
+ if(self.export.CustomAttributes != None):

PyObject *@self.export.Name@::getCustomAttributes(const char* /*attr*/) const
{
    return nullptr;
}

int @self.export.Name@::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
    return 0; 
}
-

"""
