mirror of
https://github.com/davidhalter/jedi.git
synced 2026-09-06 04:46:56 +08:00
Merge branch 'python3'
This commit is contained in:
@@ -5,15 +5,11 @@ python:
|
|||||||
- 3.8
|
- 3.8
|
||||||
- 3.7
|
- 3.7
|
||||||
- 3.6
|
- 3.6
|
||||||
- 3.5
|
|
||||||
- 2.7
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- JEDI_TEST_ENVIRONMENT=38
|
- JEDI_TEST_ENVIRONMENT=38
|
||||||
- JEDI_TEST_ENVIRONMENT=37
|
- JEDI_TEST_ENVIRONMENT=37
|
||||||
- JEDI_TEST_ENVIRONMENT=36
|
- JEDI_TEST_ENVIRONMENT=36
|
||||||
- JEDI_TEST_ENVIRONMENT=35
|
|
||||||
- JEDI_TEST_ENVIRONMENT=27
|
|
||||||
- JEDI_TEST_ENVIRONMENT=interpreter
|
- JEDI_TEST_ENVIRONMENT=interpreter
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
+1
-1
@@ -98,7 +98,7 @@ Features and Limitations
|
|||||||
Jedi's features are listed here:
|
Jedi's features are listed here:
|
||||||
`Features <https://jedi.readthedocs.org/en/latest/docs/features.html>`_.
|
`Features <https://jedi.readthedocs.org/en/latest/docs/features.html>`_.
|
||||||
|
|
||||||
You can run Jedi on CPython 2.7 or 3.5+ but it should also
|
You can run Jedi on Python 3.6+ but it should also
|
||||||
understand code that is older than those versions. Additionally you should be
|
understand code that is older than those versions. Additionally you should be
|
||||||
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
|
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
|
||||||
very well.
|
very well.
|
||||||
|
|||||||
@@ -6,12 +6,6 @@ environment:
|
|||||||
- TOXENV: py37
|
- TOXENV: py37
|
||||||
PYTHON_PATH: C:\Python37
|
PYTHON_PATH: C:\Python37
|
||||||
JEDI_TEST_ENVIRONMENT: 36
|
JEDI_TEST_ENVIRONMENT: 36
|
||||||
- TOXENV: py37
|
|
||||||
PYTHON_PATH: C:\Python37
|
|
||||||
JEDI_TEST_ENVIRONMENT: 35
|
|
||||||
- TOXENV: py37
|
|
||||||
PYTHON_PATH: C:\Python37
|
|
||||||
JEDI_TEST_ENVIRONMENT: 27
|
|
||||||
|
|
||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
PYTHON_PATH: C:\Python36
|
PYTHON_PATH: C:\Python36
|
||||||
@@ -19,38 +13,6 @@ environment:
|
|||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
PYTHON_PATH: C:\Python36
|
PYTHON_PATH: C:\Python36
|
||||||
JEDI_TEST_ENVIRONMENT: 36
|
JEDI_TEST_ENVIRONMENT: 36
|
||||||
- TOXENV: py36
|
|
||||||
PYTHON_PATH: C:\Python36
|
|
||||||
JEDI_TEST_ENVIRONMENT: 35
|
|
||||||
- TOXENV: py36
|
|
||||||
PYTHON_PATH: C:\Python36
|
|
||||||
JEDI_TEST_ENVIRONMENT: 27
|
|
||||||
|
|
||||||
- TOXENV: py35
|
|
||||||
PYTHON_PATH: C:\Python35
|
|
||||||
JEDI_TEST_ENVIRONMENT: 37
|
|
||||||
- TOXENV: py35
|
|
||||||
PYTHON_PATH: C:\Python35
|
|
||||||
JEDI_TEST_ENVIRONMENT: 36
|
|
||||||
- TOXENV: py35
|
|
||||||
PYTHON_PATH: C:\Python35
|
|
||||||
JEDI_TEST_ENVIRONMENT: 35
|
|
||||||
- TOXENV: py35
|
|
||||||
PYTHON_PATH: C:\Python35
|
|
||||||
JEDI_TEST_ENVIRONMENT: 27
|
|
||||||
|
|
||||||
- TOXENV: py27
|
|
||||||
PYTHON_PATH: C:\Python27
|
|
||||||
JEDI_TEST_ENVIRONMENT: 37
|
|
||||||
- TOXENV: py27
|
|
||||||
PYTHON_PATH: C:\Python27
|
|
||||||
JEDI_TEST_ENVIRONMENT: 36
|
|
||||||
- TOXENV: py27
|
|
||||||
PYTHON_PATH: C:\Python27
|
|
||||||
JEDI_TEST_ENVIRONMENT: 35
|
|
||||||
- TOXENV: py27
|
|
||||||
PYTHON_PATH: C:\Python27
|
|
||||||
JEDI_TEST_ENVIRONMENT: 27
|
|
||||||
install:
|
install:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- set PATH=%PYTHON_PATH%;%PYTHON_PATH%\Scripts;%PATH%
|
- set PATH=%PYTHON_PATH%;%PYTHON_PATH%\Scripts;%PATH%
|
||||||
|
|||||||
+3
-41
@@ -8,7 +8,6 @@ import pytest
|
|||||||
|
|
||||||
import jedi
|
import jedi
|
||||||
from jedi.api.environment import get_system_environment, InterpreterEnvironment
|
from jedi.api.environment import get_system_environment, InterpreterEnvironment
|
||||||
from jedi._compatibility import py_version
|
|
||||||
from test.helpers import test_dir
|
from test.helpers import test_dir
|
||||||
|
|
||||||
collect_ignore = [
|
collect_ignore = [
|
||||||
@@ -18,9 +17,6 @@ collect_ignore = [
|
|||||||
'build/',
|
'build/',
|
||||||
'test/examples',
|
'test/examples',
|
||||||
]
|
]
|
||||||
if sys.version_info < (3, 6):
|
|
||||||
# Python 2 not supported syntax
|
|
||||||
collect_ignore.append('test/test_inference/test_mixed.py')
|
|
||||||
|
|
||||||
|
|
||||||
# The following hooks (pytest_configure, pytest_unconfigure) are used
|
# The following hooks (pytest_configure, pytest_unconfigure) are used
|
||||||
@@ -45,7 +41,7 @@ def pytest_addoption(parser):
|
|||||||
help="Warnings are treated as errors.")
|
help="Warnings are treated as errors.")
|
||||||
|
|
||||||
parser.addoption("--env", action='store',
|
parser.addoption("--env", action='store',
|
||||||
help="Execute the tests in that environment (e.g. 35 for python3.5).")
|
help="Execute the tests in that environment (e.g. 39 for python3.9).")
|
||||||
parser.addoption("--interpreter-env", "-I", action='store_true',
|
parser.addoption("--interpreter-env", "-I", action='store_true',
|
||||||
help="Don't use subprocesses to guarantee having safe "
|
help="Don't use subprocesses to guarantee having safe "
|
||||||
"code execution. Useful for debugging.")
|
"code execution. Useful for debugging.")
|
||||||
@@ -97,7 +93,8 @@ def clean_jedi_cache(request):
|
|||||||
def environment(request):
|
def environment(request):
|
||||||
version = request.config.option.env
|
version = request.config.option.env
|
||||||
if version is None:
|
if version is None:
|
||||||
version = os.environ.get('JEDI_TEST_ENVIRONMENT', str(py_version))
|
v = str(sys.version_info[0]) + str(sys.version_info[1])
|
||||||
|
version = os.environ.get('JEDI_TEST_ENVIRONMENT', v)
|
||||||
|
|
||||||
if request.config.option.interpreter_env or version == 'interpreter':
|
if request.config.option.interpreter_env or version == 'interpreter':
|
||||||
return InterpreterEnvironment()
|
return InterpreterEnvironment()
|
||||||
@@ -136,17 +133,6 @@ def goto_or_help_or_infer(request, Script):
|
|||||||
return lambda code, *args, **kwargs: getattr(Script(code), request.param)(*args, **kwargs)
|
return lambda code, *args, **kwargs: getattr(Script(code), request.param)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
|
||||||
def has_typing(environment):
|
|
||||||
if environment.version_info >= (3, 5, 0):
|
|
||||||
# This if is just needed to avoid that tests ever skip way more than
|
|
||||||
# they should for all Python versions.
|
|
||||||
return True
|
|
||||||
|
|
||||||
script = jedi.Script('import typing', environment=environment)
|
|
||||||
return bool(script.infer())
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def has_django(environment):
|
def has_django(environment):
|
||||||
script = jedi.Script('import django', environment=environment)
|
script = jedi.Script('import django', environment=environment)
|
||||||
@@ -158,14 +144,6 @@ def jedi_path():
|
|||||||
return os.path.dirname(__file__)
|
return os.path.dirname(__file__)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def skip_python2(environment):
|
|
||||||
if environment.version_info.major == 2:
|
|
||||||
# This if is just needed to avoid that tests ever skip way more than
|
|
||||||
# they should for all Python versions.
|
|
||||||
pytest.skip()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def skip_pre_python38(environment):
|
def skip_pre_python38(environment):
|
||||||
if environment.version_info < (3, 8):
|
if environment.version_info < (3, 8):
|
||||||
@@ -180,19 +158,3 @@ def skip_pre_python37(environment):
|
|||||||
# This if is just needed to avoid that tests ever skip way more than
|
# This if is just needed to avoid that tests ever skip way more than
|
||||||
# they should for all Python versions.
|
# they should for all Python versions.
|
||||||
pytest.skip()
|
pytest.skip()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def skip_pre_python35(environment):
|
|
||||||
if environment.version_info < (3, 5):
|
|
||||||
# This if is just needed to avoid that tests ever skip way more than
|
|
||||||
# they should for all Python versions.
|
|
||||||
pytest.skip()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def skip_pre_python36(environment):
|
|
||||||
if environment.version_info < (3, 6):
|
|
||||||
# This if is just needed to avoid that tests ever skip way more than
|
|
||||||
# they should for all Python versions.
|
|
||||||
pytest.skip()
|
|
||||||
|
|||||||
+8
-10
@@ -1,5 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Jedi documentation build configuration file, created by
|
# Jedi documentation build configuration file, created by
|
||||||
# sphinx-quickstart on Wed Dec 26 00:11:34 2012.
|
# sphinx-quickstart on Wed Dec 26 00:11:34 2012.
|
||||||
#
|
#
|
||||||
@@ -43,8 +41,8 @@ source_encoding = 'utf-8'
|
|||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'Jedi'
|
project = 'Jedi'
|
||||||
copyright = u'jedi contributors'
|
copyright = 'jedi contributors'
|
||||||
|
|
||||||
import jedi
|
import jedi
|
||||||
from jedi.utils import version_info
|
from jedi.utils import version_info
|
||||||
@@ -205,8 +203,8 @@ latex_elements = {
|
|||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', 'Jedi.tex', u'Jedi Documentation',
|
('index', 'Jedi.tex', 'Jedi Documentation',
|
||||||
u'Jedi contributors', 'manual'),
|
'Jedi contributors', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
@@ -235,8 +233,8 @@ latex_documents = [
|
|||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [
|
||||||
('index', 'jedi', u'Jedi Documentation',
|
('index', 'jedi', 'Jedi Documentation',
|
||||||
[u'Jedi contributors'], 1)
|
['Jedi contributors'], 1)
|
||||||
]
|
]
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
@@ -249,8 +247,8 @@ man_pages = [
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'Jedi', u'Jedi Documentation',
|
('index', 'Jedi', 'Jedi Documentation',
|
||||||
u'Jedi contributors', 'Jedi', 'Awesome Python autocompletion library.',
|
'Jedi contributors', 'Jedi', 'Awesome Python autocompletion library.',
|
||||||
'Miscellaneous'),
|
'Miscellaneous'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -107,7 +107,7 @@ Completions
|
|||||||
>>> code = '''import json; json.l'''
|
>>> code = '''import json; json.l'''
|
||||||
>>> script = jedi.Script(code, path='example.py')
|
>>> script = jedi.Script(code, path='example.py')
|
||||||
>>> script
|
>>> script
|
||||||
<Script: 'example.py' <SameEnvironment: 3.5.2 in /usr>>
|
<Script: 'example.py' <SameEnvironment: 3.9.0 in /usr>>
|
||||||
>>> completions = script.complete(1, 19)
|
>>> completions = script.complete(1, 19)
|
||||||
>>> completions
|
>>> completions
|
||||||
[<Completion: load>, <Completion: loads>]
|
[<Completion: load>, <Completion: loads>]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Jedi's main API calls and features are:
|
|||||||
Basic Features
|
Basic Features
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
- Python 2.7 and 3.5+ support
|
- Python 3.6+ support
|
||||||
- Ignores syntax errors and wrong indentation
|
- Ignores syntax errors and wrong indentation
|
||||||
- Can deal with complex module / function / class structures
|
- Can deal with complex module / function / class structures
|
||||||
- Great ``virtualenv``/``venv`` support
|
- Great ``virtualenv``/``venv`` support
|
||||||
|
|||||||
@@ -50,14 +50,6 @@ Arch Linux
|
|||||||
You can install |jedi| directly from official Arch Linux packages:
|
You can install |jedi| directly from official Arch Linux packages:
|
||||||
|
|
||||||
- `python-jedi <https://www.archlinux.org/packages/community/any/python-jedi/>`__
|
- `python-jedi <https://www.archlinux.org/packages/community/any/python-jedi/>`__
|
||||||
(Python 3)
|
|
||||||
- `python2-jedi <https://www.archlinux.org/packages/community/any/python2-jedi/>`__
|
|
||||||
(Python 2)
|
|
||||||
|
|
||||||
The specified Python version just refers to the *runtime environment* for
|
|
||||||
|jedi|. Use the Python 2 version if you're running vim (or whatever editor you
|
|
||||||
use) under Python 2. Otherwise, use the Python 3 version. But whatever version
|
|
||||||
you choose, both are able to complete both Python 2 and 3 *code*.
|
|
||||||
|
|
||||||
(There is also a packaged version of the vim plugin available:
|
(There is also a packaged version of the vim plugin available:
|
||||||
`vim-jedi at Arch Linux <https://www.archlinux.org/packages/community/any/vim-jedi/>`__.)
|
`vim-jedi at Arch Linux <https://www.archlinux.org/packages/community/any/vim-jedi/>`__.)
|
||||||
|
|||||||
+7
-590
@@ -1,292 +1,13 @@
|
|||||||
"""
|
"""
|
||||||
To ensure compatibility from Python ``2.7`` - ``3.x``, a module has been
|
This module is here to ensure compatibility of Windows/Linux/MacOS and
|
||||||
created. Clearly there is huge need to use conforming syntax.
|
different Python versions.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
import atexit
|
|
||||||
import errno
|
import errno
|
||||||
import functools
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import pickle
|
||||||
import re
|
|
||||||
import pkgutil
|
|
||||||
import warnings
|
|
||||||
import subprocess
|
|
||||||
import weakref
|
|
||||||
try:
|
|
||||||
import importlib
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
from zipimport import zipimporter
|
|
||||||
|
|
||||||
from jedi.file_io import KnownContentFileIO, ZipFileIO
|
|
||||||
|
|
||||||
is_py3 = sys.version_info[0] >= 3
|
|
||||||
is_py35 = is_py3 and sys.version_info[1] >= 5
|
|
||||||
py_version = int(str(sys.version_info[0]) + str(sys.version_info[1]))
|
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info[:2] < (3, 5):
|
def cast_path(string):
|
||||||
"""
|
|
||||||
A super-minimal shim around listdir that behave like
|
|
||||||
scandir for the information we need.
|
|
||||||
"""
|
|
||||||
class _DirEntry:
|
|
||||||
|
|
||||||
def __init__(self, name, basepath):
|
|
||||||
self.name = name
|
|
||||||
self.basepath = basepath
|
|
||||||
|
|
||||||
def is_dir(self):
|
|
||||||
path_for_name = os.path.join(self.basepath, self.name)
|
|
||||||
return os.path.isdir(path_for_name)
|
|
||||||
|
|
||||||
def scandir(dir):
|
|
||||||
return [_DirEntry(name, dir) for name in os.listdir(dir)]
|
|
||||||
else:
|
|
||||||
from os import scandir
|
|
||||||
|
|
||||||
|
|
||||||
class DummyFile(object):
|
|
||||||
def __init__(self, loader, string):
|
|
||||||
self.loader = loader
|
|
||||||
self.string = string
|
|
||||||
|
|
||||||
def read(self):
|
|
||||||
return self.loader.get_source(self.string)
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
del self.loader
|
|
||||||
|
|
||||||
|
|
||||||
def find_module_py34(string, path=None, full_name=None, is_global_search=True):
|
|
||||||
spec = None
|
|
||||||
loader = None
|
|
||||||
|
|
||||||
for finder in sys.meta_path:
|
|
||||||
if is_global_search and finder != importlib.machinery.PathFinder:
|
|
||||||
p = None
|
|
||||||
else:
|
|
||||||
p = path
|
|
||||||
try:
|
|
||||||
find_spec = finder.find_spec
|
|
||||||
except AttributeError:
|
|
||||||
# These are old-school clases that still have a different API, just
|
|
||||||
# ignore those.
|
|
||||||
continue
|
|
||||||
|
|
||||||
spec = find_spec(string, p)
|
|
||||||
if spec is not None:
|
|
||||||
loader = spec.loader
|
|
||||||
if loader is None and not spec.has_location:
|
|
||||||
# This is a namespace package.
|
|
||||||
full_name = string if not path else full_name
|
|
||||||
implicit_ns_info = ImplicitNSInfo(full_name, spec.submodule_search_locations._path)
|
|
||||||
return implicit_ns_info, True
|
|
||||||
break
|
|
||||||
|
|
||||||
return find_module_py33(string, path, loader)
|
|
||||||
|
|
||||||
|
|
||||||
def find_module_py33(string, path=None, loader=None, full_name=None, is_global_search=True):
|
|
||||||
loader = loader or importlib.machinery.PathFinder.find_module(string, path)
|
|
||||||
|
|
||||||
if loader is None and path is None: # Fallback to find builtins
|
|
||||||
try:
|
|
||||||
with warnings.catch_warnings(record=True):
|
|
||||||
# Mute "DeprecationWarning: Use importlib.util.find_spec()
|
|
||||||
# instead." While we should replace that in the future, it's
|
|
||||||
# probably good to wait until we deprecate Python 3.3, since
|
|
||||||
# it was added in Python 3.4 and find_loader hasn't been
|
|
||||||
# removed in 3.6.
|
|
||||||
loader = importlib.find_loader(string)
|
|
||||||
except ValueError as e:
|
|
||||||
# See #491. Importlib might raise a ValueError, to avoid this, we
|
|
||||||
# just raise an ImportError to fix the issue.
|
|
||||||
raise ImportError("Originally " + repr(e))
|
|
||||||
|
|
||||||
if loader is None:
|
|
||||||
raise ImportError("Couldn't find a loader for {}".format(string))
|
|
||||||
|
|
||||||
return _from_loader(loader, string)
|
|
||||||
|
|
||||||
|
|
||||||
def _from_loader(loader, string):
|
|
||||||
try:
|
|
||||||
is_package_method = loader.is_package
|
|
||||||
except AttributeError:
|
|
||||||
is_package = False
|
|
||||||
else:
|
|
||||||
is_package = is_package_method(string)
|
|
||||||
try:
|
|
||||||
get_filename = loader.get_filename
|
|
||||||
except AttributeError:
|
|
||||||
return None, is_package
|
|
||||||
else:
|
|
||||||
module_path = cast_path(get_filename(string))
|
|
||||||
|
|
||||||
# To avoid unicode and read bytes, "overwrite" loader.get_source if
|
|
||||||
# possible.
|
|
||||||
try:
|
|
||||||
f = type(loader).get_source
|
|
||||||
except AttributeError:
|
|
||||||
raise ImportError("get_source was not defined on loader")
|
|
||||||
|
|
||||||
if is_py3 and f is not importlib.machinery.SourceFileLoader.get_source:
|
|
||||||
# Unfortunately we are reading unicode here, not bytes.
|
|
||||||
# It seems hard to get bytes, because the zip importer
|
|
||||||
# logic just unpacks the zip file and returns a file descriptor
|
|
||||||
# that we cannot as easily access. Therefore we just read it as
|
|
||||||
# a string in the cases where get_source was overwritten.
|
|
||||||
code = loader.get_source(string)
|
|
||||||
else:
|
|
||||||
code = _get_source(loader, string)
|
|
||||||
|
|
||||||
if code is None:
|
|
||||||
return None, is_package
|
|
||||||
if isinstance(loader, zipimporter):
|
|
||||||
return ZipFileIO(module_path, code, cast_path(loader.archive)), is_package
|
|
||||||
|
|
||||||
return KnownContentFileIO(module_path, code), is_package
|
|
||||||
|
|
||||||
|
|
||||||
def _get_source(loader, fullname):
|
|
||||||
"""
|
|
||||||
This method is here as a replacement for SourceLoader.get_source. That
|
|
||||||
method returns unicode, but we prefer bytes.
|
|
||||||
"""
|
|
||||||
path = loader.get_filename(fullname)
|
|
||||||
try:
|
|
||||||
return loader.get_data(path)
|
|
||||||
except OSError:
|
|
||||||
raise ImportError('source not available through get_data()',
|
|
||||||
name=fullname)
|
|
||||||
|
|
||||||
|
|
||||||
def find_module_pre_py3(string, path=None, full_name=None, is_global_search=True):
|
|
||||||
# This import is here, because in other places it will raise a
|
|
||||||
# DeprecationWarning.
|
|
||||||
import imp
|
|
||||||
try:
|
|
||||||
module_file, module_path, description = imp.find_module(string, path)
|
|
||||||
module_type = description[2]
|
|
||||||
is_package = module_type is imp.PKG_DIRECTORY
|
|
||||||
if is_package:
|
|
||||||
# In Python 2 directory package imports are returned as folder
|
|
||||||
# paths, not __init__.py paths.
|
|
||||||
p = os.path.join(module_path, '__init__.py')
|
|
||||||
try:
|
|
||||||
module_file = open(p)
|
|
||||||
module_path = p
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
elif module_type != imp.PY_SOURCE:
|
|
||||||
if module_file is not None:
|
|
||||||
module_file.close()
|
|
||||||
module_file = None
|
|
||||||
|
|
||||||
if module_file is None:
|
|
||||||
return None, is_package
|
|
||||||
|
|
||||||
with module_file:
|
|
||||||
code = module_file.read()
|
|
||||||
return KnownContentFileIO(cast_path(module_path), code), is_package
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if path is None:
|
|
||||||
path = sys.path
|
|
||||||
for item in path:
|
|
||||||
loader = pkgutil.get_importer(item)
|
|
||||||
if loader:
|
|
||||||
loader = loader.find_module(string)
|
|
||||||
if loader is not None:
|
|
||||||
return _from_loader(loader, string)
|
|
||||||
raise ImportError("No module named {}".format(string))
|
|
||||||
|
|
||||||
|
|
||||||
find_module = find_module_py34 if is_py3 else find_module_pre_py3
|
|
||||||
find_module.__doc__ = """
|
|
||||||
Provides information about a module.
|
|
||||||
|
|
||||||
This function isolates the differences in importing libraries introduced with
|
|
||||||
python 3.3 on; it gets a module name and optionally a path. It will return a
|
|
||||||
tuple containin an open file for the module (if not builtin), the filename
|
|
||||||
or the name of the module if it is a builtin one and a boolean indicating
|
|
||||||
if the module is contained in a package.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class ImplicitNSInfo(object):
|
|
||||||
"""Stores information returned from an implicit namespace spec"""
|
|
||||||
def __init__(self, name, paths):
|
|
||||||
self.name = name
|
|
||||||
self.paths = paths
|
|
||||||
|
|
||||||
|
|
||||||
if is_py3:
|
|
||||||
all_suffixes = importlib.machinery.all_suffixes
|
|
||||||
else:
|
|
||||||
def all_suffixes():
|
|
||||||
# Is deprecated and raises a warning in Python 3.6.
|
|
||||||
import imp
|
|
||||||
return [suffix for suffix, _, _ in imp.get_suffixes()]
|
|
||||||
|
|
||||||
|
|
||||||
# unicode function
|
|
||||||
try:
|
|
||||||
unicode = unicode
|
|
||||||
except NameError:
|
|
||||||
unicode = str
|
|
||||||
|
|
||||||
|
|
||||||
# re-raise function
|
|
||||||
if is_py3:
|
|
||||||
def reraise(exception, traceback):
|
|
||||||
raise exception.with_traceback(traceback)
|
|
||||||
else:
|
|
||||||
eval(compile("""
|
|
||||||
def reraise(exception, traceback):
|
|
||||||
raise exception, None, traceback
|
|
||||||
""", 'blub', 'exec'))
|
|
||||||
|
|
||||||
reraise.__doc__ = """
|
|
||||||
Re-raise `exception` with a `traceback` object.
|
|
||||||
|
|
||||||
Usage::
|
|
||||||
|
|
||||||
reraise(Exception, sys.exc_info()[2])
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def use_metaclass(meta, *bases):
|
|
||||||
""" Create a class with a metaclass. """
|
|
||||||
if not bases:
|
|
||||||
bases = (object,)
|
|
||||||
return meta("Py2CompatibilityMetaClass", bases, {})
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
encoding = sys.stdout.encoding
|
|
||||||
if encoding is None:
|
|
||||||
encoding = 'utf-8'
|
|
||||||
except AttributeError:
|
|
||||||
encoding = 'ascii'
|
|
||||||
|
|
||||||
|
|
||||||
def u(string, errors='strict'):
|
|
||||||
"""Cast to unicode DAMMIT!
|
|
||||||
Written because Python2 repr always implicitly casts to a string, so we
|
|
||||||
have to cast back to a unicode (and we now that we always deal with valid
|
|
||||||
unicode, because we check that in the beginning).
|
|
||||||
"""
|
|
||||||
if isinstance(string, bytes):
|
|
||||||
return unicode(string, encoding='UTF-8', errors=errors)
|
|
||||||
return string
|
|
||||||
|
|
||||||
|
|
||||||
def cast_path(obj):
|
|
||||||
"""
|
"""
|
||||||
Take a bytes or str path and cast it to unicode.
|
Take a bytes or str path and cast it to unicode.
|
||||||
|
|
||||||
@@ -297,103 +18,13 @@ def cast_path(obj):
|
|||||||
Since this just really complicates everything and Python 2.7 will be EOL
|
Since this just really complicates everything and Python 2.7 will be EOL
|
||||||
soon anyway, just go with always strings.
|
soon anyway, just go with always strings.
|
||||||
"""
|
"""
|
||||||
return u(obj, errors='replace')
|
if isinstance(string, bytes):
|
||||||
|
return str(string, encoding='UTF-8', errors='replace')
|
||||||
|
return str(string)
|
||||||
def force_unicode(obj):
|
|
||||||
# Intentionally don't mix those two up, because those two code paths might
|
|
||||||
# be different in the future (maybe windows?).
|
|
||||||
return cast_path(obj)
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
import builtins # module name in python 3
|
|
||||||
except ImportError:
|
|
||||||
import __builtin__ as builtins # noqa: F401
|
|
||||||
|
|
||||||
|
|
||||||
import ast # noqa: F401
|
|
||||||
|
|
||||||
|
|
||||||
def literal_eval(string):
|
|
||||||
return ast.literal_eval(string)
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from itertools import zip_longest
|
|
||||||
except ImportError:
|
|
||||||
from itertools import izip_longest as zip_longest # Python 2 # noqa: F401
|
|
||||||
|
|
||||||
try:
|
|
||||||
FileNotFoundError = FileNotFoundError
|
|
||||||
except NameError:
|
|
||||||
FileNotFoundError = IOError
|
|
||||||
|
|
||||||
try:
|
|
||||||
IsADirectoryError = IsADirectoryError
|
|
||||||
except NameError:
|
|
||||||
IsADirectoryError = IOError
|
|
||||||
|
|
||||||
try:
|
|
||||||
PermissionError = PermissionError
|
|
||||||
except NameError:
|
|
||||||
PermissionError = IOError
|
|
||||||
|
|
||||||
try:
|
|
||||||
NotADirectoryError = NotADirectoryError
|
|
||||||
except NameError:
|
|
||||||
class NotADirectoryError(Exception):
|
|
||||||
# Don't implement this for Python 2 anymore.
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def no_unicode_pprint(dct):
|
|
||||||
"""
|
|
||||||
Python 2/3 dict __repr__ may be different, because of unicode differens
|
|
||||||
(with or without a `u` prefix). Normally in doctests we could use `pprint`
|
|
||||||
to sort dicts and check for equality, but here we have to write a separate
|
|
||||||
function to do that.
|
|
||||||
"""
|
|
||||||
import pprint
|
|
||||||
s = pprint.pformat(dct)
|
|
||||||
print(re.sub("u'", "'", s))
|
|
||||||
|
|
||||||
|
|
||||||
def utf8_repr(func):
|
|
||||||
"""
|
|
||||||
``__repr__`` methods in Python 2 don't allow unicode objects to be
|
|
||||||
returned. Therefore cast them to utf-8 bytes in this decorator.
|
|
||||||
"""
|
|
||||||
def wrapper(self):
|
|
||||||
result = func(self)
|
|
||||||
if isinstance(result, unicode):
|
|
||||||
return result.encode('utf-8')
|
|
||||||
else:
|
|
||||||
return result
|
|
||||||
|
|
||||||
if is_py3:
|
|
||||||
return func
|
|
||||||
else:
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
if is_py3:
|
|
||||||
import queue
|
|
||||||
else:
|
|
||||||
import Queue as queue # noqa: F401
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Attempt to load the C implementation of pickle on Python 2 as it is way
|
|
||||||
# faster.
|
|
||||||
import cPickle as pickle
|
|
||||||
except ImportError:
|
|
||||||
import pickle
|
|
||||||
|
|
||||||
|
|
||||||
def pickle_load(file):
|
def pickle_load(file):
|
||||||
try:
|
try:
|
||||||
if is_py3:
|
|
||||||
return pickle.load(file, encoding='bytes')
|
|
||||||
return pickle.load(file)
|
return pickle.load(file)
|
||||||
# Python on Windows don't throw EOF errors for pipes. So reraise them with
|
# Python on Windows don't throw EOF errors for pipes. So reraise them with
|
||||||
# the correct type, which is caught upwards.
|
# the correct type, which is caught upwards.
|
||||||
@@ -403,24 +34,8 @@ def pickle_load(file):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def _python2_dct_keys_to_unicode(data):
|
|
||||||
"""
|
|
||||||
Python 2 stores object __dict__ entries as bytes, not unicode, correct it
|
|
||||||
here. Python 2 can deal with both, Python 3 expects unicode.
|
|
||||||
"""
|
|
||||||
if isinstance(data, tuple):
|
|
||||||
return tuple(_python2_dct_keys_to_unicode(x) for x in data)
|
|
||||||
elif isinstance(data, list):
|
|
||||||
return list(_python2_dct_keys_to_unicode(x) for x in data)
|
|
||||||
elif hasattr(data, '__dict__') and type(data.__dict__) == dict:
|
|
||||||
data.__dict__ = {unicode(k): v for k, v in data.__dict__.items()}
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def pickle_dump(data, file, protocol):
|
def pickle_dump(data, file, protocol):
|
||||||
try:
|
try:
|
||||||
if not is_py3:
|
|
||||||
data = _python2_dct_keys_to_unicode(data)
|
|
||||||
pickle.dump(data, file, protocol)
|
pickle.dump(data, file, protocol)
|
||||||
# On Python 3.3 flush throws sometimes an error even though the writing
|
# On Python 3.3 flush throws sometimes an error even though the writing
|
||||||
# operation should be completed.
|
# operation should be completed.
|
||||||
@@ -431,201 +46,3 @@ def pickle_dump(data, file, protocol):
|
|||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
raise IOError(errno.EPIPE, "Broken pipe")
|
raise IOError(errno.EPIPE, "Broken pipe")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
# Determine the highest protocol version compatible for a given list of Python
|
|
||||||
# versions.
|
|
||||||
def highest_pickle_protocol(python_versions):
|
|
||||||
protocol = 4
|
|
||||||
for version in python_versions:
|
|
||||||
if version[0] == 2:
|
|
||||||
# The minimum protocol version for the versions of Python that we
|
|
||||||
# support (2.7 and 3.3+) is 2.
|
|
||||||
return 2
|
|
||||||
if version[1] < 4:
|
|
||||||
protocol = 3
|
|
||||||
return protocol
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from inspect import Parameter
|
|
||||||
except ImportError:
|
|
||||||
class Parameter(object):
|
|
||||||
POSITIONAL_ONLY = object()
|
|
||||||
POSITIONAL_OR_KEYWORD = object()
|
|
||||||
VAR_POSITIONAL = object()
|
|
||||||
KEYWORD_ONLY = object()
|
|
||||||
VAR_KEYWORD = object()
|
|
||||||
|
|
||||||
|
|
||||||
class GeneralizedPopen(subprocess.Popen):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
if os.name == 'nt':
|
|
||||||
try:
|
|
||||||
# Was introduced in Python 3.7.
|
|
||||||
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW
|
|
||||||
except AttributeError:
|
|
||||||
CREATE_NO_WINDOW = 0x08000000
|
|
||||||
kwargs['creationflags'] = CREATE_NO_WINDOW
|
|
||||||
# The child process doesn't need file descriptors except 0, 1, 2.
|
|
||||||
# This is unix only.
|
|
||||||
kwargs['close_fds'] = 'posix' in sys.builtin_module_names
|
|
||||||
super(GeneralizedPopen, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
# shutil.which is not available on Python 2.7.
|
|
||||||
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
|
||||||
"""Given a command, mode, and a PATH string, return the path which
|
|
||||||
conforms to the given mode on the PATH, or None if there is no such
|
|
||||||
file.
|
|
||||||
|
|
||||||
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
|
|
||||||
of os.environ.get("PATH"), or can be overridden with a custom search
|
|
||||||
path.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# Check that a given file can be accessed with the correct mode.
|
|
||||||
# Additionally check that `file` is not a directory, as on Windows
|
|
||||||
# directories pass the os.access check.
|
|
||||||
def _access_check(fn, mode):
|
|
||||||
return (os.path.exists(fn) and os.access(fn, mode)
|
|
||||||
and not os.path.isdir(fn))
|
|
||||||
|
|
||||||
# If we're given a path with a directory part, look it up directly rather
|
|
||||||
# than referring to PATH directories. This includes checking relative to the
|
|
||||||
# current directory, e.g. ./script
|
|
||||||
if os.path.dirname(cmd):
|
|
||||||
if _access_check(cmd, mode):
|
|
||||||
return cmd
|
|
||||||
return None
|
|
||||||
|
|
||||||
if path is None:
|
|
||||||
path = os.environ.get("PATH", os.defpath)
|
|
||||||
if not path:
|
|
||||||
return None
|
|
||||||
path = path.split(os.pathsep)
|
|
||||||
|
|
||||||
if sys.platform == "win32":
|
|
||||||
# The current directory takes precedence on Windows.
|
|
||||||
if os.curdir not in path:
|
|
||||||
path.insert(0, os.curdir)
|
|
||||||
|
|
||||||
# PATHEXT is necessary to check on Windows.
|
|
||||||
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
|
|
||||||
# See if the given file matches any of the expected path extensions.
|
|
||||||
# This will allow us to short circuit when given "python.exe".
|
|
||||||
# If it does match, only test that one, otherwise we have to try
|
|
||||||
# others.
|
|
||||||
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
|
|
||||||
files = [cmd]
|
|
||||||
else:
|
|
||||||
files = [cmd + ext for ext in pathext]
|
|
||||||
else:
|
|
||||||
# On other platforms you don't have things like PATHEXT to tell you
|
|
||||||
# what file suffixes are executable, so just pass on cmd as-is.
|
|
||||||
files = [cmd]
|
|
||||||
|
|
||||||
seen = set()
|
|
||||||
for dir in path:
|
|
||||||
normdir = os.path.normcase(dir)
|
|
||||||
if normdir not in seen:
|
|
||||||
seen.add(normdir)
|
|
||||||
for thefile in files:
|
|
||||||
name = os.path.join(dir, thefile)
|
|
||||||
if _access_check(name, mode):
|
|
||||||
return name
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
if not is_py3:
|
|
||||||
# Simplified backport of Python 3 weakref.finalize:
|
|
||||||
# https://github.com/python/cpython/blob/ded4737989316653469763230036b04513cb62b3/Lib/weakref.py#L502-L662
|
|
||||||
class finalize(object):
|
|
||||||
"""Class for finalization of weakrefable objects.
|
|
||||||
|
|
||||||
finalize(obj, func, *args, **kwargs) returns a callable finalizer
|
|
||||||
object which will be called when obj is garbage collected. The
|
|
||||||
first time the finalizer is called it evaluates func(*arg, **kwargs)
|
|
||||||
and returns the result. After this the finalizer is dead, and
|
|
||||||
calling it just returns None.
|
|
||||||
|
|
||||||
When the program exits any remaining finalizers will be run.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Finalizer objects don't have any state of their own.
|
|
||||||
# This ensures that they cannot be part of a ref-cycle.
|
|
||||||
__slots__ = ()
|
|
||||||
_registry = {}
|
|
||||||
|
|
||||||
def __init__(self, obj, func, *args, **kwargs):
|
|
||||||
info = functools.partial(func, *args, **kwargs)
|
|
||||||
info.weakref = weakref.ref(obj, self)
|
|
||||||
self._registry[self] = info
|
|
||||||
|
|
||||||
# To me it's an absolute mystery why in Python 2 we need _=None. It
|
|
||||||
# makes really no sense since it's never really called. Then again it
|
|
||||||
# might be called by Python 2.7 itself, but weakref.finalize is not
|
|
||||||
# documented in Python 2 and therefore shouldn't be randomly called.
|
|
||||||
# We never call this stuff with a parameter and therefore this
|
|
||||||
# parameter should not be needed. But it is. ~dave
|
|
||||||
def __call__(self, _=None):
|
|
||||||
"""Return func(*args, **kwargs) if alive."""
|
|
||||||
info = self._registry.pop(self, None)
|
|
||||||
if info:
|
|
||||||
return info()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _exitfunc(cls):
|
|
||||||
if not cls._registry:
|
|
||||||
return
|
|
||||||
for finalizer in list(cls._registry):
|
|
||||||
try:
|
|
||||||
finalizer()
|
|
||||||
except Exception:
|
|
||||||
sys.excepthook(*sys.exc_info())
|
|
||||||
assert finalizer not in cls._registry
|
|
||||||
|
|
||||||
atexit.register(finalize._exitfunc)
|
|
||||||
weakref.finalize = finalize
|
|
||||||
|
|
||||||
|
|
||||||
if is_py3 and sys.version_info[1] > 5:
|
|
||||||
from inspect import unwrap
|
|
||||||
else:
|
|
||||||
# Only Python >=3.6 does properly limit the amount of unwraps. This is very
|
|
||||||
# relevant in the case of unittest.mock.patch.
|
|
||||||
# Below is the implementation of Python 3.7.
|
|
||||||
def unwrap(func, stop=None):
|
|
||||||
"""Get the object wrapped by *func*.
|
|
||||||
|
|
||||||
Follows the chain of :attr:`__wrapped__` attributes returning the last
|
|
||||||
object in the chain.
|
|
||||||
|
|
||||||
*stop* is an optional callback accepting an object in the wrapper chain
|
|
||||||
as its sole argument that allows the unwrapping to be terminated early if
|
|
||||||
the callback returns a true value. If the callback never returns a true
|
|
||||||
value, the last object in the chain is returned as usual. For example,
|
|
||||||
:func:`signature` uses this to stop unwrapping if any object in the
|
|
||||||
chain has a ``__signature__`` attribute defined.
|
|
||||||
|
|
||||||
:exc:`ValueError` is raised if a cycle is encountered.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if stop is None:
|
|
||||||
def _is_wrapper(f):
|
|
||||||
return hasattr(f, '__wrapped__')
|
|
||||||
else:
|
|
||||||
def _is_wrapper(f):
|
|
||||||
return hasattr(f, '__wrapped__') and not stop(f)
|
|
||||||
f = func # remember the original func for error reporting
|
|
||||||
# Memoise by id to tolerate non-hashable objects, but store objects to
|
|
||||||
# ensure they aren't destroyed, which would allow their IDs to be reused.
|
|
||||||
memo = {id(f): f}
|
|
||||||
recursion_limit = sys.getrecursionlimit()
|
|
||||||
while _is_wrapper(func):
|
|
||||||
func = func.__wrapped__
|
|
||||||
id_func = id(func)
|
|
||||||
if (id_func in memo) or (len(memo) >= recursion_limit):
|
|
||||||
raise ValueError('wrapper loop when unwrapping {!r}'.format(f))
|
|
||||||
memo[id_func] = func
|
|
||||||
return func
|
|
||||||
|
|||||||
+36
-93
@@ -7,15 +7,14 @@ Alternatively, if you don't need a custom function and are happy with printing
|
|||||||
debug messages to stdout, simply call :func:`set_debug_function` without
|
debug messages to stdout, simply call :func:`set_debug_function` without
|
||||||
arguments.
|
arguments.
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from functools import wraps
|
from pathlib import Path
|
||||||
|
|
||||||
import parso
|
import parso
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
from jedi._compatibility import force_unicode, cast_path, is_py3
|
from jedi._compatibility import cast_path
|
||||||
from jedi.parser_utils import get_executable_nodes
|
from jedi.parser_utils import get_executable_nodes
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
@@ -51,18 +50,6 @@ from jedi.inference.utils import to_list
|
|||||||
sys.setrecursionlimit(3000)
|
sys.setrecursionlimit(3000)
|
||||||
|
|
||||||
|
|
||||||
def _no_python2_support(func):
|
|
||||||
# TODO remove when removing Python 2/3.5
|
|
||||||
@wraps(func)
|
|
||||||
def wrapper(self, *args, **kwargs):
|
|
||||||
if self._inference_state.grammar.version_info < (3, 6) or sys.version_info < (3, 6):
|
|
||||||
raise NotImplementedError(
|
|
||||||
"No support for refactorings/search on Python 2/3.5"
|
|
||||||
)
|
|
||||||
return func(self, *args, **kwargs)
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
class Script(object):
|
class Script(object):
|
||||||
"""
|
"""
|
||||||
A Script is the base for completions, goto or whatever you want to do with
|
A Script is the base for completions, goto or whatever you want to do with
|
||||||
@@ -109,10 +96,7 @@ class Script(object):
|
|||||||
:type column: int
|
:type column: int
|
||||||
:param path: The path of the file in the file system, or ``''`` if
|
:param path: The path of the file in the file system, or ``''`` if
|
||||||
it hasn't been saved yet.
|
it hasn't been saved yet.
|
||||||
:type path: str or None
|
:type path: str or pathlib.Path or None
|
||||||
:param encoding: Deprecated, cast to unicode yourself. The encoding of
|
|
||||||
``code``, if it is not a ``unicode`` object (default ``'utf-8'``).
|
|
||||||
:type encoding: str
|
|
||||||
:param sys_path: Deprecated, use the project parameter.
|
:param sys_path: Deprecated, use the project parameter.
|
||||||
:type sys_path: typing.List[str]
|
:type sys_path: typing.List[str]
|
||||||
:param Environment environment: Provide a predefined :ref:`Environment <environments>`
|
:param Environment environment: Provide a predefined :ref:`Environment <environments>`
|
||||||
@@ -122,21 +106,14 @@ class Script(object):
|
|||||||
also ways to modify the sys path and other things.
|
also ways to modify the sys path and other things.
|
||||||
"""
|
"""
|
||||||
def __init__(self, code=None, line=None, column=None, path=None,
|
def __init__(self, code=None, line=None, column=None, path=None,
|
||||||
encoding=None, sys_path=None, environment=None,
|
sys_path=None, environment=None, project=None, source=None):
|
||||||
project=None, source=None):
|
|
||||||
self._orig_path = path
|
self._orig_path = path
|
||||||
# An empty path (also empty string) should always result in no path.
|
# An empty path (also empty string) should always result in no path.
|
||||||
self.path = os.path.abspath(path) if path else None
|
if isinstance(path, str):
|
||||||
|
path = Path(path)
|
||||||
|
|
||||||
|
self.path = path.absolute() if path else None
|
||||||
|
|
||||||
if encoding is None:
|
|
||||||
encoding = 'utf-8'
|
|
||||||
else:
|
|
||||||
warnings.warn(
|
|
||||||
"Deprecated since version 0.17.0. You should cast to valid "
|
|
||||||
"unicode yourself, especially if you are not using utf-8.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2
|
|
||||||
)
|
|
||||||
if line is not None:
|
if line is not None:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Providing the line is now done in the functions themselves "
|
"Providing the line is now done in the functions themselves "
|
||||||
@@ -163,14 +140,9 @@ class Script(object):
|
|||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
code = f.read()
|
code = f.read()
|
||||||
|
|
||||||
if sys_path is not None and not is_py3:
|
|
||||||
sys_path = list(map(force_unicode, sys_path))
|
|
||||||
|
|
||||||
if project is None:
|
if project is None:
|
||||||
# Load the Python grammar of the current interpreter.
|
# Load the Python grammar of the current interpreter.
|
||||||
project = get_default_project(
|
project = get_default_project(None if self.path is None else self.path.parent)
|
||||||
os.path.dirname(self.path) if path else None
|
|
||||||
)
|
|
||||||
# TODO deprecate and remove sys_path from the Script API.
|
# TODO deprecate and remove sys_path from the Script API.
|
||||||
if sys_path is not None:
|
if sys_path is not None:
|
||||||
project._sys_path = sys_path
|
project._sys_path = sys_path
|
||||||
@@ -188,8 +160,7 @@ class Script(object):
|
|||||||
self._module_node, code = self._inference_state.parse_and_get_code(
|
self._module_node, code = self._inference_state.parse_and_get_code(
|
||||||
code=code,
|
code=code,
|
||||||
path=self.path,
|
path=self.path,
|
||||||
encoding=encoding,
|
use_latest_grammar=path and path.suffix == 'pyi',
|
||||||
use_latest_grammar=path and path.endswith('.pyi'),
|
|
||||||
cache=False, # No disk cache, because the current script often changes.
|
cache=False, # No disk cache, because the current script often changes.
|
||||||
diff_cache=settings.fast_parser,
|
diff_cache=settings.fast_parser,
|
||||||
cache_path=settings.cache_directory,
|
cache_path=settings.cache_directory,
|
||||||
@@ -221,7 +192,7 @@ class Script(object):
|
|||||||
file_io = None
|
file_io = None
|
||||||
else:
|
else:
|
||||||
file_io = KnownContentFileIO(cast_path(self.path), self._code)
|
file_io = KnownContentFileIO(cast_path(self.path), self._code)
|
||||||
if self.path is not None and self.path.endswith('.pyi'):
|
if self.path is not None and self.path.suffix == '.pyi':
|
||||||
# We are in a stub file. Try to load the stub properly.
|
# We are in a stub file. Try to load the stub properly.
|
||||||
stub_module = load_proper_stub_module(
|
stub_module = load_proper_stub_module(
|
||||||
self._inference_state,
|
self._inference_state,
|
||||||
@@ -242,7 +213,7 @@ class Script(object):
|
|||||||
code_lines=self._code_lines,
|
code_lines=self._code_lines,
|
||||||
is_package=is_package,
|
is_package=is_package,
|
||||||
)
|
)
|
||||||
if names[0] not in ('builtins', '__builtin__', 'typing'):
|
if names[0] not in ('builtins', 'typing'):
|
||||||
# These modules are essential for Jedi, so don't overwrite them.
|
# These modules are essential for Jedi, so don't overwrite them.
|
||||||
self._inference_state.module_cache.add(names, ValueSet([module]))
|
self._inference_state.module_cache.add(names, ValueSet([module]))
|
||||||
return module
|
return module
|
||||||
@@ -258,7 +229,7 @@ class Script(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@validate_line_column
|
@validate_line_column
|
||||||
def complete(self, line=None, column=None, **kwargs):
|
def complete(self, line=None, column=None, *, fuzzy=False):
|
||||||
"""
|
"""
|
||||||
Completes objects under the cursor.
|
Completes objects under the cursor.
|
||||||
|
|
||||||
@@ -272,9 +243,6 @@ class Script(object):
|
|||||||
before magic methods and name mangled names that start with ``__``.
|
before magic methods and name mangled names that start with ``__``.
|
||||||
:rtype: list of :class:`.Completion`
|
:rtype: list of :class:`.Completion`
|
||||||
"""
|
"""
|
||||||
return self._complete(line, column, **kwargs)
|
|
||||||
|
|
||||||
def _complete(self, line, column, fuzzy=False): # Python 2...
|
|
||||||
with debug.increase_indent_cm('complete'):
|
with debug.increase_indent_cm('complete'):
|
||||||
completion = Completion(
|
completion = Completion(
|
||||||
self._inference_state, self._get_module_context(), self._code_lines,
|
self._inference_state, self._get_module_context(), self._code_lines,
|
||||||
@@ -291,7 +259,7 @@ class Script(object):
|
|||||||
return self.complete(*self._pos, fuzzy=fuzzy)
|
return self.complete(*self._pos, fuzzy=fuzzy)
|
||||||
|
|
||||||
@validate_line_column
|
@validate_line_column
|
||||||
def infer(self, line=None, column=None, **kwargs):
|
def infer(self, line=None, column=None, *, only_stubs=False, prefer_stubs=False):
|
||||||
"""
|
"""
|
||||||
Return the definitions of under the cursor. It is basically a wrapper
|
Return the definitions of under the cursor. It is basically a wrapper
|
||||||
around Jedi's type inference.
|
around Jedi's type inference.
|
||||||
@@ -307,18 +275,6 @@ class Script(object):
|
|||||||
:param prefer_stubs: Prefer stubs to Python objects for this method.
|
:param prefer_stubs: Prefer stubs to Python objects for this method.
|
||||||
:rtype: list of :class:`.Name`
|
:rtype: list of :class:`.Name`
|
||||||
"""
|
"""
|
||||||
with debug.increase_indent_cm('infer'):
|
|
||||||
return self._infer(line, column, **kwargs)
|
|
||||||
|
|
||||||
def goto_definitions(self, **kwargs):
|
|
||||||
warnings.warn(
|
|
||||||
"Deprecated since version 0.16.0. Use Script(...).infer instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2
|
|
||||||
)
|
|
||||||
return self.infer(*self._pos, **kwargs)
|
|
||||||
|
|
||||||
def _infer(self, line, column, only_stubs=False, prefer_stubs=False):
|
|
||||||
pos = line, column
|
pos = line, column
|
||||||
leaf = self._module_node.get_name_of_position(pos)
|
leaf = self._module_node.get_name_of_position(pos)
|
||||||
if leaf is None:
|
if leaf is None:
|
||||||
@@ -341,6 +297,14 @@ class Script(object):
|
|||||||
# the API.
|
# the API.
|
||||||
return helpers.sorted_definitions(set(defs))
|
return helpers.sorted_definitions(set(defs))
|
||||||
|
|
||||||
|
def goto_definitions(self, **kwargs):
|
||||||
|
warnings.warn(
|
||||||
|
"Deprecated since version 0.16.0. Use Script(...).infer instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2
|
||||||
|
)
|
||||||
|
return self.infer(*self._pos, **kwargs)
|
||||||
|
|
||||||
def goto_assignments(self, follow_imports=False, follow_builtin_imports=False, **kwargs):
|
def goto_assignments(self, follow_imports=False, follow_builtin_imports=False, **kwargs):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Deprecated since version 0.16.0. Use Script(...).goto instead.",
|
"Deprecated since version 0.16.0. Use Script(...).goto instead.",
|
||||||
@@ -353,7 +317,8 @@ class Script(object):
|
|||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
@validate_line_column
|
@validate_line_column
|
||||||
def goto(self, line=None, column=None, **kwargs):
|
def goto(self, line=None, column=None, *, follow_imports=False, follow_builtin_imports=False,
|
||||||
|
only_stubs=False, prefer_stubs=False):
|
||||||
"""
|
"""
|
||||||
Goes to the name that defined the object under the cursor. Optionally
|
Goes to the name that defined the object under the cursor. Optionally
|
||||||
you can follow imports.
|
you can follow imports.
|
||||||
@@ -367,11 +332,6 @@ class Script(object):
|
|||||||
:param prefer_stubs: Prefer stubs to Python objects for this method.
|
:param prefer_stubs: Prefer stubs to Python objects for this method.
|
||||||
:rtype: list of :class:`.Name`
|
:rtype: list of :class:`.Name`
|
||||||
"""
|
"""
|
||||||
with debug.increase_indent_cm('goto'):
|
|
||||||
return self._goto(line, column, **kwargs)
|
|
||||||
|
|
||||||
def _goto(self, line, column, follow_imports=False, follow_builtin_imports=False,
|
|
||||||
only_stubs=False, prefer_stubs=False):
|
|
||||||
tree_name = self._module_node.get_name_of_position((line, column))
|
tree_name = self._module_node.get_name_of_position((line, column))
|
||||||
if tree_name is None:
|
if tree_name is None:
|
||||||
# Without a name we really just want to jump to the result e.g.
|
# Without a name we really just want to jump to the result e.g.
|
||||||
@@ -407,8 +367,7 @@ class Script(object):
|
|||||||
# Avoid duplicates
|
# Avoid duplicates
|
||||||
return list(set(helpers.sorted_definitions(defs)))
|
return list(set(helpers.sorted_definitions(defs)))
|
||||||
|
|
||||||
@_no_python2_support
|
def search(self, string, *, all_scopes=False):
|
||||||
def search(self, string, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Searches a name in the current file. For a description of how the
|
Searches a name in the current file. For a description of how the
|
||||||
search string should look like, please have a look at
|
search string should look like, please have a look at
|
||||||
@@ -419,9 +378,6 @@ class Script(object):
|
|||||||
functions and classes.
|
functions and classes.
|
||||||
:yields: :class:`.Name`
|
:yields: :class:`.Name`
|
||||||
"""
|
"""
|
||||||
return self._search(string, **kwargs) # Python 2 ...
|
|
||||||
|
|
||||||
def _search(self, string, all_scopes=False):
|
|
||||||
return self._search_func(string, all_scopes=all_scopes)
|
return self._search_func(string, all_scopes=all_scopes)
|
||||||
|
|
||||||
@to_list
|
@to_list
|
||||||
@@ -685,8 +641,7 @@ class Script(object):
|
|||||||
]
|
]
|
||||||
return sorted(defs, key=lambda x: x.start_pos)
|
return sorted(defs, key=lambda x: x.start_pos)
|
||||||
|
|
||||||
@_no_python2_support
|
def rename(self, line=None, column=None, *, new_name):
|
||||||
def rename(self, line=None, column=None, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Renames all references of the variable under the cursor.
|
Renames all references of the variable under the cursor.
|
||||||
|
|
||||||
@@ -695,14 +650,11 @@ class Script(object):
|
|||||||
:raises: :exc:`.RefactoringError`
|
:raises: :exc:`.RefactoringError`
|
||||||
:rtype: :class:`.Refactoring`
|
:rtype: :class:`.Refactoring`
|
||||||
"""
|
"""
|
||||||
return self._rename(line, column, **kwargs)
|
|
||||||
|
|
||||||
def _rename(self, line, column, new_name): # Python 2...
|
|
||||||
definitions = self.get_references(line, column, include_builtins=False)
|
definitions = self.get_references(line, column, include_builtins=False)
|
||||||
return refactoring.rename(self._inference_state, definitions, new_name)
|
return refactoring.rename(self._inference_state, definitions, new_name)
|
||||||
|
|
||||||
@_no_python2_support
|
@validate_line_column
|
||||||
def extract_variable(self, line, column, **kwargs):
|
def extract_variable(self, line, column, *, new_name, until_line=None, until_column=None):
|
||||||
"""
|
"""
|
||||||
Moves an expression to a new statemenet.
|
Moves an expression to a new statemenet.
|
||||||
|
|
||||||
@@ -727,10 +679,6 @@ class Script(object):
|
|||||||
:raises: :exc:`.RefactoringError`
|
:raises: :exc:`.RefactoringError`
|
||||||
:rtype: :class:`.Refactoring`
|
:rtype: :class:`.Refactoring`
|
||||||
"""
|
"""
|
||||||
return self._extract_variable(line, column, **kwargs) # Python 2...
|
|
||||||
|
|
||||||
@validate_line_column
|
|
||||||
def _extract_variable(self, line, column, new_name, until_line=None, until_column=None):
|
|
||||||
if until_line is None and until_column is None:
|
if until_line is None and until_column is None:
|
||||||
until_pos = None
|
until_pos = None
|
||||||
else:
|
else:
|
||||||
@@ -744,8 +692,8 @@ class Script(object):
|
|||||||
new_name, (line, column), until_pos
|
new_name, (line, column), until_pos
|
||||||
)
|
)
|
||||||
|
|
||||||
@_no_python2_support
|
@validate_line_column
|
||||||
def extract_function(self, line, column, **kwargs):
|
def extract_function(self, line, column, *, new_name, until_line=None, until_column=None):
|
||||||
"""
|
"""
|
||||||
Moves an expression to a new function.
|
Moves an expression to a new function.
|
||||||
|
|
||||||
@@ -778,10 +726,6 @@ class Script(object):
|
|||||||
:raises: :exc:`.RefactoringError`
|
:raises: :exc:`.RefactoringError`
|
||||||
:rtype: :class:`.Refactoring`
|
:rtype: :class:`.Refactoring`
|
||||||
"""
|
"""
|
||||||
return self._extract_function(line, column, **kwargs) # Python 2...
|
|
||||||
|
|
||||||
@validate_line_column
|
|
||||||
def _extract_function(self, line, column, new_name, until_line=None, until_column=None):
|
|
||||||
if until_line is None and until_column is None:
|
if until_line is None and until_column is None:
|
||||||
until_pos = None
|
until_pos = None
|
||||||
else:
|
else:
|
||||||
@@ -795,7 +739,6 @@ class Script(object):
|
|||||||
new_name, (line, column), until_pos
|
new_name, (line, column), until_pos
|
||||||
)
|
)
|
||||||
|
|
||||||
@_no_python2_support
|
|
||||||
def inline(self, line=None, column=None):
|
def inline(self, line=None, column=None):
|
||||||
"""
|
"""
|
||||||
Inlines a variable under the cursor. This is basically the opposite of
|
Inlines a variable under the cursor. This is basically the opposite of
|
||||||
@@ -855,8 +798,8 @@ class Interpreter(Script):
|
|||||||
if not isinstance(environment, InterpreterEnvironment):
|
if not isinstance(environment, InterpreterEnvironment):
|
||||||
raise TypeError("The environment needs to be an InterpreterEnvironment subclass.")
|
raise TypeError("The environment needs to be an InterpreterEnvironment subclass.")
|
||||||
|
|
||||||
super(Interpreter, self).__init__(code, environment=environment,
|
super().__init__(code, environment=environment,
|
||||||
project=Project(os.getcwd()), **kwds)
|
project=Project(Path.cwd()), **kwds)
|
||||||
self.namespaces = namespaces
|
self.namespaces = namespaces
|
||||||
self._inference_state.allow_descriptor_getattr = self._allow_descriptor_getattr_default
|
self._inference_state.allow_descriptor_getattr = self._allow_descriptor_getattr_default
|
||||||
|
|
||||||
@@ -864,7 +807,7 @@ class Interpreter(Script):
|
|||||||
def _get_module_context(self):
|
def _get_module_context(self):
|
||||||
tree_module_value = ModuleValue(
|
tree_module_value = ModuleValue(
|
||||||
self._inference_state, self._module_node,
|
self._inference_state, self._module_node,
|
||||||
file_io=KnownContentFileIO(self.path, self._code),
|
file_io=KnownContentFileIO(str(self.path), self._code),
|
||||||
string_names=('__main__',),
|
string_names=('__main__',),
|
||||||
code_lines=self._code_lines,
|
code_lines=self._code_lines,
|
||||||
)
|
)
|
||||||
@@ -874,7 +817,7 @@ class Interpreter(Script):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def names(source=None, path=None, encoding='utf-8', all_scopes=False,
|
def names(source=None, path=None, all_scopes=False,
|
||||||
definitions=True, references=False, environment=None):
|
definitions=True, references=False, environment=None):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Deprecated since version 0.16.0. Use Script(...).get_names instead.",
|
"Deprecated since version 0.16.0. Use Script(...).get_names instead.",
|
||||||
@@ -882,7 +825,7 @@ def names(source=None, path=None, encoding='utf-8', all_scopes=False,
|
|||||||
stacklevel=2
|
stacklevel=2
|
||||||
)
|
)
|
||||||
|
|
||||||
return Script(source, path=path, encoding=encoding).get_names(
|
return Script(source, path=path).get_names(
|
||||||
all_scopes=all_scopes,
|
all_scopes=all_scopes,
|
||||||
definitions=definitions,
|
definitions=definitions,
|
||||||
references=references,
|
references=references,
|
||||||
@@ -899,7 +842,7 @@ def preload_module(*modules):
|
|||||||
"""
|
"""
|
||||||
for m in modules:
|
for m in modules:
|
||||||
s = "import %s as x; x." % m
|
s = "import %s as x; x." % m
|
||||||
Script(s, path=None).complete(1, len(s))
|
Script(s).complete(1, len(s))
|
||||||
|
|
||||||
|
|
||||||
def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
|
def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
|
||||||
|
|||||||
+35
-46
@@ -14,8 +14,8 @@ These classes are the much biggest part of the API, because they contain
|
|||||||
the interesting information about all operations.
|
the interesting information about all operations.
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
import warnings
|
import warnings
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from parso.python.tree import search_ancestor
|
from parso.python.tree import search_ancestor
|
||||||
|
|
||||||
@@ -71,7 +71,6 @@ class BaseName(object):
|
|||||||
'_collections': 'collections',
|
'_collections': 'collections',
|
||||||
'_socket': 'socket',
|
'_socket': 'socket',
|
||||||
'_sqlite3': 'sqlite3',
|
'_sqlite3': 'sqlite3',
|
||||||
'__builtin__': 'builtins',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_tuple_mapping = dict((tuple(k.split('.')), v) for (k, v) in {
|
_tuple_mapping = dict((tuple(k.split('.')), v) for (k, v) in {
|
||||||
@@ -94,9 +93,9 @@ class BaseName(object):
|
|||||||
return self._name.get_root_context()
|
return self._name.get_root_context()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def module_path(self):
|
def module_path(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``
|
Shows the file path of a module. e.g. ``/usr/lib/python3.9/os.py``
|
||||||
|
|
||||||
:rtype: str or None
|
:rtype: str or None
|
||||||
"""
|
"""
|
||||||
@@ -104,7 +103,9 @@ class BaseName(object):
|
|||||||
if module.is_stub() or not module.is_compiled():
|
if module.is_stub() or not module.is_compiled():
|
||||||
# Compiled modules should not return a module path even if they
|
# Compiled modules should not return a module path even if they
|
||||||
# have one.
|
# have one.
|
||||||
return self._get_module_context().py__file__()
|
path = self._get_module_context().py__file__()
|
||||||
|
if path is not None:
|
||||||
|
return path
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -129,7 +130,6 @@ class BaseName(object):
|
|||||||
to Jedi, :meth:`jedi.Script.infer` should return a list of
|
to Jedi, :meth:`jedi.Script.infer` should return a list of
|
||||||
definition for ``sys``, ``f``, ``C`` and ``x``.
|
definition for ``sys``, ``f``, ``C`` and ``x``.
|
||||||
|
|
||||||
>>> from jedi._compatibility import no_unicode_pprint
|
|
||||||
>>> from jedi import Script
|
>>> from jedi import Script
|
||||||
>>> source = '''
|
>>> source = '''
|
||||||
... import keyword
|
... import keyword
|
||||||
@@ -155,7 +155,7 @@ class BaseName(object):
|
|||||||
so that it is easy to relate the result to the source code.
|
so that it is easy to relate the result to the source code.
|
||||||
|
|
||||||
>>> defs = sorted(defs, key=lambda d: d.line)
|
>>> defs = sorted(defs, key=lambda d: d.line)
|
||||||
>>> no_unicode_pprint(defs) # doctest: +NORMALIZE_WHITESPACE
|
>>> print(defs) # doctest: +NORMALIZE_WHITESPACE
|
||||||
[<Name full_name='keyword', description='module keyword'>,
|
[<Name full_name='keyword', description='module keyword'>,
|
||||||
<Name full_name='__main__.C', description='class C'>,
|
<Name full_name='__main__.C', description='class C'>,
|
||||||
<Name full_name='__main__.D', description='instance D'>,
|
<Name full_name='__main__.D', description='instance D'>,
|
||||||
@@ -163,7 +163,7 @@ class BaseName(object):
|
|||||||
|
|
||||||
Finally, here is what you can get from :attr:`type`:
|
Finally, here is what you can get from :attr:`type`:
|
||||||
|
|
||||||
>>> defs = [str(d.type) for d in defs] # It's unicode and in Py2 has u before it.
|
>>> defs = [d.type for d in defs]
|
||||||
>>> defs[0]
|
>>> defs[0]
|
||||||
'module'
|
'module'
|
||||||
>>> defs[1]
|
>>> defs[1]
|
||||||
@@ -324,7 +324,6 @@ class BaseName(object):
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
>>> from jedi._compatibility import no_unicode_pprint
|
|
||||||
>>> from jedi import Script
|
>>> from jedi import Script
|
||||||
>>> source = '''
|
>>> source = '''
|
||||||
... def f():
|
... def f():
|
||||||
@@ -337,10 +336,10 @@ class BaseName(object):
|
|||||||
>>> script = Script(source) # line is maximum by default
|
>>> script = Script(source) # line is maximum by default
|
||||||
>>> defs = script.infer(column=3)
|
>>> defs = script.infer(column=3)
|
||||||
>>> defs = sorted(defs, key=lambda d: d.line)
|
>>> defs = sorted(defs, key=lambda d: d.line)
|
||||||
>>> no_unicode_pprint(defs) # doctest: +NORMALIZE_WHITESPACE
|
>>> print(defs) # doctest: +NORMALIZE_WHITESPACE
|
||||||
[<Name full_name='__main__.f', description='def f'>,
|
[<Name full_name='__main__.f', description='def f'>,
|
||||||
<Name full_name='__main__.C', description='class C'>]
|
<Name full_name='__main__.C', description='class C'>]
|
||||||
>>> str(defs[0].description) # strip literals in python2
|
>>> str(defs[0].description)
|
||||||
'def f'
|
'def f'
|
||||||
>>> str(defs[1].description)
|
>>> str(defs[1].description)
|
||||||
'class C'
|
'class C'
|
||||||
@@ -424,7 +423,10 @@ class BaseName(object):
|
|||||||
return False
|
return False
|
||||||
return tree_name.is_definition() and tree_name.parent.type == 'trailer'
|
return tree_name.is_definition() and tree_name.parent.type == 'trailer'
|
||||||
|
|
||||||
def goto(self, **kwargs):
|
@debug.increase_indent_cm('goto on name')
|
||||||
|
def goto(self, *, follow_imports=False, follow_builtin_imports=False,
|
||||||
|
only_stubs=False, prefer_stubs=False):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Like :meth:`.Script.goto` (also supports the same params), but does it
|
Like :meth:`.Script.goto` (also supports the same params), but does it
|
||||||
for the current name. This is typically useful if you are using
|
for the current name. This is typically useful if you are using
|
||||||
@@ -437,20 +439,6 @@ class BaseName(object):
|
|||||||
:param prefer_stubs: Prefer stubs to Python objects for this goto call.
|
:param prefer_stubs: Prefer stubs to Python objects for this goto call.
|
||||||
:rtype: list of :class:`Name`
|
:rtype: list of :class:`Name`
|
||||||
"""
|
"""
|
||||||
with debug.increase_indent_cm('goto for %s' % self._name):
|
|
||||||
return self._goto(**kwargs)
|
|
||||||
|
|
||||||
def goto_assignments(self, **kwargs): # Python 2...
|
|
||||||
warnings.warn(
|
|
||||||
"Deprecated since version 0.16.0. Use .goto.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2
|
|
||||||
)
|
|
||||||
return self.goto(**kwargs)
|
|
||||||
|
|
||||||
def _goto(self, follow_imports=False, follow_builtin_imports=False,
|
|
||||||
only_stubs=False, prefer_stubs=False):
|
|
||||||
|
|
||||||
if not self._name.is_value_name:
|
if not self._name.is_value_name:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -465,7 +453,16 @@ class BaseName(object):
|
|||||||
return [self if n == self._name else Name(self._inference_state, n)
|
return [self if n == self._name else Name(self._inference_state, n)
|
||||||
for n in names]
|
for n in names]
|
||||||
|
|
||||||
def infer(self, **kwargs): # Python 2...
|
def goto_assignments(self, **kwargs):
|
||||||
|
warnings.warn(
|
||||||
|
"Deprecated since version 0.16.0. Use .goto.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2
|
||||||
|
)
|
||||||
|
return self.goto(**kwargs)
|
||||||
|
|
||||||
|
@debug.increase_indent_cm('infer on name')
|
||||||
|
def infer(self, *, only_stubs=False, prefer_stubs=False):
|
||||||
"""
|
"""
|
||||||
Like :meth:`.Script.infer`, it can be useful to understand which type
|
Like :meth:`.Script.infer`, it can be useful to understand which type
|
||||||
the current name has.
|
the current name has.
|
||||||
@@ -482,10 +479,6 @@ class BaseName(object):
|
|||||||
inference call.
|
inference call.
|
||||||
:rtype: list of :class:`Name`
|
:rtype: list of :class:`Name`
|
||||||
"""
|
"""
|
||||||
with debug.increase_indent_cm('infer for %s' % self._name):
|
|
||||||
return self._infer(**kwargs)
|
|
||||||
|
|
||||||
def _infer(self, only_stubs=False, prefer_stubs=False):
|
|
||||||
assert not (only_stubs and prefer_stubs)
|
assert not (only_stubs and prefer_stubs)
|
||||||
|
|
||||||
if not self._name.is_value_name:
|
if not self._name.is_value_name:
|
||||||
@@ -645,7 +638,7 @@ class Completion(BaseName):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, inference_state, name, stack, like_name_length,
|
def __init__(self, inference_state, name, stack, like_name_length,
|
||||||
is_fuzzy, cached_name=None):
|
is_fuzzy, cached_name=None):
|
||||||
super(Completion, self).__init__(inference_state, name)
|
super().__init__(inference_state, name)
|
||||||
|
|
||||||
self._like_name_length = like_name_length
|
self._like_name_length = like_name_length
|
||||||
self._stack = stack
|
self._stack = stack
|
||||||
@@ -716,7 +709,7 @@ class Completion(BaseName):
|
|||||||
# wouldn't load like > 100 Python modules anymore.
|
# wouldn't load like > 100 Python modules anymore.
|
||||||
fast = False
|
fast = False
|
||||||
|
|
||||||
return super(Completion, self).docstring(raw=raw, fast=fast)
|
return super().docstring(raw=raw, fast=fast)
|
||||||
|
|
||||||
def _get_docstring(self):
|
def _get_docstring(self):
|
||||||
if self._cached_name is not None:
|
if self._cached_name is not None:
|
||||||
@@ -725,7 +718,7 @@ class Completion(BaseName):
|
|||||||
self._name.get_public_name(),
|
self._name.get_public_name(),
|
||||||
lambda: self._get_cache()
|
lambda: self._get_cache()
|
||||||
)
|
)
|
||||||
return super(Completion, self)._get_docstring()
|
return super()._get_docstring()
|
||||||
|
|
||||||
def _get_docstring_signature(self):
|
def _get_docstring_signature(self):
|
||||||
if self._cached_name is not None:
|
if self._cached_name is not None:
|
||||||
@@ -734,13 +727,13 @@ class Completion(BaseName):
|
|||||||
self._name.get_public_name(),
|
self._name.get_public_name(),
|
||||||
lambda: self._get_cache()
|
lambda: self._get_cache()
|
||||||
)
|
)
|
||||||
return super(Completion, self)._get_docstring_signature()
|
return super()._get_docstring_signature()
|
||||||
|
|
||||||
def _get_cache(self):
|
def _get_cache(self):
|
||||||
return (
|
return (
|
||||||
super(Completion, self).type,
|
super().type,
|
||||||
super(Completion, self)._get_docstring_signature(),
|
super()._get_docstring_signature(),
|
||||||
super(Completion, self)._get_docstring(),
|
super()._get_docstring(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -756,7 +749,7 @@ class Completion(BaseName):
|
|||||||
lambda: self._get_cache()
|
lambda: self._get_cache()
|
||||||
)
|
)
|
||||||
|
|
||||||
return super(Completion, self).type
|
return super().type
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (type(self).__name__, self._name.get_public_name())
|
return '<%s: %s>' % (type(self).__name__, self._name.get_public_name())
|
||||||
@@ -768,7 +761,7 @@ class Name(BaseName):
|
|||||||
:meth:`.Script.goto` or :meth:`.Script.infer`.
|
:meth:`.Script.goto` or :meth:`.Script.infer`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, inference_state, definition):
|
def __init__(self, inference_state, definition):
|
||||||
super(Name, self).__init__(inference_state, definition)
|
super().__init__(inference_state, definition)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def desc_with_module(self):
|
def desc_with_module(self):
|
||||||
@@ -821,7 +814,7 @@ class BaseSignature(Name):
|
|||||||
calls.
|
calls.
|
||||||
"""
|
"""
|
||||||
def __init__(self, inference_state, signature):
|
def __init__(self, inference_state, signature):
|
||||||
super(BaseSignature, self).__init__(inference_state, signature.name)
|
super().__init__(inference_state, signature.name)
|
||||||
self._signature = signature
|
self._signature = signature
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -851,7 +844,7 @@ class Signature(BaseSignature):
|
|||||||
:meth:`.Script.get_signatures`.
|
:meth:`.Script.get_signatures`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, inference_state, signature, call_details):
|
def __init__(self, inference_state, signature, call_details):
|
||||||
super(Signature, self).__init__(inference_state, signature)
|
super().__init__(inference_state, signature)
|
||||||
self._call_details = call_details
|
self._call_details = call_details
|
||||||
self._signature = signature
|
self._signature = signature
|
||||||
|
|
||||||
@@ -918,8 +911,4 @@ class ParamName(Name):
|
|||||||
|
|
||||||
:rtype: :py:attr:`inspect.Parameter.kind`
|
:rtype: :py:attr:`inspect.Parameter.kind`
|
||||||
"""
|
"""
|
||||||
if sys.version_info < (3, 5):
|
|
||||||
raise NotImplementedError(
|
|
||||||
'Python 2 is end-of-life, the new feature is not available for it'
|
|
||||||
)
|
|
||||||
return self._name.get_kind()
|
return self._name.get_kind()
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import re
|
import re
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
from inspect import Parameter
|
||||||
|
|
||||||
from parso.python.token import PythonTokenTypes
|
from parso.python.token import PythonTokenTypes
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
from parso.tree import search_ancestor, Leaf
|
from parso.tree import search_ancestor, Leaf
|
||||||
from parso import split_lines
|
from parso import split_lines
|
||||||
|
|
||||||
from jedi._compatibility import Parameter
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
from jedi.api import classes
|
from jedi.api import classes
|
||||||
@@ -34,9 +34,7 @@ def _get_signature_param_names(signatures, positional_count, used_kwargs):
|
|||||||
# Add named params
|
# Add named params
|
||||||
for call_sig in signatures:
|
for call_sig in signatures:
|
||||||
for i, p in enumerate(call_sig.params):
|
for i, p in enumerate(call_sig.params):
|
||||||
# Allow protected access, because it's a public API.
|
kind = p.kind
|
||||||
# TODO reconsider with Python 2 drop
|
|
||||||
kind = p._name.get_kind()
|
|
||||||
if i < positional_count and kind == Parameter.POSITIONAL_OR_KEYWORD:
|
if i < positional_count and kind == Parameter.POSITIONAL_OR_KEYWORD:
|
||||||
continue
|
continue
|
||||||
if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) \
|
if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) \
|
||||||
@@ -51,8 +49,7 @@ def _must_be_kwarg(signatures, positional_count, used_kwargs):
|
|||||||
must_be_kwarg = True
|
must_be_kwarg = True
|
||||||
for signature in signatures:
|
for signature in signatures:
|
||||||
for i, p in enumerate(signature.params):
|
for i, p in enumerate(signature.params):
|
||||||
# TODO reconsider with Python 2 drop
|
kind = p.kind
|
||||||
kind = p._name.get_kind()
|
|
||||||
if kind is Parameter.VAR_POSITIONAL:
|
if kind is Parameter.VAR_POSITIONAL:
|
||||||
# In case there were not already kwargs, the next param can
|
# In case there were not already kwargs, the next param can
|
||||||
# always be a normal argument.
|
# always be a normal argument.
|
||||||
@@ -579,8 +576,8 @@ def _complete_getattr(user_context, instance):
|
|||||||
will write it like this anyway and the other ones, well they are just
|
will write it like this anyway and the other ones, well they are just
|
||||||
out of luck I guess :) ~dave.
|
out of luck I guess :) ~dave.
|
||||||
"""
|
"""
|
||||||
names = (instance.get_function_slot_names(u'__getattr__')
|
names = (instance.get_function_slot_names('__getattr__')
|
||||||
or instance.get_function_slot_names(u'__getattribute__'))
|
or instance.get_function_slot_names('__getattribute__'))
|
||||||
functions = ValueSet.from_sets(
|
functions = ValueSet.from_sets(
|
||||||
name.infer()
|
name.infer()
|
||||||
for name in names
|
for name in names
|
||||||
|
|||||||
+38
-61
@@ -7,8 +7,8 @@ import sys
|
|||||||
import hashlib
|
import hashlib
|
||||||
import filecmp
|
import filecmp
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from shutil import which
|
||||||
|
|
||||||
from jedi._compatibility import highest_pickle_protocol, which
|
|
||||||
from jedi.cache import memoize_method, time_cache
|
from jedi.cache import memoize_method, time_cache
|
||||||
from jedi.inference.compiled.subprocess import CompiledSubprocess, \
|
from jedi.inference.compiled.subprocess import CompiledSubprocess, \
|
||||||
InferenceStateSameProcess, InferenceStateSubprocess
|
InferenceStateSameProcess, InferenceStateSubprocess
|
||||||
@@ -17,7 +17,7 @@ import parso
|
|||||||
|
|
||||||
_VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
_VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||||
|
|
||||||
_SUPPORTED_PYTHONS = ['3.8', '3.7', '3.6', '3.5', '2.7']
|
_SUPPORTED_PYTHONS = ['3.9', '3.8', '3.7', '3.6']
|
||||||
_SAFE_PATHS = ['/usr/bin', '/usr/local/bin']
|
_SAFE_PATHS = ['/usr/bin', '/usr/local/bin']
|
||||||
_CONDA_VAR = 'CONDA_PREFIX'
|
_CONDA_VAR = 'CONDA_PREFIX'
|
||||||
_CURRENT_VERSION = '%s.%s' % (sys.version_info.major, sys.version_info.minor)
|
_CURRENT_VERSION = '%s.%s' % (sys.version_info.major, sys.version_info.minor)
|
||||||
@@ -96,16 +96,6 @@ class Environment(_BaseEnvironment):
|
|||||||
Like :data:`sys.version_info`: a tuple to show the current
|
Like :data:`sys.version_info`: a tuple to show the current
|
||||||
Environment's Python version.
|
Environment's Python version.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# py2 sends bytes via pickle apparently?!
|
|
||||||
if self.version_info.major == 2:
|
|
||||||
self.executable = self.executable.decode()
|
|
||||||
self.path = self.path.decode()
|
|
||||||
|
|
||||||
# Adjust pickle protocol according to host and client version.
|
|
||||||
self._subprocess._pickle_protocol = highest_pickle_protocol([
|
|
||||||
sys.version_info, self.version_info])
|
|
||||||
|
|
||||||
return self._subprocess
|
return self._subprocess
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -267,7 +257,7 @@ def _get_cached_default_environment():
|
|||||||
return InterpreterEnvironment()
|
return InterpreterEnvironment()
|
||||||
|
|
||||||
|
|
||||||
def find_virtualenvs(paths=None, **kwargs):
|
def find_virtualenvs(paths=None, *, safe=True, use_environment_vars=True):
|
||||||
"""
|
"""
|
||||||
:param paths: A list of paths in your file system to be scanned for
|
:param paths: A list of paths in your file system to be scanned for
|
||||||
Virtualenvs. It will search in these paths and potentially execute the
|
Virtualenvs. It will search in these paths and potentially execute the
|
||||||
@@ -284,47 +274,44 @@ def find_virtualenvs(paths=None, **kwargs):
|
|||||||
|
|
||||||
:yields: :class:`.Environment`
|
:yields: :class:`.Environment`
|
||||||
"""
|
"""
|
||||||
def py27_comp(paths=None, safe=True, use_environment_vars=True):
|
if paths is None:
|
||||||
if paths is None:
|
paths = []
|
||||||
paths = []
|
|
||||||
|
|
||||||
_used_paths = set()
|
_used_paths = set()
|
||||||
|
|
||||||
if use_environment_vars:
|
if use_environment_vars:
|
||||||
# Using this variable should be safe, because attackers might be
|
# Using this variable should be safe, because attackers might be
|
||||||
# able to drop files (via git) but not environment variables.
|
# able to drop files (via git) but not environment variables.
|
||||||
virtual_env = _get_virtual_env_from_var()
|
virtual_env = _get_virtual_env_from_var()
|
||||||
if virtual_env is not None:
|
if virtual_env is not None:
|
||||||
yield virtual_env
|
yield virtual_env
|
||||||
_used_paths.add(virtual_env.path)
|
_used_paths.add(virtual_env.path)
|
||||||
|
|
||||||
conda_env = _get_virtual_env_from_var(_CONDA_VAR)
|
conda_env = _get_virtual_env_from_var(_CONDA_VAR)
|
||||||
if conda_env is not None:
|
if conda_env is not None:
|
||||||
yield conda_env
|
yield conda_env
|
||||||
_used_paths.add(conda_env.path)
|
_used_paths.add(conda_env.path)
|
||||||
|
|
||||||
for directory in paths:
|
for directory in paths:
|
||||||
if not os.path.isdir(directory):
|
if not os.path.isdir(directory):
|
||||||
|
continue
|
||||||
|
|
||||||
|
directory = os.path.abspath(directory)
|
||||||
|
for path in os.listdir(directory):
|
||||||
|
path = os.path.join(directory, path)
|
||||||
|
if path in _used_paths:
|
||||||
|
# A path shouldn't be inferred twice.
|
||||||
continue
|
continue
|
||||||
|
_used_paths.add(path)
|
||||||
|
|
||||||
directory = os.path.abspath(directory)
|
try:
|
||||||
for path in os.listdir(directory):
|
executable = _get_executable_path(path, safe=safe)
|
||||||
path = os.path.join(directory, path)
|
yield Environment(executable)
|
||||||
if path in _used_paths:
|
except InvalidPythonEnvironment:
|
||||||
# A path shouldn't be inferred twice.
|
pass
|
||||||
continue
|
|
||||||
_used_paths.add(path)
|
|
||||||
|
|
||||||
try:
|
|
||||||
executable = _get_executable_path(path, safe=safe)
|
|
||||||
yield Environment(executable)
|
|
||||||
except InvalidPythonEnvironment:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return py27_comp(paths, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def find_system_environments(**kwargs):
|
def find_system_environments(*, env_vars={}):
|
||||||
"""
|
"""
|
||||||
Ignores virtualenvs and returns the Python versions that were installed on
|
Ignores virtualenvs and returns the Python versions that were installed on
|
||||||
your system. This might return nothing, if you're running Python e.g. from
|
your system. This might return nothing, if you're running Python e.g. from
|
||||||
@@ -336,14 +323,14 @@ def find_system_environments(**kwargs):
|
|||||||
"""
|
"""
|
||||||
for version_string in _SUPPORTED_PYTHONS:
|
for version_string in _SUPPORTED_PYTHONS:
|
||||||
try:
|
try:
|
||||||
yield get_system_environment(version_string, **kwargs)
|
yield get_system_environment(version_string, env_vars=env_vars)
|
||||||
except InvalidPythonEnvironment:
|
except InvalidPythonEnvironment:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# TODO: this function should probably return a list of environments since
|
# TODO: this function should probably return a list of environments since
|
||||||
# multiple Python installations can be found on a system for the same version.
|
# multiple Python installations can be found on a system for the same version.
|
||||||
def get_system_environment(version, **kwargs):
|
def get_system_environment(version, *, env_vars={}):
|
||||||
"""
|
"""
|
||||||
Return the first Python environment found for a string of the form 'X.Y'
|
Return the first Python environment found for a string of the form 'X.Y'
|
||||||
where X and Y are the major and minor versions of Python.
|
where X and Y are the major and minor versions of Python.
|
||||||
@@ -360,26 +347,20 @@ def get_system_environment(version, **kwargs):
|
|||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
for exe in _get_executables_from_windows_registry(version):
|
for exe in _get_executables_from_windows_registry(version):
|
||||||
try:
|
try:
|
||||||
return Environment(exe, **kwargs)
|
return Environment(exe, env_vars=env_vars)
|
||||||
except InvalidPythonEnvironment:
|
except InvalidPythonEnvironment:
|
||||||
pass
|
pass
|
||||||
raise InvalidPythonEnvironment("Cannot find executable python%s." % version)
|
raise InvalidPythonEnvironment("Cannot find executable python%s." % version)
|
||||||
|
|
||||||
|
|
||||||
def create_environment(path, safe=True, **kwargs):
|
def create_environment(path, *, safe=True, env_vars=None):
|
||||||
"""
|
"""
|
||||||
Make it possible to manually create an Environment object by specifying a
|
Make it possible to manually create an Environment object by specifying a
|
||||||
Virtualenv path or an executable path and optional environment variables.
|
Virtualenv path or an executable path and optional environment variables.
|
||||||
|
|
||||||
:raises: :exc:`.InvalidPythonEnvironment`
|
:raises: :exc:`.InvalidPythonEnvironment`
|
||||||
:returns: :class:`.Environment`
|
:returns: :class:`.Environment`
|
||||||
|
|
||||||
TODO: make env_vars a kwarg when Python 2 is dropped. For now, preserve API
|
|
||||||
"""
|
"""
|
||||||
return _create_environment(path, safe, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def _create_environment(path, safe=True, env_vars=None):
|
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
_assert_safe(path, safe)
|
_assert_safe(path, safe)
|
||||||
return Environment(path, env_vars=env_vars)
|
return Environment(path, env_vars=env_vars)
|
||||||
@@ -403,11 +384,7 @@ def _get_executable_path(path, safe=True):
|
|||||||
|
|
||||||
|
|
||||||
def _get_executables_from_windows_registry(version):
|
def _get_executables_from_windows_registry(version):
|
||||||
# The winreg module is named _winreg on Python 2.
|
import winreg
|
||||||
try:
|
|
||||||
import winreg
|
|
||||||
except ImportError:
|
|
||||||
import _winreg as winreg
|
|
||||||
|
|
||||||
# TODO: support Python Anaconda.
|
# TODO: support Python Anaconda.
|
||||||
sub_keys = [
|
sub_keys = [
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from jedi._compatibility import FileNotFoundError, force_unicode, scandir
|
|
||||||
from jedi.api import classes
|
from jedi.api import classes
|
||||||
from jedi.api.strings import StringName, get_quote_ending
|
from jedi.api.strings import StringName, get_quote_ending
|
||||||
from jedi.api.helpers import match
|
from jedi.api.helpers import match
|
||||||
@@ -8,7 +7,7 @@ from jedi.inference.helpers import get_str_or_none
|
|||||||
|
|
||||||
|
|
||||||
class PathName(StringName):
|
class PathName(StringName):
|
||||||
api_type = u'path'
|
api_type = 'path'
|
||||||
|
|
||||||
|
|
||||||
def complete_file_name(inference_state, module_context, start_leaf, quote, string,
|
def complete_file_name(inference_state, module_context, start_leaf, quote, string,
|
||||||
@@ -38,7 +37,7 @@ def complete_file_name(inference_state, module_context, start_leaf, quote, strin
|
|||||||
string = to_be_added + string
|
string = to_be_added + string
|
||||||
base_path = os.path.join(inference_state.project.path, string)
|
base_path = os.path.join(inference_state.project.path, string)
|
||||||
try:
|
try:
|
||||||
listed = sorted(scandir(base_path), key=lambda e: e.name)
|
listed = sorted(os.scandir(base_path), key=lambda e: e.name)
|
||||||
# OSError: [Errno 36] File name too long: '...'
|
# OSError: [Errno 36] File name too long: '...'
|
||||||
except (FileNotFoundError, OSError):
|
except (FileNotFoundError, OSError):
|
||||||
return
|
return
|
||||||
@@ -94,7 +93,7 @@ def _add_strings(context, nodes, add_slash=False):
|
|||||||
return None
|
return None
|
||||||
if not first and add_slash:
|
if not first and add_slash:
|
||||||
string += os.path.sep
|
string += os.path.sep
|
||||||
string += force_unicode(s)
|
string += s
|
||||||
first = False
|
first = False
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|||||||
+11
-9
@@ -6,11 +6,11 @@ from collections import namedtuple
|
|||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
from inspect import Parameter
|
||||||
|
|
||||||
from parso.python.parser import Parser
|
from parso.python.parser import Parser
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
from jedi._compatibility import u, Parameter
|
|
||||||
from jedi.inference.base_value import NO_VALUES
|
from jedi.inference.base_value import NO_VALUES
|
||||||
from jedi.inference.syntax_tree import infer_atom
|
from jedi.inference.syntax_tree import infer_atom
|
||||||
from jedi.inference.helpers import infer_call_of_leaf
|
from jedi.inference.helpers import infer_call_of_leaf
|
||||||
@@ -44,7 +44,10 @@ def match(string, like_name, fuzzy=False):
|
|||||||
|
|
||||||
def sorted_definitions(defs):
|
def sorted_definitions(defs):
|
||||||
# Note: `or ''` below is required because `module_path` could be
|
# Note: `or ''` below is required because `module_path` could be
|
||||||
return sorted(defs, key=lambda x: (x.module_path or '', x.line or 0, x.column or 0, x.name))
|
return sorted(defs, key=lambda x: (str(x.module_path or ''),
|
||||||
|
x.line or 0,
|
||||||
|
x.column or 0,
|
||||||
|
x.name))
|
||||||
|
|
||||||
|
|
||||||
def get_on_completion_name(module_node, lines, position):
|
def get_on_completion_name(module_node, lines, position):
|
||||||
@@ -84,18 +87,18 @@ def _get_code_for_stack(code_lines, leaf, position):
|
|||||||
# If we're not on a comment simply get the previous leaf and proceed.
|
# If we're not on a comment simply get the previous leaf and proceed.
|
||||||
leaf = leaf.get_previous_leaf()
|
leaf = leaf.get_previous_leaf()
|
||||||
if leaf is None:
|
if leaf is None:
|
||||||
return u('') # At the beginning of the file.
|
return '' # At the beginning of the file.
|
||||||
|
|
||||||
is_after_newline = leaf.type == 'newline'
|
is_after_newline = leaf.type == 'newline'
|
||||||
while leaf.type == 'newline':
|
while leaf.type == 'newline':
|
||||||
leaf = leaf.get_previous_leaf()
|
leaf = leaf.get_previous_leaf()
|
||||||
if leaf is None:
|
if leaf is None:
|
||||||
return u('')
|
return ''
|
||||||
|
|
||||||
if leaf.type == 'error_leaf' or leaf.type == 'string':
|
if leaf.type == 'error_leaf' or leaf.type == 'string':
|
||||||
if leaf.start_pos[0] < position[0]:
|
if leaf.start_pos[0] < position[0]:
|
||||||
# On a different line, we just begin anew.
|
# On a different line, we just begin anew.
|
||||||
return u('')
|
return ''
|
||||||
|
|
||||||
# Error leafs cannot be parsed, completion in strings is also
|
# Error leafs cannot be parsed, completion in strings is also
|
||||||
# impossible.
|
# impossible.
|
||||||
@@ -111,7 +114,7 @@ def _get_code_for_stack(code_lines, leaf, position):
|
|||||||
if user_stmt.start_pos[1] > position[1]:
|
if user_stmt.start_pos[1] > position[1]:
|
||||||
# This means that it's actually a dedent and that means that we
|
# This means that it's actually a dedent and that means that we
|
||||||
# start without value (part of a suite).
|
# start without value (part of a suite).
|
||||||
return u('')
|
return ''
|
||||||
|
|
||||||
# This is basically getting the relevant lines.
|
# This is basically getting the relevant lines.
|
||||||
return _get_code(code_lines, user_stmt.get_start_pos_of_prefix(), position)
|
return _get_code(code_lines, user_stmt.get_start_pos_of_prefix(), position)
|
||||||
@@ -294,8 +297,7 @@ def _iter_arguments(nodes, position):
|
|||||||
# Returns Generator[Tuple[star_count, Optional[key_start: str], had_equal]]
|
# Returns Generator[Tuple[star_count, Optional[key_start: str], had_equal]]
|
||||||
nodes_before = [c for c in nodes if c.start_pos < position]
|
nodes_before = [c for c in nodes if c.start_pos < position]
|
||||||
if nodes_before[-1].type == 'arglist':
|
if nodes_before[-1].type == 'arglist':
|
||||||
for x in _iter_arguments(nodes_before[-1].children, position):
|
yield from _iter_arguments(nodes_before[-1].children, position)
|
||||||
yield x # Python 2 :(
|
|
||||||
return
|
return
|
||||||
|
|
||||||
previous_node_yielded = False
|
previous_node_yielded = False
|
||||||
@@ -320,7 +322,7 @@ def _iter_arguments(nodes, position):
|
|||||||
else:
|
else:
|
||||||
yield 0, None, False
|
yield 0, None, False
|
||||||
stars_seen = 0
|
stars_seen = 0
|
||||||
elif node.type in ('testlist', 'testlist_star_expr'): # testlist is Python 2
|
elif node.type == 'testlist_star_expr':
|
||||||
for n in node.children[::2]:
|
for n in node.children[::2]:
|
||||||
if n.type == 'star_expr':
|
if n.type == 'star_expr':
|
||||||
stars_seen = 1
|
stars_seen = 1
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class MixedParserTreeFilter(ParserTreeFilter):
|
|||||||
|
|
||||||
class MixedModuleContext(ModuleContext):
|
class MixedModuleContext(ModuleContext):
|
||||||
def __init__(self, tree_module_value, namespaces):
|
def __init__(self, tree_module_value, namespaces):
|
||||||
super(MixedModuleContext, self).__init__(tree_module_value)
|
super().__init__(tree_module_value)
|
||||||
self.mixed_values = [
|
self.mixed_values = [
|
||||||
self._get_mixed_object(
|
self._get_mixed_object(
|
||||||
_create(self.inference_state, NamespaceObject(n))
|
_create(self.inference_state, NamespaceObject(n))
|
||||||
|
|||||||
+4
-16
@@ -1,22 +1,13 @@
|
|||||||
import pydoc
|
import pydoc
|
||||||
|
from contextlib import suppress
|
||||||
|
|
||||||
from jedi.inference.utils import ignored
|
|
||||||
from jedi.inference.names import AbstractArbitraryName
|
from jedi.inference.names import AbstractArbitraryName
|
||||||
|
|
||||||
try:
|
from pydoc_data import topics as pydoc_topics
|
||||||
from pydoc_data import topics as pydoc_topics
|
|
||||||
except ImportError:
|
|
||||||
# Python 2
|
|
||||||
try:
|
|
||||||
import pydoc_topics
|
|
||||||
except ImportError:
|
|
||||||
# This is for Python 3 embeddable version, which dont have
|
|
||||||
# pydoc_data module in its file python3x.zip.
|
|
||||||
pydoc_topics = None
|
|
||||||
|
|
||||||
|
|
||||||
class KeywordName(AbstractArbitraryName):
|
class KeywordName(AbstractArbitraryName):
|
||||||
api_type = u'keyword'
|
api_type = 'keyword'
|
||||||
|
|
||||||
def py__doc__(self):
|
def py__doc__(self):
|
||||||
return imitate_pydoc(self.string_name)
|
return imitate_pydoc(self.string_name)
|
||||||
@@ -30,11 +21,8 @@ def imitate_pydoc(string):
|
|||||||
if pydoc_topics is None:
|
if pydoc_topics is None:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
# str needed because of possible unicode stuff in py2k (pydoc doesn't work
|
|
||||||
# with unicode strings)
|
|
||||||
string = str(string)
|
|
||||||
h = pydoc.help
|
h = pydoc.help
|
||||||
with ignored(KeyError):
|
with suppress(KeyError):
|
||||||
# try to access symbols
|
# try to access symbols
|
||||||
string = h.symbols[string]
|
string = h.symbols[string]
|
||||||
string, _, related = string.partition(' ')
|
string, _, related = string.partition(' ')
|
||||||
|
|||||||
+49
-59
@@ -7,26 +7,21 @@ flexibility to define sys paths and Python interpreters for a project,
|
|||||||
Projects can be saved to disk and loaded again, to allow project definitions to
|
Projects can be saved to disk and loaded again, to allow project definitions to
|
||||||
be used across repositories.
|
be used across repositories.
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
import errno
|
|
||||||
import json
|
import json
|
||||||
import sys
|
from pathlib import Path
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
from jedi._compatibility import FileNotFoundError, PermissionError, \
|
|
||||||
IsADirectoryError, NotADirectoryError
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.api.environment import get_cached_default_environment, create_environment
|
from jedi.api.environment import get_cached_default_environment, create_environment
|
||||||
from jedi.api.exceptions import WrongVersion
|
from jedi.api.exceptions import WrongVersion
|
||||||
from jedi.api.completion import search_in_module
|
from jedi.api.completion import search_in_module
|
||||||
from jedi.api.helpers import split_search_string, get_module_names
|
from jedi.api.helpers import split_search_string, get_module_names
|
||||||
from jedi._compatibility import force_unicode
|
|
||||||
from jedi.inference.imports import load_module_from_path, \
|
from jedi.inference.imports import load_module_from_path, \
|
||||||
load_namespace_from_path, iter_module_names
|
load_namespace_from_path, iter_module_names
|
||||||
from jedi.inference.sys_path import discover_buildout_paths
|
from jedi.inference.sys_path import discover_buildout_paths
|
||||||
from jedi.inference.cache import inference_state_as_method_param_cache
|
from jedi.inference.cache import inference_state_as_method_param_cache
|
||||||
from jedi.inference.references import recurse_find_python_folders_and_files, search_in_file_ios
|
from jedi.inference.references import recurse_find_python_folders_and_files, search_in_file_ios
|
||||||
from jedi.file_io import FolderIO
|
from jedi.file_io import FolderIO
|
||||||
from jedi.common import traverse_parents
|
|
||||||
|
|
||||||
_CONFIG_FOLDER = '.jedi'
|
_CONFIG_FOLDER = '.jedi'
|
||||||
_CONTAINS_POTENTIAL_PROJECT = \
|
_CONTAINS_POTENTIAL_PROJECT = \
|
||||||
@@ -61,10 +56,6 @@ def _remove_duplicates_from_path(path):
|
|||||||
yield p
|
yield p
|
||||||
|
|
||||||
|
|
||||||
def _force_unicode_list(lst):
|
|
||||||
return list(map(force_unicode, lst))
|
|
||||||
|
|
||||||
|
|
||||||
class Project(object):
|
class Project(object):
|
||||||
"""
|
"""
|
||||||
Projects are a simple way to manage Python folders and define how Jedi does
|
Projects are a simple way to manage Python folders and define how Jedi does
|
||||||
@@ -75,11 +66,11 @@ class Project(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_config_folder_path(base_path):
|
def _get_config_folder_path(base_path):
|
||||||
return os.path.join(base_path, _CONFIG_FOLDER)
|
return base_path.joinpath(_CONFIG_FOLDER)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_json_path(base_path):
|
def _get_json_path(base_path):
|
||||||
return os.path.join(Project._get_config_folder_path(base_path), 'project.json')
|
return Project._get_config_folder_path(base_path).joinpath('project.json')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, path):
|
def load(cls, path):
|
||||||
@@ -89,6 +80,8 @@ class Project(object):
|
|||||||
|
|
||||||
:param path: The path of the directory you want to use as a project.
|
:param path: The path of the directory you want to use as a project.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(path, str):
|
||||||
|
path = Path(path)
|
||||||
with open(cls._get_json_path(path)) as f:
|
with open(cls._get_json_path(path)) as f:
|
||||||
version, data = json.load(f)
|
version, data = json.load(f)
|
||||||
|
|
||||||
@@ -107,13 +100,9 @@ class Project(object):
|
|||||||
data.pop('_environment', None)
|
data.pop('_environment', None)
|
||||||
data.pop('_django', None) # TODO make django setting public?
|
data.pop('_django', None) # TODO make django setting public?
|
||||||
data = {k.lstrip('_'): v for k, v in data.items()}
|
data = {k.lstrip('_'): v for k, v in data.items()}
|
||||||
|
data['path'] = str(data['path'])
|
||||||
|
|
||||||
# TODO when dropping Python 2 use pathlib.Path.mkdir(parents=True, exist_ok=True)
|
self._get_config_folder_path(self._path).mkdir(parents=True, exist_ok=True)
|
||||||
try:
|
|
||||||
os.makedirs(self._get_config_folder_path(self._path))
|
|
||||||
except OSError as e:
|
|
||||||
if e.errno != errno.EEXIST:
|
|
||||||
raise
|
|
||||||
with open(self._get_json_path(self._path), 'w') as f:
|
with open(self._get_json_path(self._path), 'w') as f:
|
||||||
return json.dump((_SERIALIZER_VERSION, data), f)
|
return json.dump((_SERIALIZER_VERSION, data), f)
|
||||||
|
|
||||||
@@ -138,14 +127,20 @@ class Project(object):
|
|||||||
"""
|
"""
|
||||||
def py2_comp(path, environment_path=None, load_unsafe_extensions=False,
|
def py2_comp(path, environment_path=None, load_unsafe_extensions=False,
|
||||||
sys_path=None, added_sys_path=(), smart_sys_path=True):
|
sys_path=None, added_sys_path=(), smart_sys_path=True):
|
||||||
self._path = os.path.abspath(path)
|
if isinstance(path, str):
|
||||||
|
path = Path(path).absolute()
|
||||||
|
self._path = path
|
||||||
|
|
||||||
self._environment_path = environment_path
|
self._environment_path = environment_path
|
||||||
|
if sys_path is not None:
|
||||||
|
# Remap potential pathlib.Path entries
|
||||||
|
sys_path = list(map(str, sys_path))
|
||||||
self._sys_path = sys_path
|
self._sys_path = sys_path
|
||||||
self._smart_sys_path = smart_sys_path
|
self._smart_sys_path = smart_sys_path
|
||||||
self._load_unsafe_extensions = load_unsafe_extensions
|
self._load_unsafe_extensions = load_unsafe_extensions
|
||||||
self._django = False
|
self._django = False
|
||||||
self.added_sys_path = list(added_sys_path)
|
# Remap potential pathlib.Path entries
|
||||||
|
self.added_sys_path = list(map(str, added_sys_path))
|
||||||
"""The sys path that is going to be added at the end of the """
|
"""The sys path that is going to be added at the end of the """
|
||||||
|
|
||||||
py2_comp(path, **kwargs)
|
py2_comp(path, **kwargs)
|
||||||
@@ -182,23 +177,27 @@ class Project(object):
|
|||||||
sys_path = list(self._sys_path)
|
sys_path = list(self._sys_path)
|
||||||
|
|
||||||
if self._smart_sys_path:
|
if self._smart_sys_path:
|
||||||
prefixed.append(self._path)
|
prefixed.append(str(self._path))
|
||||||
|
|
||||||
if inference_state.script_path is not None:
|
if inference_state.script_path is not None:
|
||||||
suffixed += discover_buildout_paths(inference_state, inference_state.script_path)
|
suffixed += map(str, discover_buildout_paths(
|
||||||
|
inference_state,
|
||||||
|
inference_state.script_path
|
||||||
|
))
|
||||||
|
|
||||||
if add_parent_paths:
|
if add_parent_paths:
|
||||||
# Collect directories in upward search by:
|
# Collect directories in upward search by:
|
||||||
# 1. Skipping directories with __init__.py
|
# 1. Skipping directories with __init__.py
|
||||||
# 2. Stopping immediately when above self._path
|
# 2. Stopping immediately when above self._path
|
||||||
traversed = []
|
traversed = []
|
||||||
for parent_path in traverse_parents(inference_state.script_path):
|
for parent_path in inference_state.script_path.parents:
|
||||||
if parent_path == self._path or not parent_path.startswith(self._path):
|
if parent_path == self._path \
|
||||||
|
or self._path not in parent_path.parents:
|
||||||
break
|
break
|
||||||
if not add_init_paths \
|
if not add_init_paths \
|
||||||
and os.path.isfile(os.path.join(parent_path, "__init__.py")):
|
and parent_path.joinpath("__init__.py").is_file():
|
||||||
continue
|
continue
|
||||||
traversed.append(parent_path)
|
traversed.append(str(parent_path))
|
||||||
|
|
||||||
# AFAIK some libraries have imports like `foo.foo.bar`, which
|
# AFAIK some libraries have imports like `foo.foo.bar`, which
|
||||||
# leads to the conclusion to by default prefer longer paths
|
# leads to the conclusion to by default prefer longer paths
|
||||||
@@ -206,10 +205,10 @@ class Project(object):
|
|||||||
suffixed += reversed(traversed)
|
suffixed += reversed(traversed)
|
||||||
|
|
||||||
if self._django:
|
if self._django:
|
||||||
prefixed.append(self._path)
|
prefixed.append(str(self._path))
|
||||||
|
|
||||||
path = prefixed + sys_path + suffixed
|
path = prefixed + sys_path + suffixed
|
||||||
return list(_force_unicode_list(_remove_duplicates_from_path(path)))
|
return list(_remove_duplicates_from_path(path))
|
||||||
|
|
||||||
def get_environment(self):
|
def get_environment(self):
|
||||||
if self._environment is None:
|
if self._environment is None:
|
||||||
@@ -219,7 +218,7 @@ class Project(object):
|
|||||||
self._environment = get_cached_default_environment()
|
self._environment = get_cached_default_environment()
|
||||||
return self._environment
|
return self._environment
|
||||||
|
|
||||||
def search(self, string, **kwargs):
|
def search(self, string, *, all_scopes=False):
|
||||||
"""
|
"""
|
||||||
Searches a name in the whole project. If the project is very big,
|
Searches a name in the whole project. If the project is very big,
|
||||||
at some point Jedi will stop searching. However it's also very much
|
at some point Jedi will stop searching. However it's also very much
|
||||||
@@ -240,7 +239,7 @@ class Project(object):
|
|||||||
functions and classes.
|
functions and classes.
|
||||||
:yields: :class:`.Name`
|
:yields: :class:`.Name`
|
||||||
"""
|
"""
|
||||||
return self._search(string, **kwargs)
|
return self._search_func(string, all_scopes=all_scopes)
|
||||||
|
|
||||||
def complete_search(self, string, **kwargs):
|
def complete_search(self, string, **kwargs):
|
||||||
"""
|
"""
|
||||||
@@ -254,9 +253,6 @@ class Project(object):
|
|||||||
"""
|
"""
|
||||||
return self._search_func(string, complete=True, **kwargs)
|
return self._search_func(string, complete=True, **kwargs)
|
||||||
|
|
||||||
def _search(self, string, all_scopes=False): # Python 2..
|
|
||||||
return self._search_func(string, all_scopes=all_scopes)
|
|
||||||
|
|
||||||
@_try_to_skip_duplicates
|
@_try_to_skip_duplicates
|
||||||
def _search_func(self, string, complete=False, all_scopes=False):
|
def _search_func(self, string, complete=False, all_scopes=False):
|
||||||
# Using a Script is they easiest way to get an empty module context.
|
# Using a Script is they easiest way to get an empty module context.
|
||||||
@@ -265,16 +261,12 @@ class Project(object):
|
|||||||
inference_state = s._inference_state
|
inference_state = s._inference_state
|
||||||
empty_module_context = s._get_module_context()
|
empty_module_context = s._get_module_context()
|
||||||
|
|
||||||
if inference_state.grammar.version_info < (3, 6) or sys.version_info < (3, 6):
|
|
||||||
raise NotImplementedError(
|
|
||||||
"No support for refactorings/search on Python 2/3.5"
|
|
||||||
)
|
|
||||||
debug.dbg('Search for string %s, complete=%s', string, complete)
|
debug.dbg('Search for string %s, complete=%s', string, complete)
|
||||||
wanted_type, wanted_names = split_search_string(string)
|
wanted_type, wanted_names = split_search_string(string)
|
||||||
name = wanted_names[0]
|
name = wanted_names[0]
|
||||||
stub_folder_name = name + '-stubs'
|
stub_folder_name = name + '-stubs'
|
||||||
|
|
||||||
ios = recurse_find_python_folders_and_files(FolderIO(self._path))
|
ios = recurse_find_python_folders_and_files(FolderIO(str(self._path)))
|
||||||
file_ios = []
|
file_ios = []
|
||||||
|
|
||||||
# 1. Search for modules in the current project
|
# 1. Search for modules in the current project
|
||||||
@@ -295,14 +287,13 @@ class Project(object):
|
|||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
file_ios.append(file_io)
|
file_ios.append(file_io)
|
||||||
file_name = os.path.basename(file_io.path)
|
if Path(file_io.path).name in (name + '.py', name + '.pyi'):
|
||||||
if file_name in (name + '.py', name + '.pyi'):
|
|
||||||
m = load_module_from_path(inference_state, file_io).as_context()
|
m = load_module_from_path(inference_state, file_io).as_context()
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
debug.dbg('Search of a specific module %s', m)
|
debug.dbg('Search of a specific module %s', m)
|
||||||
for x in search_in_module(
|
yield from search_in_module(
|
||||||
inference_state,
|
inference_state,
|
||||||
m,
|
m,
|
||||||
names=[m.name],
|
names=[m.name],
|
||||||
@@ -311,15 +302,14 @@ class Project(object):
|
|||||||
complete=complete,
|
complete=complete,
|
||||||
convert=True,
|
convert=True,
|
||||||
ignore_imports=True,
|
ignore_imports=True,
|
||||||
):
|
)
|
||||||
yield x # Python 2...
|
|
||||||
|
|
||||||
# 2. Search for identifiers in the project.
|
# 2. Search for identifiers in the project.
|
||||||
for module_context in search_in_file_ios(inference_state, file_ios, name):
|
for module_context in search_in_file_ios(inference_state, file_ios, name):
|
||||||
names = get_module_names(module_context.tree_node, all_scopes=all_scopes)
|
names = get_module_names(module_context.tree_node, all_scopes=all_scopes)
|
||||||
names = [module_context.create_name(n) for n in names]
|
names = [module_context.create_name(n) for n in names]
|
||||||
names = _remove_imports(names)
|
names = _remove_imports(names)
|
||||||
for x in search_in_module(
|
yield from search_in_module(
|
||||||
inference_state,
|
inference_state,
|
||||||
module_context,
|
module_context,
|
||||||
names=names,
|
names=names,
|
||||||
@@ -327,18 +317,17 @@ class Project(object):
|
|||||||
wanted_names=wanted_names,
|
wanted_names=wanted_names,
|
||||||
complete=complete,
|
complete=complete,
|
||||||
ignore_imports=True,
|
ignore_imports=True,
|
||||||
):
|
)
|
||||||
yield x # Python 2...
|
|
||||||
|
|
||||||
# 3. Search for modules on sys.path
|
# 3. Search for modules on sys.path
|
||||||
sys_path = [
|
sys_path = [
|
||||||
p for p in self._get_sys_path(inference_state)
|
p for p in self._get_sys_path(inference_state)
|
||||||
# Exclude folders that are handled by recursing of the Python
|
# Exclude folders that are handled by recursing of the Python
|
||||||
# folders.
|
# folders.
|
||||||
if not p.startswith(self._path)
|
if not p.startswith(str(self._path))
|
||||||
]
|
]
|
||||||
names = list(iter_module_names(inference_state, empty_module_context, sys_path))
|
names = list(iter_module_names(inference_state, empty_module_context, sys_path))
|
||||||
for x in search_in_module(
|
yield from search_in_module(
|
||||||
inference_state,
|
inference_state,
|
||||||
empty_module_context,
|
empty_module_context,
|
||||||
names=names,
|
names=names,
|
||||||
@@ -346,8 +335,7 @@ class Project(object):
|
|||||||
wanted_names=wanted_names,
|
wanted_names=wanted_names,
|
||||||
complete=complete,
|
complete=complete,
|
||||||
convert=True,
|
convert=True,
|
||||||
):
|
)
|
||||||
yield x # Python 2...
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (self.__class__.__name__, self._path)
|
return '<%s: %s>' % (self.__class__.__name__, self._path)
|
||||||
@@ -355,7 +343,7 @@ class Project(object):
|
|||||||
|
|
||||||
def _is_potential_project(path):
|
def _is_potential_project(path):
|
||||||
for name in _CONTAINS_POTENTIAL_PROJECT:
|
for name in _CONTAINS_POTENTIAL_PROJECT:
|
||||||
if os.path.exists(os.path.join(path, name)):
|
if path.joinpath(name).exists():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -363,7 +351,7 @@ def _is_potential_project(path):
|
|||||||
def _is_django_path(directory):
|
def _is_django_path(directory):
|
||||||
""" Detects the path of the very well known Django library (if used) """
|
""" Detects the path of the very well known Django library (if used) """
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(directory, 'manage.py'), 'rb') as f:
|
with open(directory.joinpath('manage.py'), 'rb') as f:
|
||||||
return b"DJANGO_SETTINGS_MODULE" in f.read()
|
return b"DJANGO_SETTINGS_MODULE" in f.read()
|
||||||
except (FileNotFoundError, IsADirectoryError, PermissionError):
|
except (FileNotFoundError, IsADirectoryError, PermissionError):
|
||||||
return False
|
return False
|
||||||
@@ -380,12 +368,14 @@ def get_default_project(path=None):
|
|||||||
``requirements.txt`` and ``MANIFEST.in``.
|
``requirements.txt`` and ``MANIFEST.in``.
|
||||||
"""
|
"""
|
||||||
if path is None:
|
if path is None:
|
||||||
path = os.getcwd()
|
path = Path.cwd()
|
||||||
|
elif isinstance(path, str):
|
||||||
|
path = Path(path)
|
||||||
|
|
||||||
check = os.path.realpath(path)
|
check = path.absolute()
|
||||||
probable_path = None
|
probable_path = None
|
||||||
first_no_init_file = None
|
first_no_init_file = None
|
||||||
for dir in traverse_parents(check, include_current=True):
|
for dir in chain([check], check.parents):
|
||||||
try:
|
try:
|
||||||
return Project.load(dir)
|
return Project.load(dir)
|
||||||
except (FileNotFoundError, IsADirectoryError, PermissionError):
|
except (FileNotFoundError, IsADirectoryError, PermissionError):
|
||||||
@@ -394,11 +384,11 @@ def get_default_project(path=None):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if first_no_init_file is None:
|
if first_no_init_file is None:
|
||||||
if os.path.exists(os.path.join(dir, '__init__.py')):
|
if dir.joinpath('__init__.py').exists():
|
||||||
# In the case that a __init__.py exists, it's in 99% just a
|
# In the case that a __init__.py exists, it's in 99% just a
|
||||||
# Python package and the project sits at least one level above.
|
# Python package and the project sits at least one level above.
|
||||||
continue
|
continue
|
||||||
else:
|
elif not dir.is_file():
|
||||||
first_no_init_file = dir
|
first_no_init_file = dir
|
||||||
|
|
||||||
if _is_django_path(dir):
|
if _is_django_path(dir):
|
||||||
@@ -416,7 +406,7 @@ def get_default_project(path=None):
|
|||||||
if first_no_init_file is not None:
|
if first_no_init_file is not None:
|
||||||
return Project(first_no_init_file)
|
return Project(first_no_init_file)
|
||||||
|
|
||||||
curdir = path if os.path.isdir(path) else os.path.dirname(path)
|
curdir = path if path.is_dir() else path.parent
|
||||||
return Project(curdir)
|
return Project(curdir)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from os.path import dirname, basename, join, relpath
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import difflib
|
import difflib
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from parso import split_lines
|
from parso import split_lines
|
||||||
|
|
||||||
@@ -43,15 +42,15 @@ class ChangedFile(object):
|
|||||||
if self._from_path is None:
|
if self._from_path is None:
|
||||||
from_p = ''
|
from_p = ''
|
||||||
else:
|
else:
|
||||||
from_p = relpath(self._from_path, project_path)
|
from_p = self._from_path.relative_to(project_path)
|
||||||
if self._to_path is None:
|
if self._to_path is None:
|
||||||
to_p = ''
|
to_p = ''
|
||||||
else:
|
else:
|
||||||
to_p = relpath(self._to_path, project_path)
|
to_p = self._to_path.relative_to(project_path)
|
||||||
diff = difflib.unified_diff(
|
diff = difflib.unified_diff(
|
||||||
old_lines, new_lines,
|
old_lines, new_lines,
|
||||||
fromfile=from_p,
|
fromfile=str(from_p),
|
||||||
tofile=to_p,
|
tofile=str(to_p),
|
||||||
)
|
)
|
||||||
# Apparently there's a space at the end of the diff - for whatever
|
# Apparently there's a space at the end of the diff - for whatever
|
||||||
# reason.
|
# reason.
|
||||||
@@ -79,17 +78,15 @@ class Refactoring(object):
|
|||||||
self._renames = renames
|
self._renames = renames
|
||||||
self._file_to_node_changes = file_to_node_changes
|
self._file_to_node_changes = file_to_node_changes
|
||||||
|
|
||||||
def get_changed_files(self):
|
def get_changed_files(self) -> Dict[Path, ChangedFile]:
|
||||||
"""
|
|
||||||
Returns a path to ``ChangedFile`` map.
|
|
||||||
"""
|
|
||||||
def calculate_to_path(p):
|
def calculate_to_path(p):
|
||||||
if p is None:
|
if p is None:
|
||||||
return p
|
return p
|
||||||
|
p = str(p)
|
||||||
for from_, to in renames:
|
for from_, to in renames:
|
||||||
if p.startswith(from_):
|
if p.startswith(str(from_)):
|
||||||
p = to + p[len(from_):]
|
p = str(to) + p[len(str(from_)):]
|
||||||
return p
|
return Path(p)
|
||||||
|
|
||||||
renames = self.get_renames()
|
renames = self.get_renames()
|
||||||
return {
|
return {
|
||||||
@@ -115,7 +112,7 @@ class Refactoring(object):
|
|||||||
project_path = self._inference_state.project.path
|
project_path = self._inference_state.project.path
|
||||||
for from_, to in self.get_renames():
|
for from_, to in self.get_renames():
|
||||||
text += 'rename from %s\nrename to %s\n' \
|
text += 'rename from %s\nrename to %s\n' \
|
||||||
% (relpath(from_, project_path), relpath(to, project_path))
|
% (from_.relative_to(project_path), to.relative_to(project_path))
|
||||||
|
|
||||||
return text + ''.join(f.get_diff() for f in self.get_changed_files().values())
|
return text + ''.join(f.get_diff() for f in self.get_changed_files().values())
|
||||||
|
|
||||||
@@ -127,17 +124,14 @@ class Refactoring(object):
|
|||||||
f.apply()
|
f.apply()
|
||||||
|
|
||||||
for old, new in self.get_renames():
|
for old, new in self.get_renames():
|
||||||
os.rename(old, new)
|
old.rename(new)
|
||||||
|
|
||||||
|
|
||||||
def _calculate_rename(path, new_name):
|
def _calculate_rename(path, new_name):
|
||||||
name = basename(path)
|
dir_ = path.parent
|
||||||
dir_ = dirname(path)
|
if path.name in ('__init__.py', '__init__.pyi'):
|
||||||
if name in ('__init__.py', '__init__.pyi'):
|
return dir_, dir_.parent.joinpath(new_name)
|
||||||
parent_dir = dirname(dir_)
|
return path, dir_.joinpath(new_name + path.suffix)
|
||||||
return dir_, join(parent_dir, new_name)
|
|
||||||
ending = re.search(r'\.pyi?$', name).group(0)
|
|
||||||
return path, join(dir_, new_name + ending)
|
|
||||||
|
|
||||||
|
|
||||||
def rename(inference_state, definitions, new_name):
|
def rename(inference_state, definitions, new_name):
|
||||||
@@ -150,7 +144,8 @@ def rename(inference_state, definitions, new_name):
|
|||||||
for d in definitions:
|
for d in definitions:
|
||||||
tree_name = d._name.tree_name
|
tree_name = d._name.tree_name
|
||||||
if d.type == 'module' and tree_name is None:
|
if d.type == 'module' and tree_name is None:
|
||||||
file_renames.add(_calculate_rename(d.module_path, new_name))
|
p = None if d.module_path is None else Path(d.module_path)
|
||||||
|
file_renames.add(_calculate_rename(p, new_name))
|
||||||
else:
|
else:
|
||||||
# This private access is ok in a way. It's not public to
|
# This private access is ok in a way. It's not public to
|
||||||
# protect Jedi users from seeing it.
|
# protect Jedi users from seeing it.
|
||||||
|
|||||||
@@ -350,8 +350,7 @@ def _find_non_global_names(nodes):
|
|||||||
if node.type == 'trailer' and node.children[0] == '.':
|
if node.type == 'trailer' and node.children[0] == '.':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for x in _find_non_global_names(children): # Python 2...
|
yield from _find_non_global_names(children)
|
||||||
yield x
|
|
||||||
|
|
||||||
|
|
||||||
def _get_code_insertion_node(node, is_bound_method):
|
def _get_code_insertion_node(node, is_bound_method):
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ just use IPython instead::
|
|||||||
Then you will be able to use Jedi completer in your Python interpreter::
|
Then you will be able to use Jedi completer in your Python interpreter::
|
||||||
|
|
||||||
$ python
|
$ python
|
||||||
Python 2.7.2+ (default, Jul 20 2012, 22:15:08)
|
Python 3.9.2+ (default, Jul 20 2020, 22:15:08)
|
||||||
[GCC 4.6.1] on linux2
|
[GCC 4.6.1] on linux2
|
||||||
Type "help", "copyright", "credits" or "license" for more information.
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
>>> import os
|
>>> import os
|
||||||
|
|||||||
+2
-3
@@ -9,7 +9,6 @@ names in a module, but pretty much an arbitrary string.
|
|||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from jedi._compatibility import unicode
|
|
||||||
from jedi.inference.names import AbstractArbitraryName
|
from jedi.inference.names import AbstractArbitraryName
|
||||||
from jedi.inference.helpers import infer_call_of_leaf
|
from jedi.inference.helpers import infer_call_of_leaf
|
||||||
from jedi.api.classes import Completion
|
from jedi.api.classes import Completion
|
||||||
@@ -19,7 +18,7 @@ _sentinel = object()
|
|||||||
|
|
||||||
|
|
||||||
class StringName(AbstractArbitraryName):
|
class StringName(AbstractArbitraryName):
|
||||||
api_type = u'string'
|
api_type = 'string'
|
||||||
is_value_name = False
|
is_value_name = False
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +64,7 @@ def _completions_for_dicts(inference_state, dicts, literal_string, cut_end_quote
|
|||||||
|
|
||||||
|
|
||||||
def _create_repr_string(literal_string, dict_key):
|
def _create_repr_string(literal_string, dict_key):
|
||||||
if not isinstance(dict_key, (unicode, bytes)) or not literal_string:
|
if not isinstance(dict_key, (str, bytes)) or not literal_string:
|
||||||
return repr(dict_key)
|
return repr(dict_key)
|
||||||
|
|
||||||
r = repr(dict_key)
|
r = repr(dict_key)
|
||||||
|
|||||||
@@ -1,18 +1,6 @@
|
|||||||
import os
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
|
||||||
def traverse_parents(path, include_current=False):
|
|
||||||
if not include_current:
|
|
||||||
path = os.path.dirname(path)
|
|
||||||
|
|
||||||
previous = None
|
|
||||||
while previous != path:
|
|
||||||
yield path
|
|
||||||
previous = path
|
|
||||||
path = os.path.dirname(path)
|
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def monkeypatch(obj, attribute_name, new_value):
|
def monkeypatch(obj, attribute_name, new_value):
|
||||||
"""
|
"""
|
||||||
|
|||||||
+3
-12
@@ -2,8 +2,6 @@ import os
|
|||||||
import time
|
import time
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from jedi._compatibility import encoding, is_py3, u
|
|
||||||
|
|
||||||
_inited = False
|
_inited = False
|
||||||
|
|
||||||
|
|
||||||
@@ -97,16 +95,14 @@ def increase_indent_cm(title=None, color='MAGENTA'):
|
|||||||
dbg('End: ' + title, color=color)
|
dbg('End: ' + title, color=color)
|
||||||
|
|
||||||
|
|
||||||
def dbg(message, *args, **kwargs):
|
def dbg(message, *args, color='GREEN'):
|
||||||
""" Looks at the stack, to see if a debug message should be printed. """
|
""" Looks at the stack, to see if a debug message should be printed. """
|
||||||
# Python 2 compatibility, because it doesn't understand default args
|
|
||||||
color = kwargs.pop('color', 'GREEN')
|
|
||||||
assert color
|
assert color
|
||||||
|
|
||||||
if debug_function and enable_notice:
|
if debug_function and enable_notice:
|
||||||
i = ' ' * _debug_indent
|
i = ' ' * _debug_indent
|
||||||
_lazy_colorama_init()
|
_lazy_colorama_init()
|
||||||
debug_function(color, i + 'dbg: ' + message % tuple(u(repr(a)) for a in args))
|
debug_function(color, i + 'dbg: ' + message % tuple(repr(a) for a in args))
|
||||||
|
|
||||||
|
|
||||||
def warning(message, *args, **kwargs):
|
def warning(message, *args, **kwargs):
|
||||||
@@ -116,7 +112,7 @@ def warning(message, *args, **kwargs):
|
|||||||
if debug_function and enable_warning:
|
if debug_function and enable_warning:
|
||||||
i = ' ' * _debug_indent
|
i = ' ' * _debug_indent
|
||||||
if format:
|
if format:
|
||||||
message = message % tuple(u(repr(a)) for a in args)
|
message = message % tuple(repr(a) for a in args)
|
||||||
debug_function('RED', i + 'warning: ' + message)
|
debug_function('RED', i + 'warning: ' + message)
|
||||||
|
|
||||||
|
|
||||||
@@ -135,9 +131,4 @@ def print_to_stdout(color, str_out):
|
|||||||
"""
|
"""
|
||||||
col = getattr(Fore, color)
|
col = getattr(Fore, color)
|
||||||
_lazy_colorama_init()
|
_lazy_colorama_init()
|
||||||
if not is_py3:
|
|
||||||
str_out = str_out.encode(encoding, 'replace')
|
|
||||||
print(col + str_out + Fore.RESET)
|
print(col + str_out + Fore.RESET)
|
||||||
|
|
||||||
|
|
||||||
# debug_function = print_to_stdout
|
|
||||||
|
|||||||
+2
-2
@@ -65,13 +65,13 @@ class FileIOFolderMixin(object):
|
|||||||
class ZipFileIO(file_io.KnownContentFileIO, FileIOFolderMixin):
|
class ZipFileIO(file_io.KnownContentFileIO, FileIOFolderMixin):
|
||||||
"""For .zip and .egg archives"""
|
"""For .zip and .egg archives"""
|
||||||
def __init__(self, path, code, zip_path):
|
def __init__(self, path, code, zip_path):
|
||||||
super(ZipFileIO, self).__init__(path, code)
|
super().__init__(path, code)
|
||||||
self._zip_path = zip_path
|
self._zip_path = zip_path
|
||||||
|
|
||||||
def get_last_modified(self):
|
def get_last_modified(self):
|
||||||
try:
|
try:
|
||||||
return os.path.getmtime(self._zip_path)
|
return os.path.getmtime(self._zip_path)
|
||||||
except OSError: # Python 3 would probably only need FileNotFoundError
|
except (FileNotFoundError, PermissionError, NotADirectoryError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -123,16 +123,14 @@ class InferenceState(object):
|
|||||||
@property
|
@property
|
||||||
@inference_state_function_cache()
|
@inference_state_function_cache()
|
||||||
def builtins_module(self):
|
def builtins_module(self):
|
||||||
module_name = u'builtins'
|
module_name = 'builtins'
|
||||||
if self.environment.version_info.major == 2:
|
|
||||||
module_name = u'__builtin__'
|
|
||||||
builtins_module, = self.import_module((module_name,), sys_path=())
|
builtins_module, = self.import_module((module_name,), sys_path=())
|
||||||
return builtins_module
|
return builtins_module
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@inference_state_function_cache()
|
@inference_state_function_cache()
|
||||||
def typing_module(self):
|
def typing_module(self):
|
||||||
typing_module, = self.import_module((u'typing',))
|
typing_module, = self.import_module(('typing',))
|
||||||
return typing_module
|
return typing_module
|
||||||
|
|
||||||
def reset_recursion_limitations(self):
|
def reset_recursion_limitations(self):
|
||||||
@@ -178,14 +176,16 @@ class InferenceState(object):
|
|||||||
|
|
||||||
return helpers.infer_call_of_leaf(context, name)
|
return helpers.infer_call_of_leaf(context, name)
|
||||||
|
|
||||||
def parse_and_get_code(self, code=None, path=None, encoding='utf-8',
|
def parse_and_get_code(self, code=None, path=None,
|
||||||
use_latest_grammar=False, file_io=None, **kwargs):
|
use_latest_grammar=False, file_io=None, **kwargs):
|
||||||
|
if path is not None:
|
||||||
|
path = str(path)
|
||||||
if code is None:
|
if code is None:
|
||||||
if file_io is None:
|
if file_io is None:
|
||||||
file_io = FileIO(path)
|
file_io = FileIO(path)
|
||||||
code = file_io.read()
|
code = file_io.read()
|
||||||
# We cannot just use parso, because it doesn't use errors='replace'.
|
# We cannot just use parso, because it doesn't use errors='replace'.
|
||||||
code = parso.python_bytes_to_unicode(code, encoding=encoding, errors='replace')
|
code = parso.python_bytes_to_unicode(code, encoding='utf-8', errors='replace')
|
||||||
|
|
||||||
if len(code) > settings._cropped_file_size:
|
if len(code) > settings._cropped_file_size:
|
||||||
code = code[:settings._cropped_file_size]
|
code = code[:settings._cropped_file_size]
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ Module for statical analysis.
|
|||||||
"""
|
"""
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
from jedi._compatibility import force_unicode
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.helpers import is_string
|
from jedi.inference.helpers import is_string
|
||||||
|
|
||||||
@@ -50,13 +49,10 @@ class Error(object):
|
|||||||
first = self.__class__.__name__[0]
|
first = self.__class__.__name__[0]
|
||||||
return first + str(CODES[self.name][0])
|
return first + str(CODES[self.name][0])
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return '%s:%s:%s: %s %s' % (self.path, self.line, self.column,
|
return '%s:%s:%s: %s %s' % (self.path, self.line, self.column,
|
||||||
self.code, self.message)
|
self.code, self.message)
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.__unicode__()
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return (self.path == other.path and self.name == other.name
|
return (self.path == other.path and self.name == other.name
|
||||||
and self._start_pos == other._start_pos)
|
and self._start_pos == other._start_pos)
|
||||||
@@ -193,7 +189,7 @@ def _check_for_exception_catch(node_context, jedi_name, exception, payload=None)
|
|||||||
key, lazy_value = unpacked_args[1]
|
key, lazy_value = unpacked_args[1]
|
||||||
names = list(lazy_value.infer())
|
names = list(lazy_value.infer())
|
||||||
assert len(names) == 1 and is_string(names[0])
|
assert len(names) == 1 and is_string(names[0])
|
||||||
assert force_unicode(names[0].get_safe_value()) == payload[1].value
|
assert names[0].get_safe_value() == payload[1].value
|
||||||
|
|
||||||
# Check objects
|
# Check objects
|
||||||
key, lazy_value = unpacked_args[0]
|
key, lazy_value = unpacked_args[0]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import re
|
import re
|
||||||
|
from itertools import zip_longest
|
||||||
|
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
from jedi._compatibility import zip_longest
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.utils import PushBackIterator
|
from jedi.inference.utils import PushBackIterator
|
||||||
from jedi.inference import analysis
|
from jedi.inference import analysis
|
||||||
@@ -142,11 +142,8 @@ def unpack_arglist(arglist):
|
|||||||
if arglist is None:
|
if arglist is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Allow testlist here as well for Python2's class inheritance
|
if arglist.type != 'arglist' and not (
|
||||||
# definitions.
|
arglist.type == 'argument' and arglist.children[0] in ('*', '**')):
|
||||||
if not (arglist.type in ('arglist', 'testlist') or (
|
|
||||||
# in python 3.5 **arg is an argument, not arglist
|
|
||||||
arglist.type == 'argument' and arglist.children[0] in ('*', '**'))):
|
|
||||||
yield 0, arglist
|
yield 0, arglist
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -189,8 +186,6 @@ class TreeArguments(AbstractArguments):
|
|||||||
iterators = [_iterate_star_args(self.context, a, el, funcdef)
|
iterators = [_iterate_star_args(self.context, a, el, funcdef)
|
||||||
for a in arrays]
|
for a in arrays]
|
||||||
for values in list(zip_longest(*iterators)):
|
for values in list(zip_longest(*iterators)):
|
||||||
# TODO zip_longest yields None, that means this would raise
|
|
||||||
# an exception?
|
|
||||||
yield None, get_merged_lazy_value(
|
yield None, get_merged_lazy_value(
|
||||||
[v for v in values if v is not None]
|
[v for v in values if v is not None]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ just one.
|
|||||||
"""
|
"""
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from operator import add
|
from operator import add
|
||||||
|
from itertools import zip_longest
|
||||||
|
|
||||||
from parso.python.tree import Name
|
from parso.python.tree import Name
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi._compatibility import zip_longest, unicode
|
|
||||||
from jedi.parser_utils import clean_scope_docstring
|
from jedi.parser_utils import clean_scope_docstring
|
||||||
from jedi.inference.helpers import SimpleGetItemNotFound
|
from jedi.inference.helpers import SimpleGetItemNotFound
|
||||||
from jedi.inference.utils import safe_property
|
from jedi.inference.utils import safe_property
|
||||||
@@ -92,7 +93,7 @@ class HelperValueMixin(object):
|
|||||||
return values
|
return values
|
||||||
|
|
||||||
def py__await__(self):
|
def py__await__(self):
|
||||||
await_value_set = self.py__getattribute__(u"__await__")
|
await_value_set = self.py__getattribute__("__await__")
|
||||||
if not await_value_set:
|
if not await_value_set:
|
||||||
debug.warning('Tried to run __await__ on value %s', self)
|
debug.warning('Tried to run __await__ on value %s', self)
|
||||||
return await_value_set.execute_with_values()
|
return await_value_set.execute_with_values()
|
||||||
@@ -357,7 +358,7 @@ class ValueWrapper(_ValueWrapperBase):
|
|||||||
|
|
||||||
class TreeValue(Value):
|
class TreeValue(Value):
|
||||||
def __init__(self, inference_state, parent_context, tree_node):
|
def __init__(self, inference_state, parent_context, tree_node):
|
||||||
super(TreeValue, self).__init__(inference_state, parent_context)
|
super().__init__(inference_state, parent_context)
|
||||||
self.tree_node = tree_node
|
self.tree_node = tree_node
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -385,7 +386,7 @@ def _getitem(value, index_values, contextualized_node):
|
|||||||
unused_values = set()
|
unused_values = set()
|
||||||
for index_value in index_values:
|
for index_value in index_values:
|
||||||
index = index_value.get_safe_value(default=None)
|
index = index_value.get_safe_value(default=None)
|
||||||
if type(index) in (float, int, str, unicode, slice, bytes):
|
if type(index) in (float, int, str, slice, bytes):
|
||||||
try:
|
try:
|
||||||
result |= value.py__simple_getitem__(index)
|
result |= value.py__simple_getitem__(index)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class CachedMetaClass(type):
|
|||||||
"""
|
"""
|
||||||
@inference_state_as_method_param_cache()
|
@inference_state_as_method_param_cache()
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
return super(CachedMetaClass, self).__call__(*args, **kwargs)
|
return super().__call__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def inference_state_method_generator_cache():
|
def inference_state_method_generator_cache():
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from jedi._compatibility import unicode
|
|
||||||
from jedi.inference.compiled.value import CompiledValue, CompiledName, \
|
from jedi.inference.compiled.value import CompiledValue, CompiledName, \
|
||||||
CompiledValueFilter, CompiledValueName, create_from_access_path
|
CompiledValueFilter, CompiledValueName, create_from_access_path
|
||||||
from jedi.inference.base_value import LazyValueWrapper
|
from jedi.inference.base_value import LazyValueWrapper
|
||||||
@@ -29,7 +28,7 @@ class ExactValue(LazyValueWrapper):
|
|||||||
if name in ('get_safe_value', 'execute_operation', 'access_handle',
|
if name in ('get_safe_value', 'execute_operation', 'access_handle',
|
||||||
'negate', 'py__bool__', 'is_compiled'):
|
'negate', 'py__bool__', 'is_compiled'):
|
||||||
return getattr(self._compiled_value, name)
|
return getattr(self._compiled_value, name)
|
||||||
return super(ExactValue, self).__getattribute__(name)
|
return super().__getattribute__(name)
|
||||||
|
|
||||||
def _get_wrapped_value(self):
|
def _get_wrapped_value(self):
|
||||||
instance, = builtin_from_name(
|
instance, = builtin_from_name(
|
||||||
@@ -45,7 +44,7 @@ def create_simple_object(inference_state, obj):
|
|||||||
Only allows creations of objects that are easily picklable across Python
|
Only allows creations of objects that are easily picklable across Python
|
||||||
versions.
|
versions.
|
||||||
"""
|
"""
|
||||||
assert type(obj) in (int, float, str, bytes, unicode, slice, complex, bool), obj
|
assert type(obj) in (int, float, str, bytes, slice, complex, bool), repr(obj)
|
||||||
compiled_value = create_from_access_path(
|
compiled_value = create_from_access_path(
|
||||||
inference_state,
|
inference_state,
|
||||||
inference_state.compiled_subprocess.create_simple_object(obj)
|
inference_state.compiled_subprocess.create_simple_object(obj)
|
||||||
@@ -54,7 +53,7 @@ def create_simple_object(inference_state, obj):
|
|||||||
|
|
||||||
|
|
||||||
def get_string_value_set(inference_state):
|
def get_string_value_set(inference_state):
|
||||||
return builtin_from_name(inference_state, u'str').execute_with_values()
|
return builtin_from_name(inference_state, 'str').execute_with_values()
|
||||||
|
|
||||||
|
|
||||||
def load_module(inference_state, dotted_name, **kwargs):
|
def load_module(inference_state, dotted_name, **kwargs):
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import inspect
|
import inspect
|
||||||
import types
|
import types
|
||||||
import sys
|
import sys
|
||||||
@@ -6,12 +5,12 @@ import operator as op
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import warnings
|
import warnings
|
||||||
import re
|
import re
|
||||||
|
import builtins
|
||||||
|
import typing
|
||||||
|
|
||||||
from jedi._compatibility import unicode, is_py3, builtins, \
|
|
||||||
py_version, force_unicode
|
|
||||||
from jedi.inference.compiled.getattr_static import getattr_static
|
from jedi.inference.compiled.getattr_static import getattr_static
|
||||||
|
|
||||||
ALLOWED_GETITEM_TYPES = (str, list, tuple, unicode, bytes, bytearray, dict)
|
ALLOWED_GETITEM_TYPES = (str, list, tuple, bytes, bytearray, dict)
|
||||||
|
|
||||||
MethodDescriptorType = type(str.replace)
|
MethodDescriptorType = type(str.replace)
|
||||||
# These are not considered classes and access is granted even though they have
|
# These are not considered classes and access is granted even though they have
|
||||||
@@ -28,17 +27,12 @@ NOT_CLASS_TYPES = (
|
|||||||
types.MethodType,
|
types.MethodType,
|
||||||
types.ModuleType,
|
types.ModuleType,
|
||||||
types.TracebackType,
|
types.TracebackType,
|
||||||
MethodDescriptorType
|
MethodDescriptorType,
|
||||||
|
types.MappingProxyType,
|
||||||
|
types.SimpleNamespace,
|
||||||
|
types.DynamicClassAttribute,
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_py3:
|
|
||||||
NOT_CLASS_TYPES += (
|
|
||||||
types.MappingProxyType,
|
|
||||||
types.SimpleNamespace,
|
|
||||||
types.DynamicClassAttribute,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Those types don't exist in typing.
|
# Those types don't exist in typing.
|
||||||
MethodDescriptorType = type(str.replace)
|
MethodDescriptorType = type(str.replace)
|
||||||
WrapperDescriptorType = type(set.__iter__)
|
WrapperDescriptorType = type(set.__iter__)
|
||||||
@@ -144,35 +138,22 @@ class AccessPath(object):
|
|||||||
def __init__(self, accesses):
|
def __init__(self, accesses):
|
||||||
self.accesses = accesses
|
self.accesses = accesses
|
||||||
|
|
||||||
# Writing both of these methods here looks a bit ridiculous. However with
|
|
||||||
# the differences of Python 2/3 it's actually necessary, because we will
|
|
||||||
# otherwise have a accesses attribute that is bytes instead of unicode.
|
|
||||||
def __getstate__(self):
|
|
||||||
return self.accesses
|
|
||||||
|
|
||||||
def __setstate__(self, value):
|
|
||||||
self.accesses = value
|
|
||||||
|
|
||||||
|
|
||||||
def create_access_path(inference_state, obj):
|
def create_access_path(inference_state, obj):
|
||||||
access = create_access(inference_state, obj)
|
access = create_access(inference_state, obj)
|
||||||
return AccessPath(access.get_access_path_tuples())
|
return AccessPath(access.get_access_path_tuples())
|
||||||
|
|
||||||
|
|
||||||
def _force_unicode_decorator(func):
|
|
||||||
return lambda *args, **kwargs: force_unicode(func(*args, **kwargs))
|
|
||||||
|
|
||||||
|
|
||||||
def get_api_type(obj):
|
def get_api_type(obj):
|
||||||
if inspect.isclass(obj):
|
if inspect.isclass(obj):
|
||||||
return u'class'
|
return 'class'
|
||||||
elif inspect.ismodule(obj):
|
elif inspect.ismodule(obj):
|
||||||
return u'module'
|
return 'module'
|
||||||
elif inspect.isbuiltin(obj) or inspect.ismethod(obj) \
|
elif inspect.isbuiltin(obj) or inspect.ismethod(obj) \
|
||||||
or inspect.ismethoddescriptor(obj) or inspect.isfunction(obj):
|
or inspect.ismethoddescriptor(obj) or inspect.isfunction(obj):
|
||||||
return u'function'
|
return 'function'
|
||||||
# Everything else...
|
# Everything else...
|
||||||
return u'instance'
|
return 'instance'
|
||||||
|
|
||||||
|
|
||||||
class DirectObjectAccess(object):
|
class DirectObjectAccess(object):
|
||||||
@@ -199,7 +180,7 @@ class DirectObjectAccess(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def py__doc__(self):
|
def py__doc__(self):
|
||||||
return force_unicode(inspect.getdoc(self._obj)) or u''
|
return inspect.getdoc(self._obj) or ''
|
||||||
|
|
||||||
def py__name__(self):
|
def py__name__(self):
|
||||||
if not _is_class_instance(self._obj) or \
|
if not _is_class_instance(self._obj) or \
|
||||||
@@ -214,7 +195,7 @@ class DirectObjectAccess(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return force_unicode(cls.__name__)
|
return cls.__name__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -260,26 +241,23 @@ class DirectObjectAccess(object):
|
|||||||
# Avoid some weird hacks that would just fail, because they cannot be
|
# Avoid some weird hacks that would just fail, because they cannot be
|
||||||
# used by pickle.
|
# used by pickle.
|
||||||
if not isinstance(paths, list) \
|
if not isinstance(paths, list) \
|
||||||
or not all(isinstance(p, (bytes, unicode)) for p in paths):
|
or not all(isinstance(p, str) for p in paths):
|
||||||
return None
|
return None
|
||||||
return paths
|
return paths
|
||||||
|
|
||||||
@_force_unicode_decorator
|
|
||||||
@shorten_repr
|
@shorten_repr
|
||||||
def get_repr(self):
|
def get_repr(self):
|
||||||
builtins = 'builtins', '__builtin__'
|
|
||||||
|
|
||||||
if inspect.ismodule(self._obj):
|
if inspect.ismodule(self._obj):
|
||||||
return repr(self._obj)
|
return repr(self._obj)
|
||||||
# Try to avoid execution of the property.
|
# Try to avoid execution of the property.
|
||||||
if safe_getattr(self._obj, '__module__', default='') in builtins:
|
if safe_getattr(self._obj, '__module__', default='') == 'builtins':
|
||||||
return repr(self._obj)
|
return repr(self._obj)
|
||||||
|
|
||||||
type_ = type(self._obj)
|
type_ = type(self._obj)
|
||||||
if type_ == type:
|
if type_ == type:
|
||||||
return type.__repr__(self._obj)
|
return type.__repr__(self._obj)
|
||||||
|
|
||||||
if safe_getattr(type_, '__module__', default='') in builtins:
|
if safe_getattr(type_, '__module__', default='') == 'builtins':
|
||||||
# Allow direct execution of repr for builtins.
|
# Allow direct execution of repr for builtins.
|
||||||
return repr(self._obj)
|
return repr(self._obj)
|
||||||
return object.__repr__(self._obj)
|
return object.__repr__(self._obj)
|
||||||
@@ -310,10 +288,10 @@ class DirectObjectAccess(object):
|
|||||||
name = try_to_get_name(type(self._obj))
|
name = try_to_get_name(type(self._obj))
|
||||||
if name is None:
|
if name is None:
|
||||||
return ()
|
return ()
|
||||||
return tuple(force_unicode(n) for n in name.split('.'))
|
return tuple(name.split('.'))
|
||||||
|
|
||||||
def dir(self):
|
def dir(self):
|
||||||
return list(map(force_unicode, dir(self._obj)))
|
return dir(self._obj)
|
||||||
|
|
||||||
def has_iter(self):
|
def has_iter(self):
|
||||||
try:
|
try:
|
||||||
@@ -396,7 +374,7 @@ class DirectObjectAccess(object):
|
|||||||
return [self._create_access(module), access]
|
return [self._create_access(module), access]
|
||||||
|
|
||||||
def get_safe_value(self):
|
def get_safe_value(self):
|
||||||
if type(self._obj) in (bool, bytes, float, int, str, unicode, slice) or self._obj is None:
|
if type(self._obj) in (bool, bytes, float, int, str, slice) or self._obj is None:
|
||||||
return self._obj
|
return self._obj
|
||||||
raise ValueError("Object is type %s and not simple" % type(self._obj))
|
raise ValueError("Object is type %s and not simple" % type(self._obj))
|
||||||
|
|
||||||
@@ -464,9 +442,6 @@ class DirectObjectAccess(object):
|
|||||||
"""
|
"""
|
||||||
Returns Tuple[Optional[str], Tuple[AccessPath, ...]]
|
Returns Tuple[Optional[str], Tuple[AccessPath, ...]]
|
||||||
"""
|
"""
|
||||||
if sys.version_info < (3, 5):
|
|
||||||
return None, ()
|
|
||||||
|
|
||||||
name = None
|
name = None
|
||||||
args = ()
|
args = ()
|
||||||
if safe_getattr(self._obj, '__module__', default='') == 'typing':
|
if safe_getattr(self._obj, '__module__', default='') == 'typing':
|
||||||
@@ -485,8 +460,6 @@ class DirectObjectAccess(object):
|
|||||||
return inspect.isclass(self._obj) and self._obj != type
|
return inspect.isclass(self._obj) and self._obj != type
|
||||||
|
|
||||||
def _annotation_to_str(self, annotation):
|
def _annotation_to_str(self, annotation):
|
||||||
if py_version < 30:
|
|
||||||
return ''
|
|
||||||
return inspect.formatannotation(annotation)
|
return inspect.formatannotation(annotation)
|
||||||
|
|
||||||
def get_signature_params(self):
|
def get_signature_params(self):
|
||||||
@@ -505,8 +478,6 @@ class DirectObjectAccess(object):
|
|||||||
|
|
||||||
def _get_signature(self):
|
def _get_signature(self):
|
||||||
obj = self._obj
|
obj = self._obj
|
||||||
if py_version < 33:
|
|
||||||
raise ValueError("inspect.signature was introduced in 3.3")
|
|
||||||
try:
|
try:
|
||||||
return inspect.signature(obj)
|
return inspect.signature(obj)
|
||||||
except (RuntimeError, TypeError):
|
except (RuntimeError, TypeError):
|
||||||
@@ -525,15 +496,9 @@ class DirectObjectAccess(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Python 2 doesn't have typing.
|
o = typing.get_type_hints(self._obj).get('return')
|
||||||
import typing
|
except Exception:
|
||||||
except ImportError:
|
|
||||||
pass
|
pass
|
||||||
else:
|
|
||||||
try:
|
|
||||||
o = typing.get_type_hints(self._obj).get('return')
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return self._create_access_path(o)
|
return self._create_access_path(o)
|
||||||
|
|
||||||
@@ -546,7 +511,7 @@ class DirectObjectAccess(object):
|
|||||||
objects of an objects
|
objects of an objects
|
||||||
"""
|
"""
|
||||||
tuples = dict(
|
tuples = dict(
|
||||||
(force_unicode(name), self.is_allowed_getattr(name))
|
(name, self.is_allowed_getattr(name))
|
||||||
for name in self.dir()
|
for name in self.dir()
|
||||||
)
|
)
|
||||||
return self.needs_type_completions(), tuples
|
return self.needs_type_completions(), tuples
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ information returned to enable Jedi to make decisions.
|
|||||||
import types
|
import types
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi._compatibility import py_version
|
|
||||||
|
|
||||||
_sentinel = object()
|
_sentinel = object()
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ def _is_type(obj):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _shadowed_dict_newstyle(klass):
|
def _shadowed_dict(klass):
|
||||||
dict_attr = type.__dict__["__dict__"]
|
dict_attr = type.__dict__["__dict__"]
|
||||||
for entry in _static_getmro(klass):
|
for entry in _static_getmro(klass):
|
||||||
try:
|
try:
|
||||||
@@ -54,7 +53,7 @@ def _shadowed_dict_newstyle(klass):
|
|||||||
return _sentinel
|
return _sentinel
|
||||||
|
|
||||||
|
|
||||||
def _static_getmro_newstyle(klass):
|
def _static_getmro(klass):
|
||||||
mro = type.__dict__['__mro__'].__get__(klass)
|
mro = type.__dict__['__mro__'].__get__(klass)
|
||||||
if not isinstance(mro, (tuple, list)):
|
if not isinstance(mro, (tuple, list)):
|
||||||
# There are unfortunately no tests for this, I was not able to
|
# There are unfortunately no tests for this, I was not able to
|
||||||
@@ -65,70 +64,8 @@ def _static_getmro_newstyle(klass):
|
|||||||
return mro
|
return mro
|
||||||
|
|
||||||
|
|
||||||
if py_version >= 30:
|
|
||||||
_shadowed_dict = _shadowed_dict_newstyle
|
|
||||||
_get_type = type
|
|
||||||
_static_getmro = _static_getmro_newstyle
|
|
||||||
else:
|
|
||||||
def _shadowed_dict(klass):
|
|
||||||
"""
|
|
||||||
In Python 2 __dict__ is not overwritable:
|
|
||||||
|
|
||||||
class Foo(object): pass
|
|
||||||
setattr(Foo, '__dict__', 4)
|
|
||||||
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "<stdin>", line 1, in <module>
|
|
||||||
TypeError: __dict__ must be a dictionary object
|
|
||||||
|
|
||||||
It applies to both newstyle and oldstyle classes:
|
|
||||||
|
|
||||||
class Foo(object): pass
|
|
||||||
setattr(Foo, '__dict__', 4)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "<stdin>", line 1, in <module>
|
|
||||||
AttributeError: attribute '__dict__' of 'type' objects is not writable
|
|
||||||
|
|
||||||
It also applies to instances of those objects. However to keep things
|
|
||||||
straight forward, newstyle classes always use the complicated way of
|
|
||||||
accessing it while oldstyle classes just use getattr.
|
|
||||||
"""
|
|
||||||
if type(klass) is _oldstyle_class_type:
|
|
||||||
return getattr(klass, '__dict__', _sentinel)
|
|
||||||
return _shadowed_dict_newstyle(klass)
|
|
||||||
|
|
||||||
class _OldStyleClass:
|
|
||||||
pass
|
|
||||||
|
|
||||||
_oldstyle_instance_type = type(_OldStyleClass())
|
|
||||||
_oldstyle_class_type = type(_OldStyleClass)
|
|
||||||
|
|
||||||
def _get_type(obj):
|
|
||||||
type_ = object.__getattribute__(obj, '__class__')
|
|
||||||
if type_ is _oldstyle_instance_type:
|
|
||||||
# Somehow for old style classes we need to access it directly.
|
|
||||||
return obj.__class__
|
|
||||||
return type_
|
|
||||||
|
|
||||||
def _static_getmro(klass):
|
|
||||||
if type(klass) is _oldstyle_class_type:
|
|
||||||
def oldstyle_mro(klass):
|
|
||||||
"""
|
|
||||||
Oldstyle mro is a really simplistic way of look up mro:
|
|
||||||
https://stackoverflow.com/questions/54867/what-is-the-difference-between-old-style-and-new-style-classes-in-python
|
|
||||||
"""
|
|
||||||
yield klass
|
|
||||||
for base in klass.__bases__:
|
|
||||||
for yield_from in oldstyle_mro(base):
|
|
||||||
yield yield_from
|
|
||||||
|
|
||||||
return oldstyle_mro(klass)
|
|
||||||
|
|
||||||
return _static_getmro_newstyle(klass)
|
|
||||||
|
|
||||||
|
|
||||||
def _safe_hasattr(obj, name):
|
def _safe_hasattr(obj, name):
|
||||||
return _check_class(_get_type(obj), name) is not _sentinel
|
return _check_class(type(obj), name) is not _sentinel
|
||||||
|
|
||||||
|
|
||||||
def _safe_is_data_descriptor(obj):
|
def _safe_is_data_descriptor(obj):
|
||||||
@@ -151,7 +88,7 @@ def getattr_static(obj, attr, default=_sentinel):
|
|||||||
"""
|
"""
|
||||||
instance_result = _sentinel
|
instance_result = _sentinel
|
||||||
if not _is_type(obj):
|
if not _is_type(obj):
|
||||||
klass = _get_type(obj)
|
klass = type(obj)
|
||||||
dict_attr = _shadowed_dict(klass)
|
dict_attr = _shadowed_dict(klass)
|
||||||
if (dict_attr is _sentinel or type(dict_attr) is types.MemberDescriptorType):
|
if (dict_attr is _sentinel or type(dict_attr) is types.MemberDescriptorType):
|
||||||
instance_result = _check_instance(obj, attr)
|
instance_result = _check_instance(obj, attr)
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ Used only for REPL Completion.
|
|||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
|
|
||||||
from jedi.parser_utils import get_cached_code_lines
|
from jedi.parser_utils import get_cached_code_lines
|
||||||
|
|
||||||
from jedi._compatibility import unwrap
|
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi.inference import compiled
|
from jedi.inference import compiled
|
||||||
@@ -44,7 +42,7 @@ class MixedObject(ValueWrapper):
|
|||||||
to modify the runtime.
|
to modify the runtime.
|
||||||
"""
|
"""
|
||||||
def __init__(self, compiled_value, tree_value):
|
def __init__(self, compiled_value, tree_value):
|
||||||
super(MixedObject, self).__init__(tree_value)
|
super().__init__(tree_value)
|
||||||
self.compiled_value = compiled_value
|
self.compiled_value = compiled_value
|
||||||
self.access_handle = compiled_value.access_handle
|
self.access_handle = compiled_value.access_handle
|
||||||
|
|
||||||
@@ -115,7 +113,7 @@ class MixedName(NameWrapper):
|
|||||||
The ``CompiledName._compiled_value`` is our MixedObject.
|
The ``CompiledName._compiled_value`` is our MixedObject.
|
||||||
"""
|
"""
|
||||||
def __init__(self, wrapped_name, parent_tree_value):
|
def __init__(self, wrapped_name, parent_tree_value):
|
||||||
super(MixedName, self).__init__(wrapped_name)
|
super().__init__(wrapped_name)
|
||||||
self._parent_tree_value = parent_tree_value
|
self._parent_tree_value = parent_tree_value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -141,12 +139,12 @@ class MixedName(NameWrapper):
|
|||||||
|
|
||||||
class MixedObjectFilter(compiled.CompiledValueFilter):
|
class MixedObjectFilter(compiled.CompiledValueFilter):
|
||||||
def __init__(self, inference_state, compiled_value, tree_value):
|
def __init__(self, inference_state, compiled_value, tree_value):
|
||||||
super(MixedObjectFilter, self).__init__(inference_state, compiled_value)
|
super().__init__(inference_state, compiled_value)
|
||||||
self._tree_value = tree_value
|
self._tree_value = tree_value
|
||||||
|
|
||||||
def _create_name(self, name):
|
def _create_name(self, name):
|
||||||
return MixedName(
|
return MixedName(
|
||||||
super(MixedObjectFilter, self)._create_name(name),
|
super()._create_name(name),
|
||||||
self._tree_value,
|
self._tree_value,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -163,12 +161,11 @@ def _load_module(inference_state, path):
|
|||||||
|
|
||||||
def _get_object_to_check(python_object):
|
def _get_object_to_check(python_object):
|
||||||
"""Check if inspect.getfile has a chance to find the source."""
|
"""Check if inspect.getfile has a chance to find the source."""
|
||||||
if sys.version_info[0] > 2:
|
try:
|
||||||
try:
|
python_object = inspect.unwrap(python_object)
|
||||||
python_object = unwrap(python_object)
|
except ValueError:
|
||||||
except ValueError:
|
# Can return a ValueError when it wraps around
|
||||||
# Can return a ValueError when it wraps around
|
pass
|
||||||
pass
|
|
||||||
|
|
||||||
if (inspect.ismodule(python_object)
|
if (inspect.ismodule(python_object)
|
||||||
or inspect.isclass(python_object)
|
or inspect.isclass(python_object)
|
||||||
|
|||||||
@@ -9,19 +9,14 @@ goals:
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import queue
|
||||||
import subprocess
|
import subprocess
|
||||||
import socket
|
|
||||||
import errno
|
|
||||||
import traceback
|
import traceback
|
||||||
|
import weakref
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
try:
|
|
||||||
from queue import Queue, Empty
|
|
||||||
except ImportError:
|
|
||||||
from Queue import Queue, Empty # python 2.7
|
|
||||||
|
|
||||||
from jedi._compatibility import queue, is_py3, force_unicode, \
|
from jedi._compatibility import pickle_dump, pickle_load
|
||||||
pickle_dump, pickle_load, GeneralizedPopen, weakref
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi.inference.compiled.subprocess import functions
|
from jedi.inference.compiled.subprocess import functions
|
||||||
@@ -31,11 +26,27 @@ from jedi.api.exceptions import InternalError
|
|||||||
|
|
||||||
|
|
||||||
_MAIN_PATH = os.path.join(os.path.dirname(__file__), '__main__.py')
|
_MAIN_PATH = os.path.join(os.path.dirname(__file__), '__main__.py')
|
||||||
|
PICKLE_PROTOCOL = 4
|
||||||
|
|
||||||
|
|
||||||
def _enqueue_output(out, queue):
|
class _GeneralizedPopen(subprocess.Popen):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
if os.name == 'nt':
|
||||||
|
try:
|
||||||
|
# Was introduced in Python 3.7.
|
||||||
|
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW
|
||||||
|
except AttributeError:
|
||||||
|
CREATE_NO_WINDOW = 0x08000000
|
||||||
|
kwargs['creationflags'] = CREATE_NO_WINDOW
|
||||||
|
# The child process doesn't need file descriptors except 0, 1, 2.
|
||||||
|
# This is unix only.
|
||||||
|
kwargs['close_fds'] = 'posix' in sys.builtin_module_names
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def _enqueue_output(out, queue_):
|
||||||
for line in iter(out.readline, b''):
|
for line in iter(out.readline, b''):
|
||||||
queue.put(line)
|
queue_.put(line)
|
||||||
|
|
||||||
|
|
||||||
def _add_stderr_to_debug(stderr_queue):
|
def _add_stderr_to_debug(stderr_queue):
|
||||||
@@ -46,7 +57,7 @@ def _add_stderr_to_debug(stderr_queue):
|
|||||||
line = stderr_queue.get_nowait()
|
line = stderr_queue.get_nowait()
|
||||||
line = line.decode('utf-8', 'replace')
|
line = line.decode('utf-8', 'replace')
|
||||||
debug.warning('stderr output: %s' % line.rstrip('\n'))
|
debug.warning('stderr output: %s' % line.rstrip('\n'))
|
||||||
except Empty:
|
except queue.Empty:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
@@ -105,7 +116,7 @@ class InferenceStateSameProcess(_InferenceStateProcess):
|
|||||||
|
|
||||||
class InferenceStateSubprocess(_InferenceStateProcess):
|
class InferenceStateSubprocess(_InferenceStateProcess):
|
||||||
def __init__(self, inference_state, compiled_subprocess):
|
def __init__(self, inference_state, compiled_subprocess):
|
||||||
super(InferenceStateSubprocess, self).__init__(inference_state)
|
super().__init__(inference_state)
|
||||||
self._used = False
|
self._used = False
|
||||||
self._compiled_subprocess = compiled_subprocess
|
self._compiled_subprocess = compiled_subprocess
|
||||||
|
|
||||||
@@ -153,8 +164,6 @@ class InferenceStateSubprocess(_InferenceStateProcess):
|
|||||||
|
|
||||||
class CompiledSubprocess(object):
|
class CompiledSubprocess(object):
|
||||||
is_crashed = False
|
is_crashed = False
|
||||||
# Start with 2, gets set after _get_info.
|
|
||||||
_pickle_protocol = 2
|
|
||||||
|
|
||||||
def __init__(self, executable, env_vars=None):
|
def __init__(self, executable, env_vars=None):
|
||||||
self._executable = executable
|
self._executable = executable
|
||||||
@@ -164,10 +173,9 @@ class CompiledSubprocess(object):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
pid = os.getpid()
|
pid = os.getpid()
|
||||||
return '<%s _executable=%r, _pickle_protocol=%r, is_crashed=%r, pid=%r>' % (
|
return '<%s _executable=%r, is_crashed=%r, pid=%r>' % (
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
self._executable,
|
self._executable,
|
||||||
self._pickle_protocol,
|
|
||||||
self.is_crashed,
|
self.is_crashed,
|
||||||
pid,
|
pid,
|
||||||
)
|
)
|
||||||
@@ -182,17 +190,14 @@ class CompiledSubprocess(object):
|
|||||||
os.path.dirname(os.path.dirname(parso_path)),
|
os.path.dirname(os.path.dirname(parso_path)),
|
||||||
'.'.join(str(x) for x in sys.version_info[:3]),
|
'.'.join(str(x) for x in sys.version_info[:3]),
|
||||||
)
|
)
|
||||||
process = GeneralizedPopen(
|
process = _GeneralizedPopen(
|
||||||
args,
|
args,
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
# Use system default buffering on Python 2 to improve performance
|
|
||||||
# (this is already the case on Python 3).
|
|
||||||
bufsize=-1,
|
|
||||||
env=self._env_vars
|
env=self._env_vars
|
||||||
)
|
)
|
||||||
self._stderr_queue = Queue()
|
self._stderr_queue = queue.Queue()
|
||||||
self._stderr_thread = t = Thread(
|
self._stderr_thread = t = Thread(
|
||||||
target=_enqueue_output,
|
target=_enqueue_output,
|
||||||
args=(process.stderr, self._stderr_queue)
|
args=(process.stderr, self._stderr_queue)
|
||||||
@@ -231,20 +236,10 @@ class CompiledSubprocess(object):
|
|||||||
if self.is_crashed:
|
if self.is_crashed:
|
||||||
raise InternalError("The subprocess %s has crashed." % self._executable)
|
raise InternalError("The subprocess %s has crashed." % self._executable)
|
||||||
|
|
||||||
if not is_py3:
|
|
||||||
# Python 2 compatibility
|
|
||||||
kwargs = {force_unicode(key): value for key, value in kwargs.items()}
|
|
||||||
|
|
||||||
data = inference_state_id, function, args, kwargs
|
data = inference_state_id, function, args, kwargs
|
||||||
try:
|
try:
|
||||||
pickle_dump(data, self._get_process().stdin, self._pickle_protocol)
|
pickle_dump(data, self._get_process().stdin, PICKLE_PROTOCOL)
|
||||||
except (socket.error, IOError) as e:
|
except BrokenPipeError:
|
||||||
# Once Python2 will be removed we can just use `BrokenPipeError`.
|
|
||||||
# Also, somehow in windows it returns EINVAL instead of EPIPE if
|
|
||||||
# the subprocess dies.
|
|
||||||
if e.errno not in (errno.EPIPE, errno.EINVAL):
|
|
||||||
# Not a broken pipe
|
|
||||||
raise
|
|
||||||
self._kill()
|
self._kill()
|
||||||
raise InternalError("The subprocess %s was killed. Maybe out of memory?"
|
raise InternalError("The subprocess %s was killed. Maybe out of memory?"
|
||||||
% self._executable)
|
% self._executable)
|
||||||
@@ -286,12 +281,11 @@ class CompiledSubprocess(object):
|
|||||||
|
|
||||||
|
|
||||||
class Listener(object):
|
class Listener(object):
|
||||||
def __init__(self, pickle_protocol):
|
def __init__(self):
|
||||||
self._inference_states = {}
|
self._inference_states = {}
|
||||||
# TODO refactor so we don't need to process anymore just handle
|
# TODO refactor so we don't need to process anymore just handle
|
||||||
# controlling.
|
# controlling.
|
||||||
self._process = _InferenceStateProcess(Listener)
|
self._process = _InferenceStateProcess(Listener)
|
||||||
self._pickle_protocol = pickle_protocol
|
|
||||||
|
|
||||||
def _get_inference_state(self, function, inference_state_id):
|
def _get_inference_state(self, function, inference_state_id):
|
||||||
from jedi.inference import InferenceState
|
from jedi.inference import InferenceState
|
||||||
@@ -334,15 +328,8 @@ class Listener(object):
|
|||||||
# because stdout is used for IPC.
|
# because stdout is used for IPC.
|
||||||
sys.stdout = open(os.devnull, 'w')
|
sys.stdout = open(os.devnull, 'w')
|
||||||
stdin = sys.stdin
|
stdin = sys.stdin
|
||||||
if sys.version_info[0] > 2:
|
stdout = stdout.buffer
|
||||||
stdout = stdout.buffer
|
stdin = stdin.buffer
|
||||||
stdin = stdin.buffer
|
|
||||||
# Python 2 opens streams in text mode on Windows. Set stdout and stdin
|
|
||||||
# to binary mode.
|
|
||||||
elif sys.platform == 'win32':
|
|
||||||
import msvcrt
|
|
||||||
msvcrt.setmode(stdout.fileno(), os.O_BINARY)
|
|
||||||
msvcrt.setmode(stdin.fileno(), os.O_BINARY)
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@@ -356,7 +343,7 @@ class Listener(object):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
result = True, traceback.format_exc(), e
|
result = True, traceback.format_exc(), e
|
||||||
|
|
||||||
pickle_dump(result, stdout, self._pickle_protocol)
|
pickle_dump(result, stdout, PICKLE_PROTOCOL)
|
||||||
|
|
||||||
|
|
||||||
class AccessHandle(object):
|
class AccessHandle(object):
|
||||||
@@ -385,9 +372,8 @@ class AccessHandle(object):
|
|||||||
if name in ('id', 'access') or name.startswith('_'):
|
if name in ('id', 'access') or name.startswith('_'):
|
||||||
raise AttributeError("Something went wrong with unpickling")
|
raise AttributeError("Something went wrong with unpickling")
|
||||||
|
|
||||||
# if not is_py3: print >> sys.stderr, name
|
|
||||||
# print('getattr', name, file=sys.stderr)
|
# print('getattr', name, file=sys.stderr)
|
||||||
return partial(self._workaround, force_unicode(name))
|
return partial(self._workaround, name)
|
||||||
|
|
||||||
def _workaround(self, name, *args, **kwargs):
|
def _workaround(self, name, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from importlib.machinery import PathFinder
|
||||||
|
|
||||||
|
# Remove the first entry, because it's simply a directory entry that equals
|
||||||
|
# this directory.
|
||||||
|
del sys.path[0]
|
||||||
|
|
||||||
|
|
||||||
def _get_paths():
|
def _get_paths():
|
||||||
@@ -11,45 +16,24 @@ def _get_paths():
|
|||||||
return {'jedi': _jedi_path, 'parso': _parso_path}
|
return {'jedi': _jedi_path, 'parso': _parso_path}
|
||||||
|
|
||||||
|
|
||||||
# Remove the first entry, because it's simply a directory entry that equals
|
class _ExactImporter(object):
|
||||||
# this directory.
|
def __init__(self, path_dct):
|
||||||
del sys.path[0]
|
self._path_dct = path_dct
|
||||||
|
|
||||||
if sys.version_info > (3, 4):
|
def find_module(self, fullname, path=None):
|
||||||
from importlib.machinery import PathFinder
|
if path is None and fullname in self._path_dct:
|
||||||
|
p = self._path_dct[fullname]
|
||||||
|
loader = PathFinder.find_module(fullname, path=[p])
|
||||||
|
return loader
|
||||||
|
return None
|
||||||
|
|
||||||
class _ExactImporter(object):
|
|
||||||
def __init__(self, path_dct):
|
|
||||||
self._path_dct = path_dct
|
|
||||||
|
|
||||||
def find_module(self, fullname, path=None):
|
|
||||||
if path is None and fullname in self._path_dct:
|
|
||||||
p = self._path_dct[fullname]
|
|
||||||
loader = PathFinder.find_module(fullname, path=[p])
|
|
||||||
return loader
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Try to import jedi/parso.
|
|
||||||
sys.meta_path.insert(0, _ExactImporter(_get_paths()))
|
|
||||||
from jedi.inference.compiled import subprocess # NOQA
|
|
||||||
sys.meta_path.pop(0)
|
|
||||||
else:
|
|
||||||
import imp
|
|
||||||
|
|
||||||
def load(name):
|
|
||||||
paths = list(_get_paths().values())
|
|
||||||
fp, pathname, description = imp.find_module(name, paths)
|
|
||||||
return imp.load_module(name, fp, pathname, description)
|
|
||||||
|
|
||||||
load('parso')
|
|
||||||
load('jedi')
|
|
||||||
from jedi.inference.compiled import subprocess # NOQA
|
|
||||||
|
|
||||||
from jedi._compatibility import highest_pickle_protocol # noqa: E402
|
|
||||||
|
|
||||||
|
# Try to import jedi/parso.
|
||||||
|
sys.meta_path.insert(0, _ExactImporter(_get_paths()))
|
||||||
|
from jedi.inference.compiled import subprocess # noqa: E402
|
||||||
|
sys.meta_path.pop(0)
|
||||||
|
|
||||||
# Retrieve the pickle protocol.
|
# Retrieve the pickle protocol.
|
||||||
host_sys_version = [int(x) for x in sys.argv[2].split('.')]
|
host_sys_version = [int(x) for x in sys.argv[2].split('.')]
|
||||||
pickle_protocol = highest_pickle_protocol([sys.version_info, host_sys_version])
|
|
||||||
# And finally start the client.
|
# And finally start the client.
|
||||||
subprocess.Listener(pickle_protocol=pickle_protocol).listen()
|
subprocess.Listener().listen()
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
from __future__ import print_function
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import inspect
|
import inspect
|
||||||
|
import importlib
|
||||||
|
import warnings
|
||||||
|
from zipimport import zipimporter
|
||||||
|
from importlib.machinery import all_suffixes
|
||||||
|
|
||||||
from jedi._compatibility import find_module, cast_path, force_unicode, \
|
from jedi._compatibility import cast_path
|
||||||
all_suffixes, scandir
|
|
||||||
from jedi.inference.compiled import access
|
from jedi.inference.compiled import access
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import parser_utils
|
from jedi import parser_utils
|
||||||
|
from jedi.file_io import KnownContentFileIO, ZipFileIO
|
||||||
|
|
||||||
|
|
||||||
def get_sys_path():
|
def get_sys_path():
|
||||||
@@ -35,7 +37,7 @@ def get_module_info(inference_state, sys_path=None, full_name=None, **kwargs):
|
|||||||
if sys_path is not None:
|
if sys_path is not None:
|
||||||
sys.path, temp = sys_path, sys.path
|
sys.path, temp = sys_path, sys.path
|
||||||
try:
|
try:
|
||||||
return find_module(full_name=full_name, **kwargs)
|
return _find_module(full_name=full_name, **kwargs)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
return None, None
|
return None, None
|
||||||
finally:
|
finally:
|
||||||
@@ -44,7 +46,7 @@ def get_module_info(inference_state, sys_path=None, full_name=None, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
def get_builtin_module_names(inference_state):
|
def get_builtin_module_names(inference_state):
|
||||||
return list(map(force_unicode, sys.builtin_module_names))
|
return sys.builtin_module_names
|
||||||
|
|
||||||
|
|
||||||
def _test_raise_error(inference_state, exception_type):
|
def _test_raise_error(inference_state, exception_type):
|
||||||
@@ -90,7 +92,7 @@ def _iter_module_names(inference_state, paths):
|
|||||||
# Python modules/packages
|
# Python modules/packages
|
||||||
for path in paths:
|
for path in paths:
|
||||||
try:
|
try:
|
||||||
dirs = scandir(path)
|
dirs = os.scandir(path)
|
||||||
except OSError:
|
except OSError:
|
||||||
# The file might not exist or reading it might lead to an error.
|
# The file might not exist or reading it might lead to an error.
|
||||||
debug.warning("Not possible to list directory: %s", path)
|
debug.warning("Not possible to list directory: %s", path)
|
||||||
@@ -99,10 +101,9 @@ def _iter_module_names(inference_state, paths):
|
|||||||
name = dir_entry.name
|
name = dir_entry.name
|
||||||
# First Namespaces then modules/stubs
|
# First Namespaces then modules/stubs
|
||||||
if dir_entry.is_dir():
|
if dir_entry.is_dir():
|
||||||
# pycache is obviously not an interestin namespace. Also the
|
# pycache is obviously not an interesting namespace. Also the
|
||||||
# name must be a valid identifier.
|
# name must be a valid identifier.
|
||||||
# TODO use str.isidentifier, once Python 2 is removed
|
if name != '__pycache__' and name.isidentifier():
|
||||||
if name != '__pycache__' and not re.search(r'\W|^\d', name):
|
|
||||||
yield name
|
yield name
|
||||||
else:
|
else:
|
||||||
if name.endswith('.pyi'): # Stub files
|
if name.endswith('.pyi'): # Stub files
|
||||||
@@ -113,3 +114,123 @@ def _iter_module_names(inference_state, paths):
|
|||||||
if modname and '.' not in modname:
|
if modname and '.' not in modname:
|
||||||
if modname != '__init__':
|
if modname != '__init__':
|
||||||
yield modname
|
yield modname
|
||||||
|
|
||||||
|
|
||||||
|
def _find_module(string, path=None, full_name=None, is_global_search=True):
|
||||||
|
"""
|
||||||
|
Provides information about a module.
|
||||||
|
|
||||||
|
This function isolates the differences in importing libraries introduced with
|
||||||
|
python 3.3 on; it gets a module name and optionally a path. It will return a
|
||||||
|
tuple containin an open file for the module (if not builtin), the filename
|
||||||
|
or the name of the module if it is a builtin one and a boolean indicating
|
||||||
|
if the module is contained in a package.
|
||||||
|
"""
|
||||||
|
spec = None
|
||||||
|
loader = None
|
||||||
|
|
||||||
|
for finder in sys.meta_path:
|
||||||
|
if is_global_search and finder != importlib.machinery.PathFinder:
|
||||||
|
p = None
|
||||||
|
else:
|
||||||
|
p = path
|
||||||
|
try:
|
||||||
|
find_spec = finder.find_spec
|
||||||
|
except AttributeError:
|
||||||
|
# These are old-school clases that still have a different API, just
|
||||||
|
# ignore those.
|
||||||
|
continue
|
||||||
|
|
||||||
|
spec = find_spec(string, p)
|
||||||
|
if spec is not None:
|
||||||
|
loader = spec.loader
|
||||||
|
if loader is None and not spec.has_location:
|
||||||
|
# This is a namespace package.
|
||||||
|
full_name = string if not path else full_name
|
||||||
|
implicit_ns_info = ImplicitNSInfo(full_name, spec.submodule_search_locations._path)
|
||||||
|
return implicit_ns_info, True
|
||||||
|
break
|
||||||
|
|
||||||
|
return _find_module_py33(string, path, loader)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_module_py33(string, path=None, loader=None, full_name=None, is_global_search=True):
|
||||||
|
loader = loader or importlib.machinery.PathFinder.find_module(string, path)
|
||||||
|
|
||||||
|
if loader is None and path is None: # Fallback to find builtins
|
||||||
|
try:
|
||||||
|
with warnings.catch_warnings(record=True):
|
||||||
|
# Mute "DeprecationWarning: Use importlib.util.find_spec()
|
||||||
|
# instead." While we should replace that in the future, it's
|
||||||
|
# probably good to wait until we deprecate Python 3.3, since
|
||||||
|
# it was added in Python 3.4 and find_loader hasn't been
|
||||||
|
# removed in 3.6.
|
||||||
|
loader = importlib.find_loader(string)
|
||||||
|
except ValueError as e:
|
||||||
|
# See #491. Importlib might raise a ValueError, to avoid this, we
|
||||||
|
# just raise an ImportError to fix the issue.
|
||||||
|
raise ImportError("Originally " + repr(e))
|
||||||
|
|
||||||
|
if loader is None:
|
||||||
|
raise ImportError("Couldn't find a loader for {}".format(string))
|
||||||
|
|
||||||
|
return _from_loader(loader, string)
|
||||||
|
|
||||||
|
|
||||||
|
def _from_loader(loader, string):
|
||||||
|
try:
|
||||||
|
is_package_method = loader.is_package
|
||||||
|
except AttributeError:
|
||||||
|
is_package = False
|
||||||
|
else:
|
||||||
|
is_package = is_package_method(string)
|
||||||
|
try:
|
||||||
|
get_filename = loader.get_filename
|
||||||
|
except AttributeError:
|
||||||
|
return None, is_package
|
||||||
|
else:
|
||||||
|
module_path = cast_path(get_filename(string))
|
||||||
|
|
||||||
|
# To avoid unicode and read bytes, "overwrite" loader.get_source if
|
||||||
|
# possible.
|
||||||
|
try:
|
||||||
|
f = type(loader).get_source
|
||||||
|
except AttributeError:
|
||||||
|
raise ImportError("get_source was not defined on loader")
|
||||||
|
|
||||||
|
if f is not importlib.machinery.SourceFileLoader.get_source:
|
||||||
|
# Unfortunately we are reading unicode here, not bytes.
|
||||||
|
# It seems hard to get bytes, because the zip importer
|
||||||
|
# logic just unpacks the zip file and returns a file descriptor
|
||||||
|
# that we cannot as easily access. Therefore we just read it as
|
||||||
|
# a string in the cases where get_source was overwritten.
|
||||||
|
code = loader.get_source(string)
|
||||||
|
else:
|
||||||
|
code = _get_source(loader, string)
|
||||||
|
|
||||||
|
if code is None:
|
||||||
|
return None, is_package
|
||||||
|
if isinstance(loader, zipimporter):
|
||||||
|
return ZipFileIO(module_path, code, cast_path(loader.archive)), is_package
|
||||||
|
|
||||||
|
return KnownContentFileIO(module_path, code), is_package
|
||||||
|
|
||||||
|
|
||||||
|
def _get_source(loader, fullname):
|
||||||
|
"""
|
||||||
|
This method is here as a replacement for SourceLoader.get_source. That
|
||||||
|
method returns unicode, but we prefer bytes.
|
||||||
|
"""
|
||||||
|
path = loader.get_filename(fullname)
|
||||||
|
try:
|
||||||
|
return loader.get_data(path)
|
||||||
|
except OSError:
|
||||||
|
raise ImportError('source not available through get_data()',
|
||||||
|
name=fullname)
|
||||||
|
|
||||||
|
|
||||||
|
class ImplicitNSInfo(object):
|
||||||
|
"""Stores information returned from an implicit namespace spec"""
|
||||||
|
def __init__(self, name, paths):
|
||||||
|
self.name = name
|
||||||
|
self.paths = paths
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ Imitate the parser representation.
|
|||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from inspect import Parameter
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.utils import to_list
|
from jedi.inference.utils import to_list
|
||||||
from jedi._compatibility import force_unicode, Parameter, cast_path
|
from jedi._compatibility import cast_path
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi.inference.filters import AbstractFilter
|
from jedi.inference.filters import AbstractFilter
|
||||||
from jedi.inference.names import AbstractNameDefinition, ValueNameMixin, \
|
from jedi.inference.names import AbstractNameDefinition, ValueNameMixin, \
|
||||||
@@ -29,7 +31,7 @@ class CheckAttribute(object):
|
|||||||
def __call__(self, func):
|
def __call__(self, func):
|
||||||
self.func = func
|
self.func = func
|
||||||
if self.check_name is None:
|
if self.check_name is None:
|
||||||
self.check_name = force_unicode(func.__name__[2:])
|
self.check_name = func.__name__[2:]
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __get__(self, instance, owner):
|
def __get__(self, instance, owner):
|
||||||
@@ -43,7 +45,7 @@ class CheckAttribute(object):
|
|||||||
|
|
||||||
class CompiledValue(Value):
|
class CompiledValue(Value):
|
||||||
def __init__(self, inference_state, access_handle, parent_context=None):
|
def __init__(self, inference_state, access_handle, parent_context=None):
|
||||||
super(CompiledValue, self).__init__(inference_state, parent_context)
|
super().__init__(inference_state, parent_context)
|
||||||
self.access_handle = access_handle
|
self.access_handle = access_handle
|
||||||
|
|
||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
@@ -56,9 +58,9 @@ class CompiledValue(Value):
|
|||||||
).execute_annotation()
|
).execute_annotation()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.access_handle.getattr_paths(u'__call__')
|
self.access_handle.getattr_paths('__call__')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return super(CompiledValue, self).py__call__(arguments)
|
return super().py__call__(arguments)
|
||||||
else:
|
else:
|
||||||
if self.access_handle.is_class():
|
if self.access_handle.is_class():
|
||||||
from jedi.inference.value import CompiledInstance
|
from jedi.inference.value import CompiledInstance
|
||||||
@@ -163,7 +165,7 @@ class CompiledValue(Value):
|
|||||||
try:
|
try:
|
||||||
access = self.access_handle.py__simple_getitem__(index)
|
access = self.access_handle.py__simple_getitem__(index)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return super(CompiledValue, self).py__simple_getitem__(index)
|
return super().py__simple_getitem__(index)
|
||||||
if access is None:
|
if access is None:
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
|
|
||||||
@@ -174,19 +176,15 @@ class CompiledValue(Value):
|
|||||||
if all_access_paths is None:
|
if all_access_paths is None:
|
||||||
# This means basically that no __getitem__ has been defined on this
|
# This means basically that no __getitem__ has been defined on this
|
||||||
# object.
|
# object.
|
||||||
return super(CompiledValue, self).py__getitem__(index_value_set, contextualized_node)
|
return super().py__getitem__(index_value_set, contextualized_node)
|
||||||
return ValueSet(
|
return ValueSet(
|
||||||
create_from_access_path(self.inference_state, access)
|
create_from_access_path(self.inference_state, access)
|
||||||
for access in all_access_paths
|
for access in all_access_paths
|
||||||
)
|
)
|
||||||
|
|
||||||
def py__iter__(self, contextualized_node=None):
|
def py__iter__(self, contextualized_node=None):
|
||||||
# Python iterators are a bit strange, because there's no need for
|
|
||||||
# the __iter__ function as long as __getitem__ is defined (it will
|
|
||||||
# just start with __getitem__(0). This is especially true for
|
|
||||||
# Python 2 strings, where `str.__iter__` is not even defined.
|
|
||||||
if not self.access_handle.has_iter():
|
if not self.access_handle.has_iter():
|
||||||
for x in super(CompiledValue, self).py__iter__(contextualized_node):
|
for x in super().py__iter__(contextualized_node):
|
||||||
yield x
|
yield x
|
||||||
|
|
||||||
access_path_list = self.access_handle.py__iter__list()
|
access_path_list = self.access_handle.py__iter__list()
|
||||||
@@ -264,7 +262,7 @@ class CompiledValue(Value):
|
|||||||
v.with_generics(arguments)
|
v.with_generics(arguments)
|
||||||
for v in self.inference_state.typing_module.py__getattribute__(name)
|
for v in self.inference_state.typing_module.py__getattribute__(name)
|
||||||
]).execute_annotation()
|
]).execute_annotation()
|
||||||
return super(CompiledValue, self).execute_annotation()
|
return super().execute_annotation()
|
||||||
|
|
||||||
def negate(self):
|
def negate(self):
|
||||||
return create_from_access_path(self.inference_state, self.access_handle.negate())
|
return create_from_access_path(self.inference_state, self.access_handle.negate())
|
||||||
@@ -315,7 +313,10 @@ class CompiledModule(CompiledValue):
|
|||||||
return tuple(name.split('.'))
|
return tuple(name.split('.'))
|
||||||
|
|
||||||
def py__file__(self):
|
def py__file__(self):
|
||||||
return cast_path(self.access_handle.py__file__())
|
path = cast_path(self.access_handle.py__file__())
|
||||||
|
if path is None:
|
||||||
|
return None
|
||||||
|
return Path(path)
|
||||||
|
|
||||||
|
|
||||||
class CompiledName(AbstractNameDefinition):
|
class CompiledName(AbstractNameDefinition):
|
||||||
@@ -456,9 +457,6 @@ class CompiledValueFilter(AbstractFilter):
|
|||||||
"""
|
"""
|
||||||
To remove quite a few access calls we introduced the callback here.
|
To remove quite a few access calls we introduced the callback here.
|
||||||
"""
|
"""
|
||||||
# Always use unicode objects in Python 2 from here.
|
|
||||||
name = force_unicode(name)
|
|
||||||
|
|
||||||
if self._inference_state.allow_descriptor_getattr:
|
if self._inference_state.allow_descriptor_getattr:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -502,7 +500,7 @@ class CompiledValueFilter(AbstractFilter):
|
|||||||
|
|
||||||
# ``dir`` doesn't include the type names.
|
# ``dir`` doesn't include the type names.
|
||||||
if not self.is_instance and needs_type_completions:
|
if not self.is_instance and needs_type_completions:
|
||||||
for filter in builtin_from_name(self._inference_state, u'type').get_filters():
|
for filter in builtin_from_name(self._inference_state, 'type').get_filters():
|
||||||
names += filter.values()
|
names += filter.values()
|
||||||
return names
|
return names
|
||||||
|
|
||||||
@@ -518,11 +516,11 @@ class CompiledValueFilter(AbstractFilter):
|
|||||||
|
|
||||||
|
|
||||||
docstr_defaults = {
|
docstr_defaults = {
|
||||||
'floating point number': u'float',
|
'floating point number': 'float',
|
||||||
'character': u'str',
|
'character': 'str',
|
||||||
'integer': u'int',
|
'integer': 'int',
|
||||||
'dictionary': u'dict',
|
'dictionary': 'dict',
|
||||||
'string': u'str',
|
'string': 'str',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -534,7 +532,6 @@ def _parse_function_doc(doc):
|
|||||||
TODO docstrings like utime(path, (atime, mtime)) and a(b [, b]) -> None
|
TODO docstrings like utime(path, (atime, mtime)) and a(b [, b]) -> None
|
||||||
TODO docstrings like 'tuple of integers'
|
TODO docstrings like 'tuple of integers'
|
||||||
"""
|
"""
|
||||||
doc = force_unicode(doc)
|
|
||||||
# parse round parentheses: def func(a, (b,c))
|
# parse round parentheses: def func(a, (b,c))
|
||||||
try:
|
try:
|
||||||
count = 0
|
count = 0
|
||||||
@@ -553,7 +550,7 @@ def _parse_function_doc(doc):
|
|||||||
# UnboundLocalError for undefined end in last line
|
# UnboundLocalError for undefined end in last line
|
||||||
debug.dbg('no brackets found - no param')
|
debug.dbg('no brackets found - no param')
|
||||||
end = 0
|
end = 0
|
||||||
param_str = u''
|
param_str = ''
|
||||||
else:
|
else:
|
||||||
# remove square brackets, that show an optional param ( = None)
|
# remove square brackets, that show an optional param ( = None)
|
||||||
def change_options(m):
|
def change_options(m):
|
||||||
@@ -571,9 +568,9 @@ def _parse_function_doc(doc):
|
|||||||
param_str = param_str.replace('-', '_') # see: isinstance.__doc__
|
param_str = param_str.replace('-', '_') # see: isinstance.__doc__
|
||||||
|
|
||||||
# parse return value
|
# parse return value
|
||||||
r = re.search(u'-[>-]* ', doc[end:end + 7])
|
r = re.search('-[>-]* ', doc[end:end + 7])
|
||||||
if r is None:
|
if r is None:
|
||||||
ret = u''
|
ret = ''
|
||||||
else:
|
else:
|
||||||
index = end + r.end()
|
index = end + r.end()
|
||||||
# get result type, which can contain newlines
|
# get result type, which can contain newlines
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class ValueContext(AbstractContext):
|
|||||||
Should be defined, otherwise the API returns empty types.
|
Should be defined, otherwise the API returns empty types.
|
||||||
"""
|
"""
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
super(ValueContext, self).__init__(value.inference_state)
|
super().__init__(value.inference_state)
|
||||||
self._value = value
|
self._value = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -323,8 +323,7 @@ class ModuleContext(TreeContextMixin, ValueContext):
|
|||||||
),
|
),
|
||||||
self.get_global_filter(),
|
self.get_global_filter(),
|
||||||
)
|
)
|
||||||
for f in filters: # Python 2...
|
yield from filters
|
||||||
yield f
|
|
||||||
|
|
||||||
def get_global_filter(self):
|
def get_global_filter(self):
|
||||||
return GlobalNameFilter(self, self.tree_node)
|
return GlobalNameFilter(self, self.tree_node)
|
||||||
@@ -375,7 +374,7 @@ class ClassContext(TreeContextMixin, ValueContext):
|
|||||||
|
|
||||||
class CompForContext(TreeContextMixin, AbstractContext):
|
class CompForContext(TreeContextMixin, AbstractContext):
|
||||||
def __init__(self, parent_context, comp_for):
|
def __init__(self, parent_context, comp_for):
|
||||||
super(CompForContext, self).__init__(parent_context.inference_state)
|
super().__init__(parent_context.inference_state)
|
||||||
self.tree_node = comp_for
|
self.tree_node = comp_for
|
||||||
self.parent_context = parent_context
|
self.parent_context = parent_context
|
||||||
|
|
||||||
@@ -439,13 +438,12 @@ def get_global_filters(context, until_position, origin_scope):
|
|||||||
For global name lookups. The filters will handle name resolution
|
For global name lookups. The filters will handle name resolution
|
||||||
themselves, but here we gather possible filters downwards.
|
themselves, but here we gather possible filters downwards.
|
||||||
|
|
||||||
>>> from jedi._compatibility import u, no_unicode_pprint
|
|
||||||
>>> from jedi import Script
|
>>> from jedi import Script
|
||||||
>>> script = Script(u('''
|
>>> script = Script('''
|
||||||
... x = ['a', 'b', 'c']
|
... x = ['a', 'b', 'c']
|
||||||
... def func():
|
... def func():
|
||||||
... y = None
|
... y = None
|
||||||
... '''))
|
... ''')
|
||||||
>>> module_node = script._module_node
|
>>> module_node = script._module_node
|
||||||
>>> scope = next(module_node.iter_funcdefs())
|
>>> scope = next(module_node.iter_funcdefs())
|
||||||
>>> scope
|
>>> scope
|
||||||
@@ -455,7 +453,7 @@ def get_global_filters(context, until_position, origin_scope):
|
|||||||
|
|
||||||
First we get the names from the function scope.
|
First we get the names from the function scope.
|
||||||
|
|
||||||
>>> no_unicode_pprint(filters[0]) # doctest: +ELLIPSIS
|
>>> print(filters[0]) # doctest: +ELLIPSIS
|
||||||
MergedFilter(<ParserTreeFilter: ...>, <GlobalNameFilter: ...>)
|
MergedFilter(<ParserTreeFilter: ...>, <GlobalNameFilter: ...>)
|
||||||
>>> sorted(str(n) for n in filters[0].values()) # doctest: +NORMALIZE_WHITESPACE
|
>>> sorted(str(n) for n in filters[0].values()) # doctest: +NORMALIZE_WHITESPACE
|
||||||
['<TreeNameDefinition: string_name=func start_pos=(3, 4)>',
|
['<TreeNameDefinition: string_name=func start_pos=(3, 4)>',
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ from textwrap import dedent
|
|||||||
|
|
||||||
from parso import parse, ParserSyntaxError
|
from parso import parse, ParserSyntaxError
|
||||||
|
|
||||||
from jedi._compatibility import u
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.common import indent_block
|
from jedi.common import indent_block
|
||||||
from jedi.inference.cache import inference_state_method_cache
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
@@ -184,7 +183,7 @@ def _strip_rst_role(type_str):
|
|||||||
|
|
||||||
|
|
||||||
def _infer_for_statement_string(module_context, string):
|
def _infer_for_statement_string(module_context, string):
|
||||||
code = dedent(u("""
|
code = dedent("""
|
||||||
def pseudo_docstring_stuff():
|
def pseudo_docstring_stuff():
|
||||||
'''
|
'''
|
||||||
Create a pseudo function for docstring statements.
|
Create a pseudo function for docstring statements.
|
||||||
@@ -192,7 +191,7 @@ def _infer_for_statement_string(module_context, string):
|
|||||||
is still a function.
|
is still a function.
|
||||||
'''
|
'''
|
||||||
{}
|
{}
|
||||||
"""))
|
""")
|
||||||
if string is None:
|
if string is None:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -201,11 +200,8 @@ def _infer_for_statement_string(module_context, string):
|
|||||||
# (e.g., 'threading' in 'threading.Thread').
|
# (e.g., 'threading' in 'threading.Thread').
|
||||||
string = 'import %s\n' % element + string
|
string = 'import %s\n' % element + string
|
||||||
|
|
||||||
# Take the default grammar here, if we load the Python 2.7 grammar here, it
|
|
||||||
# will be impossible to use `...` (Ellipsis) as a token. Docstring types
|
|
||||||
# don't need to conform with the current grammar.
|
|
||||||
debug.dbg('Parse docstring code %s', string, color='BLUE')
|
debug.dbg('Parse docstring code %s', string, color='BLUE')
|
||||||
grammar = module_context.inference_state.latest_grammar
|
grammar = module_context.inference_state.grammar
|
||||||
try:
|
try:
|
||||||
module = grammar.parse(code.format(indent_block(string)), error_recovery=False)
|
module = grammar.parse(code.format(indent_block(string)), error_recovery=False)
|
||||||
except ParserSyntaxError:
|
except ParserSyntaxError:
|
||||||
|
|||||||
+18
-24
@@ -7,7 +7,6 @@ import weakref
|
|||||||
|
|
||||||
from parso.tree import search_ancestor
|
from parso.tree import search_ancestor
|
||||||
|
|
||||||
from jedi._compatibility import use_metaclass
|
|
||||||
from jedi.inference import flow_analysis
|
from jedi.inference import flow_analysis
|
||||||
from jedi.inference.base_value import ValueSet, ValueWrapper, \
|
from jedi.inference.base_value import ValueSet, ValueWrapper, \
|
||||||
LazyValueWrapper
|
LazyValueWrapper
|
||||||
@@ -109,13 +108,13 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
|
|||||||
"""
|
"""
|
||||||
if node_context is None:
|
if node_context is None:
|
||||||
node_context = parent_context
|
node_context = parent_context
|
||||||
super(ParserTreeFilter, self).__init__(parent_context, node_context.tree_node)
|
super().__init__(parent_context, node_context.tree_node)
|
||||||
self._node_context = node_context
|
self._node_context = node_context
|
||||||
self._origin_scope = origin_scope
|
self._origin_scope = origin_scope
|
||||||
self._until_position = until_position
|
self._until_position = until_position
|
||||||
|
|
||||||
def _filter(self, names):
|
def _filter(self, names):
|
||||||
names = super(ParserTreeFilter, self)._filter(names)
|
names = super()._filter(names)
|
||||||
names = [n for n in names if self._is_name_reachable(n)]
|
names = [n for n in names if self._is_name_reachable(n)]
|
||||||
return list(self._check_flows(names))
|
return list(self._check_flows(names))
|
||||||
|
|
||||||
@@ -143,7 +142,7 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
|
|||||||
|
|
||||||
class _FunctionExecutionFilter(ParserTreeFilter):
|
class _FunctionExecutionFilter(ParserTreeFilter):
|
||||||
def __init__(self, parent_context, function_value, until_position, origin_scope):
|
def __init__(self, parent_context, function_value, until_position, origin_scope):
|
||||||
super(_FunctionExecutionFilter, self).__init__(
|
super().__init__(
|
||||||
parent_context,
|
parent_context,
|
||||||
until_position=until_position,
|
until_position=until_position,
|
||||||
origin_scope=origin_scope,
|
origin_scope=origin_scope,
|
||||||
@@ -167,9 +166,9 @@ class _FunctionExecutionFilter(ParserTreeFilter):
|
|||||||
|
|
||||||
|
|
||||||
class FunctionExecutionFilter(_FunctionExecutionFilter):
|
class FunctionExecutionFilter(_FunctionExecutionFilter):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, arguments, **kwargs):
|
||||||
self._arguments = kwargs.pop('arguments') # Python 2
|
super().__init__(*args, **kwargs)
|
||||||
super(FunctionExecutionFilter, self).__init__(*args, **kwargs)
|
self._arguments = arguments
|
||||||
|
|
||||||
def _convert_param(self, param, name):
|
def _convert_param(self, param, name):
|
||||||
return ParamName(self._function_value, name, self._arguments)
|
return ParamName(self._function_value, name, self._arguments)
|
||||||
@@ -246,10 +245,10 @@ class MergedFilter(object):
|
|||||||
|
|
||||||
class _BuiltinMappedMethod(ValueWrapper):
|
class _BuiltinMappedMethod(ValueWrapper):
|
||||||
"""``Generator.__next__`` ``dict.values`` methods and so on."""
|
"""``Generator.__next__`` ``dict.values`` methods and so on."""
|
||||||
api_type = u'function'
|
api_type = 'function'
|
||||||
|
|
||||||
def __init__(self, value, method, builtin_func):
|
def __init__(self, value, method, builtin_func):
|
||||||
super(_BuiltinMappedMethod, self).__init__(builtin_func)
|
super().__init__(builtin_func)
|
||||||
self._value = value
|
self._value = value
|
||||||
self._method = method
|
self._method = method
|
||||||
|
|
||||||
@@ -264,14 +263,9 @@ class SpecialMethodFilter(DictFilter):
|
|||||||
classes like Generator (for __next__, etc).
|
classes like Generator (for __next__, etc).
|
||||||
"""
|
"""
|
||||||
class SpecialMethodName(AbstractNameDefinition):
|
class SpecialMethodName(AbstractNameDefinition):
|
||||||
api_type = u'function'
|
api_type = 'function'
|
||||||
|
|
||||||
def __init__(self, parent_context, string_name, value, builtin_value):
|
|
||||||
callable_, python_version = value
|
|
||||||
if python_version is not None and \
|
|
||||||
python_version != parent_context.inference_state.environment.version_info.major:
|
|
||||||
raise KeyError
|
|
||||||
|
|
||||||
|
def __init__(self, parent_context, string_name, callable_, builtin_value):
|
||||||
self.parent_context = parent_context
|
self.parent_context = parent_context
|
||||||
self.string_name = string_name
|
self.string_name = string_name
|
||||||
self._callable = callable_
|
self._callable = callable_
|
||||||
@@ -293,7 +287,7 @@ class SpecialMethodFilter(DictFilter):
|
|||||||
])
|
])
|
||||||
|
|
||||||
def __init__(self, value, dct, builtin_value):
|
def __init__(self, value, dct, builtin_value):
|
||||||
super(SpecialMethodFilter, self).__init__(dct)
|
super().__init__(dct)
|
||||||
self.value = value
|
self.value = value
|
||||||
self._builtin_value = builtin_value
|
self._builtin_value = builtin_value
|
||||||
"""
|
"""
|
||||||
@@ -309,7 +303,7 @@ class SpecialMethodFilter(DictFilter):
|
|||||||
|
|
||||||
class _OverwriteMeta(type):
|
class _OverwriteMeta(type):
|
||||||
def __init__(cls, name, bases, dct):
|
def __init__(cls, name, bases, dct):
|
||||||
super(_OverwriteMeta, cls).__init__(name, bases, dct)
|
super().__init__(name, bases, dct)
|
||||||
|
|
||||||
base_dct = {}
|
base_dct = {}
|
||||||
for base_cls in reversed(cls.__bases__):
|
for base_cls in reversed(cls.__bases__):
|
||||||
@@ -334,20 +328,20 @@ class _AttributeOverwriteMixin(object):
|
|||||||
yield filter
|
yield filter
|
||||||
|
|
||||||
|
|
||||||
class LazyAttributeOverwrite(use_metaclass(_OverwriteMeta, _AttributeOverwriteMixin,
|
class LazyAttributeOverwrite(_AttributeOverwriteMixin, LazyValueWrapper,
|
||||||
LazyValueWrapper)):
|
metaclass=_OverwriteMeta):
|
||||||
def __init__(self, inference_state):
|
def __init__(self, inference_state):
|
||||||
self.inference_state = inference_state
|
self.inference_state = inference_state
|
||||||
|
|
||||||
|
|
||||||
class AttributeOverwrite(use_metaclass(_OverwriteMeta, _AttributeOverwriteMixin,
|
class AttributeOverwrite(_AttributeOverwriteMixin, ValueWrapper,
|
||||||
ValueWrapper)):
|
metaclass=_OverwriteMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def publish_method(method_name, python_version_match=None):
|
def publish_method(method_name):
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
dct = func.__dict__.setdefault('registered_overwritten_methods', {})
|
dct = func.__dict__.setdefault('registered_overwritten_methods', {})
|
||||||
dct[method_name] = func, python_version_match
|
dct[method_name] = func
|
||||||
return func
|
return func
|
||||||
return decorator
|
return decorator
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ as annotations in future python versions.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from inspect import Parameter
|
||||||
|
|
||||||
from parso import ParserSyntaxError, parse
|
from parso import ParserSyntaxError, parse
|
||||||
|
|
||||||
from jedi._compatibility import force_unicode, Parameter
|
|
||||||
from jedi.inference.cache import inference_state_method_cache
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.inference.gradual.base import DefineGenericBaseClass, GenericClass
|
from jedi.inference.gradual.base import DefineGenericBaseClass, GenericClass
|
||||||
@@ -53,7 +53,7 @@ def _infer_annotation_string(context, string, index=None):
|
|||||||
value_set = context.infer_node(node)
|
value_set = context.infer_node(node)
|
||||||
if index is not None:
|
if index is not None:
|
||||||
value_set = value_set.filter(
|
value_set = value_set.filter(
|
||||||
lambda value: value.array_type == u'tuple' # noqa
|
lambda value: value.array_type == 'tuple' # noqa
|
||||||
and len(list(value.py__iter__())) >= index
|
and len(list(value.py__iter__())) >= index
|
||||||
).py__simple_getitem__(index)
|
).py__simple_getitem__(index)
|
||||||
return value_set
|
return value_set
|
||||||
@@ -62,7 +62,7 @@ def _infer_annotation_string(context, string, index=None):
|
|||||||
def _get_forward_reference_node(context, string):
|
def _get_forward_reference_node(context, string):
|
||||||
try:
|
try:
|
||||||
new_node = context.inference_state.grammar.parse(
|
new_node = context.inference_state.grammar.parse(
|
||||||
force_unicode(string),
|
string,
|
||||||
start_symbol='eval_input',
|
start_symbol='eval_input',
|
||||||
error_recovery=False
|
error_recovery=False
|
||||||
)
|
)
|
||||||
@@ -138,8 +138,7 @@ def _infer_param(function_value, param):
|
|||||||
"""
|
"""
|
||||||
annotation = param.annotation
|
annotation = param.annotation
|
||||||
if annotation is None:
|
if annotation is None:
|
||||||
# If no Python 3-style annotation, look for a Python 2-style comment
|
# If no Python 3-style annotation, look for a comment annotation.
|
||||||
# annotation.
|
|
||||||
# Identify parameters to function in the same sequence as they would
|
# Identify parameters to function in the same sequence as they would
|
||||||
# appear in a type comment.
|
# appear in a type comment.
|
||||||
all_params = [child for child in param.parent.children
|
all_params = [child for child in param.parent.children
|
||||||
@@ -204,7 +203,8 @@ def infer_return_types(function, arguments):
|
|||||||
all_annotations = py__annotations__(function.tree_node)
|
all_annotations = py__annotations__(function.tree_node)
|
||||||
annotation = all_annotations.get("return", None)
|
annotation = all_annotations.get("return", None)
|
||||||
if annotation is None:
|
if annotation is None:
|
||||||
# If there is no Python 3-type annotation, look for a Python 2-type annotation
|
# If there is no Python 3-type annotation, look for an annotation
|
||||||
|
# comment.
|
||||||
node = function.tree_node
|
node = function.tree_node
|
||||||
comment = parser_utils.get_following_comment_same_line(node)
|
comment = parser_utils.get_following_comment_same_line(node)
|
||||||
if comment is None:
|
if comment is None:
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class _TypeVarFilter(object):
|
|||||||
|
|
||||||
class _AnnotatedClassContext(ClassContext):
|
class _AnnotatedClassContext(ClassContext):
|
||||||
def get_filters(self, *args, **kwargs):
|
def get_filters(self, *args, **kwargs):
|
||||||
filters = super(_AnnotatedClassContext, self).get_filters(
|
filters = super().get_filters(
|
||||||
*args, **kwargs
|
*args, **kwargs
|
||||||
)
|
)
|
||||||
for f in filters:
|
for f in filters:
|
||||||
@@ -164,7 +164,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
|||||||
my_foo_int_cls = Foo[int]
|
my_foo_int_cls = Foo[int]
|
||||||
"""
|
"""
|
||||||
def __init__(self, class_value, generics_manager):
|
def __init__(self, class_value, generics_manager):
|
||||||
super(GenericClass, self).__init__(generics_manager)
|
super().__init__(generics_manager)
|
||||||
self._class_value = class_value
|
self._class_value = class_value
|
||||||
|
|
||||||
def _get_wrapped_value(self):
|
def _get_wrapped_value(self):
|
||||||
@@ -186,7 +186,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
|||||||
return _TypeVarFilter(self.get_generics(), self.list_type_vars())
|
return _TypeVarFilter(self.get_generics(), self.list_type_vars())
|
||||||
|
|
||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
instance, = super(GenericClass, self).py__call__(arguments)
|
instance, = super().py__call__(arguments)
|
||||||
return ValueSet([_GenericInstanceWrapper(instance)])
|
return ValueSet([_GenericInstanceWrapper(instance)])
|
||||||
|
|
||||||
def _as_context(self):
|
def _as_context(self):
|
||||||
@@ -201,7 +201,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
|||||||
return GenericClass(self._class_value, generics_manager)
|
return GenericClass(self._class_value, generics_manager)
|
||||||
|
|
||||||
def is_sub_class_of(self, class_value):
|
def is_sub_class_of(self, class_value):
|
||||||
if super(GenericClass, self).is_sub_class_of(class_value):
|
if super().is_sub_class_of(class_value):
|
||||||
return True
|
return True
|
||||||
return self._class_value.is_sub_class_of(class_value)
|
return self._class_value.is_sub_class_of(class_value)
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
|||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if py_class.api_type != u'class':
|
if py_class.api_type != 'class':
|
||||||
# Functions & modules don't have an MRO and we're not
|
# Functions & modules don't have an MRO and we're not
|
||||||
# expecting a Callable (those are handled separately within
|
# expecting a Callable (those are handled separately within
|
||||||
# TypingClassValueWithIndex).
|
# TypingClassValueWithIndex).
|
||||||
@@ -309,7 +309,7 @@ class _GenericInstanceWrapper(ValueWrapper):
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
elif cls.py__name__() == 'Iterator':
|
elif cls.py__name__() == 'Iterator':
|
||||||
return ValueSet([builtin_from_name(self.inference_state, u'None')])
|
return ValueSet([builtin_from_name(self.inference_state, 'None')])
|
||||||
return self._wrapped_value.py__stop_iteration_returns()
|
return self._wrapped_value.py__stop_iteration_returns()
|
||||||
|
|
||||||
def get_type_hint(self, add_class_info=True):
|
def get_type_hint(self, add_class_info=True):
|
||||||
@@ -326,10 +326,10 @@ class _PseudoTreeNameClass(Value):
|
|||||||
this class. Essentially this class makes it possible to goto that `Tuple`
|
this class. Essentially this class makes it possible to goto that `Tuple`
|
||||||
name, without affecting anything else negatively.
|
name, without affecting anything else negatively.
|
||||||
"""
|
"""
|
||||||
api_type = u'class'
|
api_type = 'class'
|
||||||
|
|
||||||
def __init__(self, parent_context, tree_name):
|
def __init__(self, parent_context, tree_name):
|
||||||
super(_PseudoTreeNameClass, self).__init__(
|
super().__init__(
|
||||||
parent_context.inference_state,
|
parent_context.inference_state,
|
||||||
parent_context
|
parent_context
|
||||||
)
|
)
|
||||||
@@ -356,7 +356,7 @@ class _PseudoTreeNameClass(Value):
|
|||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
# This might not be 100% correct, but it is good enough. The details of
|
# This might not be 100% correct, but it is good enough. The details of
|
||||||
# the typing library are not really an issue for Jedi.
|
# the typing library are not really an issue for Jedi.
|
||||||
return builtin_from_name(self.inference_state, u'type')
|
return builtin_from_name(self.inference_state, 'type')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -388,7 +388,7 @@ class BaseTypingValue(LazyValueWrapper):
|
|||||||
|
|
||||||
class BaseTypingClassWithGenerics(DefineGenericBaseClass):
|
class BaseTypingClassWithGenerics(DefineGenericBaseClass):
|
||||||
def __init__(self, parent_context, tree_name, generics_manager):
|
def __init__(self, parent_context, tree_name, generics_manager):
|
||||||
super(BaseTypingClassWithGenerics, self).__init__(generics_manager)
|
super().__init__(generics_manager)
|
||||||
self.inference_state = parent_context.inference_state
|
self.inference_state = parent_context.inference_state
|
||||||
self.parent_context = parent_context
|
self.parent_context = parent_context
|
||||||
self._tree_name = tree_name
|
self._tree_name = tree_name
|
||||||
@@ -423,7 +423,7 @@ class BaseTypingInstance(LazyValueWrapper):
|
|||||||
return ValueName(self, self._tree_name)
|
return ValueName(self, self._tree_name)
|
||||||
|
|
||||||
def _get_wrapped_value(self):
|
def _get_wrapped_value(self):
|
||||||
object_, = builtin_from_name(self.inference_state, u'object').execute_annotation()
|
object_, = builtin_from_name(self.inference_state, 'object').execute_annotation()
|
||||||
return object_
|
return object_
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class StubModuleValue(ModuleValue):
|
|||||||
_module_name_class = StubModuleName
|
_module_name_class = StubModuleName
|
||||||
|
|
||||||
def __init__(self, non_stub_value_set, *args, **kwargs):
|
def __init__(self, non_stub_value_set, *args, **kwargs):
|
||||||
super(StubModuleValue, self).__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.non_stub_value_set = non_stub_value_set
|
self.non_stub_value_set = non_stub_value_set
|
||||||
|
|
||||||
def is_stub(self):
|
def is_stub(self):
|
||||||
@@ -30,7 +30,7 @@ class StubModuleValue(ModuleValue):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
names.update(method())
|
names.update(method())
|
||||||
names.update(super(StubModuleValue, self).sub_modules_dict())
|
names.update(super().sub_modules_dict())
|
||||||
return names
|
return names
|
||||||
|
|
||||||
def _get_stub_filters(self, origin_scope):
|
def _get_stub_filters(self, origin_scope):
|
||||||
@@ -40,7 +40,7 @@ class StubModuleValue(ModuleValue):
|
|||||||
)] + list(self.iter_star_filters())
|
)] + list(self.iter_star_filters())
|
||||||
|
|
||||||
def get_filters(self, origin_scope=None):
|
def get_filters(self, origin_scope=None):
|
||||||
filters = super(StubModuleValue, self).get_filters(origin_scope)
|
filters = super().get_filters(origin_scope)
|
||||||
next(filters, None) # Ignore the first filter and replace it with our own
|
next(filters, None) # Ignore the first filter and replace it with our own
|
||||||
stub_filters = self._get_stub_filters(origin_scope=origin_scope)
|
stub_filters = self._get_stub_filters(origin_scope=origin_scope)
|
||||||
for f in stub_filters:
|
for f in stub_filters:
|
||||||
@@ -57,12 +57,12 @@ class StubModuleContext(ModuleContext):
|
|||||||
def get_filters(self, until_position=None, origin_scope=None):
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
# Make sure to ignore the position, because positions are not relevant
|
# Make sure to ignore the position, because positions are not relevant
|
||||||
# for stubs.
|
# for stubs.
|
||||||
return super(StubModuleContext, self).get_filters(origin_scope=origin_scope)
|
return super().get_filters(origin_scope=origin_scope)
|
||||||
|
|
||||||
|
|
||||||
class TypingModuleWrapper(StubModuleValue):
|
class TypingModuleWrapper(StubModuleValue):
|
||||||
def get_filters(self, *args, **kwargs):
|
def get_filters(self, *args, **kwargs):
|
||||||
filters = super(TypingModuleWrapper, self).get_filters(*args, **kwargs)
|
filters = super().get_filters(*args, **kwargs)
|
||||||
f = next(filters, None)
|
f = next(filters, None)
|
||||||
assert f is not None
|
assert f is not None
|
||||||
yield TypingModuleFilterWrapper(f)
|
yield TypingModuleFilterWrapper(f)
|
||||||
@@ -75,7 +75,7 @@ class TypingModuleWrapper(StubModuleValue):
|
|||||||
|
|
||||||
class TypingModuleContext(ModuleContext):
|
class TypingModuleContext(ModuleContext):
|
||||||
def get_filters(self, *args, **kwargs):
|
def get_filters(self, *args, **kwargs):
|
||||||
filters = super(TypingModuleContext, self).get_filters(*args, **kwargs)
|
filters = super().get_filters(*args, **kwargs)
|
||||||
yield TypingModuleFilterWrapper(next(filters, None))
|
yield TypingModuleFilterWrapper(next(filters, None))
|
||||||
for f in filters:
|
for f in filters:
|
||||||
yield f
|
yield f
|
||||||
@@ -85,7 +85,7 @@ class StubFilter(ParserTreeFilter):
|
|||||||
name_class = StubName
|
name_class = StubName
|
||||||
|
|
||||||
def _is_name_reachable(self, name):
|
def _is_name_reachable(self, name):
|
||||||
if not super(StubFilter, self)._is_name_reachable(name):
|
if not super()._is_name_reachable(name):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Imports in stub files are only public if they have an "as"
|
# Imports in stub files are only public if they have an "as"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from jedi._compatibility import unicode, force_unicode
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES, ValueWrapper
|
from jedi.inference.base_value import ValueSet, NO_VALUES, ValueWrapper
|
||||||
from jedi.inference.gradual.base import BaseTypingValue
|
from jedi.inference.gradual.base import BaseTypingValue
|
||||||
@@ -40,17 +39,14 @@ class TypeVarClass(BaseTypingValue):
|
|||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
safe_value = method(default=None)
|
safe_value = method(default=None)
|
||||||
if self.inference_state.environment.version_info.major == 2:
|
if isinstance(safe_value, str):
|
||||||
if isinstance(safe_value, bytes):
|
|
||||||
return force_unicode(safe_value)
|
|
||||||
if isinstance(safe_value, (str, unicode)):
|
|
||||||
return safe_value
|
return safe_value
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class TypeVar(BaseTypingValue):
|
class TypeVar(BaseTypingValue):
|
||||||
def __init__(self, parent_context, tree_name, var_name, unpacked_args):
|
def __init__(self, parent_context, tree_name, var_name, unpacked_args):
|
||||||
super(TypeVar, self).__init__(parent_context, tree_name)
|
super().__init__(parent_context, tree_name)
|
||||||
self._var_name = var_name
|
self._var_name = var_name
|
||||||
|
|
||||||
self._constraints_lazy_values = []
|
self._constraints_lazy_values = []
|
||||||
@@ -124,7 +120,7 @@ class TypeVar(BaseTypingValue):
|
|||||||
|
|
||||||
class TypeWrapper(ValueWrapper):
|
class TypeWrapper(ValueWrapper):
|
||||||
def __init__(self, wrapped_value, original_value):
|
def __init__(self, wrapped_value, original_value):
|
||||||
super(TypeWrapper, self).__init__(wrapped_value)
|
super().__init__(wrapped_value)
|
||||||
self._original_value = original_value
|
self._original_value = original_value
|
||||||
|
|
||||||
def execute_annotation(self):
|
def execute_annotation(self):
|
||||||
|
|||||||
@@ -2,19 +2,20 @@ import os
|
|||||||
import re
|
import re
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
from jedi.file_io import FileIO
|
from jedi.file_io import FileIO
|
||||||
from jedi._compatibility import FileNotFoundError, cast_path
|
from jedi._compatibility import cast_path
|
||||||
from jedi.parser_utils import get_cached_code_lines
|
from jedi.parser_utils import get_cached_code_lines
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.inference.gradual.stub_value import TypingModuleWrapper, StubModuleValue
|
from jedi.inference.gradual.stub_value import TypingModuleWrapper, StubModuleValue
|
||||||
from jedi.inference.value import ModuleValue
|
from jedi.inference.value import ModuleValue
|
||||||
|
|
||||||
_jedi_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
_jedi_path = Path(__file__).parent.parent.parent
|
||||||
TYPESHED_PATH = os.path.join(_jedi_path, 'third_party', 'typeshed')
|
TYPESHED_PATH = _jedi_path.joinpath('third_party', 'typeshed')
|
||||||
DJANGO_INIT_PATH = os.path.join(_jedi_path, 'third_party', 'django-stubs',
|
DJANGO_INIT_PATH = _jedi_path.joinpath('third_party', 'django-stubs',
|
||||||
'django-stubs', '__init__.pyi')
|
'django-stubs', '__init__.pyi')
|
||||||
|
|
||||||
_IMPORT_MAP = dict(
|
_IMPORT_MAP = dict(
|
||||||
_collections='collections',
|
_collections='collections',
|
||||||
@@ -38,8 +39,7 @@ def _create_stub_map(directory_path_info):
|
|||||||
def generate():
|
def generate():
|
||||||
try:
|
try:
|
||||||
listed = os.listdir(directory_path_info.path)
|
listed = os.listdir(directory_path_info.path)
|
||||||
except (FileNotFoundError, OSError):
|
except (FileNotFoundError, NotADirectoryError):
|
||||||
# OSError is Python 2
|
|
||||||
return
|
return
|
||||||
|
|
||||||
for entry in listed:
|
for entry in listed:
|
||||||
@@ -59,20 +59,19 @@ def _create_stub_map(directory_path_info):
|
|||||||
|
|
||||||
|
|
||||||
def _get_typeshed_directories(version_info):
|
def _get_typeshed_directories(version_info):
|
||||||
check_version_list = ['2and3', str(version_info.major)]
|
check_version_list = ['2and3', '3']
|
||||||
for base in ['stdlib', 'third_party']:
|
for base in ['stdlib', 'third_party']:
|
||||||
base_path = os.path.join(TYPESHED_PATH, base)
|
base_path = TYPESHED_PATH.joinpath(base)
|
||||||
base_list = os.listdir(base_path)
|
base_list = os.listdir(base_path)
|
||||||
for base_list_entry in base_list:
|
for base_list_entry in base_list:
|
||||||
match = re.match(r'(\d+)\.(\d+)$', base_list_entry)
|
match = re.match(r'(\d+)\.(\d+)$', base_list_entry)
|
||||||
if match is not None:
|
if match is not None:
|
||||||
if int(match.group(1)) == version_info.major \
|
if match.group(1) == '3' and int(match.group(2)) <= version_info.minor:
|
||||||
and int(match.group(2)) <= version_info.minor:
|
|
||||||
check_version_list.append(base_list_entry)
|
check_version_list.append(base_list_entry)
|
||||||
|
|
||||||
for check_version in check_version_list:
|
for check_version in check_version_list:
|
||||||
is_third_party = base != 'stdlib'
|
is_third_party = base != 'stdlib'
|
||||||
yield PathInfo(os.path.join(base_path, check_version), is_third_party)
|
yield PathInfo(str(base_path.joinpath(check_version)), is_third_party)
|
||||||
|
|
||||||
|
|
||||||
_version_cache = {}
|
_version_cache = {}
|
||||||
@@ -111,7 +110,7 @@ def import_module_decorator(func):
|
|||||||
# ``os``.
|
# ``os``.
|
||||||
python_value_set = ValueSet.from_sets(
|
python_value_set = ValueSet.from_sets(
|
||||||
func(inference_state, (n,), None, sys_path,)
|
func(inference_state, (n,), None, sys_path,)
|
||||||
for n in [u'posixpath', u'ntpath', u'macpath', u'os2emxpath']
|
for n in ['posixpath', 'ntpath', 'macpath', 'os2emxpath']
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
python_value_set = ValueSet.from_sets(
|
python_value_set = ValueSet.from_sets(
|
||||||
@@ -183,7 +182,7 @@ def _try_to_load_stub(inference_state, import_names, python_value_set,
|
|||||||
return _try_to_load_stub_from_file(
|
return _try_to_load_stub_from_file(
|
||||||
inference_state,
|
inference_state,
|
||||||
python_value_set,
|
python_value_set,
|
||||||
file_io=FileIO(DJANGO_INIT_PATH),
|
file_io=FileIO(str(DJANGO_INIT_PATH)),
|
||||||
import_names=import_names,
|
import_names=import_names,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -198,8 +197,8 @@ def _try_to_load_stub(inference_state, import_names, python_value_set,
|
|||||||
file_paths = []
|
file_paths = []
|
||||||
if c.is_namespace():
|
if c.is_namespace():
|
||||||
file_paths = [os.path.join(p, '__init__.pyi') for p in c.py__path__()]
|
file_paths = [os.path.join(p, '__init__.pyi') for p in c.py__path__()]
|
||||||
elif file_path is not None and file_path.endswith('.py'):
|
elif file_path is not None and file_path.suffix == '.py':
|
||||||
file_paths = [file_path + 'i']
|
file_paths = [str(file_path) + 'i']
|
||||||
|
|
||||||
for file_path in file_paths:
|
for file_path in file_paths:
|
||||||
m = _try_to_load_stub_from_file(
|
m = _try_to_load_stub_from_file(
|
||||||
@@ -274,7 +273,7 @@ def _load_from_typeshed(inference_state, python_value_set, parent_module_value,
|
|||||||
def _try_to_load_stub_from_file(inference_state, python_value_set, file_io, import_names):
|
def _try_to_load_stub_from_file(inference_state, python_value_set, file_io, import_names):
|
||||||
try:
|
try:
|
||||||
stub_module_node = parse_stub_module(inference_state, file_io)
|
stub_module_node = parse_stub_module(inference_state, file_io)
|
||||||
except (OSError, IOError): # IOError is Python 2 only
|
except OSError:
|
||||||
# The file that you're looking for doesn't exist (anymore).
|
# The file that you're looking for doesn't exist (anymore).
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ This file deals with all the typing.py cases.
|
|||||||
"""
|
"""
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from jedi._compatibility import unicode
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.compiled import builtin_from_name, create_simple_object
|
from jedi.inference.compiled import builtin_from_name, create_simple_object
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES, Value, \
|
from jedi.inference.base_value import ValueSet, NO_VALUES, Value, \
|
||||||
@@ -72,7 +71,7 @@ class TypingModuleName(NameWrapper):
|
|||||||
elif name == 'TYPE_CHECKING':
|
elif name == 'TYPE_CHECKING':
|
||||||
# This is needed for e.g. imports that are only available for type
|
# This is needed for e.g. imports that are only available for type
|
||||||
# checking or are in cycles. The user can then check this variable.
|
# checking or are in cycles. The user can then check this variable.
|
||||||
yield builtin_from_name(inference_state, u'True')
|
yield builtin_from_name(inference_state, 'True')
|
||||||
elif name == 'overload':
|
elif name == 'overload':
|
||||||
yield OverloadFunction.create_cached(
|
yield OverloadFunction.create_cached(
|
||||||
inference_state, self.parent_context, self.tree_name)
|
inference_state, self.parent_context, self.tree_name)
|
||||||
@@ -89,12 +88,10 @@ class TypingModuleName(NameWrapper):
|
|||||||
inference_state, self.parent_context, self.tree_name)
|
inference_state, self.parent_context, self.tree_name)
|
||||||
elif name in ('no_type_check', 'no_type_check_decorator'):
|
elif name in ('no_type_check', 'no_type_check_decorator'):
|
||||||
# This is not necessary, as long as we are not doing type checking.
|
# This is not necessary, as long as we are not doing type checking.
|
||||||
for c in self._wrapped_name.infer(): # Fuck my life Python 2
|
yield from self._wrapped_name.infer()
|
||||||
yield c
|
|
||||||
else:
|
else:
|
||||||
# Everything else shouldn't be relevant for type checking.
|
# Everything else shouldn't be relevant for type checking.
|
||||||
for c in self._wrapped_name.infer(): # Fuck my life Python 2
|
yield from self._wrapped_name.infer()
|
||||||
yield c
|
|
||||||
|
|
||||||
|
|
||||||
class TypingModuleFilterWrapper(FilterWrapper):
|
class TypingModuleFilterWrapper(FilterWrapper):
|
||||||
@@ -113,7 +110,7 @@ class ProxyWithGenerics(BaseTypingClassWithGenerics):
|
|||||||
# Optional is basically just saying it's either None or the actual
|
# Optional is basically just saying it's either None or the actual
|
||||||
# type.
|
# type.
|
||||||
return self.gather_annotation_classes().execute_annotation() \
|
return self.gather_annotation_classes().execute_annotation() \
|
||||||
| ValueSet([builtin_from_name(self.inference_state, u'None')])
|
| ValueSet([builtin_from_name(self.inference_state, 'None')])
|
||||||
elif string_name == 'Type':
|
elif string_name == 'Type':
|
||||||
# The type is actually already given in the index_value
|
# The type is actually already given in the index_value
|
||||||
return self._generics_manager[0]
|
return self._generics_manager[0]
|
||||||
@@ -156,7 +153,7 @@ class ProxyWithGenerics(BaseTypingClassWithGenerics):
|
|||||||
# Optional[T] is equivalent to Union[T, None]. In Jedi unions
|
# Optional[T] is equivalent to Union[T, None]. In Jedi unions
|
||||||
# are represented by members within a ValueSet, so we extract
|
# are represented by members within a ValueSet, so we extract
|
||||||
# the T from the Optional[T] by removing the None value.
|
# the T from the Optional[T] by removing the None value.
|
||||||
none = builtin_from_name(self.inference_state, u'None')
|
none = builtin_from_name(self.inference_state, 'None')
|
||||||
return annotation_generics[0].infer_type_vars(
|
return annotation_generics[0].infer_type_vars(
|
||||||
value_set.filter(lambda x: x != none),
|
value_set.filter(lambda x: x != none),
|
||||||
)
|
)
|
||||||
@@ -263,8 +260,6 @@ class TypeAlias(LazyValueWrapper):
|
|||||||
|
|
||||||
def _get_wrapped_value(self):
|
def _get_wrapped_value(self):
|
||||||
module_name, class_name = self._actual.split('.')
|
module_name, class_name = self._actual.split('.')
|
||||||
if self.inference_state.environment.version_info.major == 2 and module_name == 'builtins':
|
|
||||||
module_name = '__builtin__'
|
|
||||||
|
|
||||||
# TODO use inference_state.import_module?
|
# TODO use inference_state.import_module?
|
||||||
from jedi.inference.imports import Importer
|
from jedi.inference.imports import Importer
|
||||||
@@ -418,7 +413,7 @@ class NewTypeFunction(BaseTypingValue):
|
|||||||
|
|
||||||
class NewType(Value):
|
class NewType(Value):
|
||||||
def __init__(self, inference_state, parent_context, tree_node, type_value_set):
|
def __init__(self, inference_state, parent_context, tree_node, type_value_set):
|
||||||
super(NewType, self).__init__(inference_state, parent_context)
|
super().__init__(inference_state, parent_context)
|
||||||
self._type_value_set = type_value_set
|
self._type_value_set = type_value_set
|
||||||
self.tree_node = tree_node
|
self.tree_node = tree_node
|
||||||
|
|
||||||
@@ -461,7 +456,7 @@ class TypedDict(LazyValueWrapper):
|
|||||||
return ValueName(self, self.tree_node.name)
|
return ValueName(self, self.tree_node.name)
|
||||||
|
|
||||||
def py__simple_getitem__(self, index):
|
def py__simple_getitem__(self, index):
|
||||||
if isinstance(index, unicode):
|
if isinstance(index, str):
|
||||||
return ValueSet.from_sets(
|
return ValueSet.from_sets(
|
||||||
name.infer()
|
name.infer()
|
||||||
for filter in self._definition_class.get_filters(is_instance=True)
|
for filter in self._definition_class.get_filters(is_instance=True)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from jedi.inference.gradual.typeshed import TYPESHED_PATH, create_stub_module
|
from jedi.inference.gradual.typeshed import TYPESHED_PATH, create_stub_module
|
||||||
|
|
||||||
@@ -9,14 +10,18 @@ def load_proper_stub_module(inference_state, file_io, import_names, module_node)
|
|||||||
module.
|
module.
|
||||||
"""
|
"""
|
||||||
path = file_io.path
|
path = file_io.path
|
||||||
assert path.endswith('.pyi')
|
path = Path(path)
|
||||||
if path.startswith(TYPESHED_PATH):
|
assert path.suffix == '.pyi'
|
||||||
# /foo/stdlib/3/os/__init__.pyi -> stdlib/3/os/__init__
|
try:
|
||||||
rest = path[len(TYPESHED_PATH) + 1: -4]
|
relative_path = path.relative_to(TYPESHED_PATH)
|
||||||
split_paths = tuple(rest.split(os.path.sep))
|
except ValueError:
|
||||||
# Remove the stdlib/3 or third_party/3.5 part
|
pass
|
||||||
import_names = split_paths[2:]
|
else:
|
||||||
if import_names[-1] == '__init__':
|
# /[...]/stdlib/3/os/__init__.pyi -> stdlib/3/os/__init__
|
||||||
|
rest = relative_path.with_suffix('')
|
||||||
|
# Remove the stdlib/3 or third_party/3.6 part
|
||||||
|
import_names = rest.parts[2:]
|
||||||
|
if rest.name == '__init__':
|
||||||
import_names = import_names[:-1]
|
import_names = import_names[:-1]
|
||||||
|
|
||||||
if import_names is not None:
|
if import_names is not None:
|
||||||
|
|||||||
@@ -7,18 +7,17 @@ from contextlib import contextmanager
|
|||||||
|
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
from jedi._compatibility import unicode
|
|
||||||
|
|
||||||
|
|
||||||
def is_stdlib_path(path):
|
def is_stdlib_path(path):
|
||||||
# Python standard library paths look like this:
|
# Python standard library paths look like this:
|
||||||
# /usr/lib/python3.5/...
|
# /usr/lib/python3.9/...
|
||||||
# TODO The implementation below is probably incorrect and not complete.
|
# TODO The implementation below is probably incorrect and not complete.
|
||||||
if 'dist-packages' in path or 'site-packages' in path:
|
parts = path.parts
|
||||||
|
if 'dist-packages' in parts or 'site-packages' in parts:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
base_path = os.path.join(sys.prefix, 'lib', 'python')
|
base_path = os.path.join(sys.prefix, 'lib', 'python')
|
||||||
return bool(re.match(re.escape(base_path) + r'\d.\d', path))
|
return bool(re.match(re.escape(base_path) + r'\d.\d', str(path)))
|
||||||
|
|
||||||
|
|
||||||
def deep_ast_copy(obj):
|
def deep_ast_copy(obj):
|
||||||
@@ -122,11 +121,7 @@ def get_names_of_node(node):
|
|||||||
|
|
||||||
|
|
||||||
def is_string(value):
|
def is_string(value):
|
||||||
if value.inference_state.environment.version_info.major == 2:
|
return value.is_compiled() and isinstance(value.get_safe_value(default=None), str)
|
||||||
str_classes = (unicode, bytes)
|
|
||||||
else:
|
|
||||||
str_classes = (unicode,)
|
|
||||||
return value.is_compiled() and isinstance(value.get_safe_value(default=None), str_classes)
|
|
||||||
|
|
||||||
|
|
||||||
def is_literal(value):
|
def is_literal(value):
|
||||||
@@ -144,7 +139,7 @@ def get_int_or_none(value):
|
|||||||
|
|
||||||
|
|
||||||
def get_str_or_none(value):
|
def get_str_or_none(value):
|
||||||
return _get_safe_value_or_none(value, (bytes, unicode))
|
return _get_safe_value_or_none(value, str)
|
||||||
|
|
||||||
|
|
||||||
def is_number(value):
|
def is_number(value):
|
||||||
|
|||||||
+12
-11
@@ -5,18 +5,15 @@ not any actual importing done. This module is about finding modules in the
|
|||||||
filesystem. This can be quite tricky sometimes, because Python imports are not
|
filesystem. This can be quite tricky sometimes, because Python imports are not
|
||||||
always that simple.
|
always that simple.
|
||||||
|
|
||||||
This module uses imp for python up to 3.2 and importlib for python 3.3 on; the
|
|
||||||
correct implementation is delegated to _compatibility.
|
|
||||||
|
|
||||||
This module also supports import autocompletion, which means to complete
|
This module also supports import autocompletion, which means to complete
|
||||||
statements like ``from datetim`` (cursor at the end would return ``datetime``).
|
statements like ``from datetim`` (cursor at the end would return ``datetime``).
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
from parso.tree import search_ancestor
|
from parso.tree import search_ancestor
|
||||||
|
|
||||||
from jedi._compatibility import ImplicitNSInfo, force_unicode, FileNotFoundError
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
from jedi.file_io import FolderIO
|
from jedi.file_io import FolderIO
|
||||||
@@ -31,6 +28,7 @@ from jedi.inference.names import ImportName, SubModuleName
|
|||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.inference.gradual.typeshed import import_module_decorator, \
|
from jedi.inference.gradual.typeshed import import_module_decorator, \
|
||||||
create_stub_module, parse_stub_module
|
create_stub_module, parse_stub_module
|
||||||
|
from jedi.inference.compiled.subprocess.functions import ImplicitNSInfo
|
||||||
from jedi.plugins import plugin_manager
|
from jedi.plugins import plugin_manager
|
||||||
|
|
||||||
|
|
||||||
@@ -211,7 +209,7 @@ class Importer(object):
|
|||||||
# somewhere out of the filesystem.
|
# somewhere out of the filesystem.
|
||||||
self._infer_possible = False
|
self._infer_possible = False
|
||||||
else:
|
else:
|
||||||
self._fixed_sys_path = [force_unicode(base_directory)]
|
self._fixed_sys_path = [base_directory]
|
||||||
|
|
||||||
if base_import_path is None:
|
if base_import_path is None:
|
||||||
if import_path:
|
if import_path:
|
||||||
@@ -240,7 +238,10 @@ class Importer(object):
|
|||||||
# inference we want to show the user as much as possible.
|
# inference we want to show the user as much as possible.
|
||||||
# See GH #1446.
|
# See GH #1446.
|
||||||
self._inference_state.get_sys_path(add_init_paths=not is_completion)
|
self._inference_state.get_sys_path(add_init_paths=not is_completion)
|
||||||
+ sys_path.check_sys_path_modifications(self._module_context)
|
+ [
|
||||||
|
str(p) for p
|
||||||
|
in sys_path.check_sys_path_modifications(self._module_context)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
def follow(self):
|
def follow(self):
|
||||||
@@ -332,7 +333,7 @@ def import_module_by_names(inference_state, import_names, sys_path=None,
|
|||||||
sys_path = inference_state.get_sys_path()
|
sys_path = inference_state.get_sys_path()
|
||||||
|
|
||||||
str_import_names = tuple(
|
str_import_names = tuple(
|
||||||
force_unicode(i.value if isinstance(i, tree.Name) else i)
|
i.value if isinstance(i, tree.Name) else i
|
||||||
for i in import_names
|
for i in import_names
|
||||||
)
|
)
|
||||||
value_set = [None]
|
value_set = [None]
|
||||||
@@ -470,19 +471,19 @@ def load_module_from_path(inference_state, file_io, import_names=None, is_packag
|
|||||||
here to ensure that a random path is still properly loaded into the Jedi
|
here to ensure that a random path is still properly loaded into the Jedi
|
||||||
module structure.
|
module structure.
|
||||||
"""
|
"""
|
||||||
path = file_io.path
|
path = Path(file_io.path)
|
||||||
if import_names is None:
|
if import_names is None:
|
||||||
e_sys_path = inference_state.get_sys_path()
|
e_sys_path = inference_state.get_sys_path()
|
||||||
import_names, is_package = sys_path.transform_path_to_dotted(e_sys_path, path)
|
import_names, is_package = sys_path.transform_path_to_dotted(e_sys_path, path)
|
||||||
else:
|
else:
|
||||||
assert isinstance(is_package, bool)
|
assert isinstance(is_package, bool)
|
||||||
|
|
||||||
is_stub = file_io.path.endswith('.pyi')
|
is_stub = path.suffix == '.pyi'
|
||||||
if is_stub:
|
if is_stub:
|
||||||
folder_io = file_io.get_parent_folder()
|
folder_io = file_io.get_parent_folder()
|
||||||
if folder_io.path.endswith('-stubs'):
|
if folder_io.path.endswith('-stubs'):
|
||||||
folder_io = FolderIO(folder_io.path[:-6])
|
folder_io = FolderIO(folder_io.path[:-6])
|
||||||
if file_io.path.endswith('__init__.pyi'):
|
if path.name == '__init__.pyi':
|
||||||
python_file_io = folder_io.get_file_io('__init__.py')
|
python_file_io = folder_io.get_file_io('__init__.py')
|
||||||
else:
|
else:
|
||||||
python_file_io = folder_io.get_file_io(import_names[-1] + '.py')
|
python_file_io = folder_io.get_file_io(import_names[-1] + '.py')
|
||||||
@@ -513,7 +514,7 @@ def load_module_from_path(inference_state, file_io, import_names=None, is_packag
|
|||||||
def load_namespace_from_path(inference_state, folder_io):
|
def load_namespace_from_path(inference_state, folder_io):
|
||||||
import_names, is_package = sys_path.transform_path_to_dotted(
|
import_names, is_package = sys_path.transform_path_to_dotted(
|
||||||
inference_state.get_sys_path(),
|
inference_state.get_sys_path(),
|
||||||
folder_io.path
|
Path(folder_io.path)
|
||||||
)
|
)
|
||||||
from jedi.inference.value.namespace import ImplicitNamespaceValue
|
from jedi.inference.value.namespace import ImplicitNamespaceValue
|
||||||
return ImplicitNamespaceValue(inference_state, import_names, [folder_io.path])
|
return ImplicitNamespaceValue(inference_state, import_names, [folder_io.path])
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class LazyKnownValues(AbstractLazyValue):
|
|||||||
|
|
||||||
class LazyUnknownValue(AbstractLazyValue):
|
class LazyUnknownValue(AbstractLazyValue):
|
||||||
def __init__(self, min=1, max=1):
|
def __init__(self, min=1, max=1):
|
||||||
super(LazyUnknownValue, self).__init__(None, min, max)
|
super().__init__(None, min, max)
|
||||||
|
|
||||||
def infer(self):
|
def infer(self):
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
@@ -37,7 +37,7 @@ class LazyUnknownValue(AbstractLazyValue):
|
|||||||
|
|
||||||
class LazyTreeValue(AbstractLazyValue):
|
class LazyTreeValue(AbstractLazyValue):
|
||||||
def __init__(self, context, node, min=1, max=1):
|
def __init__(self, context, node, min=1, max=1):
|
||||||
super(LazyTreeValue, self).__init__(node, min, max)
|
super().__init__(node, min, max)
|
||||||
self.context = context
|
self.context = context
|
||||||
# We need to save the predefined names. It's an unfortunate side effect
|
# We need to save the predefined names. It's an unfortunate side effect
|
||||||
# that needs to be tracked otherwise results will be wrong.
|
# that needs to be tracked otherwise results will be wrong.
|
||||||
|
|||||||
+12
-12
@@ -1,8 +1,8 @@
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
from inspect import Parameter
|
||||||
|
|
||||||
from parso.tree import search_ancestor
|
from parso.tree import search_ancestor
|
||||||
|
|
||||||
from jedi._compatibility import Parameter
|
|
||||||
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
|
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
|
||||||
from jedi.inference.utils import unite
|
from jedi.inference.utils import unite
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
@@ -123,7 +123,7 @@ class AbstractTreeName(AbstractNameDefinition):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return super(AbstractTreeName, self).get_qualified_names(include_module_names)
|
return super().get_qualified_names(include_module_names)
|
||||||
|
|
||||||
def _get_qualified_names(self):
|
def _get_qualified_names(self):
|
||||||
parent_names = self.parent_context.get_qualified_names()
|
parent_names = self.parent_context.get_qualified_names()
|
||||||
@@ -242,7 +242,7 @@ class ValueNameMixin(object):
|
|||||||
def get_root_context(self):
|
def get_root_context(self):
|
||||||
if self.parent_context is None: # A module
|
if self.parent_context is None: # A module
|
||||||
return self._value.as_context()
|
return self._value.as_context()
|
||||||
return super(ValueNameMixin, self).get_root_context()
|
return super().get_root_context()
|
||||||
|
|
||||||
def get_defining_qualified_value(self):
|
def get_defining_qualified_value(self):
|
||||||
context = self.parent_context
|
context = self.parent_context
|
||||||
@@ -257,7 +257,7 @@ class ValueNameMixin(object):
|
|||||||
|
|
||||||
class ValueName(ValueNameMixin, AbstractTreeName):
|
class ValueName(ValueNameMixin, AbstractTreeName):
|
||||||
def __init__(self, value, tree_name):
|
def __init__(self, value, tree_name):
|
||||||
super(ValueName, self).__init__(value.parent_context, tree_name)
|
super().__init__(value.parent_context, tree_name)
|
||||||
self._value = value
|
self._value = value
|
||||||
|
|
||||||
def goto(self):
|
def goto(self):
|
||||||
@@ -372,7 +372,7 @@ class _ParamMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
class ParamNameInterface(_ParamMixin):
|
class ParamNameInterface(_ParamMixin):
|
||||||
api_type = u'param'
|
api_type = 'param'
|
||||||
|
|
||||||
def get_kind(self):
|
def get_kind(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@@ -429,7 +429,7 @@ class BaseTreeParamName(ParamNameInterface, AbstractTreeName):
|
|||||||
|
|
||||||
class _ActualTreeParamName(BaseTreeParamName):
|
class _ActualTreeParamName(BaseTreeParamName):
|
||||||
def __init__(self, function_value, tree_name):
|
def __init__(self, function_value, tree_name):
|
||||||
super(_ActualTreeParamName, self).__init__(
|
super().__init__(
|
||||||
function_value.get_default_param_context(), tree_name)
|
function_value.get_default_param_context(), tree_name)
|
||||||
self.function_value = function_value
|
self.function_value = function_value
|
||||||
|
|
||||||
@@ -499,11 +499,11 @@ class _ActualTreeParamName(BaseTreeParamName):
|
|||||||
class AnonymousParamName(_ActualTreeParamName):
|
class AnonymousParamName(_ActualTreeParamName):
|
||||||
@plugin_manager.decorate(name='goto_anonymous_param')
|
@plugin_manager.decorate(name='goto_anonymous_param')
|
||||||
def goto(self):
|
def goto(self):
|
||||||
return super(AnonymousParamName, self).goto()
|
return super().goto()
|
||||||
|
|
||||||
@plugin_manager.decorate(name='infer_anonymous_param')
|
@plugin_manager.decorate(name='infer_anonymous_param')
|
||||||
def infer(self):
|
def infer(self):
|
||||||
values = super(AnonymousParamName, self).infer()
|
values = super().infer()
|
||||||
if values:
|
if values:
|
||||||
return values
|
return values
|
||||||
from jedi.inference.dynamic_params import dynamic_param_lookup
|
from jedi.inference.dynamic_params import dynamic_param_lookup
|
||||||
@@ -527,11 +527,11 @@ class AnonymousParamName(_ActualTreeParamName):
|
|||||||
|
|
||||||
class ParamName(_ActualTreeParamName):
|
class ParamName(_ActualTreeParamName):
|
||||||
def __init__(self, function_value, tree_name, arguments):
|
def __init__(self, function_value, tree_name, arguments):
|
||||||
super(ParamName, self).__init__(function_value, tree_name)
|
super().__init__(function_value, tree_name)
|
||||||
self.arguments = arguments
|
self.arguments = arguments
|
||||||
|
|
||||||
def infer(self):
|
def infer(self):
|
||||||
values = super(ParamName, self).infer()
|
values = super().infer()
|
||||||
if values:
|
if values:
|
||||||
return values
|
return values
|
||||||
|
|
||||||
@@ -627,7 +627,7 @@ class StubNameMixin(object):
|
|||||||
|
|
||||||
names = convert_names(names, prefer_stub_to_compiled=False)
|
names = convert_names(names, prefer_stub_to_compiled=False)
|
||||||
if self in names:
|
if self in names:
|
||||||
return super(StubNameMixin, self).py__doc__()
|
return super().py__doc__()
|
||||||
else:
|
else:
|
||||||
# We have signatures ourselves in stubs, so don't use signatures
|
# We have signatures ourselves in stubs, so don't use signatures
|
||||||
# from the implementation.
|
# from the implementation.
|
||||||
@@ -637,7 +637,7 @@ class StubNameMixin(object):
|
|||||||
# From here on down we make looking up the sys.version_info fast.
|
# From here on down we make looking up the sys.version_info fast.
|
||||||
class StubName(StubNameMixin, TreeNameDefinition):
|
class StubName(StubNameMixin, TreeNameDefinition):
|
||||||
def infer(self):
|
def infer(self):
|
||||||
inferred = super(StubName, self).infer()
|
inferred = super().infer()
|
||||||
if self.string_name == 'version_info' and self.get_root_context().py__name__() == 'sys':
|
if self.string_name == 'version_info' and self.get_root_context().py__name__() == 'sys':
|
||||||
from jedi.inference.gradual.stub_value import VersionInfo
|
from jedi.inference.gradual.stub_value import VersionInfo
|
||||||
return ValueSet(VersionInfo(c) for c in inferred)
|
return ValueSet(VersionInfo(c) for c in inferred)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from inspect import Parameter
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.utils import PushBackIterator
|
from jedi.inference.utils import PushBackIterator
|
||||||
@@ -6,7 +7,6 @@ from jedi.inference import analysis
|
|||||||
from jedi.inference.lazy_value import LazyKnownValue, \
|
from jedi.inference.lazy_value import LazyKnownValue, \
|
||||||
LazyTreeValue, LazyUnknownValue
|
LazyTreeValue, LazyUnknownValue
|
||||||
from jedi.inference.value import iterable
|
from jedi.inference.value import iterable
|
||||||
from jedi._compatibility import Parameter
|
|
||||||
from jedi.inference.names import ParamName
|
from jedi.inference.names import ParamName
|
||||||
|
|
||||||
|
|
||||||
@@ -20,8 +20,7 @@ def _add_argument_issue(error_name, lazy_value, message):
|
|||||||
|
|
||||||
class ExecutedParamName(ParamName):
|
class ExecutedParamName(ParamName):
|
||||||
def __init__(self, function_value, arguments, param_node, lazy_value, is_default=False):
|
def __init__(self, function_value, arguments, param_node, lazy_value, is_default=False):
|
||||||
super(ExecutedParamName, self).__init__(
|
super().__init__(function_value, param_node.name, arguments=arguments)
|
||||||
function_value, param_node.name, arguments=arguments)
|
|
||||||
self._lazy_value = lazy_value
|
self._lazy_value = lazy_value
|
||||||
self._is_default = is_default
|
self._is_default = is_default
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import re
|
|||||||
|
|
||||||
from parso import python_bytes_to_unicode
|
from parso import python_bytes_to_unicode
|
||||||
|
|
||||||
from jedi._compatibility import FileNotFoundError
|
|
||||||
from jedi.debug import dbg
|
from jedi.debug import dbg
|
||||||
from jedi.file_io import KnownContentFileIO
|
from jedi.file_io import KnownContentFileIO
|
||||||
from jedi.inference.imports import SubModuleName, load_module_from_path
|
from jedi.inference.imports import SubModuleName, load_module_from_path
|
||||||
@@ -273,9 +272,8 @@ def get_module_contexts_containing_name(inference_state, module_contexts, name,
|
|||||||
return
|
return
|
||||||
|
|
||||||
file_io_iterator = _find_python_files_in_sys_path(inference_state, module_contexts)
|
file_io_iterator = _find_python_files_in_sys_path(inference_state, module_contexts)
|
||||||
for x in search_in_file_ios(inference_state, file_io_iterator, name,
|
yield from search_in_file_ios(inference_state, file_io_iterator, name,
|
||||||
limit_reduction=limit_reduction):
|
limit_reduction=limit_reduction)
|
||||||
yield x # Python 2...
|
|
||||||
|
|
||||||
|
|
||||||
def search_in_file_ios(inference_state, file_io_iterator, name, limit_reduction=1):
|
def search_in_file_ios(inference_state, file_io_iterator, name, limit_reduction=1):
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from jedi._compatibility import Parameter
|
from inspect import Parameter
|
||||||
|
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import parser_utils
|
from jedi import parser_utils
|
||||||
@@ -67,7 +68,7 @@ class AbstractSignature(_SignatureMixin):
|
|||||||
|
|
||||||
class TreeSignature(AbstractSignature):
|
class TreeSignature(AbstractSignature):
|
||||||
def __init__(self, value, function_value=None, is_bound=False):
|
def __init__(self, value, function_value=None, is_bound=False):
|
||||||
super(TreeSignature, self).__init__(value, is_bound)
|
super().__init__(value, is_bound)
|
||||||
self._function_value = function_value or value
|
self._function_value = function_value or value
|
||||||
|
|
||||||
def bind(self, value):
|
def bind(self, value):
|
||||||
@@ -121,7 +122,7 @@ class TreeSignature(AbstractSignature):
|
|||||||
|
|
||||||
class BuiltinSignature(AbstractSignature):
|
class BuiltinSignature(AbstractSignature):
|
||||||
def __init__(self, value, return_string, function_value=None, is_bound=False):
|
def __init__(self, value, return_string, function_value=None, is_bound=False):
|
||||||
super(BuiltinSignature, self).__init__(value, is_bound)
|
super().__init__(value, is_bound)
|
||||||
self._return_string = return_string
|
self._return_string = return_string
|
||||||
self.__function_value = function_value
|
self.__function_value = function_value
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ This means for example in this case::
|
|||||||
|
|
||||||
The signature here for bar should be `bar(b, c)` instead of bar(*args).
|
The signature here for bar should be `bar(b, c)` instead of bar(*args).
|
||||||
"""
|
"""
|
||||||
|
from inspect import Parameter
|
||||||
|
|
||||||
from jedi._compatibility import Parameter
|
|
||||||
from jedi.inference.utils import to_list
|
from jedi.inference.utils import to_list
|
||||||
from jedi.inference.names import ParamNameWrapper
|
from jedi.inference.names import ParamNameWrapper
|
||||||
from jedi.inference.helpers import is_big_annoying_library
|
from jedi.inference.helpers import is_big_annoying_library
|
||||||
@@ -32,8 +32,6 @@ def _iter_nodes_for_param(param_name):
|
|||||||
argument = name.parent
|
argument = name.parent
|
||||||
if argument.type == 'argument' \
|
if argument.type == 'argument' \
|
||||||
and argument.children[0] == '*' * param_name.star_count:
|
and argument.children[0] == '*' * param_name.star_count:
|
||||||
# No support for Python 2.7 here, but they are end-of-life
|
|
||||||
# anyway
|
|
||||||
trailer = search_ancestor(argument, 'trailer')
|
trailer = search_ancestor(argument, 'trailer')
|
||||||
if trailer is not None: # Make sure we're in a function
|
if trailer is not None: # Make sure we're in a function
|
||||||
context = execution_context.create_context(trailer)
|
context = execution_context.create_context(trailer)
|
||||||
@@ -210,7 +208,7 @@ def process_params(param_names, star_count=3): # default means both * and **
|
|||||||
|
|
||||||
class ParamNameFixedKind(ParamNameWrapper):
|
class ParamNameFixedKind(ParamNameWrapper):
|
||||||
def __init__(self, param_name, new_kind):
|
def __init__(self, param_name, new_kind):
|
||||||
super(ParamNameFixedKind, self).__init__(param_name)
|
super().__init__(param_name)
|
||||||
self._new_kind = new_kind
|
self._new_kind = new_kind
|
||||||
|
|
||||||
def get_kind(self):
|
def get_kind(self):
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import copy
|
|||||||
|
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
from jedi._compatibility import force_unicode, unicode
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import parser_utils
|
from jedi import parser_utils
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES, ContextualizedNode, \
|
from jedi.inference.base_value import ValueSet, NO_VALUES, ContextualizedNode, \
|
||||||
@@ -225,12 +224,10 @@ def _infer_node(context, element):
|
|||||||
| context.infer_node(element.children[-1]))
|
| context.infer_node(element.children[-1]))
|
||||||
elif typ == 'operator':
|
elif typ == 'operator':
|
||||||
# Must be an ellipsis, other operators are not inferred.
|
# Must be an ellipsis, other operators are not inferred.
|
||||||
# In Python 2 ellipsis is coded as three single dot tokens, not
|
if element.value != '...':
|
||||||
# as one token 3 dot token.
|
|
||||||
if element.value not in ('.', '...'):
|
|
||||||
origin = element.parent
|
origin = element.parent
|
||||||
raise AssertionError("unhandled operator %s in %s " % (repr(element.value), origin))
|
raise AssertionError("unhandled operator %s in %s " % (repr(element.value), origin))
|
||||||
return ValueSet([compiled.builtin_from_name(inference_state, u'Ellipsis')])
|
return ValueSet([compiled.builtin_from_name(inference_state, 'Ellipsis')])
|
||||||
elif typ == 'dotted_name':
|
elif typ == 'dotted_name':
|
||||||
value_set = infer_atom(context, element.children[0])
|
value_set = infer_atom(context, element.children[0])
|
||||||
for next_name in element.children[2::2]:
|
for next_name in element.children[2::2]:
|
||||||
@@ -289,10 +286,6 @@ def infer_atom(context, atom):
|
|||||||
"""
|
"""
|
||||||
state = context.inference_state
|
state = context.inference_state
|
||||||
if atom.type == 'name':
|
if atom.type == 'name':
|
||||||
if atom.value in ('True', 'False', 'None'):
|
|
||||||
# Python 2...
|
|
||||||
return ValueSet([compiled.builtin_from_name(state, atom.value)])
|
|
||||||
|
|
||||||
# This is the first global lookup.
|
# This is the first global lookup.
|
||||||
stmt = tree.search_ancestor(
|
stmt = tree.search_ancestor(
|
||||||
atom, 'expr_stmt', 'lambdef'
|
atom, 'expr_stmt', 'lambdef'
|
||||||
@@ -312,9 +305,6 @@ def infer_atom(context, atom):
|
|||||||
# For False/True/None
|
# For False/True/None
|
||||||
if atom.value in ('False', 'True', 'None'):
|
if atom.value in ('False', 'True', 'None'):
|
||||||
return ValueSet([compiled.builtin_from_name(state, atom.value)])
|
return ValueSet([compiled.builtin_from_name(state, atom.value)])
|
||||||
elif atom.value == 'print':
|
|
||||||
# print e.g. could be inferred like this in Python 2.7
|
|
||||||
return NO_VALUES
|
|
||||||
elif atom.value == 'yield':
|
elif atom.value == 'yield':
|
||||||
# Contrary to yield from, yield can just appear alone to return a
|
# Contrary to yield from, yield can just appear alone to return a
|
||||||
# value when used with `.send()`.
|
# value when used with `.send()`.
|
||||||
@@ -329,7 +319,7 @@ def infer_atom(context, atom):
|
|||||||
value_set = infer_atom(context, atom.children[0])
|
value_set = infer_atom(context, atom.children[0])
|
||||||
for string in atom.children[1:]:
|
for string in atom.children[1:]:
|
||||||
right = infer_atom(context, string)
|
right = infer_atom(context, string)
|
||||||
value_set = _infer_comparison(context, value_set, u'+', right)
|
value_set = _infer_comparison(context, value_set, '+', right)
|
||||||
return value_set
|
return value_set
|
||||||
elif atom.type == 'fstring':
|
elif atom.type == 'fstring':
|
||||||
return compiled.get_string_value_set(state)
|
return compiled.get_string_value_set(state)
|
||||||
@@ -567,7 +557,7 @@ def _is_tuple(value):
|
|||||||
|
|
||||||
|
|
||||||
def _bool_to_value(inference_state, bool_):
|
def _bool_to_value(inference_state, bool_):
|
||||||
return compiled.builtin_from_name(inference_state, force_unicode(str(bool_)))
|
return compiled.builtin_from_name(inference_state, str(bool_))
|
||||||
|
|
||||||
|
|
||||||
def _get_tuple_ints(value):
|
def _get_tuple_ints(value):
|
||||||
@@ -590,10 +580,10 @@ def _get_tuple_ints(value):
|
|||||||
def _infer_comparison_part(inference_state, context, left, operator, right):
|
def _infer_comparison_part(inference_state, context, left, operator, right):
|
||||||
l_is_num = is_number(left)
|
l_is_num = is_number(left)
|
||||||
r_is_num = is_number(right)
|
r_is_num = is_number(right)
|
||||||
if isinstance(operator, unicode):
|
if isinstance(operator, str):
|
||||||
str_operator = operator
|
str_operator = operator
|
||||||
else:
|
else:
|
||||||
str_operator = force_unicode(str(operator.value))
|
str_operator = str(operator.value)
|
||||||
|
|
||||||
if str_operator == '*':
|
if str_operator == '*':
|
||||||
# for iterables, ignore * operations
|
# for iterables, ignore * operations
|
||||||
@@ -747,7 +737,7 @@ def tree_name_to_values(inference_state, context, tree_name):
|
|||||||
types = infer_expr_stmt(context, node, tree_name)
|
types = infer_expr_stmt(context, node, tree_name)
|
||||||
elif typ == 'with_stmt':
|
elif typ == 'with_stmt':
|
||||||
value_managers = context.infer_node(node.get_test_node_from_name(tree_name))
|
value_managers = context.infer_node(node.get_test_node_from_name(tree_name))
|
||||||
enter_methods = value_managers.py__getattribute__(u'__enter__')
|
enter_methods = value_managers.py__getattribute__('__enter__')
|
||||||
return enter_methods.execute_with_values()
|
return enter_methods.execute_with_values()
|
||||||
elif typ in ('import_from', 'import_name'):
|
elif typ in ('import_from', 'import_name'):
|
||||||
types = imports.infer_import(context, tree_name)
|
types = imports.infer_import(context, tree_name)
|
||||||
@@ -861,8 +851,7 @@ def _infer_subscript_list(context, index):
|
|||||||
return ValueSet([iterable.Slice(context, None, None, None)])
|
return ValueSet([iterable.Slice(context, None, None, None)])
|
||||||
|
|
||||||
elif index.type == 'subscript' and not index.children[0] == '.':
|
elif index.type == 'subscript' and not index.children[0] == '.':
|
||||||
# subscript basically implies a slice operation, except for Python 2's
|
# subscript basically implies a slice operation
|
||||||
# Ellipsis.
|
|
||||||
# e.g. array[:3]
|
# e.g. array[:3]
|
||||||
result = []
|
result = []
|
||||||
for el in index.children:
|
for el in index.children:
|
||||||
|
|||||||
+26
-26
@@ -1,11 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from importlib.machinery import all_suffixes
|
||||||
|
|
||||||
from jedi._compatibility import unicode, force_unicode, all_suffixes
|
|
||||||
from jedi.inference.cache import inference_state_method_cache
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
from jedi.inference.base_value import ContextualizedNode
|
from jedi.inference.base_value import ContextualizedNode
|
||||||
from jedi.inference.helpers import is_string, get_str_or_none
|
from jedi.inference.helpers import is_string, get_str_or_none
|
||||||
from jedi.common import traverse_parents
|
|
||||||
from jedi.parser_utils import get_cached_code_lines
|
from jedi.parser_utils import get_cached_code_lines
|
||||||
from jedi.file_io import FileIO
|
from jedi.file_io import FileIO
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
@@ -14,8 +14,9 @@ from jedi import debug
|
|||||||
_BUILDOUT_PATH_INSERTION_LIMIT = 10
|
_BUILDOUT_PATH_INSERTION_LIMIT = 10
|
||||||
|
|
||||||
|
|
||||||
def _abs_path(module_context, path):
|
def _abs_path(module_context, path: str):
|
||||||
if os.path.isabs(path):
|
path = Path(path)
|
||||||
|
if path.is_absolute():
|
||||||
return path
|
return path
|
||||||
|
|
||||||
module_path = module_context.py__file__()
|
module_path = module_context.py__file__()
|
||||||
@@ -24,9 +25,8 @@ def _abs_path(module_context, path):
|
|||||||
# system.
|
# system.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
base_dir = os.path.dirname(module_path)
|
base_dir = module_path.parent
|
||||||
path = force_unicode(path)
|
return base_dir.joinpath(path).absolute()
|
||||||
return os.path.abspath(os.path.join(base_dir, path))
|
|
||||||
|
|
||||||
|
|
||||||
def _paths_from_assignment(module_context, expr_stmt):
|
def _paths_from_assignment(module_context, expr_stmt):
|
||||||
@@ -148,7 +148,7 @@ def discover_buildout_paths(inference_state, script_path):
|
|||||||
|
|
||||||
|
|
||||||
def _get_paths_from_buildout_script(inference_state, buildout_script_path):
|
def _get_paths_from_buildout_script(inference_state, buildout_script_path):
|
||||||
file_io = FileIO(buildout_script_path)
|
file_io = FileIO(str(buildout_script_path))
|
||||||
try:
|
try:
|
||||||
module_node = inference_state.parse(
|
module_node = inference_state.parse(
|
||||||
file_io=file_io,
|
file_io=file_io,
|
||||||
@@ -164,20 +164,20 @@ def _get_paths_from_buildout_script(inference_state, buildout_script_path):
|
|||||||
inference_state, module_node,
|
inference_state, module_node,
|
||||||
file_io=file_io,
|
file_io=file_io,
|
||||||
string_names=None,
|
string_names=None,
|
||||||
code_lines=get_cached_code_lines(inference_state.grammar, buildout_script_path),
|
code_lines=get_cached_code_lines(inference_state.grammar, str(buildout_script_path)),
|
||||||
).as_context()
|
).as_context()
|
||||||
for path in check_sys_path_modifications(module_context):
|
for path in check_sys_path_modifications(module_context):
|
||||||
yield path
|
yield path
|
||||||
|
|
||||||
|
|
||||||
def _get_parent_dir_with_file(path, filename):
|
def _get_parent_dir_with_file(path: Path, filename):
|
||||||
for parent in traverse_parents(path):
|
for parent in path.parents:
|
||||||
if os.path.isfile(os.path.join(parent, filename)):
|
if parent.joinpath(filename).is_file():
|
||||||
return parent
|
return parent
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _get_buildout_script_paths(search_path):
|
def _get_buildout_script_paths(search_path: Path):
|
||||||
"""
|
"""
|
||||||
if there is a 'buildout.cfg' file in one of the parent directories of the
|
if there is a 'buildout.cfg' file in one of the parent directories of the
|
||||||
given module it will return a list of all files in the buildout bin
|
given module it will return a list of all files in the buildout bin
|
||||||
@@ -189,13 +189,13 @@ def _get_buildout_script_paths(search_path):
|
|||||||
project_root = _get_parent_dir_with_file(search_path, 'buildout.cfg')
|
project_root = _get_parent_dir_with_file(search_path, 'buildout.cfg')
|
||||||
if not project_root:
|
if not project_root:
|
||||||
return
|
return
|
||||||
bin_path = os.path.join(project_root, 'bin')
|
bin_path = project_root.joinpath('bin')
|
||||||
if not os.path.exists(bin_path):
|
if not bin_path.exists():
|
||||||
return
|
return
|
||||||
|
|
||||||
for filename in os.listdir(bin_path):
|
for filename in os.listdir(bin_path):
|
||||||
try:
|
try:
|
||||||
filepath = os.path.join(bin_path, filename)
|
filepath = bin_path.joinpath(filename)
|
||||||
with open(filepath, 'r') as f:
|
with open(filepath, 'r') as f:
|
||||||
firstline = f.readline()
|
firstline = f.readline()
|
||||||
if firstline.startswith('#!') and 'python' in firstline:
|
if firstline.startswith('#!') and 'python' in firstline:
|
||||||
@@ -203,14 +203,14 @@ def _get_buildout_script_paths(search_path):
|
|||||||
except (UnicodeDecodeError, IOError) as e:
|
except (UnicodeDecodeError, IOError) as e:
|
||||||
# Probably a binary file; permission error or race cond. because
|
# Probably a binary file; permission error or race cond. because
|
||||||
# file got deleted. Ignore it.
|
# file got deleted. Ignore it.
|
||||||
debug.warning(unicode(e))
|
debug.warning(e)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
def remove_python_path_suffix(path):
|
def remove_python_path_suffix(path):
|
||||||
for suffix in all_suffixes() + ['.pyi']:
|
for suffix in all_suffixes() + ['.pyi']:
|
||||||
if path.endswith(suffix):
|
if path.suffix == suffix:
|
||||||
path = path[:-len(suffix)]
|
path = path.with_name(path.stem)
|
||||||
break
|
break
|
||||||
return path
|
return path
|
||||||
|
|
||||||
@@ -219,8 +219,7 @@ def transform_path_to_dotted(sys_path, module_path):
|
|||||||
"""
|
"""
|
||||||
Returns the dotted path inside a sys.path as a list of names. e.g.
|
Returns the dotted path inside a sys.path as a list of names. e.g.
|
||||||
|
|
||||||
>>> from os.path import abspath
|
>>> transform_path_to_dotted([str(Path("/foo").absolute())], Path('/foo/bar/baz.py').absolute())
|
||||||
>>> transform_path_to_dotted([abspath("/foo")], abspath('/foo/bar/baz.py'))
|
|
||||||
(('bar', 'baz'), False)
|
(('bar', 'baz'), False)
|
||||||
|
|
||||||
Returns (None, False) if the path doesn't really resolve to anything.
|
Returns (None, False) if the path doesn't really resolve to anything.
|
||||||
@@ -228,21 +227,22 @@ def transform_path_to_dotted(sys_path, module_path):
|
|||||||
"""
|
"""
|
||||||
# First remove the suffix.
|
# First remove the suffix.
|
||||||
module_path = remove_python_path_suffix(module_path)
|
module_path = remove_python_path_suffix(module_path)
|
||||||
|
if module_path.name.startswith('.'):
|
||||||
|
return None, False
|
||||||
|
|
||||||
# Once the suffix was removed we are using the files as we know them. This
|
# Once the suffix was removed we are using the files as we know them. This
|
||||||
# means that if someone uses an ending like .vim for a Python file, .vim
|
# means that if someone uses an ending like .vim for a Python file, .vim
|
||||||
# will be part of the returned dotted part.
|
# will be part of the returned dotted part.
|
||||||
|
|
||||||
is_package = module_path.endswith(os.path.sep + '__init__')
|
is_package = module_path.name == '__init__'
|
||||||
if is_package:
|
if is_package:
|
||||||
# -1 to remove the separator
|
module_path = module_path.parent
|
||||||
module_path = module_path[:-len('__init__') - 1]
|
|
||||||
|
|
||||||
def iter_potential_solutions():
|
def iter_potential_solutions():
|
||||||
for p in sys_path:
|
for p in sys_path:
|
||||||
if module_path.startswith(p):
|
if str(module_path).startswith(p):
|
||||||
# Strip the trailing slash/backslash
|
# Strip the trailing slash/backslash
|
||||||
rest = module_path[len(p):]
|
rest = str(module_path)[len(p):]
|
||||||
# On Windows a path can also use a slash.
|
# On Windows a path can also use a slash.
|
||||||
if rest.startswith(os.path.sep) or rest.startswith('/'):
|
if rest.startswith(os.path.sep) or rest.startswith('/'):
|
||||||
# Remove a slash in cases it's still there.
|
# Remove a slash in cases it's still there.
|
||||||
|
|||||||
+2
-27
@@ -1,12 +1,8 @@
|
|||||||
""" A universal module with functions / classes without dependencies. """
|
""" A universal module with functions / classes without dependencies. """
|
||||||
import sys
|
|
||||||
import contextlib
|
|
||||||
import functools
|
import functools
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from jedi._compatibility import reraise
|
|
||||||
|
|
||||||
|
|
||||||
_sep = os.path.sep
|
_sep = os.path.sep
|
||||||
if os.path.altsep is not None:
|
if os.path.altsep is not None:
|
||||||
@@ -36,7 +32,6 @@ class UncaughtAttributeError(Exception):
|
|||||||
"""
|
"""
|
||||||
Important, because `__getattr__` and `hasattr` catch AttributeErrors
|
Important, because `__getattr__` and `hasattr` catch AttributeErrors
|
||||||
implicitly. This is really evil (mainly because of `__getattr__`).
|
implicitly. This is really evil (mainly because of `__getattr__`).
|
||||||
`hasattr` in Python 2 is even more evil, because it catches ALL exceptions.
|
|
||||||
Therefore this class originally had to be derived from `BaseException`
|
Therefore this class originally had to be derived from `BaseException`
|
||||||
instead of `Exception`. But because I removed relevant `hasattr` from
|
instead of `Exception`. But because I removed relevant `hasattr` from
|
||||||
the code base, we can now switch back to `Exception`.
|
the code base, we can now switch back to `Exception`.
|
||||||
@@ -65,17 +60,13 @@ def reraise_uncaught(func):
|
|||||||
difficult. This decorator is to help us getting there by changing
|
difficult. This decorator is to help us getting there by changing
|
||||||
`AttributeError` to `UncaughtAttributeError` to avoid unexpected catch.
|
`AttributeError` to `UncaughtAttributeError` to avoid unexpected catch.
|
||||||
This helps us noticing bugs earlier and facilitates debugging.
|
This helps us noticing bugs earlier and facilitates debugging.
|
||||||
|
|
||||||
.. note:: Treating StopIteration here is easy.
|
|
||||||
Add that feature when needed.
|
|
||||||
"""
|
"""
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def wrapper(*args, **kwds):
|
def wrapper(*args, **kwds):
|
||||||
try:
|
try:
|
||||||
return func(*args, **kwds)
|
return func(*args, **kwds)
|
||||||
except AttributeError:
|
except AttributeError as e:
|
||||||
exc_info = sys.exc_info()
|
raise UncaughtAttributeError(e) from e
|
||||||
reraise(UncaughtAttributeError(exc_info[1]), exc_info[2])
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
@@ -91,25 +82,9 @@ class PushBackIterator(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def next(self):
|
|
||||||
""" Python 2 Compatibility """
|
|
||||||
return self.__next__()
|
|
||||||
|
|
||||||
def __next__(self):
|
def __next__(self):
|
||||||
if self.pushes:
|
if self.pushes:
|
||||||
self.current = self.pushes.pop()
|
self.current = self.pushes.pop()
|
||||||
else:
|
else:
|
||||||
self.current = next(self.iterator)
|
self.current = next(self.iterator)
|
||||||
return self.current
|
return self.current
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def ignored(*exceptions):
|
|
||||||
"""
|
|
||||||
Value manager that ignores all of the specified exceptions. This will
|
|
||||||
be in the standard library starting with Python 3.5.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
except exceptions:
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from jedi.inference.base_value import ValueWrapper, ValueSet
|
|||||||
|
|
||||||
class Decoratee(ValueWrapper):
|
class Decoratee(ValueWrapper):
|
||||||
def __init__(self, wrapped_value, original_value):
|
def __init__(self, wrapped_value, original_value):
|
||||||
super(Decoratee, self).__init__(wrapped_value)
|
super().__init__(wrapped_value)
|
||||||
self._original_value = original_value
|
self._original_value = original_value
|
||||||
|
|
||||||
def py__doc__(self):
|
def py__doc__(self):
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ class _DynamicArrayAdditions(HelperValueMixin):
|
|||||||
|
|
||||||
class _Modification(ValueWrapper):
|
class _Modification(ValueWrapper):
|
||||||
def __init__(self, wrapped_value, assigned_values, contextualized_key):
|
def __init__(self, wrapped_value, assigned_values, contextualized_key):
|
||||||
super(_Modification, self).__init__(wrapped_value)
|
super().__init__(wrapped_value)
|
||||||
self._assigned_values = assigned_values
|
self._assigned_values = assigned_values
|
||||||
self._contextualized_key = contextualized_key
|
self._contextualized_key = contextualized_key
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
from jedi._compatibility import use_metaclass
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass
|
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass
|
||||||
from jedi.inference import compiled
|
from jedi.inference import compiled
|
||||||
@@ -26,7 +25,7 @@ from jedi.inference.gradual.generics import TupleGenericManager
|
|||||||
|
|
||||||
class LambdaName(AbstractNameDefinition):
|
class LambdaName(AbstractNameDefinition):
|
||||||
string_name = '<lambda>'
|
string_name = '<lambda>'
|
||||||
api_type = u'function'
|
api_type = 'function'
|
||||||
|
|
||||||
def __init__(self, lambda_value):
|
def __init__(self, lambda_value):
|
||||||
self._lambda_value = lambda_value
|
self._lambda_value = lambda_value
|
||||||
@@ -55,7 +54,7 @@ class FunctionAndClassBase(TreeValue):
|
|||||||
|
|
||||||
|
|
||||||
class FunctionMixin(object):
|
class FunctionMixin(object):
|
||||||
api_type = u'function'
|
api_type = 'function'
|
||||||
|
|
||||||
def get_filters(self, origin_scope=None):
|
def get_filters(self, origin_scope=None):
|
||||||
cls = self.py__class__()
|
cls = self.py__class__()
|
||||||
@@ -126,7 +125,7 @@ class FunctionMixin(object):
|
|||||||
return [TreeSignature(f) for f in self.get_signature_functions()]
|
return [TreeSignature(f) for f in self.get_signature_functions()]
|
||||||
|
|
||||||
|
|
||||||
class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndClassBase)):
|
class FunctionValue(FunctionMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_context(cls, context, tree_node):
|
def from_context(cls, context, tree_node):
|
||||||
def create(tree_node):
|
def create(tree_node):
|
||||||
@@ -161,7 +160,7 @@ class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndCla
|
|||||||
return function
|
return function
|
||||||
|
|
||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
c, = values_from_qualified_names(self.inference_state, u'types', u'FunctionType')
|
c, = values_from_qualified_names(self.inference_state, 'types', 'FunctionType')
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def get_default_param_context(self):
|
def get_default_param_context(self):
|
||||||
@@ -173,7 +172,7 @@ class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndCla
|
|||||||
|
|
||||||
class FunctionNameInClass(NameWrapper):
|
class FunctionNameInClass(NameWrapper):
|
||||||
def __init__(self, class_context, name):
|
def __init__(self, class_context, name):
|
||||||
super(FunctionNameInClass, self).__init__(name)
|
super().__init__(name)
|
||||||
self._class_context = class_context
|
self._class_context = class_context
|
||||||
|
|
||||||
def get_defining_qualified_value(self):
|
def get_defining_qualified_value(self):
|
||||||
@@ -182,7 +181,7 @@ class FunctionNameInClass(NameWrapper):
|
|||||||
|
|
||||||
class MethodValue(FunctionValue):
|
class MethodValue(FunctionValue):
|
||||||
def __init__(self, inference_state, class_context, *args, **kwargs):
|
def __init__(self, inference_state, class_context, *args, **kwargs):
|
||||||
super(MethodValue, self).__init__(inference_state, *args, **kwargs)
|
super().__init__(inference_state, *args, **kwargs)
|
||||||
self.class_context = class_context
|
self.class_context = class_context
|
||||||
|
|
||||||
def get_default_param_context(self):
|
def get_default_param_context(self):
|
||||||
@@ -198,7 +197,7 @@ class MethodValue(FunctionValue):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return FunctionNameInClass(self.class_context, super(MethodValue, self).name)
|
return FunctionNameInClass(self.class_context, super().name)
|
||||||
|
|
||||||
|
|
||||||
class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
||||||
@@ -238,7 +237,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
|||||||
try:
|
try:
|
||||||
children = r.children
|
children = r.children
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
ctx = compiled.builtin_from_name(self.inference_state, u'None')
|
ctx = compiled.builtin_from_name(self.inference_state, 'None')
|
||||||
value_set |= ValueSet([ctx])
|
value_set |= ValueSet([ctx])
|
||||||
else:
|
else:
|
||||||
value_set |= self.infer_node(children[1])
|
value_set |= self.infer_node(children[1])
|
||||||
@@ -250,7 +249,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
|||||||
def _get_yield_lazy_value(self, yield_expr):
|
def _get_yield_lazy_value(self, yield_expr):
|
||||||
if yield_expr.type == 'keyword':
|
if yield_expr.type == 'keyword':
|
||||||
# `yield` just yields None.
|
# `yield` just yields None.
|
||||||
ctx = compiled.builtin_from_name(self.inference_state, u'None')
|
ctx = compiled.builtin_from_name(self.inference_state, 'None')
|
||||||
yield LazyKnownValue(ctx)
|
yield LazyKnownValue(ctx)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -330,8 +329,6 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
|||||||
|
|
||||||
if is_coroutine:
|
if is_coroutine:
|
||||||
if self.is_generator():
|
if self.is_generator():
|
||||||
if inference_state.environment.version_info < (3, 6):
|
|
||||||
return NO_VALUES
|
|
||||||
async_generator_classes = inference_state.typing_module \
|
async_generator_classes = inference_state.typing_module \
|
||||||
.py__getattribute__('AsyncGenerator')
|
.py__getattribute__('AsyncGenerator')
|
||||||
|
|
||||||
@@ -339,13 +336,10 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
|||||||
# The contravariant doesn't seem to be defined.
|
# The contravariant doesn't seem to be defined.
|
||||||
generics = (yield_values.py__class__(), NO_VALUES)
|
generics = (yield_values.py__class__(), NO_VALUES)
|
||||||
return ValueSet(
|
return ValueSet(
|
||||||
# In Python 3.6 AsyncGenerator is still a class.
|
|
||||||
GenericClass(c, TupleGenericManager(generics))
|
GenericClass(c, TupleGenericManager(generics))
|
||||||
for c in async_generator_classes
|
for c in async_generator_classes
|
||||||
).execute_annotation()
|
).execute_annotation()
|
||||||
else:
|
else:
|
||||||
if inference_state.environment.version_info < (3, 5):
|
|
||||||
return NO_VALUES
|
|
||||||
async_classes = inference_state.typing_module.py__getattribute__('Coroutine')
|
async_classes = inference_state.typing_module.py__getattribute__('Coroutine')
|
||||||
return_values = self.get_return_values()
|
return_values = self.get_return_values()
|
||||||
# Only the first generic is relevant.
|
# Only the first generic is relevant.
|
||||||
@@ -362,7 +356,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
|||||||
|
|
||||||
class FunctionExecutionContext(BaseFunctionExecutionContext):
|
class FunctionExecutionContext(BaseFunctionExecutionContext):
|
||||||
def __init__(self, function_value, arguments):
|
def __init__(self, function_value, arguments):
|
||||||
super(FunctionExecutionContext, self).__init__(function_value)
|
super().__init__(function_value)
|
||||||
self._arguments = arguments
|
self._arguments = arguments
|
||||||
|
|
||||||
def get_filters(self, until_position=None, origin_scope=None):
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
@@ -403,7 +397,7 @@ class AnonymousFunctionExecution(BaseFunctionExecutionContext):
|
|||||||
|
|
||||||
class OverloadedFunctionValue(FunctionMixin, ValueWrapper):
|
class OverloadedFunctionValue(FunctionMixin, ValueWrapper):
|
||||||
def __init__(self, function, overloaded_functions):
|
def __init__(self, function, overloaded_functions):
|
||||||
super(OverloadedFunctionValue, self).__init__(function)
|
super().__init__(function)
|
||||||
self._overloaded_functions = overloaded_functions
|
self._overloaded_functions = overloaded_functions
|
||||||
|
|
||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from jedi.parser_utils import function_is_staticmethod, function_is_classmethod
|
|||||||
|
|
||||||
class InstanceExecutedParamName(ParamName):
|
class InstanceExecutedParamName(ParamName):
|
||||||
def __init__(self, instance, function_value, tree_name):
|
def __init__(self, instance, function_value, tree_name):
|
||||||
super(InstanceExecutedParamName, self).__init__(
|
super().__init__(
|
||||||
function_value, tree_name, arguments=None)
|
function_value, tree_name, arguments=None)
|
||||||
self._instance = instance
|
self._instance = instance
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ class InstanceExecutedParamName(ParamName):
|
|||||||
|
|
||||||
class AnonymousMethodExecutionFilter(AnonymousFunctionExecutionFilter):
|
class AnonymousMethodExecutionFilter(AnonymousFunctionExecutionFilter):
|
||||||
def __init__(self, instance, *args, **kwargs):
|
def __init__(self, instance, *args, **kwargs):
|
||||||
super(AnonymousMethodExecutionFilter, self).__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._instance = instance
|
self._instance = instance
|
||||||
|
|
||||||
def _convert_param(self, param, name):
|
def _convert_param(self, param, name):
|
||||||
@@ -55,12 +55,12 @@ class AnonymousMethodExecutionFilter(AnonymousFunctionExecutionFilter):
|
|||||||
self._function_value,
|
self._function_value,
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
return super(AnonymousMethodExecutionFilter, self)._convert_param(param, name)
|
return super()._convert_param(param, name)
|
||||||
|
|
||||||
|
|
||||||
class AnonymousMethodExecutionContext(BaseFunctionExecutionContext):
|
class AnonymousMethodExecutionContext(BaseFunctionExecutionContext):
|
||||||
def __init__(self, instance, value):
|
def __init__(self, instance, value):
|
||||||
super(AnonymousMethodExecutionContext, self).__init__(value)
|
super().__init__(value)
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
|
|
||||||
def get_filters(self, until_position=None, origin_scope=None):
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
@@ -83,15 +83,15 @@ class AnonymousMethodExecutionContext(BaseFunctionExecutionContext):
|
|||||||
|
|
||||||
class MethodExecutionContext(FunctionExecutionContext):
|
class MethodExecutionContext(FunctionExecutionContext):
|
||||||
def __init__(self, instance, *args, **kwargs):
|
def __init__(self, instance, *args, **kwargs):
|
||||||
super(MethodExecutionContext, self).__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
|
|
||||||
|
|
||||||
class AbstractInstanceValue(Value):
|
class AbstractInstanceValue(Value):
|
||||||
api_type = u'instance'
|
api_type = 'instance'
|
||||||
|
|
||||||
def __init__(self, inference_state, parent_context, class_value):
|
def __init__(self, inference_state, parent_context, class_value):
|
||||||
super(AbstractInstanceValue, self).__init__(inference_state, parent_context)
|
super().__init__(inference_state, parent_context)
|
||||||
# Generated instances are classes that are just generated by self
|
# Generated instances are classes that are just generated by self
|
||||||
# (No arguments) used.
|
# (No arguments) used.
|
||||||
self.class_value = class_value
|
self.class_value = class_value
|
||||||
@@ -141,8 +141,7 @@ class CompiledInstance(AbstractInstanceValue):
|
|||||||
# This is not really a compiled class, it's just an instance from a
|
# This is not really a compiled class, it's just an instance from a
|
||||||
# compiled class.
|
# compiled class.
|
||||||
def __init__(self, inference_state, parent_context, class_value, arguments):
|
def __init__(self, inference_state, parent_context, class_value, arguments):
|
||||||
super(CompiledInstance, self).__init__(inference_state, parent_context,
|
super().__init__(inference_state, parent_context, class_value)
|
||||||
class_value)
|
|
||||||
self._arguments = arguments
|
self._arguments = arguments
|
||||||
|
|
||||||
def get_filters(self, origin_scope=None, include_self_names=True):
|
def get_filters(self, origin_scope=None, include_self_names=True):
|
||||||
@@ -234,14 +233,14 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
|||||||
# other way around.
|
# other way around.
|
||||||
if is_big_annoying_library(self.parent_context):
|
if is_big_annoying_library(self.parent_context):
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
names = (self.get_function_slot_names(u'__getattr__')
|
names = (self.get_function_slot_names('__getattr__')
|
||||||
or self.get_function_slot_names(u'__getattribute__'))
|
or self.get_function_slot_names('__getattribute__'))
|
||||||
return self.execute_function_slots(names, name)
|
return self.execute_function_slots(names, name)
|
||||||
|
|
||||||
def py__getitem__(self, index_value_set, contextualized_node):
|
def py__getitem__(self, index_value_set, contextualized_node):
|
||||||
names = self.get_function_slot_names(u'__getitem__')
|
names = self.get_function_slot_names('__getitem__')
|
||||||
if not names:
|
if not names:
|
||||||
return super(_BaseTreeInstance, self).py__getitem__(
|
return super().py__getitem__(
|
||||||
index_value_set,
|
index_value_set,
|
||||||
contextualized_node,
|
contextualized_node,
|
||||||
)
|
)
|
||||||
@@ -250,9 +249,9 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
|||||||
return ValueSet.from_sets(name.infer().execute(args) for name in names)
|
return ValueSet.from_sets(name.infer().execute(args) for name in names)
|
||||||
|
|
||||||
def py__iter__(self, contextualized_node=None):
|
def py__iter__(self, contextualized_node=None):
|
||||||
iter_slot_names = self.get_function_slot_names(u'__iter__')
|
iter_slot_names = self.get_function_slot_names('__iter__')
|
||||||
if not iter_slot_names:
|
if not iter_slot_names:
|
||||||
return super(_BaseTreeInstance, self).py__iter__(contextualized_node)
|
return super().py__iter__(contextualized_node)
|
||||||
|
|
||||||
def iterate():
|
def iterate():
|
||||||
for generator in self.execute_function_slots(iter_slot_names):
|
for generator in self.execute_function_slots(iter_slot_names):
|
||||||
@@ -261,11 +260,7 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
|||||||
return iterate()
|
return iterate()
|
||||||
|
|
||||||
def py__next__(self, contextualized_node=None):
|
def py__next__(self, contextualized_node=None):
|
||||||
# `__next__` logic.
|
name = u'__next__'
|
||||||
if self.inference_state.environment.version_info.major == 2:
|
|
||||||
name = u'next'
|
|
||||||
else:
|
|
||||||
name = u'__next__'
|
|
||||||
next_slot_names = self.get_function_slot_names(name)
|
next_slot_names = self.get_function_slot_names(name)
|
||||||
if next_slot_names:
|
if next_slot_names:
|
||||||
yield LazyKnownValues(
|
yield LazyKnownValues(
|
||||||
@@ -275,10 +270,10 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
|||||||
debug.warning('Instance has no __next__ function in %s.', self)
|
debug.warning('Instance has no __next__ function in %s.', self)
|
||||||
|
|
||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
names = self.get_function_slot_names(u'__call__')
|
names = self.get_function_slot_names('__call__')
|
||||||
if not names:
|
if not names:
|
||||||
# Means the Instance is not callable.
|
# Means the Instance is not callable.
|
||||||
return super(_BaseTreeInstance, self).py__call__(arguments)
|
return super().py__call__(arguments)
|
||||||
|
|
||||||
return ValueSet.from_sets(name.infer().execute(arguments) for name in names)
|
return ValueSet.from_sets(name.infer().execute(arguments) for name in names)
|
||||||
|
|
||||||
@@ -293,10 +288,10 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
|||||||
if result is not NotImplemented:
|
if result is not NotImplemented:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
names = self.get_function_slot_names(u'__get__')
|
names = self.get_function_slot_names('__get__')
|
||||||
if names:
|
if names:
|
||||||
if instance is None:
|
if instance is None:
|
||||||
instance = compiled.builtin_from_name(self.inference_state, u'None')
|
instance = compiled.builtin_from_name(self.inference_state, 'None')
|
||||||
return self.execute_function_slots(names, instance, class_value)
|
return self.execute_function_slots(names, instance, class_value)
|
||||||
else:
|
else:
|
||||||
return ValueSet([self])
|
return ValueSet([self])
|
||||||
@@ -322,7 +317,7 @@ class TreeInstance(_BaseTreeInstance):
|
|||||||
if settings.dynamic_array_additions:
|
if settings.dynamic_array_additions:
|
||||||
arguments = get_dynamic_array_instance(self, arguments)
|
arguments = get_dynamic_array_instance(self, arguments)
|
||||||
|
|
||||||
super(TreeInstance, self).__init__(inference_state, parent_context, class_value)
|
super().__init__(inference_state, parent_context, class_value)
|
||||||
self._arguments = arguments
|
self._arguments = arguments
|
||||||
self.tree_node = class_value.tree_node
|
self.tree_node = class_value.tree_node
|
||||||
|
|
||||||
@@ -396,7 +391,7 @@ class TreeInstance(_BaseTreeInstance):
|
|||||||
else:
|
else:
|
||||||
if key == index:
|
if key == index:
|
||||||
return lazy_context.infer()
|
return lazy_context.infer()
|
||||||
return super(TreeInstance, self).py__simple_getitem__(index)
|
return super().py__simple_getitem__(index)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_value,
|
return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_value,
|
||||||
@@ -411,7 +406,7 @@ class CompiledInstanceName(compiled.CompiledName):
|
|||||||
def __init__(self, inference_state, instance, klass, name):
|
def __init__(self, inference_state, instance, klass, name):
|
||||||
parent_value = klass.parent_context.get_value()
|
parent_value = klass.parent_context.get_value()
|
||||||
assert parent_value is not None, "How? Please reproduce and report"
|
assert parent_value is not None, "How? Please reproduce and report"
|
||||||
super(CompiledInstanceName, self).__init__(
|
super().__init__(
|
||||||
inference_state,
|
inference_state,
|
||||||
parent_value,
|
parent_value,
|
||||||
name.string_name
|
name.string_name
|
||||||
@@ -449,7 +444,7 @@ class CompiledInstanceClassFilter(AbstractFilter):
|
|||||||
|
|
||||||
class BoundMethod(FunctionMixin, ValueWrapper):
|
class BoundMethod(FunctionMixin, ValueWrapper):
|
||||||
def __init__(self, instance, class_context, function):
|
def __init__(self, instance, class_context, function):
|
||||||
super(BoundMethod, self).__init__(function)
|
super().__init__(function)
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
self._class_context = class_context
|
self._class_context = class_context
|
||||||
|
|
||||||
@@ -460,11 +455,11 @@ class BoundMethod(FunctionMixin, ValueWrapper):
|
|||||||
def name(self):
|
def name(self):
|
||||||
return FunctionNameInClass(
|
return FunctionNameInClass(
|
||||||
self._class_context,
|
self._class_context,
|
||||||
super(BoundMethod, self).name
|
super().name
|
||||||
)
|
)
|
||||||
|
|
||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
c, = values_from_qualified_names(self.inference_state, u'types', u'MethodType')
|
c, = values_from_qualified_names(self.inference_state, 'types', 'MethodType')
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def _get_arguments(self, arguments):
|
def _get_arguments(self, arguments):
|
||||||
@@ -492,7 +487,7 @@ class BoundMethod(FunctionMixin, ValueWrapper):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def get_signatures(self):
|
def get_signatures(self):
|
||||||
return [sig.bind(self) for sig in super(BoundMethod, self).get_signatures()]
|
return [sig.bind(self) for sig in super().get_signatures()]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (self.__class__.__name__, self._wrapped_value)
|
return '<%s: %s>' % (self.__class__.__name__, self._wrapped_value)
|
||||||
@@ -525,7 +520,7 @@ class SelfName(TreeNameDefinition):
|
|||||||
|
|
||||||
class LazyInstanceClassName(NameWrapper):
|
class LazyInstanceClassName(NameWrapper):
|
||||||
def __init__(self, instance, class_member_name):
|
def __init__(self, instance, class_member_name):
|
||||||
super(LazyInstanceClassName, self).__init__(class_member_name)
|
super().__init__(class_member_name)
|
||||||
self._instance = instance
|
self._instance = instance
|
||||||
|
|
||||||
@iterator_to_value_set
|
@iterator_to_value_set
|
||||||
@@ -572,7 +567,7 @@ class SelfAttributeFilter(ClassFilter):
|
|||||||
This class basically filters all the use cases where `self.*` was assigned.
|
This class basically filters all the use cases where `self.*` was assigned.
|
||||||
"""
|
"""
|
||||||
def __init__(self, instance, instance_class, node_context, origin_scope):
|
def __init__(self, instance, instance_class, node_context, origin_scope):
|
||||||
super(SelfAttributeFilter, self).__init__(
|
super().__init__(
|
||||||
class_value=instance_class,
|
class_value=instance_class,
|
||||||
node_context=node_context,
|
node_context=node_context,
|
||||||
origin_scope=origin_scope,
|
origin_scope=origin_scope,
|
||||||
@@ -616,7 +611,7 @@ class SelfAttributeFilter(ClassFilter):
|
|||||||
|
|
||||||
class InstanceArguments(TreeArgumentsWrapper):
|
class InstanceArguments(TreeArgumentsWrapper):
|
||||||
def __init__(self, instance, arguments):
|
def __init__(self, instance, arguments):
|
||||||
super(InstanceArguments, self).__init__(arguments)
|
super().__init__(arguments)
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
|
|
||||||
def unpack(self, func=None):
|
def unpack(self, func=None):
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
Contains all classes and functions to deal with lists, dicts, generators and
|
Contains all classes and functions to deal with lists, dicts, generators and
|
||||||
iterators in general.
|
iterators in general.
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
|
|
||||||
from jedi._compatibility import force_unicode, is_py3
|
|
||||||
from jedi.inference import compiled
|
from jedi.inference import compiled
|
||||||
from jedi.inference import analysis
|
from jedi.inference import analysis
|
||||||
from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues, \
|
from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues, \
|
||||||
@@ -27,7 +24,7 @@ class IterableMixin(object):
|
|||||||
return self.py__iter__(contextualized_node)
|
return self.py__iter__(contextualized_node)
|
||||||
|
|
||||||
def py__stop_iteration_returns(self):
|
def py__stop_iteration_returns(self):
|
||||||
return ValueSet([compiled.builtin_from_name(self.inference_state, u'None')])
|
return ValueSet([compiled.builtin_from_name(self.inference_state, 'None')])
|
||||||
|
|
||||||
# At the moment, safe values are simple values like "foo", 1 and not
|
# At the moment, safe values are simple values like "foo", 1 and not
|
||||||
# lists/dicts. Therefore as a small speed optimization we can just do the
|
# lists/dicts. Therefore as a small speed optimization we can just do the
|
||||||
@@ -35,14 +32,7 @@ class IterableMixin(object):
|
|||||||
# doing this in the end as well.
|
# doing this in the end as well.
|
||||||
# This mostly speeds up patterns like `sys.version_info >= (3, 0)` in
|
# This mostly speeds up patterns like `sys.version_info >= (3, 0)` in
|
||||||
# typeshed.
|
# typeshed.
|
||||||
if sys.version_info[0] == 2:
|
get_safe_value = Value.get_safe_value
|
||||||
# Python 2...........
|
|
||||||
def get_safe_value(self, default=sentinel):
|
|
||||||
if default is sentinel:
|
|
||||||
raise ValueError("There exists no safe value for value %s" % self)
|
|
||||||
return default
|
|
||||||
else:
|
|
||||||
get_safe_value = Value.get_safe_value
|
|
||||||
|
|
||||||
|
|
||||||
class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
|
class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
|
||||||
@@ -64,13 +54,12 @@ class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
|
|||||||
return ValueSet([self])
|
return ValueSet([self])
|
||||||
|
|
||||||
@publish_method('send')
|
@publish_method('send')
|
||||||
@publish_method('next', python_version_match=2)
|
@publish_method('__next__')
|
||||||
@publish_method('__next__', python_version_match=3)
|
|
||||||
def _next(self, arguments):
|
def _next(self, arguments):
|
||||||
return ValueSet.from_sets(lazy_value.infer() for lazy_value in self.py__iter__())
|
return ValueSet.from_sets(lazy_value.infer() for lazy_value in self.py__iter__())
|
||||||
|
|
||||||
def py__stop_iteration_returns(self):
|
def py__stop_iteration_returns(self):
|
||||||
return ValueSet([compiled.builtin_from_name(self.inference_state, u'None')])
|
return ValueSet([compiled.builtin_from_name(self.inference_state, 'None')])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -86,7 +75,7 @@ class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
|
|||||||
class Generator(GeneratorBase):
|
class Generator(GeneratorBase):
|
||||||
"""Handling of `yield` functions."""
|
"""Handling of `yield` functions."""
|
||||||
def __init__(self, inference_state, func_execution_context):
|
def __init__(self, inference_state, func_execution_context):
|
||||||
super(Generator, self).__init__(inference_state)
|
super().__init__(inference_state)
|
||||||
self._func_execution_context = func_execution_context
|
self._func_execution_context = func_execution_context
|
||||||
|
|
||||||
def py__iter__(self, contextualized_node=None):
|
def py__iter__(self, contextualized_node=None):
|
||||||
@@ -194,7 +183,7 @@ class _DictMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
class Sequence(LazyAttributeOverwrite, IterableMixin):
|
class Sequence(LazyAttributeOverwrite, IterableMixin):
|
||||||
api_type = u'instance'
|
api_type = 'instance'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -233,14 +222,14 @@ class Sequence(LazyAttributeOverwrite, IterableMixin):
|
|||||||
class _BaseComprehension(ComprehensionMixin):
|
class _BaseComprehension(ComprehensionMixin):
|
||||||
def __init__(self, inference_state, defining_context, sync_comp_for_node, entry_node):
|
def __init__(self, inference_state, defining_context, sync_comp_for_node, entry_node):
|
||||||
assert sync_comp_for_node.type == 'sync_comp_for'
|
assert sync_comp_for_node.type == 'sync_comp_for'
|
||||||
super(_BaseComprehension, self).__init__(inference_state)
|
super().__init__(inference_state)
|
||||||
self._defining_context = defining_context
|
self._defining_context = defining_context
|
||||||
self._sync_comp_for_node = sync_comp_for_node
|
self._sync_comp_for_node = sync_comp_for_node
|
||||||
self._entry_node = entry_node
|
self._entry_node = entry_node
|
||||||
|
|
||||||
|
|
||||||
class ListComprehension(_BaseComprehension, Sequence):
|
class ListComprehension(_BaseComprehension, Sequence):
|
||||||
array_type = u'list'
|
array_type = 'list'
|
||||||
|
|
||||||
def py__simple_getitem__(self, index):
|
def py__simple_getitem__(self, index):
|
||||||
if isinstance(index, slice):
|
if isinstance(index, slice):
|
||||||
@@ -253,7 +242,7 @@ class ListComprehension(_BaseComprehension, Sequence):
|
|||||||
|
|
||||||
|
|
||||||
class SetComprehension(_BaseComprehension, Sequence):
|
class SetComprehension(_BaseComprehension, Sequence):
|
||||||
array_type = u'set'
|
array_type = 'set'
|
||||||
|
|
||||||
|
|
||||||
class GeneratorComprehension(_BaseComprehension, GeneratorBase):
|
class GeneratorComprehension(_BaseComprehension, GeneratorBase):
|
||||||
@@ -271,11 +260,11 @@ class _DictKeyMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
class DictComprehension(ComprehensionMixin, Sequence, _DictKeyMixin):
|
class DictComprehension(ComprehensionMixin, Sequence, _DictKeyMixin):
|
||||||
array_type = u'dict'
|
array_type = 'dict'
|
||||||
|
|
||||||
def __init__(self, inference_state, defining_context, sync_comp_for_node, key_node, value_node):
|
def __init__(self, inference_state, defining_context, sync_comp_for_node, key_node, value_node):
|
||||||
assert sync_comp_for_node.type == 'sync_comp_for'
|
assert sync_comp_for_node.type == 'sync_comp_for'
|
||||||
super(DictComprehension, self).__init__(inference_state)
|
super().__init__(inference_state)
|
||||||
self._defining_context = defining_context
|
self._defining_context = defining_context
|
||||||
self._sync_comp_for_node = sync_comp_for_node
|
self._sync_comp_for_node = sync_comp_for_node
|
||||||
self._entry_node = key_node
|
self._entry_node = key_node
|
||||||
@@ -328,25 +317,25 @@ class DictComprehension(ComprehensionMixin, Sequence, _DictKeyMixin):
|
|||||||
|
|
||||||
class SequenceLiteralValue(Sequence):
|
class SequenceLiteralValue(Sequence):
|
||||||
_TUPLE_LIKE = 'testlist_star_expr', 'testlist', 'subscriptlist'
|
_TUPLE_LIKE = 'testlist_star_expr', 'testlist', 'subscriptlist'
|
||||||
mapping = {'(': u'tuple',
|
mapping = {'(': 'tuple',
|
||||||
'[': u'list',
|
'[': 'list',
|
||||||
'{': u'set'}
|
'{': 'set'}
|
||||||
|
|
||||||
def __init__(self, inference_state, defining_context, atom):
|
def __init__(self, inference_state, defining_context, atom):
|
||||||
super(SequenceLiteralValue, self).__init__(inference_state)
|
super().__init__(inference_state)
|
||||||
self.atom = atom
|
self.atom = atom
|
||||||
self._defining_context = defining_context
|
self._defining_context = defining_context
|
||||||
|
|
||||||
if self.atom.type in self._TUPLE_LIKE:
|
if self.atom.type in self._TUPLE_LIKE:
|
||||||
self.array_type = u'tuple'
|
self.array_type = 'tuple'
|
||||||
else:
|
else:
|
||||||
self.array_type = SequenceLiteralValue.mapping[atom.children[0]]
|
self.array_type = SequenceLiteralValue.mapping[atom.children[0]]
|
||||||
"""The builtin name of the array (list, set, tuple or dict)."""
|
"""The builtin name of the array (list, set, tuple or dict)."""
|
||||||
|
|
||||||
def _get_generics(self):
|
def _get_generics(self):
|
||||||
if self.array_type == u'tuple':
|
if self.array_type == 'tuple':
|
||||||
return tuple(x.infer().py__class__() for x in self.py__iter__())
|
return tuple(x.infer().py__class__() for x in self.py__iter__())
|
||||||
return super(SequenceLiteralValue, self)._get_generics()
|
return super()._get_generics()
|
||||||
|
|
||||||
def py__simple_getitem__(self, index):
|
def py__simple_getitem__(self, index):
|
||||||
"""Here the index is an int/str. Raises IndexError/KeyError."""
|
"""Here the index is an int/str. Raises IndexError/KeyError."""
|
||||||
@@ -436,10 +425,12 @@ class SequenceLiteralValue(Sequence):
|
|||||||
|
|
||||||
|
|
||||||
class DictLiteralValue(_DictMixin, SequenceLiteralValue, _DictKeyMixin):
|
class DictLiteralValue(_DictMixin, SequenceLiteralValue, _DictKeyMixin):
|
||||||
array_type = u'dict'
|
array_type = 'dict'
|
||||||
|
|
||||||
def __init__(self, inference_state, defining_context, atom):
|
def __init__(self, inference_state, defining_context, atom):
|
||||||
super(SequenceLiteralValue, self).__init__(inference_state)
|
# Intentionally don't call the super class. This is definitely a sign
|
||||||
|
# that the architecture is bad and we should refactor.
|
||||||
|
Sequence.__init__(self, inference_state)
|
||||||
self._defining_context = defining_context
|
self._defining_context = defining_context
|
||||||
self.atom = atom
|
self.atom = atom
|
||||||
|
|
||||||
@@ -448,7 +439,7 @@ class DictLiteralValue(_DictMixin, SequenceLiteralValue, _DictKeyMixin):
|
|||||||
compiled_value_index = compiled.create_simple_object(self.inference_state, index)
|
compiled_value_index = compiled.create_simple_object(self.inference_state, index)
|
||||||
for key, value in self.get_tree_entries():
|
for key, value in self.get_tree_entries():
|
||||||
for k in self._defining_context.infer_node(key):
|
for k in self._defining_context.infer_node(key):
|
||||||
for key_v in k.execute_operation(compiled_value_index, u'=='):
|
for key_v in k.execute_operation(compiled_value_index, '=='):
|
||||||
if key_v.get_safe_value():
|
if key_v.get_safe_value():
|
||||||
return self._defining_context.infer_node(value)
|
return self._defining_context.infer_node(value)
|
||||||
raise SimpleGetItemNotFound('No key found in dictionary %s.' % self)
|
raise SimpleGetItemNotFound('No key found in dictionary %s.' % self)
|
||||||
@@ -502,7 +493,7 @@ class _FakeSequence(Sequence):
|
|||||||
"""
|
"""
|
||||||
type should be one of "tuple", "list"
|
type should be one of "tuple", "list"
|
||||||
"""
|
"""
|
||||||
super(_FakeSequence, self).__init__(inference_state)
|
super().__init__(inference_state)
|
||||||
self._lazy_value_list = lazy_value_list
|
self._lazy_value_list = lazy_value_list
|
||||||
|
|
||||||
def py__simple_getitem__(self, index):
|
def py__simple_getitem__(self, index):
|
||||||
@@ -524,18 +515,18 @@ class _FakeSequence(Sequence):
|
|||||||
|
|
||||||
|
|
||||||
class FakeTuple(_FakeSequence):
|
class FakeTuple(_FakeSequence):
|
||||||
array_type = u'tuple'
|
array_type = 'tuple'
|
||||||
|
|
||||||
|
|
||||||
class FakeList(_FakeSequence):
|
class FakeList(_FakeSequence):
|
||||||
array_type = u'tuple'
|
array_type = 'tuple'
|
||||||
|
|
||||||
|
|
||||||
class FakeDict(_DictMixin, Sequence, _DictKeyMixin):
|
class FakeDict(_DictMixin, Sequence, _DictKeyMixin):
|
||||||
array_type = u'dict'
|
array_type = 'dict'
|
||||||
|
|
||||||
def __init__(self, inference_state, dct):
|
def __init__(self, inference_state, dct):
|
||||||
super(FakeDict, self).__init__(inference_state)
|
super().__init__(inference_state)
|
||||||
self._dct = dct
|
self._dct = dct
|
||||||
|
|
||||||
def py__iter__(self, contextualized_node=None):
|
def py__iter__(self, contextualized_node=None):
|
||||||
@@ -543,21 +534,6 @@ class FakeDict(_DictMixin, Sequence, _DictKeyMixin):
|
|||||||
yield LazyKnownValue(compiled.create_simple_object(self.inference_state, key))
|
yield LazyKnownValue(compiled.create_simple_object(self.inference_state, key))
|
||||||
|
|
||||||
def py__simple_getitem__(self, index):
|
def py__simple_getitem__(self, index):
|
||||||
if is_py3 and self.inference_state.environment.version_info.major == 2:
|
|
||||||
# In Python 2 bytes and unicode compare.
|
|
||||||
if isinstance(index, bytes):
|
|
||||||
index_unicode = force_unicode(index)
|
|
||||||
try:
|
|
||||||
return self._dct[index_unicode].infer()
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
elif isinstance(index, str):
|
|
||||||
index_bytes = index.encode('utf-8')
|
|
||||||
try:
|
|
||||||
return self._dct[index_bytes].infer()
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
with reraise_getitem_errors(KeyError, TypeError):
|
with reraise_getitem_errors(KeyError, TypeError):
|
||||||
lazy_value = self._dct[index]
|
lazy_value = self._dct[index]
|
||||||
return lazy_value.infer()
|
return lazy_value.infer()
|
||||||
@@ -584,7 +560,7 @@ class FakeDict(_DictMixin, Sequence, _DictKeyMixin):
|
|||||||
|
|
||||||
class MergedArray(Sequence):
|
class MergedArray(Sequence):
|
||||||
def __init__(self, inference_state, arrays):
|
def __init__(self, inference_state, arrays):
|
||||||
super(MergedArray, self).__init__(inference_state)
|
super().__init__(inference_state)
|
||||||
self.array_type = arrays[-1].array_type
|
self.array_type = arrays[-1].array_type
|
||||||
self._arrays = arrays
|
self._arrays = arrays
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ py__doc__() Returns the docstring for a value.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi._compatibility import use_metaclass
|
|
||||||
from jedi.parser_utils import get_cached_parent_scope, expr_is_dotted
|
from jedi.parser_utils import get_cached_parent_scope, expr_is_dotted
|
||||||
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass, \
|
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass, \
|
||||||
inference_state_method_generator_cache
|
inference_state_method_generator_cache
|
||||||
@@ -56,7 +55,7 @@ from jedi.plugins import plugin_manager
|
|||||||
|
|
||||||
class ClassName(TreeNameDefinition):
|
class ClassName(TreeNameDefinition):
|
||||||
def __init__(self, class_value, tree_name, name_context, apply_decorators):
|
def __init__(self, class_value, tree_name, name_context, apply_decorators):
|
||||||
super(ClassName, self).__init__(name_context, tree_name)
|
super().__init__(name_context, tree_name)
|
||||||
self._apply_decorators = apply_decorators
|
self._apply_decorators = apply_decorators
|
||||||
self._class_value = class_value
|
self._class_value = class_value
|
||||||
|
|
||||||
@@ -78,7 +77,7 @@ class ClassName(TreeNameDefinition):
|
|||||||
class ClassFilter(ParserTreeFilter):
|
class ClassFilter(ParserTreeFilter):
|
||||||
def __init__(self, class_value, node_context=None, until_position=None,
|
def __init__(self, class_value, node_context=None, until_position=None,
|
||||||
origin_scope=None, is_instance=False):
|
origin_scope=None, is_instance=False):
|
||||||
super(ClassFilter, self).__init__(
|
super().__init__(
|
||||||
class_value.as_context(), node_context,
|
class_value.as_context(), node_context,
|
||||||
until_position=until_position,
|
until_position=until_position,
|
||||||
origin_scope=origin_scope,
|
origin_scope=origin_scope,
|
||||||
@@ -125,7 +124,7 @@ class ClassFilter(ParserTreeFilter):
|
|||||||
or self._equals_origin_scope()
|
or self._equals_origin_scope()
|
||||||
|
|
||||||
def _filter(self, names):
|
def _filter(self, names):
|
||||||
names = super(ClassFilter, self)._filter(names)
|
names = super()._filter(names)
|
||||||
return [name for name in names if self._access_possible(name)]
|
return [name for name in names if self._access_possible(name)]
|
||||||
|
|
||||||
|
|
||||||
@@ -145,7 +144,7 @@ class ClassMixin(object):
|
|||||||
return ValueSet([TreeInstance(self.inference_state, self.parent_context, self, arguments)])
|
return ValueSet([TreeInstance(self.inference_state, self.parent_context, self, arguments)])
|
||||||
|
|
||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
return compiled.builtin_from_name(self.inference_state, u'type')
|
return compiled.builtin_from_name(self.inference_state, 'type')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -192,13 +191,11 @@ class ClassMixin(object):
|
|||||||
if include_metaclasses:
|
if include_metaclasses:
|
||||||
metaclasses = self.get_metaclasses()
|
metaclasses = self.get_metaclasses()
|
||||||
if metaclasses:
|
if metaclasses:
|
||||||
for f in self.get_metaclass_filters(metaclasses, is_instance):
|
yield from self.get_metaclass_filters(metaclasses, is_instance)
|
||||||
yield f # Python 2..
|
|
||||||
|
|
||||||
for cls in self.py__mro__():
|
for cls in self.py__mro__():
|
||||||
if cls.is_compiled():
|
if cls.is_compiled():
|
||||||
for filter in cls.get_filters(is_instance=is_instance):
|
yield from cls.get_filters(is_instance=is_instance)
|
||||||
yield filter
|
|
||||||
else:
|
else:
|
||||||
yield ClassFilter(
|
yield ClassFilter(
|
||||||
self, node_context=cls.as_context(),
|
self, node_context=cls.as_context(),
|
||||||
@@ -207,7 +204,7 @@ class ClassMixin(object):
|
|||||||
)
|
)
|
||||||
if not is_instance and include_type_when_class:
|
if not is_instance and include_type_when_class:
|
||||||
from jedi.inference.compiled import builtin_from_name
|
from jedi.inference.compiled import builtin_from_name
|
||||||
type_ = builtin_from_name(self.inference_state, u'type')
|
type_ = builtin_from_name(self.inference_state, 'type')
|
||||||
assert isinstance(type_, ClassValue)
|
assert isinstance(type_, ClassValue)
|
||||||
if type_ != self:
|
if type_ != self:
|
||||||
# We are not using execute_with_values here, because the
|
# We are not using execute_with_values here, because the
|
||||||
@@ -321,8 +318,8 @@ class ClassMixin(object):
|
|||||||
return ValueSet({self})
|
return ValueSet({self})
|
||||||
|
|
||||||
|
|
||||||
class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase)):
|
class ClassValue(ClassMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
|
||||||
api_type = u'class'
|
api_type = 'class'
|
||||||
|
|
||||||
@inference_state_method_cache()
|
@inference_state_method_cache()
|
||||||
def list_type_vars(self):
|
def list_type_vars(self):
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from jedi.inference.cache import inference_state_method_cache
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
from jedi.inference.names import AbstractNameDefinition, ModuleName
|
from jedi.inference.names import AbstractNameDefinition, ModuleName
|
||||||
@@ -16,7 +17,7 @@ class _ModuleAttributeName(AbstractNameDefinition):
|
|||||||
"""
|
"""
|
||||||
For module attributes like __file__, __str__ and so on.
|
For module attributes like __file__, __str__ and so on.
|
||||||
"""
|
"""
|
||||||
api_type = u'instance'
|
api_type = 'instance'
|
||||||
|
|
||||||
def __init__(self, parent_module, string_name, string_value=None):
|
def __init__(self, parent_module, string_name, string_value=None):
|
||||||
self.parent_context = parent_module
|
self.parent_context = parent_module
|
||||||
@@ -26,9 +27,6 @@ class _ModuleAttributeName(AbstractNameDefinition):
|
|||||||
def infer(self):
|
def infer(self):
|
||||||
if self._string_value is not None:
|
if self._string_value is not None:
|
||||||
s = self._string_value
|
s = self._string_value
|
||||||
if self.parent_context.inference_state.environment.version_info.major == 2 \
|
|
||||||
and not isinstance(s, bytes):
|
|
||||||
s = s.encode('utf-8')
|
|
||||||
return ValueSet([
|
return ValueSet([
|
||||||
create_simple_object(self.parent_context.inference_state, s)
|
create_simple_object(self.parent_context.inference_state, s)
|
||||||
])
|
])
|
||||||
@@ -73,7 +71,7 @@ class ModuleMixin(SubModuleDictMixin):
|
|||||||
yield star_filter
|
yield star_filter
|
||||||
|
|
||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
c, = values_from_qualified_names(self.inference_state, u'types', u'ModuleType')
|
c, = values_from_qualified_names(self.inference_state, 'types', 'ModuleType')
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def is_module(self):
|
def is_module(self):
|
||||||
@@ -92,9 +90,9 @@ class ModuleMixin(SubModuleDictMixin):
|
|||||||
names = ['__package__', '__doc__', '__name__']
|
names = ['__package__', '__doc__', '__name__']
|
||||||
# All the additional module attributes are strings.
|
# All the additional module attributes are strings.
|
||||||
dct = dict((n, _ModuleAttributeName(self, n)) for n in names)
|
dct = dict((n, _ModuleAttributeName(self, n)) for n in names)
|
||||||
file = self.py__file__()
|
path = self.py__file__()
|
||||||
if file is not None:
|
if path is not None:
|
||||||
dct['__file__'] = _ModuleAttributeName(self, '__file__', file)
|
dct['__file__'] = _ModuleAttributeName(self, '__file__', str(path))
|
||||||
return dct
|
return dct
|
||||||
|
|
||||||
def iter_star_filters(self):
|
def iter_star_filters(self):
|
||||||
@@ -137,11 +135,11 @@ class ModuleMixin(SubModuleDictMixin):
|
|||||||
|
|
||||||
|
|
||||||
class ModuleValue(ModuleMixin, TreeValue):
|
class ModuleValue(ModuleMixin, TreeValue):
|
||||||
api_type = u'module'
|
api_type = 'module'
|
||||||
|
|
||||||
def __init__(self, inference_state, module_node, code_lines, file_io=None,
|
def __init__(self, inference_state, module_node, code_lines, file_io=None,
|
||||||
string_names=None, is_package=False):
|
string_names=None, is_package=False):
|
||||||
super(ModuleValue, self).__init__(
|
super().__init__(
|
||||||
inference_state,
|
inference_state,
|
||||||
parent_context=None,
|
parent_context=None,
|
||||||
tree_node=module_node
|
tree_node=module_node
|
||||||
@@ -150,32 +148,32 @@ class ModuleValue(ModuleMixin, TreeValue):
|
|||||||
if file_io is None:
|
if file_io is None:
|
||||||
self._path = None
|
self._path = None
|
||||||
else:
|
else:
|
||||||
self._path = file_io.path
|
self._path = Path(file_io.path)
|
||||||
self.string_names = string_names # Optional[Tuple[str, ...]]
|
self.string_names = string_names # Optional[Tuple[str, ...]]
|
||||||
self.code_lines = code_lines
|
self.code_lines = code_lines
|
||||||
self._is_package = is_package
|
self._is_package = is_package
|
||||||
|
|
||||||
def is_stub(self):
|
def is_stub(self):
|
||||||
if self._path is not None and self._path.endswith('.pyi'):
|
if self._path is not None and self._path.suffix == '.pyi':
|
||||||
# Currently this is the way how we identify stubs when e.g. goto is
|
# Currently this is the way how we identify stubs when e.g. goto is
|
||||||
# used in them. This could be changed if stubs would be identified
|
# used in them. This could be changed if stubs would be identified
|
||||||
# sooner and used as StubModuleValue.
|
# sooner and used as StubModuleValue.
|
||||||
return True
|
return True
|
||||||
return super(ModuleValue, self).is_stub()
|
return super().is_stub()
|
||||||
|
|
||||||
def py__name__(self):
|
def py__name__(self):
|
||||||
if self.string_names is None:
|
if self.string_names is None:
|
||||||
return None
|
return None
|
||||||
return '.'.join(self.string_names)
|
return '.'.join(self.string_names)
|
||||||
|
|
||||||
def py__file__(self):
|
def py__file__(self) -> Path:
|
||||||
"""
|
"""
|
||||||
In contrast to Python's __file__ can be None.
|
In contrast to Python's __file__ can be None.
|
||||||
"""
|
"""
|
||||||
if self._path is None:
|
if self._path is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return os.path.abspath(self._path)
|
return self._path.absolute()
|
||||||
|
|
||||||
def is_package(self):
|
def is_package(self):
|
||||||
return self._is_package
|
return self._is_package
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ class ImplicitNamespaceValue(Value, SubModuleDictMixin):
|
|||||||
# Is a module like every other module, because if you import an empty
|
# Is a module like every other module, because if you import an empty
|
||||||
# folder foobar it will be available as an object:
|
# folder foobar it will be available as an object:
|
||||||
# <module 'foobar' (namespace)>.
|
# <module 'foobar' (namespace)>.
|
||||||
api_type = u'module'
|
api_type = 'module'
|
||||||
parent_context = None
|
parent_context = None
|
||||||
|
|
||||||
def __init__(self, inference_state, string_names, paths):
|
def __init__(self, inference_state, string_names, paths):
|
||||||
super(ImplicitNamespaceValue, self).__init__(inference_state, parent_context=None)
|
super().__init__(inference_state, parent_context=None)
|
||||||
self.inference_state = inference_state
|
self.inference_state = inference_state
|
||||||
self.string_names = string_names
|
self.string_names = string_names
|
||||||
self._paths = paths
|
self._paths = paths
|
||||||
|
|||||||
+4
-19
@@ -1,5 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
import textwrap
|
import textwrap
|
||||||
|
from ast import literal_eval
|
||||||
from inspect import cleandoc
|
from inspect import cleandoc
|
||||||
from weakref import WeakKeyDictionary
|
from weakref import WeakKeyDictionary
|
||||||
|
|
||||||
@@ -7,8 +8,6 @@ from parso.python import tree
|
|||||||
from parso.cache import parser_cache
|
from parso.cache import parser_cache
|
||||||
from parso import split_lines
|
from parso import split_lines
|
||||||
|
|
||||||
from jedi._compatibility import literal_eval, force_unicode
|
|
||||||
|
|
||||||
_EXECUTE_NODES = {'funcdef', 'classdef', 'import_from', 'import_name', 'test',
|
_EXECUTE_NODES = {'funcdef', 'classdef', 'import_from', 'import_name', 'test',
|
||||||
'or_test', 'and_test', 'not_test', 'comparison', 'expr',
|
'or_test', 'and_test', 'not_test', 'comparison', 'expr',
|
||||||
'xor_expr', 'and_expr', 'shift_expr', 'arith_expr',
|
'xor_expr', 'and_expr', 'shift_expr', 'arith_expr',
|
||||||
@@ -102,10 +101,7 @@ def clean_scope_docstring(scope_node):
|
|||||||
# leaves anymore that might be part of the docstring. A
|
# leaves anymore that might be part of the docstring. A
|
||||||
# docstring can also look like this: ``'foo' 'bar'
|
# docstring can also look like this: ``'foo' 'bar'
|
||||||
# Returns a literal cleaned version of the ``Token``.
|
# Returns a literal cleaned version of the ``Token``.
|
||||||
cleaned = cleandoc(safe_literal_eval(node.value))
|
return cleandoc(safe_literal_eval(node.value))
|
||||||
# Since we want the docstr output to be always unicode, just
|
|
||||||
# force it.
|
|
||||||
return force_unicode(cleaned)
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
@@ -117,10 +113,7 @@ def find_statement_documentation(tree_node):
|
|||||||
if maybe_string.type == 'simple_stmt':
|
if maybe_string.type == 'simple_stmt':
|
||||||
maybe_string = maybe_string.children[0]
|
maybe_string = maybe_string.children[0]
|
||||||
if maybe_string.type == 'string':
|
if maybe_string.type == 'string':
|
||||||
cleaned = cleandoc(safe_literal_eval(maybe_string.value))
|
return cleandoc(safe_literal_eval(maybe_string.value))
|
||||||
# Since we want the docstr output to be always unicode, just
|
|
||||||
# force it.
|
|
||||||
return force_unicode(cleaned)
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
@@ -131,15 +124,7 @@ def safe_literal_eval(value):
|
|||||||
# manually, but that's right now not implemented.
|
# manually, but that's right now not implemented.
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
try:
|
return literal_eval(value)
|
||||||
return literal_eval(value)
|
|
||||||
except SyntaxError:
|
|
||||||
# It's possible to create syntax errors with literals like rb'' in
|
|
||||||
# Python 2. This should not be possible and in that case just return an
|
|
||||||
# empty string.
|
|
||||||
# Before Python 3.3 there was a more strict definition in which order
|
|
||||||
# you could define literals.
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
def get_signature(funcdef, width=72, call_string=None,
|
def get_signature(funcdef, width=72, call_string=None,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
"""
|
"""
|
||||||
Module is used to infer Django model fields.
|
Module is used to infer Django model fields.
|
||||||
"""
|
"""
|
||||||
from jedi._compatibility import Parameter
|
from inspect import Parameter
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.cache import inference_state_function_cache
|
from jedi.inference.cache import inference_state_function_cache
|
||||||
from jedi.inference.base_value import ValueSet, iterator_to_value_set, ValueWrapper
|
from jedi.inference.base_value import ValueSet, iterator_to_value_set, ValueWrapper
|
||||||
@@ -113,7 +114,7 @@ def _infer_field(cls, field_name, is_instance):
|
|||||||
|
|
||||||
class DjangoModelName(NameWrapper):
|
class DjangoModelName(NameWrapper):
|
||||||
def __init__(self, cls, name, is_instance):
|
def __init__(self, cls, name, is_instance):
|
||||||
super(DjangoModelName, self).__init__(name)
|
super().__init__(name)
|
||||||
self._cls = cls
|
self._cls = cls
|
||||||
self._is_instance = is_instance
|
self._is_instance = is_instance
|
||||||
|
|
||||||
@@ -257,7 +258,7 @@ class GenericFieldWrapper(AttributeOverwrite, ClassMixin):
|
|||||||
|
|
||||||
class DjangoModelSignature(AbstractSignature):
|
class DjangoModelSignature(AbstractSignature):
|
||||||
def __init__(self, value, field_names):
|
def __init__(self, value, field_names):
|
||||||
super(DjangoModelSignature, self).__init__(value)
|
super().__init__(value)
|
||||||
self._field_names = field_names
|
self._field_names = field_names
|
||||||
|
|
||||||
def get_param_names(self, resolve_stars=False):
|
def get_param_names(self, resolve_stars=False):
|
||||||
@@ -266,7 +267,7 @@ class DjangoModelSignature(AbstractSignature):
|
|||||||
|
|
||||||
class DjangoParamName(BaseTreeParamName):
|
class DjangoParamName(BaseTreeParamName):
|
||||||
def __init__(self, field_name):
|
def __init__(self, field_name):
|
||||||
super(DjangoParamName, self).__init__(field_name.parent_context, field_name.tree_name)
|
super().__init__(field_name.parent_context, field_name.tree_name)
|
||||||
self._field_name = field_name
|
self._field_name = field_name
|
||||||
|
|
||||||
def get_kind(self):
|
def get_kind(self):
|
||||||
@@ -278,7 +279,7 @@ class DjangoParamName(BaseTreeParamName):
|
|||||||
|
|
||||||
class QuerySetMethodWrapper(ValueWrapper):
|
class QuerySetMethodWrapper(ValueWrapper):
|
||||||
def __init__(self, method, model_cls):
|
def __init__(self, method, model_cls):
|
||||||
super(QuerySetMethodWrapper, self).__init__(method)
|
super().__init__(method)
|
||||||
self._model_cls = model_cls
|
self._model_cls = model_cls
|
||||||
|
|
||||||
def py__get__(self, instance, class_value):
|
def py__get__(self, instance, class_value):
|
||||||
@@ -288,7 +289,7 @@ class QuerySetMethodWrapper(ValueWrapper):
|
|||||||
|
|
||||||
class QuerySetBoundMethodWrapper(ValueWrapper):
|
class QuerySetBoundMethodWrapper(ValueWrapper):
|
||||||
def __init__(self, method, model_cls):
|
def __init__(self, method, model_cls):
|
||||||
super(QuerySetBoundMethodWrapper, self).__init__(method)
|
super().__init__(method)
|
||||||
self._model_cls = model_cls
|
self._model_cls = model_cls
|
||||||
|
|
||||||
def get_signatures(self):
|
def get_signatures(self):
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ def import_module(callback):
|
|||||||
def wrapper(inference_state, import_names, module_context, *args, **kwargs):
|
def wrapper(inference_state, import_names, module_context, *args, **kwargs):
|
||||||
if len(import_names) == 3 and import_names[:2] == ('flask', 'ext'):
|
if len(import_names) == 3 and import_names[:2] == ('flask', 'ext'):
|
||||||
# New style.
|
# New style.
|
||||||
ipath = (u'flask_' + import_names[2]),
|
ipath = ('flask_' + import_names[2]),
|
||||||
value_set = callback(inference_state, ipath, None, *args, **kwargs)
|
value_set = callback(inference_state, ipath, None, *args, **kwargs)
|
||||||
if value_set:
|
if value_set:
|
||||||
return value_set
|
return value_set
|
||||||
value_set = callback(inference_state, (u'flaskext',), None, *args, **kwargs)
|
value_set = callback(inference_state, ('flaskext',), None, *args, **kwargs)
|
||||||
return callback(
|
return callback(
|
||||||
inference_state,
|
inference_state,
|
||||||
(u'flaskext', import_names[2]),
|
('flaskext', import_names[2]),
|
||||||
next(iter(value_set)),
|
next(iter(value_set)),
|
||||||
*args, **kwargs
|
*args, **kwargs
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from parso.python.tree import search_ancestor
|
from parso.python.tree import search_ancestor
|
||||||
from jedi._compatibility import FileNotFoundError
|
|
||||||
from jedi.inference.cache import inference_state_method_cache
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
from jedi.inference.imports import load_module_from_path
|
from jedi.inference.imports import load_module_from_path
|
||||||
from jedi.inference.filters import ParserTreeFilter
|
from jedi.inference.filters import ParserTreeFilter
|
||||||
@@ -129,7 +130,7 @@ def _iter_pytest_modules(module_context, skip_own_module=False):
|
|||||||
sys_path = module_context.inference_state.get_sys_path()
|
sys_path = module_context.inference_state.get_sys_path()
|
||||||
while any(folder.path.startswith(p) for p in sys_path):
|
while any(folder.path.startswith(p) for p in sys_path):
|
||||||
file_io = folder.get_file_io('conftest.py')
|
file_io = folder.get_file_io('conftest.py')
|
||||||
if file_io.path != module_context.py__file__():
|
if Path(file_io.path) != module_context.py__file__():
|
||||||
try:
|
try:
|
||||||
m = load_module_from_path(module_context.inference_state, file_io)
|
m = load_module_from_path(module_context.inference_state, file_io)
|
||||||
yield m.as_context()
|
yield m.as_context()
|
||||||
@@ -144,7 +145,7 @@ def _iter_pytest_modules(module_context, skip_own_module=False):
|
|||||||
|
|
||||||
class FixtureFilter(ParserTreeFilter):
|
class FixtureFilter(ParserTreeFilter):
|
||||||
def _filter(self, names):
|
def _filter(self, names):
|
||||||
for name in super(FixtureFilter, self)._filter(names):
|
for name in super()._filter(names):
|
||||||
funcdef = name.parent
|
funcdef = name.parent
|
||||||
if funcdef.type == 'funcdef':
|
if funcdef.type == 'funcdef':
|
||||||
# Class fixtures are not supported
|
# Class fixtures are not supported
|
||||||
|
|||||||
+23
-29
@@ -11,8 +11,8 @@ compiled module that returns the types for C-builtins.
|
|||||||
"""
|
"""
|
||||||
import parso
|
import parso
|
||||||
import os
|
import os
|
||||||
|
from inspect import Parameter
|
||||||
|
|
||||||
from jedi._compatibility import force_unicode, Parameter
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.utils import safe_property
|
from jedi.inference.utils import safe_property
|
||||||
from jedi.inference.helpers import get_str_or_none
|
from jedi.inference.helpers import get_str_or_none
|
||||||
@@ -182,14 +182,9 @@ def argument_clinic(clinic_string, want_value=False, want_context=False,
|
|||||||
|
|
||||||
@argument_clinic('iterator[, default], /', want_inference_state=True)
|
@argument_clinic('iterator[, default], /', want_inference_state=True)
|
||||||
def builtins_next(iterators, defaults, inference_state):
|
def builtins_next(iterators, defaults, inference_state):
|
||||||
if inference_state.environment.version_info.major == 2:
|
|
||||||
name = 'next'
|
|
||||||
else:
|
|
||||||
name = '__next__'
|
|
||||||
|
|
||||||
# TODO theoretically we have to check here if something is an iterator.
|
# TODO theoretically we have to check here if something is an iterator.
|
||||||
# That is probably done by checking if it's not a class.
|
# That is probably done by checking if it's not a class.
|
||||||
return defaults | iterators.py__getattribute__(name).execute_with_values()
|
return defaults | iterators.py__getattribute__('__next__').execute_with_values()
|
||||||
|
|
||||||
|
|
||||||
@argument_clinic('iterator[, default], /')
|
@argument_clinic('iterator[, default], /')
|
||||||
@@ -208,7 +203,7 @@ def builtins_getattr(objects, names, defaults=None):
|
|||||||
debug.warning('getattr called without str')
|
debug.warning('getattr called without str')
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
return value.py__getattribute__(force_unicode(string))
|
return value.py__getattribute__(string)
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
|
|
||||||
|
|
||||||
@@ -259,14 +254,13 @@ def builtins_super(types, objects, context):
|
|||||||
|
|
||||||
class ReversedObject(AttributeOverwrite):
|
class ReversedObject(AttributeOverwrite):
|
||||||
def __init__(self, reversed_obj, iter_list):
|
def __init__(self, reversed_obj, iter_list):
|
||||||
super(ReversedObject, self).__init__(reversed_obj)
|
super().__init__(reversed_obj)
|
||||||
self._iter_list = iter_list
|
self._iter_list = iter_list
|
||||||
|
|
||||||
def py__iter__(self, contextualized_node):
|
def py__iter__(self, contextualized_node):
|
||||||
return self._iter_list
|
return self._iter_list
|
||||||
|
|
||||||
@publish_method('next', python_version_match=2)
|
@publish_method('__next__')
|
||||||
@publish_method('__next__', python_version_match=3)
|
|
||||||
def _next(self, arguments):
|
def _next(self, arguments):
|
||||||
return ValueSet.from_sets(
|
return ValueSet.from_sets(
|
||||||
lazy_value.infer() for lazy_value in self._iter_list
|
lazy_value.infer() for lazy_value in self._iter_list
|
||||||
@@ -329,7 +323,7 @@ def builtins_isinstance(objects, types, arguments, inference_state):
|
|||||||
analysis.add(lazy_value.context, 'type-error-isinstance', node, message)
|
analysis.add(lazy_value.context, 'type-error-isinstance', node, message)
|
||||||
|
|
||||||
return ValueSet(
|
return ValueSet(
|
||||||
compiled.builtin_from_name(inference_state, force_unicode(str(b)))
|
compiled.builtin_from_name(inference_state, str(b))
|
||||||
for b in bool_results
|
for b in bool_results
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -346,7 +340,7 @@ def builtins_staticmethod(functions):
|
|||||||
|
|
||||||
class ClassMethodObject(ValueWrapper):
|
class ClassMethodObject(ValueWrapper):
|
||||||
def __init__(self, class_method_obj, function):
|
def __init__(self, class_method_obj, function):
|
||||||
super(ClassMethodObject, self).__init__(class_method_obj)
|
super().__init__(class_method_obj)
|
||||||
self._function = function
|
self._function = function
|
||||||
|
|
||||||
def py__get__(self, instance, class_value):
|
def py__get__(self, instance, class_value):
|
||||||
@@ -358,7 +352,7 @@ class ClassMethodObject(ValueWrapper):
|
|||||||
|
|
||||||
class ClassMethodGet(ValueWrapper):
|
class ClassMethodGet(ValueWrapper):
|
||||||
def __init__(self, get_method, klass, function):
|
def __init__(self, get_method, klass, function):
|
||||||
super(ClassMethodGet, self).__init__(get_method)
|
super().__init__(get_method)
|
||||||
self._class = klass
|
self._class = klass
|
||||||
self._function = function
|
self._function = function
|
||||||
|
|
||||||
@@ -371,7 +365,7 @@ class ClassMethodGet(ValueWrapper):
|
|||||||
|
|
||||||
class ClassMethodArguments(TreeArgumentsWrapper):
|
class ClassMethodArguments(TreeArgumentsWrapper):
|
||||||
def __init__(self, klass, arguments):
|
def __init__(self, klass, arguments):
|
||||||
super(ClassMethodArguments, self).__init__(arguments)
|
super().__init__(arguments)
|
||||||
self._class = klass
|
self._class = klass
|
||||||
|
|
||||||
def unpack(self, func=None):
|
def unpack(self, func=None):
|
||||||
@@ -391,7 +385,7 @@ def builtins_classmethod(functions, value, arguments):
|
|||||||
|
|
||||||
class PropertyObject(AttributeOverwrite, ValueWrapper):
|
class PropertyObject(AttributeOverwrite, ValueWrapper):
|
||||||
def __init__(self, property_obj, function):
|
def __init__(self, property_obj, function):
|
||||||
super(PropertyObject, self).__init__(property_obj)
|
super().__init__(property_obj)
|
||||||
self._function = function
|
self._function = function
|
||||||
|
|
||||||
def py__get__(self, instance, class_value):
|
def py__get__(self, instance, class_value):
|
||||||
@@ -426,11 +420,11 @@ def collections_namedtuple(value, arguments, callback):
|
|||||||
inference_state = value.inference_state
|
inference_state = value.inference_state
|
||||||
|
|
||||||
# Process arguments
|
# Process arguments
|
||||||
name = u'jedi_unknown_namedtuple'
|
name = 'jedi_unknown_namedtuple'
|
||||||
for c in _follow_param(inference_state, arguments, 0):
|
for c in _follow_param(inference_state, arguments, 0):
|
||||||
x = get_str_or_none(c)
|
x = get_str_or_none(c)
|
||||||
if x is not None:
|
if x is not None:
|
||||||
name = force_unicode(x)
|
name = x
|
||||||
break
|
break
|
||||||
|
|
||||||
# TODO here we only use one of the types, we should use all.
|
# TODO here we only use one of the types, we should use all.
|
||||||
@@ -440,10 +434,10 @@ def collections_namedtuple(value, arguments, callback):
|
|||||||
_fields = list(param_values)[0]
|
_fields = list(param_values)[0]
|
||||||
string = get_str_or_none(_fields)
|
string = get_str_or_none(_fields)
|
||||||
if string is not None:
|
if string is not None:
|
||||||
fields = force_unicode(string).replace(',', ' ').split()
|
fields = string.replace(',', ' ').split()
|
||||||
elif isinstance(_fields, iterable.Sequence):
|
elif isinstance(_fields, iterable.Sequence):
|
||||||
fields = [
|
fields = [
|
||||||
force_unicode(get_str_or_none(v))
|
get_str_or_none(v)
|
||||||
for lazy_value in _fields.py__iter__()
|
for lazy_value in _fields.py__iter__()
|
||||||
for v in lazy_value.infer()
|
for v in lazy_value.infer()
|
||||||
]
|
]
|
||||||
@@ -456,7 +450,7 @@ def collections_namedtuple(value, arguments, callback):
|
|||||||
typename=name,
|
typename=name,
|
||||||
field_names=tuple(fields),
|
field_names=tuple(fields),
|
||||||
num_fields=len(fields),
|
num_fields=len(fields),
|
||||||
arg_list=repr(tuple(fields)).replace("u'", "").replace("'", "")[1:-1],
|
arg_list=repr(tuple(fields)).replace("'", "")[1:-1],
|
||||||
repr_fmt='',
|
repr_fmt='',
|
||||||
field_defs='\n'.join(_NAMEDTUPLE_FIELD_TEMPLATE.format(index=index, name=name)
|
field_defs='\n'.join(_NAMEDTUPLE_FIELD_TEMPLATE.format(index=index, name=name)
|
||||||
for index, name in enumerate(fields))
|
for index, name in enumerate(fields))
|
||||||
@@ -475,7 +469,7 @@ def collections_namedtuple(value, arguments, callback):
|
|||||||
|
|
||||||
class PartialObject(ValueWrapper):
|
class PartialObject(ValueWrapper):
|
||||||
def __init__(self, actual_value, arguments, instance=None):
|
def __init__(self, actual_value, arguments, instance=None):
|
||||||
super(PartialObject, self).__init__(actual_value)
|
super().__init__(actual_value)
|
||||||
self._arguments = arguments
|
self._arguments = arguments
|
||||||
self._instance = instance
|
self._instance = instance
|
||||||
|
|
||||||
@@ -538,7 +532,7 @@ class PartialMethodObject(PartialObject):
|
|||||||
|
|
||||||
class PartialSignature(SignatureWrapper):
|
class PartialSignature(SignatureWrapper):
|
||||||
def __init__(self, wrapped_signature, skipped_arg_count, skipped_arg_set):
|
def __init__(self, wrapped_signature, skipped_arg_count, skipped_arg_set):
|
||||||
super(PartialSignature, self).__init__(wrapped_signature)
|
super().__init__(wrapped_signature)
|
||||||
self._skipped_arg_count = skipped_arg_count
|
self._skipped_arg_count = skipped_arg_count
|
||||||
self._skipped_arg_set = skipped_arg_set
|
self._skipped_arg_set = skipped_arg_set
|
||||||
|
|
||||||
@@ -631,7 +625,7 @@ class DataclassWrapper(ValueWrapper, ClassMixin):
|
|||||||
|
|
||||||
class DataclassSignature(AbstractSignature):
|
class DataclassSignature(AbstractSignature):
|
||||||
def __init__(self, value, param_names):
|
def __init__(self, value, param_names):
|
||||||
super(DataclassSignature, self).__init__(value)
|
super().__init__(value)
|
||||||
self._param_names = param_names
|
self._param_names = param_names
|
||||||
|
|
||||||
def get_param_names(self, resolve_stars=False):
|
def get_param_names(self, resolve_stars=False):
|
||||||
@@ -640,7 +634,7 @@ class DataclassSignature(AbstractSignature):
|
|||||||
|
|
||||||
class DataclassParamName(BaseTreeParamName):
|
class DataclassParamName(BaseTreeParamName):
|
||||||
def __init__(self, parent_context, tree_name, annotation_node, default_node):
|
def __init__(self, parent_context, tree_name, annotation_node, default_node):
|
||||||
super(DataclassParamName, self).__init__(parent_context, tree_name)
|
super().__init__(parent_context, tree_name)
|
||||||
self.annotation_node = annotation_node
|
self.annotation_node = annotation_node
|
||||||
self.default_node = default_node
|
self.default_node = default_node
|
||||||
|
|
||||||
@@ -656,7 +650,7 @@ class DataclassParamName(BaseTreeParamName):
|
|||||||
|
|
||||||
class ItemGetterCallable(ValueWrapper):
|
class ItemGetterCallable(ValueWrapper):
|
||||||
def __init__(self, instance, args_value_set):
|
def __init__(self, instance, args_value_set):
|
||||||
super(ItemGetterCallable, self).__init__(instance)
|
super().__init__(instance)
|
||||||
self._args_value_set = args_value_set
|
self._args_value_set = args_value_set
|
||||||
|
|
||||||
@repack_with_argument_clinic('item, /')
|
@repack_with_argument_clinic('item, /')
|
||||||
@@ -694,7 +688,7 @@ class WrapsCallable(ValueWrapper):
|
|||||||
|
|
||||||
class Wrapped(ValueWrapper, FunctionMixin):
|
class Wrapped(ValueWrapper, FunctionMixin):
|
||||||
def __init__(self, func, original_function):
|
def __init__(self, func, original_function):
|
||||||
super(Wrapped, self).__init__(func)
|
super().__init__(func)
|
||||||
self._original_function = original_function
|
self._original_function = original_function
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -732,7 +726,7 @@ def _create_string_input_function(func):
|
|||||||
@argument_clinic('*args, /', want_callback=True)
|
@argument_clinic('*args, /', want_callback=True)
|
||||||
def _os_path_join(args_set, callback):
|
def _os_path_join(args_set, callback):
|
||||||
if len(args_set) == 1:
|
if len(args_set) == 1:
|
||||||
string = u''
|
string = ''
|
||||||
sequence, = args_set
|
sequence, = args_set
|
||||||
is_first = True
|
is_first = True
|
||||||
for lazy_value in sequence.py__iter__():
|
for lazy_value in sequence.py__iter__():
|
||||||
@@ -744,7 +738,7 @@ def _os_path_join(args_set, callback):
|
|||||||
break
|
break
|
||||||
if not is_first:
|
if not is_first:
|
||||||
string += os.path.sep
|
string += os.path.sep
|
||||||
string += force_unicode(s)
|
string += s
|
||||||
is_first = False
|
is_first = False
|
||||||
else:
|
else:
|
||||||
return ValueSet([compiled.create_simple_object(sequence.inference_state, string)])
|
return ValueSet([compiled.create_simple_object(sequence.inference_state, string)])
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
Utilities for end-users.
|
Utilities for end-users.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
import __main__
|
import __main__
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import logging
|
import logging
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ from docopt import docopt
|
|||||||
from jedi.parser.python import load_grammar
|
from jedi.parser.python import load_grammar
|
||||||
from jedi.parser.diff import DiffParser
|
from jedi.parser.diff import DiffParser
|
||||||
from jedi.parser.python import ParserWithRecovery
|
from jedi.parser.python import ParserWithRecovery
|
||||||
from jedi._compatibility import u
|
|
||||||
from jedi.common import splitlines
|
from jedi.common import splitlines
|
||||||
import jedi
|
import jedi
|
||||||
|
|
||||||
@@ -37,14 +36,15 @@ def main(args):
|
|||||||
with open(args['<file>']) as f:
|
with open(args['<file>']) as f:
|
||||||
code = f.read()
|
code = f.read()
|
||||||
grammar = load_grammar()
|
grammar = load_grammar()
|
||||||
parser = ParserWithRecovery(grammar, u(code))
|
parser = ParserWithRecovery(grammar, code)
|
||||||
# Make sure used_names is loaded
|
# Make sure used_names is loaded
|
||||||
parser.module.used_names
|
parser.module.used_names
|
||||||
|
|
||||||
code = code + '\na\n' # Add something so the diff parser needs to run.
|
code = code + '\na\n' # Add something so the diff parser needs to run.
|
||||||
lines = splitlines(code, keepends=True)
|
lines = splitlines(code, keepends=True)
|
||||||
cProfile.runctx('run(parser, lines)', globals(), locals(), sort=args['-s'])
|
cProfile.runctx('run(parser, lines)', globals(), locals(), sort=args['-s'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
args = docopt(__doc__)
|
args = docopt(__doc__)
|
||||||
main(args)
|
main(args)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3.6
|
#!/usr/bin/env python3.6
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
"""
|
||||||
Profile a piece of Python code with ``profile``. Tries a completion on a
|
Profile a piece of Python code with ``profile``. Tries a completion on a
|
||||||
certain piece of code.
|
certain piece of code.
|
||||||
@@ -19,11 +18,7 @@ Options:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
try:
|
import profile
|
||||||
# For Python 2
|
|
||||||
import cProfile as profile
|
|
||||||
except ImportError:
|
|
||||||
import profile
|
|
||||||
import pstats
|
import pstats
|
||||||
|
|
||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
|
|||||||
@@ -33,12 +33,11 @@ setup(name='jedi',
|
|||||||
keywords='python completion refactoring vim',
|
keywords='python completion refactoring vim',
|
||||||
long_description=readme,
|
long_description=readme,
|
||||||
packages=find_packages(exclude=['test', 'test.*']),
|
packages=find_packages(exclude=['test', 'test.*']),
|
||||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
|
python_requires='>=3.6',
|
||||||
install_requires=install_requires,
|
install_requires=install_requires,
|
||||||
extras_require={
|
extras_require={
|
||||||
'testing': [
|
'testing': [
|
||||||
# Pytest 5 doesn't support Python 2 anymore.
|
'pytest<6.0.0',
|
||||||
'pytest>=3.9.0,<5.0.0',
|
|
||||||
# docopt for sith doctests
|
# docopt for sith doctests
|
||||||
'docopt',
|
'docopt',
|
||||||
# coloroma for colored debug output
|
# coloroma for colored debug output
|
||||||
@@ -58,10 +57,7 @@ setup(name='jedi',
|
|||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'License :: OSI Approved :: MIT License',
|
'License :: OSI Approved :: MIT License',
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Programming Language :: Python :: 2',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.5',
|
|
||||||
'Programming Language :: Python :: 3.6',
|
'Programming Language :: Python :: 3.6',
|
||||||
'Programming Language :: Python :: 3.7',
|
'Programming Language :: Python :: 3.7',
|
||||||
'Programming Language :: Python :: 3.8',
|
'Programming Language :: Python :: 3.8',
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ Options:
|
|||||||
--pudb Launch pudb when error is raised.
|
--pudb Launch pudb when error is raised.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function, division, unicode_literals
|
|
||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|||||||
@@ -272,9 +272,6 @@ dic = {str(key): ''}
|
|||||||
#? str()
|
#? str()
|
||||||
dic['']
|
dic['']
|
||||||
|
|
||||||
# Just skip Python 2 tests from here. EoL soon, I'm too lazy for it.
|
|
||||||
# python > 2.7
|
|
||||||
|
|
||||||
|
|
||||||
for x in {1: 3.0, '': 1j}:
|
for x in {1: 3.0, '': 1j}:
|
||||||
#? int() str()
|
#? int() str()
|
||||||
@@ -473,7 +470,6 @@ def test_func():
|
|||||||
#? int()
|
#? int()
|
||||||
tuple({1})[0]
|
tuple({1})[0]
|
||||||
|
|
||||||
# python > 2.7
|
|
||||||
# -----------------
|
# -----------------
|
||||||
# PEP 3132 Extended Iterable Unpacking (star unpacking)
|
# PEP 3132 Extended Iterable Unpacking (star unpacking)
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ Currently we're not supporting completion of them, but they should at least not
|
|||||||
raise errors or return extremely strange results.
|
raise errors or return extremely strange results.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# python >= 3.5
|
|
||||||
|
|
||||||
async def x():
|
async def x():
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|||||||
@@ -291,14 +291,6 @@ except ImportError as i_a:
|
|||||||
i_a
|
i_a
|
||||||
#? ImportError()
|
#? ImportError()
|
||||||
i_a
|
i_a
|
||||||
try:
|
|
||||||
import math
|
|
||||||
except ImportError, i_b:
|
|
||||||
# TODO check this only in Python2
|
|
||||||
##? ['i_b']
|
|
||||||
i_b
|
|
||||||
##? ImportError()
|
|
||||||
i_b
|
|
||||||
|
|
||||||
|
|
||||||
class MyException(Exception):
|
class MyException(Exception):
|
||||||
@@ -344,8 +336,6 @@ def foo(my_t=some_defa
|
|||||||
#? ['some_default']
|
#? ['some_default']
|
||||||
def foo(my_t=some_defa, my_t2=some_defa
|
def foo(my_t=some_defa, my_t2=some_defa
|
||||||
|
|
||||||
# python > 2.7
|
|
||||||
|
|
||||||
#? ['my_type']
|
#? ['my_type']
|
||||||
def foo(my_t: lala=some_defa, my_t2: my_typ
|
def foo(my_t: lala=some_defa, my_t2: my_typ
|
||||||
#? ['my_type']
|
#? ['my_type']
|
||||||
|
|||||||
@@ -382,7 +382,6 @@ getattr(getattr, 1)
|
|||||||
getattr(str, [])
|
getattr(str, [])
|
||||||
|
|
||||||
|
|
||||||
# python >= 3.5
|
|
||||||
class Base():
|
class Base():
|
||||||
def ret(self, b):
|
def ret(self, b):
|
||||||
return b
|
return b
|
||||||
|
|||||||
@@ -174,8 +174,6 @@ class X():
|
|||||||
#? int()
|
#? int()
|
||||||
X([1]).foo()
|
X([1]).foo()
|
||||||
|
|
||||||
# set/dict comprehensions were introduced in 2.7, therefore:
|
|
||||||
# python >= 2.7
|
|
||||||
# -----------------
|
# -----------------
|
||||||
# dict comprehensions
|
# dict comprehensions
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|||||||
@@ -388,7 +388,6 @@ k = 'a'
|
|||||||
#? int()
|
#? int()
|
||||||
some_dct[k]
|
some_dct[k]
|
||||||
|
|
||||||
# python > 3.5
|
|
||||||
some_other_dct = dict(some_dct, c=set)
|
some_other_dct = dict(some_dct, c=set)
|
||||||
#? int()
|
#? int()
|
||||||
some_other_dct['a']
|
some_other_dct['a']
|
||||||
|
|||||||
@@ -242,8 +242,6 @@ def x():
|
|||||||
# yield from
|
# yield from
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|
||||||
# python > 2.7
|
|
||||||
|
|
||||||
def yield_from():
|
def yield_from():
|
||||||
yield from iter([1])
|
yield from iter([1])
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ def x(): pass
|
|||||||
# -----------------
|
# -----------------
|
||||||
# Only keyword arguments are valid
|
# Only keyword arguments are valid
|
||||||
# -----------------
|
# -----------------
|
||||||
# python >= 3.5
|
|
||||||
|
|
||||||
def x(bam, *, bar, baz):
|
def x(bam, *, bar, baz):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
""" Pep-0484 type hinting """
|
""" Pep-0484 type hinting """
|
||||||
|
|
||||||
# python > 2.7
|
|
||||||
|
|
||||||
|
|
||||||
class A():
|
class A():
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# python >= 3.4
|
|
||||||
import typing
|
import typing
|
||||||
from typing import (
|
from typing import (
|
||||||
Callable,
|
Callable,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# python >= 3.4
|
|
||||||
from typing import (
|
from typing import (
|
||||||
Callable,
|
Callable,
|
||||||
Dict,
|
Dict,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# python >= 3.4
|
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Test the typing library, with docstrings. This is needed since annotations
|
Test the typing library, with docstrings and annotations
|
||||||
are not supported in python 2.7 else then annotating by comment (and this is
|
|
||||||
still TODO at 2016-01-23)
|
|
||||||
"""
|
"""
|
||||||
import typing
|
import typing
|
||||||
class B:
|
class B:
|
||||||
@@ -295,8 +293,6 @@ y = type(PlainInt)
|
|||||||
#? type.mro
|
#? type.mro
|
||||||
y.mro
|
y.mro
|
||||||
|
|
||||||
# python > 2.7
|
|
||||||
|
|
||||||
class TestDefaultDict(typing.DefaultDict[str, int]):
|
class TestDefaultDict(typing.DefaultDict[str, int]):
|
||||||
def setdud(self):
|
def setdud(self):
|
||||||
pass
|
pass
|
||||||
@@ -323,7 +319,6 @@ for key in x.keys():
|
|||||||
for value in x.values():
|
for value in x.values():
|
||||||
#? int()
|
#? int()
|
||||||
value
|
value
|
||||||
# python > 2.7
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -178,8 +178,6 @@ from datetime import datetime, timedelta
|
|||||||
# magic methods
|
# magic methods
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|
||||||
# python >= 3.5
|
|
||||||
|
|
||||||
class C:
|
class C:
|
||||||
def __sub__(self, other) -> int: ...
|
def __sub__(self, other) -> int: ...
|
||||||
def __radd__(self, other) -> float: ...
|
def __radd__(self, other) -> float: ...
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# python > 2.7
|
|
||||||
import pytest
|
import pytest
|
||||||
from pytest import fixture
|
from pytest import fixture
|
||||||
|
|
||||||
@@ -130,8 +129,6 @@ def test_p(monkeypatch):
|
|||||||
#? ['setattr']
|
#? ['setattr']
|
||||||
monkeypatch.setatt
|
monkeypatch.setatt
|
||||||
|
|
||||||
# python > 2.7
|
|
||||||
|
|
||||||
#? ['capsysbinary']
|
#? ['capsysbinary']
|
||||||
def test_p(capsysbin
|
def test_p(capsysbin
|
||||||
|
|
||||||
|
|||||||
+41
-50
@@ -133,48 +133,6 @@ weakref.ref(1)
|
|||||||
#? int() None
|
#? int() None
|
||||||
weakref.ref(1)()
|
weakref.ref(1)()
|
||||||
|
|
||||||
# -----------------
|
|
||||||
# functools
|
|
||||||
# -----------------
|
|
||||||
import functools
|
|
||||||
|
|
||||||
basetwo = functools.partial(int, base=2)
|
|
||||||
#? int()
|
|
||||||
basetwo()
|
|
||||||
|
|
||||||
def function(a, b):
|
|
||||||
return a, b
|
|
||||||
a = functools.partial(function, 0)
|
|
||||||
|
|
||||||
#? int()
|
|
||||||
a('')[0]
|
|
||||||
#? str()
|
|
||||||
a('')[1]
|
|
||||||
|
|
||||||
kw = functools.partial(function, b=1.0)
|
|
||||||
tup = kw(1)
|
|
||||||
#? int()
|
|
||||||
tup[0]
|
|
||||||
#? float()
|
|
||||||
tup[1]
|
|
||||||
|
|
||||||
def my_decorator(f):
|
|
||||||
@functools.wraps(f)
|
|
||||||
def wrapper(*args, **kwds):
|
|
||||||
return f(*args, **kwds)
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
@my_decorator
|
|
||||||
def example(a):
|
|
||||||
return a
|
|
||||||
|
|
||||||
#? str()
|
|
||||||
example('')
|
|
||||||
|
|
||||||
# From GH #1574
|
|
||||||
#? float()
|
|
||||||
functools.wraps(functools.partial(str, 1))(lambda: 1.0)()
|
|
||||||
|
|
||||||
# -----------------
|
# -----------------
|
||||||
# sqlite3 (#84)
|
# sqlite3 (#84)
|
||||||
# -----------------
|
# -----------------
|
||||||
@@ -253,7 +211,7 @@ z.read('name').upper
|
|||||||
# -----------------
|
# -----------------
|
||||||
# contextlib
|
# contextlib
|
||||||
# -----------------
|
# -----------------
|
||||||
# python > 2.7
|
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
import contextlib
|
import contextlib
|
||||||
with contextlib.closing('asd') as string:
|
with contextlib.closing('asd') as string:
|
||||||
@@ -384,7 +342,6 @@ class Test(metaclass=Meta):
|
|||||||
# Enum
|
# Enum
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|
||||||
# python > 2.7
|
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
class X(enum.Enum):
|
class X(enum.Enum):
|
||||||
@@ -409,8 +366,47 @@ X().name
|
|||||||
X().attr_x.attr_y.value
|
X().attr_x.attr_y.value
|
||||||
|
|
||||||
# -----------------
|
# -----------------
|
||||||
# functools Python 3.5+
|
# functools
|
||||||
# -----------------
|
# -----------------
|
||||||
|
import functools
|
||||||
|
|
||||||
|
basetwo = functools.partial(int, base=2)
|
||||||
|
#? int()
|
||||||
|
basetwo()
|
||||||
|
|
||||||
|
def function(a, b):
|
||||||
|
return a, b
|
||||||
|
a = functools.partial(function, 0)
|
||||||
|
|
||||||
|
#? int()
|
||||||
|
a('')[0]
|
||||||
|
#? str()
|
||||||
|
a('')[1]
|
||||||
|
|
||||||
|
kw = functools.partial(function, b=1.0)
|
||||||
|
tup = kw(1)
|
||||||
|
#? int()
|
||||||
|
tup[0]
|
||||||
|
#? float()
|
||||||
|
tup[1]
|
||||||
|
|
||||||
|
def my_decorator(f):
|
||||||
|
@functools.wraps(f)
|
||||||
|
def wrapper(*args, **kwds):
|
||||||
|
return f(*args, **kwds)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@my_decorator
|
||||||
|
def example(a):
|
||||||
|
return a
|
||||||
|
|
||||||
|
#? str()
|
||||||
|
example('')
|
||||||
|
|
||||||
|
# From GH #1574
|
||||||
|
#? float()
|
||||||
|
functools.wraps(functools.partial(str, 1))(lambda: 1.0)()
|
||||||
|
|
||||||
class X:
|
class X:
|
||||||
def function(self, a, b):
|
def function(self, a, b):
|
||||||
return a, b
|
return a, b
|
||||||
@@ -463,11 +459,6 @@ X().just_partial('')[0]
|
|||||||
#? str()
|
#? str()
|
||||||
X().just_partial('')[1]
|
X().just_partial('')[1]
|
||||||
|
|
||||||
|
|
||||||
# -----------------
|
|
||||||
# functools Python 3.8
|
|
||||||
# -----------------
|
|
||||||
|
|
||||||
# python >= 3.8
|
# python >= 3.8
|
||||||
|
|
||||||
@functools.lru_cache
|
@functools.lru_cache
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# python > 2.7
|
|
||||||
from stub_folder import with_stub, stub_only, with_stub_folder, stub_only_folder
|
from stub_folder import with_stub, stub_only, with_stub_folder, stub_only_folder
|
||||||
|
|
||||||
# -------------------------
|
# -------------------------
|
||||||
@@ -35,6 +34,7 @@ from stub_folder.with_stub import in_
|
|||||||
#? ['with_stub', 'stub_only', 'with_stub_folder', 'stub_only_folder']
|
#? ['with_stub', 'stub_only', 'with_stub_folder', 'stub_only_folder']
|
||||||
from stub_folder.
|
from stub_folder.
|
||||||
|
|
||||||
|
|
||||||
# -------------------------
|
# -------------------------
|
||||||
# Folders
|
# Folders
|
||||||
# -------------------------
|
# -------------------------
|
||||||
|
|||||||
@@ -135,7 +135,6 @@ set_t2.c
|
|||||||
# -----------------
|
# -----------------
|
||||||
# pep 448 unpacking generalizations
|
# pep 448 unpacking generalizations
|
||||||
# -----------------
|
# -----------------
|
||||||
# python >= 3.5
|
|
||||||
|
|
||||||
d = {'a': 3}
|
d = {'a': 3}
|
||||||
dc = {v: 3 for v in ['a']}
|
dc = {v: 3 for v in ['a']}
|
||||||
|
|||||||
@@ -354,7 +354,6 @@ class DefinitelyNotGlobal:
|
|||||||
# stubs
|
# stubs
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|
||||||
# python > 2.7
|
|
||||||
from stub_folder import with_stub
|
from stub_folder import with_stub
|
||||||
#< ('stub:stub_folder.with_stub', 5, 4), ('stub_folder.with_stub', 5, 4), (0, 10)
|
#< ('stub:stub_folder.with_stub', 5, 4), ('stub_folder.with_stub', 5, 4), (0, 10)
|
||||||
with_stub.stub_function
|
with_stub.stub_function
|
||||||
|
|||||||
+1
-3
@@ -102,9 +102,7 @@ def collect_static_analysis_tests(base_dir, test_files):
|
|||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def venv_path(tmpdir_factory, environment):
|
def venv_path(tmpdir_factory, environment):
|
||||||
if environment.version_info.major < 3:
|
if isinstance(environment, InterpreterEnvironment):
|
||||||
pytest.skip("python -m venv does not exist in Python 2")
|
|
||||||
elif isinstance(environment, InterpreterEnvironment):
|
|
||||||
# The environment can be a tox virtualenv environment which we don't
|
# The environment can be a tox virtualenv environment which we don't
|
||||||
# want, so use the system environment.
|
# want, so use the system environment.
|
||||||
environment = get_system_environment(
|
environment = get_system_environment(
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
"""
|
|
||||||
This is a module that imports the *standard library* unittest,
|
|
||||||
despite there being a local "unittest" module. It specifies that it
|
|
||||||
wants the stdlib one with the ``absolute_import`` __future__ import.
|
|
||||||
|
|
||||||
The twisted equivalent of this module is ``twisted.trial._synctest``.
|
|
||||||
"""
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
|
|
||||||
class Assertions(unittest.TestCase):
|
|
||||||
pass
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
"""
|
|
||||||
This is a module that shadows a builtin (intentionally).
|
|
||||||
|
|
||||||
It imports a local module, which in turn imports stdlib unittest (the
|
|
||||||
name shadowed by this module). If that is properly resolved, there's
|
|
||||||
no problem. However, if jedi doesn't understand absolute_imports, it
|
|
||||||
will get this module again, causing infinite recursion.
|
|
||||||
"""
|
|
||||||
from local_module import Assertions
|
|
||||||
|
|
||||||
|
|
||||||
class TestCase(Assertions):
|
|
||||||
def test(self):
|
|
||||||
self.assertT
|
|
||||||
+8
-15
@@ -3,25 +3,18 @@ A helper module for testing, improves compatibility for testing (as
|
|||||||
``jedi._compatibility``) as well as introducing helper functions.
|
``jedi._compatibility``) as well as introducing helper functions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
if sys.hexversion < 0x02070000:
|
|
||||||
import unittest2 as unittest
|
|
||||||
else:
|
|
||||||
import unittest
|
|
||||||
TestCase = unittest.TestCase
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
from os.path import abspath, dirname, join
|
|
||||||
from functools import partial, wraps
|
from functools import partial, wraps
|
||||||
from jedi import Project
|
from jedi import Project
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
test_dir = dirname(abspath(__file__))
|
test_dir = Path(__file__).absolute().parent
|
||||||
test_dir_project = Project(test_dir)
|
test_dir_project = Project(test_dir)
|
||||||
root_dir = dirname(test_dir)
|
root_dir = test_dir.parent
|
||||||
example_dir = join(test_dir, 'examples')
|
example_dir = test_dir.joinpath('examples')
|
||||||
|
|
||||||
sample_int = 1 # This is used in completion/imports.py
|
sample_int = 1 # This is used in completion/imports.py
|
||||||
|
|
||||||
@@ -32,7 +25,7 @@ skip_if_not_windows = partial(pytest.param,
|
|||||||
|
|
||||||
|
|
||||||
def get_example_dir(*names):
|
def get_example_dir(*names):
|
||||||
return join(example_dir, *names)
|
return example_dir.joinpath(*names)
|
||||||
|
|
||||||
|
|
||||||
def cwd_at(path):
|
def cwd_at(path):
|
||||||
@@ -53,10 +46,10 @@ def cwd_at(path):
|
|||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def set_cwd(path, absolute_path=False):
|
def set_cwd(path, absolute_path=False):
|
||||||
repo_root = os.path.dirname(test_dir)
|
repo_root = test_dir.parent
|
||||||
|
|
||||||
oldcwd = os.getcwd()
|
oldcwd = Path.cwd()
|
||||||
os.chdir(os.path.join(repo_root, path))
|
os.chdir(repo_root.joinpath(path))
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user