File: pythoninterpreter.h

package info (click to toggle)
regina-normal 7.4.1-1.1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 154,244 kB
  • sloc: cpp: 295,026; xml: 9,992; sh: 1,344; python: 1,225; perl: 616; ansic: 138; makefile: 26
file content (471 lines) | stat: -rw-r--r-- 18,742 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471

/**************************************************************************
 *                                                                        *
 *  Regina - A Normal Surface Theory Calculator                           *
 *  Python Interface                                                      *
 *                                                                        *
 *  Copyright (c) 1999-2025, Ben Burton                                   *
 *  For further details contact Ben Burton (bab@debian.org).              *
 *                                                                        *
 *  This program is free software; you can redistribute it and/or         *
 *  modify it under the terms of the GNU General Public License as        *
 *  published by the Free Software Foundation; either version 2 of the    *
 *  License, or (at your option) any later version.                       *
 *                                                                        *
 *  As an exception, when this program is distributed through (i) the     *
 *  App Store by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or     *
 *  (iii) Google Play by Google Inc., then that store may impose any      *
 *  digital rights management, device limits and/or redistribution        *
 *  restrictions that are required by its terms of service.               *
 *                                                                        *
 *  This program is distributed in the hope that it will be useful, but   *
 *  WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *  General Public License for more details.                              *
 *                                                                        *
 *  You should have received a copy of the GNU General Public License     *
 *  along with this program. If not, see <https://www.gnu.org/licenses/>. *
 *                                                                        *
 **************************************************************************/

/*! \file pythoninterpreter.h
 *  \brief Provides an interface to the python interpreter and
 *  subinterpreters.
 *
 *  The accompanying source file (pythoninterpreter.cpp) should be built
 *  directly into each user interface that requires it.
 *  It is _not_ built into Regina's python module.
 */

#ifndef __PYTHONINTERPRETER_H
#define __PYTHONINTERPRETER_H

#include "regina-config.h" // Required for REGINA_PYBIND11_VERSION

#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#if REGINA_PYBIND11_VERSION == 3
#include <pybind11/subinterpreter.h>
#endif
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include "utilities/exception.h"

namespace regina {
    class Packet;
    class Script;
}

namespace regina::python {

class PythonOutputStream;

/**
 * A callback object that the user can pass to PythonInterpreter::complete().
 *
 * Subclasses must override addCompletion(), which receives completions
 * one at a time as PythonInterpreter::complete() finds them.
 */
class PythonCompleter {
    public:
        /**
         * Called each time addCompletion() finds a new completion.
         *
         * Note that python's completion code has been known to return the
         * same completion multiple times (in which case the same completion
         * will be passed to this function multiple times in turn).
         *
         * \param s the new completion.  This string will begin with the
         * original text that was passed to PythonCompleter::complete().
         * \return \c true to indicate that PythonCompleter::complete()
         * should continue searching for more completions, or \c false
         * if PythonCompleter::complete() can finish now.
         */
        virtual bool addCompletion(const std::string& s) = 0;
};

/**
 * A python completion callback that computes the longest common prefix
 * for all of the completions that it receives.  This can (for example)
 * be used to decide what text to immediately append to the current line
 * when tab is pressed.
 *
 * The common prefix is computed in terms of unicode characters, not raw bytes.
 */
class PrefixCompleter : public PythonCompleter {
    private:
        bool initialised_;
            /** Has this object received any completions at all yet? */
        std::string prefix_;
            /** The longest common prefix for all completions received. */

    public:
        /**
         * Creates a new callback object.  You will need to create a new
         * object each time you call PythonCompleter::complete(); that is,
         * you cannot reuse the same callback object across multiple
         * calls to PythonCompleter::complete().
         */
        PrefixCompleter();
        /**
         * Returns the longest common prefix for all completions received so
         * far.  If no completions have been received at all, then this
         * will be the empty string.
         *
         * The common prefix is computed in terms of unicode characters,
         * and the return value will be a valid UTF-8 string.
         *
         * \return the longest common prefix for all completions.
         */
        const std::string& prefix() const;

        bool addCompletion(const std::string& s) override;
};

/**
 * A single python subinterpreter.  Multiple subinterpreters are independent
 * and may exist simultaneously.
 *
 * Each new subinterpreter corresponds to a new call to
 * Py_NewInterpreter().  The global routine Py_Initialize() is called when
 * the first interpreter is created, and Py_Finalize() is never called.
 */
class PythonInterpreter {
    private:
        static bool pythonInitialised;
            /**< Has the python system (i.e., the main interpreter) been
                 initialised yet?  This is only done on demand. */

#if REGINA_PYBIND11_VERSION == 3
        static std::mutex initMutex;
            /**< A mutual exclusion device to protect the creation of the main
                 interpreter. */
        pybind11::subinterpreter subInterpreter;
            /**< This specific subinterpreter. */
#elif REGINA_PYBIND11_VERSION == 2
        static std::mutex interpreterMutex;
            /**< A mutual exclusion device to protect the creation and/or
                 destruction of the main interpreter and subinterpreters. */
        std::thread::id thread;
            /**< The ID of the C++ thread to be used exclusively with this
                 subinterpreter. */
        PyThreadState* state;
            /**< The first thread state created in this particular
                 subinterpreter. */
#else
        #error "Unsupported pybind11 version"
#endif

        PyObject* mainModule;
            /**< The __main__ module. */
        PyObject* mainNamespace;
            /**< The global namespace. */
        PyObject* completer;
            /**< The current plainCompleter::Completer object, or \c null
                 if one could not be created. */
        PyObject* completerFunc;
            /**< The method completer.complete(), or \c null if this reference
                 could not be acquired. */

        std::string currentCode;
            /**< Any previous statements (such as loop openings) that are
                 waiting to be completed. */

        bool caughtSystemExit;
            /**< Has the interpreter thrown a SystemExit exception? */

        PythonOutputStream& output;
            /**< The stream that we are using for sys.stdout. */
        PythonOutputStream& errors;
            /**< The stream that we are using for sys.stderr. */

    public:
        /**
         * Constructor.
         *
         * In the constructor, if \a fixPythonPath is \c true then:
         *
         * - if Regina ships its own copy of Python, then this constructor
         *   will adjust the Python path so that Regina's copy of the core
         *   Python libraries can be found;
         *
         * - if necessary, this constructor will also adjust the Python path
         *   so that Regina's own module can be found.
         *
         * If \a fixPythonPath is \c false then the Python path will not be
         * touched at all.
         */
        PythonInterpreter(
            regina::python::PythonOutputStream& pyStdOut,
            regina::python::PythonOutputStream& pyStdErr,
            bool fixPythonPath = true);

        /**
         * Destructor.
         *
         * \pre This is called from the same C++ thread that created
         * this Python interpreter.
         */
        ~PythonInterpreter();

        /**
         * Execute a single line of code in the subinterpreter.
         * Returns \c true if no further input is required, or
         * \c false if the interpreter is waiting on further lines of code.
         *
         * This is intended for use in an interactive Python session.
         *
         * You should always test exitAttempted() after executing user code.
         *
         * \pre This is called from the same C++ thread that created
         * this Python interpreter.
         */
        bool executeLine(const std::string& command);

        /**
         * Imports Regina's python module.
         *
         * This function also sets up a completer object, for use with
         * complete().
         *
         * If \a fixPythonPath is \c true, then this routine will (before the
         * import) adjust the Python path so that Regina's module can be found.
         *
         * \pre This is called from the same C++ thread that created
         * this Python interpreter.
         *
         * \return \c true on success or \c false on failure.
         */
        bool importRegina(bool fixPythonPath = true);

        /**
         * Asks Regina to deduce where its supporting files are installed.
         *
         * This simply calls `regina.GlobalDirs.deduceDirs()` via Python,
         * using a properly escaped version of \a executable.
         *
         * \param executable the path to an executable, which would
         * typically be the executable currently being run.
         */
        bool deduceDirs(const std::string& executable);

        /**
         * Set the given variable in Python's main namespace to
         * represent the given Regina packet.
         *
         * \pre This is called from the same C++ thread that created
         * this Python interpreter.
         *
         * \return \c true on success or \c false on failure.
         */
        bool setVar(const char* name, std::shared_ptr<Packet> value);

        /**
         * Run the given script packet in Python's main namespace.
         * This involves setting all of the script variables, and then running
         * the script code itself.
         *
         * This routine flushes standard output and standard error.
         *
         * You should always test exitAttempted() after executing user code.
         *
         * \pre This is called from the same C++ thread that created
         * this Python interpreter.
         *
         * \return \c true on success or \c false on failure.
         */
        bool runScript(const regina::Script* script);

        /**
         * Flushes the standard output and error streams.
         *
         * This may be called regardless of whether or not the Python
         * global interpreter lock is currently held.
         */
        void flush();

        /**
         * Has the subinterpreter attempted to exit?
         *
         * Specifically, this tests whether a \c SystemExit exception
         * has been thrown (typically by calling a Python function such as
         * exit(), quit(), or sys.quit()).  In a command-line python
         * session, such a function would exit the python * session; here it
         * just sets this flag so the enclosing GUI can clean up nicely.
         *
         * This does _not_ capture os._exit(), which will instead
         * immediately terminate the parent process (i.e., the enclosing GUI).
         */
        bool exitAttempted() const;

        /**
         * Attempts to complete the given Python string.
         *
         * The completion process uses Regina's \c plainCompleter Python
         * module, which is a copy of Python's own \c rlcompleter module
         * with all \c readline interaction disabled (since \c readline does
         * not play well with subinterpreters and may produce deadlocks).
         * See the Python documentation for \c rlcompleter for what
         * text can be completed and how completion works.
         *
         * Each completion that is found will be passed to \a completer
         * using PythonCompleter::addCompletion(), until either
         * (i) \a completer returns \c false to signify that no more
         * completions are required, or (ii) no more completions can be found.
         *
         * \pre This is called from the same C++ thread that created
         * this Python interpreter.
         *
         * \param text the Python text to complete.
         * \param completer the callback object that will receive the
         * resulting completions (if any).
         * \return the number of completions that were passed to \a completer,
         * or -1 if the completion process failed (e.g., the \c plainCompleter
         * Python module could not be imported).  In particular, if the
         * completion process ran succesfully and determined that the given
         * text has no completions at all, this routine will return 0.
         */
        int complete(const std::string& text, PythonCompleter& completer);

    private:
#if REGINA_PYBIND11_VERSION == 2
        /**
         * Ensures that the current C++ thread is in fact the thread that
         * created this subinterpreter.
         *
         * When this function is called, it is typically verifying a
         * precondition to some other member function of PythonInterpreter.
         * Therefore the behaviour when this check _fails_ is subject to
         * change in future versions of Regina (since in theory, it should
         * never happen).
         */
        void verifyThread() const;
#endif

        /**
         * Run the given Python code in Python's main namespace.
         *
         * \pre This is called from the same C++ thread that created
         * this Python interpreter.
         */
        bool runCode(const char* code);

        /**
         * Is the given command comment or only whitespace?
         */
        static bool isEmptyCommand(const std::string& command);

        /**
         * Extract the current error message.  A new python reference is
         * returned.
         */
        static PyObject* extractErrMsg();

        /**
         * Push regina's python path onto the beginning of python's sys.path.
         *
         * This routine assumes that the global interpreter lock is already
         * held by the current thread, and it acts on the (sub-)interpreter
         * that is referenced by the current python thread state.
         */
        static void prependReginaToSysPath();

        /**
         * Attempt to import regina into the given namespace.  Typically
         * \a useNamespace would be the main namespace for either the
         * main interpreter or a subinterpreter.
         *
         * This routine assumes that the global interpreter lock is already
         * held by the current thread.  It acts on the (sub-)interpreter
         * that is referenced by the current python thread state, to which
         * the given namespace must belong.
         *
         * If \a fixPythonPath is \c true, then this routine will (before the
         * import) adjust the Python path so that Regina's module can be found.
         *
         * Returns \c true on success or \c false on failure.
         */
        static bool importReginaIntoNamespace(PyObject* useNamespace,
            bool fixPythonPath = true);

#if REGINA_PYBIND11_VERSION == 2
        /**
         * An object that calls PyEval_RestoreThread() on construction
         * and PyEval_SaveThread() on destruction.  This manages both
         * (i) the Python thread state for the subinterpreter being used,
         * and also (ii) the Python global interpreter lock.
         *
         * This class insists that the same C++ that created the Python
         * subinterpreter is also used for both construction and destruction
         * of the ScopedThreadRestore object.
         *
         * An object of this type cannot be copied or moved.
         */
        class ScopedThreadRestore {
            private:
                PythonInterpreter& interpreter_;
                    /**< The Python subinterpreter being used. */

            public:
                /**
                 * Restores the primary Python thread for the given Python
                 * subinterpreter.
                 *
                 * \pre This constructor is called from the same C++ thread
                 * that created the given interpreter.
                 */
                ScopedThreadRestore(PythonInterpreter& interpreter) :
                        interpreter_(interpreter) {
                    interpreter.verifyThread();
                    PyEval_RestoreThread(interpreter.state);
                }

                /**
                 * Saves the current Python thread.
                 *
                 * \pre This destructor is called from the same C++ thread
                 * as the corresponding constructor.
                 */
                ~ScopedThreadRestore() {
                    interpreter_.state = PyEval_SaveThread();
                }

                ScopedThreadRestore(const ScopedThreadRestore&) = delete;
                ScopedThreadRestore& operator = (const ScopedThreadRestore&)
                    = delete;
        };
#endif
};

inline PrefixCompleter::PrefixCompleter() : initialised_(false) {
}

inline const std::string& PrefixCompleter::prefix() const {
    return prefix_;
}

inline bool PythonInterpreter::exitAttempted() const {
    return caughtSystemExit;
}

#if REGINA_PYBIND11_VERSION == 2
inline void PythonInterpreter::verifyThread() const {
    if (std::this_thread::get_id() != thread) {
        /*
        std::cerr << "ERROR: A PythonInterpreter was used from the wrong "
            "C++ thread.\n\n"
            "Please report this to the Regina developers!\n"
            << std::endl;
        */
        throw regina::FailedPrecondition(
            "PythonInterpreter used from the wrong C++ thread");
    }
}
#endif

} // namespace regina::python

#endif