[ci] Fix clang-santisers job for GHA change
[xapian.git] / xapian-bindings / python3 / python.i
blobe6ef3ba8a53980f54df4b781f297fac1dd9dd9fa
1 %module(directors="1", moduleimport="from . import _xapian") xapian
2 %{
3 /* python.i: SWIG interface file for the Python bindings
5 * Copyright (C) 2011-2023 Olly Betts
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
24 %pythonbegin %{
25 """
26 Xapian is a highly adaptable toolkit which allows developers to easily
27 add advanced indexing and search facilities to their own applications.
28 It has built-in support for several families of weighting models
29 and also supports a rich set of boolean query operators.
31 In addition to the doc strings provided by this python library, you
32 may wish to look at the library's overall documentation, either
33 installed along with the bindings or online at
34 <https://xapian.org/docs/bindings/python/>, as well as the library's
35 documentation, possibly installed with the library or with its
36 development files, or again online at <https://xapian.org/docs/>.
37 """
40 %begin %{
41 #include <config.h>
43 #ifdef __clang__
44 // The Python 3.3 headers have several uses of the C register keyword, which
45 // result in warnings from clang++ 6. There's nothing we can really do about
46 // them, so just suppress them. This appears to have been addressed in Python
47 // 3.4 and later.
48 # pragma clang diagnostic push
49 # pragma clang diagnostic ignored "-Wdeprecated-register"
50 #endif
52 #include <Python.h>
54 #ifdef __clang__
55 # pragma clang diagnostic pop
56 #endif
58 /* Override SWIG's standard GIL locking machinery - we want to handle the GIL
59 * in a way which also works in sub-interpreters.
61 * For Python < 3.7 we can also avoid the overhead of thread locking when the
62 * user's code isn't using threads (since 3.7, Python always initialises
63 * threads.)
65 #define SWIG_PYTHON_NO_USE_GIL
67 #ifdef THREAD_LOCAL
69 static THREAD_LOCAL PyThreadState * swig_pythreadstate = NULL;
71 inline void swig_pythreadstate_ensure_init() { }
73 inline PyThreadState * swig_pythreadstate_reset() {
74 PyThreadState * v = swig_pythreadstate;
75 if (v) swig_pythreadstate = NULL;
76 return v;
79 inline PyThreadState * swig_pythreadstate_set(PyThreadState * v) {
80 PyThreadState * old = swig_pythreadstate;
81 swig_pythreadstate = v;
82 return old;
85 #else
87 #include <pthread.h>
89 static pthread_key_t swig_pythreadstate_key;
90 static pthread_once_t swig_pythreadstate_key_once = PTHREAD_ONCE_INIT;
92 static void swig_pythreadstate_make_key()
94 if (pthread_key_create(&swig_pythreadstate_key, NULL) != 0)
95 Py_FatalError("pthread_key_create failed");
98 inline void swig_pythreadstate_ensure_init() {
99 pthread_once(&swig_pythreadstate_key_once, swig_pythreadstate_make_key);
102 inline PyThreadState * swig_pythreadstate_reset() {
103 PyThreadState * v = (PyThreadState*)pthread_getspecific(swig_pythreadstate_key);
104 if (v) pthread_setspecific(swig_pythreadstate_key, NULL);
105 return v;
108 inline PyThreadState* swig_pythreadstate_set(PyThreadState * v) {
109 PyThreadState * old = (PyThreadState*)pthread_getspecific(swig_pythreadstate_key);
110 pthread_setspecific(swig_pythreadstate_key, (void*)v);
111 return old;
114 #endif
116 class XapianSWIG_Python_Thread_Block {
117 bool status;
118 public:
119 XapianSWIG_Python_Thread_Block() : status(false) {
120 #if PY_VERSION_HEX < 0x03070000
121 // Since 3.7, Python initialises the GIL in PyInitialize() so
122 // PyEval_ThreadsInitialized() is no longer useful and was
123 // deprecated in 3.9.
124 if (!PyEval_ThreadsInitialized()) return;
125 #endif
126 swig_pythreadstate_ensure_init();
127 PyThreadState* ts = swig_pythreadstate_reset();
128 if (ts) {
129 status = true;
130 PyEval_RestoreThread(ts);
133 void end() {
134 if (status) {
135 if (swig_pythreadstate_set(PyEval_SaveThread()))
136 Py_FatalError("swig_pythreadstate set in XapianSWIG_Python_Thread_Block::end()");
137 status = false;
140 ~XapianSWIG_Python_Thread_Block() { end(); }
143 class XapianSWIG_Python_Thread_Allow {
144 bool status;
145 public:
146 XapianSWIG_Python_Thread_Allow() : status(true) {
147 #if PY_VERSION_HEX < 0x03070000
148 // Since 3.7, Python initialises the GIL in PyInitialize() so
149 // PyEval_ThreadsInitialized() is no longer useful and was
150 // deprecated in 3.9.
151 if (!PyEval_ThreadsInitialized()) {
152 status = false;
153 return;
155 #endif
156 swig_pythreadstate_ensure_init();
157 if (swig_pythreadstate_set(PyEval_SaveThread()))
158 Py_FatalError("swig_pythreadstate set in XapianSWIG_Python_Thread_Allow ctor");
160 void end() {
161 if (status) {
162 PyThreadState * ts = swig_pythreadstate_reset();
163 if (!ts)
164 Py_FatalError("swig_pythreadstate unset in XapianSWIG_Python_Thread_Block::end()");
165 PyEval_RestoreThread(ts);
166 status = false;
169 ~XapianSWIG_Python_Thread_Allow() { end(); }
172 #define SWIG_PYTHON_THREAD_BEGIN_BLOCK XapianSWIG_Python_Thread_Block _xapian_swig_thread_block
173 #define SWIG_PYTHON_THREAD_END_BLOCK _xapian_swig_thread_block.end()
174 #define SWIG_PYTHON_THREAD_BEGIN_ALLOW XapianSWIG_Python_Thread_Allow _xapian_swig_thread_allow
175 #define SWIG_PYTHON_THREAD_END_ALLOW _xapian_swig_thread_allow.end()
178 // Use SWIG directors for Python wrappers.
179 #define XAPIAN_SWIG_DIRECTORS
181 %include version.i
182 %include ../xapian-head.i
184 // Doccomments from Doxgyen-generated XML from C++ API docs.
185 %include doccomments.i
187 // Manually added exceptions for cases where the automatic comments aren't
188 // helpful, or are missing.
189 %include extracomments.i
191 %include util.i
193 // get_description() should return 'str' via the default typemap.
194 %typemap(out) std::string get_description() = std::string;
195 %typemap(out) std::string __str__() = std::string;
197 // All other std::string returns should map to 'bytes'.
198 %typemap(out) std::string %{
199 $result = PyBytes_FromStringAndSize($1.data(), $1.size());
201 %typemap(directorin) std::string, const std::string & %{
202 $input = PyBytes_FromStringAndSize($1_name.data(), $1_name.size());
204 // Similarly for std::string_view (`out` typemap not currently used).
205 %typemap(out) std::string_view %{
206 $result = PyBytes_FromStringAndSize($1.data(), $1.size());
208 %typemap(directorin) std::string_view %{
209 $input = PyBytes_FromStringAndSize($1_name.data(), $1_name.size());
212 // And const char * too.
213 %typemap(out) const char * %{
214 $result = PyBytes_FromString($1);
216 %typemap(directorin) const char * %{
217 $input = PyBytes_FromString($1_name);
220 // Make xapian.version_string() return a Unicode string.
221 %typemap(out) const char * version_string %{
222 $result = PyUnicode_FromString($1);
225 // Parameters where passing Unicode makes no sense.
226 %typemap(typecheck) const std::string & serialised %{
227 $1 = PyBytes_Check($input) ? 1 : 0;
229 %typemap(in) const std::string & serialised (std::string bytes) {
230 char * p;
231 Py_ssize_t len;
232 if (PyBytes_AsStringAndSize($input, &p, &len) < 0) SWIG_fail;
233 bytes.assign(p, len);
234 $1 = &bytes;
237 // Parameters where passing Unicode makes no sense.
238 %typemap(typecheck) std::string_view serialised %{
239 $1 = PyBytes_Check($input) ? 1 : 0;
241 %typemap(in) std::string_view serialised {
242 char * p;
243 Py_ssize_t len;
244 if (PyBytes_AsStringAndSize($input, &p, &len) < 0) SWIG_fail;
245 $1 = std::string_view(p, len);
247 %typemap(freearg) std::string_view serialised "";
249 #define XAPIAN_MIXED_SUBQUERIES_BY_ITERATOR_TYPEMAP
251 // Don't release the GIL for this method since we use Python C API calls to do
252 // the iteration.
253 %nothreadallow Xapian::Query::Query(op op_, XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend, Xapian::termcount parameter = 0);
255 %typemap(typecheck, precedence=500) (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend) {
256 // Checking for a sequence which isn't a string or bytes is enough to
257 // disambiguate currently.
258 $1 = (PySequence_Check($input) &&
259 !PyUnicode_Check($input) &&
260 !PyBytes_Check($input));
264 class XapianSWIGQueryItor {
265 mutable PyObject * seq;
267 int i;
269 /// str_obj must be a bytes object
270 Xapian::Query str_obj_to_query(PyObject * str_obj) const {
271 char * p;
272 Py_ssize_t len;
273 (void)PyBytes_AsStringAndSize(str_obj, &p, &len);
274 return Xapian::Query(string(p, len));
277 public:
278 typedef std::random_access_iterator_tag iterator_category;
279 typedef Xapian::Query value_type;
280 typedef Xapian::termcount_diff difference_type;
281 typedef Xapian::Query * pointer;
282 typedef Xapian::Query & reference;
284 XapianSWIGQueryItor() : seq(NULL), i(0) { }
286 void begin(PyObject * seq_) {
287 seq = seq_;
290 void end(PyObject * seq_) {
291 i = PySequence_Fast_GET_SIZE(seq_);
294 void free_seq() {
295 Py_CLEAR(seq);
298 XapianSWIGQueryItor & operator++() {
299 ++i;
300 return *this;
303 Xapian::Query operator*() const {
304 PyObject * obj = PySequence_Fast_GET_ITEM(seq, i);
306 // Unicode object.
307 if (PyUnicode_Check(obj)) {
308 PyObject* s = PyUnicode_AsUTF8String(obj);
309 if (!s) goto fail;
310 Xapian::Query result = str_obj_to_query(s);
311 Py_DECREF(s);
312 return result;
315 // String.
316 if (PyBytes_Check(obj))
317 return str_obj_to_query(obj);
319 // xapian.Query object (or unexpected object type).
321 Xapian::Query * result_ptr = Xapian::get_py_query(obj);
322 if (result_ptr) return *result_ptr;
325 fail:
326 throw Xapian::InvalidArgumentError("Expected Query object or string");
329 bool operator==(const XapianSWIGQueryItor & o) {
330 return i == o.i;
333 bool operator!=(const XapianSWIGQueryItor & o) {
334 return !(*this == o);
337 difference_type operator-(const XapianSWIGQueryItor &o) const {
338 return i - o.i;
344 %typemap(in) (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend) {
345 PyObject * seq;
346 seq = PySequence_Fast($input,
347 "expected sequence of Query objects and/or strings");
348 if (!seq) SWIG_fail;
349 $1.begin(seq);
350 $2.end(seq);
353 %typemap(freearg) (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend)
354 %{ $1.free_seq(); %}
356 %include except.i
357 %include ../xapian-headers.i
358 %include extra.i