Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

markers.py 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2012-2017 Vinay Sajip.
  4. # Licensed to the Python Software Foundation under a contributor agreement.
  5. # See LICENSE.txt and CONTRIBUTORS.txt.
  6. #
  7. """
  8. Parser for the environment markers micro-language defined in PEP 508.
  9. """
  10. # Note: In PEP 345, the micro-language was Python compatible, so the ast
  11. # module could be used to parse it. However, PEP 508 introduced operators such
  12. # as ~= and === which aren't in Python, necessitating a different approach.
  13. import os
  14. import sys
  15. import platform
  16. import re
  17. from .compat import python_implementation, urlparse, string_types
  18. from .util import in_venv, parse_marker
  19. __all__ = ['interpret']
  20. def _is_literal(o):
  21. if not isinstance(o, string_types) or not o:
  22. return False
  23. return o[0] in '\'"'
  24. class Evaluator(object):
  25. """
  26. This class is used to evaluate marker expessions.
  27. """
  28. operations = {
  29. '==': lambda x, y: x == y,
  30. '===': lambda x, y: x == y,
  31. '~=': lambda x, y: x == y or x > y,
  32. '!=': lambda x, y: x != y,
  33. '<': lambda x, y: x < y,
  34. '<=': lambda x, y: x == y or x < y,
  35. '>': lambda x, y: x > y,
  36. '>=': lambda x, y: x == y or x > y,
  37. 'and': lambda x, y: x and y,
  38. 'or': lambda x, y: x or y,
  39. 'in': lambda x, y: x in y,
  40. 'not in': lambda x, y: x not in y,
  41. }
  42. def evaluate(self, expr, context):
  43. """
  44. Evaluate a marker expression returned by the :func:`parse_requirement`
  45. function in the specified context.
  46. """
  47. if isinstance(expr, string_types):
  48. if expr[0] in '\'"':
  49. result = expr[1:-1]
  50. else:
  51. if expr not in context:
  52. raise SyntaxError('unknown variable: %s' % expr)
  53. result = context[expr]
  54. else:
  55. assert isinstance(expr, dict)
  56. op = expr['op']
  57. if op not in self.operations:
  58. raise NotImplementedError('op not implemented: %s' % op)
  59. elhs = expr['lhs']
  60. erhs = expr['rhs']
  61. if _is_literal(expr['lhs']) and _is_literal(expr['rhs']):
  62. raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs))
  63. lhs = self.evaluate(elhs, context)
  64. rhs = self.evaluate(erhs, context)
  65. result = self.operations[op](lhs, rhs)
  66. return result
  67. def default_context():
  68. def format_full_version(info):
  69. version = '%s.%s.%s' % (info.major, info.minor, info.micro)
  70. kind = info.releaselevel
  71. if kind != 'final':
  72. version += kind[0] + str(info.serial)
  73. return version
  74. if hasattr(sys, 'implementation'):
  75. implementation_version = format_full_version(sys.implementation.version)
  76. implementation_name = sys.implementation.name
  77. else:
  78. implementation_version = '0'
  79. implementation_name = ''
  80. result = {
  81. 'implementation_name': implementation_name,
  82. 'implementation_version': implementation_version,
  83. 'os_name': os.name,
  84. 'platform_machine': platform.machine(),
  85. 'platform_python_implementation': platform.python_implementation(),
  86. 'platform_release': platform.release(),
  87. 'platform_system': platform.system(),
  88. 'platform_version': platform.version(),
  89. 'platform_in_venv': str(in_venv()),
  90. 'python_full_version': platform.python_version(),
  91. 'python_version': platform.python_version()[:3],
  92. 'sys_platform': sys.platform,
  93. }
  94. return result
  95. DEFAULT_CONTEXT = default_context()
  96. del default_context
  97. evaluator = Evaluator()
  98. def interpret(marker, execution_context=None):
  99. """
  100. Interpret a marker and return a result depending on environment.
  101. :param marker: The marker to interpret.
  102. :type marker: str
  103. :param execution_context: The context used for name lookup.
  104. :type execution_context: mapping
  105. """
  106. try:
  107. expr, rest = parse_marker(marker)
  108. except Exception as e:
  109. raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e))
  110. if rest and rest[0] != '#':
  111. raise SyntaxError('unexpected trailing data in marker: %s: %s' % (marker, rest))
  112. context = dict(DEFAULT_CONTEXT)
  113. if execution_context:
  114. context.update(execution_context)
  115. return evaluator.evaluate(expr, context)