Library of Assembled Shared Sources
 
Loading...
Searching...
No Matches
pyobject_plus.cpp
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2025 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43
44
45#include "python_common.h"
46#include "pyobject_plus.h"
47#include "py_tuple.h"
48#include "pyiteratorrange.h"
49#include <iostream>
50
51namespace lass
52{
53namespace python
54{
55
56impl::ClassDefinition PyObjectPlus::_lassPyClassDef(
57 "PyObjectPlus", 0, sizeof(PyObjectPlus), 0, 0, &PyObjectPlus::_lassPyClassRegisterHook);
58
59/** This function can be used to execute some code at injection time.
60 * By default it doens't do anything, but you can override it for
61 * any type. Be aware that the top level implementation is the
62 * only one that counts. Consider it as a 'virtual' function at
63 * static level
64 */
68
69PyObjectPlus::PyObjectPlus()
70{
71 // initializing the type to NULL, when the object is exported to python the type is fixed
72 this->ob_type = NULL;
73 LockGIL lock;
74 _Py_NewReference( this );
75};
76
77PyObjectPlus::~PyObjectPlus()
78{
79 LASS_ASSERT(Py_REFCNT(this) <= 1);
80 if (Py_REFCNT(this) > 1)
81 {
82 std::cerr << "[LASS RUN MSG] DANGLING REFERENCE to lass::python::PyObjectPlus" << std::endl;
83 }
84};
85
86PyObjectPlus::PyObjectPlus(const PyObjectPlus& other)
87{
88 LockGIL lock;
89 this->ob_type = other.ob_type;
90 Py_XINCREF(this->ob_type);
91 _Py_NewReference( this );
92}
93
94PyObjectPlus& PyObjectPlus::operator =([[maybe_unused]] const PyObjectPlus& iOther)
95{
96 LASS_ASSERT(!this->ob_type || this->ob_type == iOther.ob_type);
97 return *this;
98}
99
100// --- impl ----------------------------------------------------------------------------------------
101
102namespace impl
103{
104
105/** @internal
106*/
107bool checkSequenceSize(PyObject* obj, Py_ssize_t expectedSize)
108{
109 LockGIL lock;
110 if (!PySequence_Check(obj))
111 {
112 PyErr_SetString(PyExc_TypeError, "not a python sequence (tuple, list, ...)");
113 return false;
114 }
115 const Py_ssize_t size = PySequence_Size(obj);
116 if (size != expectedSize)
117 {
118 std::ostringstream buffer;
119 buffer << "tuple/list is not of expected size " << expectedSize << " (size is " << size << ")";
120 PyErr_SetString(PyExc_TypeError, buffer.str().c_str());
121 return false;
122 }
123 return true;
124}
125
126/** @internal
127 * Check that @a obj is a sequence, and return it as a "FAST sequence"
128 * so that you can use PySequence_Fast_GET_ITEM to get its items with borrowed references.
129 */
130TPyObjPtr checkedFastSequence(PyObject* obj)
131{
132 LockGIL lock;
133 return TPyObjPtr(PySequence_Fast(obj, "expected a sequence (tuple, list, ...)"));
134}
135
136/** @internal
137 * Check that @a obj is a sequence and of expected size, and return it as a "FAST sequence"
138 * so that you can use PySequence_Fast_GET_ITEM to get its items with borrowed references.
139 */
140TPyObjPtr checkedFastSequence(PyObject* obj, Py_ssize_t expectedSize)
141{
142 LockGIL lock;
143 TPyObjPtr result = checkedFastSequence(obj);
144 if (result)
145 {
146 const Py_ssize_t size = PySequence_Fast_GET_SIZE(result.get());
147 if (size != expectedSize)
148 {
149 std::ostringstream buffer;
150 buffer << "expected a sequence of size " << expectedSize << " (your size is " << size << ")";
151 PyErr_SetString(PyExc_TypeError, buffer.str().c_str());
152 result.reset();
153 }
154 }
155 return result;
156}
157
158/** @internal
159 * Check that @a obj is a sequence and of expected size, and return it as a "FAST sequence"
160 * so that you can use PySequence_Fast_GET_ITEM to get its items with borrowed references.
161 */
162TPyObjPtr checkedFastSequence(PyObject* obj, Py_ssize_t minimumSize, Py_ssize_t maximumSize)
163{
164 LockGIL lock;
165 TPyObjPtr result = checkedFastSequence(obj);
166 if (result)
167 {
168 const Py_ssize_t size = PySequence_Fast_GET_SIZE(result.get());
169 if (size < minimumSize || size > maximumSize)
170 {
171 std::ostringstream buffer;
172 buffer << "expected a sequence of size between " << minimumSize << " and " << maximumSize
173 << " inclusive (your size is " << size << ")";
174 PyErr_SetString(PyExc_TypeError, buffer.str().c_str());
175 result.reset();
176 }
177 }
178 return result;
179}
180
181/** Here, we try to fix some lifetime issues to guarantee some lifetime requirements on self.
182 */
183PyObject* establishMagicalBackLinks(PyObject* result, PyObject* self)
184{
185 if (!result)
186 {
187 return 0;
188 }
189 if (PyIteratorRange::_lassPyClassDef.isFrozen_ && result->ob_type == PyIteratorRange::_lassPyClassDef.type())
190 {
191 LockGIL lock;
192 PyIteratorRange* iter = static_cast<PyIteratorRange*>(result);
193 if (!iter->owner())
194 {
196 }
197 }
198 return result;
199}
200
201}
202}
203}
204
205// EOF
acquire the GIL for the current scope.
Definition gil.h:56
Python iterator object.
void setOwner(const TPyObjPtr &owner)
Owner object of the iterators.
const TPyObjPtr & owner() const
Owner object of the iterators.
static void _lassPyClassRegisterHook()
This function can be used to execute some code at injection time.
Definition of a Python class.
friend LASS_PYTHON_DLL PyObject *LASS_CALL establishMagicalBackLinks(PyObject *result, PyObject *self)
Here, we try to fix some lifetime issues to guarantee some lifetime requirements on self.
PyObjectPtr< PyObject >::Type TPyObjPtr
PyObjectPtr to a PyObject.
lass::util::SharedPtr< T, PyObjectStorage, PyObjectCounter > fromNakedToSharedPtrCast(PyObject *object)
fromNakedToSharedPtrCast.
Comprehensive C++ to Python binding library.
Library for Assembled Shared Sources.
Definition config.h:53