Skip to content

Commit 9886dd0

Browse files
authored
Fix Crash when Python is not Found on Windows (#6870)
* check for process failure in python version check * unify windows and linux python checks * add mac python advice to translation strings * remove unnecessary QProcess includes * import sys in 64-bit python check * fix indentation * fix crash on invalid command * Revert "remove unnecessary QProcess includes" (moved to another pr) This reverts commit 31f04ea. * try removing unusedPrivateFunction cppcheck suppression * undo if/ifdef reorder * add else comment * Revert "fix crash on invalid command" I forgot that this only becomes necessary when some other changes are added (which will come in another PR) This reverts commit 15982ce. * formatting * remove newline * update changelog * wording
1 parent cf74366 commit 9886dd0

File tree

3 files changed

+34
-36
lines changed

3 files changed

+34
-36
lines changed

docs/reference/changelog-r2025.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- Fixed a bug causing `TrackWheel` nodes to lose their field values when used in a proto converted to a base node ([#6856](https://github.com/cyberbotics/webots/pull/6856)).
1919
- Fixed a bug causing supervisors to occasionally read stale field values after the simulation was reset ([#6758](https://github.com/cyberbotics/webots/pull/6758)).
2020
- Fixed a bug causing Webots to occasionally crash when unloading a world ([#6857](https://github.com/cyberbotics/webots/pull/6857)).
21+
- Fixed a crash occurring when Python was not found on Windows ([#6870](https://github.com/cyberbotics/webots/pull/6870)).
2122

2223
## Webots R2025a
2324
Released on January 31st, 2025.

src/webots/control/WbLanguageTools.cpp

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -67,44 +67,25 @@ QString WbLanguageTools::pythonCommand(QString &shortVersion, const QString &com
6767
if (pythonCommand.isEmpty())
6868
#ifdef _WIN32
6969
pythonCommand = "python";
70+
if (!command.endsWith(".exe", Qt::CaseInsensitive))
71+
pythonCommand += ".exe";
7072
#else
7173
pythonCommand = "python3";
7274
#endif
75+
7376
const QString advice =
7477
#ifdef __APPLE__
75-
"To fix the problem, you should set the full path of your python command in "
76-
"Webots->preferences->python command.\n";
78+
QObject::tr("To fix the problem, you should set the full path of your python command in "
79+
"Webots->preferences->python command.\n");
7780
#else
7881
QObject::tr("Webots requires Python version 3.7 or newer in your current PATH.\n"
7982
"To fix the problem, you should:\n"
8083
"1. Check the Python command set in the Webots preferences.\n"
8184
"2. Check the COMMAND set in the [python] section of the runtime.ini file of your controller program if any.\n"
8285
"3. Install a recent Python 64 bit version and ensure your PATH environment variable points to it.\n");
8386
#endif
84-
#ifdef _WIN32
85-
if (!command.endsWith(".exe", Qt::CaseInsensitive))
86-
pythonCommand += ".exe";
87-
QProcess process;
88-
process.setProcessEnvironment(env);
89-
process.start(pythonCommand, QStringList() << "-u"
90-
<< "-c"
91-
<< "import sys;print(sys.version);print(sys.maxsize > 2**32)");
92-
process.waitForFinished();
93-
const QString output = process.readAll();
94-
// "3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]\nTrue\n" or the like
95-
const QStringList version = output.split("\n");
96-
const int v = (QString(version[0][2]) + (version[0][3] != '.' ? QString(version[0][3]) : "")).toInt();
97-
if (!version[0].startsWith("3.") || v < 7) {
98-
WbLog::warning(QObject::tr("\"%1\" was not found.\n").arg(pythonCommand) + advice);
99-
pythonCommand = "!";
100-
} else if (version.size() > 1 && version[1].startsWith("False")) {
101-
WbLog::warning(QObject::tr("\"%1\" 64 bit was not found, but the 32 bit version was found.\n").arg(pythonCommand) + advice);
102-
pythonCommand = "!";
103-
} else
104-
shortVersion = QString(version[0][0]) + version[0][2];
105-
if (version[0][3] != '.')
106-
shortVersion += version[0][3]; // handle versions 310, 311, 321, etc.
107-
#elif __APPLE__
87+
88+
#ifdef __APPLE__
10889
if (std::getenv("PWD"))
10990
shortVersion = checkIfPythonCommandExist(pythonCommand, env, true);
11091
else if (pythonCommand == "python" || pythonCommand == "python3") {
@@ -129,39 +110,58 @@ QString WbLanguageTools::pythonCommand(QString &shortVersion, const QString &com
129110

130111
if (pythonCommand == "!")
131112
WbLog::warning(QObject::tr("Python was not found.\n") + advice);
132-
#else // __linux__
133-
shortVersion = checkIfPythonCommandExist(pythonCommand, env, true);
113+
#else // __linux__ and _WIN32
114+
shortVersion = checkIfPythonCommandExist(pythonCommand, env, true);
134115
if (shortVersion.isEmpty()) {
135116
pythonCommand = "!";
136117
WbLog::warning(QObject::tr("Python was not found.\n") + advice);
118+
} else { // Python exists
119+
120+
#ifdef _WIN32 // 64-bit check
121+
QProcess process;
122+
process.setProcessEnvironment(env);
123+
process.start(pythonCommand, QStringList() << "-u"
124+
<< "-c"
125+
<< "import sys;print(sys.maxsize > 2**32)");
126+
process.waitForFinished();
127+
bool processSucceeded = process.error() == QProcess::UnknownError;
128+
const QString output = process.readAll();
129+
if (!processSucceeded || !output.startsWith("True")) {
130+
WbLog::warning(QObject::tr("\"%1\" 64 bit was not found, but the 32 bit version was found.\n").arg(pythonCommand) +
131+
advice);
132+
pythonCommand = "!";
133+
shortVersion = QString();
134+
}
135+
#endif // _WIN32
137136
}
138137

139-
#endif
138+
#endif // __APPLE__
139+
140140
return pythonCommand;
141141
}
142142

143-
#if defined __APPLE__ || defined __linux__
144143
const QString WbLanguageTools::checkIfPythonCommandExist(const QString &pythonCommand, QProcessEnvironment &env, bool log) {
145144
QString shortVersion;
146145
QProcess process;
147146
process.setProcessEnvironment(env);
148147
process.start(pythonCommand, QStringList() << "-c"
149148
<< "import sys;print(sys.version);");
150149
process.waitForFinished();
150+
bool processSucceeded = process.error() == QProcess::UnknownError;
151151
const QString output = process.readAll();
152152
// "3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)]" or the like
153153
const QStringList version = output.split(" ");
154-
if (!version[0].startsWith("3.")) {
154+
const QStringList version_numbers(version[0].split("."));
155+
const int minor_version = version_numbers.size() >= 2 ? version_numbers[1].toInt() : 0;
156+
if (!processSucceeded || !version[0].startsWith("3.") || minor_version < 7) {
155157
if (log)
156158
WbLog::warning(QObject::tr("\"%1\" was not found.\n").arg(pythonCommand));
157159
shortVersion = QString();
158160
} else {
159-
const QStringList version_numbers(version[0].split("."));
160161
shortVersion = version_numbers[0] + version_numbers[1];
161162
}
162163
return shortVersion;
163164
}
164-
#endif
165165

166166
#ifdef __APPLE__
167167
QString WbLanguageTools::findWorkingPythonPath(const QString &pythonVersion, QProcessEnvironment &env, bool log) {

src/webots/control/WbLanguageTools.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,7 @@ class WbLanguageTools {
3535
private:
3636
WbLanguageTools() {}
3737
~WbLanguageTools() {}
38-
#if defined __APPLE__ || defined __linux__
39-
// cppcheck-suppress unusedPrivateFunction
4038
static const QString checkIfPythonCommandExist(const QString &pythonCommand, QProcessEnvironment &env, bool log);
41-
#endif
4239
#ifdef __APPLE__
4340
static QString findWorkingPythonPath(const QString &pythonVersion, QProcessEnvironment &env, bool log);
4441
#endif

0 commit comments

Comments
 (0)