mirror of
https://github.com/davidhalter/jedi.git
synced 2026-03-18 00:32:23 +08:00
Merge branch 'python3'
This commit is contained in:
@@ -5,15 +5,11 @@ python:
|
||||
- 3.8
|
||||
- 3.7
|
||||
- 3.6
|
||||
- 3.5
|
||||
- 2.7
|
||||
|
||||
env:
|
||||
- JEDI_TEST_ENVIRONMENT=38
|
||||
- JEDI_TEST_ENVIRONMENT=37
|
||||
- JEDI_TEST_ENVIRONMENT=36
|
||||
- JEDI_TEST_ENVIRONMENT=35
|
||||
- JEDI_TEST_ENVIRONMENT=27
|
||||
- JEDI_TEST_ENVIRONMENT=interpreter
|
||||
|
||||
matrix:
|
||||
|
||||
@@ -98,7 +98,7 @@ Features and Limitations
|
||||
Jedi's features are listed here:
|
||||
`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
|
||||
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
|
||||
very well.
|
||||
|
||||
38
appveyor.yml
38
appveyor.yml
@@ -6,12 +6,6 @@ environment:
|
||||
- TOXENV: py37
|
||||
PYTHON_PATH: C:\Python37
|
||||
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
|
||||
PYTHON_PATH: C:\Python36
|
||||
@@ -19,38 +13,6 @@ environment:
|
||||
- TOXENV: py36
|
||||
PYTHON_PATH: C:\Python36
|
||||
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:
|
||||
- git submodule update --init --recursive
|
||||
- set PATH=%PYTHON_PATH%;%PYTHON_PATH%\Scripts;%PATH%
|
||||
|
||||
44
conftest.py
44
conftest.py
@@ -8,7 +8,6 @@ import pytest
|
||||
|
||||
import jedi
|
||||
from jedi.api.environment import get_system_environment, InterpreterEnvironment
|
||||
from jedi._compatibility import py_version
|
||||
from test.helpers import test_dir
|
||||
|
||||
collect_ignore = [
|
||||
@@ -18,9 +17,6 @@ collect_ignore = [
|
||||
'build/',
|
||||
'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
|
||||
@@ -45,7 +41,7 @@ def pytest_addoption(parser):
|
||||
help="Warnings are treated as errors.")
|
||||
|
||||
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',
|
||||
help="Don't use subprocesses to guarantee having safe "
|
||||
"code execution. Useful for debugging.")
|
||||
@@ -97,7 +93,8 @@ def clean_jedi_cache(request):
|
||||
def environment(request):
|
||||
version = request.config.option.env
|
||||
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':
|
||||
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)
|
||||
|
||||
|
||||
@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')
|
||||
def has_django(environment):
|
||||
script = jedi.Script('import django', environment=environment)
|
||||
@@ -158,14 +144,6 @@ def jedi_path():
|
||||
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()
|
||||
def skip_pre_python38(environment):
|
||||
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
|
||||
# they should for all Python versions.
|
||||
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()
|
||||
|
||||
18
docs/conf.py
18
docs/conf.py
@@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Jedi documentation build configuration file, created by
|
||||
# sphinx-quickstart on Wed Dec 26 00:11:34 2012.
|
||||
#
|
||||
@@ -43,8 +41,8 @@ source_encoding = 'utf-8'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Jedi'
|
||||
copyright = u'jedi contributors'
|
||||
project = 'Jedi'
|
||||
copyright = 'jedi contributors'
|
||||
|
||||
import jedi
|
||||
from jedi.utils import version_info
|
||||
@@ -205,8 +203,8 @@ latex_elements = {
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Jedi.tex', u'Jedi Documentation',
|
||||
u'Jedi contributors', 'manual'),
|
||||
('index', 'Jedi.tex', 'Jedi Documentation',
|
||||
'Jedi contributors', 'manual'),
|
||||
]
|
||||
|
||||
# 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
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'jedi', u'Jedi Documentation',
|
||||
[u'Jedi contributors'], 1)
|
||||
('index', 'jedi', 'Jedi Documentation',
|
||||
['Jedi contributors'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
@@ -249,8 +247,8 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'Jedi', u'Jedi Documentation',
|
||||
u'Jedi contributors', 'Jedi', 'Awesome Python autocompletion library.',
|
||||
('index', 'Jedi', 'Jedi Documentation',
|
||||
'Jedi contributors', 'Jedi', 'Awesome Python autocompletion library.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ Completions
|
||||
>>> code = '''import json; json.l'''
|
||||
>>> script = jedi.Script(code, path='example.py')
|
||||
>>> 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
|
||||
[<Completion: load>, <Completion: loads>]
|
||||
|
||||
@@ -16,7 +16,7 @@ Jedi's main API calls and features are:
|
||||
Basic Features
|
||||
--------------
|
||||
|
||||
- Python 2.7 and 3.5+ support
|
||||
- Python 3.6+ support
|
||||
- Ignores syntax errors and wrong indentation
|
||||
- Can deal with complex module / function / class structures
|
||||
- Great ``virtualenv``/``venv`` support
|
||||
|
||||
@@ -50,14 +50,6 @@ Arch Linux
|
||||
You can install |jedi| directly from official Arch Linux packages:
|
||||
|
||||
- `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:
|
||||
`vim-jedi at Arch Linux <https://www.archlinux.org/packages/community/any/vim-jedi/>`__.)
|
||||
|
||||
@@ -1,292 +1,13 @@
|
||||
"""
|
||||
To ensure compatibility from Python ``2.7`` - ``3.x``, a module has been
|
||||
created. Clearly there is huge need to use conforming syntax.
|
||||
This module is here to ensure compatibility of Windows/Linux/MacOS and
|
||||
different Python versions.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
import atexit
|
||||
import errno
|
||||
import functools
|
||||
import sys
|
||||
import os
|
||||
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]))
|
||||
import pickle
|
||||
|
||||
|
||||
if sys.version_info[:2] < (3, 5):
|
||||
"""
|
||||
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):
|
||||
def cast_path(string):
|
||||
"""
|
||||
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
|
||||
soon anyway, just go with always strings.
|
||||
"""
|
||||
return u(obj, errors='replace')
|
||||
|
||||
|
||||
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
|
||||
if isinstance(string, bytes):
|
||||
return str(string, encoding='UTF-8', errors='replace')
|
||||
return str(string)
|
||||
|
||||
|
||||
def pickle_load(file):
|
||||
try:
|
||||
if is_py3:
|
||||
return pickle.load(file, encoding='bytes')
|
||||
return pickle.load(file)
|
||||
# Python on Windows don't throw EOF errors for pipes. So reraise them with
|
||||
# the correct type, which is caught upwards.
|
||||
@@ -403,24 +34,8 @@ def pickle_load(file):
|
||||
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):
|
||||
try:
|
||||
if not is_py3:
|
||||
data = _python2_dct_keys_to_unicode(data)
|
||||
pickle.dump(data, file, protocol)
|
||||
# On Python 3.3 flush throws sometimes an error even though the writing
|
||||
# operation should be completed.
|
||||
@@ -431,201 +46,3 @@ def pickle_dump(data, file, protocol):
|
||||
if sys.platform == 'win32':
|
||||
raise IOError(errno.EPIPE, "Broken pipe")
|
||||
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
|
||||
|
||||
@@ -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
|
||||
arguments.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
from functools import wraps
|
||||
from pathlib import Path
|
||||
|
||||
import parso
|
||||
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 import debug
|
||||
from jedi import settings
|
||||
@@ -51,18 +50,6 @@ from jedi.inference.utils import to_list
|
||||
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):
|
||||
"""
|
||||
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
|
||||
:param path: The path of the file in the file system, or ``''`` if
|
||||
it hasn't been saved yet.
|
||||
:type path: str 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
|
||||
:type path: str or pathlib.Path or None
|
||||
:param sys_path: Deprecated, use the project parameter.
|
||||
:type sys_path: typing.List[str]
|
||||
: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.
|
||||
"""
|
||||
def __init__(self, code=None, line=None, column=None, path=None,
|
||||
encoding=None, sys_path=None, environment=None,
|
||||
project=None, source=None):
|
||||
sys_path=None, environment=None, project=None, source=None):
|
||||
self._orig_path = 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:
|
||||
warnings.warn(
|
||||
"Providing the line is now done in the functions themselves "
|
||||
@@ -163,14 +140,9 @@ class Script(object):
|
||||
with open(path, 'rb') as f:
|
||||
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:
|
||||
# Load the Python grammar of the current interpreter.
|
||||
project = get_default_project(
|
||||
os.path.dirname(self.path) if path else None
|
||||
)
|
||||
project = get_default_project(None if self.path is None else self.path.parent)
|
||||
# TODO deprecate and remove sys_path from the Script API.
|
||||
if sys_path is not None:
|
||||
project._sys_path = sys_path
|
||||
@@ -188,8 +160,7 @@ class Script(object):
|
||||
self._module_node, code = self._inference_state.parse_and_get_code(
|
||||
code=code,
|
||||
path=self.path,
|
||||
encoding=encoding,
|
||||
use_latest_grammar=path and path.endswith('.pyi'),
|
||||
use_latest_grammar=path and path.suffix == 'pyi',
|
||||
cache=False, # No disk cache, because the current script often changes.
|
||||
diff_cache=settings.fast_parser,
|
||||
cache_path=settings.cache_directory,
|
||||
@@ -221,7 +192,7 @@ class Script(object):
|
||||
file_io = None
|
||||
else:
|
||||
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.
|
||||
stub_module = load_proper_stub_module(
|
||||
self._inference_state,
|
||||
@@ -242,7 +213,7 @@ class Script(object):
|
||||
code_lines=self._code_lines,
|
||||
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.
|
||||
self._inference_state.module_cache.add(names, ValueSet([module]))
|
||||
return module
|
||||
@@ -258,7 +229,7 @@ class Script(object):
|
||||
)
|
||||
|
||||
@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.
|
||||
|
||||
@@ -272,9 +243,6 @@ class Script(object):
|
||||
before magic methods and name mangled names that start with ``__``.
|
||||
: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'):
|
||||
completion = Completion(
|
||||
self._inference_state, self._get_module_context(), self._code_lines,
|
||||
@@ -291,7 +259,7 @@ class Script(object):
|
||||
return self.complete(*self._pos, fuzzy=fuzzy)
|
||||
|
||||
@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
|
||||
around Jedi's type inference.
|
||||
@@ -307,18 +275,6 @@ class Script(object):
|
||||
:param prefer_stubs: Prefer stubs to Python objects for this method.
|
||||
: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
|
||||
leaf = self._module_node.get_name_of_position(pos)
|
||||
if leaf is None:
|
||||
@@ -341,6 +297,14 @@ class Script(object):
|
||||
# the API.
|
||||
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):
|
||||
warnings.warn(
|
||||
"Deprecated since version 0.16.0. Use Script(...).goto instead.",
|
||||
@@ -353,7 +317,8 @@ class Script(object):
|
||||
**kwargs)
|
||||
|
||||
@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
|
||||
you can follow imports.
|
||||
@@ -367,11 +332,6 @@ class Script(object):
|
||||
:param prefer_stubs: Prefer stubs to Python objects for this method.
|
||||
: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))
|
||||
if tree_name is None:
|
||||
# Without a name we really just want to jump to the result e.g.
|
||||
@@ -407,8 +367,7 @@ class Script(object):
|
||||
# Avoid duplicates
|
||||
return list(set(helpers.sorted_definitions(defs)))
|
||||
|
||||
@_no_python2_support
|
||||
def search(self, string, **kwargs):
|
||||
def search(self, string, *, all_scopes=False):
|
||||
"""
|
||||
Searches a name in the current file. For a description of how the
|
||||
search string should look like, please have a look at
|
||||
@@ -419,9 +378,6 @@ class Script(object):
|
||||
functions and classes.
|
||||
: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)
|
||||
|
||||
@to_list
|
||||
@@ -685,8 +641,7 @@ class Script(object):
|
||||
]
|
||||
return sorted(defs, key=lambda x: x.start_pos)
|
||||
|
||||
@_no_python2_support
|
||||
def rename(self, line=None, column=None, **kwargs):
|
||||
def rename(self, line=None, column=None, *, new_name):
|
||||
"""
|
||||
Renames all references of the variable under the cursor.
|
||||
|
||||
@@ -695,14 +650,11 @@ class Script(object):
|
||||
:raises: :exc:`.RefactoringError`
|
||||
: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)
|
||||
return refactoring.rename(self._inference_state, definitions, new_name)
|
||||
|
||||
@_no_python2_support
|
||||
def extract_variable(self, line, column, **kwargs):
|
||||
@validate_line_column
|
||||
def extract_variable(self, line, column, *, new_name, until_line=None, until_column=None):
|
||||
"""
|
||||
Moves an expression to a new statemenet.
|
||||
|
||||
@@ -727,10 +679,6 @@ class Script(object):
|
||||
:raises: :exc:`.RefactoringError`
|
||||
: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:
|
||||
until_pos = None
|
||||
else:
|
||||
@@ -744,8 +692,8 @@ class Script(object):
|
||||
new_name, (line, column), until_pos
|
||||
)
|
||||
|
||||
@_no_python2_support
|
||||
def extract_function(self, line, column, **kwargs):
|
||||
@validate_line_column
|
||||
def extract_function(self, line, column, *, new_name, until_line=None, until_column=None):
|
||||
"""
|
||||
Moves an expression to a new function.
|
||||
|
||||
@@ -778,10 +726,6 @@ class Script(object):
|
||||
:raises: :exc:`.RefactoringError`
|
||||
: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:
|
||||
until_pos = None
|
||||
else:
|
||||
@@ -795,7 +739,6 @@ class Script(object):
|
||||
new_name, (line, column), until_pos
|
||||
)
|
||||
|
||||
@_no_python2_support
|
||||
def inline(self, line=None, column=None):
|
||||
"""
|
||||
Inlines a variable under the cursor. This is basically the opposite of
|
||||
@@ -855,8 +798,8 @@ class Interpreter(Script):
|
||||
if not isinstance(environment, InterpreterEnvironment):
|
||||
raise TypeError("The environment needs to be an InterpreterEnvironment subclass.")
|
||||
|
||||
super(Interpreter, self).__init__(code, environment=environment,
|
||||
project=Project(os.getcwd()), **kwds)
|
||||
super().__init__(code, environment=environment,
|
||||
project=Project(Path.cwd()), **kwds)
|
||||
self.namespaces = namespaces
|
||||
self._inference_state.allow_descriptor_getattr = self._allow_descriptor_getattr_default
|
||||
|
||||
@@ -864,7 +807,7 @@ class Interpreter(Script):
|
||||
def _get_module_context(self):
|
||||
tree_module_value = ModuleValue(
|
||||
self._inference_state, self._module_node,
|
||||
file_io=KnownContentFileIO(self.path, self._code),
|
||||
file_io=KnownContentFileIO(str(self.path), self._code),
|
||||
string_names=('__main__',),
|
||||
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):
|
||||
warnings.warn(
|
||||
"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
|
||||
)
|
||||
|
||||
return Script(source, path=path, encoding=encoding).get_names(
|
||||
return Script(source, path=path).get_names(
|
||||
all_scopes=all_scopes,
|
||||
definitions=definitions,
|
||||
references=references,
|
||||
@@ -899,7 +842,7 @@ def preload_module(*modules):
|
||||
"""
|
||||
for m in modules:
|
||||
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,
|
||||
|
||||
@@ -14,8 +14,8 @@ These classes are the much biggest part of the API, because they contain
|
||||
the interesting information about all operations.
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
from typing import Optional
|
||||
|
||||
from parso.python.tree import search_ancestor
|
||||
|
||||
@@ -71,7 +71,6 @@ class BaseName(object):
|
||||
'_collections': 'collections',
|
||||
'_socket': 'socket',
|
||||
'_sqlite3': 'sqlite3',
|
||||
'__builtin__': 'builtins',
|
||||
}
|
||||
|
||||
_tuple_mapping = dict((tuple(k.split('.')), v) for (k, v) in {
|
||||
@@ -94,9 +93,9 @@ class BaseName(object):
|
||||
return self._name.get_root_context()
|
||||
|
||||
@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
|
||||
"""
|
||||
@@ -104,7 +103,9 @@ class BaseName(object):
|
||||
if module.is_stub() or not module.is_compiled():
|
||||
# Compiled modules should not return a module path even if they
|
||||
# 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
|
||||
|
||||
@@ -129,7 +130,6 @@ class BaseName(object):
|
||||
to Jedi, :meth:`jedi.Script.infer` should return a list of
|
||||
definition for ``sys``, ``f``, ``C`` and ``x``.
|
||||
|
||||
>>> from jedi._compatibility import no_unicode_pprint
|
||||
>>> from jedi import Script
|
||||
>>> source = '''
|
||||
... import keyword
|
||||
@@ -155,7 +155,7 @@ class BaseName(object):
|
||||
so that it is easy to relate the result to the source code.
|
||||
|
||||
>>> 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='__main__.C', description='class C'>,
|
||||
<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`:
|
||||
|
||||
>>> 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]
|
||||
'module'
|
||||
>>> defs[1]
|
||||
@@ -324,7 +324,6 @@ class BaseName(object):
|
||||
|
||||
Example:
|
||||
|
||||
>>> from jedi._compatibility import no_unicode_pprint
|
||||
>>> from jedi import Script
|
||||
>>> source = '''
|
||||
... def f():
|
||||
@@ -337,10 +336,10 @@ class BaseName(object):
|
||||
>>> script = Script(source) # line is maximum by default
|
||||
>>> defs = script.infer(column=3)
|
||||
>>> 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__.C', description='class C'>]
|
||||
>>> str(defs[0].description) # strip literals in python2
|
||||
>>> str(defs[0].description)
|
||||
'def f'
|
||||
>>> str(defs[1].description)
|
||||
'class C'
|
||||
@@ -424,7 +423,10 @@ class BaseName(object):
|
||||
return False
|
||||
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
|
||||
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.
|
||||
: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:
|
||||
return []
|
||||
|
||||
@@ -465,7 +453,16 @@ class BaseName(object):
|
||||
return [self if n == self._name else Name(self._inference_state, n)
|
||||
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
|
||||
the current name has.
|
||||
@@ -482,10 +479,6 @@ class BaseName(object):
|
||||
inference call.
|
||||
: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)
|
||||
|
||||
if not self._name.is_value_name:
|
||||
@@ -645,7 +638,7 @@ class Completion(BaseName):
|
||||
"""
|
||||
def __init__(self, inference_state, name, stack, like_name_length,
|
||||
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._stack = stack
|
||||
@@ -716,7 +709,7 @@ class Completion(BaseName):
|
||||
# wouldn't load like > 100 Python modules anymore.
|
||||
fast = False
|
||||
|
||||
return super(Completion, self).docstring(raw=raw, fast=fast)
|
||||
return super().docstring(raw=raw, fast=fast)
|
||||
|
||||
def _get_docstring(self):
|
||||
if self._cached_name is not None:
|
||||
@@ -725,7 +718,7 @@ class Completion(BaseName):
|
||||
self._name.get_public_name(),
|
||||
lambda: self._get_cache()
|
||||
)
|
||||
return super(Completion, self)._get_docstring()
|
||||
return super()._get_docstring()
|
||||
|
||||
def _get_docstring_signature(self):
|
||||
if self._cached_name is not None:
|
||||
@@ -734,13 +727,13 @@ class Completion(BaseName):
|
||||
self._name.get_public_name(),
|
||||
lambda: self._get_cache()
|
||||
)
|
||||
return super(Completion, self)._get_docstring_signature()
|
||||
return super()._get_docstring_signature()
|
||||
|
||||
def _get_cache(self):
|
||||
return (
|
||||
super(Completion, self).type,
|
||||
super(Completion, self)._get_docstring_signature(),
|
||||
super(Completion, self)._get_docstring(),
|
||||
super().type,
|
||||
super()._get_docstring_signature(),
|
||||
super()._get_docstring(),
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -756,7 +749,7 @@ class Completion(BaseName):
|
||||
lambda: self._get_cache()
|
||||
)
|
||||
|
||||
return super(Completion, self).type
|
||||
return super().type
|
||||
|
||||
def __repr__(self):
|
||||
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`.
|
||||
"""
|
||||
def __init__(self, inference_state, definition):
|
||||
super(Name, self).__init__(inference_state, definition)
|
||||
super().__init__(inference_state, definition)
|
||||
|
||||
@property
|
||||
def desc_with_module(self):
|
||||
@@ -821,7 +814,7 @@ class BaseSignature(Name):
|
||||
calls.
|
||||
"""
|
||||
def __init__(self, inference_state, signature):
|
||||
super(BaseSignature, self).__init__(inference_state, signature.name)
|
||||
super().__init__(inference_state, signature.name)
|
||||
self._signature = signature
|
||||
|
||||
@property
|
||||
@@ -851,7 +844,7 @@ class Signature(BaseSignature):
|
||||
:meth:`.Script.get_signatures`.
|
||||
"""
|
||||
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._signature = signature
|
||||
|
||||
@@ -918,8 +911,4 @@ class ParamName(Name):
|
||||
|
||||
: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()
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import re
|
||||
from textwrap import dedent
|
||||
from inspect import Parameter
|
||||
|
||||
from parso.python.token import PythonTokenTypes
|
||||
from parso.python import tree
|
||||
from parso.tree import search_ancestor, Leaf
|
||||
from parso import split_lines
|
||||
|
||||
from jedi._compatibility import Parameter
|
||||
from jedi import debug
|
||||
from jedi import settings
|
||||
from jedi.api import classes
|
||||
@@ -34,9 +34,7 @@ def _get_signature_param_names(signatures, positional_count, used_kwargs):
|
||||
# Add named params
|
||||
for call_sig in signatures:
|
||||
for i, p in enumerate(call_sig.params):
|
||||
# Allow protected access, because it's a public API.
|
||||
# TODO reconsider with Python 2 drop
|
||||
kind = p._name.get_kind()
|
||||
kind = p.kind
|
||||
if i < positional_count and kind == Parameter.POSITIONAL_OR_KEYWORD:
|
||||
continue
|
||||
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
|
||||
for signature in signatures:
|
||||
for i, p in enumerate(signature.params):
|
||||
# TODO reconsider with Python 2 drop
|
||||
kind = p._name.get_kind()
|
||||
kind = p.kind
|
||||
if kind is Parameter.VAR_POSITIONAL:
|
||||
# In case there were not already kwargs, the next param can
|
||||
# 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
|
||||
out of luck I guess :) ~dave.
|
||||
"""
|
||||
names = (instance.get_function_slot_names(u'__getattr__')
|
||||
or instance.get_function_slot_names(u'__getattribute__'))
|
||||
names = (instance.get_function_slot_names('__getattr__')
|
||||
or instance.get_function_slot_names('__getattribute__'))
|
||||
functions = ValueSet.from_sets(
|
||||
name.infer()
|
||||
for name in names
|
||||
|
||||
@@ -7,8 +7,8 @@ import sys
|
||||
import hashlib
|
||||
import filecmp
|
||||
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.inference.compiled.subprocess import CompiledSubprocess, \
|
||||
InferenceStateSameProcess, InferenceStateSubprocess
|
||||
@@ -17,7 +17,7 @@ import parso
|
||||
|
||||
_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']
|
||||
_CONDA_VAR = 'CONDA_PREFIX'
|
||||
_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
|
||||
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
|
||||
|
||||
def __repr__(self):
|
||||
@@ -267,7 +257,7 @@ def _get_cached_default_environment():
|
||||
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
|
||||
Virtualenvs. It will search in these paths and potentially execute the
|
||||
@@ -284,47 +274,44 @@ def find_virtualenvs(paths=None, **kwargs):
|
||||
|
||||
:yields: :class:`.Environment`
|
||||
"""
|
||||
def py27_comp(paths=None, safe=True, use_environment_vars=True):
|
||||
if paths is None:
|
||||
paths = []
|
||||
if paths is None:
|
||||
paths = []
|
||||
|
||||
_used_paths = set()
|
||||
_used_paths = set()
|
||||
|
||||
if use_environment_vars:
|
||||
# Using this variable should be safe, because attackers might be
|
||||
# able to drop files (via git) but not environment variables.
|
||||
virtual_env = _get_virtual_env_from_var()
|
||||
if virtual_env is not None:
|
||||
yield virtual_env
|
||||
_used_paths.add(virtual_env.path)
|
||||
if use_environment_vars:
|
||||
# Using this variable should be safe, because attackers might be
|
||||
# able to drop files (via git) but not environment variables.
|
||||
virtual_env = _get_virtual_env_from_var()
|
||||
if virtual_env is not None:
|
||||
yield virtual_env
|
||||
_used_paths.add(virtual_env.path)
|
||||
|
||||
conda_env = _get_virtual_env_from_var(_CONDA_VAR)
|
||||
if conda_env is not None:
|
||||
yield conda_env
|
||||
_used_paths.add(conda_env.path)
|
||||
conda_env = _get_virtual_env_from_var(_CONDA_VAR)
|
||||
if conda_env is not None:
|
||||
yield conda_env
|
||||
_used_paths.add(conda_env.path)
|
||||
|
||||
for directory in paths:
|
||||
if not os.path.isdir(directory):
|
||||
for directory in paths:
|
||||
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
|
||||
_used_paths.add(path)
|
||||
|
||||
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
|
||||
_used_paths.add(path)
|
||||
|
||||
try:
|
||||
executable = _get_executable_path(path, safe=safe)
|
||||
yield Environment(executable)
|
||||
except InvalidPythonEnvironment:
|
||||
pass
|
||||
|
||||
return py27_comp(paths, **kwargs)
|
||||
try:
|
||||
executable = _get_executable_path(path, safe=safe)
|
||||
yield Environment(executable)
|
||||
except InvalidPythonEnvironment:
|
||||
pass
|
||||
|
||||
|
||||
def find_system_environments(**kwargs):
|
||||
def find_system_environments(*, env_vars={}):
|
||||
"""
|
||||
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
|
||||
@@ -336,14 +323,14 @@ def find_system_environments(**kwargs):
|
||||
"""
|
||||
for version_string in _SUPPORTED_PYTHONS:
|
||||
try:
|
||||
yield get_system_environment(version_string, **kwargs)
|
||||
yield get_system_environment(version_string, env_vars=env_vars)
|
||||
except InvalidPythonEnvironment:
|
||||
pass
|
||||
|
||||
|
||||
# TODO: this function should probably return a list of environments since
|
||||
# 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'
|
||||
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':
|
||||
for exe in _get_executables_from_windows_registry(version):
|
||||
try:
|
||||
return Environment(exe, **kwargs)
|
||||
return Environment(exe, env_vars=env_vars)
|
||||
except InvalidPythonEnvironment:
|
||||
pass
|
||||
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
|
||||
Virtualenv path or an executable path and optional environment variables.
|
||||
|
||||
:raises: :exc:`.InvalidPythonEnvironment`
|
||||
: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):
|
||||
_assert_safe(path, safe)
|
||||
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):
|
||||
# The winreg module is named _winreg on Python 2.
|
||||
try:
|
||||
import winreg
|
||||
except ImportError:
|
||||
import _winreg as winreg
|
||||
import winreg
|
||||
|
||||
# TODO: support Python Anaconda.
|
||||
sub_keys = [
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import os
|
||||
|
||||
from jedi._compatibility import FileNotFoundError, force_unicode, scandir
|
||||
from jedi.api import classes
|
||||
from jedi.api.strings import StringName, get_quote_ending
|
||||
from jedi.api.helpers import match
|
||||
@@ -8,7 +7,7 @@ from jedi.inference.helpers import get_str_or_none
|
||||
|
||||
|
||||
class PathName(StringName):
|
||||
api_type = u'path'
|
||||
api_type = 'path'
|
||||
|
||||
|
||||
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
|
||||
base_path = os.path.join(inference_state.project.path, string)
|
||||
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: '...'
|
||||
except (FileNotFoundError, OSError):
|
||||
return
|
||||
@@ -94,7 +93,7 @@ def _add_strings(context, nodes, add_slash=False):
|
||||
return None
|
||||
if not first and add_slash:
|
||||
string += os.path.sep
|
||||
string += force_unicode(s)
|
||||
string += s
|
||||
first = False
|
||||
return string
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ from collections import namedtuple
|
||||
from textwrap import dedent
|
||||
from itertools import chain
|
||||
from functools import wraps
|
||||
from inspect import Parameter
|
||||
|
||||
from parso.python.parser import Parser
|
||||
from parso.python import tree
|
||||
|
||||
from jedi._compatibility import u, Parameter
|
||||
from jedi.inference.base_value import NO_VALUES
|
||||
from jedi.inference.syntax_tree import infer_atom
|
||||
from jedi.inference.helpers import infer_call_of_leaf
|
||||
@@ -44,7 +44,10 @@ def match(string, like_name, fuzzy=False):
|
||||
|
||||
def sorted_definitions(defs):
|
||||
# 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):
|
||||
@@ -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.
|
||||
leaf = leaf.get_previous_leaf()
|
||||
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'
|
||||
while leaf.type == 'newline':
|
||||
leaf = leaf.get_previous_leaf()
|
||||
if leaf is None:
|
||||
return u('')
|
||||
return ''
|
||||
|
||||
if leaf.type == 'error_leaf' or leaf.type == 'string':
|
||||
if leaf.start_pos[0] < position[0]:
|
||||
# On a different line, we just begin anew.
|
||||
return u('')
|
||||
return ''
|
||||
|
||||
# Error leafs cannot be parsed, completion in strings is also
|
||||
# impossible.
|
||||
@@ -111,7 +114,7 @@ def _get_code_for_stack(code_lines, leaf, position):
|
||||
if user_stmt.start_pos[1] > position[1]:
|
||||
# This means that it's actually a dedent and that means that we
|
||||
# start without value (part of a suite).
|
||||
return u('')
|
||||
return ''
|
||||
|
||||
# This is basically getting the relevant lines.
|
||||
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]]
|
||||
nodes_before = [c for c in nodes if c.start_pos < position]
|
||||
if nodes_before[-1].type == 'arglist':
|
||||
for x in _iter_arguments(nodes_before[-1].children, position):
|
||||
yield x # Python 2 :(
|
||||
yield from _iter_arguments(nodes_before[-1].children, position)
|
||||
return
|
||||
|
||||
previous_node_yielded = False
|
||||
@@ -320,7 +322,7 @@ def _iter_arguments(nodes, position):
|
||||
else:
|
||||
yield 0, None, False
|
||||
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]:
|
||||
if n.type == 'star_expr':
|
||||
stars_seen = 1
|
||||
|
||||
@@ -47,7 +47,7 @@ class MixedParserTreeFilter(ParserTreeFilter):
|
||||
|
||||
class MixedModuleContext(ModuleContext):
|
||||
def __init__(self, tree_module_value, namespaces):
|
||||
super(MixedModuleContext, self).__init__(tree_module_value)
|
||||
super().__init__(tree_module_value)
|
||||
self.mixed_values = [
|
||||
self._get_mixed_object(
|
||||
_create(self.inference_state, NamespaceObject(n))
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
import pydoc
|
||||
from contextlib import suppress
|
||||
|
||||
from jedi.inference.utils import ignored
|
||||
from jedi.inference.names import AbstractArbitraryName
|
||||
|
||||
try:
|
||||
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
|
||||
from pydoc_data import topics as pydoc_topics
|
||||
|
||||
|
||||
class KeywordName(AbstractArbitraryName):
|
||||
api_type = u'keyword'
|
||||
api_type = 'keyword'
|
||||
|
||||
def py__doc__(self):
|
||||
return imitate_pydoc(self.string_name)
|
||||
@@ -30,11 +21,8 @@ def imitate_pydoc(string):
|
||||
if pydoc_topics is None:
|
||||
return ''
|
||||
|
||||
# str needed because of possible unicode stuff in py2k (pydoc doesn't work
|
||||
# with unicode strings)
|
||||
string = str(string)
|
||||
h = pydoc.help
|
||||
with ignored(KeyError):
|
||||
with suppress(KeyError):
|
||||
# try to access symbols
|
||||
string = h.symbols[string]
|
||||
string, _, related = string.partition(' ')
|
||||
|
||||
@@ -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
|
||||
be used across repositories.
|
||||
"""
|
||||
import os
|
||||
import errno
|
||||
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.api.environment import get_cached_default_environment, create_environment
|
||||
from jedi.api.exceptions import WrongVersion
|
||||
from jedi.api.completion import search_in_module
|
||||
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, \
|
||||
load_namespace_from_path, iter_module_names
|
||||
from jedi.inference.sys_path import discover_buildout_paths
|
||||
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.file_io import FolderIO
|
||||
from jedi.common import traverse_parents
|
||||
|
||||
_CONFIG_FOLDER = '.jedi'
|
||||
_CONTAINS_POTENTIAL_PROJECT = \
|
||||
@@ -61,10 +56,6 @@ def _remove_duplicates_from_path(path):
|
||||
yield p
|
||||
|
||||
|
||||
def _force_unicode_list(lst):
|
||||
return list(map(force_unicode, lst))
|
||||
|
||||
|
||||
class Project(object):
|
||||
"""
|
||||
Projects are a simple way to manage Python folders and define how Jedi does
|
||||
@@ -75,11 +66,11 @@ class Project(object):
|
||||
|
||||
@staticmethod
|
||||
def _get_config_folder_path(base_path):
|
||||
return os.path.join(base_path, _CONFIG_FOLDER)
|
||||
return base_path.joinpath(_CONFIG_FOLDER)
|
||||
|
||||
@staticmethod
|
||||
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
|
||||
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.
|
||||
"""
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
with open(cls._get_json_path(path)) as f:
|
||||
version, data = json.load(f)
|
||||
|
||||
@@ -107,13 +100,9 @@ class Project(object):
|
||||
data.pop('_environment', None)
|
||||
data.pop('_django', None) # TODO make django setting public?
|
||||
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)
|
||||
try:
|
||||
os.makedirs(self._get_config_folder_path(self._path))
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
self._get_config_folder_path(self._path).mkdir(parents=True, exist_ok=True)
|
||||
with open(self._get_json_path(self._path), 'w') as 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,
|
||||
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
|
||||
if sys_path is not None:
|
||||
# Remap potential pathlib.Path entries
|
||||
sys_path = list(map(str, sys_path))
|
||||
self._sys_path = sys_path
|
||||
self._smart_sys_path = smart_sys_path
|
||||
self._load_unsafe_extensions = load_unsafe_extensions
|
||||
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 """
|
||||
|
||||
py2_comp(path, **kwargs)
|
||||
@@ -182,23 +177,27 @@ class Project(object):
|
||||
sys_path = list(self._sys_path)
|
||||
|
||||
if self._smart_sys_path:
|
||||
prefixed.append(self._path)
|
||||
prefixed.append(str(self._path))
|
||||
|
||||
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:
|
||||
# Collect directories in upward search by:
|
||||
# 1. Skipping directories with __init__.py
|
||||
# 2. Stopping immediately when above self._path
|
||||
traversed = []
|
||||
for parent_path in traverse_parents(inference_state.script_path):
|
||||
if parent_path == self._path or not parent_path.startswith(self._path):
|
||||
for parent_path in inference_state.script_path.parents:
|
||||
if parent_path == self._path \
|
||||
or self._path not in parent_path.parents:
|
||||
break
|
||||
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
|
||||
traversed.append(parent_path)
|
||||
traversed.append(str(parent_path))
|
||||
|
||||
# AFAIK some libraries have imports like `foo.foo.bar`, which
|
||||
# leads to the conclusion to by default prefer longer paths
|
||||
@@ -206,10 +205,10 @@ class Project(object):
|
||||
suffixed += reversed(traversed)
|
||||
|
||||
if self._django:
|
||||
prefixed.append(self._path)
|
||||
prefixed.append(str(self._path))
|
||||
|
||||
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):
|
||||
if self._environment is None:
|
||||
@@ -219,7 +218,7 @@ class Project(object):
|
||||
self._environment = get_cached_default_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,
|
||||
at some point Jedi will stop searching. However it's also very much
|
||||
@@ -240,7 +239,7 @@ class Project(object):
|
||||
functions and classes.
|
||||
:yields: :class:`.Name`
|
||||
"""
|
||||
return self._search(string, **kwargs)
|
||||
return self._search_func(string, all_scopes=all_scopes)
|
||||
|
||||
def complete_search(self, string, **kwargs):
|
||||
"""
|
||||
@@ -254,9 +253,6 @@ class Project(object):
|
||||
"""
|
||||
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
|
||||
def _search_func(self, string, complete=False, all_scopes=False):
|
||||
# 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
|
||||
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)
|
||||
wanted_type, wanted_names = split_search_string(string)
|
||||
name = wanted_names[0]
|
||||
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 = []
|
||||
|
||||
# 1. Search for modules in the current project
|
||||
@@ -295,14 +287,13 @@ class Project(object):
|
||||
continue
|
||||
else:
|
||||
file_ios.append(file_io)
|
||||
file_name = os.path.basename(file_io.path)
|
||||
if file_name in (name + '.py', name + '.pyi'):
|
||||
if Path(file_io.path).name in (name + '.py', name + '.pyi'):
|
||||
m = load_module_from_path(inference_state, file_io).as_context()
|
||||
else:
|
||||
continue
|
||||
|
||||
debug.dbg('Search of a specific module %s', m)
|
||||
for x in search_in_module(
|
||||
yield from search_in_module(
|
||||
inference_state,
|
||||
m,
|
||||
names=[m.name],
|
||||
@@ -311,15 +302,14 @@ class Project(object):
|
||||
complete=complete,
|
||||
convert=True,
|
||||
ignore_imports=True,
|
||||
):
|
||||
yield x # Python 2...
|
||||
)
|
||||
|
||||
# 2. Search for identifiers in the project.
|
||||
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 = [module_context.create_name(n) for n in names]
|
||||
names = _remove_imports(names)
|
||||
for x in search_in_module(
|
||||
yield from search_in_module(
|
||||
inference_state,
|
||||
module_context,
|
||||
names=names,
|
||||
@@ -327,18 +317,17 @@ class Project(object):
|
||||
wanted_names=wanted_names,
|
||||
complete=complete,
|
||||
ignore_imports=True,
|
||||
):
|
||||
yield x # Python 2...
|
||||
)
|
||||
|
||||
# 3. Search for modules on sys.path
|
||||
sys_path = [
|
||||
p for p in self._get_sys_path(inference_state)
|
||||
# Exclude folders that are handled by recursing of the Python
|
||||
# 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))
|
||||
for x in search_in_module(
|
||||
yield from search_in_module(
|
||||
inference_state,
|
||||
empty_module_context,
|
||||
names=names,
|
||||
@@ -346,8 +335,7 @@ class Project(object):
|
||||
wanted_names=wanted_names,
|
||||
complete=complete,
|
||||
convert=True,
|
||||
):
|
||||
yield x # Python 2...
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s: %s>' % (self.__class__.__name__, self._path)
|
||||
@@ -355,7 +343,7 @@ class Project(object):
|
||||
|
||||
def _is_potential_project(path):
|
||||
for name in _CONTAINS_POTENTIAL_PROJECT:
|
||||
if os.path.exists(os.path.join(path, name)):
|
||||
if path.joinpath(name).exists():
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -363,7 +351,7 @@ def _is_potential_project(path):
|
||||
def _is_django_path(directory):
|
||||
""" Detects the path of the very well known Django library (if used) """
|
||||
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()
|
||||
except (FileNotFoundError, IsADirectoryError, PermissionError):
|
||||
return False
|
||||
@@ -380,12 +368,14 @@ def get_default_project(path=None):
|
||||
``requirements.txt`` and ``MANIFEST.in``.
|
||||
"""
|
||||
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
|
||||
first_no_init_file = None
|
||||
for dir in traverse_parents(check, include_current=True):
|
||||
for dir in chain([check], check.parents):
|
||||
try:
|
||||
return Project.load(dir)
|
||||
except (FileNotFoundError, IsADirectoryError, PermissionError):
|
||||
@@ -394,11 +384,11 @@ def get_default_project(path=None):
|
||||
continue
|
||||
|
||||
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
|
||||
# Python package and the project sits at least one level above.
|
||||
continue
|
||||
else:
|
||||
elif not dir.is_file():
|
||||
first_no_init_file = dir
|
||||
|
||||
if _is_django_path(dir):
|
||||
@@ -416,7 +406,7 @@ def get_default_project(path=None):
|
||||
if first_no_init_file is not None:
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from os.path import dirname, basename, join, relpath
|
||||
import os
|
||||
import re
|
||||
import difflib
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
from parso import split_lines
|
||||
|
||||
@@ -43,15 +42,15 @@ class ChangedFile(object):
|
||||
if self._from_path is None:
|
||||
from_p = ''
|
||||
else:
|
||||
from_p = relpath(self._from_path, project_path)
|
||||
from_p = self._from_path.relative_to(project_path)
|
||||
if self._to_path is None:
|
||||
to_p = ''
|
||||
else:
|
||||
to_p = relpath(self._to_path, project_path)
|
||||
to_p = self._to_path.relative_to(project_path)
|
||||
diff = difflib.unified_diff(
|
||||
old_lines, new_lines,
|
||||
fromfile=from_p,
|
||||
tofile=to_p,
|
||||
fromfile=str(from_p),
|
||||
tofile=str(to_p),
|
||||
)
|
||||
# Apparently there's a space at the end of the diff - for whatever
|
||||
# reason.
|
||||
@@ -79,17 +78,15 @@ class Refactoring(object):
|
||||
self._renames = renames
|
||||
self._file_to_node_changes = file_to_node_changes
|
||||
|
||||
def get_changed_files(self):
|
||||
"""
|
||||
Returns a path to ``ChangedFile`` map.
|
||||
"""
|
||||
def get_changed_files(self) -> Dict[Path, ChangedFile]:
|
||||
def calculate_to_path(p):
|
||||
if p is None:
|
||||
return p
|
||||
p = str(p)
|
||||
for from_, to in renames:
|
||||
if p.startswith(from_):
|
||||
p = to + p[len(from_):]
|
||||
return p
|
||||
if p.startswith(str(from_)):
|
||||
p = str(to) + p[len(str(from_)):]
|
||||
return Path(p)
|
||||
|
||||
renames = self.get_renames()
|
||||
return {
|
||||
@@ -115,7 +112,7 @@ class Refactoring(object):
|
||||
project_path = self._inference_state.project.path
|
||||
for from_, to in self.get_renames():
|
||||
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())
|
||||
|
||||
@@ -127,17 +124,14 @@ class Refactoring(object):
|
||||
f.apply()
|
||||
|
||||
for old, new in self.get_renames():
|
||||
os.rename(old, new)
|
||||
old.rename(new)
|
||||
|
||||
|
||||
def _calculate_rename(path, new_name):
|
||||
name = basename(path)
|
||||
dir_ = dirname(path)
|
||||
if name in ('__init__.py', '__init__.pyi'):
|
||||
parent_dir = dirname(dir_)
|
||||
return dir_, join(parent_dir, new_name)
|
||||
ending = re.search(r'\.pyi?$', name).group(0)
|
||||
return path, join(dir_, new_name + ending)
|
||||
dir_ = path.parent
|
||||
if path.name in ('__init__.py', '__init__.pyi'):
|
||||
return dir_, dir_.parent.joinpath(new_name)
|
||||
return path, dir_.joinpath(new_name + path.suffix)
|
||||
|
||||
|
||||
def rename(inference_state, definitions, new_name):
|
||||
@@ -150,7 +144,8 @@ def rename(inference_state, definitions, new_name):
|
||||
for d in definitions:
|
||||
tree_name = d._name.tree_name
|
||||
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:
|
||||
# This private access is ok in a way. It's not public to
|
||||
# protect Jedi users from seeing it.
|
||||
|
||||
@@ -350,8 +350,7 @@ def _find_non_global_names(nodes):
|
||||
if node.type == 'trailer' and node.children[0] == '.':
|
||||
continue
|
||||
|
||||
for x in _find_non_global_names(children): # Python 2...
|
||||
yield x
|
||||
yield from _find_non_global_names(children)
|
||||
|
||||
|
||||
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::
|
||||
|
||||
$ 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
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> import os
|
||||
|
||||
@@ -9,7 +9,6 @@ names in a module, but pretty much an arbitrary string.
|
||||
"""
|
||||
import re
|
||||
|
||||
from jedi._compatibility import unicode
|
||||
from jedi.inference.names import AbstractArbitraryName
|
||||
from jedi.inference.helpers import infer_call_of_leaf
|
||||
from jedi.api.classes import Completion
|
||||
@@ -19,7 +18,7 @@ _sentinel = object()
|
||||
|
||||
|
||||
class StringName(AbstractArbitraryName):
|
||||
api_type = u'string'
|
||||
api_type = 'string'
|
||||
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):
|
||||
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)
|
||||
|
||||
r = repr(dict_key)
|
||||
|
||||
@@ -1,18 +1,6 @@
|
||||
import os
|
||||
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
|
||||
def monkeypatch(obj, attribute_name, new_value):
|
||||
"""
|
||||
|
||||
@@ -2,8 +2,6 @@ import os
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
|
||||
from jedi._compatibility import encoding, is_py3, u
|
||||
|
||||
_inited = False
|
||||
|
||||
|
||||
@@ -97,16 +95,14 @@ def increase_indent_cm(title=None, color='MAGENTA'):
|
||||
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. """
|
||||
# Python 2 compatibility, because it doesn't understand default args
|
||||
color = kwargs.pop('color', 'GREEN')
|
||||
assert color
|
||||
|
||||
if debug_function and enable_notice:
|
||||
i = ' ' * _debug_indent
|
||||
_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):
|
||||
@@ -116,7 +112,7 @@ def warning(message, *args, **kwargs):
|
||||
if debug_function and enable_warning:
|
||||
i = ' ' * _debug_indent
|
||||
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)
|
||||
|
||||
|
||||
@@ -135,9 +131,4 @@ def print_to_stdout(color, str_out):
|
||||
"""
|
||||
col = getattr(Fore, color)
|
||||
_lazy_colorama_init()
|
||||
if not is_py3:
|
||||
str_out = str_out.encode(encoding, 'replace')
|
||||
print(col + str_out + Fore.RESET)
|
||||
|
||||
|
||||
# debug_function = print_to_stdout
|
||||
|
||||
@@ -65,13 +65,13 @@ class FileIOFolderMixin(object):
|
||||
class ZipFileIO(file_io.KnownContentFileIO, FileIOFolderMixin):
|
||||
"""For .zip and .egg archives"""
|
||||
def __init__(self, path, code, zip_path):
|
||||
super(ZipFileIO, self).__init__(path, code)
|
||||
super().__init__(path, code)
|
||||
self._zip_path = zip_path
|
||||
|
||||
def get_last_modified(self):
|
||||
try:
|
||||
return os.path.getmtime(self._zip_path)
|
||||
except OSError: # Python 3 would probably only need FileNotFoundError
|
||||
except (FileNotFoundError, PermissionError, NotADirectoryError):
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -123,16 +123,14 @@ class InferenceState(object):
|
||||
@property
|
||||
@inference_state_function_cache()
|
||||
def builtins_module(self):
|
||||
module_name = u'builtins'
|
||||
if self.environment.version_info.major == 2:
|
||||
module_name = u'__builtin__'
|
||||
module_name = 'builtins'
|
||||
builtins_module, = self.import_module((module_name,), sys_path=())
|
||||
return builtins_module
|
||||
|
||||
@property
|
||||
@inference_state_function_cache()
|
||||
def typing_module(self):
|
||||
typing_module, = self.import_module((u'typing',))
|
||||
typing_module, = self.import_module(('typing',))
|
||||
return typing_module
|
||||
|
||||
def reset_recursion_limitations(self):
|
||||
@@ -178,14 +176,16 @@ class InferenceState(object):
|
||||
|
||||
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):
|
||||
if path is not None:
|
||||
path = str(path)
|
||||
if code is None:
|
||||
if file_io is None:
|
||||
file_io = FileIO(path)
|
||||
code = file_io.read()
|
||||
# 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:
|
||||
code = code[:settings._cropped_file_size]
|
||||
|
||||
@@ -3,7 +3,6 @@ Module for statical analysis.
|
||||
"""
|
||||
from parso.python import tree
|
||||
|
||||
from jedi._compatibility import force_unicode
|
||||
from jedi import debug
|
||||
from jedi.inference.helpers import is_string
|
||||
|
||||
@@ -50,13 +49,10 @@ class Error(object):
|
||||
first = self.__class__.__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,
|
||||
self.code, self.message)
|
||||
|
||||
def __str__(self):
|
||||
return self.__unicode__()
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.path == other.path and self.name == other.name
|
||||
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]
|
||||
names = list(lazy_value.infer())
|
||||
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
|
||||
key, lazy_value = unpacked_args[0]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import re
|
||||
from itertools import zip_longest
|
||||
|
||||
from parso.python import tree
|
||||
|
||||
from jedi._compatibility import zip_longest
|
||||
from jedi import debug
|
||||
from jedi.inference.utils import PushBackIterator
|
||||
from jedi.inference import analysis
|
||||
@@ -142,11 +142,8 @@ def unpack_arglist(arglist):
|
||||
if arglist is None:
|
||||
return
|
||||
|
||||
# Allow testlist here as well for Python2's class inheritance
|
||||
# definitions.
|
||||
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 ('*', '**'))):
|
||||
if arglist.type != 'arglist' and not (
|
||||
arglist.type == 'argument' and arglist.children[0] in ('*', '**')):
|
||||
yield 0, arglist
|
||||
return
|
||||
|
||||
@@ -189,8 +186,6 @@ class TreeArguments(AbstractArguments):
|
||||
iterators = [_iterate_star_args(self.context, a, el, funcdef)
|
||||
for a in arrays]
|
||||
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(
|
||||
[v for v in values if v is not None]
|
||||
)
|
||||
|
||||
@@ -8,10 +8,11 @@ just one.
|
||||
"""
|
||||
from functools import reduce
|
||||
from operator import add
|
||||
from itertools import zip_longest
|
||||
|
||||
from parso.python.tree import Name
|
||||
|
||||
from jedi import debug
|
||||
from jedi._compatibility import zip_longest, unicode
|
||||
from jedi.parser_utils import clean_scope_docstring
|
||||
from jedi.inference.helpers import SimpleGetItemNotFound
|
||||
from jedi.inference.utils import safe_property
|
||||
@@ -92,7 +93,7 @@ class HelperValueMixin(object):
|
||||
return values
|
||||
|
||||
def py__await__(self):
|
||||
await_value_set = self.py__getattribute__(u"__await__")
|
||||
await_value_set = self.py__getattribute__("__await__")
|
||||
if not await_value_set:
|
||||
debug.warning('Tried to run __await__ on value %s', self)
|
||||
return await_value_set.execute_with_values()
|
||||
@@ -357,7 +358,7 @@ class ValueWrapper(_ValueWrapperBase):
|
||||
|
||||
class TreeValue(Value):
|
||||
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
|
||||
|
||||
def __repr__(self):
|
||||
@@ -385,7 +386,7 @@ def _getitem(value, index_values, contextualized_node):
|
||||
unused_values = set()
|
||||
for index_value in index_values:
|
||||
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:
|
||||
result |= value.py__simple_getitem__(index)
|
||||
continue
|
||||
|
||||
@@ -78,7 +78,7 @@ class CachedMetaClass(type):
|
||||
"""
|
||||
@inference_state_as_method_param_cache()
|
||||
def __call__(self, *args, **kwargs):
|
||||
return super(CachedMetaClass, self).__call__(*args, **kwargs)
|
||||
return super().__call__(*args, **kwargs)
|
||||
|
||||
|
||||
def inference_state_method_generator_cache():
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from jedi._compatibility import unicode
|
||||
from jedi.inference.compiled.value import CompiledValue, CompiledName, \
|
||||
CompiledValueFilter, CompiledValueName, create_from_access_path
|
||||
from jedi.inference.base_value import LazyValueWrapper
|
||||
@@ -29,7 +28,7 @@ class ExactValue(LazyValueWrapper):
|
||||
if name in ('get_safe_value', 'execute_operation', 'access_handle',
|
||||
'negate', 'py__bool__', 'is_compiled'):
|
||||
return getattr(self._compiled_value, name)
|
||||
return super(ExactValue, self).__getattribute__(name)
|
||||
return super().__getattribute__(name)
|
||||
|
||||
def _get_wrapped_value(self):
|
||||
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
|
||||
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(
|
||||
inference_state,
|
||||
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):
|
||||
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):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from __future__ import print_function
|
||||
import inspect
|
||||
import types
|
||||
import sys
|
||||
@@ -6,12 +5,12 @@ import operator as op
|
||||
from collections import namedtuple
|
||||
import warnings
|
||||
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
|
||||
|
||||
ALLOWED_GETITEM_TYPES = (str, list, tuple, unicode, bytes, bytearray, dict)
|
||||
ALLOWED_GETITEM_TYPES = (str, list, tuple, bytes, bytearray, dict)
|
||||
|
||||
MethodDescriptorType = type(str.replace)
|
||||
# These are not considered classes and access is granted even though they have
|
||||
@@ -28,17 +27,12 @@ NOT_CLASS_TYPES = (
|
||||
types.MethodType,
|
||||
types.ModuleType,
|
||||
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.
|
||||
MethodDescriptorType = type(str.replace)
|
||||
WrapperDescriptorType = type(set.__iter__)
|
||||
@@ -144,35 +138,22 @@ class AccessPath(object):
|
||||
def __init__(self, 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):
|
||||
access = create_access(inference_state, obj)
|
||||
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):
|
||||
if inspect.isclass(obj):
|
||||
return u'class'
|
||||
return 'class'
|
||||
elif inspect.ismodule(obj):
|
||||
return u'module'
|
||||
return 'module'
|
||||
elif inspect.isbuiltin(obj) or inspect.ismethod(obj) \
|
||||
or inspect.ismethoddescriptor(obj) or inspect.isfunction(obj):
|
||||
return u'function'
|
||||
return 'function'
|
||||
# Everything else...
|
||||
return u'instance'
|
||||
return 'instance'
|
||||
|
||||
|
||||
class DirectObjectAccess(object):
|
||||
@@ -199,7 +180,7 @@ class DirectObjectAccess(object):
|
||||
return None
|
||||
|
||||
def py__doc__(self):
|
||||
return force_unicode(inspect.getdoc(self._obj)) or u''
|
||||
return inspect.getdoc(self._obj) or ''
|
||||
|
||||
def py__name__(self):
|
||||
if not _is_class_instance(self._obj) or \
|
||||
@@ -214,7 +195,7 @@ class DirectObjectAccess(object):
|
||||
return None
|
||||
|
||||
try:
|
||||
return force_unicode(cls.__name__)
|
||||
return cls.__name__
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
@@ -260,26 +241,23 @@ class DirectObjectAccess(object):
|
||||
# Avoid some weird hacks that would just fail, because they cannot be
|
||||
# used by pickle.
|
||||
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 paths
|
||||
|
||||
@_force_unicode_decorator
|
||||
@shorten_repr
|
||||
def get_repr(self):
|
||||
builtins = 'builtins', '__builtin__'
|
||||
|
||||
if inspect.ismodule(self._obj):
|
||||
return repr(self._obj)
|
||||
# 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)
|
||||
|
||||
type_ = type(self._obj)
|
||||
if type_ == type:
|
||||
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.
|
||||
return repr(self._obj)
|
||||
return object.__repr__(self._obj)
|
||||
@@ -310,10 +288,10 @@ class DirectObjectAccess(object):
|
||||
name = try_to_get_name(type(self._obj))
|
||||
if name is None:
|
||||
return ()
|
||||
return tuple(force_unicode(n) for n in name.split('.'))
|
||||
return tuple(name.split('.'))
|
||||
|
||||
def dir(self):
|
||||
return list(map(force_unicode, dir(self._obj)))
|
||||
return dir(self._obj)
|
||||
|
||||
def has_iter(self):
|
||||
try:
|
||||
@@ -396,7 +374,7 @@ class DirectObjectAccess(object):
|
||||
return [self._create_access(module), access]
|
||||
|
||||
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
|
||||
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, ...]]
|
||||
"""
|
||||
if sys.version_info < (3, 5):
|
||||
return None, ()
|
||||
|
||||
name = None
|
||||
args = ()
|
||||
if safe_getattr(self._obj, '__module__', default='') == 'typing':
|
||||
@@ -485,8 +460,6 @@ class DirectObjectAccess(object):
|
||||
return inspect.isclass(self._obj) and self._obj != type
|
||||
|
||||
def _annotation_to_str(self, annotation):
|
||||
if py_version < 30:
|
||||
return ''
|
||||
return inspect.formatannotation(annotation)
|
||||
|
||||
def get_signature_params(self):
|
||||
@@ -505,8 +478,6 @@ class DirectObjectAccess(object):
|
||||
|
||||
def _get_signature(self):
|
||||
obj = self._obj
|
||||
if py_version < 33:
|
||||
raise ValueError("inspect.signature was introduced in 3.3")
|
||||
try:
|
||||
return inspect.signature(obj)
|
||||
except (RuntimeError, TypeError):
|
||||
@@ -525,15 +496,9 @@ class DirectObjectAccess(object):
|
||||
return None
|
||||
|
||||
try:
|
||||
# Python 2 doesn't have typing.
|
||||
import typing
|
||||
except ImportError:
|
||||
o = typing.get_type_hints(self._obj).get('return')
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
o = typing.get_type_hints(self._obj).get('return')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return self._create_access_path(o)
|
||||
|
||||
@@ -546,7 +511,7 @@ class DirectObjectAccess(object):
|
||||
objects of an objects
|
||||
"""
|
||||
tuples = dict(
|
||||
(force_unicode(name), self.is_allowed_getattr(name))
|
||||
(name, self.is_allowed_getattr(name))
|
||||
for name in self.dir()
|
||||
)
|
||||
return self.needs_type_completions(), tuples
|
||||
|
||||
@@ -7,7 +7,6 @@ information returned to enable Jedi to make decisions.
|
||||
import types
|
||||
|
||||
from jedi import debug
|
||||
from jedi._compatibility import py_version
|
||||
|
||||
_sentinel = object()
|
||||
|
||||
@@ -39,7 +38,7 @@ def _is_type(obj):
|
||||
return True
|
||||
|
||||
|
||||
def _shadowed_dict_newstyle(klass):
|
||||
def _shadowed_dict(klass):
|
||||
dict_attr = type.__dict__["__dict__"]
|
||||
for entry in _static_getmro(klass):
|
||||
try:
|
||||
@@ -54,7 +53,7 @@ def _shadowed_dict_newstyle(klass):
|
||||
return _sentinel
|
||||
|
||||
|
||||
def _static_getmro_newstyle(klass):
|
||||
def _static_getmro(klass):
|
||||
mro = type.__dict__['__mro__'].__get__(klass)
|
||||
if not isinstance(mro, (tuple, list)):
|
||||
# There are unfortunately no tests for this, I was not able to
|
||||
@@ -65,70 +64,8 @@ def _static_getmro_newstyle(klass):
|
||||
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):
|
||||
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):
|
||||
@@ -151,7 +88,7 @@ def getattr_static(obj, attr, default=_sentinel):
|
||||
"""
|
||||
instance_result = _sentinel
|
||||
if not _is_type(obj):
|
||||
klass = _get_type(obj)
|
||||
klass = type(obj)
|
||||
dict_attr = _shadowed_dict(klass)
|
||||
if (dict_attr is _sentinel or type(dict_attr) is types.MemberDescriptorType):
|
||||
instance_result = _check_instance(obj, attr)
|
||||
|
||||
@@ -4,11 +4,9 @@ Used only for REPL Completion.
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
|
||||
from jedi.parser_utils import get_cached_code_lines
|
||||
|
||||
from jedi._compatibility import unwrap
|
||||
from jedi import settings
|
||||
from jedi.cache import memoize_method
|
||||
from jedi.inference import compiled
|
||||
@@ -44,7 +42,7 @@ class MixedObject(ValueWrapper):
|
||||
to modify the runtime.
|
||||
"""
|
||||
def __init__(self, compiled_value, tree_value):
|
||||
super(MixedObject, self).__init__(tree_value)
|
||||
super().__init__(tree_value)
|
||||
self.compiled_value = compiled_value
|
||||
self.access_handle = compiled_value.access_handle
|
||||
|
||||
@@ -115,7 +113,7 @@ class MixedName(NameWrapper):
|
||||
The ``CompiledName._compiled_value`` is our MixedObject.
|
||||
"""
|
||||
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
|
||||
|
||||
@property
|
||||
@@ -141,12 +139,12 @@ class MixedName(NameWrapper):
|
||||
|
||||
class MixedObjectFilter(compiled.CompiledValueFilter):
|
||||
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
|
||||
|
||||
def _create_name(self, name):
|
||||
return MixedName(
|
||||
super(MixedObjectFilter, self)._create_name(name),
|
||||
super()._create_name(name),
|
||||
self._tree_value,
|
||||
)
|
||||
|
||||
@@ -163,12 +161,11 @@ def _load_module(inference_state, path):
|
||||
|
||||
def _get_object_to_check(python_object):
|
||||
"""Check if inspect.getfile has a chance to find the source."""
|
||||
if sys.version_info[0] > 2:
|
||||
try:
|
||||
python_object = unwrap(python_object)
|
||||
except ValueError:
|
||||
# Can return a ValueError when it wraps around
|
||||
pass
|
||||
try:
|
||||
python_object = inspect.unwrap(python_object)
|
||||
except ValueError:
|
||||
# Can return a ValueError when it wraps around
|
||||
pass
|
||||
|
||||
if (inspect.ismodule(python_object)
|
||||
or inspect.isclass(python_object)
|
||||
|
||||
@@ -9,19 +9,14 @@ goals:
|
||||
|
||||
import os
|
||||
import sys
|
||||
import queue
|
||||
import subprocess
|
||||
import socket
|
||||
import errno
|
||||
import traceback
|
||||
import weakref
|
||||
from functools import partial
|
||||
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, \
|
||||
pickle_dump, pickle_load, GeneralizedPopen, weakref
|
||||
from jedi._compatibility import pickle_dump, pickle_load
|
||||
from jedi import debug
|
||||
from jedi.cache import memoize_method
|
||||
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')
|
||||
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''):
|
||||
queue.put(line)
|
||||
queue_.put(line)
|
||||
|
||||
|
||||
def _add_stderr_to_debug(stderr_queue):
|
||||
@@ -46,7 +57,7 @@ def _add_stderr_to_debug(stderr_queue):
|
||||
line = stderr_queue.get_nowait()
|
||||
line = line.decode('utf-8', 'replace')
|
||||
debug.warning('stderr output: %s' % line.rstrip('\n'))
|
||||
except Empty:
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
|
||||
@@ -105,7 +116,7 @@ class InferenceStateSameProcess(_InferenceStateProcess):
|
||||
|
||||
class InferenceStateSubprocess(_InferenceStateProcess):
|
||||
def __init__(self, inference_state, compiled_subprocess):
|
||||
super(InferenceStateSubprocess, self).__init__(inference_state)
|
||||
super().__init__(inference_state)
|
||||
self._used = False
|
||||
self._compiled_subprocess = compiled_subprocess
|
||||
|
||||
@@ -153,8 +164,6 @@ class InferenceStateSubprocess(_InferenceStateProcess):
|
||||
|
||||
class CompiledSubprocess(object):
|
||||
is_crashed = False
|
||||
# Start with 2, gets set after _get_info.
|
||||
_pickle_protocol = 2
|
||||
|
||||
def __init__(self, executable, env_vars=None):
|
||||
self._executable = executable
|
||||
@@ -164,10 +173,9 @@ class CompiledSubprocess(object):
|
||||
|
||||
def __repr__(self):
|
||||
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._executable,
|
||||
self._pickle_protocol,
|
||||
self.is_crashed,
|
||||
pid,
|
||||
)
|
||||
@@ -182,17 +190,14 @@ class CompiledSubprocess(object):
|
||||
os.path.dirname(os.path.dirname(parso_path)),
|
||||
'.'.join(str(x) for x in sys.version_info[:3]),
|
||||
)
|
||||
process = GeneralizedPopen(
|
||||
process = _GeneralizedPopen(
|
||||
args,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=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
|
||||
)
|
||||
self._stderr_queue = Queue()
|
||||
self._stderr_queue = queue.Queue()
|
||||
self._stderr_thread = t = Thread(
|
||||
target=_enqueue_output,
|
||||
args=(process.stderr, self._stderr_queue)
|
||||
@@ -231,20 +236,10 @@ class CompiledSubprocess(object):
|
||||
if self.is_crashed:
|
||||
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
|
||||
try:
|
||||
pickle_dump(data, self._get_process().stdin, self._pickle_protocol)
|
||||
except (socket.error, IOError) as e:
|
||||
# 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
|
||||
pickle_dump(data, self._get_process().stdin, PICKLE_PROTOCOL)
|
||||
except BrokenPipeError:
|
||||
self._kill()
|
||||
raise InternalError("The subprocess %s was killed. Maybe out of memory?"
|
||||
% self._executable)
|
||||
@@ -286,12 +281,11 @@ class CompiledSubprocess(object):
|
||||
|
||||
|
||||
class Listener(object):
|
||||
def __init__(self, pickle_protocol):
|
||||
def __init__(self):
|
||||
self._inference_states = {}
|
||||
# TODO refactor so we don't need to process anymore just handle
|
||||
# controlling.
|
||||
self._process = _InferenceStateProcess(Listener)
|
||||
self._pickle_protocol = pickle_protocol
|
||||
|
||||
def _get_inference_state(self, function, inference_state_id):
|
||||
from jedi.inference import InferenceState
|
||||
@@ -334,15 +328,8 @@ class Listener(object):
|
||||
# because stdout is used for IPC.
|
||||
sys.stdout = open(os.devnull, 'w')
|
||||
stdin = sys.stdin
|
||||
if sys.version_info[0] > 2:
|
||||
stdout = stdout.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)
|
||||
stdout = stdout.buffer
|
||||
stdin = stdin.buffer
|
||||
|
||||
while True:
|
||||
try:
|
||||
@@ -356,7 +343,7 @@ class Listener(object):
|
||||
except Exception as e:
|
||||
result = True, traceback.format_exc(), e
|
||||
|
||||
pickle_dump(result, stdout, self._pickle_protocol)
|
||||
pickle_dump(result, stdout, PICKLE_PROTOCOL)
|
||||
|
||||
|
||||
class AccessHandle(object):
|
||||
@@ -385,9 +372,8 @@ class AccessHandle(object):
|
||||
if name in ('id', 'access') or name.startswith('_'):
|
||||
raise AttributeError("Something went wrong with unpickling")
|
||||
|
||||
# if not is_py3: print >> sys.stderr, name
|
||||
# print('getattr', name, file=sys.stderr)
|
||||
return partial(self._workaround, force_unicode(name))
|
||||
return partial(self._workaround, name)
|
||||
|
||||
def _workaround(self, name, *args, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import os
|
||||
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():
|
||||
@@ -11,45 +16,24 @@ def _get_paths():
|
||||
return {'jedi': _jedi_path, 'parso': _parso_path}
|
||||
|
||||
|
||||
# Remove the first entry, because it's simply a directory entry that equals
|
||||
# this directory.
|
||||
del sys.path[0]
|
||||
class _ExactImporter(object):
|
||||
def __init__(self, path_dct):
|
||||
self._path_dct = path_dct
|
||||
|
||||
if sys.version_info > (3, 4):
|
||||
from importlib.machinery import PathFinder
|
||||
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
|
||||
|
||||
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.
|
||||
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.
|
||||
subprocess.Listener(pickle_protocol=pickle_protocol).listen()
|
||||
subprocess.Listener().listen()
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
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, \
|
||||
all_suffixes, scandir
|
||||
from jedi._compatibility import cast_path
|
||||
from jedi.inference.compiled import access
|
||||
from jedi import debug
|
||||
from jedi import parser_utils
|
||||
from jedi.file_io import KnownContentFileIO, ZipFileIO
|
||||
|
||||
|
||||
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:
|
||||
sys.path, temp = sys_path, sys.path
|
||||
try:
|
||||
return find_module(full_name=full_name, **kwargs)
|
||||
return _find_module(full_name=full_name, **kwargs)
|
||||
except ImportError:
|
||||
return None, None
|
||||
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):
|
||||
return list(map(force_unicode, sys.builtin_module_names))
|
||||
return sys.builtin_module_names
|
||||
|
||||
|
||||
def _test_raise_error(inference_state, exception_type):
|
||||
@@ -90,7 +92,7 @@ def _iter_module_names(inference_state, paths):
|
||||
# Python modules/packages
|
||||
for path in paths:
|
||||
try:
|
||||
dirs = scandir(path)
|
||||
dirs = os.scandir(path)
|
||||
except OSError:
|
||||
# The file might not exist or reading it might lead to an error.
|
||||
debug.warning("Not possible to list directory: %s", path)
|
||||
@@ -99,10 +101,9 @@ def _iter_module_names(inference_state, paths):
|
||||
name = dir_entry.name
|
||||
# First Namespaces then modules/stubs
|
||||
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.
|
||||
# TODO use str.isidentifier, once Python 2 is removed
|
||||
if name != '__pycache__' and not re.search(r'\W|^\d', name):
|
||||
if name != '__pycache__' and name.isidentifier():
|
||||
yield name
|
||||
else:
|
||||
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 != '__init__':
|
||||
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
|
||||
from functools import partial
|
||||
from inspect import Parameter
|
||||
from pathlib import Path
|
||||
|
||||
from jedi import debug
|
||||
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.inference.filters import AbstractFilter
|
||||
from jedi.inference.names import AbstractNameDefinition, ValueNameMixin, \
|
||||
@@ -29,7 +31,7 @@ class CheckAttribute(object):
|
||||
def __call__(self, func):
|
||||
self.func = func
|
||||
if self.check_name is None:
|
||||
self.check_name = force_unicode(func.__name__[2:])
|
||||
self.check_name = func.__name__[2:]
|
||||
return self
|
||||
|
||||
def __get__(self, instance, owner):
|
||||
@@ -43,7 +45,7 @@ class CheckAttribute(object):
|
||||
|
||||
class CompiledValue(Value):
|
||||
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
|
||||
|
||||
def py__call__(self, arguments):
|
||||
@@ -56,9 +58,9 @@ class CompiledValue(Value):
|
||||
).execute_annotation()
|
||||
|
||||
try:
|
||||
self.access_handle.getattr_paths(u'__call__')
|
||||
self.access_handle.getattr_paths('__call__')
|
||||
except AttributeError:
|
||||
return super(CompiledValue, self).py__call__(arguments)
|
||||
return super().py__call__(arguments)
|
||||
else:
|
||||
if self.access_handle.is_class():
|
||||
from jedi.inference.value import CompiledInstance
|
||||
@@ -163,7 +165,7 @@ class CompiledValue(Value):
|
||||
try:
|
||||
access = self.access_handle.py__simple_getitem__(index)
|
||||
except AttributeError:
|
||||
return super(CompiledValue, self).py__simple_getitem__(index)
|
||||
return super().py__simple_getitem__(index)
|
||||
if access is None:
|
||||
return NO_VALUES
|
||||
|
||||
@@ -174,19 +176,15 @@ class CompiledValue(Value):
|
||||
if all_access_paths is None:
|
||||
# This means basically that no __getitem__ has been defined on this
|
||||
# object.
|
||||
return super(CompiledValue, self).py__getitem__(index_value_set, contextualized_node)
|
||||
return super().py__getitem__(index_value_set, contextualized_node)
|
||||
return ValueSet(
|
||||
create_from_access_path(self.inference_state, access)
|
||||
for access in all_access_paths
|
||||
)
|
||||
|
||||
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():
|
||||
for x in super(CompiledValue, self).py__iter__(contextualized_node):
|
||||
for x in super().py__iter__(contextualized_node):
|
||||
yield x
|
||||
|
||||
access_path_list = self.access_handle.py__iter__list()
|
||||
@@ -264,7 +262,7 @@ class CompiledValue(Value):
|
||||
v.with_generics(arguments)
|
||||
for v in self.inference_state.typing_module.py__getattribute__(name)
|
||||
]).execute_annotation()
|
||||
return super(CompiledValue, self).execute_annotation()
|
||||
return super().execute_annotation()
|
||||
|
||||
def negate(self):
|
||||
return create_from_access_path(self.inference_state, self.access_handle.negate())
|
||||
@@ -315,7 +313,10 @@ class CompiledModule(CompiledValue):
|
||||
return tuple(name.split('.'))
|
||||
|
||||
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):
|
||||
@@ -456,9 +457,6 @@ class CompiledValueFilter(AbstractFilter):
|
||||
"""
|
||||
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:
|
||||
pass
|
||||
|
||||
@@ -502,7 +500,7 @@ class CompiledValueFilter(AbstractFilter):
|
||||
|
||||
# ``dir`` doesn't include the type names.
|
||||
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()
|
||||
return names
|
||||
|
||||
@@ -518,11 +516,11 @@ class CompiledValueFilter(AbstractFilter):
|
||||
|
||||
|
||||
docstr_defaults = {
|
||||
'floating point number': u'float',
|
||||
'character': u'str',
|
||||
'integer': u'int',
|
||||
'dictionary': u'dict',
|
||||
'string': u'str',
|
||||
'floating point number': 'float',
|
||||
'character': 'str',
|
||||
'integer': 'int',
|
||||
'dictionary': 'dict',
|
||||
'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 'tuple of integers'
|
||||
"""
|
||||
doc = force_unicode(doc)
|
||||
# parse round parentheses: def func(a, (b,c))
|
||||
try:
|
||||
count = 0
|
||||
@@ -553,7 +550,7 @@ def _parse_function_doc(doc):
|
||||
# UnboundLocalError for undefined end in last line
|
||||
debug.dbg('no brackets found - no param')
|
||||
end = 0
|
||||
param_str = u''
|
||||
param_str = ''
|
||||
else:
|
||||
# remove square brackets, that show an optional param ( = None)
|
||||
def change_options(m):
|
||||
@@ -571,9 +568,9 @@ def _parse_function_doc(doc):
|
||||
param_str = param_str.replace('-', '_') # see: isinstance.__doc__
|
||||
|
||||
# parse return value
|
||||
r = re.search(u'-[>-]* ', doc[end:end + 7])
|
||||
r = re.search('-[>-]* ', doc[end:end + 7])
|
||||
if r is None:
|
||||
ret = u''
|
||||
ret = ''
|
||||
else:
|
||||
index = end + r.end()
|
||||
# get result type, which can contain newlines
|
||||
|
||||
@@ -164,7 +164,7 @@ class ValueContext(AbstractContext):
|
||||
Should be defined, otherwise the API returns empty types.
|
||||
"""
|
||||
def __init__(self, value):
|
||||
super(ValueContext, self).__init__(value.inference_state)
|
||||
super().__init__(value.inference_state)
|
||||
self._value = value
|
||||
|
||||
@property
|
||||
@@ -323,8 +323,7 @@ class ModuleContext(TreeContextMixin, ValueContext):
|
||||
),
|
||||
self.get_global_filter(),
|
||||
)
|
||||
for f in filters: # Python 2...
|
||||
yield f
|
||||
yield from filters
|
||||
|
||||
def get_global_filter(self):
|
||||
return GlobalNameFilter(self, self.tree_node)
|
||||
@@ -375,7 +374,7 @@ class ClassContext(TreeContextMixin, ValueContext):
|
||||
|
||||
class CompForContext(TreeContextMixin, AbstractContext):
|
||||
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.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
|
||||
themselves, but here we gather possible filters downwards.
|
||||
|
||||
>>> from jedi._compatibility import u, no_unicode_pprint
|
||||
>>> from jedi import Script
|
||||
>>> script = Script(u('''
|
||||
>>> script = Script('''
|
||||
... x = ['a', 'b', 'c']
|
||||
... def func():
|
||||
... y = None
|
||||
... '''))
|
||||
... ''')
|
||||
>>> module_node = script._module_node
|
||||
>>> scope = next(module_node.iter_funcdefs())
|
||||
>>> scope
|
||||
@@ -455,7 +453,7 @@ def get_global_filters(context, until_position, origin_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: ...>)
|
||||
>>> sorted(str(n) for n in filters[0].values()) # doctest: +NORMALIZE_WHITESPACE
|
||||
['<TreeNameDefinition: string_name=func start_pos=(3, 4)>',
|
||||
|
||||
@@ -21,7 +21,6 @@ from textwrap import dedent
|
||||
|
||||
from parso import parse, ParserSyntaxError
|
||||
|
||||
from jedi._compatibility import u
|
||||
from jedi import debug
|
||||
from jedi.common import indent_block
|
||||
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):
|
||||
code = dedent(u("""
|
||||
code = dedent("""
|
||||
def pseudo_docstring_stuff():
|
||||
'''
|
||||
Create a pseudo function for docstring statements.
|
||||
@@ -192,7 +191,7 @@ def _infer_for_statement_string(module_context, string):
|
||||
is still a function.
|
||||
'''
|
||||
{}
|
||||
"""))
|
||||
""")
|
||||
if string is None:
|
||||
return []
|
||||
|
||||
@@ -201,11 +200,8 @@ def _infer_for_statement_string(module_context, string):
|
||||
# (e.g., 'threading' in 'threading.Thread').
|
||||
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')
|
||||
grammar = module_context.inference_state.latest_grammar
|
||||
grammar = module_context.inference_state.grammar
|
||||
try:
|
||||
module = grammar.parse(code.format(indent_block(string)), error_recovery=False)
|
||||
except ParserSyntaxError:
|
||||
|
||||
@@ -7,7 +7,6 @@ import weakref
|
||||
|
||||
from parso.tree import search_ancestor
|
||||
|
||||
from jedi._compatibility import use_metaclass
|
||||
from jedi.inference import flow_analysis
|
||||
from jedi.inference.base_value import ValueSet, ValueWrapper, \
|
||||
LazyValueWrapper
|
||||
@@ -109,13 +108,13 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
|
||||
"""
|
||||
if node_context is None:
|
||||
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._origin_scope = origin_scope
|
||||
self._until_position = until_position
|
||||
|
||||
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)]
|
||||
return list(self._check_flows(names))
|
||||
|
||||
@@ -143,7 +142,7 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
|
||||
|
||||
class _FunctionExecutionFilter(ParserTreeFilter):
|
||||
def __init__(self, parent_context, function_value, until_position, origin_scope):
|
||||
super(_FunctionExecutionFilter, self).__init__(
|
||||
super().__init__(
|
||||
parent_context,
|
||||
until_position=until_position,
|
||||
origin_scope=origin_scope,
|
||||
@@ -167,9 +166,9 @@ class _FunctionExecutionFilter(ParserTreeFilter):
|
||||
|
||||
|
||||
class FunctionExecutionFilter(_FunctionExecutionFilter):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._arguments = kwargs.pop('arguments') # Python 2
|
||||
super(FunctionExecutionFilter, self).__init__(*args, **kwargs)
|
||||
def __init__(self, *args, arguments, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._arguments = arguments
|
||||
|
||||
def _convert_param(self, param, name):
|
||||
return ParamName(self._function_value, name, self._arguments)
|
||||
@@ -246,10 +245,10 @@ class MergedFilter(object):
|
||||
|
||||
class _BuiltinMappedMethod(ValueWrapper):
|
||||
"""``Generator.__next__`` ``dict.values`` methods and so on."""
|
||||
api_type = u'function'
|
||||
api_type = 'function'
|
||||
|
||||
def __init__(self, value, method, builtin_func):
|
||||
super(_BuiltinMappedMethod, self).__init__(builtin_func)
|
||||
super().__init__(builtin_func)
|
||||
self._value = value
|
||||
self._method = method
|
||||
|
||||
@@ -264,14 +263,9 @@ class SpecialMethodFilter(DictFilter):
|
||||
classes like Generator (for __next__, etc).
|
||||
"""
|
||||
class SpecialMethodName(AbstractNameDefinition):
|
||||
api_type = u'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
|
||||
api_type = 'function'
|
||||
|
||||
def __init__(self, parent_context, string_name, callable_, builtin_value):
|
||||
self.parent_context = parent_context
|
||||
self.string_name = string_name
|
||||
self._callable = callable_
|
||||
@@ -293,7 +287,7 @@ class SpecialMethodFilter(DictFilter):
|
||||
])
|
||||
|
||||
def __init__(self, value, dct, builtin_value):
|
||||
super(SpecialMethodFilter, self).__init__(dct)
|
||||
super().__init__(dct)
|
||||
self.value = value
|
||||
self._builtin_value = builtin_value
|
||||
"""
|
||||
@@ -309,7 +303,7 @@ class SpecialMethodFilter(DictFilter):
|
||||
|
||||
class _OverwriteMeta(type):
|
||||
def __init__(cls, name, bases, dct):
|
||||
super(_OverwriteMeta, cls).__init__(name, bases, dct)
|
||||
super().__init__(name, bases, dct)
|
||||
|
||||
base_dct = {}
|
||||
for base_cls in reversed(cls.__bases__):
|
||||
@@ -334,20 +328,20 @@ class _AttributeOverwriteMixin(object):
|
||||
yield filter
|
||||
|
||||
|
||||
class LazyAttributeOverwrite(use_metaclass(_OverwriteMeta, _AttributeOverwriteMixin,
|
||||
LazyValueWrapper)):
|
||||
class LazyAttributeOverwrite(_AttributeOverwriteMixin, LazyValueWrapper,
|
||||
metaclass=_OverwriteMeta):
|
||||
def __init__(self, inference_state):
|
||||
self.inference_state = inference_state
|
||||
|
||||
|
||||
class AttributeOverwrite(use_metaclass(_OverwriteMeta, _AttributeOverwriteMixin,
|
||||
ValueWrapper)):
|
||||
class AttributeOverwrite(_AttributeOverwriteMixin, ValueWrapper,
|
||||
metaclass=_OverwriteMeta):
|
||||
pass
|
||||
|
||||
|
||||
def publish_method(method_name, python_version_match=None):
|
||||
def publish_method(method_name):
|
||||
def decorator(func):
|
||||
dct = func.__dict__.setdefault('registered_overwritten_methods', {})
|
||||
dct[method_name] = func, python_version_match
|
||||
dct[method_name] = func
|
||||
return func
|
||||
return decorator
|
||||
|
||||
@@ -6,10 +6,10 @@ as annotations in future python versions.
|
||||
"""
|
||||
|
||||
import re
|
||||
from inspect import Parameter
|
||||
|
||||
from parso import ParserSyntaxError, parse
|
||||
|
||||
from jedi._compatibility import force_unicode, Parameter
|
||||
from jedi.inference.cache import inference_state_method_cache
|
||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||
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)
|
||||
if index is not None:
|
||||
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
|
||||
).py__simple_getitem__(index)
|
||||
return value_set
|
||||
@@ -62,7 +62,7 @@ def _infer_annotation_string(context, string, index=None):
|
||||
def _get_forward_reference_node(context, string):
|
||||
try:
|
||||
new_node = context.inference_state.grammar.parse(
|
||||
force_unicode(string),
|
||||
string,
|
||||
start_symbol='eval_input',
|
||||
error_recovery=False
|
||||
)
|
||||
@@ -138,8 +138,7 @@ def _infer_param(function_value, param):
|
||||
"""
|
||||
annotation = param.annotation
|
||||
if annotation is None:
|
||||
# If no Python 3-style annotation, look for a Python 2-style comment
|
||||
# annotation.
|
||||
# If no Python 3-style annotation, look for a comment annotation.
|
||||
# Identify parameters to function in the same sequence as they would
|
||||
# appear in a type comment.
|
||||
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)
|
||||
annotation = all_annotations.get("return", 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
|
||||
comment = parser_utils.get_following_comment_same_line(node)
|
||||
if comment is None:
|
||||
|
||||
@@ -70,7 +70,7 @@ class _TypeVarFilter(object):
|
||||
|
||||
class _AnnotatedClassContext(ClassContext):
|
||||
def get_filters(self, *args, **kwargs):
|
||||
filters = super(_AnnotatedClassContext, self).get_filters(
|
||||
filters = super().get_filters(
|
||||
*args, **kwargs
|
||||
)
|
||||
for f in filters:
|
||||
@@ -164,7 +164,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
||||
my_foo_int_cls = Foo[int]
|
||||
"""
|
||||
def __init__(self, class_value, generics_manager):
|
||||
super(GenericClass, self).__init__(generics_manager)
|
||||
super().__init__(generics_manager)
|
||||
self._class_value = class_value
|
||||
|
||||
def _get_wrapped_value(self):
|
||||
@@ -186,7 +186,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
||||
return _TypeVarFilter(self.get_generics(), self.list_type_vars())
|
||||
|
||||
def py__call__(self, arguments):
|
||||
instance, = super(GenericClass, self).py__call__(arguments)
|
||||
instance, = super().py__call__(arguments)
|
||||
return ValueSet([_GenericInstanceWrapper(instance)])
|
||||
|
||||
def _as_context(self):
|
||||
@@ -201,7 +201,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
||||
return GenericClass(self._class_value, generics_manager)
|
||||
|
||||
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 self._class_value.is_sub_class_of(class_value)
|
||||
|
||||
@@ -230,7 +230,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
||||
else:
|
||||
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
|
||||
# expecting a Callable (those are handled separately within
|
||||
# TypingClassValueWithIndex).
|
||||
@@ -309,7 +309,7 @@ class _GenericInstanceWrapper(ValueWrapper):
|
||||
except IndexError:
|
||||
pass
|
||||
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()
|
||||
|
||||
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`
|
||||
name, without affecting anything else negatively.
|
||||
"""
|
||||
api_type = u'class'
|
||||
api_type = 'class'
|
||||
|
||||
def __init__(self, parent_context, tree_name):
|
||||
super(_PseudoTreeNameClass, self).__init__(
|
||||
super().__init__(
|
||||
parent_context.inference_state,
|
||||
parent_context
|
||||
)
|
||||
@@ -356,7 +356,7 @@ class _PseudoTreeNameClass(Value):
|
||||
def py__class__(self):
|
||||
# This might not be 100% correct, but it is good enough. The details of
|
||||
# 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
|
||||
def name(self):
|
||||
@@ -388,7 +388,7 @@ class BaseTypingValue(LazyValueWrapper):
|
||||
|
||||
class BaseTypingClassWithGenerics(DefineGenericBaseClass):
|
||||
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.parent_context = parent_context
|
||||
self._tree_name = tree_name
|
||||
@@ -423,7 +423,7 @@ class BaseTypingInstance(LazyValueWrapper):
|
||||
return ValueName(self, self._tree_name)
|
||||
|
||||
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_
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -10,7 +10,7 @@ class StubModuleValue(ModuleValue):
|
||||
_module_name_class = StubModuleName
|
||||
|
||||
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
|
||||
|
||||
def is_stub(self):
|
||||
@@ -30,7 +30,7 @@ class StubModuleValue(ModuleValue):
|
||||
pass
|
||||
else:
|
||||
names.update(method())
|
||||
names.update(super(StubModuleValue, self).sub_modules_dict())
|
||||
names.update(super().sub_modules_dict())
|
||||
return names
|
||||
|
||||
def _get_stub_filters(self, origin_scope):
|
||||
@@ -40,7 +40,7 @@ class StubModuleValue(ModuleValue):
|
||||
)] + list(self.iter_star_filters())
|
||||
|
||||
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
|
||||
stub_filters = self._get_stub_filters(origin_scope=origin_scope)
|
||||
for f in stub_filters:
|
||||
@@ -57,12 +57,12 @@ class StubModuleContext(ModuleContext):
|
||||
def get_filters(self, until_position=None, origin_scope=None):
|
||||
# Make sure to ignore the position, because positions are not relevant
|
||||
# for stubs.
|
||||
return super(StubModuleContext, self).get_filters(origin_scope=origin_scope)
|
||||
return super().get_filters(origin_scope=origin_scope)
|
||||
|
||||
|
||||
class TypingModuleWrapper(StubModuleValue):
|
||||
def get_filters(self, *args, **kwargs):
|
||||
filters = super(TypingModuleWrapper, self).get_filters(*args, **kwargs)
|
||||
filters = super().get_filters(*args, **kwargs)
|
||||
f = next(filters, None)
|
||||
assert f is not None
|
||||
yield TypingModuleFilterWrapper(f)
|
||||
@@ -75,7 +75,7 @@ class TypingModuleWrapper(StubModuleValue):
|
||||
|
||||
class TypingModuleContext(ModuleContext):
|
||||
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))
|
||||
for f in filters:
|
||||
yield f
|
||||
@@ -85,7 +85,7 @@ class StubFilter(ParserTreeFilter):
|
||||
name_class = StubName
|
||||
|
||||
def _is_name_reachable(self, name):
|
||||
if not super(StubFilter, self)._is_name_reachable(name):
|
||||
if not super()._is_name_reachable(name):
|
||||
return False
|
||||
|
||||
# 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.inference.base_value import ValueSet, NO_VALUES, ValueWrapper
|
||||
from jedi.inference.gradual.base import BaseTypingValue
|
||||
@@ -40,17 +39,14 @@ class TypeVarClass(BaseTypingValue):
|
||||
return None
|
||||
else:
|
||||
safe_value = method(default=None)
|
||||
if self.inference_state.environment.version_info.major == 2:
|
||||
if isinstance(safe_value, bytes):
|
||||
return force_unicode(safe_value)
|
||||
if isinstance(safe_value, (str, unicode)):
|
||||
if isinstance(safe_value, str):
|
||||
return safe_value
|
||||
return None
|
||||
|
||||
|
||||
class TypeVar(BaseTypingValue):
|
||||
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._constraints_lazy_values = []
|
||||
@@ -124,7 +120,7 @@ class TypeVar(BaseTypingValue):
|
||||
|
||||
class TypeWrapper(ValueWrapper):
|
||||
def __init__(self, wrapped_value, original_value):
|
||||
super(TypeWrapper, self).__init__(wrapped_value)
|
||||
super().__init__(wrapped_value)
|
||||
self._original_value = original_value
|
||||
|
||||
def execute_annotation(self):
|
||||
|
||||
@@ -2,19 +2,20 @@ import os
|
||||
import re
|
||||
from functools import wraps
|
||||
from collections import namedtuple
|
||||
from pathlib import Path
|
||||
|
||||
from jedi import settings
|
||||
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.inference.base_value import ValueSet, NO_VALUES
|
||||
from jedi.inference.gradual.stub_value import TypingModuleWrapper, StubModuleValue
|
||||
from jedi.inference.value import ModuleValue
|
||||
|
||||
_jedi_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
TYPESHED_PATH = os.path.join(_jedi_path, 'third_party', 'typeshed')
|
||||
DJANGO_INIT_PATH = os.path.join(_jedi_path, 'third_party', 'django-stubs',
|
||||
'django-stubs', '__init__.pyi')
|
||||
_jedi_path = Path(__file__).parent.parent.parent
|
||||
TYPESHED_PATH = _jedi_path.joinpath('third_party', 'typeshed')
|
||||
DJANGO_INIT_PATH = _jedi_path.joinpath('third_party', 'django-stubs',
|
||||
'django-stubs', '__init__.pyi')
|
||||
|
||||
_IMPORT_MAP = dict(
|
||||
_collections='collections',
|
||||
@@ -38,8 +39,7 @@ def _create_stub_map(directory_path_info):
|
||||
def generate():
|
||||
try:
|
||||
listed = os.listdir(directory_path_info.path)
|
||||
except (FileNotFoundError, OSError):
|
||||
# OSError is Python 2
|
||||
except (FileNotFoundError, NotADirectoryError):
|
||||
return
|
||||
|
||||
for entry in listed:
|
||||
@@ -59,20 +59,19 @@ def _create_stub_map(directory_path_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']:
|
||||
base_path = os.path.join(TYPESHED_PATH, base)
|
||||
base_path = TYPESHED_PATH.joinpath(base)
|
||||
base_list = os.listdir(base_path)
|
||||
for base_list_entry in base_list:
|
||||
match = re.match(r'(\d+)\.(\d+)$', base_list_entry)
|
||||
if match is not None:
|
||||
if int(match.group(1)) == version_info.major \
|
||||
and int(match.group(2)) <= version_info.minor:
|
||||
if match.group(1) == '3' and int(match.group(2)) <= version_info.minor:
|
||||
check_version_list.append(base_list_entry)
|
||||
|
||||
for check_version in check_version_list:
|
||||
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 = {}
|
||||
@@ -111,7 +110,7 @@ def import_module_decorator(func):
|
||||
# ``os``.
|
||||
python_value_set = ValueSet.from_sets(
|
||||
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:
|
||||
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(
|
||||
inference_state,
|
||||
python_value_set,
|
||||
file_io=FileIO(DJANGO_INIT_PATH),
|
||||
file_io=FileIO(str(DJANGO_INIT_PATH)),
|
||||
import_names=import_names,
|
||||
)
|
||||
|
||||
@@ -198,8 +197,8 @@ def _try_to_load_stub(inference_state, import_names, python_value_set,
|
||||
file_paths = []
|
||||
if c.is_namespace():
|
||||
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'):
|
||||
file_paths = [file_path + 'i']
|
||||
elif file_path is not None and file_path.suffix == '.py':
|
||||
file_paths = [str(file_path) + 'i']
|
||||
|
||||
for file_path in file_paths:
|
||||
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):
|
||||
try:
|
||||
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).
|
||||
return None
|
||||
else:
|
||||
|
||||
@@ -7,7 +7,6 @@ This file deals with all the typing.py cases.
|
||||
"""
|
||||
import itertools
|
||||
|
||||
from jedi._compatibility import unicode
|
||||
from jedi import debug
|
||||
from jedi.inference.compiled import builtin_from_name, create_simple_object
|
||||
from jedi.inference.base_value import ValueSet, NO_VALUES, Value, \
|
||||
@@ -72,7 +71,7 @@ class TypingModuleName(NameWrapper):
|
||||
elif name == 'TYPE_CHECKING':
|
||||
# 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.
|
||||
yield builtin_from_name(inference_state, u'True')
|
||||
yield builtin_from_name(inference_state, 'True')
|
||||
elif name == 'overload':
|
||||
yield OverloadFunction.create_cached(
|
||||
inference_state, self.parent_context, self.tree_name)
|
||||
@@ -89,12 +88,10 @@ class TypingModuleName(NameWrapper):
|
||||
inference_state, self.parent_context, self.tree_name)
|
||||
elif name in ('no_type_check', 'no_type_check_decorator'):
|
||||
# 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 c
|
||||
yield from self._wrapped_name.infer()
|
||||
else:
|
||||
# Everything else shouldn't be relevant for type checking.
|
||||
for c in self._wrapped_name.infer(): # Fuck my life Python 2
|
||||
yield c
|
||||
yield from self._wrapped_name.infer()
|
||||
|
||||
|
||||
class TypingModuleFilterWrapper(FilterWrapper):
|
||||
@@ -113,7 +110,7 @@ class ProxyWithGenerics(BaseTypingClassWithGenerics):
|
||||
# Optional is basically just saying it's either None or the actual
|
||||
# type.
|
||||
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':
|
||||
# The type is actually already given in the index_value
|
||||
return self._generics_manager[0]
|
||||
@@ -156,7 +153,7 @@ class ProxyWithGenerics(BaseTypingClassWithGenerics):
|
||||
# Optional[T] is equivalent to Union[T, None]. In Jedi unions
|
||||
# are represented by members within a ValueSet, so we extract
|
||||
# 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(
|
||||
value_set.filter(lambda x: x != none),
|
||||
)
|
||||
@@ -263,8 +260,6 @@ class TypeAlias(LazyValueWrapper):
|
||||
|
||||
def _get_wrapped_value(self):
|
||||
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?
|
||||
from jedi.inference.imports import Importer
|
||||
@@ -418,7 +413,7 @@ class NewTypeFunction(BaseTypingValue):
|
||||
|
||||
class NewType(Value):
|
||||
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.tree_node = tree_node
|
||||
|
||||
@@ -461,7 +456,7 @@ class TypedDict(LazyValueWrapper):
|
||||
return ValueName(self, self.tree_node.name)
|
||||
|
||||
def py__simple_getitem__(self, index):
|
||||
if isinstance(index, unicode):
|
||||
if isinstance(index, str):
|
||||
return ValueSet.from_sets(
|
||||
name.infer()
|
||||
for filter in self._definition_class.get_filters(is_instance=True)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
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.
|
||||
"""
|
||||
path = file_io.path
|
||||
assert path.endswith('.pyi')
|
||||
if path.startswith(TYPESHED_PATH):
|
||||
# /foo/stdlib/3/os/__init__.pyi -> stdlib/3/os/__init__
|
||||
rest = path[len(TYPESHED_PATH) + 1: -4]
|
||||
split_paths = tuple(rest.split(os.path.sep))
|
||||
# Remove the stdlib/3 or third_party/3.5 part
|
||||
import_names = split_paths[2:]
|
||||
if import_names[-1] == '__init__':
|
||||
path = Path(path)
|
||||
assert path.suffix == '.pyi'
|
||||
try:
|
||||
relative_path = path.relative_to(TYPESHED_PATH)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
# /[...]/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]
|
||||
|
||||
if import_names is not None:
|
||||
|
||||
@@ -7,18 +7,17 @@ from contextlib import contextmanager
|
||||
|
||||
from parso.python import tree
|
||||
|
||||
from jedi._compatibility import unicode
|
||||
|
||||
|
||||
def is_stdlib_path(path):
|
||||
# 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.
|
||||
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
|
||||
|
||||
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):
|
||||
@@ -122,11 +121,7 @@ def get_names_of_node(node):
|
||||
|
||||
|
||||
def is_string(value):
|
||||
if value.inference_state.environment.version_info.major == 2:
|
||||
str_classes = (unicode, bytes)
|
||||
else:
|
||||
str_classes = (unicode,)
|
||||
return value.is_compiled() and isinstance(value.get_safe_value(default=None), str_classes)
|
||||
return value.is_compiled() and isinstance(value.get_safe_value(default=None), str)
|
||||
|
||||
|
||||
def is_literal(value):
|
||||
@@ -144,7 +139,7 @@ def get_int_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):
|
||||
|
||||
@@ -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
|
||||
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
|
||||
statements like ``from datetim`` (cursor at the end would return ``datetime``).
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from parso.python import tree
|
||||
from parso.tree import search_ancestor
|
||||
|
||||
from jedi._compatibility import ImplicitNSInfo, force_unicode, FileNotFoundError
|
||||
from jedi import debug
|
||||
from jedi import settings
|
||||
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.gradual.typeshed import import_module_decorator, \
|
||||
create_stub_module, parse_stub_module
|
||||
from jedi.inference.compiled.subprocess.functions import ImplicitNSInfo
|
||||
from jedi.plugins import plugin_manager
|
||||
|
||||
|
||||
@@ -211,7 +209,7 @@ class Importer(object):
|
||||
# somewhere out of the filesystem.
|
||||
self._infer_possible = False
|
||||
else:
|
||||
self._fixed_sys_path = [force_unicode(base_directory)]
|
||||
self._fixed_sys_path = [base_directory]
|
||||
|
||||
if base_import_path is None:
|
||||
if import_path:
|
||||
@@ -240,7 +238,10 @@ class Importer(object):
|
||||
# inference we want to show the user as much as possible.
|
||||
# See GH #1446.
|
||||
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):
|
||||
@@ -332,7 +333,7 @@ def import_module_by_names(inference_state, import_names, sys_path=None,
|
||||
sys_path = inference_state.get_sys_path()
|
||||
|
||||
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
|
||||
)
|
||||
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
|
||||
module structure.
|
||||
"""
|
||||
path = file_io.path
|
||||
path = Path(file_io.path)
|
||||
if import_names is None:
|
||||
e_sys_path = inference_state.get_sys_path()
|
||||
import_names, is_package = sys_path.transform_path_to_dotted(e_sys_path, path)
|
||||
else:
|
||||
assert isinstance(is_package, bool)
|
||||
|
||||
is_stub = file_io.path.endswith('.pyi')
|
||||
is_stub = path.suffix == '.pyi'
|
||||
if is_stub:
|
||||
folder_io = file_io.get_parent_folder()
|
||||
if folder_io.path.endswith('-stubs'):
|
||||
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')
|
||||
else:
|
||||
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):
|
||||
import_names, is_package = sys_path.transform_path_to_dotted(
|
||||
inference_state.get_sys_path(),
|
||||
folder_io.path
|
||||
Path(folder_io.path)
|
||||
)
|
||||
from jedi.inference.value.namespace import ImplicitNamespaceValue
|
||||
return ImplicitNamespaceValue(inference_state, import_names, [folder_io.path])
|
||||
|
||||
@@ -29,7 +29,7 @@ class LazyKnownValues(AbstractLazyValue):
|
||||
|
||||
class LazyUnknownValue(AbstractLazyValue):
|
||||
def __init__(self, min=1, max=1):
|
||||
super(LazyUnknownValue, self).__init__(None, min, max)
|
||||
super().__init__(None, min, max)
|
||||
|
||||
def infer(self):
|
||||
return NO_VALUES
|
||||
@@ -37,7 +37,7 @@ class LazyUnknownValue(AbstractLazyValue):
|
||||
|
||||
class LazyTreeValue(AbstractLazyValue):
|
||||
def __init__(self, context, node, min=1, max=1):
|
||||
super(LazyTreeValue, self).__init__(node, min, max)
|
||||
super().__init__(node, min, max)
|
||||
self.context = context
|
||||
# We need to save the predefined names. It's an unfortunate side effect
|
||||
# that needs to be tracked otherwise results will be wrong.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from abc import abstractmethod
|
||||
from inspect import Parameter
|
||||
|
||||
from parso.tree import search_ancestor
|
||||
|
||||
from jedi._compatibility import Parameter
|
||||
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
|
||||
from jedi.inference.utils import unite
|
||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||
@@ -123,7 +123,7 @@ class AbstractTreeName(AbstractNameDefinition):
|
||||
else:
|
||||
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):
|
||||
parent_names = self.parent_context.get_qualified_names()
|
||||
@@ -242,7 +242,7 @@ class ValueNameMixin(object):
|
||||
def get_root_context(self):
|
||||
if self.parent_context is None: # A module
|
||||
return self._value.as_context()
|
||||
return super(ValueNameMixin, self).get_root_context()
|
||||
return super().get_root_context()
|
||||
|
||||
def get_defining_qualified_value(self):
|
||||
context = self.parent_context
|
||||
@@ -257,7 +257,7 @@ class ValueNameMixin(object):
|
||||
|
||||
class ValueName(ValueNameMixin, AbstractTreeName):
|
||||
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
|
||||
|
||||
def goto(self):
|
||||
@@ -372,7 +372,7 @@ class _ParamMixin(object):
|
||||
|
||||
|
||||
class ParamNameInterface(_ParamMixin):
|
||||
api_type = u'param'
|
||||
api_type = 'param'
|
||||
|
||||
def get_kind(self):
|
||||
raise NotImplementedError
|
||||
@@ -429,7 +429,7 @@ class BaseTreeParamName(ParamNameInterface, AbstractTreeName):
|
||||
|
||||
class _ActualTreeParamName(BaseTreeParamName):
|
||||
def __init__(self, function_value, tree_name):
|
||||
super(_ActualTreeParamName, self).__init__(
|
||||
super().__init__(
|
||||
function_value.get_default_param_context(), tree_name)
|
||||
self.function_value = function_value
|
||||
|
||||
@@ -499,11 +499,11 @@ class _ActualTreeParamName(BaseTreeParamName):
|
||||
class AnonymousParamName(_ActualTreeParamName):
|
||||
@plugin_manager.decorate(name='goto_anonymous_param')
|
||||
def goto(self):
|
||||
return super(AnonymousParamName, self).goto()
|
||||
return super().goto()
|
||||
|
||||
@plugin_manager.decorate(name='infer_anonymous_param')
|
||||
def infer(self):
|
||||
values = super(AnonymousParamName, self).infer()
|
||||
values = super().infer()
|
||||
if values:
|
||||
return values
|
||||
from jedi.inference.dynamic_params import dynamic_param_lookup
|
||||
@@ -527,11 +527,11 @@ class AnonymousParamName(_ActualTreeParamName):
|
||||
|
||||
class ParamName(_ActualTreeParamName):
|
||||
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
|
||||
|
||||
def infer(self):
|
||||
values = super(ParamName, self).infer()
|
||||
values = super().infer()
|
||||
if values:
|
||||
return values
|
||||
|
||||
@@ -627,7 +627,7 @@ class StubNameMixin(object):
|
||||
|
||||
names = convert_names(names, prefer_stub_to_compiled=False)
|
||||
if self in names:
|
||||
return super(StubNameMixin, self).py__doc__()
|
||||
return super().py__doc__()
|
||||
else:
|
||||
# We have signatures ourselves in stubs, so don't use signatures
|
||||
# from the implementation.
|
||||
@@ -637,7 +637,7 @@ class StubNameMixin(object):
|
||||
# From here on down we make looking up the sys.version_info fast.
|
||||
class StubName(StubNameMixin, TreeNameDefinition):
|
||||
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':
|
||||
from jedi.inference.gradual.stub_value import VersionInfo
|
||||
return ValueSet(VersionInfo(c) for c in inferred)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from collections import defaultdict
|
||||
from inspect import Parameter
|
||||
|
||||
from jedi import debug
|
||||
from jedi.inference.utils import PushBackIterator
|
||||
@@ -6,7 +7,6 @@ from jedi.inference import analysis
|
||||
from jedi.inference.lazy_value import LazyKnownValue, \
|
||||
LazyTreeValue, LazyUnknownValue
|
||||
from jedi.inference.value import iterable
|
||||
from jedi._compatibility import Parameter
|
||||
from jedi.inference.names import ParamName
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ def _add_argument_issue(error_name, lazy_value, message):
|
||||
|
||||
class ExecutedParamName(ParamName):
|
||||
def __init__(self, function_value, arguments, param_node, lazy_value, is_default=False):
|
||||
super(ExecutedParamName, self).__init__(
|
||||
function_value, param_node.name, arguments=arguments)
|
||||
super().__init__(function_value, param_node.name, arguments=arguments)
|
||||
self._lazy_value = lazy_value
|
||||
self._is_default = is_default
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import re
|
||||
|
||||
from parso import python_bytes_to_unicode
|
||||
|
||||
from jedi._compatibility import FileNotFoundError
|
||||
from jedi.debug import dbg
|
||||
from jedi.file_io import KnownContentFileIO
|
||||
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
|
||||
|
||||
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,
|
||||
limit_reduction=limit_reduction):
|
||||
yield x # Python 2...
|
||||
yield from search_in_file_ios(inference_state, file_io_iterator, name,
|
||||
limit_reduction=limit_reduction)
|
||||
|
||||
|
||||
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 import debug
|
||||
from jedi import parser_utils
|
||||
@@ -67,7 +68,7 @@ class AbstractSignature(_SignatureMixin):
|
||||
|
||||
class TreeSignature(AbstractSignature):
|
||||
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
|
||||
|
||||
def bind(self, value):
|
||||
@@ -121,7 +122,7 @@ class TreeSignature(AbstractSignature):
|
||||
|
||||
class BuiltinSignature(AbstractSignature):
|
||||
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.__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).
|
||||
"""
|
||||
from inspect import Parameter
|
||||
|
||||
from jedi._compatibility import Parameter
|
||||
from jedi.inference.utils import to_list
|
||||
from jedi.inference.names import ParamNameWrapper
|
||||
from jedi.inference.helpers import is_big_annoying_library
|
||||
@@ -32,8 +32,6 @@ def _iter_nodes_for_param(param_name):
|
||||
argument = name.parent
|
||||
if argument.type == 'argument' \
|
||||
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')
|
||||
if trailer is not None: # Make sure we're in a function
|
||||
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):
|
||||
def __init__(self, param_name, new_kind):
|
||||
super(ParamNameFixedKind, self).__init__(param_name)
|
||||
super().__init__(param_name)
|
||||
self._new_kind = new_kind
|
||||
|
||||
def get_kind(self):
|
||||
|
||||
@@ -5,7 +5,6 @@ import copy
|
||||
|
||||
from parso.python import tree
|
||||
|
||||
from jedi._compatibility import force_unicode, unicode
|
||||
from jedi import debug
|
||||
from jedi import parser_utils
|
||||
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]))
|
||||
elif typ == 'operator':
|
||||
# Must be an ellipsis, other operators are not inferred.
|
||||
# In Python 2 ellipsis is coded as three single dot tokens, not
|
||||
# as one token 3 dot token.
|
||||
if element.value not in ('.', '...'):
|
||||
if element.value != '...':
|
||||
origin = element.parent
|
||||
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':
|
||||
value_set = infer_atom(context, element.children[0])
|
||||
for next_name in element.children[2::2]:
|
||||
@@ -289,10 +286,6 @@ def infer_atom(context, atom):
|
||||
"""
|
||||
state = context.inference_state
|
||||
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.
|
||||
stmt = tree.search_ancestor(
|
||||
atom, 'expr_stmt', 'lambdef'
|
||||
@@ -312,9 +305,6 @@ def infer_atom(context, atom):
|
||||
# For False/True/None
|
||||
if atom.value in ('False', 'True', 'None'):
|
||||
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':
|
||||
# Contrary to yield from, yield can just appear alone to return a
|
||||
# value when used with `.send()`.
|
||||
@@ -329,7 +319,7 @@ def infer_atom(context, atom):
|
||||
value_set = infer_atom(context, atom.children[0])
|
||||
for string in atom.children[1:]:
|
||||
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
|
||||
elif atom.type == 'fstring':
|
||||
return compiled.get_string_value_set(state)
|
||||
@@ -567,7 +557,7 @@ def _is_tuple(value):
|
||||
|
||||
|
||||
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):
|
||||
@@ -590,10 +580,10 @@ def _get_tuple_ints(value):
|
||||
def _infer_comparison_part(inference_state, context, left, operator, right):
|
||||
l_is_num = is_number(left)
|
||||
r_is_num = is_number(right)
|
||||
if isinstance(operator, unicode):
|
||||
if isinstance(operator, str):
|
||||
str_operator = operator
|
||||
else:
|
||||
str_operator = force_unicode(str(operator.value))
|
||||
str_operator = str(operator.value)
|
||||
|
||||
if str_operator == '*':
|
||||
# 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)
|
||||
elif typ == 'with_stmt':
|
||||
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()
|
||||
elif typ in ('import_from', 'import_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)])
|
||||
|
||||
elif index.type == 'subscript' and not index.children[0] == '.':
|
||||
# subscript basically implies a slice operation, except for Python 2's
|
||||
# Ellipsis.
|
||||
# subscript basically implies a slice operation
|
||||
# e.g. array[:3]
|
||||
result = []
|
||||
for el in index.children:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import os
|
||||
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.base_value import ContextualizedNode
|
||||
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.file_io import FileIO
|
||||
from jedi import settings
|
||||
@@ -14,8 +14,9 @@ from jedi import debug
|
||||
_BUILDOUT_PATH_INSERTION_LIMIT = 10
|
||||
|
||||
|
||||
def _abs_path(module_context, path):
|
||||
if os.path.isabs(path):
|
||||
def _abs_path(module_context, path: str):
|
||||
path = Path(path)
|
||||
if path.is_absolute():
|
||||
return path
|
||||
|
||||
module_path = module_context.py__file__()
|
||||
@@ -24,9 +25,8 @@ def _abs_path(module_context, path):
|
||||
# system.
|
||||
return None
|
||||
|
||||
base_dir = os.path.dirname(module_path)
|
||||
path = force_unicode(path)
|
||||
return os.path.abspath(os.path.join(base_dir, path))
|
||||
base_dir = module_path.parent
|
||||
return base_dir.joinpath(path).absolute()
|
||||
|
||||
|
||||
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):
|
||||
file_io = FileIO(buildout_script_path)
|
||||
file_io = FileIO(str(buildout_script_path))
|
||||
try:
|
||||
module_node = inference_state.parse(
|
||||
file_io=file_io,
|
||||
@@ -164,20 +164,20 @@ def _get_paths_from_buildout_script(inference_state, buildout_script_path):
|
||||
inference_state, module_node,
|
||||
file_io=file_io,
|
||||
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()
|
||||
for path in check_sys_path_modifications(module_context):
|
||||
yield path
|
||||
|
||||
|
||||
def _get_parent_dir_with_file(path, filename):
|
||||
for parent in traverse_parents(path):
|
||||
if os.path.isfile(os.path.join(parent, filename)):
|
||||
def _get_parent_dir_with_file(path: Path, filename):
|
||||
for parent in path.parents:
|
||||
if parent.joinpath(filename).is_file():
|
||||
return parent
|
||||
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
|
||||
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')
|
||||
if not project_root:
|
||||
return
|
||||
bin_path = os.path.join(project_root, 'bin')
|
||||
if not os.path.exists(bin_path):
|
||||
bin_path = project_root.joinpath('bin')
|
||||
if not bin_path.exists():
|
||||
return
|
||||
|
||||
for filename in os.listdir(bin_path):
|
||||
try:
|
||||
filepath = os.path.join(bin_path, filename)
|
||||
filepath = bin_path.joinpath(filename)
|
||||
with open(filepath, 'r') as f:
|
||||
firstline = f.readline()
|
||||
if firstline.startswith('#!') and 'python' in firstline:
|
||||
@@ -203,14 +203,14 @@ def _get_buildout_script_paths(search_path):
|
||||
except (UnicodeDecodeError, IOError) as e:
|
||||
# Probably a binary file; permission error or race cond. because
|
||||
# file got deleted. Ignore it.
|
||||
debug.warning(unicode(e))
|
||||
debug.warning(e)
|
||||
continue
|
||||
|
||||
|
||||
def remove_python_path_suffix(path):
|
||||
for suffix in all_suffixes() + ['.pyi']:
|
||||
if path.endswith(suffix):
|
||||
path = path[:-len(suffix)]
|
||||
if path.suffix == suffix:
|
||||
path = path.with_name(path.stem)
|
||||
break
|
||||
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.
|
||||
|
||||
>>> from os.path import abspath
|
||||
>>> transform_path_to_dotted([abspath("/foo")], abspath('/foo/bar/baz.py'))
|
||||
>>> transform_path_to_dotted([str(Path("/foo").absolute())], Path('/foo/bar/baz.py').absolute())
|
||||
(('bar', 'baz'), False)
|
||||
|
||||
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.
|
||||
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
|
||||
# means that if someone uses an ending like .vim for a Python file, .vim
|
||||
# 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:
|
||||
# -1 to remove the separator
|
||||
module_path = module_path[:-len('__init__') - 1]
|
||||
module_path = module_path.parent
|
||||
|
||||
def iter_potential_solutions():
|
||||
for p in sys_path:
|
||||
if module_path.startswith(p):
|
||||
if str(module_path).startswith(p):
|
||||
# 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.
|
||||
if rest.startswith(os.path.sep) or rest.startswith('/'):
|
||||
# Remove a slash in cases it's still there.
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
""" A universal module with functions / classes without dependencies. """
|
||||
import sys
|
||||
import contextlib
|
||||
import functools
|
||||
import re
|
||||
import os
|
||||
|
||||
from jedi._compatibility import reraise
|
||||
|
||||
|
||||
_sep = os.path.sep
|
||||
if os.path.altsep is not None:
|
||||
@@ -36,7 +32,6 @@ class UncaughtAttributeError(Exception):
|
||||
"""
|
||||
Important, because `__getattr__` and `hasattr` catch AttributeErrors
|
||||
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`
|
||||
instead of `Exception`. But because I removed relevant `hasattr` from
|
||||
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
|
||||
`AttributeError` to `UncaughtAttributeError` to avoid unexpected catch.
|
||||
This helps us noticing bugs earlier and facilitates debugging.
|
||||
|
||||
.. note:: Treating StopIteration here is easy.
|
||||
Add that feature when needed.
|
||||
"""
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwds):
|
||||
try:
|
||||
return func(*args, **kwds)
|
||||
except AttributeError:
|
||||
exc_info = sys.exc_info()
|
||||
reraise(UncaughtAttributeError(exc_info[1]), exc_info[2])
|
||||
except AttributeError as e:
|
||||
raise UncaughtAttributeError(e) from e
|
||||
return wrapper
|
||||
|
||||
|
||||
@@ -91,25 +82,9 @@ class PushBackIterator(object):
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
""" Python 2 Compatibility """
|
||||
return self.__next__()
|
||||
|
||||
def __next__(self):
|
||||
if self.pushes:
|
||||
self.current = self.pushes.pop()
|
||||
else:
|
||||
self.current = next(self.iterator)
|
||||
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):
|
||||
def __init__(self, wrapped_value, original_value):
|
||||
super(Decoratee, self).__init__(wrapped_value)
|
||||
super().__init__(wrapped_value)
|
||||
self._original_value = original_value
|
||||
|
||||
def py__doc__(self):
|
||||
|
||||
@@ -170,7 +170,7 @@ class _DynamicArrayAdditions(HelperValueMixin):
|
||||
|
||||
class _Modification(ValueWrapper):
|
||||
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._contextualized_key = contextualized_key
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from parso.python import tree
|
||||
|
||||
from jedi._compatibility import use_metaclass
|
||||
from jedi import debug
|
||||
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass
|
||||
from jedi.inference import compiled
|
||||
@@ -26,7 +25,7 @@ from jedi.inference.gradual.generics import TupleGenericManager
|
||||
|
||||
class LambdaName(AbstractNameDefinition):
|
||||
string_name = '<lambda>'
|
||||
api_type = u'function'
|
||||
api_type = 'function'
|
||||
|
||||
def __init__(self, lambda_value):
|
||||
self._lambda_value = lambda_value
|
||||
@@ -55,7 +54,7 @@ class FunctionAndClassBase(TreeValue):
|
||||
|
||||
|
||||
class FunctionMixin(object):
|
||||
api_type = u'function'
|
||||
api_type = 'function'
|
||||
|
||||
def get_filters(self, origin_scope=None):
|
||||
cls = self.py__class__()
|
||||
@@ -126,7 +125,7 @@ class FunctionMixin(object):
|
||||
return [TreeSignature(f) for f in self.get_signature_functions()]
|
||||
|
||||
|
||||
class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndClassBase)):
|
||||
class FunctionValue(FunctionMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
|
||||
@classmethod
|
||||
def from_context(cls, context, tree_node):
|
||||
def create(tree_node):
|
||||
@@ -161,7 +160,7 @@ class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndCla
|
||||
return function
|
||||
|
||||
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
|
||||
|
||||
def get_default_param_context(self):
|
||||
@@ -173,7 +172,7 @@ class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndCla
|
||||
|
||||
class FunctionNameInClass(NameWrapper):
|
||||
def __init__(self, class_context, name):
|
||||
super(FunctionNameInClass, self).__init__(name)
|
||||
super().__init__(name)
|
||||
self._class_context = class_context
|
||||
|
||||
def get_defining_qualified_value(self):
|
||||
@@ -182,7 +181,7 @@ class FunctionNameInClass(NameWrapper):
|
||||
|
||||
class MethodValue(FunctionValue):
|
||||
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
|
||||
|
||||
def get_default_param_context(self):
|
||||
@@ -198,7 +197,7 @@ class MethodValue(FunctionValue):
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return FunctionNameInClass(self.class_context, super(MethodValue, self).name)
|
||||
return FunctionNameInClass(self.class_context, super().name)
|
||||
|
||||
|
||||
class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
||||
@@ -238,7 +237,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
||||
try:
|
||||
children = r.children
|
||||
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])
|
||||
else:
|
||||
value_set |= self.infer_node(children[1])
|
||||
@@ -250,7 +249,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
||||
def _get_yield_lazy_value(self, yield_expr):
|
||||
if yield_expr.type == 'keyword':
|
||||
# `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)
|
||||
return
|
||||
|
||||
@@ -330,8 +329,6 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
||||
|
||||
if is_coroutine:
|
||||
if self.is_generator():
|
||||
if inference_state.environment.version_info < (3, 6):
|
||||
return NO_VALUES
|
||||
async_generator_classes = inference_state.typing_module \
|
||||
.py__getattribute__('AsyncGenerator')
|
||||
|
||||
@@ -339,13 +336,10 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
||||
# The contravariant doesn't seem to be defined.
|
||||
generics = (yield_values.py__class__(), NO_VALUES)
|
||||
return ValueSet(
|
||||
# In Python 3.6 AsyncGenerator is still a class.
|
||||
GenericClass(c, TupleGenericManager(generics))
|
||||
for c in async_generator_classes
|
||||
).execute_annotation()
|
||||
else:
|
||||
if inference_state.environment.version_info < (3, 5):
|
||||
return NO_VALUES
|
||||
async_classes = inference_state.typing_module.py__getattribute__('Coroutine')
|
||||
return_values = self.get_return_values()
|
||||
# Only the first generic is relevant.
|
||||
@@ -362,7 +356,7 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
|
||||
|
||||
class FunctionExecutionContext(BaseFunctionExecutionContext):
|
||||
def __init__(self, function_value, arguments):
|
||||
super(FunctionExecutionContext, self).__init__(function_value)
|
||||
super().__init__(function_value)
|
||||
self._arguments = arguments
|
||||
|
||||
def get_filters(self, until_position=None, origin_scope=None):
|
||||
@@ -403,7 +397,7 @@ class AnonymousFunctionExecution(BaseFunctionExecutionContext):
|
||||
|
||||
class OverloadedFunctionValue(FunctionMixin, ValueWrapper):
|
||||
def __init__(self, function, overloaded_functions):
|
||||
super(OverloadedFunctionValue, self).__init__(function)
|
||||
super().__init__(function)
|
||||
self._overloaded_functions = overloaded_functions
|
||||
|
||||
def py__call__(self, arguments):
|
||||
|
||||
@@ -25,7 +25,7 @@ from jedi.parser_utils import function_is_staticmethod, function_is_classmethod
|
||||
|
||||
class InstanceExecutedParamName(ParamName):
|
||||
def __init__(self, instance, function_value, tree_name):
|
||||
super(InstanceExecutedParamName, self).__init__(
|
||||
super().__init__(
|
||||
function_value, tree_name, arguments=None)
|
||||
self._instance = instance
|
||||
|
||||
@@ -38,7 +38,7 @@ class InstanceExecutedParamName(ParamName):
|
||||
|
||||
class AnonymousMethodExecutionFilter(AnonymousFunctionExecutionFilter):
|
||||
def __init__(self, instance, *args, **kwargs):
|
||||
super(AnonymousMethodExecutionFilter, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self._instance = instance
|
||||
|
||||
def _convert_param(self, param, name):
|
||||
@@ -55,12 +55,12 @@ class AnonymousMethodExecutionFilter(AnonymousFunctionExecutionFilter):
|
||||
self._function_value,
|
||||
name
|
||||
)
|
||||
return super(AnonymousMethodExecutionFilter, self)._convert_param(param, name)
|
||||
return super()._convert_param(param, name)
|
||||
|
||||
|
||||
class AnonymousMethodExecutionContext(BaseFunctionExecutionContext):
|
||||
def __init__(self, instance, value):
|
||||
super(AnonymousMethodExecutionContext, self).__init__(value)
|
||||
super().__init__(value)
|
||||
self.instance = instance
|
||||
|
||||
def get_filters(self, until_position=None, origin_scope=None):
|
||||
@@ -83,15 +83,15 @@ class AnonymousMethodExecutionContext(BaseFunctionExecutionContext):
|
||||
|
||||
class MethodExecutionContext(FunctionExecutionContext):
|
||||
def __init__(self, instance, *args, **kwargs):
|
||||
super(MethodExecutionContext, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.instance = instance
|
||||
|
||||
|
||||
class AbstractInstanceValue(Value):
|
||||
api_type = u'instance'
|
||||
api_type = 'instance'
|
||||
|
||||
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
|
||||
# (No arguments) used.
|
||||
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
|
||||
# compiled class.
|
||||
def __init__(self, inference_state, parent_context, class_value, arguments):
|
||||
super(CompiledInstance, self).__init__(inference_state, parent_context,
|
||||
class_value)
|
||||
super().__init__(inference_state, parent_context, class_value)
|
||||
self._arguments = arguments
|
||||
|
||||
def get_filters(self, origin_scope=None, include_self_names=True):
|
||||
@@ -234,14 +233,14 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
||||
# other way around.
|
||||
if is_big_annoying_library(self.parent_context):
|
||||
return NO_VALUES
|
||||
names = (self.get_function_slot_names(u'__getattr__')
|
||||
or self.get_function_slot_names(u'__getattribute__'))
|
||||
names = (self.get_function_slot_names('__getattr__')
|
||||
or self.get_function_slot_names('__getattribute__'))
|
||||
return self.execute_function_slots(names, name)
|
||||
|
||||
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:
|
||||
return super(_BaseTreeInstance, self).py__getitem__(
|
||||
return super().py__getitem__(
|
||||
index_value_set,
|
||||
contextualized_node,
|
||||
)
|
||||
@@ -250,9 +249,9 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
||||
return ValueSet.from_sets(name.infer().execute(args) for name in names)
|
||||
|
||||
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:
|
||||
return super(_BaseTreeInstance, self).py__iter__(contextualized_node)
|
||||
return super().py__iter__(contextualized_node)
|
||||
|
||||
def iterate():
|
||||
for generator in self.execute_function_slots(iter_slot_names):
|
||||
@@ -261,11 +260,7 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
||||
return iterate()
|
||||
|
||||
def py__next__(self, contextualized_node=None):
|
||||
# `__next__` logic.
|
||||
if self.inference_state.environment.version_info.major == 2:
|
||||
name = u'next'
|
||||
else:
|
||||
name = u'__next__'
|
||||
name = u'__next__'
|
||||
next_slot_names = self.get_function_slot_names(name)
|
||||
if next_slot_names:
|
||||
yield LazyKnownValues(
|
||||
@@ -275,10 +270,10 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
||||
debug.warning('Instance has no __next__ function in %s.', self)
|
||||
|
||||
def py__call__(self, arguments):
|
||||
names = self.get_function_slot_names(u'__call__')
|
||||
names = self.get_function_slot_names('__call__')
|
||||
if not names:
|
||||
# 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)
|
||||
|
||||
@@ -293,10 +288,10 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
||||
if result is not NotImplemented:
|
||||
return result
|
||||
|
||||
names = self.get_function_slot_names(u'__get__')
|
||||
names = self.get_function_slot_names('__get__')
|
||||
if names:
|
||||
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)
|
||||
else:
|
||||
return ValueSet([self])
|
||||
@@ -322,7 +317,7 @@ class TreeInstance(_BaseTreeInstance):
|
||||
if settings.dynamic_array_additions:
|
||||
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.tree_node = class_value.tree_node
|
||||
|
||||
@@ -396,7 +391,7 @@ class TreeInstance(_BaseTreeInstance):
|
||||
else:
|
||||
if key == index:
|
||||
return lazy_context.infer()
|
||||
return super(TreeInstance, self).py__simple_getitem__(index)
|
||||
return super().py__simple_getitem__(index)
|
||||
|
||||
def __repr__(self):
|
||||
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):
|
||||
parent_value = klass.parent_context.get_value()
|
||||
assert parent_value is not None, "How? Please reproduce and report"
|
||||
super(CompiledInstanceName, self).__init__(
|
||||
super().__init__(
|
||||
inference_state,
|
||||
parent_value,
|
||||
name.string_name
|
||||
@@ -449,7 +444,7 @@ class CompiledInstanceClassFilter(AbstractFilter):
|
||||
|
||||
class BoundMethod(FunctionMixin, ValueWrapper):
|
||||
def __init__(self, instance, class_context, function):
|
||||
super(BoundMethod, self).__init__(function)
|
||||
super().__init__(function)
|
||||
self.instance = instance
|
||||
self._class_context = class_context
|
||||
|
||||
@@ -460,11 +455,11 @@ class BoundMethod(FunctionMixin, ValueWrapper):
|
||||
def name(self):
|
||||
return FunctionNameInClass(
|
||||
self._class_context,
|
||||
super(BoundMethod, self).name
|
||||
super().name
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
def _get_arguments(self, arguments):
|
||||
@@ -492,7 +487,7 @@ class BoundMethod(FunctionMixin, ValueWrapper):
|
||||
]
|
||||
|
||||
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):
|
||||
return '<%s: %s>' % (self.__class__.__name__, self._wrapped_value)
|
||||
@@ -525,7 +520,7 @@ class SelfName(TreeNameDefinition):
|
||||
|
||||
class LazyInstanceClassName(NameWrapper):
|
||||
def __init__(self, instance, class_member_name):
|
||||
super(LazyInstanceClassName, self).__init__(class_member_name)
|
||||
super().__init__(class_member_name)
|
||||
self._instance = instance
|
||||
|
||||
@iterator_to_value_set
|
||||
@@ -572,7 +567,7 @@ class SelfAttributeFilter(ClassFilter):
|
||||
This class basically filters all the use cases where `self.*` was assigned.
|
||||
"""
|
||||
def __init__(self, instance, instance_class, node_context, origin_scope):
|
||||
super(SelfAttributeFilter, self).__init__(
|
||||
super().__init__(
|
||||
class_value=instance_class,
|
||||
node_context=node_context,
|
||||
origin_scope=origin_scope,
|
||||
@@ -616,7 +611,7 @@ class SelfAttributeFilter(ClassFilter):
|
||||
|
||||
class InstanceArguments(TreeArgumentsWrapper):
|
||||
def __init__(self, instance, arguments):
|
||||
super(InstanceArguments, self).__init__(arguments)
|
||||
super().__init__(arguments)
|
||||
self.instance = instance
|
||||
|
||||
def unpack(self, func=None):
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
Contains all classes and functions to deal with lists, dicts, generators and
|
||||
iterators in general.
|
||||
"""
|
||||
import sys
|
||||
|
||||
from jedi._compatibility import force_unicode, is_py3
|
||||
from jedi.inference import compiled
|
||||
from jedi.inference import analysis
|
||||
from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues, \
|
||||
@@ -27,7 +24,7 @@ class IterableMixin(object):
|
||||
return self.py__iter__(contextualized_node)
|
||||
|
||||
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
|
||||
# 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.
|
||||
# This mostly speeds up patterns like `sys.version_info >= (3, 0)` in
|
||||
# typeshed.
|
||||
if sys.version_info[0] == 2:
|
||||
# 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
|
||||
get_safe_value = Value.get_safe_value
|
||||
|
||||
|
||||
class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
|
||||
@@ -64,13 +54,12 @@ class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
|
||||
return ValueSet([self])
|
||||
|
||||
@publish_method('send')
|
||||
@publish_method('next', python_version_match=2)
|
||||
@publish_method('__next__', python_version_match=3)
|
||||
@publish_method('__next__')
|
||||
def _next(self, arguments):
|
||||
return ValueSet.from_sets(lazy_value.infer() for lazy_value in self.py__iter__())
|
||||
|
||||
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
|
||||
def name(self):
|
||||
@@ -86,7 +75,7 @@ class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
|
||||
class Generator(GeneratorBase):
|
||||
"""Handling of `yield` functions."""
|
||||
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
|
||||
|
||||
def py__iter__(self, contextualized_node=None):
|
||||
@@ -194,7 +183,7 @@ class _DictMixin(object):
|
||||
|
||||
|
||||
class Sequence(LazyAttributeOverwrite, IterableMixin):
|
||||
api_type = u'instance'
|
||||
api_type = 'instance'
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@@ -233,14 +222,14 @@ class Sequence(LazyAttributeOverwrite, IterableMixin):
|
||||
class _BaseComprehension(ComprehensionMixin):
|
||||
def __init__(self, inference_state, defining_context, sync_comp_for_node, entry_node):
|
||||
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._sync_comp_for_node = sync_comp_for_node
|
||||
self._entry_node = entry_node
|
||||
|
||||
|
||||
class ListComprehension(_BaseComprehension, Sequence):
|
||||
array_type = u'list'
|
||||
array_type = 'list'
|
||||
|
||||
def py__simple_getitem__(self, index):
|
||||
if isinstance(index, slice):
|
||||
@@ -253,7 +242,7 @@ class ListComprehension(_BaseComprehension, Sequence):
|
||||
|
||||
|
||||
class SetComprehension(_BaseComprehension, Sequence):
|
||||
array_type = u'set'
|
||||
array_type = 'set'
|
||||
|
||||
|
||||
class GeneratorComprehension(_BaseComprehension, GeneratorBase):
|
||||
@@ -271,11 +260,11 @@ class _DictKeyMixin(object):
|
||||
|
||||
|
||||
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):
|
||||
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._sync_comp_for_node = sync_comp_for_node
|
||||
self._entry_node = key_node
|
||||
@@ -328,25 +317,25 @@ class DictComprehension(ComprehensionMixin, Sequence, _DictKeyMixin):
|
||||
|
||||
class SequenceLiteralValue(Sequence):
|
||||
_TUPLE_LIKE = 'testlist_star_expr', 'testlist', 'subscriptlist'
|
||||
mapping = {'(': u'tuple',
|
||||
'[': u'list',
|
||||
'{': u'set'}
|
||||
mapping = {'(': 'tuple',
|
||||
'[': 'list',
|
||||
'{': 'set'}
|
||||
|
||||
def __init__(self, inference_state, defining_context, atom):
|
||||
super(SequenceLiteralValue, self).__init__(inference_state)
|
||||
super().__init__(inference_state)
|
||||
self.atom = atom
|
||||
self._defining_context = defining_context
|
||||
|
||||
if self.atom.type in self._TUPLE_LIKE:
|
||||
self.array_type = u'tuple'
|
||||
self.array_type = 'tuple'
|
||||
else:
|
||||
self.array_type = SequenceLiteralValue.mapping[atom.children[0]]
|
||||
"""The builtin name of the array (list, set, tuple or dict)."""
|
||||
|
||||
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 super(SequenceLiteralValue, self)._get_generics()
|
||||
return super()._get_generics()
|
||||
|
||||
def py__simple_getitem__(self, index):
|
||||
"""Here the index is an int/str. Raises IndexError/KeyError."""
|
||||
@@ -436,10 +425,12 @@ class SequenceLiteralValue(Sequence):
|
||||
|
||||
|
||||
class DictLiteralValue(_DictMixin, SequenceLiteralValue, _DictKeyMixin):
|
||||
array_type = u'dict'
|
||||
array_type = 'dict'
|
||||
|
||||
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.atom = atom
|
||||
|
||||
@@ -448,7 +439,7 @@ class DictLiteralValue(_DictMixin, SequenceLiteralValue, _DictKeyMixin):
|
||||
compiled_value_index = compiled.create_simple_object(self.inference_state, index)
|
||||
for key, value in self.get_tree_entries():
|
||||
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():
|
||||
return self._defining_context.infer_node(value)
|
||||
raise SimpleGetItemNotFound('No key found in dictionary %s.' % self)
|
||||
@@ -502,7 +493,7 @@ class _FakeSequence(Sequence):
|
||||
"""
|
||||
type should be one of "tuple", "list"
|
||||
"""
|
||||
super(_FakeSequence, self).__init__(inference_state)
|
||||
super().__init__(inference_state)
|
||||
self._lazy_value_list = lazy_value_list
|
||||
|
||||
def py__simple_getitem__(self, index):
|
||||
@@ -524,18 +515,18 @@ class _FakeSequence(Sequence):
|
||||
|
||||
|
||||
class FakeTuple(_FakeSequence):
|
||||
array_type = u'tuple'
|
||||
array_type = 'tuple'
|
||||
|
||||
|
||||
class FakeList(_FakeSequence):
|
||||
array_type = u'tuple'
|
||||
array_type = 'tuple'
|
||||
|
||||
|
||||
class FakeDict(_DictMixin, Sequence, _DictKeyMixin):
|
||||
array_type = u'dict'
|
||||
array_type = 'dict'
|
||||
|
||||
def __init__(self, inference_state, dct):
|
||||
super(FakeDict, self).__init__(inference_state)
|
||||
super().__init__(inference_state)
|
||||
self._dct = dct
|
||||
|
||||
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))
|
||||
|
||||
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):
|
||||
lazy_value = self._dct[index]
|
||||
return lazy_value.infer()
|
||||
@@ -584,7 +560,7 @@ class FakeDict(_DictMixin, Sequence, _DictKeyMixin):
|
||||
|
||||
class MergedArray(Sequence):
|
||||
def __init__(self, inference_state, arrays):
|
||||
super(MergedArray, self).__init__(inference_state)
|
||||
super().__init__(inference_state)
|
||||
self.array_type = arrays[-1].array_type
|
||||
self._arrays = arrays
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ py__doc__() Returns the docstring for a value.
|
||||
|
||||
"""
|
||||
from jedi import debug
|
||||
from jedi._compatibility import use_metaclass
|
||||
from jedi.parser_utils import get_cached_parent_scope, expr_is_dotted
|
||||
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass, \
|
||||
inference_state_method_generator_cache
|
||||
@@ -56,7 +55,7 @@ from jedi.plugins import plugin_manager
|
||||
|
||||
class ClassName(TreeNameDefinition):
|
||||
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._class_value = class_value
|
||||
|
||||
@@ -78,7 +77,7 @@ class ClassName(TreeNameDefinition):
|
||||
class ClassFilter(ParserTreeFilter):
|
||||
def __init__(self, class_value, node_context=None, until_position=None,
|
||||
origin_scope=None, is_instance=False):
|
||||
super(ClassFilter, self).__init__(
|
||||
super().__init__(
|
||||
class_value.as_context(), node_context,
|
||||
until_position=until_position,
|
||||
origin_scope=origin_scope,
|
||||
@@ -125,7 +124,7 @@ class ClassFilter(ParserTreeFilter):
|
||||
or self._equals_origin_scope()
|
||||
|
||||
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)]
|
||||
|
||||
|
||||
@@ -145,7 +144,7 @@ class ClassMixin(object):
|
||||
return ValueSet([TreeInstance(self.inference_state, self.parent_context, self, arguments)])
|
||||
|
||||
def py__class__(self):
|
||||
return compiled.builtin_from_name(self.inference_state, u'type')
|
||||
return compiled.builtin_from_name(self.inference_state, 'type')
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@@ -192,13 +191,11 @@ class ClassMixin(object):
|
||||
if include_metaclasses:
|
||||
metaclasses = self.get_metaclasses()
|
||||
if metaclasses:
|
||||
for f in self.get_metaclass_filters(metaclasses, is_instance):
|
||||
yield f # Python 2..
|
||||
yield from self.get_metaclass_filters(metaclasses, is_instance)
|
||||
|
||||
for cls in self.py__mro__():
|
||||
if cls.is_compiled():
|
||||
for filter in cls.get_filters(is_instance=is_instance):
|
||||
yield filter
|
||||
yield from cls.get_filters(is_instance=is_instance)
|
||||
else:
|
||||
yield ClassFilter(
|
||||
self, node_context=cls.as_context(),
|
||||
@@ -207,7 +204,7 @@ class ClassMixin(object):
|
||||
)
|
||||
if not is_instance and include_type_when_class:
|
||||
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)
|
||||
if type_ != self:
|
||||
# We are not using execute_with_values here, because the
|
||||
@@ -321,8 +318,8 @@ class ClassMixin(object):
|
||||
return ValueSet({self})
|
||||
|
||||
|
||||
class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase)):
|
||||
api_type = u'class'
|
||||
class ClassValue(ClassMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
|
||||
api_type = 'class'
|
||||
|
||||
@inference_state_method_cache()
|
||||
def list_type_vars(self):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from jedi.inference.cache import inference_state_method_cache
|
||||
from jedi.inference.names import AbstractNameDefinition, ModuleName
|
||||
@@ -16,7 +17,7 @@ class _ModuleAttributeName(AbstractNameDefinition):
|
||||
"""
|
||||
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):
|
||||
self.parent_context = parent_module
|
||||
@@ -26,9 +27,6 @@ class _ModuleAttributeName(AbstractNameDefinition):
|
||||
def infer(self):
|
||||
if self._string_value is not None:
|
||||
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([
|
||||
create_simple_object(self.parent_context.inference_state, s)
|
||||
])
|
||||
@@ -73,7 +71,7 @@ class ModuleMixin(SubModuleDictMixin):
|
||||
yield star_filter
|
||||
|
||||
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
|
||||
|
||||
def is_module(self):
|
||||
@@ -92,9 +90,9 @@ class ModuleMixin(SubModuleDictMixin):
|
||||
names = ['__package__', '__doc__', '__name__']
|
||||
# All the additional module attributes are strings.
|
||||
dct = dict((n, _ModuleAttributeName(self, n)) for n in names)
|
||||
file = self.py__file__()
|
||||
if file is not None:
|
||||
dct['__file__'] = _ModuleAttributeName(self, '__file__', file)
|
||||
path = self.py__file__()
|
||||
if path is not None:
|
||||
dct['__file__'] = _ModuleAttributeName(self, '__file__', str(path))
|
||||
return dct
|
||||
|
||||
def iter_star_filters(self):
|
||||
@@ -137,11 +135,11 @@ class ModuleMixin(SubModuleDictMixin):
|
||||
|
||||
|
||||
class ModuleValue(ModuleMixin, TreeValue):
|
||||
api_type = u'module'
|
||||
api_type = 'module'
|
||||
|
||||
def __init__(self, inference_state, module_node, code_lines, file_io=None,
|
||||
string_names=None, is_package=False):
|
||||
super(ModuleValue, self).__init__(
|
||||
super().__init__(
|
||||
inference_state,
|
||||
parent_context=None,
|
||||
tree_node=module_node
|
||||
@@ -150,32 +148,32 @@ class ModuleValue(ModuleMixin, TreeValue):
|
||||
if file_io is None:
|
||||
self._path = None
|
||||
else:
|
||||
self._path = file_io.path
|
||||
self._path = Path(file_io.path)
|
||||
self.string_names = string_names # Optional[Tuple[str, ...]]
|
||||
self.code_lines = code_lines
|
||||
self._is_package = is_package
|
||||
|
||||
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
|
||||
# used in them. This could be changed if stubs would be identified
|
||||
# sooner and used as StubModuleValue.
|
||||
return True
|
||||
return super(ModuleValue, self).is_stub()
|
||||
return super().is_stub()
|
||||
|
||||
def py__name__(self):
|
||||
if self.string_names is None:
|
||||
return None
|
||||
return '.'.join(self.string_names)
|
||||
|
||||
def py__file__(self):
|
||||
def py__file__(self) -> Path:
|
||||
"""
|
||||
In contrast to Python's __file__ can be None.
|
||||
"""
|
||||
if self._path is None:
|
||||
return None
|
||||
|
||||
return os.path.abspath(self._path)
|
||||
return self._path.absolute()
|
||||
|
||||
def is_package(self):
|
||||
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
|
||||
# folder foobar it will be available as an object:
|
||||
# <module 'foobar' (namespace)>.
|
||||
api_type = u'module'
|
||||
api_type = 'module'
|
||||
parent_context = None
|
||||
|
||||
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.string_names = string_names
|
||||
self._paths = paths
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import re
|
||||
import textwrap
|
||||
from ast import literal_eval
|
||||
from inspect import cleandoc
|
||||
from weakref import WeakKeyDictionary
|
||||
|
||||
@@ -7,8 +8,6 @@ from parso.python import tree
|
||||
from parso.cache import parser_cache
|
||||
from parso import split_lines
|
||||
|
||||
from jedi._compatibility import literal_eval, force_unicode
|
||||
|
||||
_EXECUTE_NODES = {'funcdef', 'classdef', 'import_from', 'import_name', 'test',
|
||||
'or_test', 'and_test', 'not_test', 'comparison', '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
|
||||
# docstring can also look like this: ``'foo' 'bar'
|
||||
# Returns a literal cleaned version of the ``Token``.
|
||||
cleaned = cleandoc(safe_literal_eval(node.value))
|
||||
# Since we want the docstr output to be always unicode, just
|
||||
# force it.
|
||||
return force_unicode(cleaned)
|
||||
return cleandoc(safe_literal_eval(node.value))
|
||||
return ''
|
||||
|
||||
|
||||
@@ -117,10 +113,7 @@ def find_statement_documentation(tree_node):
|
||||
if maybe_string.type == 'simple_stmt':
|
||||
maybe_string = maybe_string.children[0]
|
||||
if maybe_string.type == 'string':
|
||||
cleaned = 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 cleandoc(safe_literal_eval(maybe_string.value))
|
||||
return ''
|
||||
|
||||
|
||||
@@ -131,15 +124,7 @@ def safe_literal_eval(value):
|
||||
# manually, but that's right now not implemented.
|
||||
return ''
|
||||
|
||||
try:
|
||||
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 ''
|
||||
return literal_eval(value)
|
||||
|
||||
|
||||
def get_signature(funcdef, width=72, call_string=None,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"""
|
||||
Module is used to infer Django model fields.
|
||||
"""
|
||||
from jedi._compatibility import Parameter
|
||||
from inspect import Parameter
|
||||
|
||||
from jedi import debug
|
||||
from jedi.inference.cache import inference_state_function_cache
|
||||
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):
|
||||
def __init__(self, cls, name, is_instance):
|
||||
super(DjangoModelName, self).__init__(name)
|
||||
super().__init__(name)
|
||||
self._cls = cls
|
||||
self._is_instance = is_instance
|
||||
|
||||
@@ -257,7 +258,7 @@ class GenericFieldWrapper(AttributeOverwrite, ClassMixin):
|
||||
|
||||
class DjangoModelSignature(AbstractSignature):
|
||||
def __init__(self, value, field_names):
|
||||
super(DjangoModelSignature, self).__init__(value)
|
||||
super().__init__(value)
|
||||
self._field_names = field_names
|
||||
|
||||
def get_param_names(self, resolve_stars=False):
|
||||
@@ -266,7 +267,7 @@ class DjangoModelSignature(AbstractSignature):
|
||||
|
||||
class DjangoParamName(BaseTreeParamName):
|
||||
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
|
||||
|
||||
def get_kind(self):
|
||||
@@ -278,7 +279,7 @@ class DjangoParamName(BaseTreeParamName):
|
||||
|
||||
class QuerySetMethodWrapper(ValueWrapper):
|
||||
def __init__(self, method, model_cls):
|
||||
super(QuerySetMethodWrapper, self).__init__(method)
|
||||
super().__init__(method)
|
||||
self._model_cls = model_cls
|
||||
|
||||
def py__get__(self, instance, class_value):
|
||||
@@ -288,7 +289,7 @@ class QuerySetMethodWrapper(ValueWrapper):
|
||||
|
||||
class QuerySetBoundMethodWrapper(ValueWrapper):
|
||||
def __init__(self, method, model_cls):
|
||||
super(QuerySetBoundMethodWrapper, self).__init__(method)
|
||||
super().__init__(method)
|
||||
self._model_cls = model_cls
|
||||
|
||||
def get_signatures(self):
|
||||
|
||||
@@ -6,14 +6,14 @@ def import_module(callback):
|
||||
def wrapper(inference_state, import_names, module_context, *args, **kwargs):
|
||||
if len(import_names) == 3 and import_names[:2] == ('flask', 'ext'):
|
||||
# New style.
|
||||
ipath = (u'flask_' + import_names[2]),
|
||||
ipath = ('flask_' + import_names[2]),
|
||||
value_set = callback(inference_state, ipath, None, *args, **kwargs)
|
||||
if 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(
|
||||
inference_state,
|
||||
(u'flaskext', import_names[2]),
|
||||
('flaskext', import_names[2]),
|
||||
next(iter(value_set)),
|
||||
*args, **kwargs
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
from parso.python.tree import search_ancestor
|
||||
from jedi._compatibility import FileNotFoundError
|
||||
from jedi.inference.cache import inference_state_method_cache
|
||||
from jedi.inference.imports import load_module_from_path
|
||||
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()
|
||||
while any(folder.path.startswith(p) for p in sys_path):
|
||||
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:
|
||||
m = load_module_from_path(module_context.inference_state, file_io)
|
||||
yield m.as_context()
|
||||
@@ -144,7 +145,7 @@ def _iter_pytest_modules(module_context, skip_own_module=False):
|
||||
|
||||
class FixtureFilter(ParserTreeFilter):
|
||||
def _filter(self, names):
|
||||
for name in super(FixtureFilter, self)._filter(names):
|
||||
for name in super()._filter(names):
|
||||
funcdef = name.parent
|
||||
if funcdef.type == 'funcdef':
|
||||
# Class fixtures are not supported
|
||||
|
||||
@@ -11,8 +11,8 @@ compiled module that returns the types for C-builtins.
|
||||
"""
|
||||
import parso
|
||||
import os
|
||||
from inspect import Parameter
|
||||
|
||||
from jedi._compatibility import force_unicode, Parameter
|
||||
from jedi import debug
|
||||
from jedi.inference.utils import safe_property
|
||||
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)
|
||||
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.
|
||||
# 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], /')
|
||||
@@ -208,7 +203,7 @@ def builtins_getattr(objects, names, defaults=None):
|
||||
debug.warning('getattr called without str')
|
||||
continue
|
||||
else:
|
||||
return value.py__getattribute__(force_unicode(string))
|
||||
return value.py__getattribute__(string)
|
||||
return NO_VALUES
|
||||
|
||||
|
||||
@@ -259,14 +254,13 @@ def builtins_super(types, objects, context):
|
||||
|
||||
class ReversedObject(AttributeOverwrite):
|
||||
def __init__(self, reversed_obj, iter_list):
|
||||
super(ReversedObject, self).__init__(reversed_obj)
|
||||
super().__init__(reversed_obj)
|
||||
self._iter_list = iter_list
|
||||
|
||||
def py__iter__(self, contextualized_node):
|
||||
return self._iter_list
|
||||
|
||||
@publish_method('next', python_version_match=2)
|
||||
@publish_method('__next__', python_version_match=3)
|
||||
@publish_method('__next__')
|
||||
def _next(self, arguments):
|
||||
return ValueSet.from_sets(
|
||||
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)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
@@ -346,7 +340,7 @@ def builtins_staticmethod(functions):
|
||||
|
||||
class ClassMethodObject(ValueWrapper):
|
||||
def __init__(self, class_method_obj, function):
|
||||
super(ClassMethodObject, self).__init__(class_method_obj)
|
||||
super().__init__(class_method_obj)
|
||||
self._function = function
|
||||
|
||||
def py__get__(self, instance, class_value):
|
||||
@@ -358,7 +352,7 @@ class ClassMethodObject(ValueWrapper):
|
||||
|
||||
class ClassMethodGet(ValueWrapper):
|
||||
def __init__(self, get_method, klass, function):
|
||||
super(ClassMethodGet, self).__init__(get_method)
|
||||
super().__init__(get_method)
|
||||
self._class = klass
|
||||
self._function = function
|
||||
|
||||
@@ -371,7 +365,7 @@ class ClassMethodGet(ValueWrapper):
|
||||
|
||||
class ClassMethodArguments(TreeArgumentsWrapper):
|
||||
def __init__(self, klass, arguments):
|
||||
super(ClassMethodArguments, self).__init__(arguments)
|
||||
super().__init__(arguments)
|
||||
self._class = klass
|
||||
|
||||
def unpack(self, func=None):
|
||||
@@ -391,7 +385,7 @@ def builtins_classmethod(functions, value, arguments):
|
||||
|
||||
class PropertyObject(AttributeOverwrite, ValueWrapper):
|
||||
def __init__(self, property_obj, function):
|
||||
super(PropertyObject, self).__init__(property_obj)
|
||||
super().__init__(property_obj)
|
||||
self._function = function
|
||||
|
||||
def py__get__(self, instance, class_value):
|
||||
@@ -426,11 +420,11 @@ def collections_namedtuple(value, arguments, callback):
|
||||
inference_state = value.inference_state
|
||||
|
||||
# Process arguments
|
||||
name = u'jedi_unknown_namedtuple'
|
||||
name = 'jedi_unknown_namedtuple'
|
||||
for c in _follow_param(inference_state, arguments, 0):
|
||||
x = get_str_or_none(c)
|
||||
if x is not None:
|
||||
name = force_unicode(x)
|
||||
name = x
|
||||
break
|
||||
|
||||
# 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]
|
||||
string = get_str_or_none(_fields)
|
||||
if string is not None:
|
||||
fields = force_unicode(string).replace(',', ' ').split()
|
||||
fields = string.replace(',', ' ').split()
|
||||
elif isinstance(_fields, iterable.Sequence):
|
||||
fields = [
|
||||
force_unicode(get_str_or_none(v))
|
||||
get_str_or_none(v)
|
||||
for lazy_value in _fields.py__iter__()
|
||||
for v in lazy_value.infer()
|
||||
]
|
||||
@@ -456,7 +450,7 @@ def collections_namedtuple(value, arguments, callback):
|
||||
typename=name,
|
||||
field_names=tuple(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='',
|
||||
field_defs='\n'.join(_NAMEDTUPLE_FIELD_TEMPLATE.format(index=index, name=name)
|
||||
for index, name in enumerate(fields))
|
||||
@@ -475,7 +469,7 @@ def collections_namedtuple(value, arguments, callback):
|
||||
|
||||
class PartialObject(ValueWrapper):
|
||||
def __init__(self, actual_value, arguments, instance=None):
|
||||
super(PartialObject, self).__init__(actual_value)
|
||||
super().__init__(actual_value)
|
||||
self._arguments = arguments
|
||||
self._instance = instance
|
||||
|
||||
@@ -538,7 +532,7 @@ class PartialMethodObject(PartialObject):
|
||||
|
||||
class PartialSignature(SignatureWrapper):
|
||||
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_set = skipped_arg_set
|
||||
|
||||
@@ -631,7 +625,7 @@ class DataclassWrapper(ValueWrapper, ClassMixin):
|
||||
|
||||
class DataclassSignature(AbstractSignature):
|
||||
def __init__(self, value, param_names):
|
||||
super(DataclassSignature, self).__init__(value)
|
||||
super().__init__(value)
|
||||
self._param_names = param_names
|
||||
|
||||
def get_param_names(self, resolve_stars=False):
|
||||
@@ -640,7 +634,7 @@ class DataclassSignature(AbstractSignature):
|
||||
|
||||
class DataclassParamName(BaseTreeParamName):
|
||||
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.default_node = default_node
|
||||
|
||||
@@ -656,7 +650,7 @@ class DataclassParamName(BaseTreeParamName):
|
||||
|
||||
class ItemGetterCallable(ValueWrapper):
|
||||
def __init__(self, instance, args_value_set):
|
||||
super(ItemGetterCallable, self).__init__(instance)
|
||||
super().__init__(instance)
|
||||
self._args_value_set = args_value_set
|
||||
|
||||
@repack_with_argument_clinic('item, /')
|
||||
@@ -694,7 +688,7 @@ class WrapsCallable(ValueWrapper):
|
||||
|
||||
class Wrapped(ValueWrapper, FunctionMixin):
|
||||
def __init__(self, func, original_function):
|
||||
super(Wrapped, self).__init__(func)
|
||||
super().__init__(func)
|
||||
self._original_function = original_function
|
||||
|
||||
@property
|
||||
@@ -732,7 +726,7 @@ def _create_string_input_function(func):
|
||||
@argument_clinic('*args, /', want_callback=True)
|
||||
def _os_path_join(args_set, callback):
|
||||
if len(args_set) == 1:
|
||||
string = u''
|
||||
string = ''
|
||||
sequence, = args_set
|
||||
is_first = True
|
||||
for lazy_value in sequence.py__iter__():
|
||||
@@ -744,7 +738,7 @@ def _os_path_join(args_set, callback):
|
||||
break
|
||||
if not is_first:
|
||||
string += os.path.sep
|
||||
string += force_unicode(s)
|
||||
string += s
|
||||
is_first = False
|
||||
else:
|
||||
return ValueSet([compiled.create_simple_object(sequence.inference_state, string)])
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
Utilities for end-users.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import __main__
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
@@ -18,7 +18,6 @@ from docopt import docopt
|
||||
from jedi.parser.python import load_grammar
|
||||
from jedi.parser.diff import DiffParser
|
||||
from jedi.parser.python import ParserWithRecovery
|
||||
from jedi._compatibility import u
|
||||
from jedi.common import splitlines
|
||||
import jedi
|
||||
|
||||
@@ -37,14 +36,15 @@ def main(args):
|
||||
with open(args['<file>']) as f:
|
||||
code = f.read()
|
||||
grammar = load_grammar()
|
||||
parser = ParserWithRecovery(grammar, u(code))
|
||||
parser = ParserWithRecovery(grammar, code)
|
||||
# Make sure used_names is loaded
|
||||
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)
|
||||
cProfile.runctx('run(parser, lines)', globals(), locals(), sort=args['-s'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = docopt(__doc__)
|
||||
main(args)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python3.6
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Profile a piece of Python code with ``profile``. Tries a completion on a
|
||||
certain piece of code.
|
||||
@@ -19,11 +18,7 @@ Options:
|
||||
"""
|
||||
|
||||
import time
|
||||
try:
|
||||
# For Python 2
|
||||
import cProfile as profile
|
||||
except ImportError:
|
||||
import profile
|
||||
import profile
|
||||
import pstats
|
||||
|
||||
from docopt import docopt
|
||||
|
||||
8
setup.py
8
setup.py
@@ -33,12 +33,11 @@ setup(name='jedi',
|
||||
keywords='python completion refactoring vim',
|
||||
long_description=readme,
|
||||
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,
|
||||
extras_require={
|
||||
'testing': [
|
||||
# Pytest 5 doesn't support Python 2 anymore.
|
||||
'pytest>=3.9.0,<5.0.0',
|
||||
'pytest<6.0.0',
|
||||
# docopt for sith doctests
|
||||
'docopt',
|
||||
# coloroma for colored debug output
|
||||
@@ -58,10 +57,7 @@ setup(name='jedi',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
|
||||
1
sith.py
1
sith.py
@@ -44,7 +44,6 @@ Options:
|
||||
--pudb Launch pudb when error is raised.
|
||||
"""
|
||||
|
||||
from __future__ import print_function, division, unicode_literals
|
||||
from docopt import docopt
|
||||
|
||||
import json
|
||||
|
||||
@@ -272,9 +272,6 @@ dic = {str(key): ''}
|
||||
#? str()
|
||||
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}:
|
||||
#? int() str()
|
||||
@@ -473,7 +470,6 @@ def test_func():
|
||||
#? int()
|
||||
tuple({1})[0]
|
||||
|
||||
# python > 2.7
|
||||
# -----------------
|
||||
# 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.
|
||||
"""
|
||||
|
||||
# python >= 3.5
|
||||
|
||||
async def x():
|
||||
return 1
|
||||
|
||||
|
||||
@@ -291,14 +291,6 @@ except ImportError as i_a:
|
||||
i_a
|
||||
#? ImportError()
|
||||
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):
|
||||
@@ -344,8 +336,6 @@ def foo(my_t=some_defa
|
||||
#? ['some_default']
|
||||
def foo(my_t=some_defa, my_t2=some_defa
|
||||
|
||||
# python > 2.7
|
||||
|
||||
#? ['my_type']
|
||||
def foo(my_t: lala=some_defa, my_t2: my_typ
|
||||
#? ['my_type']
|
||||
|
||||
@@ -382,7 +382,6 @@ getattr(getattr, 1)
|
||||
getattr(str, [])
|
||||
|
||||
|
||||
# python >= 3.5
|
||||
class Base():
|
||||
def ret(self, b):
|
||||
return b
|
||||
|
||||
@@ -174,8 +174,6 @@ class X():
|
||||
#? int()
|
||||
X([1]).foo()
|
||||
|
||||
# set/dict comprehensions were introduced in 2.7, therefore:
|
||||
# python >= 2.7
|
||||
# -----------------
|
||||
# dict comprehensions
|
||||
# -----------------
|
||||
|
||||
@@ -388,7 +388,6 @@ k = 'a'
|
||||
#? int()
|
||||
some_dct[k]
|
||||
|
||||
# python > 3.5
|
||||
some_other_dct = dict(some_dct, c=set)
|
||||
#? int()
|
||||
some_other_dct['a']
|
||||
|
||||
@@ -242,8 +242,6 @@ def x():
|
||||
# yield from
|
||||
# -----------------
|
||||
|
||||
# python > 2.7
|
||||
|
||||
def yield_from():
|
||||
yield from iter([1])
|
||||
|
||||
|
||||
@@ -97,7 +97,6 @@ def x(): pass
|
||||
# -----------------
|
||||
# Only keyword arguments are valid
|
||||
# -----------------
|
||||
# python >= 3.5
|
||||
|
||||
def x(bam, *, bar, baz):
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
""" Pep-0484 type hinting """
|
||||
|
||||
# python > 2.7
|
||||
|
||||
|
||||
class A():
|
||||
pass
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# python >= 3.4
|
||||
import typing
|
||||
from typing import (
|
||||
Callable,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# python >= 3.4
|
||||
from typing import (
|
||||
Callable,
|
||||
Dict,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# python >= 3.4
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"""
|
||||
Test the typing library, with docstrings. This is needed since annotations
|
||||
are not supported in python 2.7 else then annotating by comment (and this is
|
||||
still TODO at 2016-01-23)
|
||||
Test the typing library, with docstrings and annotations
|
||||
"""
|
||||
import typing
|
||||
class B:
|
||||
@@ -295,8 +293,6 @@ y = type(PlainInt)
|
||||
#? type.mro
|
||||
y.mro
|
||||
|
||||
# python > 2.7
|
||||
|
||||
class TestDefaultDict(typing.DefaultDict[str, int]):
|
||||
def setdud(self):
|
||||
pass
|
||||
@@ -323,7 +319,6 @@ for key in x.keys():
|
||||
for value in x.values():
|
||||
#? int()
|
||||
value
|
||||
# python > 2.7
|
||||
|
||||
|
||||
"""
|
||||
|
||||
@@ -178,8 +178,6 @@ from datetime import datetime, timedelta
|
||||
# magic methods
|
||||
# -----------------
|
||||
|
||||
# python >= 3.5
|
||||
|
||||
class C:
|
||||
def __sub__(self, other) -> int: ...
|
||||
def __radd__(self, other) -> float: ...
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# python > 2.7
|
||||
import pytest
|
||||
from pytest import fixture
|
||||
|
||||
@@ -130,8 +129,6 @@ def test_p(monkeypatch):
|
||||
#? ['setattr']
|
||||
monkeypatch.setatt
|
||||
|
||||
# python > 2.7
|
||||
|
||||
#? ['capsysbinary']
|
||||
def test_p(capsysbin
|
||||
|
||||
|
||||
@@ -133,48 +133,6 @@ weakref.ref(1)
|
||||
#? int() None
|
||||
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)
|
||||
# -----------------
|
||||
@@ -253,7 +211,7 @@ z.read('name').upper
|
||||
# -----------------
|
||||
# contextlib
|
||||
# -----------------
|
||||
# python > 2.7
|
||||
|
||||
from typing import Iterator
|
||||
import contextlib
|
||||
with contextlib.closing('asd') as string:
|
||||
@@ -384,7 +342,6 @@ class Test(metaclass=Meta):
|
||||
# Enum
|
||||
# -----------------
|
||||
|
||||
# python > 2.7
|
||||
import enum
|
||||
|
||||
class X(enum.Enum):
|
||||
@@ -409,8 +366,47 @@ X().name
|
||||
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:
|
||||
def function(self, a, b):
|
||||
return a, b
|
||||
@@ -463,11 +459,6 @@ X().just_partial('')[0]
|
||||
#? str()
|
||||
X().just_partial('')[1]
|
||||
|
||||
|
||||
# -----------------
|
||||
# functools Python 3.8
|
||||
# -----------------
|
||||
|
||||
# python >= 3.8
|
||||
|
||||
@functools.lru_cache
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# python > 2.7
|
||||
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']
|
||||
from stub_folder.
|
||||
|
||||
|
||||
# -------------------------
|
||||
# Folders
|
||||
# -------------------------
|
||||
|
||||
@@ -135,7 +135,6 @@ set_t2.c
|
||||
# -----------------
|
||||
# pep 448 unpacking generalizations
|
||||
# -----------------
|
||||
# python >= 3.5
|
||||
|
||||
d = {'a': 3}
|
||||
dc = {v: 3 for v in ['a']}
|
||||
|
||||
@@ -354,7 +354,6 @@ class DefinitelyNotGlobal:
|
||||
# stubs
|
||||
# -----------------
|
||||
|
||||
# python > 2.7
|
||||
from stub_folder import with_stub
|
||||
#< ('stub:stub_folder.with_stub', 5, 4), ('stub_folder.with_stub', 5, 4), (0, 10)
|
||||
with_stub.stub_function
|
||||
|
||||
@@ -102,9 +102,7 @@ def collect_static_analysis_tests(base_dir, test_files):
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def venv_path(tmpdir_factory, environment):
|
||||
if environment.version_info.major < 3:
|
||||
pytest.skip("python -m venv does not exist in Python 2")
|
||||
elif isinstance(environment, InterpreterEnvironment):
|
||||
if isinstance(environment, InterpreterEnvironment):
|
||||
# The environment can be a tox virtualenv environment which we don't
|
||||
# want, so use the 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
|
||||
@@ -3,25 +3,18 @@ A helper module for testing, improves compatibility for testing (as
|
||||
``jedi._compatibility``) as well as introducing helper functions.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
|
||||
if sys.hexversion < 0x02070000:
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
import unittest
|
||||
TestCase = unittest.TestCase
|
||||
|
||||
import os
|
||||
import pytest
|
||||
from os.path import abspath, dirname, join
|
||||
from functools import partial, wraps
|
||||
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)
|
||||
root_dir = dirname(test_dir)
|
||||
example_dir = join(test_dir, 'examples')
|
||||
root_dir = test_dir.parent
|
||||
example_dir = test_dir.joinpath('examples')
|
||||
|
||||
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):
|
||||
return join(example_dir, *names)
|
||||
return example_dir.joinpath(*names)
|
||||
|
||||
|
||||
def cwd_at(path):
|
||||
@@ -53,10 +46,10 @@ def cwd_at(path):
|
||||
|
||||
@contextmanager
|
||||
def set_cwd(path, absolute_path=False):
|
||||
repo_root = os.path.dirname(test_dir)
|
||||
repo_root = test_dir.parent
|
||||
|
||||
oldcwd = os.getcwd()
|
||||
os.chdir(os.path.join(repo_root, path))
|
||||
oldcwd = Path.cwd()
|
||||
os.chdir(repo_root.joinpath(path))
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user