繁体   English   中英

创建虚拟环境时,传递给venv.create()的参数无效

[英]Arguments passed to venv.create() have no effect when creating a virtual environment

我正在使用PyQt5向导来创建Python虚拟环境。 创建环境是可行的。 参数(例如,带有或不带有pip ,...)从QCheckBox()传递到Python随附的venv模块的create()函数。

问题在于传递给venv.create()的参数对虚拟环境的创建没有影响。 始终使用默认设置创建它(例如,默认情况下安装pip )。

但是,如果我直接通过with_pip=False ,将不会安装pip 这意味着,出于某种原因,从args传递的args对创建没有影响。 我尝试将值转换为bool() ,但这没有用。

我不清楚为什么,因为print(args)输出TrueFalse (作为字符串),具体取决于相应QCheckBox()isChecked()状态。

此外,我正在使用locationname (在args )来构建将要安装虚拟环境的路径,并且可以正常工作。

有人可以解释为什么venv.create()不接受来自QCheckBox() isChecked()的参数吗? 还是我错过了什么?


复制代码:

from subprocess import Popen, PIPE, CalledProcessError
from functools import partial
import venv
import os

from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt, QObject, QTimer, QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import (QApplication, QFileDialog, QGridLayout, QLabel,
                             QVBoxLayout, QWizard, QWizardPage, QProgressBar,
                             QCheckBox, QLineEdit, QGroupBox, QToolButton,
                             QComboBox, QDialog, QHBoxLayout)



#]===========================================================================[#
#] FIND INSTALLED INTERPRETERS [#============================================[#
#]===========================================================================[#

# look for installed Python 3 versions
versions = ['3.9', '3.8', '3.7', '3.6', '3.5', '3.4', '3.3', '3']

notFound = []
versFound = []
pathFound = []

for i, v in enumerate(versions):
    try:
        # get installed python3 versions
        getVers = Popen(["python" + v, "-V"],
                            stdout=PIPE, universal_newlines=True)
        version = getVers.communicate()[0].strip()

        # get paths of the python executables
        getPath = Popen(["which", "python" + v],
                            stdout=PIPE, universal_newlines=True)
        path = getPath.communicate()[0].strip()

        versFound.append(version)
        pathFound.append(path)

    except (CalledProcessError, FileNotFoundError):
        notFound.append(i)


#]===========================================================================[#
#] PROGRESS BAR [#===========================================================[#
#]===========================================================================[#

class ProgBarWidget(QDialog):
    """
    The dialog that shows a progress bar during the create process.
    """
    def __init__(self):
        super().__init__()
        self.initMe()

    def initMe(self):
        self.setGeometry(690, 365, 325, 80)
        self.setFixedSize(325, 80)
        self.setWindowTitle("Creating")
        self.setWindowFlag(Qt.WindowCloseButtonHint, False)
        self.setWindowFlag(Qt.WindowMinimizeButtonHint, False)

        horizontalLayout = QHBoxLayout(self)
        verticalLayout = QVBoxLayout()

        statusLabel = QLabel(self)
        statusLabel.setText("Creating virtual environment...")

        self.progressBar = QProgressBar(self)
        self.progressBar.setFixedSize(300, 23)
        self.progressBar.setRange(0, 0)

        verticalLayout.addWidget(statusLabel)
        verticalLayout.addWidget(self.progressBar)

        horizontalLayout.addLayout(verticalLayout)
        self.setLayout(horizontalLayout)



#]===========================================================================[#
#] VENV WIZARD [#============================================================[#
#]===========================================================================[#

class VenvWizard(QWizard):
    """
    Wizard for creating and setting up virtual environments.
    """
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Venv Wizard")
        self.resize(535, 430)
        self.move(578, 183)

        self.setStyleSheet(
            """
            QToolTip {
                background-color: rgb(47, 52, 63);
                border: rgb(47, 52, 63);
                color: rgb(210, 210, 210);
                padding: 2px;
                opacity: 325
            }
            """
        )

        self.addPage(BasicSettings())
        self.addPage(InstallPackages())
        self.addPage(Summary())


class BasicSettings(QWizardPage):
    """
    Basic settings of the virtual environment being created.
    """
    def __init__(self):
        super().__init__()

        folder_icon = QIcon.fromTheme("folder")

        self.setTitle("Basic Settings")
        self.setSubTitle("This wizard will help you to create and set up "
                         "a virtual environment for Python 3. ")


        #]===================================================================[#
        #] PAGE CONTENT [#===================================================[#
        #]===================================================================[#

        interpreterLabel = QLabel("&Interpreter:")
        self.interprComboBox = QComboBox()
        interpreterLabel.setBuddy(self.interprComboBox)

        # add items from versFound to combobox
        self.interprComboBox.addItem("---")
        for i in range(len(versFound)):
            self.interprComboBox.addItem(versFound[i], pathFound[i])

        venvNameLabel = QLabel("Venv &name:")
        self.venvNameLineEdit = QLineEdit()
        venvNameLabel.setBuddy(self.venvNameLineEdit)

        venvLocationLabel = QLabel("&Location:")
        self.venvLocationLineEdit = QLineEdit()
        venvLocationLabel.setBuddy(self.venvLocationLineEdit)

        selectFolderToolButton = QToolButton()
        selectFolderToolButton.setFixedSize(26, 27)
        selectFolderToolButton.setIcon(folder_icon)
        selectFolderToolButton.setToolTip("Browse")

        placeHolder = QLabel()

        # the 'options' groupbox
        groupBox = QGroupBox("Options")

        self.withPipCBox = QCheckBox("Install and update &Pip")
        self.sitePackagesCBox = QCheckBox(
            "&Make system (global) site-packages dir available to venv")
        self.launchVenvCBox = QCheckBox(
            "Launch a terminal with activated &venv after installation")
        self.symlinksCBox = QCheckBox(
            "Attempt to &symlink rather than copy files into venv")

        # events
        self.withPipCBox.toggled.connect(self.collectData)
        self.sitePackagesCBox.toggled.connect(self.collectData)
        self.launchVenvCBox.toggled.connect(self.collectData)
        self.venvNameLineEdit.textChanged.connect(self.collectData)
        self.venvLocationLineEdit.textChanged.connect(self.collectData)
        self.interprComboBox.currentIndexChanged.connect(self.collectData)
        self.symlinksCBox.toggled.connect(self.collectData)
        selectFolderToolButton.clicked.connect(self.selectDir)

        # store the collected data in line edits
        self.interprVers = QLineEdit()
        self.interprPath = QLineEdit()
        self.venvName = QLineEdit()
        self.venvLocation = QLineEdit()
        self.withPip = QLineEdit()
        self.sitePackages = QLineEdit()
        self.launchVenv = QLineEdit()
        self.symlinks = QLineEdit()

        # register fields
        self.registerField("interprComboBox*", self.interprComboBox)
        self.registerField("venvNameLineEdit*", self.venvNameLineEdit)
        self.registerField("venvLocationLineEdit*", self.venvLocationLineEdit)
        self.registerField("interprVers", self.interprVers)
        self.registerField("interprPath", self.interprPath)
        self.registerField("venvName", self.venvName)
        self.registerField("venvLocation", self.venvLocation)
        self.registerField("withPip", self.withPip)
        self.registerField("sitePackages", self.sitePackages)
        self.registerField("launchVenv", self.launchVenv)
        self.registerField("symlinks", self.symlinks)

        # grid layout
        gridLayout = QGridLayout()
        gridLayout.addWidget(interpreterLabel, 0, 0, 1, 1)
        gridLayout.addWidget(self.interprComboBox, 0, 1, 1, 2)
        gridLayout.addWidget(venvNameLabel, 1, 0, 1, 1)
        gridLayout.addWidget(self.venvNameLineEdit, 1, 1, 1, 2)
        gridLayout.addWidget(venvLocationLabel, 2, 0, 1, 1)
        gridLayout.addWidget(self.venvLocationLineEdit, 2, 1, 1, 1)
        gridLayout.addWidget(selectFolderToolButton, 2, 2, 1, 1)
        gridLayout.addWidget(placeHolder, 3, 0, 1, 2)
        gridLayout.addWidget(groupBox, 4, 0, 1, 3)
        self.setLayout(gridLayout)

        # 'options' groupbox
        groupBoxLayout = QVBoxLayout()
        groupBoxLayout.addWidget(self.withPipCBox)
        groupBoxLayout.addWidget(self.sitePackagesCBox)
        groupBoxLayout.addWidget(self.launchVenvCBox)
        groupBoxLayout.addWidget(self.symlinksCBox)
        groupBox.setLayout(groupBoxLayout)


    #]=======================================================================[#
    #] SELECTIONS [#=========================================================[#
    #]=======================================================================[#

    def selectDir(self):
        """
        Specify path where to create venv.
        """
        folderName = QFileDialog.getExistingDirectory()
        self.venvLocationLineEdit.setText(folderName)

    def collectData(self, i):
        """
        Collect all input data and create the virtual environment.
        """
        self.interprVers.setText(self.interprComboBox.currentText())
        self.interprPath.setText(self.interprComboBox.currentData())
        self.venvName.setText(self.venvNameLineEdit.text())
        self.venvLocation.setText(self.venvLocationLineEdit.text())

        # the 'options'
        self.withPip.setText(str(self.withPipCBox.isChecked()))
        self.sitePackages.setText(str(self.sitePackagesCBox.isChecked()))
        self.launchVenv.setText(str(self.launchVenvCBox.isChecked()))
        self.symlinks.setText(str(self.symlinksCBox.isChecked()))


#]===========================================================================[#
#] WORKER  [#================================================================[#
#]===========================================================================[#

class InstallWorker(QObject):
    """
    Worker informing about start and finish of the create process.
    """
    started = pyqtSignal()
    finished = pyqtSignal()

    @pyqtSlot(tuple)
    def install(self, args):
        self.started.emit()

        name, location, with_pip, site_packages, symlinks = args
        # outputs as excpected
        #print(args)
        #print("pip:", args[2], "\nsite-pkgs:", args[3], "\nsymlinks:", args[4])

        venv.create(
            os.path.join(location, name),  # 'location' and 'name' works
            with_pip=with_pip,  # installs pip always (the default)
            system_site_packages=site_packages,  # not tested yet
            symlinks=symlinks,  # never symlinking
        )

        self.finished.emit()


class InstallPackages(QWizardPage):
    """
    Install packages via `pip` into the created virtual environment.
    """
    def __init__(self):
        super().__init__()

        self.setTitle("Install Packages")
        self.setSubTitle("Specify the packages which you want Pip to "
                         "install into the virtual environment.")

        self.progressBar = ProgBarWidget()


        #]===================================================================[#
        #] THREAD  [#========================================================[#
        #]===================================================================[#

        thread = QThread(self)
        thread.start()

        self.m_install_worker = InstallWorker()
        self.m_install_worker.moveToThread(thread)

        self.m_install_worker.started.connect(self.progressBar.exec_)
        self.m_install_worker.finished.connect(self.progressBar.close)
        self.m_install_worker.finished.connect(self.reEnablePage)


        #]===================================================================[#
        #] PAGE CONTENT [#===================================================[#
        #]===================================================================[#

        # just some test content (page is still in development)
        TestLabel = QLabel("This is a test label:", self)
        TestLineEdit = QLineEdit(self)
        TestLabel.setBuddy(TestLineEdit)

        TestLabel2 = QLabel("This is a test label:", self)
        TestLineEdit2 = QLineEdit(self)
        TestLabel2.setBuddy(TestLineEdit2)

        v_layout = QVBoxLayout(self)
        v_layout.addWidget(TestLabel)
        v_layout.addWidget(TestLineEdit)
        v_layout.addWidget(TestLabel2)
        v_layout.addWidget(TestLineEdit2)
        self.setLayout(v_layout)


    def initializePage(self):
        #interprVers = self.field("interprVers")
        self.interprPath = self.field("interprPath")
        self.venvName = self.field("venvName")
        self.venvLocation = self.field("venvLocation")
        self.withPip = self.field("withPip")
        self.sitePackages = self.field("sitePackages")
        #launchVenv = self.field("launchVenv")
        self.symlinks = self.field("symlinks")

        # set the selected interpreter
        sys.executable = self.interprPath

        # run the create process
        self.createProcess()

        # disable the page as long as the progress bar is up
        self.setEnabled(False)


    def reEnablePage(self):
        """
        Re-enable page after the create process has finished.
        """
        self.setEnabled(True)


    def createProcess(self):
        """
        Create the virtual environment.
        """
        args = (
            self.venvName,
            self.venvLocation,
            self.withPip,
            self.sitePackages,
            self.symlinks,
        )

        wrapper = partial(self.m_install_worker.install, args)
        QTimer.singleShot(0, wrapper)



class Summary(QWizardPage):
    def __init__(self):
        super().__init__()

        self.setTitle("Summary")
        self.setSubTitle("...............")



if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)

    wizard = VenvWizard()
    wizard.show()

    sys.exit(app.exec_())

创建QLineEdit只是为了保存不必要的数据,因为您可以将小部件属性注册为复选框的状态。 您还将布尔值True或False分别转换为字符串“ True”或“ False”,然后将其传递给函数venv.create(),该函数会将其转换为布尔值,但任何不为空的字符串都是真实的。

解决方案是除了其他小部件之外,直接注册QCheckBox。

class BasicSettings(QWizardPage):
    """
    Basic settings of the virtual environment being created.
    """

    def __init__(self):
        super().__init__()

        # ...
        groupBox.setLayout(groupBoxLayout)

        selectFolderToolButton.clicked.connect(self.selectDir)

        self.registerField("interprVers", self.interprComboBox, "currentText")
        self.registerField("interprPath", self.interprComboBox, "currentData")
        self.registerField("venvName", self.venvNameLineEdit)
        self.registerField("venvLocation", self.venvLocationLineEdit)

        self.registerField("withPip", self.withPipCBox)
        self.registerField("sitePackages", self.sitePackagesCBox)
        self.registerField("launchVenv", self.launchVenvCBox)
        self.registerField("symlinks", self.symlinksCBox)

    # ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM