From e2b38d274131c901d51b2358c3a6f2faf6236a77 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Sat, 6 Jul 2019 03:26:51 -0400 Subject: [PATCH] Update pythonfinder Signed-off-by: Dan Ryan --- pipenv/vendor/pythonfinder/__init__.py | 2 +- .../_vendor/pep514tools/environment.py | 3 +- pipenv/vendor/pythonfinder/models/path.py | 4 +- pipenv/vendor/pythonfinder/models/python.py | 37 ++++++++++++++----- pipenv/vendor/pythonfinder/models/windows.py | 11 ++++-- pipenv/vendor/pythonfinder/utils.py | 34 +++++++++++++++++ 6 files changed, 74 insertions(+), 17 deletions(-) diff --git a/pipenv/vendor/pythonfinder/__init__.py b/pipenv/vendor/pythonfinder/__init__.py index d1f70c3b..428599bd 100644 --- a/pipenv/vendor/pythonfinder/__init__.py +++ b/pipenv/vendor/pythonfinder/__init__.py @@ -10,7 +10,7 @@ from .exceptions import InvalidPythonVersion from .models import SystemPath, WindowsFinder from .pythonfinder import Finder -__version__ = "1.2.1" +__version__ = "1.2.2.dev0" logger = logging.getLogger(__name__) diff --git a/pipenv/vendor/pythonfinder/_vendor/pep514tools/environment.py b/pipenv/vendor/pythonfinder/_vendor/pep514tools/environment.py index 2c09ccbc..e201d0b5 100644 --- a/pipenv/vendor/pythonfinder/_vendor/pep514tools/environment.py +++ b/pipenv/vendor/pythonfinder/_vendor/pep514tools/environment.py @@ -15,7 +15,8 @@ import sys # These tags are treated specially when the Company is 'PythonCore' _PYTHONCORE_COMPATIBILITY_TAGS = { '2.0', '2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', - '3.0', '3.1', '3.2', '3.3', '3.4' + '3.0', '3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.7', + '3.8' } _IS_64BIT_OS = None diff --git a/pipenv/vendor/pythonfinder/models/path.py b/pipenv/vendor/pythonfinder/models/path.py index 34559f7d..b3b8d712 100644 --- a/pipenv/vendor/pythonfinder/models/path.py +++ b/pipenv/vendor/pythonfinder/models/path.py @@ -14,8 +14,6 @@ from cached_property import cached_property from vistir.compat import Path, fs_str from vistir.misc import dedup -from .mixins import BaseFinder, BasePath -from .python import PythonVersion from ..environment import ( ASDF_DATA_DIR, ASDF_INSTALLED, @@ -42,6 +40,8 @@ from ..utils import ( split_version_and_name, unnest, ) +from .mixins import BaseFinder, BasePath +from .python import PythonVersion if MYPY_RUNNING: from typing import ( diff --git a/pipenv/vendor/pythonfinder/models/python.py b/pipenv/vendor/pythonfinder/models/python.py index 8e5eecd6..49fce709 100644 --- a/pipenv/vendor/pythonfinder/models/python.py +++ b/pipenv/vendor/pythonfinder/models/python.py @@ -13,7 +13,6 @@ import six from packaging.version import Version from vistir.compat import Path, lru_cache -from .mixins import BaseFinder, BasePath from ..environment import ASDF_DATA_DIR, MYPY_RUNNING, PYENV_ROOT, SYSTEM_ARCH from ..exceptions import InvalidPythonVersion from ..utils import ( @@ -21,14 +20,17 @@ from ..utils import ( _filter_none, ensure_path, get_python_version, + guess_company, is_in_path, looks_like_python, optional_instance_of, parse_asdf_version_order, parse_pyenv_version_order, parse_python_version, + path_is_pythoncore, unnest, ) +from .mixins import BaseFinder, BasePath if MYPY_RUNNING: from typing import ( @@ -114,7 +116,8 @@ class PythonFinder(BaseFinder, BasePath): versions[v] for v in parse_asdf_version_order() if v in versions ] for version in version_order: - version_paths.remove(version) + if version in version_paths: + version_paths.remove(version) if version_order: version_order += version_paths else: @@ -351,6 +354,7 @@ class PythonVersion(object): architecture = attr.ib(default=None) # type: Optional[str] comes_from = attr.ib(default=None) # type: Optional[PathEntry] executable = attr.ib(default=None) # type: Optional[str] + company = attr.ib(default="PythonCore") # type: Optional[str] name = attr.ib(default=None, type=str) def __getattribute__(self, key): @@ -381,11 +385,14 @@ class PythonVersion(object): """ A tuple for sorting against other instances of the same class. - Returns a tuple of the python version but includes a point for non-dev, - and a point for non-prerelease versions. So released versions will have 2 points - for this value. E.g. `(3, 6, 6, 2)` is a release, `(3, 6, 6, 1)` is a prerelease, - `(3, 6, 6, 0)` is a dev release, and `(3, 6, 6, 3)` is a postrelease. + Returns a tuple of the python version but includes points for core python, + non-dev, and non-prerelease versions. So released versions will have 2 points + for this value. E.g. ``(1, 3, 6, 6, 2)`` is a release, ``(1, 3, 6, 6, 1)`` is a + prerelease, ``(1, 3, 6, 6, 0)`` is a dev release, and ``(1, 3, 6, 6, 3)`` is a + postrelease. ``(0, 3, 7, 3, 2)`` represents a non-core python release, e.g. by + a repackager of python like Continuum. """ + company_sort = 1 if self.company == "PythonCore" else 0 release_sort = 2 if self.is_postrelease: release_sort = 3 @@ -395,7 +402,13 @@ class PythonVersion(object): release_sort = 0 elif self.is_debug: release_sort = 1 - return (self.major, self.minor, self.patch if self.patch else 0, release_sort) + return ( + company_sort, + self.major, + self.minor, + self.patch if self.patch else 0, + release_sort, + ) @property def version_tuple(self): @@ -473,6 +486,7 @@ class PythonVersion(object): "is_devrelease": self.is_devrelease, "is_debug": self.is_debug, "version": self.version, + "company": self.company, } def update_metadata(self, metadata): @@ -532,8 +546,8 @@ class PythonVersion(object): return self.architecture @classmethod - def from_path(cls, path, name=None, ignore_unsupported=True): - # type: (Union[str, PathEntry], Optional[str], bool) -> PythonVersion + def from_path(cls, path, name=None, ignore_unsupported=True, company=None): + # type: (Union[str, PathEntry], Optional[str], bool, Optional[str]) -> PythonVersion """ Parses a python version from a system path. @@ -544,6 +558,7 @@ class PythonVersion(object): :type path: str or :class:`~pythonfinder.models.path.PathEntry` instance :param str name: Name of the python distribution in question :param bool ignore_unsupported: Whether to ignore or error on unsupported paths. + :param Optional[str] company: The company or vendor packaging the distribution. :return: An instance of a PythonVersion. :rtype: :class:`~pythonfinder.models.python.PythonVersion` """ @@ -576,6 +591,8 @@ class PythonVersion(object): instance_dict = cls.parse_executable(path.path.absolute().as_posix()) if name is None: name = path_name + if company is None: + company = guess_company(path.path.as_posix()) instance_dict.update( {"comes_from": path, "name": name, "executable": path.path.as_posix()} ) @@ -622,6 +639,7 @@ class PythonVersion(object): exe_path = ensure_path( getattr(launcher_entry.info.install_path, "executable_path", default_path) ) + company = getattr(launcher_entry, "company", "PythonCore") creation_dict.update( { "architecture": getattr( @@ -629,6 +647,7 @@ class PythonVersion(object): ), "executable": exe_path, "name": name, + "company": company, } ) py_version = cls.create(**creation_dict) diff --git a/pipenv/vendor/pythonfinder/models/windows.py b/pipenv/vendor/pythonfinder/models/windows.py index e96e1081..92da74c5 100644 --- a/pipenv/vendor/pythonfinder/models/windows.py +++ b/pipenv/vendor/pythonfinder/models/windows.py @@ -6,12 +6,12 @@ from collections import defaultdict import attr -from .mixins import BaseFinder -from .path import PathEntry -from .python import PythonVersion, VersionMap from ..environment import MYPY_RUNNING from ..exceptions import InvalidPythonVersion from ..utils import ensure_path +from .mixins import BaseFinder +from .path import PathEntry +from .python import PythonVersion, VersionMap if MYPY_RUNNING: from typing import DefaultDict, Tuple, List, Optional, Union, TypeVar, Type, Any @@ -81,6 +81,7 @@ class WindowsFinder(BaseFinder): path = None for version_object in env_versions: install_path = getattr(version_object.info, "install_path", None) + name = getattr(version_object, "tag", None) if install_path is None: continue try: @@ -88,7 +89,9 @@ class WindowsFinder(BaseFinder): except AttributeError: continue try: - py_version = PythonVersion.from_windows_launcher(version_object) + py_version = PythonVersion.from_windows_launcher( + version_object, name=name + ) except InvalidPythonVersion: continue if py_version is None: diff --git a/pipenv/vendor/pythonfinder/utils.py b/pipenv/vendor/pythonfinder/utils.py index bbab5381..477f3668 100644 --- a/pipenv/vendor/pythonfinder/utils.py +++ b/pipenv/vendor/pythonfinder/utils.py @@ -239,6 +239,40 @@ def path_is_python(path): return path_is_executable(path) and looks_like_python(path.name) +@lru_cache(maxsize=1024) +def guess_company(path): + # type: (str) -> Optional[str] + """Given a path to python, guess the company who created it + + :param str path: The path to guess about + :return: The guessed company + :rtype: Optional[str] + """ + non_core_pythons = [impl for impl in PYTHON_IMPLEMENTATIONS if impl != "python"] + return next( + iter(impl for impl in non_core_pythons if impl in path.lower()), "PythonCore" + ) + + +@lru_cache(maxsize=1024) +def path_is_pythoncore(path): + # type: (str) -> bool + """Given a path, determine whether it appears to be pythoncore. + + Does not verify whether the path is in fact a path to python, but simply + does an exclusionary check on the possible known python implementations + to see if their names are present in the path (fairly dumb check). + + :param str path: The path to check + :return: Whether that path is a PythonCore path or not + :rtype: bool + """ + company = guess_company(path) + if company: + return company == "PythonCore" + return False + + @lru_cache(maxsize=1024) def ensure_path(path): # type: (Union[vistir.compat.Path, str]) -> vistir.compat.Path