diff options
| author | Steve Kowalik <steven@wedontsleep.org> | 2015-12-10 11:35:41 +1300 |
|---|---|---|
| committer | Steve Kowalik <steven@wedontsleep.org> | 2015-12-10 11:35:41 +1300 |
| commit | a718819d2849196e902808301c9a95724510c5c1 (patch) | |
| tree | ffa7e63c52e3101d76a3dc55387dd4f88e367716 /pkg_resources/_vendor/packaging/requirements.py | |
| parent | dadd14d82c5f1db83704eb1c6da0b62998cb25a7 (diff) | |
| download | python-setuptools-git-a718819d2849196e902808301c9a95724510c5c1.tar.gz | |
First shot at removing usage of _markerlib and switching to the PEP 508 implementation in packaging.
Diffstat (limited to 'pkg_resources/_vendor/packaging/requirements.py')
| -rw-r--r-- | pkg_resources/_vendor/packaging/requirements.py | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/pkg_resources/_vendor/packaging/requirements.py b/pkg_resources/_vendor/packaging/requirements.py new file mode 100644 index 00000000..95b2d986 --- /dev/null +++ b/pkg_resources/_vendor/packaging/requirements.py @@ -0,0 +1,118 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import string +import re + +from pkg_resources._vendor.pyparsing import stringStart, stringEnd, originalTextFor, ParseException +from pkg_resources._vendor.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine +from pkg_resources._vendor.pyparsing import Literal as L # noqa +from six.moves.urllib import parse as urlparse + +from .markers import MARKER_EXPR, Marker +from .specifiers import LegacySpecifier, Specifier, SpecifierSet + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +ALPHANUM = Word(string.ascii_letters + string.digits) + +LBRACKET = L("[").suppress() +RBRACKET = L("]").suppress() +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() +COMMA = L(",").suppress() +SEMICOLON = L(";").suppress() +AT = L("@").suppress() + +PUNCTUATION = Word("-_.") +IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) +IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) + +NAME = IDENTIFIER("name") +EXTRA = IDENTIFIER + +URI = Regex(r'[^ ]+')("url") +URL = (AT + URI) + +EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) +EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") + +VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) +VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) + +VERSION_ONE = VERSION_PEP440 | VERSION_LEGACY +VERSION_MANY = VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE) +VERSION_MANY.setParseAction( + lambda s, l, t: SpecifierSet(','.join(t.asList())) +) +VERSION_SPEC = ((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)("specifier") + +MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") +MARKER_EXPR.setParseAction( + lambda s, l, t: Marker(s[t._original_start:t._original_end]) +) +MARKER_SEPERATOR = SEMICOLON +MARKER = MARKER_SEPERATOR + MARKER_EXPR + +VERSION_AND_MARKER = Optional(VERSION_SPEC) + Optional(MARKER) +URL_AND_MARKER = URL + Optional(MARKER) + +NAMED_REQUIREMENT = \ + NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) + +REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd + + +class Requirement(object): + + # TODO: Can we test whether something is contained within a requirement? + # If so how do we do that? Do we need to test against the _name_ of + # the thing as well as the version? What about the markers? + # TODO: Can we normalize the name and extra name? + + def __init__(self, requirement_string): + try: + req = REQUIREMENT.parseString(requirement_string) + except ParseException: + raise InvalidRequirement( + "Invalid requirement: {0!r}".format(requirement_string)) + + self.name = req.name + if req.url: + parsed_url = urlparse.urlparse(req.url) + if not (parsed_url.scheme and parsed_url.netloc) or ( + not parsed_url.scheme and not parsed_url.netloc): + raise InvalidRequirement("Invalid URL given") + self.url = req.url + else: + self.url = None + self.extras = req.extras.asList() if req.extras else [] + self.specifier = req.specifier if req.specifier else None + self.marker = req.marker if req.marker else None + + def __str__(self): + parts = [self.name] + + if self.extras: + parts.append("[{0}]".format(",".join(sorted(self.extras)))) + + if self.specifier: + parts.append(str(self.specifier)) + + if self.url: + parts.append("@ {0}".format(self.url)) + + if self.marker: + parts.append("; {0}".format(self.marker)) + + return "".join(parts) + + def __repr__(self): + return "<Requirement({0!r})>".format(str(self)) |
