Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge #3191, #3196 and #3209 #3217

Merged
merged 89 commits into from
Nov 14, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
80a6dcb
add PIPENV_SKIP_LOCK envvar, and suitable doc
devxpy Oct 27, 2018
023e786
fix PIPENV_SKIP_LOCK for `pipenv unisntall` command.
devxpy Oct 27, 2018
09ba364
Merge branch 'master' into master
devxpy Oct 30, 2018
e2769fe
Merge branch 'master' into master
devxpy Oct 30, 2018
9ed610f
Merge branch 'master' into master
devxpy Nov 3, 2018
18be92b
Merge branch 'master' into master
devxpy Nov 7, 2018
2b195dd
fix errors from merge
devxpy Nov 8, 2018
3eba19d
Improve toml parsing
frostming Nov 8, 2018
e147dc3
Drops prettytoml/contoml form vendors
frostming Nov 8, 2018
b27d6a7
clear references in patched.txt
frostming Nov 8, 2018
1555200
Add back some tests
frostming Nov 8, 2018
53b073c
python 2.7 unicode
frostming Nov 8, 2018
b3aa66b
make tomlkit dump toml's inline table
frostming Nov 8, 2018
9743d98
Merge branch 'master' into improve-toml-parse
techalchemy Nov 8, 2018
36f054d
Grab updates from latest vendored changes
techalchemy Nov 8, 2018
65d7090
Force inline table
frostming Nov 8, 2018
5b49670
Fix broken requirementslib updates
techalchemy Nov 8, 2018
f3003b6
Merge branch 'master' into update-vendor
techalchemy Nov 8, 2018
0762528
Final fix
frostming Nov 9, 2018
3490fc8
fix patch
frostming Nov 9, 2018
de78c1e
Only convert outline tables when write toml
frostming Nov 9, 2018
accd0ea
Move to utils function
frostming Nov 9, 2018
6df7d88
update tomlkit
frostming Nov 10, 2018
1f7c9ef
update patch
frostming Nov 10, 2018
de98b87
backports import
frostming Nov 10, 2018
f5c7c58
Change fallback style
frostming Nov 10, 2018
2b90c89
Revendor requirementslib
techalchemy Nov 11, 2018
dec7be5
Introduce `pipenv.environments.Environment`
techalchemy Nov 11, 2018
642b6f9
Update vistir and requirementslib
techalchemy Nov 11, 2018
aedb41c
Fix stdout and stderr wrappers
techalchemy Nov 11, 2018
45100b8
Fix stdout and stderr wrappers
techalchemy Nov 11, 2018
118c9d3
Add dramatically improved queued installation
techalchemy Nov 11, 2018
5602952
Merge branch 'update-vendor' of github.com:pypa/pipenv into update-ve…
techalchemy Nov 11, 2018
690d1e8
Merge branch 'update-vendor' into feature/improved-async-installer
techalchemy Nov 11, 2018
8644611
Merge branch 'master' into update-vendor
techalchemy Nov 11, 2018
ac96370
Merge branch 'update-vendor' into feature/improved-async-installer
techalchemy Nov 11, 2018
8643a73
Fix configparser import
techalchemy Nov 11, 2018
0caf7a0
Fix configparser import
techalchemy Nov 11, 2018
650cc32
Fix resource errors
techalchemy Nov 11, 2018
fe9d996
Fix resource errors
techalchemy Nov 11, 2018
e5be2ac
Fix python 2.7 installations
techalchemy Nov 12, 2018
382be38
Fix python 2.7 installations
techalchemy Nov 12, 2018
489e534
Fix various bugs with python 2.7 and vendored deps
techalchemy Nov 12, 2018
3984632
Fix various bugs with python 2.7 and vendored deps
techalchemy Nov 12, 2018
32a6dd3
Support python 2 parsing
techalchemy Nov 12, 2018
4009198
Fix environment site import
techalchemy Nov 12, 2018
32b1113
Support python 2 parsing
techalchemy Nov 12, 2018
1216ae0
Fix environment site import
techalchemy Nov 12, 2018
70fc92b
Fix import errors on setup parsing
techalchemy Nov 12, 2018
7e139ad
Fix import errors on setup parsing
techalchemy Nov 12, 2018
8502ac9
Revendor
techalchemy Nov 12, 2018
013e3d0
Revendor
techalchemy Nov 12, 2018
96cbd58
Fix prefix comparison for py2
techalchemy Nov 12, 2018
8fa4057
Merge branch 'master' into update-vendor
techalchemy Nov 12, 2018
0c7f287
Fix prefix comparison for py2
techalchemy Nov 12, 2018
eed0f0f
Merge branch 'master' into feature/improved-async-installer
techalchemy Nov 12, 2018
d7d50ef
no samefile for windows python2.7
techalchemy Nov 12, 2018
9eabde0
no samefile for windows python2.7
techalchemy Nov 12, 2018
ef59d15
Fix bugs in environment implementation
techalchemy Nov 13, 2018
9296f56
Fix bugs in environment implementation
techalchemy Nov 13, 2018
e62b800
Fix syntax
techalchemy Nov 13, 2018
cb601b0
Fix syntax
techalchemy Nov 13, 2018
13c9e62
Update pythonfinder
techalchemy Nov 13, 2018
7bc754a
Merge branch 'master' into update-vendor
techalchemy Nov 13, 2018
d73879b
Update requirementslib
techalchemy Nov 13, 2018
e328ae2
Fix feedback
techalchemy Nov 13, 2018
310e0b2
Fix pythonfinder
techalchemy Nov 13, 2018
6b3c9a7
Remove accidentally committed test script
techalchemy Nov 13, 2018
4370281
Merge branch 'update-vendor' into feature/improved-async-installer
techalchemy Nov 13, 2018
c3cdbfb
Merge remote-tracking branch 'frostming/improve-toml-parse' into main…
techalchemy Nov 13, 2018
72e2ef7
Derive source names from URLs when not supplied
techalchemy Nov 13, 2018
1e3b8f9
Update news entries
techalchemy Nov 13, 2018
15f8d78
Syntax error and pythonfinder issue fixes
techalchemy Nov 13, 2018
f494571
Code cleanup -- unused functions
techalchemy Nov 13, 2018
2e10ff6
Fix pythonfinder
techalchemy Nov 13, 2018
f9b97da
Get rid of split file test
techalchemy Nov 14, 2018
095c9ef
remove useless tests
frostming Nov 14, 2018
08c384b
Implement `auto_envvar_prefix`
techalchemy Nov 14, 2018
2f97279
Update vendor file
techalchemy Nov 14, 2018
3585ef1
Merge branch 'maintenance/merge-3191-3196-3209' of github.com:pypa/pi…
techalchemy Nov 14, 2018
ec166f9
Reformat cli and command code
techalchemy Nov 14, 2018
e864343
Merge remote-tracking branch 'devxpy/master' into maintenance/merge-3…
techalchemy Nov 14, 2018
86c894d
Woops, delegator isn't updated, neither packaging
techalchemy Nov 14, 2018
ada66d3
Remove old patch
techalchemy Nov 14, 2018
bfa0b29
Update vendored deps
techalchemy Nov 14, 2018
5e5e1ed
Stray print
techalchemy Nov 14, 2018
08d94d4
Update core and rebuild ci
techalchemy Nov 14, 2018
a8f4c7e
accidental commit
techalchemy Nov 14, 2018
41cbe4d
Pin postreleases to pass packaging ci
techalchemy Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix pythonfinder
Signed-off-by: Dan Ryan <dan@danryan.co>
  • Loading branch information
techalchemy committed Nov 13, 2018
commit 310e0b293bf5febd035430d2a2f80e5c3158c5c8
43 changes: 37 additions & 6 deletions pipenv/vendor/pythonfinder/models/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
optional_instance_of,
path_is_known_executable,
unnest,
normalize_path
normalize_path,
parse_pyenv_version_order,
parse_asdf_version_order
)
from .python import PythonVersion

Expand Down Expand Up @@ -165,23 +167,26 @@ def _remove_path(self, path):
self.path_order = new_order

def _setup_asdf(self):
from .asdf import AsdfFinder
from .python import PythonFinder
asdf_index = self._get_last_instance(ASDF_DATA_DIR)
if not asdf_index:
# we are in a virtualenv without global pyenv on the path, so we should
# not write pyenv to the path here
return
self.asdf_finder = AsdfFinder.create(root=ASDF_DATA_DIR, ignore_unsupported=True)
self.asdf_finder = PythonFinder.create(
root=ASDF_DATA_DIR, ignore_unsupported=True,
sort_function=parse_asdf_version_order, version_glob_path="installs/python/*")
root_paths = [p for p in self.asdf_finder.roots]
self._slice_in_paths(asdf_index, root_paths)
self.paths.update(self.asdf_finder.roots)
self._register_finder("asdf", self.asdf_finder)

def _setup_pyenv(self):
from .pyenv import PyenvFinder
from .python import PythonFinder

self.pyenv_finder = PyenvFinder.create(
root=PYENV_ROOT, ignore_unsupported=self.ignore_unsupported
self.pyenv_finder = PythonFinder.create(
root=PYENV_ROOT, sort_function=parse_pyenv_version_order,
version_glob_path="versions/*", ignore_unsupported=self.ignore_unsupported
)
pyenv_index = self._get_last_instance(PYENV_ROOT)
if not pyenv_index:
Expand Down Expand Up @@ -585,3 +590,29 @@ def is_python(self):
return self.is_executable and (
looks_like_python(self.path.name)
)


@attr.s
class VersionPath(SystemPath):
base = attr.ib(default=None, validator=optional_instance_of(Path))
name = attr.ib(default=None)

@classmethod
def create(cls, path, only_python=True, pythons=None, name=None):
"""Accepts a path to a base python version directory.

Generates the version listings for it"""
from .path import PathEntry
path = ensure_path(path)
path_entries = defaultdict(PathEntry)
bin_ = "{base}/bin"
if path.as_posix().endswith(Path(bin_).name):
path = path.parent
bin_dir = ensure_path(bin_.format(base=path.as_posix()))
if not name:
name = path.name
current_entry = PathEntry.create(
bin_dir, is_root=True, only_python=True, pythons=pythons, name=name
)
path_entries[bin_dir.as_posix()] = current_entry
return cls(name=name, base=bin_dir, paths=path_entries)
2 changes: 0 additions & 2 deletions pipenv/vendor/pythonfinder/models/pyenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
from ..utils import (
ensure_path,
optional_instance_of,
get_python_version,
filter_pythons,
unnest,
)
from .mixins import BaseFinder, BasePath
Expand Down
221 changes: 218 additions & 3 deletions pipenv/vendor/pythonfinder/models/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,238 @@

import copy
import platform
import operator
import logging

from collections import defaultdict

import attr

from packaging.version import Version, LegacyVersion
from packaging.version import Version
from packaging.version import parse as parse_version
from vistir.compat import Path

from ..environment import SYSTEM_ARCH
from ..environment import SYSTEM_ARCH, PYENV_ROOT, ASDF_DATA_DIR
from .mixins import BaseFinder, BasePath
from ..utils import (
_filter_none,
ensure_path,
get_python_version,
optional_instance_of,
ensure_path,
unnest,
is_in_path,
parse_pyenv_version_order,
parse_asdf_version_order,
)

logger = logging.getLogger(__name__)


@attr.s(slots=True)
class PythonFinder(BaseFinder, BasePath):
root = attr.ib(default=None, validator=optional_instance_of(Path))
#: ignore_unsupported should come before versions, because its value is used
#: in versions's default initializer.
ignore_unsupported = attr.ib(default=True)
#: The function to use to sort version order when returning an ordered verion set
sort_function = attr.ib(default=None)
paths = attr.ib(default=attr.Factory(list))
roots = attr.ib(default=attr.Factory(defaultdict))
#: Glob path for python versions off of the root directory
version_glob_path = attr.ib(default="versions/*")
versions = attr.ib()
pythons = attr.ib()

@property
def expanded_paths(self):
return (
path for path in unnest(p for p in self.versions.values())
if path is not None
)

@property
def is_pyenv(self):
return is_in_path(str(self.root), PYENV_ROOT)

@property
def is_asdf(self):
return is_in_path(str(self.root), ASDF_DATA_DIR)

def get_version_order(self):
version_paths = [
p for p in self.root.glob(self.version_glob_path)
if not (p.parent.name == "envs" or p.name == "envs")
]
versions = {v.name: v for v in version_paths}
if self.is_pyenv:
version_order = [versions[v] for v in parse_pyenv_version_order()]
elif self.is_asdf:
version_order = [versions[v] for v in parse_asdf_version_order()]
for version in version_order:
version_paths.remove(version)
if version_order:
version_order += version_paths
else:
version_order = version_paths
return version_order

@classmethod
def version_from_bin_dir(cls, base_dir, name=None):
from .path import PathEntry
py_version = None
version_path = PathEntry.create(
path=base_dir.absolute().as_posix(),
only_python=True,
name=base_dir.parent.name,
)
py_version = next(iter(version_path.find_all_python_versions()), None)
return py_version

@versions.default
def get_versions(self):
from .path import PathEntry
versions = defaultdict()
bin_ = "{base}/bin"
for p in self.get_version_order():
bin_dir = Path(bin_.format(base=p.as_posix()))
version_path = None
if bin_dir.exists():
version_path = PathEntry.create(
path=bin_dir.absolute().as_posix(),
only_python=False,
name=p.name,
is_root=True,
)
version = None
try:
version = PythonVersion.parse(p.name)
except ValueError:
entry = next(iter(version_path.find_all_python_versions()), None)
if not entry:
if self.ignore_unsupported:
continue
raise
else:
version = entry.py_version.as_dict()
except Exception:
if not self.ignore_unsupported:
raise
logger.warning(
"Unsupported Python version %r, ignoring...", p.name, exc_info=True
)
continue
if not version:
continue
version_tuple = (
version.get("major"),
version.get("minor"),
version.get("patch"),
version.get("is_prerelease"),
version.get("is_devrelease"),
version.get("is_debug"),
)
self.roots[p] = version_path
versions[version_tuple] = version_path
self.paths.append(version_path)
return versions

@pythons.default
def get_pythons(self):
pythons = defaultdict()
for p in self.paths:
pythons.update(p.pythons)
return pythons

@classmethod
def create(cls, root, sort_function=None, version_glob_path=None, ignore_unsupported=True):
root = ensure_path(root)
if not version_glob_path:
version_glob_path = "versions/*"
return cls(root=root, ignore_unsupported=ignore_unsupported,
sort_function=sort_function, version_glob_path=version_glob_path)

def find_all_python_versions(
self,
major=None,
minor=None,
patch=None,
pre=None,
dev=None,
arch=None,
name=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 int minor: Minor python version to search for, defaults to None
:param int patch: Patch python version to search for, defaults to None
:param bool pre: Search for prereleases (default None) - prioritize releases if None
:param bool dev: Search for devreleases (default None) - prioritize releases if None
:param str arch: Architecture to include, e.g. '64bit', defaults to None
:param str name: The name of a python version, e.g. ``anaconda3-5.3.0``
:return: A list of :class:`~pythonfinder.models.PathEntry` instances matching the version requested.
:rtype: List[:class:`~pythonfinder.models.PathEntry`]
"""

version_matcher = operator.methodcaller(
"matches",
major=major,
minor=minor,
patch=patch,
pre=pre,
dev=dev,
arch=arch,
name=name,
)
py = operator.attrgetter("as_python")
pythons = (
py_ver for py_ver in (py(p) for p in self.pythons.values() if p is not None)
if py_ver is not None
)
# pythons = filter(None, [p.as_python for p in self.pythons.values()])
matching_versions = filter(lambda py: version_matcher(py), pythons)
version_sort = operator.attrgetter("version_sort")
return sorted(matching_versions, key=version_sort, reverse=True)

def find_python_version(
self,
major=None,
minor=None,
patch=None,
pre=None,
dev=None,
arch=None,
name=None,
):
"""Search or self for the specified Python version and return the first match.

:param major: Major version number.
:type major: int
:param int minor: Minor python version to search for, defaults to None
:param int patch: Patch python version to search for, defaults to None
:param bool pre: Search for prereleases (default None) - prioritize releases if None
:param bool dev: Search for devreleases (default None) - prioritize releases if None
:param str arch: Architecture to include, e.g. '64bit', defaults to None
:param str name: The name of a python version, e.g. ``anaconda3-5.3.0``
:returns: A :class:`~pythonfinder.models.PathEntry` instance matching the version requested.
"""

version_matcher = operator.methodcaller(
"matches",
major=major,
minor=minor,
patch=patch,
pre=pre,
dev=dev,
arch=arch,
name=name,
)
pythons = filter(None, [p.as_python for p in self.pythons.values()])
matching_versions = filter(lambda py: version_matcher(py), pythons)
version_sort = operator.attrgetter("version_sort")
return next(iter(c for c in sorted(matching_versions, key=version_sort, reverse=True)), None)


@attr.s(slots=True)
class PythonVersion(object):
Expand Down
35 changes: 29 additions & 6 deletions pipenv/vendor/pythonfinder/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
from fnmatch import fnmatch

import attr
import io
import six

import vistir

from .environment import PYENV_INSTALLED, PYENV_ROOT, ASDF_INSTALLED, ASDF_DATA_DIR
from .exceptions import InvalidPythonVersion

try:
Expand Down Expand Up @@ -127,12 +129,6 @@ def filter_pythons(path):
return filter(lambda x: path_is_python(x), path.iterdir())


# def unnest(item):
# if isinstance(next((i for i in item), None), (list, tuple)):
# return chain(*filter(None, item))
# return chain(filter(None, item))


def unnest(item):
if isinstance(item, Iterable) and not isinstance(item, six.string_types):
item, target = itertools.tee(item, 2)
Expand All @@ -145,3 +141,30 @@ def unnest(item):
yield sub
else:
yield el


def parse_pyenv_version_order(filename="version"):
version_order_file = normalize_path(os.path.join(PYENV_ROOT, filename))
if os.path.exists(version_order_file) and os.path.isfile(version_order_file):
with io.open(version_order_file, encoding="utf-8") as fh:
contents = fh.read()
version_order = [v for v in contents.splitlines()]
return version_order


def parse_asdf_version_order(filename=".tool-versions"):
version_order_file = normalize_path(os.path.join("~", filename))
if os.path.exists(version_order_file) and os.path.isfile(version_order_file):
with io.open(version_order_file, encoding="utf-8") as fh:
contents = fh.read()
python_section = next(iter(
line for line in contents.splitlines() if line.startswith("python")
), None)
if python_section:
python_key, versions = python_section.partition()
if versions:
return versions.split()


def is_in_path(path, parent):
return normalize_path(str(path)).startswith(normalize_path(str(parent)))