Upgrade vendored pythonfinder

Now at commit 6ad2bbd8bdc2, around 0.1.4.
This commit is contained in:
Tzu-ping Chung
2018-07-10 14:45:28 +08:00
parent 040b535fd6
commit 6ee13ebaae
13 changed files with 156 additions and 53 deletions
+3 -2
View File
@@ -1,7 +1,8 @@
from __future__ import print_function, absolute_import
__version__ = "0.1.2"
__version__ = "0.1.4.dev0"
__all__ = ["Finder", "WindowsFinder", "SystemPath"]
__all__ = ["Finder", "WindowsFinder", "SystemPath", "InvalidPythonVersion"]
from .pythonfinder import Finder
from .models import SystemPath, WindowsFinder
from .exceptions import InvalidPythonVersion
+14
View File
@@ -0,0 +1,14 @@
# Taken from pip: https://github.com/pypa/pip/blob/95bcf8c5f6394298035a7332c441868f3b0169f4/src/pip/_vendor/Makefile
all: clean vendor
clean:
@# Delete vendored items
find . -maxdepth 1 -mindepth 1 -type d -exec rm -rf {} \;
vendor:
@# Install vendored libraries
pip install -t . -r vendor.txt
@# Cleanup .egg-info directories
rm -rf *.egg-info
rm -rf *.dist-info
+1
View File
@@ -0,0 +1 @@
-e git+https://github.com/zooba/pep514tools.git@320e48745660b696e2dcaee888fc2e516b435e48#egg=pep514tools
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import click
import crayons
import sys
+1
View File
@@ -1,4 +1,5 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import os
import platform
import sys
+7
View File
@@ -0,0 +1,7 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
class InvalidPythonVersion(Exception):
"""Raised when parsing an invalid python version"""
pass
+11 -13
View File
@@ -1,4 +1,5 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import abc
import operator
import six
@@ -33,16 +34,13 @@ class BasePath(object):
:returns: :class:`~pythonfinder.models.PathEntry` instance.
"""
valid_names = [
valid_names = [name] + [
"{0}.{1}".format(name, ext).lower() if ext else "{0}".format(name).lower()
for ext in KNOWN_EXTS
]
finder = filter(operator.attrgetter("is_executable"), self.children.values())
name_getter = operator.attrgetter("path.name")
return next(
(child for child in finder if name_getter(child).lower() in valid_names),
None,
)
children = self.children
found = next((children[(self.path / child).as_posix()] for child in valid_names if (self.path / child).as_posix() in children), None)
return found
def find_python_version(self, major, minor=None, patch=None, pre=None, dev=None):
"""Search or self for the specified Python version and return the first match.
@@ -62,16 +60,16 @@ class BasePath(object):
is_py = operator.attrgetter("is_python")
py_version = operator.attrgetter("as_python")
if not self.is_dir:
if self.is_python:
return self if version_matcher(self.as_python) else None
if self.is_python and self.as_python.matches(major, minor=minor, patch=patch, pre=pre, dev=dev):
return self
return
finder = (c for c in self.children.values() if is_py(c) and py_version(c))
finder = ((child, child.as_python) for child in self.children.values() if child.is_python and child.as_python)
py_filter = filter(
None, filter(lambda c: version_matcher(py_version(c)), finder)
None, filter(lambda child: version_matcher(child[1]), finder)
)
version_sort = operator.attrgetter("py_version.version")
version_sort = operator.attrgetter("version")
return next(
(c for c in sorted(py_filter, key=version_sort, reverse=True)), None
(c[0] for c in sorted(py_filter, key=lambda child: child[1].version, reverse=True)), None
)
+64 -20
View File
@@ -1,4 +1,5 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import attr
import operator
import os
@@ -7,12 +8,14 @@ from collections import defaultdict
from . import BasePath
from .python import PythonVersion
from ..environment import PYENV_INSTALLED, PYENV_ROOT
from ..exceptions import InvalidPythonVersion
from ..utils import (
optional_instance_of,
filter_pythons,
path_is_known_executable,
is_python_name,
ensure_path,
fs_str
)
try:
@@ -50,7 +53,7 @@ class SystemPath(object):
for p in self.python_executables:
try:
version_object = PythonVersion.from_path(p)
except ValueError:
except (ValueError, InvalidPythonVersion):
continue
version_dict[version_object.version_tuple].append(version_object)
return version_dict
@@ -64,11 +67,11 @@ class SystemPath(object):
if PYENV_INSTALLED:
self._setup_pyenv()
venv = os.environ.get('VIRTUAL_ENV')
if os.name == 'nt':
bin_dir = 'Scripts'
else:
bin_dir = 'bin'
if venv:
if os.name == 'nt':
bin_dir = 'Scripts'
else:
bin_dir = 'bin'
p = Path(venv)
self.path_order = [(p / bin_dir).as_posix()] + self.path_order
self.paths[p] = PathEntry.create(
@@ -76,9 +79,12 @@ class SystemPath(object):
)
if self.system:
syspath = Path(sys.executable)
self.path_order = [syspath.parent.as_posix()] + self.path_order
self.paths[syspath.parent.as_posix()] = PathEntry.create(
path=syspath.parent, is_root=True, only_python=True
syspath_bin = syspath.parent
if syspath_bin.name != bin_dir and syspath_bin.joinpath(bin_dir).exists():
syspath_bin = syspath_bin / bin_dir
self.path_order = [syspath_bin.as_posix()] + self.path_order
self.paths[syspath_bin.as_posix()] = PathEntry.create(
path=syspath_bin, is_root=True, only_python=False
)
def _setup_pyenv(self):
@@ -111,12 +117,24 @@ class SystemPath(object):
self.paths.update({p.path: p for p in root_paths})
def get_path(self, path):
_path = self.paths.get(path)
if not _path and path in self.path_order:
self.paths[path] = PathEntry.create(
path=path, is_root=True, only_python=self.only_python
path = Path(path)
_path = self.paths.get(path.as_posix())
if not _path and path.as_posix() in self.path_order:
self.paths[path.as_posix()] = PathEntry.create(
path=path.resolve(), is_root=True, only_python=self.only_python
)
return self.paths.get(path)
return self.paths.get(path.as_posix())
def find_all(self, executable):
"""Search the path for an executable. Return all copies.
:param executable: Name of the executable
:type executable: str
:returns: List[PathEntry]
"""
sub_which = operator.methodcaller("which", name=executable)
filtered = filter(None, (sub_which(self.get_path(k)) for k in self.path_order))
return [f for f in filtered]
def which(self, executable):
"""Search for an executable on the path.
@@ -126,9 +144,33 @@ class SystemPath(object):
:returns: :class:`~pythonfinder.models.PathEntry` object.
"""
sub_which = operator.methodcaller("which", name=executable)
return next(
(sub_which(self.get_path(k)) for k in self.path_order), None
filtered = filter(None, (sub_which(self.get_path(k)) for k in self.path_order))
return next((f for f in filtered), None)
def find_all_python_versions(self, major, minor=None, patch=None, pre=None, dev=None):
"""Search for a specific python version on the path. Return all copies
:param major: Major python version to search for.
:type major: int
:param minor: Minor python version to search for, defaults to None
:param minor: int, optional
:param path: Patch python version to search for, defaults to None
:param path: int, optional
:return: A list of :class:`~pythonfinder.models.PathEntry` instances matching the version requested.
:rtype: List[:class:`~pythonfinder.models.PathEntry`]
"""
sub_finder = operator.methodcaller(
"find_python_version", major, minor=minor, patch=patch, pre=pre, dev=dev
)
if os.name == "nt" and self.windows_finder:
windows_finder_version = sub_finder(self.windows_finder)
if windows_finder_version:
return windows_finder_version
paths = (self.get_path(k) for k in self.path_order)
path_filter = filter(None, (sub_finder(p) for p in paths if p is not None))
version_sort = operator.attrgetter("as_python.version")
return [c for c in sorted(path_filter, key=version_sort, reverse=True)]
def find_python_version(self, major, minor=None, patch=None, pre=None, dev=None):
"""Search for a specific python version on the path.
@@ -150,8 +192,8 @@ class SystemPath(object):
windows_finder_version = sub_finder(self.windows_finder)
if windows_finder_version:
return windows_finder_version
paths = [self.get_path(k) for k in self.path_order]
path_filter = filter(None, [sub_finder(p) for p in paths])
paths = (self.get_path(k) for k in self.path_order)
path_filter = filter(None, (sub_finder(p) for p in paths if p is not None))
version_sort = operator.attrgetter("as_python.version")
return next(
(c for c in sorted(path_filter, key=version_sort, reverse=True)), None
@@ -180,7 +222,7 @@ class SystemPath(object):
path_entries.update(
{
p.as_posix(): PathEntry.create(
path=p, is_root=True, only_python=only_python
path=p.absolute(), is_root=True, only_python=only_python
)
for p in _path_objects
}
@@ -197,6 +239,9 @@ class PathEntry(BasePath):
py_version = attr.ib(default=None)
pythons = attr.ib(default=None)
def __str__(self):
return fs_str('{0}'.format(self.path.as_posix()))
def _filter_children(self):
if self.only_python:
children = filter_pythons(self.path)
@@ -219,9 +264,8 @@ class PathEntry(BasePath):
if not self.py_version:
try:
from .python import PythonVersion
self.py_version = PythonVersion.from_path(self.path)
except ValueError:
except (ValueError, InvalidPythonVersion):
self.py_version = None
return self.py_version
+2 -1
View File
@@ -1,4 +1,5 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import attr
from collections import defaultdict
from . import BaseFinder
@@ -30,7 +31,7 @@ class PyenvFinder(BaseFinder):
version.get("is_prerelease"),
version.get("is_devrelease"),
)
versions[version_tuple] = VersionPath.create(path=p, only_python=True)
versions[version_tuple] = VersionPath.create(path=p.resolve(), only_python=True)
return versions
@classmethod
+2 -1
View File
@@ -1,4 +1,5 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import attr
import copy
import platform
@@ -122,7 +123,7 @@ class PythonVersion(object):
if not path.is_python:
raise ValueError("Not a valid python path: %s" % path.path)
return
py_version, _ = get_python_version(str(path.path))
py_version = get_python_version(str(path.path))
instance_dict = cls.parse(py_version)
if not isinstance(instance_dict.get("version"), Version):
raise ValueError("Not a valid python path: %s" % path.path)
+6 -1
View File
@@ -1,10 +1,12 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import attr
import operator
from collections import defaultdict
from . import BaseFinder
from .path import PathEntry
from .python import PythonVersion
from ..exceptions import InvalidPythonVersion
from ..utils import ensure_path
@@ -35,7 +37,10 @@ class WindowsFinder(BaseFinder):
path = None
for version_object in env_versions:
path = ensure_path(version_object.info.install_path.__getattr__(""))
py_version = PythonVersion.from_windows_launcher(version_object)
try:
py_version = PythonVersion.from_windows_launcher(version_object)
except InvalidPythonVersion:
continue
self.version_list.append(py_version)
base_dir = PathEntry.create(
path,
+16 -7
View File
@@ -1,4 +1,5 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import os
import six
from .models import SystemPath
@@ -39,15 +40,23 @@ class Finder(object):
and not dev
and isinstance(major, six.string_types)
):
from .models import PythonVersion
version_dict = {}
if "." in major:
from .models import PythonVersion
version_dict = PythonVersion.parse(major)
major = version_dict["major"]
minor = version_dict["minor"]
patch = version_dict["patch"]
pre = version_dict["is_prerelease"]
dev = version_dict["is_devrelease"]
elif len(major) == 1:
version_dict = {
'major': int(major),
'minor': None,
'patch': None,
'is_prerelease': False,
'is_devrelease': False
}
major = version_dict.get("major", major)
minor = version_dict.get("minor", minor)
patch = version_dict.get("patch", patch)
pre = version_dict.get("is_prerelease", pre)
dev = version_dict.get("is_devrelease", dev)
if os.name == "nt":
match = self.windows_finder.find_python_version(
major, minor=minor, patch=patch, pre=pre, dev=dev
+28 -7
View File
@@ -1,9 +1,13 @@
# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import attr
import locale
import os
import six
import subprocess
import sys
from fnmatch import fnmatch
from .exceptions import InvalidPythonVersion
try:
from pathlib import Path
@@ -26,23 +30,26 @@ def _run(cmd):
:returns: A 2-tuple of (output, error)
"""
encoding = locale.getdefaultlocale()[1] or "utf-8"
env = os.environ.copy()
c = subprocess.Popen(
cmd,
encoding=encoding,
env=env,
universal_newlines=True,
env=os.environ.copy(),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
output, err = c.communicate()
return output.strip(), err.strip()
out, err = c.communicate()
return out.decode(encoding).strip(), err.decode(encoding).strip()
def get_python_version(path):
"""Get python version string using subprocess from a given path."""
version_cmd = [path, "-c", "import sys; print(sys.version.split()[0])"]
return _run(version_cmd)
try:
out, _ = _run(version_cmd)
except OSError:
raise InvalidPythonVersion("%s is not a valid python path" % path)
if not out:
raise InvalidPythonVersion("%s is not a valid python path" % path)
return out
def optional_instance_of(cls):
@@ -111,3 +118,17 @@ def filter_pythons(path):
if not path.is_dir():
return path if path_is_python(path) else None
return filter(lambda x: path_is_python(x), path.iterdir())
def fs_str(string):
"""Encodes a string into the proper filesystem encoding
Borrowed from pip-tools
"""
if isinstance(string, str):
return string
assert not isinstance(string, bytes)
return string.encode(_fs_encoding)
_fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()