~ubuntu-branches/debian/jessie/python-pip/jessie

« back to all changes in this revision

Viewing changes to pip/vendor/distlib/markers.py

  • Committer: Package Import Robot
  • Author(s): Barry Warsaw
  • Date: 2013-08-19 18:33:23 UTC
  • mfrom: (1.2.5)
  • Revision ID: package-import@ubuntu.com-20130819183323-8xyoldb2798iil6e
Tags: 1.4.1-1
* Team upload.
* New upstream release.
  - d/control: Update Standards-Version to 3.9.4 with no additional
    changes required.
  - d/patches/no-python-specific-scripts.patch: Refreshed.
  - d/patches/format_egg_string.patch: Refreshed.
  - d/patches/system-ca-certificates.patch: Refreshed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# Copyright (C) 2012-2013 Vinay Sajip.
 
4
# Licensed to the Python Software Foundation under a contributor agreement.
 
5
# See LICENSE.txt and CONTRIBUTORS.txt.
 
6
#
 
7
"""Parser for the environment markers micro-language defined in PEP 345."""
 
8
 
 
9
import ast
 
10
import os
 
11
import sys
 
12
import platform
 
13
 
 
14
from .compat import python_implementation, string_types
 
15
from .util import in_venv
 
16
 
 
17
__all__ = ['interpret']
 
18
 
 
19
class Evaluator(object):
 
20
    """
 
21
    A limited evaluator for Python expressions.
 
22
    """
 
23
 
 
24
    operators = {
 
25
        'eq': lambda x, y: x == y,
 
26
        'gt': lambda x, y: x > y,
 
27
        'gte': lambda x, y: x >= y,
 
28
        'in': lambda x, y: x in y,
 
29
        'lt': lambda x, y: x < y,
 
30
        'lte': lambda x, y: x <= y,
 
31
        'not': lambda x: not x,
 
32
        'noteq': lambda x, y: x != y,
 
33
        'notin': lambda x, y: x not in y,
 
34
    }
 
35
 
 
36
    allowed_values = {
 
37
        'sys.platform': sys.platform,
 
38
        'python_version': '%s.%s' % sys.version_info[:2],
 
39
        # parsing sys.platform is not reliable, but there is no other
 
40
        # way to get e.g. 2.7.2+, and the PEP is defined with sys.version
 
41
        'python_full_version': sys.version.split(' ', 1)[0],
 
42
        'os.name': os.name,
 
43
        'platform.in_venv': str(in_venv()),
 
44
        'platform.version': platform.version(),
 
45
        'platform.machine': platform.machine(),
 
46
        'platform.python_implementation': platform.python_implementation(),
 
47
    }
 
48
 
 
49
    def __init__(self, context=None):
 
50
        """
 
51
        Initialise an instance.
 
52
 
 
53
        :param context: If specified, names are looked up in this mapping.
 
54
        """
 
55
        self.context = context or {}
 
56
        self.source = None
 
57
 
 
58
    def get_fragment(self, offset):
 
59
        """
 
60
        Get the part of the source which is causing a problem.
 
61
        """
 
62
        fragment_len = 10
 
63
        s = '%r' % (self.source[offset:offset + fragment_len])
 
64
        if offset + fragment_len < len(self.source):
 
65
            s += '...'
 
66
        return s
 
67
 
 
68
    def get_handler(self, node_type):
 
69
        """
 
70
        Get a handler for the specified AST node type.
 
71
        """
 
72
        return getattr(self, 'do_%s' % node_type, None)
 
73
 
 
74
    def evaluate(self, node, filename=None):
 
75
        """
 
76
        Evaluate a source string or node, using ``filename`` when
 
77
        displaying errors.
 
78
        """
 
79
        if isinstance(node, string_types):
 
80
            self.source = node
 
81
            kwargs = {'mode': 'eval'}
 
82
            if filename:
 
83
                kwargs['filename'] = filename
 
84
            try:
 
85
                node = ast.parse(node, **kwargs)
 
86
            except SyntaxError as e:
 
87
                s = self.get_fragment(e.offset)
 
88
                raise SyntaxError('syntax error %s' % s)
 
89
        node_type = node.__class__.__name__.lower()
 
90
        handler = self.get_handler(node_type)
 
91
        if handler is None:
 
92
            if self.source is None:
 
93
                s = '(source not available)'
 
94
            else:
 
95
                s = self.get_fragment(node.col_offset)
 
96
            raise SyntaxError("don't know how to evaluate %r %s" % (
 
97
                node_type, s))
 
98
        return handler(node)
 
99
 
 
100
    def get_attr_key(self, node):
 
101
        assert isinstance(node, ast.Attribute), 'attribute node expected'
 
102
        return '%s.%s' % (node.value.id, node.attr)
 
103
 
 
104
    def do_attribute(self, node):
 
105
        valid = True
 
106
        if not isinstance(node.value, ast.Name):
 
107
            valid = False
 
108
        else:
 
109
            key = self.get_attr_key(node)
 
110
            valid = key in self.context or key in self.allowed_values
 
111
        if not valid:
 
112
            raise SyntaxError('invalid expression: %s' % key)
 
113
        if key in self.context:
 
114
            result = self.context[key]
 
115
        else:
 
116
            result = self.allowed_values[key]
 
117
        return result
 
118
 
 
119
    def do_boolop(self, node):
 
120
        result = self.evaluate(node.values[0])
 
121
        is_or = node.op.__class__ is ast.Or
 
122
        is_and = node.op.__class__ is ast.And
 
123
        assert is_or or is_and
 
124
        if (is_and and result) or (is_or and not result):
 
125
            for n in node.values[1:]:
 
126
                result = self.evaluate(n)
 
127
                if (is_or and result) or (is_and and not result):
 
128
                    break
 
129
        return result
 
130
 
 
131
    def do_compare(self, node):
 
132
        def sanity_check(lhsnode, rhsnode):
 
133
            valid = True
 
134
            if isinstance(lhsnode, ast.Str) and isinstance(rhsnode, ast.Str):
 
135
                valid = False
 
136
            elif (isinstance(lhsnode, ast.Attribute)
 
137
                  and isinstance(rhsnode, ast.Attribute)):
 
138
                klhs = self.get_attr_key(lhsnode)
 
139
                krhs = self.get_attr_key(rhsnode)
 
140
                valid = klhs != krhs
 
141
            if not valid:
 
142
                s = self.get_fragment(node.col_offset)
 
143
                raise SyntaxError('Invalid comparison: %s' % s)
 
144
 
 
145
        lhsnode = node.left
 
146
        lhs = self.evaluate(lhsnode)
 
147
        result = True
 
148
        for op, rhsnode in zip(node.ops, node.comparators):
 
149
            sanity_check(lhsnode, rhsnode)
 
150
            op = op.__class__.__name__.lower()
 
151
            if op not in self.operators:
 
152
                raise SyntaxError('unsupported operation: %r' % op)
 
153
            rhs = self.evaluate(rhsnode)
 
154
            result = self.operators[op](lhs, rhs)
 
155
            if not result:
 
156
                break
 
157
            lhs = rhs
 
158
            lhsnode = rhsnode
 
159
        return result
 
160
 
 
161
    def do_expression(self, node):
 
162
        return self.evaluate(node.body)
 
163
 
 
164
    def do_name(self, node):
 
165
        valid = False
 
166
        if node.id in self.context:
 
167
            valid = True
 
168
            result = self.context[node.id]
 
169
        elif node.id in self.allowed_values:
 
170
            valid = True
 
171
            result = self.allowed_values[node.id]
 
172
        if not valid:
 
173
            raise SyntaxError('invalid expression: %s' % node.id)
 
174
        return result
 
175
 
 
176
    def do_str(self, node):
 
177
        return node.s
 
178
 
 
179
 
 
180
def interpret(marker, execution_context=None):
 
181
    """
 
182
    Interpret a marker and return a result depending on environment.
 
183
 
 
184
    :param marker: The marker to interpret.
 
185
    :type marker: str
 
186
    :param execution_context: The context used for name lookup.
 
187
    :type execution_context: mapping
 
188
    """
 
189
    return Evaluator(execution_context).evaluate(marker.strip())