from __future__ import absolute_import
import sys
import copy
from io import StringIO
from pip.commands.search import SearchCommand, transform_hits, highest_version
from pip.commands.list import ListCommand
from pip.commands.show import ShowCommand
from pip.exceptions import CommandError
from pip.status_codes import SUCCESS, ERROR, NO_MATCHES_FOUND
from pip import main
from pip_tkinter.utils import Redirect
# For GUI version, redirects would be here, done once.
# Put in runpip for prototype testing in text mode, so can print.
[docs]def runpip(argstring):
"""Run pip with argument string containing command and options.
:param argstring: is quoted version of what would follow 'pip'
on command line.
"""
with Redirect('stdout', sysout) as f1, Redirect('stderr', syserr) as f2:
status = main(argstring.split())
out = sysout.getvalue()
err = syserr.getvalue()
sysout.seek(0); sysout.truncate(0)
syserr.seek(0); syserr.truncate(0)
return status, out, err
[docs]class GUISearchCommand(SearchCommand):
"""
Inherited the class : pip.commands.search.SearchCommand to override
run method
Advantage of inheriting the class is that we can have better control of
pip. For example, currently pip search gives output for latest version.
But, we can retrieve output for all available versions.
Another advantage is that search can now be done with less time lag as
compared to pip.main().
"""
[docs] def run(self, options, args):
if not args:
raise CommandError('Missing required argument (search query).')
query = args
try:
# The developer version of pip uses options as argument
pypi_hits = self.search(query,options)
self.hits = transform_hits(pypi_hits)
if pypi_hits:
return SUCCESS
else:
return NO_MATCHES_FOUND
except TypeError:
# But, the stable version of pip uses options.index as argument
pypi_hits = self.search(query,options.index)
self.hits = transform_hits(pypi_hits)
if pypi_hits:
return SUCCESS
else:
return NO_MATCHES_FOUND
[docs] def get_search_results(self):
"""
This code is taken from pip.commands.search.print_results(). It is modified
to return results in dictionary format instead of printing results
For all the search results obtained, we can check if a package is already
installed or not. If installed then the version of installed package is
found and stored.
"""
if not hasattr(self, "hits"):
return None
# Here pkg_resources is a module of pip._vendor. It has been included
# in pip gui because as mentioned by pip, this module is considered to
# be 'immutable'. There are very less chances that it will changed in future
from pip_tkinter._vendor import pkg_resources
self.installed_packages = [p.project_name for p in pkg_resources.working_set]
for hit in self.hits:
hit['latest'] = highest_version(hit['versions'])
name = hit['name']
if name in self.installed_packages:
dist = pkg_resources.get_distribution(name)
hit['installed'] = dist.version
return self.hits
[docs]class GUIListCommand(ListCommand):
"""
Extending the pip ListCommand to show list of packages :
1. For uninstall : retrieves list of installed packages with their versions
2. For update : retrieved list of installed packages which are outdated
"""
[docs] def output_package_listing(self, installed_packages):
self.installed_packages_list = []
installed_packages = sorted(
installed_packages,
key=lambda dist: dist.project_name.lower(),
)
for dist in installed_packages:
self.installed_packages_list.append((dist.project_name, dist.version))
[docs] def run_outdated(self, options):
self.find_outdated = False
self.outdated_packages_list = []
if options.outdated:
self.find_outdated = True
for dist, latest_version, typ in sorted(
self.find_packages_latest_versions(options),
key=lambda p: p[0].project_name.lower()):
if latest_version > dist.parsed_version:
self.outdated_packages_list.append((
dist.project_name,
dist.version,
str(latest_version),
))
[docs] def get_installed_packages_list(self):
if hasattr(self,'find_outdated'):
if self.find_outdated:
return self.outdated_packages_list
else:
return self.installed_packages_list
[docs]class GUIShowCommand(ShowCommand):
"""
Parent class : pip.commands.show.ShowCommand
"""
[docs] def run(self, options, args):
if not args:
logger.warning('ERROR: Please provide a package name or names.')
return ERROR
query = args
from pip.commands.show import search_packages_info
results = search_packages_info(query)
if not self.save_results(results, options.files):
return ERROR
return SUCCESS
[docs] def save_results(self, distributions, list_all_files):
results_printed = False
for dist in distributions:
results_printed = True
self.package_details.append(dist)
return results_printed
[docs] def get_package_details(self):
if hasattr(self,'package_details'):
return self.package_details
else:
return []