簡體   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