Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to specify Python executable path #19644

Merged
merged 2 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/base/preferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1487,6 +1487,19 @@ void Preferences::setTrackerPortForwardingEnabled(const bool enabled)
setValue(u"Preferences/Advanced/trackerPortForwarding"_s, enabled);
}

Path Preferences::getPythonExecutablePath() const
{
return value(u"Preferences/Search/pythonExecutablePath"_s, Path());
}

void Preferences::setPythonExecutablePath(const Path &path)
{
if (path == getPythonExecutablePath())
return;

setValue(u"Preferences/Search/pythonExecutablePath"_s, path);
}

#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
bool Preferences::isUpdateCheckEnabled() const
{
Expand Down
2 changes: 2 additions & 0 deletions src/base/preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ class Preferences final : public QObject
void setTrackerPort(int port);
bool isTrackerPortForwardingEnabled() const;
void setTrackerPortForwardingEnabled(bool enabled);
Path getPythonExecutablePath() const;
void setPythonExecutablePath(const Path &path);
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
bool isUpdateCheckEnabled() const;
void setUpdateCheckEnabled(bool enabled);
Expand Down
43 changes: 35 additions & 8 deletions src/base/utils/foreignapps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@

#include "base/global.h"
#include "base/logger.h"
#include "base/path.h"
#include "base/preferences.h"
#include "base/utils/bytearray.h"

using namespace Utils::ForeignApps;
Expand All @@ -52,6 +54,8 @@ namespace
{
bool testPythonInstallation(const QString &exeName, PythonInfo &info)
{
info = {};

QProcess proc;
proc.start(exeName, {u"--version"_s}, QIODevice::ReadOnly);
if (proc.waitForFinished() && (proc.exitCode() == QProcess::NormalExit))
Expand All @@ -77,7 +81,7 @@ namespace
return false;

info = {exeName, version};
LogMsg(QCoreApplication::translate("Utils::ForeignApps", "Python detected, executable name: '%1', version: %2")
LogMsg(QCoreApplication::translate("Utils::ForeignApps", "Found Python executable. Name: \"%1\". Version: \"%2\"")
.arg(info.executableName, info.version.toString()), Log::INFO);
return true;
}
Expand Down Expand Up @@ -254,20 +258,43 @@ bool Utils::ForeignApps::PythonInfo::isSupportedVersion() const
PythonInfo Utils::ForeignApps::pythonInfo()
{
static PythonInfo pyInfo;
if (!pyInfo.isValid())

const QString preferredPythonPath = Preferences::instance()->getPythonExecutablePath().toString();
if (pyInfo.isValid() && (preferredPythonPath == pyInfo.executableName))
return pyInfo;

if (!preferredPythonPath.isEmpty())
{
if (testPythonInstallation(u"python3"_s, pyInfo))
if (testPythonInstallation(preferredPythonPath, pyInfo))
return pyInfo;
LogMsg(QCoreApplication::translate("Utils::ForeignApps", "Failed to find Python executable. Path: \"%1\".")
.arg(preferredPythonPath), Log::WARNING);
}
else
{
// auto detect only when there are no preferred python path

if (testPythonInstallation(u"python"_s, pyInfo))
return pyInfo;
if (!pyInfo.isValid())
Chocobo1 marked this conversation as resolved.
Show resolved Hide resolved
{
if (testPythonInstallation(u"python3"_s, pyInfo))
return pyInfo;
LogMsg(QCoreApplication::translate("Utils::ForeignApps", "Failed to find `python3` executable in PATH environment variable. PATH: \"%1\"")
.arg(qEnvironmentVariable("PATH")), Log::INFO);

if (testPythonInstallation(u"python"_s, pyInfo))
return pyInfo;
LogMsg(QCoreApplication::translate("Utils::ForeignApps", "Failed to find `python` executable in PATH environment variable. PATH: \"%1\"")
.arg(qEnvironmentVariable("PATH")), Log::INFO);

#if defined(Q_OS_WIN)
if (testPythonInstallation(findPythonPath(), pyInfo))
return pyInfo;
if (testPythonInstallation(findPythonPath(), pyInfo))
return pyInfo;
LogMsg(QCoreApplication::translate("Utils::ForeignApps", "Failed to find `python` executable in Windows Registry."), Log::INFO);
#endif

LogMsg(QCoreApplication::translate("Utils::ForeignApps", "Python not detected"), Log::INFO);
LogMsg(QCoreApplication::translate("Utils::ForeignApps", "Failed to find Python executable"), Log::WARNING);

}
}

return pyInfo;
Expand Down
8 changes: 7 additions & 1 deletion src/gui/advancedsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ namespace
TRACKER_STATUS,
TRACKER_PORT,
TRACKER_PORT_FORWARDING,
PYTHON_EXECUTABLE_PATH,
// libtorrent section
LIBTORRENT_HEADER,
BDECODE_DEPTH_LIMIT,
Expand Down Expand Up @@ -316,7 +317,8 @@ void AdvancedSettings::saveAdvancedSettings() const
pref->setTrackerPort(m_spinBoxTrackerPort.value());
pref->setTrackerPortForwardingEnabled(m_checkBoxTrackerPortForwarding.isChecked());
session->setTrackerEnabled(m_checkBoxTrackerStatus.isChecked());

// Python executable path
pref->setPythonExecutablePath(Path(m_pythonExecutablePath.text().trimmed()));
// Choking algorithm
session->setChokingAlgorithm(m_comboBoxChokingAlgorithm.currentData().value<BitTorrent::ChokingAlgorithm>());
// Seed choking algorithm
Expand Down Expand Up @@ -810,6 +812,10 @@ void AdvancedSettings::loadAdvancedSettings()
// Tracker port forwarding
m_checkBoxTrackerPortForwarding.setChecked(pref->isTrackerPortForwardingEnabled());
addRow(TRACKER_PORT_FORWARDING, tr("Enable port forwarding for embedded tracker"), &m_checkBoxTrackerPortForwarding);
// Python executable path
m_pythonExecutablePath.setPlaceholderText(tr("(Auto detect if empty)"));
m_pythonExecutablePath.setText(pref->getPythonExecutablePath().toString());
addRow(PYTHON_EXECUTABLE_PATH, tr("Python executable path (may require restart)"), &m_pythonExecutablePath);
// Choking algorithm
m_comboBoxChokingAlgorithm.addItem(tr("Fixed slots"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::FixedSlots));
m_comboBoxChokingAlgorithm.addItem(tr("Upload rate based"), QVariant::fromValue(BitTorrent::ChokingAlgorithm::RateBased));
Expand Down
2 changes: 1 addition & 1 deletion src/gui/advancedsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private slots:
m_checkBoxSuggestMode, m_checkBoxSpeedWidgetEnabled, m_checkBoxIDNSupport;
QComboBox m_comboBoxInterface, m_comboBoxInterfaceAddress, m_comboBoxDiskIOReadMode, m_comboBoxDiskIOWriteMode, m_comboBoxUtpMixedMode, m_comboBoxChokingAlgorithm,
m_comboBoxSeedChokingAlgorithm, m_comboBoxResumeDataStorage;
QLineEdit m_lineEditAnnounceIP, m_lineEditDHTBootstrapNodes;
QLineEdit m_pythonExecutablePath, m_lineEditAnnounceIP, m_lineEditDHTBootstrapNodes;

#ifndef QBT_USES_LIBTORRENT2
QSpinBox m_spinBoxCache, m_spinBoxCacheTTL;
Expand Down
5 changes: 2 additions & 3 deletions src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1635,11 +1635,11 @@ void MainWindow::on_actionRSSReader_triggered()

void MainWindow::on_actionSearchWidget_triggered()
{
if (!m_hasPython && m_ui->actionSearchWidget->isChecked())
if (m_ui->actionSearchWidget->isChecked())
{
const Utils::ForeignApps::PythonInfo pyInfo = Utils::ForeignApps::pythonInfo();

// Not installed
// Not found
if (!pyInfo.isValid())
{
m_ui->actionSearchWidget->setChecked(false);
Expand Down Expand Up @@ -1679,7 +1679,6 @@ void MainWindow::on_actionSearchWidget_triggered()
return;
}

m_hasPython = true;
m_ui->actionSearchWidget->setChecked(true);
Preferences::instance()->setSearchEnabled(true);
}
Expand Down
1 change: 0 additions & 1 deletion src/gui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ private slots:
// Power Management
PowerManagement *m_pwr = nullptr;
QTimer *m_preventTimer = nullptr;
bool m_hasPython = false;
QMenu *m_toolbarMenu = nullptr;

SettingValue<bool> m_storeExecutionLogEnabled;
Expand Down
5 changes: 5 additions & 0 deletions src/webui/api/appcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ void AppController::preferencesAction()
data[u"enable_embedded_tracker"_s] = session->isTrackerEnabled();
data[u"embedded_tracker_port"_s] = pref->getTrackerPort();
data[u"embedded_tracker_port_forwarding"_s] = pref->isTrackerPortForwardingEnabled();
// Python executable path
data[u"python_executable_path"_s] = pref->getPythonExecutablePath().toString();
// Choking algorithm
data[u"upload_slots_behavior"_s] = static_cast<int>(session->chokingAlgorithm());
// Seed choking algorithm
Expand Down Expand Up @@ -990,6 +992,9 @@ void AppController::setPreferencesAction()
pref->setTrackerPortForwardingEnabled(it.value().toBool());
if (hasKey(u"enable_embedded_tracker"_s))
session->setTrackerEnabled(it.value().toBool());
// Python executable path
if (hasKey(u"python_executable_path"_s))
pref->setPythonExecutablePath(Path(it.value().toString()));
// Choking algorithm
if (hasKey(u"upload_slots_behavior"_s))
session->setChokingAlgorithm(static_cast<BitTorrent::ChokingAlgorithm>(it.value().toInt()));
Expand Down
2 changes: 1 addition & 1 deletion src/webui/webapplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
#include "base/utils/version.h"
#include "api/isessionmanager.h"

inline const Utils::Version<3, 2> API_VERSION {2, 9, 4};
inline const Utils::Version<3, 2> API_VERSION {2, 9, 5};

class APIController;
class AuthController;
Expand Down
10 changes: 10 additions & 0 deletions src/webui/www/private/views/preferences.html
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,14 @@
<input type="checkbox" id="embeddedTrackerPortForwarding" />
</td>
</tr>
<tr>
<td>
<label for="pythonExecutablePath">QBT_TR(Python executable path (may require restart):)QBT_TR[CONTEXT=OptionsDialog]</label>
</td>
<td>
<input type="text" id="pythonExecutablePath" placeholder="QBT_TR((Auto detect if empty))QBT_TR[CONTEXT=OptionsDialog]" style="width: 15em;" />
</td>
</tr>
</table>
</fieldset>
<fieldset class="settings">
Expand Down Expand Up @@ -2238,6 +2246,7 @@
$('enableEmbeddedTracker').setProperty('checked', pref.enable_embedded_tracker);
$('embeddedTrackerPort').setProperty('value', pref.embedded_tracker_port);
$('embeddedTrackerPortForwarding').setProperty('checked', pref.embedded_tracker_port_forwarding);
$('pythonExecutablePath').setProperty('value', pref.python_executable_path);
$('uploadSlotsBehavior').setProperty('value', pref.upload_slots_behavior);
$('uploadChokingAlgorithm').setProperty('value', pref.upload_choking_algorithm);
$('announceAllTrackers').setProperty('checked', pref.announce_to_all_trackers);
Expand Down Expand Up @@ -2671,6 +2680,7 @@
settings.set('enable_embedded_tracker', $('enableEmbeddedTracker').getProperty('checked'));
settings.set('embedded_tracker_port', $('embeddedTrackerPort').getProperty('value'));
settings.set('embedded_tracker_port_forwarding', $('embeddedTrackerPortForwarding').getProperty('checked'));
settings.set('python_executable_path', $('pythonExecutablePath').getProperty('value'));
settings.set('upload_slots_behavior', $('uploadSlotsBehavior').getProperty('value'));
settings.set('upload_choking_algorithm', $('uploadChokingAlgorithm').getProperty('value'));
settings.set('announce_to_all_trackers', $('announceAllTrackers').getProperty('checked'));
Expand Down