eric7/PipInterface/PipFreezeDialog.py

Sun, 13 Mar 2022 15:20:26 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 13 Mar 2022 15:20:26 +0100
branch
eric7
changeset 8976
ca442cd49b9e
parent 8881
54e42bc2437a
permissions
-rw-r--r--

Refactored the 'pip freeze' functionality and moved it to the main pip interface module.

# -*- coding: utf-8 -*-

# Copyright (c) 2015 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog to generate a requirements file.
"""

import os

from PyQt6.QtCore import pyqtSlot, Qt
from PyQt6.QtWidgets import (
    QDialog, QDialogButtonBox, QAbstractButton, QApplication
)

from EricWidgets import EricMessageBox, EricFileDialog
from EricWidgets.EricPathPicker import EricPathPickerModes
from EricWidgets.EricApplication import ericApp
from EricGui.EricOverrideCursor import EricOverrideCursor

from .Ui_PipFreezeDialog import Ui_PipFreezeDialog

import Utilities


class PipFreezeDialog(QDialog, Ui_PipFreezeDialog):
    """
    Class implementing a dialog to generate a requirements file.
    """
    def __init__(self, pip, parent=None):
        """
        Constructor
        
        @param pip reference to the master object
        @type Pip
        @param parent reference to the parent widget
        @type QWidget
        """
        super().__init__(parent)
        self.setupUi(self)
        self.setWindowFlags(Qt.WindowType.Window)
        
        self.__refreshButton = self.buttonBox.addButton(
            self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole)
        
        self.__environmentName = ""
        
        self.requirementsFilePicker.setMode(EricPathPickerModes.SAVE_FILE_MODE)
        self.requirementsFilePicker.setFilters(
            self.tr("Text Files (*.txt);;All Files (*)"))
        
        self.__pip = pip
        
        self.__requirementsEdited = False
        self.__requirementsAvailable = False
        
        self.__updateButtons()
    
    def closeEvent(self, e):
        """
        Protected slot implementing a close event handler.
        
        @param e close event
        @type QCloseEvent
        """
        e.accept()
    
    @pyqtSlot()
    def on_localCheckBox_clicked(self):
        """
        Private slot handling the switching of the local mode.
        """
        self.__refresh()
    
    @pyqtSlot()
    def on_userCheckBox_clicked(self):
        """
        Private slot handling the switching of the user-site mode.
        """
        self.__refresh()
    
    @pyqtSlot(str)
    def on_requirementsFilePicker_textChanged(self, txt):
        """
        Private slot handling a change of the requirements file name.
        
        @param txt name of the requirements file
        @type str
        """
        self.__updateButtons()
    
    @pyqtSlot()
    def on_requirementsEdit_textChanged(self):
        """
        Private slot handling changes of the requirements text.
        """
        self.__requirementsEdited = True
    
    @pyqtSlot(QAbstractButton)
    def on_buttonBox_clicked(self, button):
        """
        Private slot called by a button of the button box clicked.
        
        @param button button that was clicked
        @type QAbstractButton
        """
        if button == self.buttonBox.button(
            QDialogButtonBox.StandardButton.Close
        ):
            self.close()
        elif button == self.__refreshButton:
            self.__refresh()
    
    def __refresh(self):
        """
        Private slot to refresh the displayed list.
        """
        ok = (
            EricMessageBox.yesNo(
                self,
                self.tr("Generate Requirements"),
                self.tr("""The requirements were changed. Do you want"""
                        """ to overwrite these changes?"""))
            if self.__requirementsEdited else
            True
        )
        if ok:
            self.start(self.__environmentName)
    
    def start(self, venvName):
        """
        Public method to start the command.
        
        @param venvName name of the environment to act upon
        @type str
        """
        self.requirementsEdit.clear()
        self.__requirementsAvailable = False
        self.__environmentName = venvName
        
        fileName = (
            Utilities.toNativeSeparators(self.requirementsFilePicker.text())
            if self.requirementsFilePicker.text() else
            ""
        )
        
        with EricOverrideCursor():
            specifiers = self.__pip.getFrozenPackages(
                venvName, localPackages=self.localCheckBox.isChecked(),
                usersite=self.userCheckBox.isChecked(), requirement=fileName)
            
            if specifiers:
                self.requirementsEdit.setPlainText(
                    "\n".join(specifiers) + "\n")
                self.__requirementsAvailable = True
            else:
                self.requirementsEdit.setPlainText(self.tr(
                    "No package specifiers generated by 'pip freeze'.")
                )
        
        self.__updateButtons()
        
        self.__requirementsEdited = False
    
    def __updateButtons(self):
        """
        Private method to set the state of the various buttons.
        """
        self.saveButton.setEnabled(
            self.__requirementsAvailable and
            bool(self.requirementsFilePicker.text())
        )
        self.saveToButton.setEnabled(self.__requirementsAvailable)
        self.copyButton.setEnabled(self.__requirementsAvailable)
        
        aw = ericApp().getObject("ViewManager").activeWindow()
        if aw and self.__requirementsAvailable:
            self.insertButton.setEnabled(True)
            self.replaceAllButton.setEnabled(True)
            self.replaceSelectionButton.setEnabled(
                aw.hasSelectedText())
        else:
            self.insertButton.setEnabled(False)
            self.replaceAllButton.setEnabled(False)
            self.replaceSelectionButton.setEnabled(False)
    
    def __writeToFile(self, fileName):
        """
        Private method to write the requirements text to a file.
        
        @param fileName name of the file to write to
        @type str
        """
        if os.path.exists(fileName):
            ok = EricMessageBox.warning(
                self,
                self.tr("Generate Requirements"),
                self.tr("""The file <b>{0}</b> already exists. Do you want"""
                        """ to overwrite it?""").format(fileName))
            if not ok:
                return
        
        try:
            with open(fileName, "w") as f:
                f.write(self.requirementsEdit.toPlainText())
        except OSError as err:
            EricMessageBox.critical(
                self,
                self.tr("Generate Requirements"),
                self.tr("""<p>The requirements could not be written"""
                        """ to <b>{0}</b>.</p><p>Reason: {1}</p>""")
                .format(fileName, str(err)))
    
    @pyqtSlot()
    def on_saveButton_clicked(self):
        """
        Private slot to save the requirements text to the requirements file.
        """
        fileName = self.requirementsFilePicker.text()
        self.__writeToFile(fileName)
    
    @pyqtSlot()
    def on_saveToButton_clicked(self):
        """
        Private slot to write the requirements text to a new file.
        """
        fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
            self,
            self.tr("Generate Requirements"),
            os.path.expanduser("~"),
            self.tr("Text Files (*.txt);;All Files (*)"),
            None,
            EricFileDialog.DontConfirmOverwrite
        )
        if fileName:
            ext = os.path.splitext(fileName)[1]
            if not ext:
                ex = selectedFilter.split("(*")[1].split(")")[0]
                if ex:
                    fileName += ex
            self.__writeToFile(fileName)
    
    @pyqtSlot()
    def on_copyButton_clicked(self):
        """
        Private slot to copy the requirements text to the clipboard.
        """
        txt = self.requirementsEdit.toPlainText()
        cb = QApplication.clipboard()
        cb.setText(txt)
    
    @pyqtSlot()
    def on_insertButton_clicked(self):
        """
        Private slot to insert the requirements text at the cursor position
        of the current editor.
        """
        aw = ericApp().getObject("ViewManager").activeWindow()
        if aw:
            aw.beginUndoAction()
            aw.insert(self.requirementsEdit.toPlainText())
            aw.endUndoAction()
    
    @pyqtSlot()
    def on_replaceSelectionButton_clicked(self):
        """
        Private slot to replace the selected text of the current editor
        with the requirements text.
        """
        aw = ericApp().getObject("ViewManager").activeWindow()
        if aw:
            aw.beginUndoAction()
            aw.replaceSelectedText(self.requirementsEdit.toPlainText())
            aw.endUndoAction()
    
    @pyqtSlot()
    def on_replaceAllButton_clicked(self):
        """
        Private slot to replace the text of the current editor with the
        requirements text.
        """
        aw = ericApp().getObject("ViewManager").activeWindow()
        if aw:
            aw.setText(self.requirementsEdit.toPlainText())

eric ide

mercurial