mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 14:04:26 +08:00
probably finished the load_module method migration
This commit is contained in:
@@ -35,10 +35,12 @@ import inspect
|
|||||||
from jedi import common
|
from jedi import common
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.parser import Parser
|
from jedi.parser import Parser
|
||||||
|
from jedi.parser import fast
|
||||||
from jedi import modules
|
from jedi import modules
|
||||||
|
from jedi import cache
|
||||||
|
|
||||||
|
|
||||||
class BuiltinModule(modules.CachedModule):
|
class BuiltinModule(object):
|
||||||
"""
|
"""
|
||||||
This module is a parser for all builtin modules, which are programmed in
|
This module is a parser for all builtin modules, which are programmed in
|
||||||
C/C++. It should also work on third party modules.
|
C/C++. It should also work on third party modules.
|
||||||
@@ -69,14 +71,32 @@ class BuiltinModule(modules.CachedModule):
|
|||||||
def __init__(self, path=None, name=None, sys_path=None):
|
def __init__(self, path=None, name=None, sys_path=None):
|
||||||
if sys_path is None:
|
if sys_path is None:
|
||||||
sys_path = modules.get_sys_path()
|
sys_path = modules.get_sys_path()
|
||||||
|
self.sys_path = list(sys_path)
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
name = os.path.basename(path)
|
name = os.path.basename(path)
|
||||||
name = name.rpartition('.')[0] # cut file type (normally .so)
|
name = name.rpartition('.')[0] # cut file type (normally .so)
|
||||||
super(BuiltinModule, self).__init__(path=path, name=name)
|
self.name = name
|
||||||
|
|
||||||
self.sys_path = list(sys_path)
|
self.path = path and os.path.abspath(path)
|
||||||
|
self._parser = None
|
||||||
self._module = None
|
self._module = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parser(self):
|
||||||
|
""" get the parser lazy """
|
||||||
|
if self._parser is None:
|
||||||
|
self._parser = cache.load_parser(self.path, self.name) \
|
||||||
|
or self._load_module()
|
||||||
|
return self._parser
|
||||||
|
|
||||||
|
def _load_module(self):
|
||||||
|
source = _generate_code(self.module, self._load_mixins())
|
||||||
|
p = self.path or self.name
|
||||||
|
p = fast.FastParser(source, p)
|
||||||
|
cache.save_parser(self.path, self.name, p)
|
||||||
|
return p
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def module(self):
|
def module(self):
|
||||||
def load_module(name, path):
|
def load_module(name, path):
|
||||||
@@ -118,10 +138,6 @@ class BuiltinModule(modules.CachedModule):
|
|||||||
load_module(name, path)
|
load_module(name, path)
|
||||||
return self._module
|
return self._module
|
||||||
|
|
||||||
def _get_source(self):
|
|
||||||
""" Override this abstract method """
|
|
||||||
return _generate_code(self.module, self._load_mixins())
|
|
||||||
|
|
||||||
def _load_mixins(self):
|
def _load_mixins(self):
|
||||||
"""
|
"""
|
||||||
Load functions that are mixed in to the standard library.
|
Load functions that are mixed in to the standard library.
|
||||||
@@ -158,14 +174,14 @@ class BuiltinModule(modules.CachedModule):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
return funcs
|
return funcs
|
||||||
|
|
||||||
try:
|
name = self.name
|
||||||
name = self.name
|
# sometimes there are stupid endings like `_sqlite3.cpython-32mu`
|
||||||
# sometimes there are stupid endings like `_sqlite3.cpython-32mu`
|
name = re.sub(r'\..*', '', name)
|
||||||
name = re.sub(r'\..*', '', name)
|
|
||||||
|
|
||||||
if name == '__builtin__' and not is_py3k:
|
if name == '__builtin__' and not is_py3k:
|
||||||
name = 'builtins'
|
name = 'builtins'
|
||||||
path = os.path.dirname(os.path.abspath(__file__))
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
try:
|
||||||
with open(os.path.join(path, 'mixin', name) + '.pym') as f:
|
with open(os.path.join(path, 'mixin', name) + '.pym') as f:
|
||||||
s = f.read()
|
s = f.read()
|
||||||
except IOError:
|
except IOError:
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ def get_directory_modules_for_name(mods, name):
|
|||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
source = modules.source_to_unicode(f.read())
|
source = modules.source_to_unicode(f.read())
|
||||||
if name in source:
|
if name in source:
|
||||||
return modules.Module(path, source).parser.module
|
return modules.load_module(path, source)
|
||||||
|
|
||||||
# skip non python modules
|
# skip non python modules
|
||||||
mods = set(m for m in mods if m.path is None or m.path.endswith('.py'))
|
mods = set(m for m in mods if m.path is None or m.path.endswith('.py'))
|
||||||
|
|||||||
@@ -110,9 +110,9 @@ class ImportPath(pr.Base):
|
|||||||
|
|
||||||
if self._is_relative_import():
|
if self._is_relative_import():
|
||||||
rel_path = self._get_relative_path() + '/__init__.py'
|
rel_path = self._get_relative_path() + '/__init__.py'
|
||||||
with common.ignored(IOError):
|
if os.path.exists(rel_path):
|
||||||
m = modules.Module(rel_path)
|
m = modules.load_module(rel_path)
|
||||||
names += m.parser.module.get_defined_names()
|
names += m.get_defined_names()
|
||||||
else:
|
else:
|
||||||
if on_import_stmt and isinstance(scope, pr.Module) \
|
if on_import_stmt and isinstance(scope, pr.Module) \
|
||||||
and scope.path.endswith('__init__.py'):
|
and scope.path.endswith('__init__.py'):
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ from jedi import common
|
|||||||
|
|
||||||
def load_module(path=None, source=None, name=None):
|
def load_module(path=None, source=None, name=None):
|
||||||
def load(source):
|
def load(source):
|
||||||
if path.endswith('.py'):
|
if path is not None and path.endswith('.py'):
|
||||||
if source is None:
|
if source is None:
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
source = f.read()
|
source = f.read()
|
||||||
else:
|
else:
|
||||||
# TODO refactoring remove
|
# TODO refactoring remove
|
||||||
from jedi.evaluate import builtin
|
from jedi.evaluate import builtin
|
||||||
return builtin.BuiltinModule(name=path).parser.module
|
return builtin.BuiltinModule(path, name).parser.module
|
||||||
p = path or name
|
p = path or name
|
||||||
p = fast.FastParser(source_to_unicode(source), p)
|
p = fast.FastParser(source_to_unicode(source), p)
|
||||||
cache.save_parser(path, name, p)
|
cache.save_parser(path, name, p)
|
||||||
@@ -61,9 +61,13 @@ class ModuleWithCursor(object):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, path, source, position):
|
def __init__(self, path, source, position):
|
||||||
super(ModuleWithCursor, self).__init__()
|
super(ModuleWithCursor, self).__init__()
|
||||||
self.position = position
|
self.path = path and os.path.abspath(path)
|
||||||
|
self.name = None
|
||||||
self.source = source
|
self.source = source
|
||||||
|
self.position = position
|
||||||
self._path_until_cursor = None
|
self._path_until_cursor = None
|
||||||
|
self._line_cache = None
|
||||||
|
self._parser = None
|
||||||
|
|
||||||
# this two are only used, because there is no nonlocal in Python 2
|
# this two are only used, because there is no nonlocal in Python 2
|
||||||
self._line_temp = None
|
self._line_temp = None
|
||||||
|
|||||||
@@ -8,15 +8,16 @@ import pytest
|
|||||||
|
|
||||||
import jedi
|
import jedi
|
||||||
from jedi import settings, cache
|
from jedi import settings, cache
|
||||||
from jedi.cache import ParserCacheItem, _ModulePickling
|
from jedi.cache import ParserCacheItem, ParserPickling
|
||||||
|
|
||||||
|
|
||||||
ModulePickling = _ModulePickling()
|
ParserPicklingCls = type(ParserPickling)
|
||||||
|
ParserPickling = ParserPicklingCls()
|
||||||
|
|
||||||
|
|
||||||
def test_modulepickling_change_cache_dir(monkeypatch, tmpdir):
|
def test_modulepickling_change_cache_dir(monkeypatch, tmpdir):
|
||||||
"""
|
"""
|
||||||
ModulePickling should not save old cache when cache_directory is changed.
|
ParserPickling should not save old cache when cache_directory is changed.
|
||||||
|
|
||||||
See: `#168 <https://github.com/davidhalter/jedi/pull/168>`_
|
See: `#168 <https://github.com/davidhalter/jedi/pull/168>`_
|
||||||
"""
|
"""
|
||||||
@@ -29,19 +30,19 @@ def test_modulepickling_change_cache_dir(monkeypatch, tmpdir):
|
|||||||
path_2 = 'fake path 2'
|
path_2 = 'fake path 2'
|
||||||
|
|
||||||
monkeypatch.setattr(settings, 'cache_directory', dir_1)
|
monkeypatch.setattr(settings, 'cache_directory', dir_1)
|
||||||
ModulePickling.save_module(path_1, item_1)
|
ParserPickling.save_parser(path_1, item_1)
|
||||||
cached = load_stored_item(ModulePickling, path_1, item_1)
|
cached = load_stored_item(ParserPickling, path_1, item_1)
|
||||||
assert cached == item_1.parser
|
assert cached == item_1.parser
|
||||||
|
|
||||||
monkeypatch.setattr(settings, 'cache_directory', dir_2)
|
monkeypatch.setattr(settings, 'cache_directory', dir_2)
|
||||||
ModulePickling.save_module(path_2, item_2)
|
ParserPickling.save_parser(path_2, item_2)
|
||||||
cached = load_stored_item(ModulePickling, path_1, item_1)
|
cached = load_stored_item(ParserPickling, path_1, item_1)
|
||||||
assert cached is None
|
assert cached is None
|
||||||
|
|
||||||
|
|
||||||
def load_stored_item(cache, path, item):
|
def load_stored_item(cache, path, item):
|
||||||
"""Load `item` stored at `path` in `cache`."""
|
"""Load `item` stored at `path` in `cache`."""
|
||||||
return cache.load_module(path, item.change_time - 1)
|
return cache.load_parser(path, item.change_time - 1)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("isolated_jedi_cache")
|
@pytest.mark.usefixtures("isolated_jedi_cache")
|
||||||
@@ -49,13 +50,13 @@ def test_modulepickling_delete_incompatible_cache():
|
|||||||
item = ParserCacheItem('fake parser')
|
item = ParserCacheItem('fake parser')
|
||||||
path = 'fake path'
|
path = 'fake path'
|
||||||
|
|
||||||
cache1 = _ModulePickling()
|
cache1 = ParserPicklingCls()
|
||||||
cache1.version = 1
|
cache1.version = 1
|
||||||
cache1.save_module(path, item)
|
cache1.save_parser(path, item)
|
||||||
cached1 = load_stored_item(cache1, path, item)
|
cached1 = load_stored_item(cache1, path, item)
|
||||||
assert cached1 == item.parser
|
assert cached1 == item.parser
|
||||||
|
|
||||||
cache2 = _ModulePickling()
|
cache2 = ParserPicklingCls()
|
||||||
cache2.version = 2
|
cache2.version = 2
|
||||||
cached2 = load_stored_item(cache2, path, item)
|
cached2 = load_stored_item(cache2, path, item)
|
||||||
assert cached2 is None
|
assert cached2 is None
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from .helpers import TestCase, cwd_at
|
|||||||
import jedi
|
import jedi
|
||||||
from jedi import Script
|
from jedi import Script
|
||||||
from jedi import api
|
from jedi import api
|
||||||
|
from jedi import modules
|
||||||
from jedi.parser import Parser
|
from jedi.parser import Parser
|
||||||
|
|
||||||
#jedi.set_debug_function()
|
#jedi.set_debug_function()
|
||||||
@@ -81,8 +82,7 @@ class TestRegression(TestCase):
|
|||||||
src1 = "def r(a): return a"
|
src1 = "def r(a): return a"
|
||||||
# Other fictional modules in another place in the fs.
|
# Other fictional modules in another place in the fs.
|
||||||
src2 = 'from .. import setup; setup.r(1)'
|
src2 = 'from .. import setup; setup.r(1)'
|
||||||
# .parser to load the module
|
modules.load_module(os.path.abspath(fname), src2)
|
||||||
api.modules.Module(os.path.abspath(fname), src2).parser
|
|
||||||
result = Script(src1, path='../setup.py').goto_definitions()
|
result = Script(src1, path='../setup.py').goto_definitions()
|
||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
assert result[0].description == 'class int'
|
assert result[0].description == 'class int'
|
||||||
|
|||||||
Reference in New Issue
Block a user