Parse a requirement passed in as a string. Return a Container whose attributes contain the various parts of the requirement.
(req)
| 11 | NON_SPACE = re.compile(r'(\S+)\s*') |
| 12 | |
| 13 | def parse_requirement(req): |
| 14 | """ |
| 15 | Parse a requirement passed in as a string. Return a Container |
| 16 | whose attributes contain the various parts of the requirement. |
| 17 | """ |
| 18 | remaining = req.strip() |
| 19 | if not remaining or remaining.startswith('#'): |
| 20 | return None |
| 21 | m = IDENTIFIER.match(remaining) |
| 22 | if not m: |
| 23 | raise SyntaxError('name expected: %s' % remaining) |
| 24 | distname = m.groups()[0] |
| 25 | remaining = remaining[m.end():] |
| 26 | extras = mark_expr = versions = uri = None |
| 27 | if remaining and remaining[0] == '[': |
| 28 | i = remaining.find(']', 1) |
| 29 | if i < 0: |
| 30 | raise SyntaxError('unterminated extra: %s' % remaining) |
| 31 | s = remaining[1:i] |
| 32 | remaining = remaining[i + 1:].lstrip() |
| 33 | extras = [] |
| 34 | while s: |
| 35 | m = IDENTIFIER.match(s) |
| 36 | if not m: |
| 37 | raise SyntaxError('malformed extra: %s' % s) |
| 38 | extras.append(m.groups()[0]) |
| 39 | s = s[m.end():] |
| 40 | if not s: |
| 41 | break |
| 42 | if s[0] != ',': |
| 43 | raise SyntaxError('comma expected in extras: %s' % s) |
| 44 | s = s[1:].lstrip() |
| 45 | if not extras: |
| 46 | extras = None |
| 47 | if remaining: |
| 48 | if remaining[0] == '@': |
| 49 | # it's a URI |
| 50 | remaining = remaining[1:].lstrip() |
| 51 | m = NON_SPACE.match(remaining) |
| 52 | if not m: |
| 53 | raise SyntaxError('invalid URI: %s' % remaining) |
| 54 | uri = m.groups()[0] |
| 55 | t = urlparse(uri) |
| 56 | # there are issues with Python and URL parsing, so this test |
| 57 | # is a bit crude. See bpo-20271, bpo-23505. Python doesn't |
| 58 | # always parse invalid URLs correctly - it should raise |
| 59 | # exceptions for malformed URLs |
| 60 | if not (t.scheme and t.netloc): |
| 61 | raise SyntaxError('Invalid URL: %s' % uri) |
| 62 | remaining = remaining[m.end():].lstrip() |
| 63 | else: |
| 64 | |
| 65 | def get_versions(ver_remaining): |
| 66 | """ |
| 67 | Return a list of operator, version tuples if any are |
| 68 | specified, else None. |
| 69 | """ |
| 70 | m = COMPARE_OP.match(ver_remaining) |
nothing calls this directly
no test coverage detected