def _build_args( self, requirements=None, requirements_file=None, no_use_wheel=False): pip_command = 'download' if parse_version(pip.__version__) < parse_version('8.0.0'): pip_command = 'install' args = [ pip_command, '-d', self.download_path, ] if no_use_wheel: args.append('--no-use-wheel') if requirements is not None: args.extend(requirements) elif requirements_file is not None: args.extend(['-r', requirements_file]) else: error = 'Either requirements or requirements_file must be given.' raise ValueError(error) return args
def test_sets_correct_variables(self): obj = candidate.InstallationCandidate( "A", "1.0.0", "https://somewhere.com/path/A-1.0.0.tar.gz" ) assert obj.project == "A" assert obj.version == parse_version("1.0.0") assert obj.location == "https://somewhere.com/path/A-1.0.0.tar.gz"
def run_egg_info(self): assert self.source_dir if self.name: logger.debug( 'Running setup.py (path:%s) egg_info for package %s', self.setup_py, self.name, ) else: logger.debug( 'Running setup.py (path:%s) egg_info for package from %s', self.setup_py, self.link, ) with indent_log(): script = SETUPTOOLS_SHIM % self.setup_py base_cmd = [sys.executable, '-c', script] if self.isolated: base_cmd += ["--no-user-cfg"] egg_info_cmd = base_cmd + ['egg_info'] # We can't put the .egg-info files at the root, because then the # source code will be mistaken for an installed egg, causing # problems if self.editable: egg_base_option = [] else: egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info') ensure_dir(egg_info_dir) egg_base_option = ['--egg-base', 'pip-egg-info'] call_subprocess( egg_info_cmd + egg_base_option, cwd=self.setup_py_dir, show_stdout=False, command_level=logging.DEBUG, command_desc='python setup.py egg_info') if not self.req: if isinstance(parse_version(self.pkg_info()["Version"]), Version): op = "==" else: op = "===" self.req = Requirement( "".join([ self.pkg_info()["Name"], op, self.pkg_info()["Version"], ]) ) self._correct_build_location() else: metadata_name = canonicalize_name(self.pkg_info()["Name"]) if canonicalize_name(self.req.name) != metadata_name: logger.warning( 'Running setup.py (path:%s) egg_info for package %s ' 'produced metadata for project name %s. Fix your ' '#egg=%s fragments.', self.setup_py, self.name, metadata_name, self.name ) self.req = Requirement(metadata_name)
def __init__(self, project, version, location): self.project = project self.version = parse_version(version) self.location = location super(InstallationCandidate, self).__init__( key=(self.project, self.version, self.location), defining_class=InstallationCandidate )
def __init__(self, project, version, location): # type: (Any, str, Link) -> None self.project = project self.version = parse_version(version) # type: _BaseVersion self.location = location super(InstallationCandidate, self).__init__( key=(self.project, self.version, self.location), defining_class=InstallationCandidate )
def get_git_version(self): VERSION_PFX = 'git version ' version = self.run_command(['version'], show_stdout=False) if version.startswith(VERSION_PFX): version = version[len(VERSION_PFX):] else: version = '' # get first 3 positions of the git version becasue # on windows it is x.y.z.windows.t, and this parses as # LegacyVersion which always smaller than a Version. version = '.'.join(version.split('.')[:3]) return parse_version(version)
def update(self, dest, url, rev_options): # First fetch changes from the default remote if self.get_git_version() >= parse_version('1.9.0'): # fetch tags in addition to everything else self.run_command(['fetch', '-q', '--tags'], cwd=dest) else: self.run_command(['fetch', '-q'], cwd=dest) # Then reset to wanted revision (maybe even origin/master) rev_options = self.resolve_revision(dest, url, rev_options) cmd_args = ['reset', '--hard', '-q'] + rev_options.to_args() self.run_command(cmd_args, cwd=dest) #: update submodules self.update_submodules(dest)
def _set_requirement(self): # type: () -> None """Set requirement after generating metadata. """ assert self.req is None assert self.metadata is not None assert self.source_dir is not None # Construct a Requirement object from the generated metadata if isinstance(parse_version(self.metadata["Version"]), Version): op = "==" else: op = "===" self.req = Requirement( "".join([ self.metadata["Name"], op, self.metadata["Version"], ]) )
def print_results(hits, name_column_width=None, terminal_width=None): if not hits: return if name_column_width is None: name_column_width = max([ len(hit['pic']) + len(highest_version(hit.get('versions', ['-']))) for hit in hits ]) + 4 installed_packages = [p.project_name for p in pkg_resources.working_set] for hit in hits: name = hit['pic'] summary = hit['summary'] or '' latest = highest_version(hit.get('versions', ['-'])) if terminal_width is not None: target_width = terminal_width - name_column_width - 5 if target_width > 10: # wrap and indent summary to fit terminal summary = textwrap.wrap(summary, target_width) summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) line = '%-*s - %s' % (name_column_width, '%s (%s)' % (name, latest), summary) try: logger.info(line) if name in installed_packages: dist = pkg_resources.get_distribution(name) with indent_log(): if dist.version == latest: logger.info('INSTALLED: %s (latest)', dist.version) else: logger.info('INSTALLED: %s', dist.version) if parse_version(latest).pre: logger.info( 'LATEST: %s (pre-release; install' ' with "pip install --pre")', latest) else: logger.info('LATEST: %s', latest) except UnicodeEncodeError: pass
def _verify_one(req, wheel_path): # type: (InstallRequirement, str) -> None canonical_name = canonicalize_name(req.name) w = Wheel(os.path.basename(wheel_path)) if canonicalize_name(w.name) != canonical_name: raise InvalidWheelFilename( "Wheel has unexpected file name: expected {!r}, " "got {!r}".format(canonical_name, w.name), ) with zipfile.ZipFile(wheel_path, allowZip64=True) as zf: dist = pkg_resources_distribution_for_wheel( zf, canonical_name, wheel_path, ) if canonicalize_version(dist.version) != canonicalize_version(w.version): raise InvalidWheelFilename( "Wheel has unexpected file name: expected {!r}, " "got {!r}".format(dist.version, w.version), ) if (_get_metadata_version(dist) >= Version("1.2") and not isinstance(parse_version(dist.version), Version)): raise UnsupportedWheel("Metadata 1.2 mandates PEP 440 version, " "but {!r} is not".format(dist.version))
def prepare_metadata(self): # type: () -> None """Ensure that project metadata is available. Under PEP 517, call the backend hook to prepare the metadata. Under legacy processing, call setup.py egg-info. """ assert self.source_dir with indent_log(): if self.use_pep517: self.prepare_pep517_metadata() else: self.run_egg_info() if not self.req: if isinstance(parse_version(self.metadata["Version"]), Version): op = "==" else: op = "===" self.req = Requirement( "".join([ self.metadata["Name"], op, self.metadata["Version"], ]) ) self._correct_build_location() else: metadata_name = canonicalize_name(self.metadata["Name"]) if canonicalize_name(self.req.name) != metadata_name: logger.warning( 'Generating metadata for package %s ' 'produced metadata for project name %s. Fix your ' '#egg=%s fragments.', self.name, metadata_name, self.name ) self.req = Requirement(metadata_name)
import subprocess import sys import mock from click.testing import CliRunner import pytest from piptools._compat.pip_compat import path_to_url from piptools.repositories import PyPIRepository from piptools.scripts.compile import cli from piptools.scripts.sync import cli as sync_cli from pip._vendor.packaging.version import parse as parse_version from pip import __version__ as pip_version PIP_VERSION = parse_version(os.environ.get('PIP', pip_version)) fail_below_pip9 = pytest.mark.xfail(PIP_VERSION < parse_version('9'), reason="needs pip 9 or greater") @pytest.yield_fixture def pip_conf(tmpdir): test_conf = dedent("""\ [global] index-url = http://example.com trusted-host = example.com """) pip_conf_file = 'pip.conf' if os.name != 'nt' else 'pip.ini' path = (tmpdir / pip_conf_file).strpath
def __init__(self, project, version, product): self.project = project self.version = parse_version(version) self.product = product self._key = (self.project, self.version, self.product)
from __future__ import absolute_import, division, print_function, unicode_literals import sys from collections import OrderedDict from itertools import chain, groupby import pip import six from click.utils import LazyFile from pip._vendor.packaging.version import parse as parse_version from six.moves import shlex_quote from ._compat import install_req_from_line from .click import style PIP_VERSION = tuple(map(int, parse_version(pip.__version__).base_version.split("."))) UNSAFE_PACKAGES = {"setuptools", "distribute", "pip"} COMPILE_EXCLUDE_OPTIONS = { "--dry-run", "--quiet", "--rebuild", "--upgrade", "--upgrade-package", "--verbose", } def key_from_ireq(ireq): """Get a standardized key for an InstallRequirement.""" if ireq.req is None and ireq.link is not None: return str(ireq.link)
def find_requirement(self, req, upgrade): """Try to find a Link matching req Expects req, an InstallRequirement and upgrade, a boolean Returns a Link if found, Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise """ all_candidates = self.find_all_candidates(req.name) # Filter out anything which doesn't match our specifier compatible_versions = set( req.specifier.filter( # We turn the version object into a str here because otherwise # when we're debundled but setuptools isn't, Python will see # packaging.version.Version and # pkg_resources._vendor.packaging.version.Version as different # types. This way we'll use a str as a common data interchange # format. If we stop using the pkg_resources provided specifier # and start using our own, we can drop the cast to str(). [str(c.version) for c in all_candidates], prereleases=( self.allow_all_prereleases if self.allow_all_prereleases else None ), ) ) applicable_candidates = [ # Again, converting to str to deal with debundling. c for c in all_candidates if str(c.version) in compatible_versions ] if applicable_candidates: best_candidate = max(applicable_candidates, key=self._candidate_sort_key) else: best_candidate = None if req.satisfied_by is not None: installed_version = parse_version(req.satisfied_by.version) else: installed_version = None if installed_version is None and best_candidate is None: logger.critical( 'Could not find a version that satisfies the requirement %s ' '(from versions: %s)', req, ', '.join( sorted( {str(c.version) for c in all_candidates}, key=parse_version, ) ) ) raise DistributionNotFound( 'No matching distribution found for %s' % req ) best_installed = False if installed_version and ( best_candidate is None or best_candidate.version <= installed_version): best_installed = True if not upgrade and installed_version is not None: if best_installed: logger.debug( 'Existing installed version (%s) is most up-to-date and ' 'satisfies requirement', installed_version, ) else: logger.debug( 'Existing installed version (%s) satisfies requirement ' '(most up-to-date version is %s)', installed_version, best_candidate.version, ) return None if best_installed: # We have an existing version, and its the best version logger.debug( 'Installed version (%s) is most up-to-date (past versions: ' '%s)', installed_version, ', '.join(sorted(compatible_versions, key=parse_version)) or "none", ) raise BestVersionAlreadyInstalled logger.debug( 'Using version %s (newest of versions: %s)', best_candidate.version, ', '.join(sorted(compatible_versions, key=parse_version)) ) return best_candidate.location
def test_get_git_version(): git_version = Git().get_git_version() assert git_version >= parse_version('1.0.0')
def test_sets_correct_variables(self): obj = candidate.InstallationCandidate( "A", "1.0.0", "https://somewhere.com/path/A-1.0.0.tar.gz") assert obj.project == "A" assert obj.version == parse_version("1.0.0") assert obj.location == "https://somewhere.com/path/A-1.0.0.tar.gz"
import sys from textwrap import dedent import mock import pytest from click.testing import CliRunner from pip import __version__ as pip_version from pip._vendor.packaging.version import parse as parse_version from .utils import invoke from piptools._compat.pip_compat import path_to_url from piptools.repositories import PyPIRepository from piptools.scripts.compile import cli PIP_VERSION = parse_version(os.environ.get("PIP", pip_version)) TEST_DATA_PATH = os.path.join(os.path.split(__file__)[0], "test_data") fail_below_pip9 = pytest.mark.xfail(PIP_VERSION < parse_version("9"), reason="needs pip 9 or greater") @pytest.fixture def pip_conf(tmpdir, monkeypatch): test_conf = dedent("""\ [global] index-url = http://example.com trusted-host = example.com """) pip_conf_file = "pip.conf" if os.name != "nt" else "pip.ini"
from textwrap import dedent from six.moves.urllib.request import pathname2url import subprocess import sys import mock from click.testing import CliRunner import pytest from piptools.scripts.compile import cli from piptools.scripts.sync import cli as sync_cli from pip._vendor.packaging.version import parse as parse_version from pip import __version__ as pip_version PIP_VERSION = parse_version(os.environ.get('PIP', pip_version)) fail_below_pip9 = pytest.mark.xfail( PIP_VERSION < parse_version('9'), reason="needs pip 9 or greater" ) @pytest.yield_fixture def pip_conf(tmpdir): test_conf = dedent("""\ [global] index-url = http://example.com trusted-host = example.com """)
from piptools._compat import PackageFinder, install_req_from_line from piptools.pip import get_pip_command from piptools.repositories.pypi import PyPIRepository def test_pypirepo_build_dir_is_str(): assert isinstance(get_pypi_repository().build_dir, str) def test_pypirepo_source_dir_is_str(): assert isinstance(get_pypi_repository().source_dir, str) @pytest.mark.skipif( parse_version(pip_version) >= parse_version("10.0.0"), reason="RequirementSet objects don't take arguments after pip 10.", ) def test_pypirepo_calls_reqset_with_str_paths(): """ Make sure that paths passed to RequirementSet init are str. Passing unicode paths on Python 2 could make pip fail later on unpack, if the package contains non-ASCII file names, because non-ASCII str and unicode paths cannot be combined. """ with patch("piptools.repositories.pypi.RequirementSet") as mocked_init: repo = get_pypi_repository() ireq = install_req_from_line("ansible==2.4.0.0") # Setup a mock object to be returned from the RequirementSet call
def version(self): # type: () -> CandidateVersion return parse_version(self.dist.version)
from piptools.repositories.pypi import PyPIRepository from piptools.scripts.compile import get_pip_command import pytest def test_pypirepo_build_dir_is_str(): assert isinstance(get_pypi_repository().build_dir, str) def test_pypirepo_source_dir_is_str(): assert isinstance(get_pypi_repository().source_dir, str) @pytest.mark.skipif( parse_version(pip_version) >= parse_version('10.0.0'), reason="RequirementSet objects don't take arguments after pip 10." ) def test_pypirepo_calls_reqset_with_str_paths(): """ Make sure that paths passed to RequirementSet init are str. Passing unicode paths on Python 2 could make pip fail later on unpack, if the package contains non-ASCII file names, because non-ASCII str and unicode paths cannot be combined. """ with patch('piptools.repositories.pypi.RequirementSet') as mocked_init: repo = get_pypi_repository() ireq = InstallRequirement.from_line('ansible==2.4.0.0') # Setup a mock object to be returned from the RequirementSet call
def version(self): # type: () -> CandidateVersion if self._version is None: self._version = parse_version(self.dist.version) return self._version
def update(args=None): from pip.utils import (get_installed_version, dist_is_editable, dist_location) import platform import subprocess from subprocess import CalledProcessError dist = get_dist('topicexplorer') if dist_is_editable(dist): # pragma: no cover print( "You have an editable install, so updates will be pulled from git." ) print("Your install directory is: {}\n".format(dist.location)) for attempt in range(2): try: import git from git.exc import InvalidGitRepositoryError break except ImportError: install = input( "GitPython is required, but is not installed. Install? [Y/n] " ) if install == '' or install.lower()[0] == 'y': subprocess.check_call('pip install gitpython', shell=True) # TODO: Add error handling for failed gitpython install # Refresh local python path to reflect gitpython import site reload(site) # attempt import once again import git reload(git) from git.exc import InvalidGitRepositoryError else: print("GitPython is required to work with an editable install,") print("but it was not successfully installed.\n") return try: repo = git.Repo(dist.location) except InvalidGitRepositoryError: print( "pip has detected an editable install, but the install directory" ) print("is not a valid git repository.\n") return if repo.is_dirty(): print("There are uncommitted changes in your local repository.") print("Please commit before running `topicexplorer update`.\n") return if repo.active_branch != repo.heads.master: print("You are on the '{}' branch.".format(repo.active_branch), end=' ') install = input("Switch to the 'master' branch? [Y/n] ") if install == '' or install.lower()[0] == 'y': print("Switched to 'master' branch.") repo.heads.master.checkout() else: print( "You must switch to the 'master' branch to use `topicexplorer update`." ) return if not repo.bare: # check for upstream updates branch = repo.active_branch repo.remotes.origin.fetch(branch) commits_behind = list( repo.iter_commits( '{BRANCH}..origin/{BRANCH}'.format(BRANCH=branch.name))) commits_ahead = list( repo.iter_commits( 'origin/{BRANCH}..{BRANCH}'.format(BRANCH=branch.name))) if commits_behind: print("Your branch is {} commits behind GitHub.".format( len(commits_behind))) if platform.system() == 'Windows': # pragma: no cover import sys if sys.argv[0] != __file__: print( "Use the `python -m topicexplorer.update` command to update." ) return # TODO: remove process_exists('vsm.exe') on 1.0rc1 if process_exists('topicexplorer.exe') or process_exists( 'vsm.exe'): print("vsm is currently running,", end=' ') print("please close all Topic Explorers to update.") return print("Pulling changes.") repo.remotes.origin.pull() # reinstall, just in case dependencies or version have updated try: subprocess.check_call('python setup.py develop', cwd=dist.location, shell=True) except: print("ERROR: Update did not comlete installation.\n") else: print("Your local branch was updated.\n") elif commits_ahead: print("Your branch is {} commits ahead of GitHub.".format( len(commits_ahead))) push = input("Do you want to push? [Y/n] ") if push == '' or push.lower()[0] == 'y': repo.remotes.origin.push() else: print( "Your local branch is synced with GitHub. No updates available.\n" ) else: # TODO: Check if pre-release, if so, then continue beta updates. # If not, then wait for stable release. Allow for override flag. from pip._vendor.packaging.version import parse as parse_version installed_version = parse_version( get_installed_version('topicexplorer')) pypi_version = parse_version(pypi_versions('topicexplorer')[-1]) update_available = pypi_version > installed_version if update_available: if platform.system() == 'Windows': # pragma: no cover import sys if sys.argv[0] != __file__: print( "Update available. Use the `python -m topicexplorer.update`", end=' ') print("command to update.") return # TODO: remove process_exists('vsm.exe') on 1.0rc1 if process_exists('topicexplorer.exe') or process_exists( 'vsm.exe'): print( "topicexplorer is currently running, please close all Topic Explorers to update." ) return try: subprocess.check_call( 'pip install topicexplorer=={} --no-cache-dir'.format( pypi_version), shell=True) except CalledProcessError: print("ERROR: Update did not comlete installation.\n") else: print("Updated from {} to {}.\n".format( installed_version, pypi_version)) else: print("You have the most recent release. No updates available.\n")
def __init__(self, installer: str, version: str) -> None: self.installer = installer self.version = parse_version(version)
def resolve( self, root_reqs: List[InstallRequirement], check_supported_wheels: bool ) -> RequirementSet: collected = self.factory.collect_root_requirements(root_reqs) provider = PipProvider( factory=self.factory, constraints=collected.constraints, ignore_dependencies=self.ignore_dependencies, upgrade_strategy=self.upgrade_strategy, user_requested=collected.user_requested, ) if "PIP_RESOLVER_DEBUG" in os.environ: reporter: BaseReporter = PipDebuggingReporter() else: reporter = PipReporter() resolver: RLResolver[Requirement, Candidate, str] = RLResolver( provider, reporter, ) try: try_to_avoid_resolution_too_deep = 2000000 result = self._result = resolver.resolve( collected.requirements, max_rounds=try_to_avoid_resolution_too_deep ) except ResolutionImpossible as e: error = self.factory.get_installation_error( cast("ResolutionImpossible[Requirement, Candidate]", e), collected.constraints, ) raise error from e req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in result.mapping.values(): ireq = candidate.get_install_requirement() if ireq is None: continue # Check if there is already an installation under the same name, # and set a flag for later stages to uninstall it, if needed. installed_dist = self.factory.get_dist_to_uninstall(candidate) if installed_dist is None: # There is no existing installation -- nothing to uninstall. ireq.should_reinstall = False elif self.factory.force_reinstall: # The --force-reinstall flag is set -- reinstall. ireq.should_reinstall = True elif parse_version(installed_dist.version) != candidate.version: # The installation is different in version -- reinstall. ireq.should_reinstall = True elif candidate.is_editable or dist_is_editable(installed_dist): # The incoming distribution is editable, or different in # editable-ness to installation -- reinstall. ireq.should_reinstall = True elif candidate.source_link and candidate.source_link.is_file: # The incoming distribution is under file:// if candidate.source_link.is_wheel: # is a local wheel -- do nothing. logger.info( "%s is already installed with the same version as the " "provided wheel. Use --force-reinstall to force an " "installation of the wheel.", ireq.name, ) continue looks_like_sdist = ( is_archive_file(candidate.source_link.file_path) and candidate.source_link.ext != ".zip" ) if looks_like_sdist: # is a local sdist -- show a deprecation warning! reason = ( "Source distribution is being reinstalled despite an " "installed package having the same name and version as " "the installed package." ) replacement = "use --force-reinstall" deprecated( reason=reason, replacement=replacement, gone_in="21.2", issue=8711, ) # is a local sdist or path -- reinstall ireq.should_reinstall = True else: continue link = candidate.source_link if link and link.is_yanked: # The reason can contain non-ASCII characters, Unicode # is required for Python 2. msg = ( "The candidate selected for download or install is a " "yanked version: {name!r} candidate (version {version} " "at {link})\nReason for being yanked: {reason}" ).format( name=candidate.name, version=candidate.version, link=link, reason=link.yanked_reason or "<none given>", ) logger.warning(msg) req_set.add_named_requirement(ireq) reqs = req_set.all_requirements self.factory.preparer.prepare_linked_requirements_more(reqs) return req_set
def find_requirement(self, req, upgrade): # type: (InstallRequirement, bool) -> Optional[Link] """Try to find a Link matching req Expects req, an InstallRequirement and upgrade, a boolean Returns a Link if found, Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise """ candidates = self.find_candidates(req.name, req.specifier) best_candidate = candidates.get_best() installed_version = None # type: Optional[_BaseVersion] if req.satisfied_by is not None: installed_version = parse_version(req.satisfied_by.version) def _format_versions(cand_iter): # This repeated parse_version and str() conversion is needed to # handle different vendoring sources from pip and pkg_resources. # If we stop using the pkg_resources provided specifier and start # using our own, we can drop the cast to str(). return ", ".join( sorted( {str(c.version) for c in cand_iter}, key=parse_version, )) or "none" if installed_version is None and best_candidate is None: logger.critical( 'Could not find a version that satisfies the requirement %s ' '(from versions: %s)', req, _format_versions(candidates.iter_all()), ) raise DistributionNotFound( 'No matching distribution found for %s' % req) best_installed = False if installed_version and (best_candidate is None or best_candidate.version <= installed_version): best_installed = True if not upgrade and installed_version is not None: if best_installed: logger.debug( 'Existing installed version (%s) is most up-to-date and ' 'satisfies requirement', installed_version, ) else: logger.debug( 'Existing installed version (%s) satisfies requirement ' '(most up-to-date version is %s)', installed_version, best_candidate.version, ) return None if best_installed: # We have an existing version, and its the best version logger.debug( 'Installed version (%s) is most up-to-date (past versions: ' '%s)', installed_version, _format_versions(candidates.iter_applicable()), ) raise BestVersionAlreadyInstalled logger.debug( 'Using version %s (newest of versions: %s)', best_candidate.version, _format_versions(candidates.iter_applicable()), ) return best_candidate.location
def get_git_version(self): VERSION_PFX = 'git version ' <<<<<<< HEAD version = self.run_command(['version']) ======= version = self.run_command(['version'], show_stdout=False) >>>>>>> b66a76afa15ab74019740676a52a071b85ed8f71 if version.startswith(VERSION_PFX): version = version[len(VERSION_PFX):].split()[0] else: version = '' # get first 3 positions of the git version because # on windows it is x.y.z.windows.t, and this parses as # LegacyVersion which always smaller than a Version. version = '.'.join(version.split('.')[:3]) return parse_version(version) @classmethod def get_current_branch(cls, location): """ Return the current branch, or None if HEAD isn't at a branch (e.g. detached HEAD). """ # git-symbolic-ref exits with empty stdout if "HEAD" is a detached # HEAD rather than a symbolic ref. In addition, the -q causes the # command to exit with status code 1 instead of 128 in this case # and to suppress the message to stderr. args = ['symbolic-ref', '-q', 'HEAD'] output = cls.run_command( <<<<<<< HEAD args, extra_ok_returncodes=(1, ), cwd=location,
class InstallationCandidate(KeyBasedCompareMixin): """Represents a potential "candidate" for installation. """ <<<<<<< HEAD def __init__(self, project, version, link): # type: (Any, str, Link) -> None self.project = project ======= def __init__(self, name, version, link): # type: (str, str, Link) -> None self.name = name >>>>>>> e585743114c1741ec20dc76010f96171f3516589 self.version = parse_version(version) # type: _BaseVersion self.link = link super(InstallationCandidate, self).__init__( <<<<<<< HEAD key=(self.project, self.version, self.link), ======= key=(self.name, self.version, self.link), >>>>>>> e585743114c1741ec20dc76010f96171f3516589 defining_class=InstallationCandidate ) def __repr__(self): # type: () -> str return "<InstallationCandidate({!r}, {!r}, {!r})>".format( <<<<<<< HEAD
def pip_self_version_check(session, options): # type: (PipSession, optparse.Values) -> None """Check for an update for pip. Limit the frequency of checks to once per week. State is stored either in the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix of the pip script path. """ installed_dist = get_default_environment().get_distribution("pip") if not installed_dist: return pip_version = installed_dist.version pypi_version = None try: state = SelfCheckState(cache_dir=options.cache_dir) current_time = datetime.datetime.utcnow() # Determine if we need to refresh the state if "last_check" in state.state and "pypi_version" in state.state: last_check = datetime.datetime.strptime(state.state["last_check"], SELFCHECK_DATE_FMT) if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60: pypi_version = state.state["pypi_version"] # Refresh the version if we need to or just see if we need to warn if pypi_version is None: # Lets use PackageFinder to see what the latest pip version is link_collector = LinkCollector.create( session, options=options, suppress_no_index=True, ) # Pass allow_yanked=False so we don't suggest upgrading to a # yanked version. selection_prefs = SelectionPreferences( allow_yanked=False, allow_all_prereleases=False, # Explicitly set to False ) finder = PackageFinder.create( link_collector=link_collector, selection_prefs=selection_prefs, ) best_candidate = finder.find_best_candidate("pip").best_candidate if best_candidate is None: return pypi_version = str(best_candidate.version) # save that we've performed a check state.save(pypi_version, current_time) remote_version = parse_version(pypi_version) local_version_is_older = ( pip_version < remote_version and pip_version.base_version != remote_version.base_version and was_installed_by_pip('pip')) # Determine if our pypi_version is older if not local_version_is_older: return # We cannot tell how the current pip is available in the current # command context, so be pragmatic here and suggest the command # that's always available. This does not accommodate spaces in # `sys.executable`. pip_cmd = f"{sys.executable} -m pip" logger.warning( "You are using pip version %s; however, version %s is " "available.\nYou should consider upgrading via the " "'%s install --upgrade pip' command.", pip_version, pypi_version, pip_cmd) except Exception: logger.debug( "There was an error checking the latest version of pip", exc_info=True, )
def update(args=None): try: from pip._internal.utils.misc import (get_installed_version, dist_is_editable, dist_location) except ImportError: from pip.utils import (get_installed_version, dist_is_editable, dist_location) import platform import subprocess from subprocess import CalledProcessError dist = get_dist('topicexplorer') if dist_is_editable(dist): # pragma: no cover print("You have an editable install, so updates will be pulled from git.") print("Your install directory is: {}\n".format(dist.location)) for attempt in range(2): try: import git from git.exc import InvalidGitRepositoryError break except ImportError: install = input( "GitPython is required, but is not installed. Install? [Y/n] ") if install == '' or install.lower()[0] == 'y': subprocess.check_call('pip install gitpython', shell=True) # TODO: Add error handling for failed gitpython install # Refresh local python path to reflect gitpython import site reload(site) # attempt import once again import git reload(git) from git.exc import InvalidGitRepositoryError else: print("GitPython is required to work with an editable install,") print("but it was not successfully installed.\n") return try: repo = git.Repo(dist.location) except InvalidGitRepositoryError: print("pip has detected an editable install, but the install directory") print("is not a valid git repository.\n") return if repo.is_dirty(): print("There are uncommitted changes in your local repository.") print("Please commit before running `topicexplorer update`.\n") return if repo.active_branch != repo.heads.master: print("You are on the '{}' branch.".format(repo.active_branch), end=' ') install = input("Switch to the 'master' branch? [Y/n] ") if install == '' or install.lower()[0] == 'y': print("Switched to 'master' branch.") repo.heads.master.checkout() else: print("You must switch to the 'master' branch to use `topicexplorer update`.") return if not repo.bare: # check for upstream updates branch = repo.active_branch repo.remotes.origin.fetch(branch) commits_behind = list(repo.iter_commits( '{BRANCH}..origin/{BRANCH}'.format(BRANCH=branch.name))) commits_ahead = list(repo.iter_commits( 'origin/{BRANCH}..{BRANCH}'.format(BRANCH=branch.name))) if commits_behind: print("Your branch is {} commits behind GitHub.".format(len(commits_behind))) if platform.system() == 'Windows': # pragma: no cover import sys if sys.argv[0] != __file__: print("Use the `python -m topicexplorer.update` command to update.") return # TODO: remove process_exists('vsm.exe') on 1.0rc1 if process_exists('topicexplorer.exe') or process_exists('vsm.exe'): print("vsm is currently running,", end=' ') print("please close all Topic Explorers to update.") return print("Pulling changes.") repo.remotes.origin.pull() # reinstall, just in case dependencies or version have updated try: subprocess.check_call('python setup.py develop', cwd=dist.location, shell=True) except: print("ERROR: Update did not comlete installation.\n") else: print("Your local branch was updated.\n") elif commits_ahead: print("Your branch is {} commits ahead of GitHub.".format(len(commits_ahead))) push = input("Do you want to push? [Y/n] ") if push == '' or push.lower()[0] == 'y': repo.remotes.origin.push() else: print("Your local branch is synced with GitHub. No updates available.\n") else: # TODO: Check if pre-release, if so, then continue beta updates. # If not, then wait for stable release. Allow for override flag. from pip._vendor.packaging.version import parse as parse_version installed_version = parse_version(get_installed_version('topicexplorer')) pypi_version = parse_version(pypi_versions('topicexplorer')[-1]) update_available = pypi_version > installed_version if update_available: if platform.system() == 'Windows': # pragma: no cover import sys if sys.argv[0] != __file__: print("Update available. Use the `python -m topicexplorer.update`", end=' ') print("command to update.") return # TODO: remove process_exists('vsm.exe') on 1.0rc1 if process_exists('topicexplorer.exe') or process_exists('vsm.exe'): print("topicexplorer is currently running, please close all Topic Explorers to update.") return try: subprocess.check_call( 'pip install topicexplorer=={} --no-cache-dir'.format(pypi_version), shell=True) except CalledProcessError: print("ERROR: Update did not comlete installation.\n") else: print("Updated from {} to {}.\n".format(installed_version, pypi_version)) else: print("You have the most recent release. No updates available.\n")
def find_requirement(self, req, upgrade): # type: (InstallRequirement, bool) -> Optional[Link] """Try to find a Link matching req Expects req, an InstallRequirement and upgrade, a boolean Returns a Link if found, Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise """ hashes = req.hashes(trust_internet=False) best_candidate_result = self.find_best_candidate( req.name, specifier=req.specifier, hashes=hashes, ) best_candidate = best_candidate_result.best_candidate installed_version = None # type: Optional[_BaseVersion] if req.satisfied_by is not None: installed_version = parse_version(req.satisfied_by.version) def _format_versions(cand_iter): # type: (Iterable[InstallationCandidate]) -> str # This repeated parse_version and str() conversion is needed to # handle different vendoring sources from pip and pkg_resources. # If we stop using the pkg_resources provided specifier and start # using our own, we can drop the cast to str(). return (", ".join( sorted( {str(c.version) for c in cand_iter}, key=parse_version, )) or "none") if installed_version is None and best_candidate is None: logger.critical( "Could not find a version that satisfies the requirement %s " "(from versions: %s)", req, _format_versions(best_candidate_result.iter_all()), ) raise DistributionNotFound( "No matching distribution found for {}".format(req)) best_installed = False if installed_version and (best_candidate is None or best_candidate.version <= installed_version): best_installed = True if not upgrade and installed_version is not None: if best_installed: logger.debug( "Existing installed version (%s) is most up-to-date and " "satisfies requirement", installed_version, ) else: logger.debug( "Existing installed version (%s) satisfies requirement " "(most up-to-date version is %s)", installed_version, best_candidate.version, ) return None if best_installed: # We have an existing version, and its the best version logger.debug( "Installed version (%s) is most up-to-date (past versions: " "%s)", installed_version, _format_versions(best_candidate_result.iter_applicable()), ) raise BestVersionAlreadyInstalled logger.debug( "Using version %s (newest of versions: %s)", best_candidate.version, _format_versions(best_candidate_result.iter_applicable()), ) return best_candidate.link
def version(self): # type: () -> _BaseVersion return parse_version(self._dist.version)
def __init__(self, project, version, location): self.project = project self.version = parse_version(version) self.location = location self._key = (self.project, self.version, self.location)
import sys from textwrap import dedent import mock import pytest from click.testing import CliRunner from pip import __version__ as pip_version from pip._vendor.packaging.version import parse as parse_version from .utils import invoke from piptools._compat.pip_compat import path_to_url from piptools.repositories import PyPIRepository from piptools.scripts.compile import cli PIP_VERSION = parse_version(os.environ.get("PIP", pip_version)) TEST_DATA_PATH = os.path.join(os.path.split(__file__)[0], "test_data") fail_below_pip9 = pytest.mark.xfail( PIP_VERSION < parse_version("9"), reason="needs pip 9 or greater" ) @pytest.fixture def pip_conf(tmpdir, monkeypatch): test_conf = dedent( """\ [global] index-url = http://example.com trusted-host = example.com """
def find_requirement(self, req, upgrade): """Try to find a Link matching req Expects req, an InstallRequirement and upgrade, a boolean Returns a Link if found, Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise """ all_candidates = self.find_all_candidates(req.name) # Filter out anything which doesn't match our specifier compatible_versions = set( req.specifier.filter( # We turn the version object into a str here because otherwise # when we're debundled but setuptools isn't, Python will see # packaging.version.Version and # pkg_resources._vendor.packaging.version.Version as different # types. This way we'll use a str as a common data interchange # format. If we stop using the pkg_resources provided specifier # and start using our own, we can drop the cast to str(). [str(c.version) for c in all_candidates], prereleases=(self.allow_all_prereleases if self.allow_all_prereleases else None), )) applicable_candidates = [ # Again, converting to str to deal with debundling. c for c in all_candidates if str(c.version) in compatible_versions ] if applicable_candidates: best_candidate = max(applicable_candidates, key=self._candidate_sort_key) else: best_candidate = None if req.satisfied_by is not None: installed_version = parse_version(req.satisfied_by.version) else: installed_version = None if installed_version is None and best_candidate is None: logger.critical( 'Could not find a version that satisfies the requirement %s ' '(from versions: %s)', req, ', '.join( sorted( set(str(c.version) for c in all_candidates), key=parse_version, ))) raise DistributionNotFound( 'No matching distribution found for %s' % req) best_installed = False if installed_version and (best_candidate is None or best_candidate.version <= installed_version): best_installed = True if not upgrade and installed_version is not None: if best_installed: logger.debug( 'Existing installed version (%s) is most up-to-date and ' 'satisfies requirement', installed_version, ) else: logger.debug( 'Existing installed version (%s) satisfies requirement ' '(most up-to-date version is %s)', installed_version, best_candidate.version, ) return None if best_installed: # We have an existing version, and its the best version logger.debug( 'Installed version (%s) is most up-to-date (past versions: ' '%s)', installed_version, ', '.join(sorted(compatible_versions, key=parse_version)) or "none", ) raise BestVersionAlreadyInstalled logger.debug('Using version %s (newest of versions: %s)', best_candidate.version, ', '.join(sorted(compatible_versions, key=parse_version))) return best_candidate.location
def move_to_correct_build_directory(self): # type: () -> None """Move self._temp_build_dir to "self._ideal_build_dir/{metadata name}" For some requirements (e.g. a path to a directory), the name of the package is not available until we run egg_info, so the build_location will return a temporary directory and store the _ideal_build_dir. This is only called to "fix" the build directory after generating metadata. """ assert self.req is None assert self.metadata is not None # Construct a Requirement object from the generated metadata if isinstance(parse_version(self.metadata["Version"]), Version): op = "==" else: op = "===" self.req = Requirement("".join([ self.metadata["Name"], op, self.metadata["Version"], ])) if self.source_dir is not None: return assert self._temp_build_dir assert (self._ideal_build_dir is not None and self._ideal_build_dir.path # type: ignore ) # Backup directory for later use. old_location = self._temp_build_dir self._temp_build_dir = None # checked inside ensure_build_location # Figure out the correct place to put the files. new_location = self.ensure_build_location(self._ideal_build_dir) if os.path.exists(new_location): raise InstallationError( 'A package already exists in %s; please remove it to continue' % display_path(new_location)) # Move the files to the correct location. logger.debug( 'Moving package %s from %s to new location %s', self, display_path(old_location.path), display_path(new_location), ) shutil.move(old_location.path, new_location) # Update directory-tracking variables, to be in line with new_location self.source_dir = os.path.normpath(os.path.abspath(new_location)) self._temp_build_dir = TempDirectory( path=new_location, kind="req-install", ) # Correct the metadata directory old_meta = self.metadata_directory rel = os.path.relpath(old_meta, start=old_location.path) new_meta = os.path.join(new_location, rel) new_meta = os.path.normpath(os.path.abspath(new_meta)) self.metadata_directory = new_meta # Done with any "move built files" work, since have moved files to the # "ideal" build location. Setting to None allows to clearly flag that # no more moves are needed. self._ideal_build_dir = None
import subprocess import sys import mock from click.testing import CliRunner import pytest from piptools.repositories import PyPIRepository from piptools.scripts.compile import cli from piptools.scripts.sync import cli as sync_cli from pip._vendor.packaging.version import parse as parse_version from pip import __version__ as pip_version PIP_VERSION = parse_version(os.environ.get('PIP', pip_version)) fail_below_pip9 = pytest.mark.xfail( PIP_VERSION < parse_version('9'), reason="needs pip 9 or greater" ) @pytest.yield_fixture def pip_conf(tmpdir): test_conf = dedent("""\ [global] index-url = http://example.com trusted-host = example.com """)
def find_requirement(self, req, upgrade): # type: (InstallRequirement, bool) -> Optional[Link] """Try to find a Link matching req Expects req, an InstallRequirement and upgrade, a boolean Returns a Link if found, Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise """ candidates = self.find_candidates(req.name, req.specifier) best_candidate = candidates.get_best() installed_version = None # type: Optional[_BaseVersion] if req.satisfied_by is not None: installed_version = parse_version(req.satisfied_by.version) def _format_versions(cand_iter): # This repeated parse_version and str() conversion is needed to # handle different vendoring sources from pip and pkg_resources. # If we stop using the pkg_resources provided specifier and start # using our own, we can drop the cast to str(). return ", ".join(sorted( {str(c.version) for c in cand_iter}, key=parse_version, )) or "none" if installed_version is None and best_candidate is None: logger.critical( 'Could not find a version that satisfies the requirement %s ' '(from versions: %s)', req, _format_versions(candidates.iter_all()), ) raise DistributionNotFound( 'No matching distribution found for %s' % req ) best_installed = False if installed_version and ( best_candidate is None or best_candidate.version <= installed_version): best_installed = True if not upgrade and installed_version is not None: if best_installed: logger.debug( 'Existing installed version (%s) is most up-to-date and ' 'satisfies requirement', installed_version, ) else: logger.debug( 'Existing installed version (%s) satisfies requirement ' '(most up-to-date version is %s)', installed_version, best_candidate.version, ) return None if best_installed: # We have an existing version, and its the best version logger.debug( 'Installed version (%s) is most up-to-date (past versions: ' '%s)', installed_version, _format_versions(candidates.iter_applicable()), ) raise BestVersionAlreadyInstalled logger.debug( 'Using version %s (newest of versions: %s)', best_candidate.version, _format_versions(candidates.iter_applicable()), ) return best_candidate.location
import optparse from typing import Iterator, Optional import pip from pip._internal.index.package_finder import PackageFinder from pip._internal.network.session import PipSession from pip._internal.req import InstallRequirement from pip._internal.req import parse_requirements as _parse_requirements from pip._internal.req.constructors import install_req_from_parsed_requirement from pip._vendor.packaging.version import parse as parse_version PIP_VERSION = tuple( map(int, parse_version(pip.__version__).base_version.split("."))) def parse_requirements( filename: str, session: PipSession, finder: Optional[PackageFinder] = None, options: Optional[optparse.Values] = None, constraint: bool = False, isolated: bool = False, ) -> Iterator[InstallRequirement]: for parsed_req in _parse_requirements(filename, session, finder=finder, options=options, constraint=constraint): yield install_req_from_parsed_requirement(parsed_req, isolated=isolated)
from textwrap import dedent import mock import pytest from click.testing import CliRunner from pip import __version__ as pip_version from pip._vendor.packaging.version import parse as parse_version from pytest import mark from .utils import invoke from piptools._compat.pip_compat import path_to_url from piptools.repositories import PyPIRepository from piptools.scripts.compile import cli PIP_VERSION = parse_version(os.environ.get("PIP", pip_version)) TEST_DATA_PATH = os.path.join(os.path.split(__file__)[0], "test_data") MINIMAL_WHEELS_PATH = os.path.join(TEST_DATA_PATH, "minimal_wheels") fail_below_pip9 = pytest.mark.xfail( PIP_VERSION < parse_version("9"), reason="needs pip 9 or greater" ) @pytest.fixture def pip_conf(tmpdir, monkeypatch): test_conf = dedent( """\ [global] index-url = http://example.com trusted-host = example.com
def version(self) -> DistributionVersion: return parse_version(self._dist.version)
def version(self): # type: () -> DistributionVersion return parse_version(self._dist.version)
from piptools.repositories.pypi import PyPIRepository from piptools.scripts.compile import get_pip_command import pytest def test_pypirepo_build_dir_is_str(): assert isinstance(get_pypi_repository().build_dir, str) def test_pypirepo_source_dir_is_str(): assert isinstance(get_pypi_repository().source_dir, str) @pytest.mark.skipif( parse_version(pip_version) >= parse_version('10.0.0'), reason="RequirementSet objects don't take arguments after pip 10." ) def test_pypirepo_calls_reqset_with_str_paths(): """ Make sure that paths passed to RequirementSet init are str. Passing unicode paths on Python 2 could make pip fail later on unpack, if the package contains non-ASCII file names, because non-ASCII str and unicode paths cannot be combined. """ with patch('piptools.repositories.pypi.RequirementSet') as mocked_init: repo = get_pypi_repository() ireq = install_req_from_line('ansible==2.4.0.0') # Setup a mock object to be returned from the RequirementSet call