Commit 9ebbe014 authored by Daniel Holth's avatar Daniel Holth

impractical to support _markerlib on Python < 2.6 (no compile(ast))

--HG--
branch : distribute
extra : rebase_source : c5019294d83fab26bc393fe72f086d0b13b1e337
parent 4095eb5d
"""Used by pkg_resources to interpret PEP 345 environment markers."""
from _markerlib.markers import default_environment, compile, interpret, as_function
# -*- coding: utf-8 -*-
"""
Just enough of ast.py for markers.py
"""
from _ast import AST, PyCF_ONLY_AST
def parse(source, filename='<unknown>', mode='exec'):
"""
Parse the source into an AST node.
Equivalent to compile(source, filename, mode, PyCF_ONLY_AST).
"""
return compile(source, filename, mode, PyCF_ONLY_AST)
def copy_location(new_node, old_node):
"""
Copy source location (`lineno` and `col_offset` attributes) from
*old_node* to *new_node* if possible, and return *new_node*.
"""
for attr in 'lineno', 'col_offset':
if attr in old_node._attributes and attr in new_node._attributes \
and hasattr(old_node, attr):
setattr(new_node, attr, getattr(old_node, attr))
return new_node
def iter_fields(node):
"""
Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields``
that is present on *node*.
"""
for field in node._fields:
try:
yield field, getattr(node, field)
except AttributeError:
pass
class NodeVisitor(object):
"""
A node visitor base class that walks the abstract syntax tree and calls a
visitor function for every node found. This function may return a value
which is forwarded by the `visit` method.
This class is meant to be subclassed, with the subclass adding visitor
methods.
Per default the visitor functions for the nodes are ``'visit_'`` +
class name of the node. So a `TryFinally` node visit function would
be `visit_TryFinally`. This behavior can be changed by overriding
the `visit` method. If no visitor function exists for a node
(return value `None`) the `generic_visit` visitor is used instead.
Don't use the `NodeVisitor` if you want to apply changes to nodes during
traversing. For this a special visitor exists (`NodeTransformer`) that
allows modifications.
"""
def visit(self, node):
"""Visit a node."""
method = 'visit_' + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
return visitor(node)
# def generic_visit(self, node):
# """Called if no explicit visitor function exists for a node."""
# for field, value in iter_fields(node):
# if isinstance(value, list):
# for item in value:
# if isinstance(item, AST):
# self.visit(item)
# elif isinstance(value, AST):
# self.visit(value)
class NodeTransformer(NodeVisitor):
"""
A :class:`NodeVisitor` subclass that walks the abstract syntax tree and
allows modification of nodes.
The `NodeTransformer` will walk the AST and use the return value of the
visitor methods to replace or remove the old node. If the return value of
the visitor method is ``None``, the node will be removed from its location,
otherwise it is replaced with the return value. The return value may be the
original node in which case no replacement takes place.
Here is an example transformer that rewrites all occurrences of name lookups
(``foo``) to ``data['foo']``::
class RewriteName(NodeTransformer):
def visit_Name(self, node):
return copy_location(Subscript(
value=Name(id='data', ctx=Load()),
slice=Index(value=Str(s=node.id)),
ctx=node.ctx
), node)
Keep in mind that if the node you're operating on has child nodes you must
either transform the child nodes yourself or call the :meth:`generic_visit`
method for the node first.
For nodes that were part of a collection of statements (that applies to all
statement nodes), the visitor may also return a list of nodes rather than
just a single node.
Usually you use the transformer like this::
node = YourTransformer().visit(node)
"""
def generic_visit(self, node):
for field, old_value in iter_fields(node):
old_value = getattr(node, field, None)
if isinstance(old_value, list):
new_values = []
for value in old_value:
if isinstance(value, AST):
value = self.visit(value)
if value is None:
continue
elif not isinstance(value, AST):
new_values.extend(value)
continue
new_values.append(value)
old_value[:] = new_values
elif isinstance(old_value, AST):
new_node = self.visit(old_value)
if new_node is None:
delattr(node, field)
else:
setattr(node, field, new_node)
return node
\ No newline at end of file
......@@ -12,17 +12,13 @@ where EXPR belongs to any of those:
platform.version = platform.version()
platform.machine = platform.machine()
platform.python_implementation = platform.python_implementation()
a free string, like '2.4', or 'win32'
a free string, like '2.6', or 'win32'
"""
__all__ = ['default_environment', 'compile', 'interpret']
# Would import from ast but for Python 2.5
from _ast import Compare, BoolOp, Attribute, Name, Load, Str, cmpop, boolop
try:
from ast import parse, copy_location, NodeTransformer
except ImportError: # pragma no coverage
from markerlib._markers_ast import parse, copy_location, NodeTransformer
from ast import Compare, BoolOp, Attribute, Name, Load, Str, cmpop, boolop
from ast import parse, copy_location, NodeTransformer
import os
import platform
......@@ -104,7 +100,5 @@ def compile(marker):
_cache[marker] = marker_fn
return _cache[marker]
as_function = compile # bw compat
def interpret(marker, environment=None):
return compile(marker)(environment)
......@@ -2489,9 +2489,9 @@ class DistInfoDistribution(Distribution):
marker_fn.__doc__ = marker
return marker_fn
try:
from _markerlib import as_function
from _markerlib import compile as compile_marker
except ImportError:
as_function = dummy_marker
compile_marker = dummy_marker
dm = self.__dep_map = {None: []}
reqs = []
......@@ -2499,7 +2499,7 @@ class DistInfoDistribution(Distribution):
for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
distvers, mark = self._preparse_requirement(req)
parsed = parse_requirements(distvers).next()
parsed.marker_fn = as_function(mark)
parsed.marker_fn = compile_marker(mark)
reqs.append(parsed)
def reqs_for_extra(extra):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment