Let us walk on the 3-isogeny graph
Loading...
Searching...
No Matches
markers.py
Go to the documentation of this file.
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"""
8Parser for the environment markers micro-language defined in PEP 508.
9"""
10
11# Note: In PEP 345, the micro-language was Python compatible, so the ast
12# module could be used to parse it. However, PEP 508 introduced operators such
13# as ~= and === which aren't in Python, necessitating a different approach.
14
15import os
16import re
17import sys
18import platform
19
20from .compat import string_types
21from .util import in_venv, parse_marker
22from .version import NormalizedVersion as NV
23
24__all__ = ['interpret']
25
26_VERSION_PATTERN = re.compile(r'((\d+(\.\d+)*\w*)|\'(\d+(\.\d+)*\w*)\'|\"(\d+(\.\d+)*\w*)\")')
27
29 if not isinstance(o, string_types) or not o:
30 return False
31 return o[0] in '\'"'
32
34 result = []
35 for m in _VERSION_PATTERN.finditer(s):
37 return set(result)
38
39class Evaluator(object):
40 """
41 This class is used to evaluate marker expessions.
42 """
43
44 operations = {
45 '==': lambda x, y: x == y,
46 '===': lambda x, y: x == y,
47 '~=': lambda x, y: x == y or x > y,
48 '!=': lambda x, y: x != y,
49 '<': lambda x, y: x < y,
50 '<=': lambda x, y: x == y or x < y,
51 '>': lambda x, y: x > y,
52 '>=': lambda x, y: x == y or x > y,
53 'and': lambda x, y: x and y,
54 'or': lambda x, y: x or y,
55 'in': lambda x, y: x in y,
56 'not in': lambda x, y: x not in y,
57 }
58
59 def evaluate(self, expr, context):
60 """
61 Evaluate a marker expression returned by the :func:`parse_requirement`
62 function in the specified context.
63 """
64 if isinstance(expr, string_types):
65 if expr[0] in '\'"':
66 result = expr[1:-1]
67 else:
68 if expr not in context:
69 raise SyntaxError('unknown variable: %s' % expr)
70 result = context[expr]
71 else:
72 assert isinstance(expr, dict)
73 op = expr['op']
74 if op not in self.operations:
75 raise NotImplementedError('op not implemented: %s' % op)
76 elhs = expr['lhs']
77 erhs = expr['rhs']
78 if _is_literal(expr['lhs']) and _is_literal(expr['rhs']):
79 raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs))
80
81 lhs = self.evaluate(elhs, context)
82 rhs = self.evaluate(erhs, context)
83 if ((elhs == 'python_version' or erhs == 'python_version') and
84 op in ('<', '<=', '>', '>=', '===', '==', '!=', '~=')):
85 lhs = NV(lhs)
86 rhs = NV(rhs)
87 elif elhs == 'python_version' and op in ('in', 'not in'):
88 lhs = NV(lhs)
89 rhs = _get_versions(rhs)
90 result = self.operations[op](lhs, rhs)
91 return result
92
93_DIGITS = re.compile(r'\d+\.\d+')
94
96 def format_full_version(info):
97 version = '%s.%s.%s' % (info.major, info.minor, info.micro)
99 if kind != 'final':
100 version += kind[0] + str(info.serial)
101 return version
102
103 if hasattr(sys, 'implementation'):
104 implementation_version = format_full_version(sys.implementation.version)
105 implementation_name = sys.implementation.name
106 else:
107 implementation_version = '0'
108 implementation_name = ''
109
111 m = _DIGITS.match(ppv)
112 pv = m.group(0)
113 result = {
114 'implementation_name': implementation_name,
115 'implementation_version': implementation_version,
116 'os_name': os.name,
117 'platform_machine': platform.machine(),
118 'platform_python_implementation': platform.python_implementation(),
119 'platform_release': platform.release(),
120 'platform_system': platform.system(),
121 'platform_version': platform.version(),
122 'platform_in_venv': str(in_venv()),
123 'python_full_version': ppv,
124 'python_version': pv,
125 'sys_platform': sys.platform,
126 }
127 return result
128
129DEFAULT_CONTEXT = default_context()
130del default_context
131
132evaluator = Evaluator()
133
134def interpret(marker, execution_context=None):
135 """
136 Interpret a marker and return a result depending on environment.
137
138 :param marker: The marker to interpret.
139 :type marker: str
140 :param execution_context: The context used for name lookup.
141 :type execution_context: mapping
142 """
143 try:
144 expr, rest = parse_marker(marker)
145 except Exception as e:
146 raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e))
147 if rest and rest[0] != '#':
148 raise SyntaxError('unexpected trailing data in marker: %s: %s' % (marker, rest))
149 context = dict(DEFAULT_CONTEXT)
150 if execution_context:
151 context.update(execution_context)
152 return evaluator.evaluate(expr, context)
evaluate(self, expr, context)
Definition markers.py:59
for i