Merge pull request #11421 from Pesc0/vscode-split-4--upgrade-python-debugger

Vscode split 4  upgrade python debugger
This commit is contained in:
Chris Hennes
2023-11-20 11:18:36 -06:00
committed by GitHub
13 changed files with 134 additions and 87 deletions

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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)

View File

@@ -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/>

View File

@@ -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))

View File

@@ -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">

View File

@@ -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">

View File

@@ -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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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()

View File

@@ -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"]