Merge pull request #11421 from Pesc0/vscode-split-4--upgrade-python-debugger
Vscode split 4 upgrade python debugger
This commit is contained in:
@@ -10,7 +10,7 @@ opencamlib==2023.1.11
|
||||
packaging==23.0
|
||||
Pivy==0.6.8
|
||||
ply==3.11
|
||||
ptvsd==4.3.2
|
||||
debugpy==1.6.7
|
||||
pyNastran==1.3.4
|
||||
pyshp==2.3.1
|
||||
PySide2==5.15.2.1
|
||||
|
||||
@@ -27,6 +27,7 @@ endif()
|
||||
configure_file(__init__.py.template ${NAMESPACE_INIT})
|
||||
configure_file(project_utility.py ${NAMESPACE_DIR}/project_utility.py)
|
||||
configure_file(UiTools.py ${NAMESPACE_DIR}/UiTools.py)
|
||||
configure_file(utils.py ${NAMESPACE_DIR}/utils.py)
|
||||
|
||||
if (INSTALL_TO_SITEPACKAGES)
|
||||
SET(SITE_PACKAGE_DIR ${PYTHON_MAIN_DIR}/freecad)
|
||||
@@ -39,6 +40,7 @@ INSTALL(
|
||||
${NAMESPACE_INIT}
|
||||
project_utility.py
|
||||
UiTools.py
|
||||
utils.py
|
||||
DESTINATION
|
||||
${SITE_PACKAGE_DIR}
|
||||
)
|
||||
|
||||
63
src/Ext/freecad/utils.py
Normal file
63
src/Ext/freecad/utils.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2022-2023 FreeCAD Project Association *
|
||||
# * Copyright (c) 2018 Gaël Écorchard <galou_breizh@yahoo.fr> *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD 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 *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
|
||||
import FreeCAD
|
||||
|
||||
|
||||
def get_python_exe() -> str:
|
||||
"""Find Python. In preference order
|
||||
A) The value of the PythonExecutableForPip user preference
|
||||
B) The executable located in the same bin directory as FreeCAD and called "python3"
|
||||
C) The executable located in the same bin directory as FreeCAD and called "python"
|
||||
D) The result of a shutil search for your system's "python3" executable
|
||||
E) The result of a shutil search for your system's "python" executable"""
|
||||
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/PythonConsole")
|
||||
python_exe = prefs.GetString("ExternalPythonExecutable", "Not set")
|
||||
fc_dir = FreeCAD.getHomePath()
|
||||
if not python_exe or python_exe == "Not set" or not os.path.exists(python_exe):
|
||||
python_exe = os.path.join(fc_dir, "bin", "python3")
|
||||
if "Windows" in platform.system():
|
||||
python_exe += ".exe"
|
||||
|
||||
if not python_exe or not os.path.exists(python_exe):
|
||||
python_exe = os.path.join(fc_dir, "bin", "python")
|
||||
if "Windows" in platform.system():
|
||||
python_exe += ".exe"
|
||||
|
||||
if not python_exe or not os.path.exists(python_exe):
|
||||
python_exe = shutil.which("python3")
|
||||
|
||||
if not python_exe or not os.path.exists(python_exe):
|
||||
python_exe = shutil.which("python")
|
||||
|
||||
if not python_exe or not os.path.exists(python_exe):
|
||||
return ""
|
||||
|
||||
python_exe = python_exe.replace("/", os.path.sep)
|
||||
prefs.SetString("ExternalPythonExecutable", python_exe)
|
||||
return python_exe
|
||||
@@ -45,6 +45,7 @@ void DlgSettingsPythonConsole::saveSettings()
|
||||
ui->PythonBlockCursor->onSave();
|
||||
ui->PythonSaveHistory->onSave();
|
||||
ui->ProfilerInterval->onSave();
|
||||
ui->ExternalPythonExecutable->onSave();
|
||||
}
|
||||
|
||||
void DlgSettingsPythonConsole::loadSettings()
|
||||
@@ -53,6 +54,7 @@ void DlgSettingsPythonConsole::loadSettings()
|
||||
ui->PythonBlockCursor->onRestore();
|
||||
ui->PythonSaveHistory->onRestore();
|
||||
ui->ProfilerInterval->onRestore();
|
||||
ui->ExternalPythonExecutable->onRestore();
|
||||
}
|
||||
|
||||
void DlgSettingsPythonConsole::changeEvent(QEvent* event)
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Python console</string>
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="GroupBox11">
|
||||
<property name="title">
|
||||
<string>Settings</string>
|
||||
<string>Console</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
@@ -111,6 +111,47 @@ horizontal space in Python console</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="GroupBox11">
|
||||
<property name="title">
|
||||
<string>Other</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="fclabel">
|
||||
<property name="text">
|
||||
<string>Path to external Python executable (optional):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefFileChooser" name="ExternalPythonExecutable" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Used for package installation with pip and debugging with debugpy. Autodetected if needed and not specified.</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>ExternalPythonExecutable</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>PythonConsole</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -135,6 +176,11 @@ horizontal space in Python console</string>
|
||||
<class>Gui::PrefSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefFileChooser</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
from PySide import QtGui
|
||||
from freecad.utils import get_python_exe
|
||||
|
||||
class RemoteDebugger():
|
||||
def __init__(self, parent=None):
|
||||
@@ -46,11 +47,17 @@ class RemoteDebugger():
|
||||
elif index == 1: # VS code
|
||||
address = self.dialog.lineEditAddress.text()
|
||||
port = self.dialog.spinBoxPort.value()
|
||||
redirect = self.dialog.checkRedirectOutput.isChecked()
|
||||
|
||||
import ptvsd
|
||||
ptvsd.enable_attach(address=(address, port), redirect_output=redirect)
|
||||
ptvsd.wait_for_attach()
|
||||
import debugpy
|
||||
|
||||
# get_python_exe is needed because debugpy needs a python interpreter to work.
|
||||
# It does not have to be FC embedded interpreter.
|
||||
# By default it attempts to use Freecad's PID mistaking it for python.
|
||||
# https://github.com/microsoft/debugpy/issues/262
|
||||
debugpy.configure(python=get_python_exe())
|
||||
debugpy.listen((address, port))
|
||||
debugpy.wait_for_client()
|
||||
|
||||
except Exception as e:
|
||||
QtGui.QMessageBox.warning(self.dialog, "Failed to attach", str(e))
|
||||
|
||||
|
||||
@@ -89,16 +89,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkRedirectOutput">
|
||||
<property name="text">
|
||||
<string>Redirect output</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -270,38 +270,6 @@ installed addons will be checked for available updates
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="fclabel">
|
||||
<property name="text">
|
||||
<string>Path to Python executable (optional):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The path to the Python executable for package installation with pip. Autodetected if needed and not specified.</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>PythonExecutableForPip</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Addons</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
|
||||
@@ -27,6 +27,8 @@ import os
|
||||
import subprocess
|
||||
from typing import List
|
||||
|
||||
from freecad.utils import get_python_exe
|
||||
|
||||
import addonmanager_freecad_interface as fci
|
||||
from addonmanager_pyside_interface import QObject, Signal, is_interruption_requested
|
||||
|
||||
@@ -170,7 +172,7 @@ class DependencyInstaller(QObject):
|
||||
|
||||
def _get_python(self) -> str:
|
||||
"""Wrap Python access so test code can mock it."""
|
||||
python_exe = utils.get_python_exe()
|
||||
python_exe = get_python_exe()
|
||||
if not python_exe:
|
||||
self.no_python_exe.emit()
|
||||
return python_exe
|
||||
|
||||
@@ -29,6 +29,7 @@ import subprocess
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from freecad.utils import get_python_exe
|
||||
|
||||
from PySide.QtWidgets import (
|
||||
QFileDialog,
|
||||
@@ -618,7 +619,7 @@ class DeveloperMode:
|
||||
FreeCAD.Console.PrintMessage(
|
||||
translate("AddonsInstaller", "Attempting to install Vermin from PyPi") + "...\n"
|
||||
)
|
||||
python_exe = utils.get_python_exe()
|
||||
python_exe = get_python_exe()
|
||||
vendor_path = os.path.join(FreeCAD.getUserAppDataDir(), "AdditionalPythonPackages")
|
||||
if not os.path.exists(vendor_path):
|
||||
os.makedirs(vendor_path)
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
"PrimaryAddonsSubmoduleURL":
|
||||
"https://raw.githubusercontent.com/FreeCAD/FreeCAD-addons/master/.gitmodules",
|
||||
"ProxyUrl": "",
|
||||
"PythonExecutableForPip": "Not set",
|
||||
"RemoteIconCacheURL": "https://addons.freecad.org/icon_cache.zip",
|
||||
"SelectedAddon": "",
|
||||
"ShowBranchSwitcher": false,
|
||||
|
||||
@@ -345,40 +345,6 @@ def is_float(element: Any) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def get_python_exe() -> str:
|
||||
"""Find Python. In preference order
|
||||
A) The value of the PythonExecutableForPip user preference
|
||||
B) The executable located in the same bin directory as FreeCAD and called "python3"
|
||||
C) The executable located in the same bin directory as FreeCAD and called "python"
|
||||
D) The result of a shutil search for your system's "python3" executable
|
||||
E) The result of a shutil search for your system's "python" executable"""
|
||||
prefs = fci.ParamGet("User parameter:BaseApp/Preferences/Addons")
|
||||
python_exe = prefs.GetString("PythonExecutableForPip", "Not set")
|
||||
fc_dir = fci.DataPaths().home_dir
|
||||
if not python_exe or python_exe == "Not set" or not os.path.exists(python_exe):
|
||||
python_exe = os.path.join(fc_dir, "bin", "python3")
|
||||
if "Windows" in platform.system():
|
||||
python_exe += ".exe"
|
||||
|
||||
if not python_exe or not os.path.exists(python_exe):
|
||||
python_exe = os.path.join(fc_dir, "bin", "python")
|
||||
if "Windows" in platform.system():
|
||||
python_exe += ".exe"
|
||||
|
||||
if not python_exe or not os.path.exists(python_exe):
|
||||
python_exe = shutil.which("python3")
|
||||
|
||||
if not python_exe or not os.path.exists(python_exe):
|
||||
python_exe = shutil.which("python")
|
||||
|
||||
if not python_exe or not os.path.exists(python_exe):
|
||||
return ""
|
||||
|
||||
python_exe = python_exe.replace("/", os.path.sep)
|
||||
prefs.SetString("PythonExecutableForPip", python_exe)
|
||||
return python_exe
|
||||
|
||||
|
||||
def get_pip_target_directory():
|
||||
# Get the default location to install new pip packages
|
||||
major, minor, _ = platform.python_version_tuple()
|
||||
|
||||
@@ -36,6 +36,7 @@ from typing import Dict, List, Tuple
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from freecad.utils import get_python_exe
|
||||
from PySide import QtCore, QtGui, QtWidgets
|
||||
|
||||
import addonmanager_utilities as utils
|
||||
@@ -89,7 +90,7 @@ def call_pip(args) -> List[str]:
|
||||
"""Tries to locate the appropriate Python executable and run pip with version checking
|
||||
disabled. Fails if Python can't be found or if pip is not installed."""
|
||||
|
||||
python_exe = utils.get_python_exe()
|
||||
python_exe = get_python_exe()
|
||||
pip_failed = False
|
||||
if python_exe:
|
||||
call_args = [python_exe, "-m", "pip", "--disable-pip-version-check"]
|
||||
|
||||
Reference in New Issue
Block a user