FreeCAD

Форк
0
/
ExtensionContainerPyImp.cpp 
267 строк · 10.1 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25

26
#ifndef _PreComp_
27
# include <sstream>
28
#endif
29

30
#include "Application.h"
31

32
#include <App/ExtensionContainerPy.h>
33
#include <App/ExtensionContainerPy.cpp>
34
#include <App/Extension.h>
35

36
using namespace App;
37

38
// returns a string which represent the object e.g. when printed in python
39
std::string ExtensionContainerPy::representation() const
40
{
41
    return {"<extension>"};
42
}
43

44
int  ExtensionContainerPy::initialization() {
45

46
    if (!this->ob_type->tp_dict) {
47
        if (PyType_Ready(this->ob_type) < 0)
48
            return 0;
49
    }
50

51
    ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
52
    for(; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
53

54
        // The PyTypeObject is shared by all instances of this type and therefore
55
        // we have to add new methods only once.
56
        PyObject* obj = (*it).second->getExtensionPyObject();
57
        PyMethodDef* meth = obj->ob_type->tp_methods;
58
        PyTypeObject *type = this->ob_type;
59
        PyObject *dict = type->tp_dict;
60

61
        // make sure to do the initialization only once
62
        if (meth->ml_name) {
63
            PyObject* item = PyDict_GetItemString(dict, meth->ml_name);
64
            if (!item) {
65
                // Note: this adds the methods to the type object to make sure
66
                // it appears in the call tips. The function will not be bound
67
                // to an instance
68
                Py_INCREF(dict);
69
                while (meth->ml_name) {
70
                    PyObject *func;
71
                    func = PyCFunction_New(meth, 0);
72
                    if (!func)
73
                        break;
74
                    if (PyDict_SetItemString(dict, meth->ml_name, func) < 0)
75
                        break;
76
                    Py_DECREF(func);
77
                    ++meth;
78
                }
79

80
                Py_DECREF(dict);
81
            }
82
        }
83

84
        Py_DECREF(obj);
85
    }
86
    return 1;
87
}
88

89
int  ExtensionContainerPy::finalization() {
90
/*
91
    //we need to delete all added python extensions, as we are the owner! 
92
    ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
93
    for(; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
94
        if((*it).second->isPythonExtension())
95
            delete (*it).second;
96
    }*/
97
    return 1;
98
}
99

100
PyObject* ExtensionContainerPy::PyMake(struct _typeobject *, PyObject *, PyObject *)  // Python wrapper
101
{
102
    // create a new instance of @self.export.Name@ and the Twin object 
103
    return nullptr;
104
}
105

106
// constructor method
107
int ExtensionContainerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
108
{
109
    return 0;
110
}
111

112
PyObject *ExtensionContainerPy::getCustomAttributes(const char* attr) const
113
{
114
    if (Base::streq(attr, "__dict__")) {
115
        PyObject* dict = PyDict_New();
116
        PyObject* props = PropertyContainerPy::getCustomAttributes("__dict__");
117
        if (props && PyDict_Check(props)) {
118
            PyDict_Merge(dict, props, 0);
119
            Py_DECREF(props);
120
        }
121

122
        ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
123
        for (; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
124
            // The PyTypeObject is shared by all instances of this type and therefore
125
            // we have to add new methods only once.
126
            PyObject* obj = (*it).second->getExtensionPyObject();
127
            PyTypeObject *tp = Py_TYPE(obj);
128
            if (tp && tp->tp_dict) {
129
                Py_XINCREF(tp->tp_dict);
130
                PyDict_Merge(dict, tp->tp_dict, 0);
131
                Py_XDECREF(tp->tp_dict);
132
            }
133
            Py_DECREF(obj);
134
        }
135

136
        return dict;
137
    }
138
    // Search for the method called 'attr' in the extensions. If the search with
139
    // Py_FindMethod is successful then a PyCFunction_New instance is returned
140
    // with the PyObject pointer of the extension to make sure the method will
141
    // be called for the correct instance.
142
    PyObject *func = nullptr;
143
    ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
144
    for (; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
145
        // The PyTypeObject is shared by all instances of this type and therefore
146
        // we have to add new methods only once.
147
        PyObject* obj = (*it).second->getExtensionPyObject();
148
        PyObject *nameobj = PyUnicode_FromString(attr);
149
        func = PyObject_GenericGetAttr(obj, nameobj);
150
        Py_DECREF(nameobj);
151
        Py_DECREF(obj);
152
        if (func && PyCFunction_Check(func)) {
153
            PyCFunctionObject* cfunc = reinterpret_cast<PyCFunctionObject*>(func);
154

155
            // OK, that's what we wanted
156
            if (cfunc->m_self == obj)
157
                break;
158
            // otherwise cleanup the result again
159
            Py_DECREF(func);
160
            func = nullptr;
161
        }
162
        PyErr_Clear(); // clear the error set inside Py_FindMethod
163
    }
164

165
    return func;
166
}
167

168
int ExtensionContainerPy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/)
169
{
170
    return 0;
171
}
172

173
PyObject* ExtensionContainerPy::hasExtension(PyObject *args) {
174

175
    char *type;
176
    PyObject *deriv = Py_True;
177
    if (!PyArg_ParseTuple(args, "s|O!", &type, &PyBool_Type, &deriv))
178
        return nullptr;
179

180
    //get the extension type asked for
181
    bool derived = Base::asBoolean(deriv);
182
    Base::Type extension =  Base::Type::fromName(type);
183
    if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
184
        std::stringstream str;
185
        str << "No extension found of type '" << type << "'" << std::ends;
186
        throw Py::TypeError(str.str());
187
    }
188

189
    bool val = false;
190
    if (getExtensionContainerPtr()->hasExtension(extension, derived)) {
191
        val = true;
192
    }
193

194
    return PyBool_FromLong(val ? 1 : 0);
195
}
196

197
PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
198

199
    char *typeId;
200
    PyObject* proxy = nullptr;
201
    if (!PyArg_ParseTuple(args, "s|O", &typeId, &proxy))
202
        return nullptr;
203

204
    if (proxy) {
205
        PyErr_SetString(PyExc_DeprecationWarning, "Second argument is deprecated. It is ignored and will be removed in future versions. "
206
                                                  "The default Python feature proxy is used for extension method overrides.");
207
        PyErr_Print();
208
    }
209

210
    //get the extension type asked for
211
    Base::Type extension =  Base::Type::fromName(typeId);
212
    if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
213
        std::stringstream str;
214
        str << "No extension found of type '" << typeId << "'" << std::ends;
215
        throw Py::TypeError(str.str());
216
    }
217

218
    //register the extension
219
    App::Extension* ext = static_cast<App::Extension*>(extension.createInstance());
220
    //check if this really is a python extension!
221
    if (!ext->isPythonExtension()) {
222
        delete ext;
223
        std::stringstream str;
224
        str << "Extension is not a python addable version: '" << typeId << "'" << std::ends;
225
        throw Py::TypeError(str.str());
226
    }
227

228
    GetApplication().signalBeforeAddingDynamicExtension(*getExtensionContainerPtr(), typeId);
229
    ext->initExtension(getExtensionContainerPtr());
230

231
    // The PyTypeObject is shared by all instances of this type and therefore
232
    // we have to add new methods only once.
233
    PyObject* obj = ext->getExtensionPyObject();
234
    PyMethodDef* meth = obj->ob_type->tp_methods;
235
    PyTypeObject *type = this->ob_type;
236
    PyObject *dict = type->tp_dict;
237

238
    // make sure to do the initialization only once
239
    if (meth->ml_name) {
240
        PyObject* item = PyDict_GetItemString(dict, meth->ml_name);
241
        if (!item) {
242
            // Note: this adds the methods to the type object to make sure
243
            // it appears in the call tips. The function will not be bound
244
            // to an instance
245
            Py_INCREF(dict);
246
            while (meth->ml_name) {
247
                PyObject *func;
248
                func = PyCFunction_New(meth, 0);
249
                if (!func)
250
                    break;
251
                if (PyDict_SetItemString(dict, meth->ml_name, func) < 0)
252
                    break;
253
                Py_DECREF(func);
254
                ++meth;
255
            }
256

257
            Py_DECREF(dict);
258
        }
259
    }
260

261
    Py_DECREF(obj);
262
    
263
    //throw the appropriate event
264
    GetApplication().signalAddedDynamicExtension(*getExtensionContainerPtr(), typeId);
265

266
    Py_Return;
267
}
268

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.