1
/***************************************************************************
2
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
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. *
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. *
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 *
21
***************************************************************************/
28
/// Type structure of FeaturePythonPyT
29
template<class FeaturePyT>
30
PyTypeObject FeaturePythonPyT<FeaturePyT>::Type = {
31
PyVarObject_HEAD_INIT(&PyType_Type,0)
32
"FeaturePython", /*tp_name*/
33
sizeof(FeaturePythonPyT), /*tp_basicsize*/
36
FeaturePyT::PyDestructor, /*tp_dealloc*/
37
#if PY_VERSION_HEX >= 0x03080000
38
0, /*tp_vectorcall_offset*/
42
nullptr, /*tp_getattr*/
43
nullptr, /*tp_setattr*/
44
nullptr, /*tp_compare*/
46
nullptr, /*tp_as_number*/
47
nullptr, /*tp_as_sequence*/
48
nullptr, /*tp_as_mapping*/
52
FeaturePyT::__getattro, /*tp_getattro*/
53
__setattro, /*tp_setattro*/
54
/* --- Functions to access object as input/output buffer ---------*/
55
nullptr, /* tp_as_buffer */
56
/* --- Flags to define presence of optional/expanded features */
57
Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT, /*tp_flags */
58
"This is the father of all Feature classes", /*tp_doc */
59
nullptr, /*tp_traverse */
60
nullptr, /*tp_clear */
61
nullptr, /*tp_richcompare */
62
0, /*tp_weaklistoffset */
64
nullptr, /*tp_iternext */
65
nullptr, /*tp_methods */
66
nullptr, /*tp_members */
67
nullptr, /*tp_getset */
68
&FeaturePyT::Type, /*tp_base */
70
nullptr, /*tp_descr_get */
71
nullptr, /*tp_descr_set */
73
FeaturePyT::__PyInit, /*tp_init */
74
nullptr, /*tp_alloc */
76
nullptr, /*tp_free Low-level free-memory routine */
77
nullptr, /*tp_is_gc For PyObject_IS_GC */
78
nullptr, /*tp_bases */
79
nullptr, /*tp_mro method resolution order */
80
nullptr, /*tp_cache */
81
nullptr, /*tp_subclasses */
82
nullptr, /*tp_weaklist */
84
0, /*tp_version_tag */
85
nullptr /*tp_finalize */
86
#if PY_VERSION_HEX >= 0x03080000
88
#if PY_VERSION_HEX >= 0x030c0000
94
template<class FeaturePyT>
95
FeaturePythonPyT<FeaturePyT>::FeaturePythonPyT(Base::BaseClass *pcObject, PyTypeObject *T)
96
: FeaturePyT(static_cast<typename FeaturePyT::PointerType>(pcObject), T)
98
Base::PyGILStateLocker lock;
99
dict_methods = PyDict_New();
102
template<class FeaturePyT>
103
FeaturePythonPyT<FeaturePyT>::~FeaturePythonPyT()
105
Base::PyGILStateLocker lock;
106
Py_DECREF(dict_methods);
109
template<class FeaturePyT>
110
int FeaturePythonPyT<FeaturePyT>::__setattro(PyObject *obj, PyObject *attro, PyObject *value)
113
attr = PyUnicode_AsUTF8(attro);
114
// This overwrites PyObjectBase::__setattr because this actively disallows to delete an attribute
117
if (!static_cast<Base::PyObjectBase*>(obj)->isValid()){
118
PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr);
122
int ret = static_cast<Base::PyObjectBase*>(obj)->_setattr(attr, value);
124
static_cast<Base::PyObjectBase*>(obj)->startNotify();
130
template<class FeaturePyT>
131
int FeaturePythonPyT<FeaturePyT>::_setattr(const char *attr, PyObject *value)
133
App::Property *prop = FeaturePyT::getPropertyContainerPtr()->getPropertyByName(attr);
134
if (prop && !value) {
135
PyErr_Format(PyExc_AttributeError, "Cannot delete attribute: '%s'", attr);
139
int returnValue = FeaturePyT::_setattr(attr, value);
140
if (returnValue == -1) {
141
PyObject* dict_item = value;
143
if (PyFunction_Check(value)) {
145
dict_item = PyMethod_New(value, this);
146
returnValue = PyDict_SetItemString(dict_methods, attr, dict_item);
147
Py_XDECREF(dict_item);
153
returnValue = PyDict_DelItemString(dict_methods, attr);
154
if (returnValue < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
155
PyErr_SetString(PyExc_AttributeError, attr);
161
template<class FeaturePyT>
162
PyObject *FeaturePythonPyT<FeaturePyT>::_getattr(const char *attr)
164
// See CallTipsList::extractTips
165
if (Base::streq(attr, "__fc_template__")) {
170
// get only attributes of this type
171
if (Base::streq(attr, "__dict__")) {
172
// Return the default dict
173
PyTypeObject *tp = this->ob_type;
174
// register type if needed
176
if (PyType_Ready(tp) < 0)
180
PyObject* dict = FeaturePyT::_getattr(attr);
181
if (dict && PyDict_CheckExact(dict)) {
182
PyObject* dict_old = dict;
183
dict = PyDict_Copy(dict_old);
184
Py_DECREF(dict_old); // delete old dict
185
PyDict_Merge(dict, dict_methods, 0);
190
// find the attribute in the dict
191
PyObject *dict_item = nullptr;
192
dict_item = PyDict_GetItemString(dict_methods, attr);
194
Py_INCREF(dict_item);
198
// search for the attribute in the base class
200
return FeaturePyT::_getattr(attr);