author |
Steve Losh <steve@stevelosh.com> |
date |
Sat, 18 Dec 2010 11:14:11 -0500 |
parents |
48cacfdc2ca6 |
children |
(none) |
from rope.base import ast, evaluate, builtins, pyobjects
from rope.refactor import patchedast, occurrences
class Wildcard(object):
def get_name(self):
"""Return the name of this wildcard"""
def matches(self, suspect, arg):
"""Return `True` if `suspect` matches this wildcard"""
class Suspect(object):
def __init__(self, pymodule, node, name):
self.name = name
self.pymodule = pymodule
self.node = node
class DefaultWildcard(object):
"""The default restructuring wildcard
The argument passed to this wildcard is in the
``key1=value1,key2=value2,...`` format. Possible keys are:
* name - for checking the reference
* type - for checking the type
* object - for checking the object
* instance - for checking types but similar to builtin isinstance
* exact - matching only occurrences with the same name as the wildcard
* unsure - matching unsure occurrences
"""
def __init__(self, project):
self.project = project
def get_name(self):
return 'default'
def matches(self, suspect, arg=''):
args = parse_arg(arg)
if not self._check_exact(args, suspect):
return False
if not self._check_object(args, suspect):
return False
return True
def _check_object(self, args, suspect):
kind = None
expected = None
unsure = args.get('unsure', False)
for check in ['name', 'object', 'type', 'instance']:
if check in args:
kind = check
expected = args[check]
if expected is not None:
checker = _CheckObject(self.project, expected,
kind, unsure=unsure)
return checker(suspect.pymodule, suspect.node)
return True
def _check_exact(self, args, suspect):
node = suspect.node
if args.get('exact'):
if not isinstance(node, ast.Name) or not node.id == suspect.name:
return False
else:
if not isinstance(node, ast.expr):
return False
return True
def parse_arg(arg):
if isinstance(arg, dict):
return arg
result = {}
tokens = arg.split(',')
for token in tokens:
if '=' in token:
parts = token.split('=', 1)
result[parts[0].strip()] = parts[1].strip()
else:
result[token.strip()] = True
return result
class _CheckObject(object):
def __init__(self, project, expected, kind='object', unsure=False):
self.project = project
self.kind = kind
self.unsure = unsure
self.expected = self._evaluate(expected)
def __call__(self, pymodule, node):
pyname = self._evaluate_node(pymodule, node)
if pyname is None or self.expected is None:
return self.unsure
if self._unsure_pyname(pyname, unbound=self.kind=='name'):
return True
if self.kind == 'name':
return self._same_pyname(self.expected, pyname)
else:
pyobject = pyname.get_object()
if self.kind == 'object':
objects = [pyobject]
if self.kind == 'type':
objects = [pyobject.get_type()]
if self.kind == 'instance':
objects = [pyobject]
objects.extend(self._get_super_classes(pyobject))
objects.extend(self._get_super_classes(pyobject.get_type()))
for pyobject in objects:
if self._same_pyobject(self.expected.get_object(), pyobject):
return True
return False
def _get_super_classes(self, pyobject):
result = []
if isinstance(pyobject, pyobjects.AbstractClass):
for superclass in pyobject.get_superclasses():
result.append(superclass)
result.extend(self._get_super_classes(superclass))
return result
def _same_pyobject(self, expected, pyobject):
return expected == pyobject
def _same_pyname(self, expected, pyname):
return occurrences.same_pyname(expected, pyname)
def _unsure_pyname(self, pyname, unbound=True):
return self.unsure and occurrences.unsure_pyname(pyname, unbound)
def _split_name(self, name):
parts = name.split('.')
expression, kind = parts[0], parts[-1]
if len(parts) == 1:
kind = 'name'
return expression, kind
def _evaluate_node(self, pymodule, node):
scope = pymodule.get_scope().get_inner_scope_for_line(node.lineno)
expression = node
if isinstance(expression, ast.Name) and \
isinstance(expression.ctx, ast.Store):
start, end = patchedast.node_region(expression)
text = pymodule.source_code[start:end]
return evaluate.eval_str(scope, text)
else:
return evaluate.eval_node(scope, expression)
def _evaluate(self, code):
attributes = code.split('.')
pyname = None
if attributes[0] in ('__builtin__', '__builtins__'):
class _BuiltinsStub(object):
def get_attribute(self, name):
return builtins.builtins[name]
def __getitem__(self, name):
return builtins.builtins[name]
def __contains__(self, name):
return name in builtins.builtins
pyobject = _BuiltinsStub()
else:
pyobject = self.project.pycore.get_module(attributes[0])
for attribute in attributes[1:]:
pyname = pyobject[attribute]
if pyname is None:
return None
pyobject = pyname.get_object()
return pyname