CondaInterface/Conda.py

Wed, 06 Feb 2019 19:52:33 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 06 Feb 2019 19:52:33 +0100
branch
conda
changeset 6705
8cf1c3851b5c
parent 6701
af29cf6ca309
child 6706
d792e054cde2
permissions
-rw-r--r--

Conda, CondaPackagesWidget: continued implementing list functionality.

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

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

"""
Package implementing the conda GUI logic.
"""

from __future__ import unicode_literals
try:
    str = unicode       # __IGNORE_EXCEPTION__
except NameError:
    pass

import json
import os

from PyQt5.QtCore import QObject, QProcess

from E5Gui import E5MessageBox

import Globals
import Preferences

from . import rootPrefix


class Conda(QObject):
    """
    Class implementing the conda GUI logic.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent parent
        @type QObject
        """
        super(Conda, self).__init__(parent)
        
        self.__ui = parent
    
    #######################################################################
    ## environment related methods below
    #######################################################################
    
    def createCondaEnvironment(self, arguments):
        """
        Public method to create a conda environment.
        
        @param arguments list of command line arguments
        @type list of str
        @return tuple containing a flag indicating success, the directory of
            the created environment (aka. prefix) and the corresponding Python
            interpreter
        @rtype tuple of (bool, str, str)
        """
        from .CondaExecDialog import CondaExecDialog
        
        args = ["create", "--json", "--yes"] + arguments
        
        dlg = CondaExecDialog("create", self.__ui)
        dlg.start(args)
        dlg.exec_()
        ok, resultDict = dlg.getResult()
        
        if ok:
            if "actions" in resultDict and \
                    "PREFIX" in resultDict["actions"]:
                prefix = resultDict["actions"]["PREFIX"]
            elif "prefix" in resultDict:
                prefix = resultDict["prefix"]
            elif "dst_prefix" in resultDict:
                prefix = resultDict["dst_prefix"]
            else:
                prefix = ""
            
            # determine Python executable
            if prefix:
                pathPrefixes = [
                    prefix,
                    rootPrefix()
                ]
            else:
                pathPrefixes = [
                    rootPrefix()
                ]
            for pathPrefix in pathPrefixes:
                if Globals.isWindowsPlatform():
                    python = os.path.join(pathPrefix, "python.exe")
                else:
                    python = os.path.join(pathPrefix, "bin", "python")
                if os.path.exists(python):
                    break
            else:
                python = ""
            
            return True, prefix, python
        else:
            return False, "", ""
    
    def removeCondaEnvironment(self, name="", prefix=""):
        """
        Public method to remove a conda environment.
        
        @param name name of the environment
        @type str
        @param prefix prefix of the environment
        @type str
        @return flag indicating success
        @rtype bool
        @exception RuntimeError raised to indicate an error in parameters
        
        Note: only one of name or prefix must be given.
        """
        if name and prefix:
            raise RuntimeError("Only one of 'name' or 'prefix' must be given.")
        
        if not name and not prefix:
            raise RuntimeError("One of 'name' or 'prefix' must be given.")
        
        args = [
            "remove",
            "--json",
            "--quiet",
            "--all",
        ]
        if name:
            args.extend(["--name", name])
        elif prefix:
            args.extend(["--prefix", prefix])
        
        exe = Preferences.getConda("CondaExecutable")
        if not exe:
            exe = "conda"
        
        proc = QProcess()
        proc.start(exe, args)
        if not proc.waitForStarted(15000):
            E5MessageBox.critical(
                self.__ui,
                self.tr("conda remove"),
                self.tr("""The conda executable could not be started."""))
            return False
        else:
            proc.waitForFinished(15000)
            output = str(proc.readAllStandardOutput(),
                         Preferences.getSystem("IOEncoding"),
                         'replace').strip()
            try:
                jsonDict = json.loads(output)
            except Exception:
                E5MessageBox.critical(
                    self.__ui,
                    self.tr("conda remove"),
                    self.tr("""The conda executable returned invalid data."""))
                return False
            
            if "error" in jsonDict:
                E5MessageBox.critical(
                    self.__ui,
                    self.tr("conda remove"),
                    self.tr("<p>The conda executable returned an error.</p>"
                            "<p>{0}</p>").format(jsonDict["message"]))
                return False
            
            return jsonDict["success"]
    
    def getCondaEnvironmentsList(self):
        """
        Public method to get a list of all Conda environments.
        
        @return list of tuples containing the environment name and prefix
        @rtype list of tuples of (str, str)
        """
        exe = Preferences.getConda("CondaExecutable")
        if not exe:
            exe = "conda"
        
        environmentsList = []
        
        proc = QProcess()
        proc.start(exe, ["info", "--json"])
        if proc.waitForStarted(15000):
            if proc.waitForFinished(15000):
                output = str(proc.readAllStandardOutput(),
                             Preferences.getSystem("IOEncoding"),
                             'replace').strip()
                try:
                    jsonDict = json.loads(output)
                except Exception:
                    jsonDict = {}
                
                if "envs" in jsonDict:
                    for prefix in jsonDict["envs"][:]:
                        if prefix == jsonDict["root_prefix"]:
                            if not jsonDict["root_writable"]:
                                # root prefix is listed but not writable
                                continue
                            name = self.tr("<root>")
                        else:
                            name = os.path.basename(prefix)
                        
                        environmentsList.append((name, prefix))
        
        return environmentsList
    
    #######################################################################
    ## package related methods below
    #######################################################################
    
    def getInstalledPackages(self, name="", prefix=""):
        """
        Public method to get a list of installed packages of a conda
        environment.
        
        @param name name of the environment
        @type str
        @param prefix prefix of the environment
        @type str
        @return list of installed packages. Each entry is a tuple containing
            the package name, version and build.
        @rtype list of tuples of (str, str, str)
        @rtype bool
        @exception RuntimeError raised to indicate an error in parameters
        
        Note: only one of name or prefix must be given.
        """
        if name and prefix:
            raise RuntimeError("Only one of 'name' or 'prefix' must be given.")
        
        if not name and not prefix:
            raise RuntimeError("One of 'name' or 'prefix' must be given.")
        
        args = [
            "list",
            "--json",
        ]
        if name:
            args.extend(["--name", name])
        elif prefix:
            args.extend(["--prefix", prefix])
        
        exe = Preferences.getConda("CondaExecutable")
        if not exe:
            exe = "conda"
        
        packages = []
        
        proc = QProcess()
        proc.start(exe, args)
        if proc.waitForStarted(15000):
            if proc.waitForFinished(30000):
                output = str(proc.readAllStandardOutput(),
                             Preferences.getSystem("IOEncoding"),
                             'replace').strip()
                try:
                    jsonList = json.loads(output)
                except Exception:
                    jsonList = []
                
                for package in jsonList:
                    if isinstance(package, dict):
                        packages.append((
                            package["name"],
                            package["version"],
                            package["build_string"]
                        ))
                    else:
                        packages.append(tuple(package.rsplit("-", 2)))
        
        return packages
    
    def getUpdateablePackages(self, name="", prefix=""):
        """
        Public method to get a list of updateable packages of a conda
        environment.
        
        @param name name of the environment
        @type str
        @param prefix prefix of the environment
        @type str
        @return list of installed packages. Each entry is a tuple containing
            the package name, version and build.
        @rtype list of tuples of (str, str, str)
        @rtype bool
        @exception RuntimeError raised to indicate an error in parameters
        
        Note: only one of name or prefix must be given.
        """
        if name and prefix:
            raise RuntimeError("Only one of 'name' or 'prefix' must be given.")
        
        if not name and not prefix:
            raise RuntimeError("One of 'name' or 'prefix' must be given.")
        
        args = [
            "update",
            "--json",
            "--quiet",
            "--all",
            "--dry-run",
        ]
        if name:
            args.extend(["--name", name])
        elif prefix:
            args.extend(["--prefix", prefix])
        
        exe = Preferences.getConda("CondaExecutable")
        if not exe:
            exe = "conda"
        
        packages = []
        
        proc = QProcess()
        proc.start(exe, args)
        if proc.waitForStarted(15000):
            if proc.waitForFinished(30000):
                output = str(proc.readAllStandardOutput(),
                             Preferences.getSystem("IOEncoding"),
                             'replace').strip()
                try:
                    jsonDict = json.loads(output)
                except Exception:
                    jsonDict = {}
                
                if "actions" in jsonDict and "LINK" in jsonDict["actions"]:
                    for linkEntry in jsonDict["actions"]["LINK"]:
                        if isinstance(linkEntry, dict):
                            packages.append((
                                linkEntry["name"],
                                linkEntry["version"],
                                linkEntry["build_string"]
                            ))
                        else:
                            package = linkEntry.split()[0]
                            packages.append(tuple(package.rsplit("-", 2)))
        
        return packages
    
    def updatePackages(self, packages, name="", prefix=""):
        """
        Public method to update packages of a conda environment.
        
        @param packages list of package names to be updated
        @type list of str
        @param name name of the environment
        @type str
        @param prefix prefix of the environment
        @type str
        @return list of installed packages. Each entry is a tuple containing
            the package name, version and build.
        @rtype list of tuples of (str, str, str)
        @rtype bool
        @exception RuntimeError raised to indicate an error in parameters
        
        Note: only one of name or prefix must be given.
        """
        if name and prefix:
            raise RuntimeError("Only one of 'name' or 'prefix' must be given.")
        
        if not name and not prefix:
            raise RuntimeError("One of 'name' or 'prefix' must be given.")
        
        # TODO: not implemented yet
    
    def updateAllPackages(self, name="", prefix=""):
        """
        Public method to update all packages of a conda environment.
        
        @param name name of the environment
        @type str
        @param prefix prefix of the environment
        @type str
        @return list of installed packages. Each entry is a tuple containing
            the package name, version and build.
        @rtype list of tuples of (str, str, str)
        @rtype bool
        @exception RuntimeError raised to indicate an error in parameters
        
        Note: only one of name or prefix must be given.
        """
        if name and prefix:
            raise RuntimeError("Only one of 'name' or 'prefix' must be given.")
        
        if not name and not prefix:
            raise RuntimeError("One of 'name' or 'prefix' must be given.")
        
        # TODO: not implemented yet
    
    def installPackages(self, packages, name="", prefix=""):
        """
        Public method to install packages into a conda environment.
        
        @param packages list of package names to be installed
        @type list of str
        @param name name of the environment
        @type str
        @param prefix prefix of the environment
        @type str
        @return list of installed packages. Each entry is a tuple containing
            the package name, version and build.
        @rtype list of tuples of (str, str, str)
        @rtype bool
        @exception RuntimeError raised to indicate an error in parameters
        
        Note: only one of name or prefix must be given.
        """
        if name and prefix:
            raise RuntimeError("Only one of 'name' or 'prefix' must be given.")
        
        if not name and not prefix:
            raise RuntimeError("One of 'name' or 'prefix' must be given.")
        
        # TODO: not implemented yet
    
    def uninstallPackages(self, packages, name="", prefix=""):
        """
        Public method to uninstall packages of a conda environment.
        
        @param packages list of package names to be uninstalled
        @type list of str
        @param name name of the environment
        @type str
        @param prefix prefix of the environment
        @type str
        @return list of installed packages. Each entry is a tuple containing
            the package name, version and build.
        @rtype list of tuples of (str, str, str)
        @rtype bool
        @exception RuntimeError raised to indicate an error in parameters
        
        Note: only one of name or prefix must be given.
        """
        if name and prefix:
            raise RuntimeError("Only one of 'name' or 'prefix' must be given.")
        
        if not name and not prefix:
            raise RuntimeError("One of 'name' or 'prefix' must be given.")
        
        # TODO: not implemented yet

eric ide

mercurial