text: # -*- coding: utf-8 -*-
  #
  # Copyright (C) 2012-2017 Vinay Sajip.
  # Licensed to the Python Software Foundation under a contributor agreement.
  # See LICENSE.txt and CONTRIBUTORS.txt.
  #
  """
  Parser for the environment markers micro-language defined in PEP 508.
  """
  
  # Note: In PEP 345, the micro-language was Python compatible, so the ast
  # module could be used to parse it. However, PEP 508 introduced operators such
  # as ~= and === which aren't in Python, necessitating a different approach.
  
  import os
  import sys
  import platform
  import re
  
  from .compat import python_implementation, urlparse, string_types
  from .util import in_venv, parse_marker
  
  __all__ = ['interpret']
  
  def _is_literal(o):
      if not isinstance(o, string_types) or not o:
          return False
      return o[0] in '\'"'
  
  class Evaluator(object):
      """
      This class is used to evaluate marker expessions.
      """
  
      operations = {
          '==': lambda x, y: x == y,
          '===': lambda x, y: x == y,
          '~=': lambda x, y: x == y or x > y,
          '!=': lambda x, y: x != y,
          '<':  lambda x, y: x < y,
          '<=':  lambda x, y: x == y or x < y,
          '>':  lambda x, y: x > y,
          '>=':  lambda x, y: x == y or x > y,
          'and': lambda x, y: x and y,
          'or': lambda x, y: x or y,
          'in': lambda x, y: x in y,
          'not in': lambda x, y: x not in y,
      }
  
      def evaluate(self, expr, context):
          """
          Evaluate a marker expression returned by the :func:`parse_requirement`
          function in the specified context.
          """
          if isinstance(expr, string_types):
              if expr[0] in '\'"':
                  result = expr[1:-1]
              else:
                  if expr not in context:
                      raise SyntaxError('unknown variable: %s' % expr)
                  result = context[expr]
          else:
              assert isinstance(expr, dict)
              op = expr['op']
              if op not in self.operations:
                  raise NotImplementedError('op not implemented: %s' % op)
              elhs = expr['lhs']
              erhs = expr['rhs']
              if _is_literal(expr['lhs']) and _is_literal(expr['rhs']):
                  raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs))
  
              lhs = self.evaluate(elhs, context)
              rhs = self.evaluate(erhs, context)
              result = self.operations[op](lhs, rhs)
          return result
  
  def default_context():
      def format_full_version(info):
          version = '%s.%s.%s' % (info.major, info.minor, info.micro)
          kind = info.releaselevel
          if kind != 'final':
              version += kind[0] + str(info.serial)
          return version
  
      if hasattr(sys, 'implementation'):
          implementation_version = format_full_version(sys.implementation.version)
          implementation_name = sys.implementation.name
      else:
          implementation_version = '0'
          implementation_name = ''
  
      result = {
          'implementation_name': implementation_name,
          'implementation_version': implementation_version,
          'os_name': os.name,
          'platform_machine': platform.machine(),
          'platform_python_implementation': platform.python_implementation(),
          'platform_release': platform.release(),
          'platform_system': platform.system(),
          'platform_version': platform.version(),
          'platform_in_venv': str(in_venv()),
          'python_full_version': platform.python_version(),
          'python_version': platform.python_version()[:3],
          'sys_platform': sys.platform,
      }
      return result
  
  DEFAULT_CONTEXT = default_context()
  del default_context
  
  evaluator = Evaluator()
  
  def interpret(marker, execution_context=None):
      """
      Interpret a marker and return a result depending on environment.
  
      :param marker: The marker to interpret.
      :type marker: str
      :param execution_context: The context used for name lookup.
      :type execution_context: mapping
      """
      try:
          expr, rest = parse_marker(marker)
      except Exception as e:
          raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e))
      if rest and rest[0] != '#':
          raise SyntaxError('unexpected trailing tmp in marker: %s: %s' % (marker, rest))
      context = dict(DEFAULT_CONTEXT)
      if execution_context:
          context.update(execution_context)
      return evaluator.evaluate(expr, context)
  