如何向QProcess path环境变量添加路径?(Python 3.7上的PyQt5) 1.问题被解释了

如何向QProcess path环境变量添加路径?(Python 3.7上的PyQt5) 1.问题被解释了,python,python-3.x,process,environment-variables,qprocess,Python,Python 3.x,Process,Environment Variables,Qprocess,在应用程序显示其主窗口之前,我实例化了一个QProcess()-对象。QProcess()-实例存储在self.\uu myProcess变量中,只要您能看到主窗口,它就会保持活动状态 主窗口如下所示: 单击按钮时,将执行以下代码: def __btn_clicked(self): self.__add_openocd_to_env() command = "openocd.exe" + '\r\n' self.__myProcess.start(command) 最

在应用程序显示其主窗口之前,我实例化了一个
QProcess()
-对象。
QProcess()
-实例存储在
self.\uu myProcess
变量中,只要您能看到主窗口,它就会保持活动状态

主窗口如下所示:

单击按钮时,将执行以下代码:

def __btn_clicked(self):
    self.__add_openocd_to_env()
    command = "openocd.exe" + '\r\n'
    self.__myProcess.start(command)
最后两行非常清楚:命令
openocd.exe
被传递到
self.\uu myProcess
并执行。这个可执行文件的实际功能在这里并不重要。事实上,我可以使用任何随机的可执行文件。关键是:如果可执行文件在我的Windows
PATH
环境变量中,它就会被找到并执行

假设可执行文件不在
路径
环境变量中。然后,函数
self.\u\u将\u openocd\u添加到\u env()
将解决该问题:

def __add_openocd_to_env(self):
    env = self.__myProcess.processEnvironment()
    env.insert("PATH", "C:\\Users\\Kristof\\programs\\openocd_0.10.0\\bin;" + env.value("PATH"))
    self.__myProcess.setProcessEnvironment(env)
然而,我注意到它没有任何效果。我在这个函数中尝试了很多不同的东西,但都没有效果


您可以在此处找到完整代码:
如果PyQt5安装了Python3,只需将代码复制粘贴到.py模块中并运行即可。你应该看到有按钮的小窗口。当然,您应该将路径“C:\Users\Kristof..”更改为计算机上的有效路径。您可以为此测试选择任何您喜欢的可执行文件


2.我的问题 我知道在实例化
QProcess()
之前,我可以简单地将“C:\Users\Kristof\programs\openocd\u 0.10.0\bin”添加到我的Windows
PATH
环境变量中。但这不是重点。我想知道如何将它添加到特定
QProcess()
-实例的
PATH
环境变量中。如果可能,它不应影响我软件中的任何其他
QProcess()
-实例,也不应影响我以后创建的任何
QProcess()
-实例

3.系统设置 我在Windows10上使用Python3.7中的PyQt5框架


注:
我刚刚尝试通过以下方式改进
QProcess()
设置:

        # -------------------------------- #
        #          QProcess() setup        #
        # -------------------------------- #
        self.__myProcess = QProcess()
        self.__myProcess.setProcessChannelMode(QProcess.MergedChannels)
        self.__myProcess.readyRead.connect(self.__on_output)
        self.__myProcess.errorOccurred.connect(self.__on_error)
        self.__myProcess.finished.connect(self.__on_exit)

        # NEW: initialize the environment variables for self.__myProcess:
        env = QProcessEnvironment.systemEnvironment()
        self.__myProcess.setProcessEnvironment(env)
我很有希望。。。但它仍然不起作用:-(


根据@JonBrave先生的评论,我编写了以下解决方法:

import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class CustomMainWindow(QMainWindow):
    def __init__(self):
        super(CustomMainWindow, self).__init__()
        # -------------------------------- #
        #          QProcess() setup        #
        # -------------------------------- #
        self.__myProcess = QProcess()
        self.__myProcess.setProcessChannelMode(QProcess.MergedChannels)
        self.__myProcess.readyRead.connect(self.__on_output)
        self.__myProcess.errorOccurred.connect(self.__on_error)
        self.__myProcess.finished.connect(self.__on_exit)

        # -------------------------------- #
        #           Window setup           #
        # -------------------------------- #
        self.setGeometry(100, 100, 800, 200)
        self.setWindowTitle("QProcess test")

        self.__frm = QFrame(self)
        self.__frm.setStyleSheet("QWidget { background-color: #ffffff }")
        self.__lyt = QVBoxLayout()
        self.__lyt.setAlignment(Qt.AlignTop)
        self.__frm.setLayout(self.__lyt)
        self.setCentralWidget(self.__frm)

        self.__myBtn = QPushButton("START QPROCESS()")
        self.__myBtn.clicked.connect(self.__btn_clicked)
        self.__myBtn.setFixedHeight(70)
        self.__myBtn.setFixedWidth(200)
        self.__lyt.addWidget(self.__myBtn)
        self.show()

    def __add_openocd_to_env(self):
        self.__oldEnv = os.environ["PATH"]
        os.environ["PATH"] = "C:\\Users\\Kristof\\Dropbox (Personal)\\EMBEDOFFICE\\embedoffice\\resources\\programs\\openocd_0.10.0_dev00459\\bin;" + self.__oldEnv

    def __remove_openocd_from_env(self):
        os.environ["PATH"] = self.__oldEnv

    def __btn_clicked(self):
        self.__add_openocd_to_env()
        command = "openocd.exe" + '\r\n'
        self.__myProcess.start(command)
        self.__myProcess.waitForStarted(-1)
        self.__remove_openocd_from_env()

    def __on_output(self):
        data = bytes(self.__myProcess.readAll()).decode().replace('\r\n', '\n')
        print(data)

    def __on_error(self, error):
        print("")
        print("Process error: {0}".format(str(error)))
        print("")

    def __on_exit(self, exitCode, exitStatus):
        print("")
        print("ExitCode = {0}".format(str(exitCode)))
        print("ExitStatus = {0}".format(str(exitStatus)))
        print("")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    QApplication.setStyle(QStyleFactory.create('Fusion'))
    myGUI = CustomMainWindow()
    sys.exit(app.exec_())
基本上我在做以下工作:在命令
QProcess()
-实例启动命令之前,我将可执行路径添加到属于整个Python会话的
path
环境变量中。一旦命令启动,我可以再次删除它,这样它就不会对其他
QProcess()产生影响
-将来创建的实例


它是有效的,但如果我要在我的软件中应用这种方法,它肯定需要大量的“簿记”(许多
QProcess()
-实例都存在于我的软件中)。如果你找到更好的方法,请毫不犹豫地与大家分享!

有一个解决方案使用python subprocess.run()而不是QProcess

在subprocess.run()中,可以使用
env
参数指定一组环境变量(实际上是一个字典)。其思想是复制原始环境,修改路径变量,并将修改后的环境传递给subprocess.run,如下所示:

env = os.environ.copy()
env['PATH'] = "C:\\Users\\Kristof\\programs\\openocd_0.10.0\\bin" \
   + os.pathsep + env['PATH']
subprocess.run("openocd", env=env)
这仍然不起作用:剩下的问题是环境(包括修改后的PATH变量)将在子流程中可用,但不用于搜索openocd命令。但这很容易解决:subprocess.run还有一个布尔
shell
参数(默认为False)这告诉它在shell中运行命令。由于shell将在子流程中运行,因此它将使用修改后的路径搜索openocd。因此,工作代码为:

env = os.environ.copy()
env['PATH'] = "C:\\Users\\Kristof\\programs\\openocd_0.10.0\\bin" \
   + os.pathsep + env['PATH']
subprocess.run("openocd", env=env, shell=True)
shell=True的另一种选择是使用shutil.which(在Python>=3.3中可用)解析命令。当命令作为字符串列表而不是单个字符串给出时,这也将可靠地工作

env = os.environ.copy()
env['PATH'] = "C:\\Users\\Kristof\\programs\\openocd_0.10.0\\bin" \
   + os.pathsep + env['PATH']
command = shutil.which("openocd", path = self.env.get('PATH', None))
subprocess.run([ command ], env=env)

我认为您误解了。您试图影响传递给子进程的
路径
环境。您要做的只是更改父进程中的
路径
环境,它需要在生成子进程之前找到您的可执行文件。如果您愿意,请更改父进程的路径s
路径
在子进程生成后返回。您好@JonBrave,您有一个观点。您可以用一个例子来说明吗?看起来很好。对不起,我没有时间键入答案!您可能可以在
开始()之后,在
等待开始()之前,直接从env()调用
移除\u openocd\u
(这样你就不需要)来减少改变环境的暴露时间(试试吧?)。您可以从
QProcess
派生自己的类,仅用于本例,以避免更改其他类。最后,您可以从当前目录中
路径上的
.bat
文件执行此操作,该文件在调用
openocd.exe
之前更改路径,然后它位于一个位置(您可以更改路径)您不必更改
QProcess
…:)只需注意您的代码:
command=“openocd.exe”+'\r\n'
。去掉CRLF的东西,它不能发出操作系统命令。最后,从您给出的示例来看,如果您知道
exe
位于您要添加到
PATH
的目录中,并且exe本身不需要为自己的目的更改路径,只需自己创建exe的完整路径即可如果这样调用,就简单多了。这个过程在linux上对我很有用,因为我计划制作自己的IDE。谢谢你的提问和回答。非常有趣@SpencerWilliams,请将我添加到LinkedIn上。我的名字是:Kristof Mulier
env = os.environ.copy()
env['PATH'] = "C:\\Users\\Kristof\\programs\\openocd_0.10.0\\bin" \
   + os.pathsep + env['PATH']
command = shutil.which("openocd", path = self.env.get('PATH', None))
subprocess.run([ command ], env=env)