Library of Assembled Shared Sources
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 LASS_UNUSED(lock);
74 _Py_NewReference( this );
75};
76
77PyObjectPlus::~PyObjectPlus()
78{
79 if (this->ob_refcnt>0)
80 {
81 if (this->ob_refcnt>1)
82 {
83 std::cerr << "[LASS RUN MSG] DANGLING REFERENCE to lass::python::PyObjectPlus"
84 << std::endl;
85 }
86 --this->ob_refcnt;
87 }
88 LASS_ASSERT(this->ob_refcnt==0);
89};
90
91PyObjectPlus::PyObjectPlus(const PyObjectPlus& other)
92{
93 LockGIL LASS_UNUSED(lock);
94 this->ob_type = other.ob_type;
95 Py_XINCREF(this->ob_type);
96 _Py_NewReference( this );
97}
98
99PyObjectPlus& PyObjectPlus::operator =([[maybe_unused]] const PyObjectPlus& iOther)
100{
101 LASS_ASSERT(!this->ob_type || this->ob_type == iOther.ob_type);
102 return *this;
103}
104
105// --- impl ----------------------------------------------------------------------------------------
106
107namespace impl
108{
109
110/** @internal
111*/
112bool checkSequenceSize(PyObject* obj, Py_ssize_t expectedSize)
113{
114 LockGIL LASS_UNUSED(lock);
115 if (!PySequence_Check(obj))
116 {
117 PyErr_SetString(PyExc_TypeError, "not a python sequence (tuple, list, ...)");
118 return false;
119 }
120 const Py_ssize_t size = PySequence_Size(obj);
121 if (size != expectedSize)
122 {
123 std::ostringstream buffer;
124 buffer << "tuple/list is not of expected size " << expectedSize << " (size is " << size << ")";
125 PyErr_SetString(PyExc_TypeError, buffer.str().c_str());
126 return false;
127 }
128 return true;
129}
130
131/** @internal
132 * Check that @a obj is a sequence, and return it as a "FAST sequence"
133 * so that you can use PySequence_Fast_GET_ITEM to get its items with borrowed references.
134 */
135TPyObjPtr checkedFastSequence(PyObject* obj)
136{
137 LockGIL LASS_UNUSED(lock);
138 return TPyObjPtr(PySequence_Fast(obj, "expected a sequence (tuple, list, ...)"));
139}
140
141/** @internal
142 * Check that @a obj is a sequence and of expected size, and return it as a "FAST sequence"
143 * so that you can use PySequence_Fast_GET_ITEM to get its items with borrowed references.
144 */
145TPyObjPtr checkedFastSequence(PyObject* obj, Py_ssize_t expectedSize)
146{
147 LockGIL LASS_UNUSED(lock);
148 TPyObjPtr result = checkedFastSequence(obj);
149 if (result)
150 {
151 const Py_ssize_t size = PySequence_Fast_GET_SIZE(result.get());
152 if (size != expectedSize)
153 {
154 std::ostringstream buffer;
155 buffer << "expected a sequence of size " << expectedSize << " (your size is " << size << ")";
156 PyErr_SetString(PyExc_TypeError, buffer.str().c_str());
157 result.reset();
158 }
159 }
160 return result;
161}
162
163/** @internal
164 * Check that @a obj is a sequence and of expected size, and return it as a "FAST sequence"
165 * so that you can use PySequence_Fast_GET_ITEM to get its items with borrowed references.
166 */
167TPyObjPtr checkedFastSequence(PyObject* obj, Py_ssize_t minimumSize, Py_ssize_t maximumSize)
168{
169 LockGIL LASS_UNUSED(lock);
170 TPyObjPtr result = checkedFastSequence(obj);
171 if (result)
172 {
173 const Py_ssize_t size = PySequence_Fast_GET_SIZE(result.get());
174 if (size < minimumSize || size > maximumSize)
175 {
176 std::ostringstream buffer;
177 buffer << "expected a sequence of size between " << minimumSize << " and " << maximumSize
178 << " inclusive (your size is " << size << ")";
179 PyErr_SetString(PyExc_TypeError, buffer.str().c_str());
180 result.reset();
181 }
182 }
183 return result;
184}
185
186/** Here, we try to fix some lifetime issues to guarantee some lifetime requirements on self.
187 */
188PyObject* establishMagicalBackLinks(PyObject* result, PyObject* self)
189{
190 if (!result)
191 {
192 return 0;
193 }
194 if (PyIteratorRange::_lassPyClassDef.isFrozen_ && result->ob_type == PyIteratorRange::_lassPyClassDef.type())
195 {
196 LockGIL LASS_UNUSED(lock);
197 PyIteratorRange* iter = static_cast<PyIteratorRange*>(result);
198 if (!iter->owner())
199 {
201 }
202 }
203 return result;
204}
205
206}
207}
208}
209
210// 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