aboutsummaryrefslogtreecommitdiffstats
path: root/pkg_resources/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'pkg_resources/__init__.py')
-rw-r--r--pkg_resources/__init__.py158
1 files changed, 34 insertions, 124 deletions
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py
index 3cd67fa0..82a35702 100644
--- a/pkg_resources/__init__.py
+++ b/pkg_resources/__init__.py
@@ -90,6 +90,8 @@ except ImportError:
try:
import pkg_resources._vendor.packaging.version
import pkg_resources._vendor.packaging.specifiers
+ import pkg_resources._vendor.packaging.requirements
+ import pkg_resources._vendor.packaging.markers
packaging = pkg_resources._vendor.packaging
except ImportError:
# fallback to naturally-installed version; allows system packagers to
@@ -1420,13 +1422,15 @@ class MarkerEvaluation(object):
@classmethod
def is_invalid_marker(cls, text):
"""
- Validate text as a PEP 426 environment marker; return an exception
+ Validate text as a PEP 508 environment marker; return an exception
if invalid or False otherwise.
"""
try:
cls.evaluate_marker(text)
- except SyntaxError as e:
- return cls.normalize_exception(e)
+ except packaging.markers.InvalidMarker as e:
+ e.filename = None
+ e.lineno = None
+ return e
return False
@staticmethod
@@ -1518,48 +1522,14 @@ class MarkerEvaluation(object):
@classmethod
def evaluate_marker(cls, text, extra=None):
"""
- Evaluate a PEP 426 environment marker on CPython 2.4+.
+ Evaluate a PEP 508 environment marker on CPython 2.4+.
Return a boolean indicating the marker result in this environment.
- Raise SyntaxError if marker is invalid.
+ Raise InvalidMarker if marker is invalid.
- This implementation uses the 'parser' module, which is not implemented
- on
- Jython and has been superseded by the 'ast' module in Python 2.6 and
- later.
+ This implementation uses the 'pyparsing' module.
"""
- return cls.interpret(parser.expr(text).totuple(1)[1])
-
- @staticmethod
- def _translate_metadata2(env):
- """
- Markerlib implements Metadata 1.2 (PEP 345) environment markers.
- Translate the variables to Metadata 2.0 (PEP 426).
- """
- return dict(
- (key.replace('.', '_'), value)
- for key, value in env
- )
-
- @classmethod
- def _markerlib_evaluate(cls, text):
- """
- Evaluate a PEP 426 environment marker using markerlib.
- Return a boolean indicating the marker result in this environment.
- Raise SyntaxError if marker is invalid.
- """
- import _markerlib
-
- env = cls._translate_metadata2(_markerlib.default_environment())
- try:
- result = _markerlib.interpret(text, env)
- except NameError as e:
- raise SyntaxError(e.args[0])
- return result
-
- if 'parser' not in globals():
- # Fall back to less-complete _markerlib implementation if 'parser' module
- # is not available.
- evaluate_marker = _markerlib_evaluate
+ marker = packaging.markers.Marker(text)
+ return marker.evaluate()
@classmethod
def interpret(cls, nodelist):
@@ -2314,18 +2284,6 @@ def yield_lines(strs):
for s in yield_lines(ss):
yield s
-# whitespace and comment
-LINE_END = re.compile(r"\s*(#.*)?$").match
-# line continuation
-CONTINUE = re.compile(r"\s*\\\s*(#.*)?$").match
-# Distribution or extra
-DISTRO = re.compile(r"\s*((\w|[-.])+)").match
-# ver. info
-VERSION = re.compile(r"\s*(<=?|>=?|===?|!=|~=)\s*((\w|[-.*_!+])+)").match
-# comma between items
-COMMA = re.compile(r"\s*,").match
-OBRACKET = re.compile(r"\s*\[").match
-CBRACKET = re.compile(r"\s*\]").match
MODULE = re.compile(r"\w+(\.\w+)*$").match
EGG_NAME = re.compile(
r"""
@@ -2861,34 +2819,22 @@ class DistInfoDistribution(Distribution):
self.__dep_map = self._compute_dependencies()
return self.__dep_map
- def _preparse_requirement(self, requires_dist):
- """Convert 'Foobar (1); baz' to ('Foobar ==1', 'baz')
- Split environment marker, add == prefix to version specifiers as
- necessary, and remove parenthesis.
- """
- parts = requires_dist.split(';', 1) + ['']
- distvers = parts[0].strip()
- mark = parts[1].strip()
- distvers = re.sub(self.EQEQ, r"\1==\2\3", distvers)
- distvers = distvers.replace('(', '').replace(')', '')
- return (distvers, mark)
-
def _compute_dependencies(self):
"""Recompute this distribution's dependencies."""
- from _markerlib import compile as compile_marker
dm = self.__dep_map = {None: []}
reqs = []
# Including any condition expressions
for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
- distvers, mark = self._preparse_requirement(req)
- parsed = next(parse_requirements(distvers))
- parsed.marker_fn = compile_marker(mark)
+ current_req = packaging.requirements.Requirement(req)
+ specs = _parse_requirement_specs(current_req)
+ parsed = Requirement(current_req.name, specs, current_req.extras)
+ parsed._marker = current_req.marker
reqs.append(parsed)
def reqs_for_extra(extra):
for req in reqs:
- if req.marker_fn(override={'extra':extra}):
+ if not req._marker or req._marker.evaluate({'extra': extra}):
yield req
common = frozenset(reqs_for_extra(None))
@@ -2926,6 +2872,13 @@ class RequirementParseError(ValueError):
return ' '.join(self.args)
+def _parse_requirement_specs(req):
+ if req.specifier:
+ return [(spec.operator, spec.version) for spec in req.specifier]
+ else:
+ return []
+
+
def parse_requirements(strs):
"""Yield ``Requirement`` objects for each specification in `strs`
@@ -2934,60 +2887,17 @@ def parse_requirements(strs):
# create a steppable iterator, so we can handle \-continuations
lines = iter(yield_lines(strs))
- def scan_list(ITEM, TERMINATOR, line, p, groups, item_name):
-
- items = []
-
- while not TERMINATOR(line, p):
- if CONTINUE(line, p):
- try:
- line = next(lines)
- p = 0
- except StopIteration:
- msg = "\\ must not appear on the last nonblank line"
- raise RequirementParseError(msg)
-
- match = ITEM(line, p)
- if not match:
- msg = "Expected " + item_name + " in"
- raise RequirementParseError(msg, line, "at", line[p:])
-
- items.append(match.group(*groups))
- p = match.end()
-
- match = COMMA(line, p)
- if match:
- # skip the comma
- p = match.end()
- elif not TERMINATOR(line, p):
- msg = "Expected ',' or end-of-list in"
- raise RequirementParseError(msg, line, "at", line[p:])
-
- match = TERMINATOR(line, p)
- # skip the terminator, if any
- if match:
- p = match.end()
- return line, p, items
-
for line in lines:
- match = DISTRO(line)
- if not match:
- raise RequirementParseError("Missing distribution spec", line)
- project_name = match.group(1)
- p = match.end()
- extras = []
-
- match = OBRACKET(line, p)
- if match:
- p = match.end()
- line, p, extras = scan_list(
- DISTRO, CBRACKET, line, p, (1,), "'extra' name"
- )
-
- line, p, specs = scan_list(VERSION, LINE_END, line, p, (1, 2),
- "version spec")
- specs = [(op, val) for op, val in specs]
- yield Requirement(project_name, specs, extras)
+ # Drop comments -- a hash without a space may be in a URL.
+ if ' #' in line:
+ line = line[:line.find(' #')]
+ # If there is a line continuation, drop it, and append the next line.
+ if line.endswith('\\'):
+ line = line[:-2].strip()
+ line += next(lines)
+ req = packaging.requirements.Requirement(line)
+ specs = _parse_requirement_specs(req)
+ yield Requirement(req.name, specs, req.extras)
class Requirement: