Skip to content

Commit

Permalink
Merge pull request #2564 from pypa/requirementslib-update
Browse files Browse the repository at this point in the history
Update requirementslib
  • Loading branch information
techalchemy authored Jul 12, 2018
2 parents 6e801ed + 35b071d commit 97241a9
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 30 deletions.
2 changes: 2 additions & 0 deletions news/2564.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed a bug related to parsing vcs requirements with both extras and subdirectory fragments.
Corrected an issue in the ``requirementslib`` parser which led to some markers being discarded rather than evaluated.
2 changes: 1 addition & 1 deletion pipenv/vendor/requirementslib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding=utf-8 -*-
__version__ = "1.0.9"
__version__ = "1.0.10"


from .exceptions import RequirementError
Expand Down
7 changes: 7 additions & 0 deletions pipenv/vendor/requirementslib/models/baserequirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,10 @@ def pipfile_part(self):
@classmethod
def attr_fields(cls):
return [field.name for field in attr.fields(cls)]

@property
def extras_as_pip(self):
if self.extras:
return "[{0}]".format(",".join(self.extras))

return ""
27 changes: 12 additions & 15 deletions pipenv/vendor/requirementslib/models/markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,31 +66,28 @@ def make_marker(cls, marker_string):
raise RequirementError(
"Invalid requirement: Invalid marker %r" % marker_string
)
marker_dict = {}
for m in marker._markers:
if isinstance(m, six.string_types):
continue
var, op, val = m
if var.value in cls.attr_fields():
marker_dict[var.value] = '{0} "{1}"'.format(op, val)
return marker_dict
return marker

@classmethod
def from_line(cls, line):
if ";" in line:
line = line.rsplit(";", 1)[1].strip()
marker_dict = cls.make_marker(line)
return cls(**marker_dict)
marker = cls.make_marker(line)
return marker

@classmethod
def from_pipfile(cls, name, pipfile):
found_keys = [k for k in pipfile.keys() if k in cls.attr_fields()]
marker_strings = ["{0} {1}".format(k, pipfile[k]) for k in found_keys]
if pipfile.get("markers"):
marker_strings.append(pipfile.get("markers"))
markers = {}
markers = []
for marker in marker_strings:
marker_dict = cls.make_marker(marker)
if marker_dict:
markers.update(marker_dict)
return cls(**markers)
markers.append(marker)
marker = ''
try:
marker = cls.make_marker(" and ".join(markers))
except RequirementError:
pass
else:
return marker
44 changes: 31 additions & 13 deletions pipenv/vendor/requirementslib/models/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
filter_none,
optional_instance_of,
split_markers_from_line,
parse_extras,
)
from .._compat import (
Link,
Expand Down Expand Up @@ -56,6 +57,7 @@ class NamedRequirement(BaseRequirement):
name = attr.ib()
version = attr.ib(validator=attr.validators.optional(validate_specifiers))
req = attr.ib()
extras = attr.ib(default=attr.Factory(list))

@req.default
def get_requirement(self):
Expand Down Expand Up @@ -114,6 +116,7 @@ class FileRequirement(BaseRequirement):
path = attr.ib(default=None, validator=attr.validators.optional(validate_path))
# : path to hit - without any of the VCS prefixes (like git+ / http+ / etc)
editable = attr.ib(default=None)
extras = attr.ib(default=attr.Factory(list))
uri = attr.ib()
link = attr.ib()
name = attr.ib()
Expand Down Expand Up @@ -501,6 +504,7 @@ def get_link(self):
name=self.name,
ref=self.ref,
subdirectory=self.subdirectory,
extras=self.extras
)

@name.default
Expand Down Expand Up @@ -546,14 +550,16 @@ def get_requirement(self):
req.vcs = self.vcs
if self.ref and not req.revision:
req.revision = self.ref
if self.extras and not req.extras:
req.extras = self.extras
return req

@classmethod
def from_pipfile(cls, name, pipfile):
creation_args = {}
pipfile_keys = [
k
for k in ("ref", "vcs", "subdirectory", "path", "editable", "file", "uri")
for k in ("ref", "vcs", "subdirectory", "path", "editable", "file", "uri", "extras")
+ VCS_LIST
if k in pipfile
]
Expand All @@ -572,13 +578,18 @@ def from_pipfile(cls, name, pipfile):
return cls(**creation_args)

@classmethod
def from_line(cls, line, editable=None):
def from_line(cls, line, editable=None, extras=None):
relpath = None
if line.startswith("-e "):
editable = True
line = line.split(" ", 1)[1]
vcs_type, prefer, relpath, path, uri, link = cls.get_link_from_line(line)
name = link.egg_fragment
if not extras and link.egg_fragment:
name, extras = _strip_extras(link.egg_fragment)
if extras:
extras = parse_extras(extras)
else:
name = link.egg_fragment
subdirectory = link.subdirectory_fragment
ref = None
if "@" in link.show_url and "@" in uri:
Expand All @@ -594,6 +605,7 @@ def from_line(cls, line, editable=None):
path=relpath or path,
editable=editable,
uri=uri,
extras=extras,
)

@property
Expand Down Expand Up @@ -623,7 +635,7 @@ def pipfile_part(self):
pipfile_dict = attr.asdict(self, filter=filter_none).copy()
if "vcs" in pipfile_dict:
pipfile_dict = self._choose_vcs_source(pipfile_dict)
name = pipfile_dict.pop("name")
name, _ = _strip_extras(pipfile_dict.pop("name"))
return {name: pipfile_dict}


Expand Down Expand Up @@ -659,7 +671,7 @@ def hashes_as_pip(self):
@property
def markers_as_pip(self):
if self.markers:
return "; {0}".format(self.markers.replace('"', "'"))
return "; {0}".format(self.markers).replace('"', "'")

return ""

Expand Down Expand Up @@ -702,6 +714,8 @@ def from_line(cls, line):
line = line.split(" ", 1)[1] if editable else line
line, markers = split_markers_from_line(line)
line, extras = _strip_extras(line)
if extras:
extras = parse_extras(extras)
line = line.strip('"').strip("'").strip()
line_with_prefix = "-e {0}".format(line) if editable else line
vcs = None
Expand All @@ -710,7 +724,7 @@ def from_line(cls, line):
if is_installable_file(line) or (is_valid_url(line) and not is_vcs(line)):
r = FileRequirement.from_line(line_with_prefix)
elif is_vcs(line):
r = VCSRequirement.from_line(line_with_prefix)
r = VCSRequirement.from_line(line_with_prefix, extras=extras)
vcs = r.vcs
elif line == "." and not is_installable_file(line):
raise RequirementError(
Expand All @@ -727,14 +741,11 @@ def from_line(cls, line):
version = line[spec_idx:]
if not extras:
name, extras = _strip_extras(name)
if extras:
extras = parse_extras(extras)
if version:
name = "{0}{1}".format(name, version)
r = NamedRequirement.from_line(line)
if extras:
extras = first(
requirements.parse("fakepkg{0}".format(extras_to_string(extras)))
).extras
r.req.extras = extras
if markers:
r.req.markers = markers
args = {
Expand All @@ -746,6 +757,10 @@ def from_line(cls, line):
}
if extras:
args["extras"] = extras
r.req.extras = extras
r.extras = extras
elif r.extras:
args["extras"] = r.extras
if hashes:
args["hashes"] = hashes
return cls(**args)
Expand All @@ -764,11 +779,14 @@ def from_pipfile(cls, name, pipfile):
r = FileRequirement.from_pipfile(name, pipfile)
else:
r = NamedRequirement.from_pipfile(name, pipfile)
markers = PipenvMarkers.from_pipfile(name, _pipfile)
if markers:
markers = str(markers)
args = {
"name": r.name,
"vcs": vcs,
"req": r,
"markers": PipenvMarkers.from_pipfile(name, _pipfile).line_part,
"markers": markers,
"extras": _pipfile.get("extras"),
"editable": _pipfile.get("editable", False),
"index": _pipfile.get("index"),
Expand All @@ -788,7 +806,7 @@ def as_line(self, sources=None):
"""
line = "{0}{1}{2}{3}{4}".format(
self.req.line_part,
self.extras_as_pip,
self.extras_as_pip if not self.is_vcs else "",
self.specifiers if self.specifiers else "",
self.markers_as_pip,
self.hashes_as_pip,
Expand Down
10 changes: 10 additions & 0 deletions pipenv/vendor/requirementslib/models/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ def extras_to_string(extras):
return "[{0}]".format(",".join(extras))


def parse_extras(extras_str):
"""Turn a string of extras into a parsed extras list"""
import requirements
extras = first(
requirements.parse("fakepkg{0}".format(extras_to_string(extras_str)))
).extras
return extras


def specs_to_string(specs):
"""Turn a list of specifier tuples into a string"""
if specs:
Expand Down Expand Up @@ -133,6 +142,7 @@ def validate_markers(instance, attr_, value):

def validate_specifiers(instance, attr_, value):
from packaging.specifiers import SpecifierSet, InvalidSpecifier
from packaging.markers import InvalidMarker
if value == "":
return True
try:
Expand Down
2 changes: 1 addition & 1 deletion pipenv/vendor/vendor.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ requests==2.19.1
idna==2.7
urllib3==1.23
certifi==2018.4.16
requirementslib==1.0.9
requirementslib==1.0.10
attrs==18.1.0
distlib==0.2.7
packaging==17.1
Expand Down

0 comments on commit 97241a9

Please sign in to comment.