forked from VimPlug/jedi
Remove the module path from the parser tree.
Some static analysis tests are still failing.
This commit is contained in:
@@ -142,7 +142,11 @@ class Script(object):
|
|||||||
|
|
||||||
@cache.memoize_method
|
@cache.memoize_method
|
||||||
def _get_module(self):
|
def _get_module(self):
|
||||||
module = er.ModuleContext(self._evaluator, self._get_module_node())
|
module = er.ModuleContext(
|
||||||
|
self._evaluator,
|
||||||
|
self._get_module_node(),
|
||||||
|
self.path
|
||||||
|
)
|
||||||
imports.add_module(self._evaluator, module.name.string_name, module)
|
imports.add_module(self._evaluator, module.name.string_name, module)
|
||||||
return module
|
return module
|
||||||
|
|
||||||
@@ -398,7 +402,8 @@ class Interpreter(Script):
|
|||||||
return interpreter.MixedModuleContext(
|
return interpreter.MixedModuleContext(
|
||||||
self._evaluator,
|
self._evaluator,
|
||||||
parser_module,
|
parser_module,
|
||||||
self.namespaces
|
self.namespaces,
|
||||||
|
path=self.path
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ def cache_call_signatures(evaluator, context, bracket_leaf, code_lines, user_pos
|
|||||||
whole = '\n'.join(other_lines + [before_cursor])
|
whole = '\n'.join(other_lines + [before_cursor])
|
||||||
before_bracket = re.match(r'.*\(', whole, re.DOTALL)
|
before_bracket = re.match(r'.*\(', whole, re.DOTALL)
|
||||||
|
|
||||||
module_path = bracket_leaf.get_root_node().path
|
module_path = context.get_root_context().py__file__()
|
||||||
if module_path is None:
|
if module_path is None:
|
||||||
yield None # Don't cache!
|
yield None # Don't cache!
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ class MixedModuleContext(Context):
|
|||||||
resets_positions = True
|
resets_positions = True
|
||||||
type = 'mixed_module'
|
type = 'mixed_module'
|
||||||
|
|
||||||
def __init__(self, evaluator, tree_module, namespaces):
|
def __init__(self, evaluator, tree_module, namespaces, path):
|
||||||
self.evaluator = evaluator
|
self.evaluator = evaluator
|
||||||
self._namespaces = namespaces
|
self._namespaces = namespaces
|
||||||
|
|
||||||
self._namespace_objects = [type('jedi_namespace', (), n) for n in namespaces]
|
self._namespace_objects = [type('jedi_namespace', (), n) for n in namespaces]
|
||||||
self._module_context = ModuleContext(evaluator, tree_module)
|
self._module_context = ModuleContext(evaluator, tree_module, path=path)
|
||||||
self.tree_node = tree_module
|
self.tree_node = tree_module
|
||||||
|
|
||||||
def get_node(self):
|
def get_node(self):
|
||||||
@@ -33,7 +33,7 @@ class MixedModuleContext(Context):
|
|||||||
self.evaluator,
|
self.evaluator,
|
||||||
parent_context=self,
|
parent_context=self,
|
||||||
compiled_object=compiled_object,
|
compiled_object=compiled_object,
|
||||||
tree_name=self.tree_node.name
|
tree_context=self._module_context
|
||||||
)
|
)
|
||||||
for filter in mixed_object.get_filters(*args, **kwargs):
|
for filter in mixed_object.get_filters(*args, **kwargs):
|
||||||
yield filter
|
yield filter
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ from jedi import debug
|
|||||||
from jedi.parser.python import tree
|
from jedi.parser.python import tree
|
||||||
from jedi.evaluate.compiled import CompiledObject
|
from jedi.evaluate.compiled import CompiledObject
|
||||||
|
|
||||||
from jedi.common import unite
|
|
||||||
|
|
||||||
|
|
||||||
CODES = {
|
CODES = {
|
||||||
'attribute-error': (1, AttributeError, 'Potential AttributeError.'),
|
'attribute-error': (1, AttributeError, 'Potential AttributeError.'),
|
||||||
@@ -82,7 +80,9 @@ def add(node_context, error_name, node, message=None, typ=Error, payload=None):
|
|||||||
if _check_for_exception_catch(node_context, node, exception, payload):
|
if _check_for_exception_catch(node_context, node, exception, payload):
|
||||||
return
|
return
|
||||||
|
|
||||||
module_path = node.get_root_node().path
|
# TODO this path is probably not right
|
||||||
|
module_context = node_context.get_root_context()
|
||||||
|
module_path = module_context.py__file__()
|
||||||
instance = typ(error_name, module_path, node.start_pos, message)
|
instance = typ(error_name, module_path, node.start_pos, message)
|
||||||
debug.warning(str(instance), format=False)
|
debug.warning(str(instance), format=False)
|
||||||
node_context.evaluator.analysis.append(instance)
|
node_context.evaluator.analysis.append(instance)
|
||||||
|
|||||||
@@ -29,25 +29,12 @@ class MixedObject(object):
|
|||||||
fewer special cases, because we in Python you don't have the same freedoms
|
fewer special cases, because we in Python you don't have the same freedoms
|
||||||
to modify the runtime.
|
to modify the runtime.
|
||||||
"""
|
"""
|
||||||
def __init__(self, evaluator, parent_context, compiled_object, tree_name):
|
def __init__(self, evaluator, parent_context, compiled_object, tree_context):
|
||||||
self.evaluator = evaluator
|
self.evaluator = evaluator
|
||||||
|
self.parent_context = parent_context
|
||||||
self.compiled_object = compiled_object
|
self.compiled_object = compiled_object
|
||||||
|
self._context = tree_context
|
||||||
self.obj = compiled_object.obj
|
self.obj = compiled_object.obj
|
||||||
self._tree_name = tree_name
|
|
||||||
name_module = tree_name.get_root_node()
|
|
||||||
if parent_context.tree_node.get_root_node() != name_module:
|
|
||||||
from jedi.evaluate.representation import ModuleContext
|
|
||||||
module_context = ModuleContext(evaluator, name_module)
|
|
||||||
name = compiled_object.get_root_context().py__name__()
|
|
||||||
imports.add_module(evaluator, name, module_context)
|
|
||||||
else:
|
|
||||||
module_context = parent_context.get_root_context()
|
|
||||||
|
|
||||||
self._context = module_context.create_context(
|
|
||||||
tree_name.parent,
|
|
||||||
node_is_context=True,
|
|
||||||
node_is_object=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# We have to overwrite everything that has to do with trailers, name
|
# We have to overwrite everything that has to do with trailers, name
|
||||||
# lookups and filters to make it possible to route name lookups towards
|
# lookups and filters to make it possible to route name lookups towards
|
||||||
@@ -132,10 +119,10 @@ def find_syntax_node_name(evaluator, python_object):
|
|||||||
path = inspect.getsourcefile(python_object)
|
path = inspect.getsourcefile(python_object)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# The type might not be known (e.g. class_with_dict.__weakref__)
|
# The type might not be known (e.g. class_with_dict.__weakref__)
|
||||||
return None
|
return None, None
|
||||||
if path is None or not os.path.exists(path):
|
if path is None or not os.path.exists(path):
|
||||||
# The path might not exist or be e.g. <stdin>.
|
# The path might not exist or be e.g. <stdin>.
|
||||||
return None
|
return None, None
|
||||||
|
|
||||||
module = _load_module(evaluator, path, python_object)
|
module = _load_module(evaluator, path, python_object)
|
||||||
|
|
||||||
@@ -143,17 +130,17 @@ def find_syntax_node_name(evaluator, python_object):
|
|||||||
# We don't need to check names for modules, because there's not really
|
# We don't need to check names for modules, because there's not really
|
||||||
# a way to write a module in a module in Python (and also __name__ can
|
# a way to write a module in a module in Python (and also __name__ can
|
||||||
# be something like ``email.utils``).
|
# be something like ``email.utils``).
|
||||||
return module.name
|
return module, path
|
||||||
|
|
||||||
name_str = python_object.__name__
|
name_str = python_object.__name__
|
||||||
if name_str == '<lambda>':
|
if name_str == '<lambda>':
|
||||||
return None # It's too hard to find lambdas.
|
return None, None # It's too hard to find lambdas.
|
||||||
|
|
||||||
# Doesn't always work (e.g. os.stat_result)
|
# Doesn't always work (e.g. os.stat_result)
|
||||||
try:
|
try:
|
||||||
names = module.used_names[name_str]
|
names = module.used_names[name_str]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None, None
|
||||||
names = [n for n in names if n.is_definition()]
|
names = [n for n in names if n.is_definition()]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -170,22 +157,44 @@ def find_syntax_node_name(evaluator, python_object):
|
|||||||
# There's a chance that the object is not available anymore, because
|
# There's a chance that the object is not available anymore, because
|
||||||
# the code has changed in the background.
|
# the code has changed in the background.
|
||||||
if line_names:
|
if line_names:
|
||||||
return line_names[-1]
|
return line_names[-1].parent, path
|
||||||
|
|
||||||
# It's really hard to actually get the right definition, here as a last
|
# It's really hard to actually get the right definition, here as a last
|
||||||
# resort we just return the last one. This chance might lead to odd
|
# resort we just return the last one. This chance might lead to odd
|
||||||
# completions at some points but will lead to mostly correct type
|
# completions at some points but will lead to mostly correct type
|
||||||
# inference, because people tend to define a public name in a module only
|
# inference, because people tend to define a public name in a module only
|
||||||
# once.
|
# once.
|
||||||
return names[-1]
|
return names[-1].parent, path
|
||||||
|
|
||||||
|
|
||||||
@compiled.compiled_objects_cache('mixed_cache')
|
@compiled.compiled_objects_cache('mixed_cache')
|
||||||
def create(evaluator, obj, parent_context=None, *args):
|
def create(evaluator, obj, parent_context=None, *args):
|
||||||
tree_name = find_syntax_node_name(evaluator, obj)
|
tree_node, path = find_syntax_node_name(evaluator, obj)
|
||||||
|
|
||||||
compiled_object = compiled.create(
|
compiled_object = compiled.create(
|
||||||
evaluator, obj, parent_context=parent_context.compiled_object)
|
evaluator, obj, parent_context=parent_context.compiled_object)
|
||||||
if tree_name is None:
|
if tree_node is None:
|
||||||
return compiled_object
|
return compiled_object
|
||||||
return MixedObject(evaluator, parent_context, compiled_object, tree_name)
|
|
||||||
|
module_node = tree_node.get_root_node()
|
||||||
|
if parent_context.tree_node.get_root_node() == module_node:
|
||||||
|
module_context = parent_context.get_root_context()
|
||||||
|
else:
|
||||||
|
from jedi.evaluate.representation import ModuleContext
|
||||||
|
module_context = ModuleContext(evaluator, module_node, path=path)
|
||||||
|
name = compiled_object.get_root_context().py__name__()
|
||||||
|
imports.add_module(evaluator, name, module_context)
|
||||||
|
|
||||||
|
tree_context = module_context.create_context(
|
||||||
|
tree_node,
|
||||||
|
node_is_context=True,
|
||||||
|
node_is_object=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return MixedObject(
|
||||||
|
evaluator,
|
||||||
|
parent_context,
|
||||||
|
compiled_object,
|
||||||
|
tree_context=tree_context
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -459,7 +459,7 @@ def _load_module(evaluator, path=None, code=None, sys_path=None, parent_module=N
|
|||||||
module_node = parse(code=code, path=path, cache=True, diff_cache=True)
|
module_node = parse(code=code, path=path, cache=True, diff_cache=True)
|
||||||
|
|
||||||
from jedi.evaluate.representation import ModuleContext
|
from jedi.evaluate.representation import ModuleContext
|
||||||
return ModuleContext(evaluator, module_node)
|
return ModuleContext(evaluator, module_node, path=path)
|
||||||
else:
|
else:
|
||||||
return compiled.load_module(evaluator, path)
|
return compiled.load_module(evaluator, path)
|
||||||
|
|
||||||
@@ -489,7 +489,7 @@ def get_modules_containing_name(evaluator, modules, name):
|
|||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
module_node = parser_cache_item.parser.get_root_node()
|
module_node = parser_cache_item.parser.get_root_node()
|
||||||
return er.ModuleContext(evaluator, module_node)
|
return er.ModuleContext(evaluator, module_node, path=path)
|
||||||
|
|
||||||
def check_fs(path):
|
def check_fs(path):
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
|
|||||||
@@ -150,7 +150,11 @@ def py__getitem__(context, typ, node):
|
|||||||
return context.eval_node(nodes[0])
|
return context.eval_node(nodes[0])
|
||||||
|
|
||||||
from jedi.evaluate.representation import ModuleContext
|
from jedi.evaluate.representation import ModuleContext
|
||||||
typing = ModuleContext(context.evaluator, _get_typing_replacement_module())
|
typing = ModuleContext(
|
||||||
|
context.evaluator,
|
||||||
|
module_node=_get_typing_replacement_module(),
|
||||||
|
path=None
|
||||||
|
)
|
||||||
factories = typing.py__getattribute__("factory")
|
factories = typing.py__getattribute__("factory")
|
||||||
assert len(factories) == 1
|
assert len(factories) == 1
|
||||||
factory = list(factories)[0]
|
factory = list(factories)[0]
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ from jedi.evaluate import imports
|
|||||||
from jedi.evaluate import helpers
|
from jedi.evaluate import helpers
|
||||||
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
|
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
|
||||||
GlobalNameFilter, DictFilter, ContextName, AbstractNameDefinition, \
|
GlobalNameFilter, DictFilter, ContextName, AbstractNameDefinition, \
|
||||||
ParamName, AnonymousInstanceParamName, TreeNameDefinition
|
ParamName, AnonymousInstanceParamName, TreeNameDefinition, \
|
||||||
|
ContextNameMixin
|
||||||
from jedi.evaluate.dynamic import search_params
|
from jedi.evaluate.dynamic import search_params
|
||||||
from jedi.evaluate import context
|
from jedi.evaluate import context
|
||||||
|
|
||||||
@@ -406,13 +407,26 @@ class ModuleAttributeName(AbstractNameDefinition):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleName(ContextNameMixin, AbstractNameDefinition):
|
||||||
|
start_pos = 1, 0
|
||||||
|
|
||||||
|
def __init__(self, context, name):
|
||||||
|
self._context = context
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string_name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
|
||||||
class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
||||||
api_type = 'module'
|
api_type = 'module'
|
||||||
parent_context = None
|
parent_context = None
|
||||||
|
|
||||||
def __init__(self, evaluator, module_node):
|
def __init__(self, evaluator, module_node, path):
|
||||||
super(ModuleContext, self).__init__(evaluator, parent_context=None)
|
super(ModuleContext, self).__init__(evaluator, parent_context=None)
|
||||||
self.tree_node = module_node
|
self.tree_node = module_node
|
||||||
|
self._path = path
|
||||||
|
|
||||||
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
||||||
yield ParserTreeFilter(
|
yield ParserTreeFilter(
|
||||||
@@ -449,10 +463,21 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
|||||||
# All the additional module attributes are strings.
|
# All the additional module attributes are strings.
|
||||||
return dict((n, ModuleAttributeName(self, n)) for n in names)
|
return dict((n, ModuleAttributeName(self, n)) for n in names)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _string_name(self):
|
||||||
|
""" This is used for the goto functions. """
|
||||||
|
if self._path is None:
|
||||||
|
return '' # no path -> empty name
|
||||||
|
else:
|
||||||
|
sep = (re.escape(os.path.sep),) * 2
|
||||||
|
r = re.search(r'([^%s]*?)(%s__init__)?(\.py|\.so)?$' % sep, self._path)
|
||||||
|
# Remove PEP 3149 names
|
||||||
|
return re.sub('\.[a-z]+-\d{2}[mud]{0,3}$', '', r.group(1))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@memoize_default()
|
@memoize_default()
|
||||||
def name(self):
|
def name(self):
|
||||||
return ContextName(self, self.tree_node.name)
|
return ModuleName(self, self._string_name)
|
||||||
|
|
||||||
def _get_init_directory(self):
|
def _get_init_directory(self):
|
||||||
"""
|
"""
|
||||||
@@ -478,10 +503,10 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
|||||||
"""
|
"""
|
||||||
In contrast to Python's __file__ can be None.
|
In contrast to Python's __file__ can be None.
|
||||||
"""
|
"""
|
||||||
if self.tree_node.path is None:
|
if self._path is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return os.path.abspath(self.tree_node.path)
|
return os.path.abspath(self._path)
|
||||||
|
|
||||||
def py__package__(self):
|
def py__package__(self):
|
||||||
if self._get_init_directory() is None:
|
if self._get_init_directory() is None:
|
||||||
@@ -539,7 +564,7 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
|||||||
Lists modules in the directory of this module (if this module is a
|
Lists modules in the directory of this module (if this module is a
|
||||||
package).
|
package).
|
||||||
"""
|
"""
|
||||||
path = self.tree_node.path
|
path = self._path
|
||||||
names = {}
|
names = {}
|
||||||
if path is not None and path.endswith(os.path.sep + '__init__.py'):
|
if path is not None and path.endswith(os.path.sep + '__init__.py'):
|
||||||
mods = pkgutil.iter_modules([os.path.dirname(path)])
|
mods = pkgutil.iter_modules([os.path.dirname(path)])
|
||||||
@@ -559,6 +584,11 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
|||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
return compiled.get_special_object(self.evaluator, 'MODULE_CLASS')
|
return compiled.get_special_object(self.evaluator, 'MODULE_CLASS')
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s: %s@%s-%s>" % (
|
||||||
|
self.__class__.__name__, self._string_name,
|
||||||
|
self.tree_node.start_pos[0], self.tree_node.end_pos[0])
|
||||||
|
|
||||||
|
|
||||||
class ImplicitNSName(AbstractNameDefinition):
|
class ImplicitNSName(AbstractNameDefinition):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ def _get_paths_from_buildout_script(evaluator, buildout_script_path):
|
|||||||
return
|
return
|
||||||
|
|
||||||
from jedi.evaluate.representation import ModuleContext
|
from jedi.evaluate.representation import ModuleContext
|
||||||
for path in _check_module(ModuleContext(evaluator, module_node)):
|
for path in _check_module(ModuleContext(evaluator, module_node, buildout_script_path)):
|
||||||
yield path
|
yield path
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -144,8 +144,6 @@ class ParserWithRecovery(Parser):
|
|||||||
|
|
||||||
:param grammar: The grammar object of pgen2. Loaded by load_grammar.
|
:param grammar: The grammar object of pgen2. Loaded by load_grammar.
|
||||||
:param source: The codebase for the parser. Must be unicode.
|
:param source: The codebase for the parser. Must be unicode.
|
||||||
:param module_path: The path of the module in the file system, may be None.
|
|
||||||
:type module_path: str
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, grammar, source, module_path=None):
|
def __init__(self, grammar, source, module_path=None):
|
||||||
super(ParserWithRecovery, self).__init__(
|
super(ParserWithRecovery, self).__init__(
|
||||||
@@ -155,7 +153,6 @@ class ParserWithRecovery(Parser):
|
|||||||
self.syntax_errors = []
|
self.syntax_errors = []
|
||||||
self._omit_dedent_list = []
|
self._omit_dedent_list = []
|
||||||
self._indent_counter = 0
|
self._indent_counter = 0
|
||||||
self._module_path = module_path
|
|
||||||
|
|
||||||
# TODO do print absolute import detection here.
|
# TODO do print absolute import detection here.
|
||||||
# try:
|
# try:
|
||||||
@@ -169,7 +166,6 @@ class ParserWithRecovery(Parser):
|
|||||||
|
|
||||||
def parse(self, tokens):
|
def parse(self, tokens):
|
||||||
root_node = super(ParserWithRecovery, self).parse(self._tokenize(tokens))
|
root_node = super(ParserWithRecovery, self).parse(self._tokenize(tokens))
|
||||||
root_node.path = self._module_path
|
|
||||||
return root_node
|
return root_node
|
||||||
|
|
||||||
def error_recovery(self, grammar, stack, arcs, typ, value, start_pos, prefix,
|
def error_recovery(self, grammar, stack, arcs, typ, value, start_pos, prefix,
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ For static analysis purposes there exists a method called
|
|||||||
``nodes_to_execute`` on all nodes and leaves. It's documented in the static
|
``nodes_to_execute`` on all nodes and leaves. It's documented in the static
|
||||||
anaylsis documentation.
|
anaylsis documentation.
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
import re
|
|
||||||
from inspect import cleandoc
|
from inspect import cleandoc
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
import textwrap
|
import textwrap
|
||||||
@@ -277,7 +276,7 @@ class Name(_LeafWithoutNewlines):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
stmt = self.get_definition()
|
stmt = self.get_definition()
|
||||||
if stmt.type in ('funcdef', 'classdef', 'file_input', 'param'):
|
if stmt.type in ('funcdef', 'classdef', 'param'):
|
||||||
return self == stmt.name
|
return self == stmt.name
|
||||||
elif stmt.type == 'for_stmt':
|
elif stmt.type == 'for_stmt':
|
||||||
return self.start_pos < stmt.children[2].start_pos
|
return self.start_pos < stmt.children[2].start_pos
|
||||||
@@ -413,12 +412,9 @@ class Scope(PythonBaseNode, DocstringMixin):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
try:
|
try:
|
||||||
name = self.path
|
name = self.name
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
try:
|
name = ''
|
||||||
name = self.name
|
|
||||||
except AttributeError:
|
|
||||||
name = self.command
|
|
||||||
|
|
||||||
return "<%s: %s@%s-%s>" % (type(self).__name__, name,
|
return "<%s: %s@%s-%s>" % (type(self).__name__, name,
|
||||||
self.start_pos[0], self.end_pos[0])
|
self.start_pos[0], self.end_pos[0])
|
||||||
@@ -442,38 +438,13 @@ class Module(Scope):
|
|||||||
Depending on the underlying parser this may be a full module or just a part
|
Depending on the underlying parser this may be a full module or just a part
|
||||||
of a module.
|
of a module.
|
||||||
"""
|
"""
|
||||||
__slots__ = ('path', '_used_names', '_name')
|
__slots__ = ('_used_names', '_name')
|
||||||
type = 'file_input'
|
type = 'file_input'
|
||||||
|
|
||||||
def __init__(self, children):
|
def __init__(self, children):
|
||||||
"""
|
|
||||||
Initialize :class:`Module`.
|
|
||||||
|
|
||||||
:type path: str
|
|
||||||
:arg path: File path to this module.
|
|
||||||
|
|
||||||
.. todo:: Document `top_module`.
|
|
||||||
"""
|
|
||||||
super(Module, self).__init__(children)
|
super(Module, self).__init__(children)
|
||||||
self.path = None # Set later.
|
|
||||||
self._used_names = None
|
self._used_names = None
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
""" This is used for the goto functions. """
|
|
||||||
if self.path is None:
|
|
||||||
string = '' # no path -> empty name
|
|
||||||
else:
|
|
||||||
sep = (re.escape(os.path.sep),) * 2
|
|
||||||
r = re.search(r'([^%s]*?)(%s__init__)?(\.py|\.so)?$' % sep, self.path)
|
|
||||||
# Remove PEP 3149 names
|
|
||||||
string = re.sub('\.[a-z]+-\d{2}[mud]{0,3}$', '', r.group(1))
|
|
||||||
# Positions are not real, but a module starts at (1, 0)
|
|
||||||
p = (1, 0)
|
|
||||||
name = Name(string, p)
|
|
||||||
name.parent = self
|
|
||||||
return name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_explicit_absolute_import(self):
|
def has_explicit_absolute_import(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ class TestGotoAssignments(TestCase):
|
|||||||
n = nms[0].goto_assignments()[0]
|
n = nms[0].goto_assignments()[0]
|
||||||
assert n.name == 'json'
|
assert n.name == 'json'
|
||||||
assert n.type == 'module'
|
assert n.type == 'module'
|
||||||
assert n._name.tree_name.get_definition().type == 'file_input'
|
assert n._name._context.tree_node.type == 'file_input'
|
||||||
|
|
||||||
assert nms[1].name == 'foo'
|
assert nms[1].name == 'foo'
|
||||||
assert nms[1].type == 'module'
|
assert nms[1].type == 'module'
|
||||||
@@ -347,7 +347,7 @@ class TestGotoAssignments(TestCase):
|
|||||||
assert len(ass) == 1
|
assert len(ass) == 1
|
||||||
assert ass[0].name == 'json'
|
assert ass[0].name == 'json'
|
||||||
assert ass[0].type == 'module'
|
assert ass[0].type == 'module'
|
||||||
assert ass[0]._name.tree_name.get_definition().type == 'file_input'
|
assert ass[0]._name._context.tree_node.type == 'file_input'
|
||||||
|
|
||||||
|
|
||||||
def test_added_equals_to_params():
|
def test_added_equals_to_params():
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from ..helpers import cwd_at
|
|||||||
|
|
||||||
def check_module_test(code):
|
def check_module_test(code):
|
||||||
grammar = load_grammar()
|
grammar = load_grammar()
|
||||||
module_context = ModuleContext(Evaluator(grammar), parse(code))
|
module_context = ModuleContext(Evaluator(grammar), parse(code), path=None)
|
||||||
return _check_module(module_context)
|
return _check_module(module_context)
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ def test_sys_path_with_modifications():
|
|||||||
path = os.path.abspath(os.path.join(os.curdir, 'module_name.py'))
|
path = os.path.abspath(os.path.join(os.curdir, 'module_name.py'))
|
||||||
grammar = load_grammar()
|
grammar = load_grammar()
|
||||||
module_node = parse(code, path=path)
|
module_node = parse(code, path=path)
|
||||||
module_context = ModuleContext(Evaluator(grammar), module_node)
|
module_context = ModuleContext(Evaluator(grammar), module_node, path=path)
|
||||||
paths = sys_path_with_modifications(module_context.evaluator, module_context)
|
paths = sys_path_with_modifications(module_context.evaluator, module_context)
|
||||||
assert '/tmp/.buildout/eggs/important_package.egg' in paths
|
assert '/tmp/.buildout/eggs/important_package.egg' in paths
|
||||||
|
|
||||||
|
|||||||
@@ -88,20 +88,6 @@ class TestImports():
|
|||||||
assert imp.end_pos == (1, len('import math'))
|
assert imp.end_pos == (1, len('import math'))
|
||||||
|
|
||||||
|
|
||||||
def test_module():
|
|
||||||
module = parse('asdf', path='example.py')
|
|
||||||
name = module.name
|
|
||||||
assert str(name) == 'example'
|
|
||||||
assert name.start_pos == (1, 0)
|
|
||||||
assert name.end_pos == (1, 7)
|
|
||||||
|
|
||||||
module = parse('asdf')
|
|
||||||
name = module.name
|
|
||||||
assert str(name) == ''
|
|
||||||
assert name.start_pos == (1, 0)
|
|
||||||
assert name.end_pos == (1, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def test_end_pos():
|
def test_end_pos():
|
||||||
s = dedent('''
|
s = dedent('''
|
||||||
x = ['a', 'b', 'c']
|
x = ['a', 'b', 'c']
|
||||||
|
|||||||
Reference in New Issue
Block a user