|
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