|
29 | 29 | import functools
|
30 | 30 | import pkgutil
|
31 | 31 | import token
|
32 |
| -import symbol |
33 | 32 | import operator
|
34 | 33 | import platform
|
35 | 34 | import collections
|
@@ -1402,202 +1401,30 @@ def to_filename(name):
|
1402 | 1401 | return name.replace('-','_')
|
1403 | 1402 |
|
1404 | 1403 |
|
1405 |
| -class MarkerEvaluation(object): |
1406 |
| - values = { |
1407 |
| - 'os_name': lambda: os.name, |
1408 |
| - 'sys_platform': lambda: sys.platform, |
1409 |
| - 'python_full_version': platform.python_version, |
1410 |
| - 'python_version': lambda: platform.python_version()[:3], |
1411 |
| - 'platform_version': platform.version, |
1412 |
| - 'platform_machine': platform.machine, |
1413 |
| - 'platform_python_implementation': platform.python_implementation, |
1414 |
| - 'python_implementation': platform.python_implementation, |
1415 |
| - } |
1416 |
| - |
1417 |
| - @classmethod |
1418 |
| - def is_invalid_marker(cls, text): |
1419 |
| - """ |
1420 |
| - Validate text as a PEP 426 environment marker; return an exception |
1421 |
| - if invalid or False otherwise. |
1422 |
| - """ |
1423 |
| - try: |
1424 |
| - cls.evaluate_marker(text) |
1425 |
| - except SyntaxError as e: |
1426 |
| - return cls.normalize_exception(e) |
1427 |
| - return False |
1428 |
| - |
1429 |
| - @staticmethod |
1430 |
| - def normalize_exception(exc): |
1431 |
| - """ |
1432 |
| - Given a SyntaxError from a marker evaluation, normalize the error |
1433 |
| - message: |
1434 |
| - - Remove indications of filename and line number. |
1435 |
| - - Replace platform-specific error messages with standard error |
1436 |
| - messages. |
1437 |
| - """ |
1438 |
| - subs = { |
1439 |
| - 'unexpected EOF while parsing': 'invalid syntax', |
1440 |
| - 'parenthesis is never closed': 'invalid syntax', |
1441 |
| - } |
1442 |
| - exc.filename = None |
1443 |
| - exc.lineno = None |
1444 |
| - exc.msg = subs.get(exc.msg, exc.msg) |
1445 |
| - return exc |
1446 |
| - |
1447 |
| - @classmethod |
1448 |
| - def and_test(cls, nodelist): |
1449 |
| - # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! |
1450 |
| - items = [ |
1451 |
| - cls.interpret(nodelist[i]) |
1452 |
| - for i in range(1, len(nodelist), 2) |
1453 |
| - ] |
1454 |
| - return functools.reduce(operator.and_, items) |
1455 |
| - |
1456 |
| - @classmethod |
1457 |
| - def test(cls, nodelist): |
1458 |
| - # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! |
1459 |
| - items = [ |
1460 |
| - cls.interpret(nodelist[i]) |
1461 |
| - for i in range(1, len(nodelist), 2) |
1462 |
| - ] |
1463 |
| - return functools.reduce(operator.or_, items) |
1464 |
| - |
1465 |
| - @classmethod |
1466 |
| - def atom(cls, nodelist): |
1467 |
| - t = nodelist[1][0] |
1468 |
| - if t == token.LPAR: |
1469 |
| - if nodelist[2][0] == token.RPAR: |
1470 |
| - raise SyntaxError("Empty parentheses") |
1471 |
| - return cls.interpret(nodelist[2]) |
1472 |
| - msg = "Language feature not supported in environment markers" |
1473 |
| - raise SyntaxError(msg) |
1474 |
| - |
1475 |
| - @classmethod |
1476 |
| - def comparison(cls, nodelist): |
1477 |
| - if len(nodelist) > 4: |
1478 |
| - msg = "Chained comparison not allowed in environment markers" |
1479 |
| - raise SyntaxError(msg) |
1480 |
| - comp = nodelist[2][1] |
1481 |
| - cop = comp[1] |
1482 |
| - if comp[0] == token.NAME: |
1483 |
| - if len(nodelist[2]) == 3: |
1484 |
| - if cop == 'not': |
1485 |
| - cop = 'not in' |
1486 |
| - else: |
1487 |
| - cop = 'is not' |
1488 |
| - try: |
1489 |
| - cop = cls.get_op(cop) |
1490 |
| - except KeyError: |
1491 |
| - msg = repr(cop) + " operator not allowed in environment markers" |
1492 |
| - raise SyntaxError(msg) |
1493 |
| - return cop(cls.evaluate(nodelist[1]), cls.evaluate(nodelist[3])) |
1494 |
| - |
1495 |
| - @classmethod |
1496 |
| - def get_op(cls, op): |
1497 |
| - ops = { |
1498 |
| - symbol.test: cls.test, |
1499 |
| - symbol.and_test: cls.and_test, |
1500 |
| - symbol.atom: cls.atom, |
1501 |
| - symbol.comparison: cls.comparison, |
1502 |
| - 'not in': lambda x, y: x not in y, |
1503 |
| - 'in': lambda x, y: x in y, |
1504 |
| - '==': operator.eq, |
1505 |
| - '!=': operator.ne, |
1506 |
| - '<': operator.lt, |
1507 |
| - '>': operator.gt, |
1508 |
| - '<=': operator.le, |
1509 |
| - '>=': operator.ge, |
1510 |
| - } |
1511 |
| - if hasattr(symbol, 'or_test'): |
1512 |
| - ops[symbol.or_test] = cls.test |
1513 |
| - return ops[op] |
1514 |
| - |
1515 |
| - @classmethod |
1516 |
| - def evaluate_marker(cls, text, extra=None): |
1517 |
| - """ |
1518 |
| - Evaluate a PEP 426 environment marker on CPython 2.4+. |
1519 |
| - Return a boolean indicating the marker result in this environment. |
1520 |
| - Raise SyntaxError if marker is invalid. |
1521 |
| -
|
1522 |
| - This implementation uses the 'parser' module, which is not implemented |
1523 |
| - on |
1524 |
| - Jython and has been superseded by the 'ast' module in Python 2.6 and |
1525 |
| - later. |
1526 |
| - """ |
1527 |
| - return cls.interpret(parser.expr(text).totuple(1)[1]) |
1528 |
| - |
1529 |
| - @staticmethod |
1530 |
| - def _translate_metadata2(env): |
1531 |
| - """ |
1532 |
| - Markerlib implements Metadata 1.2 (PEP 345) environment markers. |
1533 |
| - Translate the variables to Metadata 2.0 (PEP 426). |
1534 |
| - """ |
1535 |
| - return dict( |
1536 |
| - (key.replace('.', '_'), value) |
1537 |
| - for key, value in env |
1538 |
| - ) |
1539 |
| - |
1540 |
| - @classmethod |
1541 |
| - def _markerlib_evaluate(cls, text): |
1542 |
| - """ |
1543 |
| - Evaluate a PEP 426 environment marker using markerlib. |
1544 |
| - Return a boolean indicating the marker result in this environment. |
1545 |
| - Raise SyntaxError if marker is invalid. |
1546 |
| - """ |
1547 |
| - import _markerlib |
1548 |
| - |
1549 |
| - env = cls._translate_metadata2(_markerlib.default_environment()) |
1550 |
| - try: |
1551 |
| - result = _markerlib.interpret(text, env) |
1552 |
| - except NameError as e: |
1553 |
| - raise SyntaxError(e.args[0]) |
1554 |
| - return result |
1555 |
| - |
1556 |
| - if 'parser' not in globals(): |
1557 |
| - # Fall back to less-complete _markerlib implementation if 'parser' module |
1558 |
| - # is not available. |
1559 |
| - evaluate_marker = _markerlib_evaluate |
1560 |
| - |
1561 |
| - @classmethod |
1562 |
| - def interpret(cls, nodelist): |
1563 |
| - while len(nodelist)==2: nodelist = nodelist[1] |
1564 |
| - try: |
1565 |
| - op = cls.get_op(nodelist[0]) |
1566 |
| - except KeyError: |
1567 |
| - raise SyntaxError("Comparison or logical expression expected") |
1568 |
| - return op(nodelist) |
| 1404 | +def invalid_marker(text): |
| 1405 | + """ |
| 1406 | + Validate text as a PEP 508 environment marker; return an exception |
| 1407 | + if invalid or False otherwise. |
| 1408 | + """ |
| 1409 | + try: |
| 1410 | + evaluate_marker(text) |
| 1411 | + except packaging.markers.InvalidMarker as e: |
| 1412 | + e.filename = None |
| 1413 | + e.lineno = None |
| 1414 | + return e |
| 1415 | + return False |
1569 | 1416 |
|
1570 |
| - @classmethod |
1571 |
| - def evaluate(cls, nodelist): |
1572 |
| - while len(nodelist)==2: nodelist = nodelist[1] |
1573 |
| - kind = nodelist[0] |
1574 |
| - name = nodelist[1] |
1575 |
| - if kind==token.NAME: |
1576 |
| - try: |
1577 |
| - op = cls.values[name] |
1578 |
| - except KeyError: |
1579 |
| - raise SyntaxError("Unknown name %r" % name) |
1580 |
| - return op() |
1581 |
| - if kind==token.STRING: |
1582 |
| - s = nodelist[1] |
1583 |
| - if not cls._safe_string(s): |
1584 |
| - raise SyntaxError( |
1585 |
| - "Only plain strings allowed in environment markers") |
1586 |
| - return s[1:-1] |
1587 |
| - msg = "Language feature not supported in environment markers" |
1588 |
| - raise SyntaxError(msg) |
1589 | 1417 |
|
1590 |
| - @staticmethod |
1591 |
| - def _safe_string(cand): |
1592 |
| - return ( |
1593 |
| - cand[:1] in "'\"" and |
1594 |
| - not cand.startswith('"""') and |
1595 |
| - not cand.startswith("'''") and |
1596 |
| - '\\' not in cand |
1597 |
| - ) |
| 1418 | +def evaluate_marker(text, extra=None): |
| 1419 | + """ |
| 1420 | + Evaluate a PEP 508 environment marker. |
| 1421 | + Return a boolean indicating the marker result in this environment. |
| 1422 | + Raise InvalidMarker if marker is invalid. |
| 1423 | + This implementation uses the 'pyparsing' module. |
| 1424 | + """ |
| 1425 | + marker = packaging.markers.Marker(text) |
| 1426 | + return marker.evaluate() |
1598 | 1427 |
|
1599 |
| -invalid_marker = MarkerEvaluation.is_invalid_marker |
1600 |
| -evaluate_marker = MarkerEvaluation.evaluate_marker |
1601 | 1428 |
|
1602 | 1429 | class NullProvider:
|
1603 | 1430 | """Try to implement resources and metadata for arbitrary PEP 302 loaders"""
|
|
0 commit comments