16 #include <QInputDialog>
17 #include <QApplication>
18 #include <QFileDialog>
23 #include "hal_config.h"
29 #if PY_VERSION_HEX < 0x030900a0
40 PythonContext::PythonContext(
QObject *parent)
41 :
QObject(parent), mContext(nullptr), mSender(nullptr), mTriggerReset(false), mThread(nullptr),
42 mThreadAborted(false), mInterpreterCaller(nullptr)
44 py::initialize_interpreter();
59 mMainThreadState = PyEval_SaveThread();
63 PythonContext::~PythonContext()
65 PyEval_RestoreThread(mMainThreadState);
68 py::finalize_interpreter();
71 void PythonContext::setConsole(PythonConsole* c)
76 connect(mConsole,&PythonConsole::inputReceived,
this,&PythonContext::handleConsoleInputReceived);
80 PythonThread* PythonContext::pythonThread()
const
85 void PythonContext::abortThread()
88 mThreadAborted =
true;
92 void PythonContext::abortThreadAndWait()
99 void PythonContext::initializeContext(py::dict* context)
103 std::string
command =
"import __main__\n"
104 "import io, sys, threading, builtins\n";
107 command +=
"sys.path.append('" + path.string() +
"')\n";
111 "from hal_gui.console import reset\n"
112 "from hal_gui.console import clear\n"
113 "class StdOutCatcher(io.TextIOBase):\n"
114 " def __init__(self):\n"
116 " def write(self, stuff):\n"
117 " from hal_gui import console\n"
118 " if threading.current_thread() is threading.main_thread():\n"
119 " console.redirector.write_stdout(stuff)\n"
121 " console.redirector.thread_stdout(stuff)\n"
122 "class StdErrCatcher(io.TextIOBase):\n"
123 " def __init__(self):\n"
125 " def write(self, stuff):\n"
126 " from hal_gui import console\n"
127 " if threading.current_thread() is threading.main_thread():\n"
128 " console.redirector.write_stderr(stuff)\n"
130 " console.redirector.thread_stderr(stuff)\n"
131 "def redirect_input(prompt=\"Please enter input:\"):\n"
132 " if threading.current_thread() is threading.main_thread():\n"
133 " return \"input in main thread not supported\"\n"
135 " return console.redirector.thread_stdin(prompt)\n"
136 "sys.stdout = StdOutCatcher()\n"
137 "sys.__stdout__ = sys.stdout\n"
138 "sys.stderr = StdErrCatcher()\n"
139 "sys.__stderr__ = sys.stderr\n"
140 "builtins.input = redirect_input\n"
141 "builtins.raw_input = redirect_input\n"
144 py::exec(
command, *context, *context);
154 void PythonContext::initializeScript(py::dict *context)
158 std::string
command =
"import __main__\n"
159 "import io, sys, threading\n"
160 "from hal_gui.console import reset\n"
161 "from hal_gui.console import clear\n"
164 py::exec(
command, *context, *context);
175 void PythonContext::initPython()
182 mContext =
new py::dict(**py::globals());
184 initializeContext(mContext);
189 void PythonContext::closePython()
196 void PythonContext::interpretBackground(
QObject* caller,
const QString& input,
bool multiple_expressions)
203 if (input ==
"quit()")
205 forwardError(
"quit() cannot be used in this interpreter. Use console.reset() to restart it.\n");
209 if (input ==
"help()")
211 forwardError(
"help() cannot be used in this interpreter.\n");
215 if (input ==
"license()")
217 forwardError(
"license() cannot be used in this interpreter.\n");
223 forwardError(
"python thread already running. Please retry after other thread finished.\n");
226 log_info(
"python",
"Python console execute: \"{}\".",
input.toStdString());
228 mInterpreterCaller = caller;
229 startThread(input,!multiple_expressions);
232 void PythonContext::startThread(
const QString& input,
bool singleStatement)
234 mThread =
new PythonThread(input,singleStatement,
this);
236 connect(mThread,&PythonThread::stdOutput,
this,&PythonContext::handleScriptOutput);
237 connect(mThread,&PythonThread::stdError,
this,&PythonContext::handleScriptError);
238 connect(mThread,&PythonThread::requireInput,
this,&PythonContext::handleInputRequired);
239 if (mConsole) mConsole->setReadOnly(
true);
240 mLayoutLocker =
new LayoutLocker;
244 void PythonContext::interpretForeground(
const QString &input)
251 log_info(
"python",
"Python console execute: \"{}\".",
input.toStdString());
255 PyGILState_STATE
state = PyGILState_Ensure();
265 rc = py::eval<py::eval_single_statement>(
input.toStdString(), *mContext, *mContext);
272 catch (py::error_already_set& e)
274 qDebug() <<
"interpret error set";
279 catch (std::exception& e)
281 qDebug() <<
"interpret exception";
286 PyGILState_Release(state);
291 void PythonContext::interpretScript(
QObject* caller,
const QString& input)
295 log_warning(
"python",
"Not executed, python script already running");
301 log_info(
"UserStudy",
"Python editor execute script:\n{}\n",
input.toStdString());
304 forwardStdout(
"<Execute Python Editor content>");
307 mInterpreterCaller = caller;
308 startThread(input,
false);
311 void PythonContext::handleScriptOutput(
const QString& txt)
317 void PythonContext::handleScriptError(
const QString& txt)
323 void PythonContext::handleInputRequired(
int type,
const QString& prompt,
const QVariant &defaultValue)
326 if (mThread && !mThread->stdoutBuffer().isEmpty())
327 mConsole->handleStdout(mThread->flushStdout());
330 case PythonThread::ConsoleInput:
331 mConsole->handleStdout(prompt +
"\n");
332 mConsole->setInputMode(
true);
333 mConsole->displayPrompt();
334 mConsole->setReadOnly(
false);
336 case PythonThread::StringInput:
339 if (!confirm) userInput.
clear();
340 if (mThread) mThread->setInput(userInput);
343 case PythonThread::NumberInput:
346 if (mThread) mThread->setInput(userInput);
349 case PythonThread::GateInput:
354 PythonGateSelectionReceiver* pgs =
new PythonGateSelectionReceiver(mThread,
this);
355 GateDialog gd(gats, prompt, pgs, qApp->activeWindow());
359 if (!gd.pickerModeActivated() && mThread) mThread->setInput(QVariant::fromValue<void*>(gatSelect));
362 case PythonThread::ModuleInput:
366 PythonModuleSelectionReceiver* pms =
new PythonModuleSelectionReceiver(mThread,
this);
367 ModuleDialog md({}, prompt,
false, pms, qApp->activeWindow());
371 if (!md.pickerModeActivated() && mThread) mThread->setInput(QVariant::fromValue<void*>(modSelect));
374 case PythonThread::FilenameInput:
377 if (mThread) mThread->setInput(userInput);
385 void PythonGateSelectionReceiver::handleGatesPicked(
const QSet<u32>& gats)
390 if (mThread) mThread->setInput(QVariant::fromValue<void*>(gatSelect));
394 void PythonModuleSelectionReceiver::handleModulesPicked(
const QSet<u32>& mods)
399 if (mThread) mThread->setInput(QVariant::fromValue<void*>(modSelect));
403 void PythonContext::handleConsoleInputReceived(
const QString& input)
405 mConsole->setInputMode(
false);
406 mConsole->setReadOnly(
true);
407 mThread->setInput(input);
410 void PythonContext::handleThreadFinished()
412 if (mConsole) mConsole->setReadOnly(
false);
413 PythonEditor* calledFromEditor =
dynamic_cast<PythonEditor*
>(mInterpreterCaller);
417 mThreadAborted =
false;
422 errmsg = mThread->errorMessage();
423 if (!mThread->stdoutBuffer().isEmpty())
424 forwardStdout(mThread->stdoutBuffer());
425 if (!calledFromEditor && !mThread->result().isEmpty() && errmsg.
isEmpty())
426 forwardStdout(mThread->result());
430 forwardError(
"\nPython thread aborted\n");
431 mThreadAborted =
false;
434 mThread->deleteLater();
436 delete mLayoutLocker;
439 forwardError(errmsg);
441 if (calledFromEditor)
443 calledFromEditor->handleThreadFinished();
446 forwardError(
"\nreset() can only be used in the Python console!\n");
447 mTriggerReset =
false;
451 forwardError(
"\nclear() can only be used in the Python console!\n");
452 mTriggerClear =
false;
459 mConsole->handleThreadFinished();
464 mConsole->setInputMode(PythonConsole::Standard);
465 mConsole->displayPrompt();
469 void PythonContext::forwardStdout(
const QString& output)
477 mConsole->handleStdout(output);
481 void PythonContext::forwardError(
const QString& output)
486 mConsole->handleError(output);
490 std::vector<std::tuple<std::string, std::string>> PythonContext::complete(
const QString& text,
bool use_console_context)
492 PyGILState_STATE
state = PyGILState_Ensure();
494 std::vector<std::tuple<std::string, std::string>> ret_val;
497 auto namespaces = py::list();
498 if (use_console_context)
500 namespaces.append(*mContext);
501 namespaces.append(*mContext);
505 py::dict tmp_context = py::globals();
506 initializeContext(&tmp_context);
507 namespaces.append(tmp_context);
508 namespaces.append(tmp_context);
511 py::object script = jedi.attr(
"Interpreter")(text.
toStdString(), namespaces);
513 if (py::hasattr(script,
"complete"))
514 list = script.attr(
"complete")();
515 else if (py::hasattr(script,
"completions"))
516 list = script.attr(
"completions")();
518 log_warning(
"python",
"Jedi autocompletion failed, neither complete() nor completions() found.");
520 for (
const auto& entry : list)
522 auto a = entry.attr(
"name_with_symbols").cast<std::string>();
523 auto b = entry.attr(
"complete").cast<std::string>();
524 ret_val.emplace_back(a, b);
527 catch (py::error_already_set& e)
534 PyGILState_Release(state);
539 int PythonContext::checkCompleteStatement(
const QString& text)
542 PyGILState_STATE
state = PyGILState_Ensure();
544 #if PY_VERSION_HEX < 0x030900a0
553 if (e.error == E_EOF)
555 PyGILState_Release(state);
558 PyGILState_Release(state);
563 PyGILState_Release(state);
569 PyCompilerFlags flags {PyCF_ONLY_AST, PY_MINOR_VERSION};
570 PyObject* o = Py_CompileStringExFlags(text.
toStdString().c_str(),
"stdin", Py_file_input, &flags, 0);
573 PyGILState_Release(state);
579 void PythonContext::handleReset()
583 PyGILState_STATE
state = PyGILState_Ensure();
586 PyGILState_Release(state);
588 mTriggerReset =
false;
592 void PythonContext::handleClear()
600 mTriggerClear =
false;
604 void PythonContext::scheduleReset()
606 mTriggerReset =
true;
609 void PythonContext::scheduleClear()
611 mTriggerClear =
true;
614 void PythonContext::updateNetlist()
616 PyGILState_STATE
state = PyGILState_Ensure();
618 PyGILState_Release(state);
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the whether in Source or Object that is based or other modifications as a an original work of authorship For the purposes of this Derivative Works shall not include works that remain separable or merely the Work and Derivative Works thereof Contribution shall mean any work of including the original version of the Work and any modifications or additions to that Work or Derivative Works that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner For the purposes of this submitted means any form of or written communication sent to the Licensor or its including but not limited to communication on electronic mailing source code control and issue tracking systems that are managed or on behalf the Licensor for the purpose of discussing and improving the but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as Not a Contribution Contributor shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work Grant of Copyright License Subject to the terms and conditions of this each Contributor hereby grants to You a non no royalty irrevocable copyright license to prepare Derivative Works publicly publicly and distribute the Work and such Derivative Works in Source or Object form Grant of Patent License Subject to the terms and conditions of this each Contributor hereby grants to You a non no royalty have offer to import
const std::vector< Gate * > & get_gates() const
Gate * get_gate_by_id(const u32 gate_id) const
Module * get_module_by_id(u32 module_id) const
int numberSelectedGates() const
int numberSelectedModules() const
#define log_error(channel,...)
#define log_info(channel,...)
#define log_warning(channel,...)
CORE_API T rtrim(const T &s, const char *to_remove=" \t\r\n")
std::filesystem::path get_library_directory()
std::vector< std::filesystem::path > get_plugin_directories()
SelectionRelay * gSelectionRelay
std::shared_ptr< Netlist > gNetlistOwner
grammar _PyParser_Grammar
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
QSet::const_iterator constBegin() const const
QSet::iterator insert(const T &value)
bool isEmpty() const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
std::string toStdString() const const
int toInt(bool *ok) const const
QString toString() const const