#!/usr/bin/env python from __future__ import print_function import json import re import sys from bisect import bisect from datetime import datetime from datetime import timedelta import ssl try: from urllib.request import Request, build_opener, HTTPSHandler, URLError except ImportError: from urllib2 import Request, build_opener, HTTPSHandler, URLError from pip.commands.uninstall import UninstallCommand from pip.commands.install import InstallCommand from pip import get_installed_distributions def get_releases(package_name): url = 'https://pypi.python.org/pypi/%s/json' % package_name ssl_context = HTTPSHandler( context=ssl.SSLContext(ssl.PROTOCOL_TLSv1)) opener = build_opener(ssl_context) retries = 10 while retries > 0: try: r = opener.open(Request(url)) break except URLError: retries -= 1 return json.loads(r.read().decode('utf8'))['releases'] def parse_iso8601(s): return datetime(*map(int, re.split('[^\d]', s))) def select_version(select_date, package_name): versions = [] for version, dists in get_releases(package_name).items(): date = [parse_iso8601(d['upload_time']) for d in dists] if date: versions.append((sorted(date)[0], version)) versions = sorted(versions) min_date = versions[0][0] if select_date < min_date: raise Exception('invalid select_date: %s, must be ' '%s or newer.' % (select_date, min_date)) return versions[bisect([x[0] for x in versions], select_date) - 1][1] installed_packages = [ package.project_name for package in get_installed_distributions() if (not package.location.endswith('dist-packages') and package.project_name not in ('pip', 'setuptools')) ] if installed_packages: pip = UninstallCommand() options, args = pip.parse_args(installed_packages) options.yes = True try: pip.run(options, args) except OSError as e: if e.errno != 13: raise e print("You lack permissions to uninstall this package. Perhaps run with sudo? Exiting.") exit(13) date = parse_iso8601(sys.argv[1]) packages = {p: select_version(date, p) for p in sys.argv[2:]} args = ['=='.join(a) for a in packages.items()] cmd = InstallCommand() options, args = cmd.parse_args(args) options.ignore_installed = True options.force_reinstall = True try: print(cmd.run(options, args)) except OSError as e: if e.errno != 13: raise e print("You lack permissions to uninstall this package. Perhaps run with sudo? Exiting.") exit(13)