ยปCore Development>Code coverage>Lib/packaging/markers.py

Python code coverage for Lib/packaging/markers.py

#countcontent
1n/a"""Parser for the environment markers micro-language defined in PEP 345."""
2n/a
3n/aimport os
4n/aimport sys
5n/aimport platform
6n/afrom io import BytesIO
7n/afrom tokenize import tokenize, NAME, OP, STRING, ENDMARKER, ENCODING
8n/a
9n/a__all__ = ['interpret']
10n/a
11n/a
12n/a# allowed operators
13n/a_OPERATORS = {'==': lambda x, y: x == y,
14n/a '!=': lambda x, y: x != y,
15n/a '>': lambda x, y: x > y,
16n/a '>=': lambda x, y: x >= y,
17n/a '<': lambda x, y: x < y,
18n/a '<=': lambda x, y: x <= y,
19n/a 'in': lambda x, y: x in y,
20n/a 'not in': lambda x, y: x not in y}
21n/a
22n/a
23n/adef _operate(operation, x, y):
24n/a return _OPERATORS[operation](x, y)
25n/a
26n/a
27n/a# restricted set of variables
28n/a_VARS = {'sys.platform': sys.platform,
29n/a 'python_version': '%s.%s' % sys.version_info[:2],
30n/a # FIXME parsing sys.platform is not reliable, but there is no other
31n/a # way to get e.g. 2.7.2+, and the PEP is defined with sys.version
32n/a 'python_full_version': sys.version.split(' ', 1)[0],
33n/a 'os.name': os.name,
34n/a 'platform.version': platform.version(),
35n/a 'platform.machine': platform.machine(),
36n/a 'platform.python_implementation': platform.python_implementation(),
37n/a }
38n/a
39n/a
40n/aclass _Operation:
41n/a
42n/a def __init__(self, execution_context=None):
43n/a self.left = None
44n/a self.op = None
45n/a self.right = None
46n/a if execution_context is None:
47n/a execution_context = {}
48n/a self.execution_context = execution_context
49n/a
50n/a def _get_var(self, name):
51n/a if name in self.execution_context:
52n/a return self.execution_context[name]
53n/a return _VARS[name]
54n/a
55n/a def __repr__(self):
56n/a return '%s %s %s' % (self.left, self.op, self.right)
57n/a
58n/a def _is_string(self, value):
59n/a if value is None or len(value) < 2:
60n/a return False
61n/a for delimiter in '"\'':
62n/a if value[0] == value[-1] == delimiter:
63n/a return True
64n/a return False
65n/a
66n/a def _is_name(self, value):
67n/a return value in _VARS
68n/a
69n/a def _convert(self, value):
70n/a if value in _VARS:
71n/a return self._get_var(value)
72n/a return value.strip('"\'')
73n/a
74n/a def _check_name(self, value):
75n/a if value not in _VARS:
76n/a raise NameError(value)
77n/a
78n/a def _nonsense_op(self):
79n/a msg = 'This operation is not supported : "%s"' % self
80n/a raise SyntaxError(msg)
81n/a
82n/a def __call__(self):
83n/a # make sure we do something useful
84n/a if self._is_string(self.left):
85n/a if self._is_string(self.right):
86n/a self._nonsense_op()
87n/a self._check_name(self.right)
88n/a else:
89n/a if not self._is_string(self.right):
90n/a self._nonsense_op()
91n/a self._check_name(self.left)
92n/a
93n/a if self.op not in _OPERATORS:
94n/a raise TypeError('Operator not supported "%s"' % self.op)
95n/a
96n/a left = self._convert(self.left)
97n/a right = self._convert(self.right)
98n/a return _operate(self.op, left, right)
99n/a
100n/a
101n/aclass _OR:
102n/a def __init__(self, left, right=None):
103n/a self.left = left
104n/a self.right = right
105n/a
106n/a def filled(self):
107n/a return self.right is not None
108n/a
109n/a def __repr__(self):
110n/a return 'OR(%r, %r)' % (self.left, self.right)
111n/a
112n/a def __call__(self):
113n/a return self.left() or self.right()
114n/a
115n/a
116n/aclass _AND:
117n/a def __init__(self, left, right=None):
118n/a self.left = left
119n/a self.right = right
120n/a
121n/a def filled(self):
122n/a return self.right is not None
123n/a
124n/a def __repr__(self):
125n/a return 'AND(%r, %r)' % (self.left, self.right)
126n/a
127n/a def __call__(self):
128n/a return self.left() and self.right()
129n/a
130n/a
131n/adef interpret(marker, execution_context=None):
132n/a """Interpret a marker and return a result depending on environment."""
133n/a marker = marker.strip().encode()
134n/a ops = []
135n/a op_starting = True
136n/a for token in tokenize(BytesIO(marker).readline):
137n/a # Unpack token
138n/a toktype, tokval, rowcol, line, logical_line = token
139n/a if toktype not in (NAME, OP, STRING, ENDMARKER, ENCODING):
140n/a raise SyntaxError('Type not supported "%s"' % tokval)
141n/a
142n/a if op_starting:
143n/a op = _Operation(execution_context)
144n/a if len(ops) > 0:
145n/a last = ops[-1]
146n/a if isinstance(last, (_OR, _AND)) and not last.filled():
147n/a last.right = op
148n/a else:
149n/a ops.append(op)
150n/a else:
151n/a ops.append(op)
152n/a op_starting = False
153n/a else:
154n/a op = ops[-1]
155n/a
156n/a if (toktype == ENDMARKER or
157n/a (toktype == NAME and tokval in ('and', 'or'))):
158n/a if toktype == NAME and tokval == 'and':
159n/a ops.append(_AND(ops.pop()))
160n/a elif toktype == NAME and tokval == 'or':
161n/a ops.append(_OR(ops.pop()))
162n/a op_starting = True
163n/a continue
164n/a
165n/a if isinstance(op, (_OR, _AND)) and op.right is not None:
166n/a op = op.right
167n/a
168n/a if ((toktype in (NAME, STRING) and tokval not in ('in', 'not'))
169n/a or (toktype == OP and tokval == '.')):
170n/a if op.op is None:
171n/a if op.left is None:
172n/a op.left = tokval
173n/a else:
174n/a op.left += tokval
175n/a else:
176n/a if op.right is None:
177n/a op.right = tokval
178n/a else:
179n/a op.right += tokval
180n/a elif toktype == OP or tokval in ('in', 'not'):
181n/a if tokval == 'in' and op.op == 'not':
182n/a op.op = 'not in'
183n/a else:
184n/a op.op = tokval
185n/a
186n/a for op in ops:
187n/a if not op():
188n/a return False
189n/a return True