forked from VimPlug/jedi
Merge pull request #2095 from davidhalter/typing
Use Zuban instead of Mypy for subsecond type checking and editor integration
This commit is contained in:
@@ -7,8 +7,8 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-24.04, windows-2022]
|
os: [ubuntu-24.04, windows-2022]
|
||||||
python-version: ["3.13", "3.12", "3.11", "3.10", "3.9", "3.8"]
|
python-version: ["3.13", "3.12", "3.11", "3.10"]
|
||||||
environment: ['3.8', '3.13', '3.12', '3.11', '3.10', '3.9', 'interpreter']
|
environment: ['3.13', '3.12', '3.11', '3.10', 'interpreter']
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
allow-prereleases: true
|
allow-prereleases: true
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: 'pip install .[testing]'
|
run: 'pip install .[dev]'
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: python -m pytest
|
run: python -m pytest
|
||||||
@@ -43,12 +43,12 @@ jobs:
|
|||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: 'pip install .[qa]'
|
run: 'pip install .[dev]'
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
python -m flake8 jedi test setup.py
|
python -m flake8 jedi test setup.py
|
||||||
python -m mypy jedi sith.py setup.py
|
zuban check
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: 'pip install .[testing] coverage'
|
run: 'pip install .[dev] coverage'
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+2
-2
@@ -14,8 +14,8 @@ sphinx:
|
|||||||
configuration: docs/conf.py
|
configuration: docs/conf.py
|
||||||
|
|
||||||
build:
|
build:
|
||||||
os: ubuntu-22.04
|
os: ubuntu-24.04
|
||||||
tools:
|
tools:
|
||||||
python: "3.11"
|
python: "3.14"
|
||||||
apt_packages:
|
apt_packages:
|
||||||
- graphviz
|
- graphviz
|
||||||
|
|||||||
+3
-3
@@ -102,7 +102,7 @@ Features and Limitations
|
|||||||
Jedi's features are listed here:
|
Jedi's features are listed here:
|
||||||
`Features <https://jedi.readthedocs.org/en/latest/docs/features.html>`_.
|
`Features <https://jedi.readthedocs.org/en/latest/docs/features.html>`_.
|
||||||
|
|
||||||
You can run Jedi on Python 3.8+ but it should also
|
You can run Jedi on Python 3.10+ but it should also
|
||||||
understand code that is older than those versions. Additionally you should be
|
understand code that is older than those versions. Additionally you should be
|
||||||
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
|
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
|
||||||
very well.
|
very well.
|
||||||
@@ -183,10 +183,10 @@ The test suite uses ``pytest``::
|
|||||||
|
|
||||||
pip install pytest
|
pip install pytest
|
||||||
|
|
||||||
If you want to test only a specific Python version (e.g. Python 3.8), it is as
|
If you want to test only a specific Python version (e.g. Python 3.14), it is as
|
||||||
easy as::
|
easy as::
|
||||||
|
|
||||||
python3.8 -m pytest
|
python3.14 -m pytest
|
||||||
|
|
||||||
For more detailed information visit the `testing documentation
|
For more detailed information visit the `testing documentation
|
||||||
<https://jedi.readthedocs.org/en/latest/docs/testing.html>`_.
|
<https://jedi.readthedocs.org/en/latest/docs/testing.html>`_.
|
||||||
|
|||||||
+7
-21
@@ -42,7 +42,7 @@ def pytest_addoption(parser):
|
|||||||
help="Warnings are treated as errors.")
|
help="Warnings are treated as errors.")
|
||||||
|
|
||||||
parser.addoption("--env", action='store',
|
parser.addoption("--env", action='store',
|
||||||
help="Execute the tests in that environment (e.g. 39 for python3.9).")
|
help="Execute the tests in that environment (e.g. 314 for python3.14).")
|
||||||
parser.addoption("--interpreter-env", "-I", action='store_true',
|
parser.addoption("--interpreter-env", "-I", action='store_true',
|
||||||
help="Don't use subprocesses to guarantee having safe "
|
help="Don't use subprocesses to guarantee having safe "
|
||||||
"code execution. Useful for debugging.")
|
"code execution. Useful for debugging.")
|
||||||
@@ -133,11 +133,13 @@ def goto_or_help(request, Script):
|
|||||||
|
|
||||||
@pytest.fixture(scope='session', params=['goto', 'help', 'infer'])
|
@pytest.fixture(scope='session', params=['goto', 'help', 'infer'])
|
||||||
def goto_or_help_or_infer(request, Script):
|
def goto_or_help_or_infer(request, Script):
|
||||||
def do(code, *args, **kwargs):
|
class GotoOrHelpOrInfer:
|
||||||
return getattr(Script(code), request.param)(*args, **kwargs)
|
def __call__(self, code, *args, **kwargs):
|
||||||
|
return getattr(Script(code), request.param)(*args, **kwargs)
|
||||||
|
|
||||||
do.type = request.param
|
type = request.param
|
||||||
return do
|
|
||||||
|
return GotoOrHelpOrInfer()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session', params=['goto', 'complete', 'help'])
|
@pytest.fixture(scope='session', params=['goto', 'complete', 'help'])
|
||||||
@@ -162,19 +164,3 @@ def skip_pre_python311(environment):
|
|||||||
# This if is just needed to avoid that tests ever skip way more than
|
# This if is just needed to avoid that tests ever skip way more than
|
||||||
# they should for all Python versions.
|
# they should for all Python versions.
|
||||||
pytest.skip()
|
pytest.skip()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def skip_pre_python38(environment):
|
|
||||||
if environment.version_info < (3, 8):
|
|
||||||
# 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_python37(environment):
|
|
||||||
if environment.version_info < (3, 7):
|
|
||||||
# This if is just needed to avoid that tests ever skip way more than
|
|
||||||
# they should for all Python versions.
|
|
||||||
pytest.skip()
|
|
||||||
|
|||||||
+1
-1
@@ -107,7 +107,7 @@ Completions
|
|||||||
>>> code = '''import json; json.l'''
|
>>> code = '''import json; json.l'''
|
||||||
>>> script = jedi.Script(code, path='example.py')
|
>>> script = jedi.Script(code, path='example.py')
|
||||||
>>> script
|
>>> script
|
||||||
<Script: 'example.py' <SameEnvironment: 3.9.0 in /usr>>
|
<Script: 'example.py' <SameEnvironment: 3.14.0 in /usr>>
|
||||||
>>> completions = script.complete(1, 19)
|
>>> completions = script.complete(1, 19)
|
||||||
>>> completions
|
>>> completions
|
||||||
[<Completion: load>, <Completion: loads>]
|
[<Completion: load>, <Completion: loads>]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Jedi's main API calls and features are:
|
|||||||
Basic Features
|
Basic Features
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
- Python 3.8+ support
|
- Python 3.10+ support
|
||||||
- Ignores syntax errors and wrong indentation
|
- Ignores syntax errors and wrong indentation
|
||||||
- Can deal with complex module / function / class structures
|
- Can deal with complex module / function / class structures
|
||||||
- Great ``virtualenv``/``venv`` support
|
- Great ``virtualenv``/``venv`` support
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ The test suite depends on ``pytest``::
|
|||||||
|
|
||||||
pip install pytest
|
pip install pytest
|
||||||
|
|
||||||
If you want to test only a specific Python version (e.g. Python 3.8), it is as
|
If you want to test only a specific Python version (e.g. Python 3.14), it is as
|
||||||
easy as::
|
easy as::
|
||||||
|
|
||||||
python3.8 -m pytest
|
python3.14 -m pytest
|
||||||
|
|
||||||
Tests are also run automatically on `GitHub Actions
|
Tests are also run automatically on `GitHub Actions
|
||||||
<https://github.com/davidhalter/jedi/actions>`_.
|
<https://github.com/davidhalter/jedi/actions>`_.
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ Below you can also find a list of :ref:`recipes for type hinting <recipes>`.
|
|||||||
.. _language-servers:
|
.. _language-servers:
|
||||||
|
|
||||||
Language Servers
|
Language Servers
|
||||||
--------------
|
----------------
|
||||||
|
|
||||||
- `jedi-language-server <https://github.com/pappasam/jedi-language-server>`_
|
- `jedi-language-server <https://github.com/pappasam/jedi-language-server>`_
|
||||||
- `python-language-server <https://github.com/palantir/python-language-server>`_ (currently unmaintained)
|
- `python-language-server <https://github.com/palantir/python-language-server>`_ (currently unmaintained)
|
||||||
|
|||||||
+1
-1
@@ -96,7 +96,7 @@ class BaseName:
|
|||||||
@property
|
@property
|
||||||
def module_path(self) -> Optional[Path]:
|
def module_path(self) -> Optional[Path]:
|
||||||
"""
|
"""
|
||||||
Shows the file path of a module. e.g. ``/usr/lib/python3.9/os.py``
|
Shows the file path of a module. e.g. ``/usr/lib/python3.14/os.py``
|
||||||
"""
|
"""
|
||||||
module = self._get_module_context()
|
module = self._get_module_context()
|
||||||
if module.is_stub() or not module.is_compiled():
|
if module.is_stub() or not module.is_compiled():
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
from typing import Any
|
||||||
from inspect import Parameter
|
from inspect import Parameter
|
||||||
|
|
||||||
from parso.python.token import PythonTokenTypes
|
from parso.python.token import PythonTokenTypes
|
||||||
@@ -265,7 +266,7 @@ class Completion:
|
|||||||
elif type_ == 'for_stmt':
|
elif type_ == 'for_stmt':
|
||||||
allowed_transitions.append('else')
|
allowed_transitions.append('else')
|
||||||
|
|
||||||
completion_names = []
|
completion_names: list[Any] = []
|
||||||
|
|
||||||
kwargs_only = False
|
kwargs_only = False
|
||||||
if any(t in allowed_transitions for t in (PythonTokenTypes.NAME,
|
if any(t in allowed_transitions for t in (PythonTokenTypes.NAME,
|
||||||
|
|||||||
+29
-25
@@ -8,7 +8,7 @@ import hashlib
|
|||||||
import filecmp
|
import filecmp
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from shutil import which
|
from shutil import which
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from jedi.cache import memoize_method, time_cache
|
from jedi.cache import memoize_method, time_cache
|
||||||
from jedi.inference.compiled.subprocess import CompiledSubprocess, \
|
from jedi.inference.compiled.subprocess import CompiledSubprocess, \
|
||||||
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
_VersionInfo = namedtuple('VersionInfo', 'major minor micro') # type: ignore[name-match]
|
_VersionInfo = namedtuple('VersionInfo', 'major minor micro') # type: ignore[name-match]
|
||||||
|
|
||||||
_SUPPORTED_PYTHONS = ['3.13', '3.12', '3.11', '3.10', '3.9', '3.8']
|
_SUPPORTED_PYTHONS = ['3.13', '3.12', '3.11', '3.10']
|
||||||
_SAFE_PATHS = ['/usr/bin', '/usr/local/bin']
|
_SAFE_PATHS = ['/usr/bin', '/usr/local/bin']
|
||||||
_CONDA_VAR = 'CONDA_PREFIX'
|
_CONDA_VAR = 'CONDA_PREFIX'
|
||||||
_CURRENT_VERSION = '%s.%s' % (sys.version_info.major, sys.version_info.minor)
|
_CURRENT_VERSION = '%s.%s' % (sys.version_info.major, sys.version_info.minor)
|
||||||
@@ -36,6 +36,9 @@ class InvalidPythonEnvironment(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class _BaseEnvironment:
|
class _BaseEnvironment:
|
||||||
|
version_info: Any
|
||||||
|
executable: Any
|
||||||
|
|
||||||
@memoize_method
|
@memoize_method
|
||||||
def get_grammar(self):
|
def get_grammar(self):
|
||||||
version_string = '%s.%s' % (self.version_info.major, self.version_info.minor)
|
version_string = '%s.%s' % (self.version_info.major, self.version_info.minor)
|
||||||
@@ -251,7 +254,7 @@ def get_cached_default_environment():
|
|||||||
# /path/to/env so we need to fully resolve the paths in order to
|
# /path/to/env so we need to fully resolve the paths in order to
|
||||||
# compare them.
|
# compare them.
|
||||||
if var and os.path.realpath(var) != os.path.realpath(environment.path):
|
if var and os.path.realpath(var) != os.path.realpath(environment.path):
|
||||||
_get_cached_default_environment.clear_cache()
|
_get_cached_default_environment.clear_cache() # type: ignore[attr-defined]
|
||||||
return _get_cached_default_environment()
|
return _get_cached_default_environment()
|
||||||
return environment
|
return environment
|
||||||
|
|
||||||
@@ -355,7 +358,7 @@ def get_system_environment(version, *, env_vars=None):
|
|||||||
return SameEnvironment()
|
return SameEnvironment()
|
||||||
return Environment(exe)
|
return Environment(exe)
|
||||||
|
|
||||||
if os.name == 'nt':
|
if sys.platform == "win32":
|
||||||
for exe in _get_executables_from_windows_registry(version):
|
for exe in _get_executables_from_windows_registry(version):
|
||||||
try:
|
try:
|
||||||
return Environment(exe, env_vars=env_vars)
|
return Environment(exe, env_vars=env_vars)
|
||||||
@@ -383,7 +386,7 @@ def _get_executable_path(path, safe=True):
|
|||||||
Returns None if it's not actually a virtual env.
|
Returns None if it's not actually a virtual env.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if os.name == 'nt':
|
if sys.platform == "win32":
|
||||||
pythons = [os.path.join(path, 'Scripts', 'python.exe'), os.path.join(path, 'python.exe')]
|
pythons = [os.path.join(path, 'Scripts', 'python.exe'), os.path.join(path, 'python.exe')]
|
||||||
else:
|
else:
|
||||||
pythons = [os.path.join(path, 'bin', 'python')]
|
pythons = [os.path.join(path, 'bin', 'python')]
|
||||||
@@ -397,27 +400,28 @@ def _get_executable_path(path, safe=True):
|
|||||||
return python
|
return python
|
||||||
|
|
||||||
|
|
||||||
def _get_executables_from_windows_registry(version):
|
if sys.platform == "win32":
|
||||||
import winreg
|
def _get_executables_from_windows_registry(version):
|
||||||
|
import winreg
|
||||||
|
|
||||||
# TODO: support Python Anaconda.
|
# TODO: support Python Anaconda.
|
||||||
sub_keys = [
|
sub_keys = [
|
||||||
r'SOFTWARE\Python\PythonCore\{version}\InstallPath',
|
r'SOFTWARE\Python\PythonCore\{version}\InstallPath',
|
||||||
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath',
|
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath',
|
||||||
r'SOFTWARE\Python\PythonCore\{version}-32\InstallPath',
|
r'SOFTWARE\Python\PythonCore\{version}-32\InstallPath',
|
||||||
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}-32\InstallPath'
|
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}-32\InstallPath'
|
||||||
]
|
]
|
||||||
for root_key in [winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE]:
|
for root_key in [winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE]:
|
||||||
for sub_key in sub_keys:
|
for sub_key in sub_keys:
|
||||||
sub_key = sub_key.format(version=version)
|
sub_key = sub_key.format(version=version)
|
||||||
try:
|
try:
|
||||||
with winreg.OpenKey(root_key, sub_key) as key:
|
with winreg.OpenKey(root_key, sub_key) as key:
|
||||||
prefix = winreg.QueryValueEx(key, '')[0]
|
prefix = winreg.QueryValueEx(key, '')[0]
|
||||||
exe = os.path.join(prefix, 'python.exe')
|
exe = os.path.join(prefix, 'python.exe')
|
||||||
if os.path.isfile(exe):
|
if os.path.isfile(exe):
|
||||||
yield exe
|
yield exe
|
||||||
except WindowsError:
|
except WindowsError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _assert_safe(executable_path, safe):
|
def _assert_safe(executable_path, safe):
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ def imitate_pydoc(string):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# is a tuple now
|
# is a tuple now
|
||||||
label, related = string
|
label, related = string # type: ignore[misc]
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ just use IPython instead::
|
|||||||
Then you will be able to use Jedi completer in your Python interpreter::
|
Then you will be able to use Jedi completer in your Python interpreter::
|
||||||
|
|
||||||
$ python
|
$ python
|
||||||
Python 3.9.2+ (default, Jul 20 2020, 22:15:08)
|
Python 3.14.0+ (default, Jul 20 2020, 22:15:08)
|
||||||
[GCC 4.6.1] on linux2
|
[GCC 4.6.1] on linux2
|
||||||
Type "help", "copyright", "credits" or "license" for more information.
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
>>> import os
|
>>> import os
|
||||||
|
|||||||
+1
-1
@@ -93,7 +93,7 @@ def time_cache(seconds):
|
|||||||
cache[key] = time.time(), result
|
cache[key] = time.time(), result
|
||||||
return result
|
return result
|
||||||
|
|
||||||
wrapper.clear_cache = lambda: cache.clear()
|
wrapper.clear_cache = lambda: cache.clear() # type: ignore[attr-defined]
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ try:
|
|||||||
# pytest resets the stream at the end - causes troubles. Since
|
# pytest resets the stream at the end - causes troubles. Since
|
||||||
# after every output the stream is reset automatically we don't
|
# after every output the stream is reset automatically we don't
|
||||||
# need this.
|
# need this.
|
||||||
initialise.atexit_done = True
|
initialise.atexit_done = True # type: ignore[attr-defined]
|
||||||
try:
|
try:
|
||||||
init(strip=False)
|
init(strip=False)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from parso import file_io
|
from parso import file_io
|
||||||
|
|
||||||
@@ -58,6 +59,8 @@ class FolderIO(AbstractFolderIO):
|
|||||||
|
|
||||||
|
|
||||||
class FileIOFolderMixin:
|
class FileIOFolderMixin:
|
||||||
|
path: Any
|
||||||
|
|
||||||
def get_parent_folder(self):
|
def get_parent_folder(self):
|
||||||
return FolderIO(os.path.dirname(self.path))
|
return FolderIO(os.path.dirname(self.path))
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ I need to mention now that lazy type inference is really good because it
|
|||||||
only *inferes* what needs to be *inferred*. All the statements and modules
|
only *inferes* what needs to be *inferred*. All the statements and modules
|
||||||
that are not used are just being ignored.
|
that are not used are just being ignored.
|
||||||
"""
|
"""
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import parso
|
import parso
|
||||||
from jedi.file_io import FileIO
|
from jedi.file_io import FileIO
|
||||||
|
|
||||||
@@ -82,6 +84,8 @@ from jedi.plugins import plugin_manager
|
|||||||
|
|
||||||
|
|
||||||
class InferenceState:
|
class InferenceState:
|
||||||
|
analysis_modules: "list[Any]"
|
||||||
|
|
||||||
def __init__(self, project, environment=None, script_path=None):
|
def __init__(self, project, environment=None, script_path=None):
|
||||||
if environment is None:
|
if environment is None:
|
||||||
environment = project.get_environment()
|
environment = project.get_environment()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ class _AbstractArgumentsMixin:
|
|||||||
|
|
||||||
class AbstractArguments(_AbstractArgumentsMixin):
|
class AbstractArguments(_AbstractArgumentsMixin):
|
||||||
context = None
|
context = None
|
||||||
argument_node = None
|
argument_node: Any = None
|
||||||
trailer = None
|
trailer = None
|
||||||
|
|
||||||
|
|
||||||
@@ -164,6 +165,8 @@ def unpack_arglist(arglist):
|
|||||||
|
|
||||||
|
|
||||||
class TreeArguments(AbstractArguments):
|
class TreeArguments(AbstractArguments):
|
||||||
|
context: Any
|
||||||
|
|
||||||
def __init__(self, inference_state, context, argument_node, trailer=None):
|
def __init__(self, inference_state, context, argument_node, trailer=None):
|
||||||
"""
|
"""
|
||||||
:param argument_node: May be an argument_node or a list of nodes.
|
:param argument_node: May be an argument_node or a list of nodes.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ just one.
|
|||||||
from functools import reduce
|
from functools import reduce
|
||||||
from operator import add
|
from operator import add
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from parso.python.tree import Name
|
from parso.python.tree import Name
|
||||||
|
|
||||||
@@ -21,12 +22,25 @@ from jedi.cache import memoize_method
|
|||||||
|
|
||||||
sentinel = object()
|
sentinel = object()
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from jedi.inference import InferenceState
|
||||||
|
|
||||||
|
|
||||||
class HasNoContext(Exception):
|
class HasNoContext(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class HelperValueMixin:
|
class HelperValueMixin:
|
||||||
|
parent_context: Any
|
||||||
|
inference_state: "InferenceState"
|
||||||
|
name: Any
|
||||||
|
get_filters: Any
|
||||||
|
is_stub: Any
|
||||||
|
py__getattribute__alternatives: Any
|
||||||
|
py__iter__: Any
|
||||||
|
py__mro__: Any
|
||||||
|
_as_context: Any
|
||||||
|
|
||||||
def get_root_context(self):
|
def get_root_context(self):
|
||||||
value = self
|
value = self
|
||||||
if value.parent_context is None:
|
if value.parent_context is None:
|
||||||
@@ -337,11 +351,16 @@ class _ValueWrapperBase(HelperValueMixin):
|
|||||||
|
|
||||||
|
|
||||||
class LazyValueWrapper(_ValueWrapperBase):
|
class LazyValueWrapper(_ValueWrapperBase):
|
||||||
@safe_property
|
if TYPE_CHECKING:
|
||||||
@memoize_method
|
@property
|
||||||
def _wrapped_value(self):
|
def _wrapped_value(self) -> Any:
|
||||||
with debug.increase_indent_cm('Resolve lazy value wrapper'):
|
return
|
||||||
return self._get_wrapped_value()
|
else:
|
||||||
|
@safe_property
|
||||||
|
@memoize_method
|
||||||
|
def _wrapped_value(self):
|
||||||
|
with debug.increase_indent_cm('Resolve lazy value wrapper'):
|
||||||
|
return self._get_wrapped_value()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s>' % (self.__class__.__name__)
|
return '<%s>' % (self.__class__.__name__)
|
||||||
@@ -499,7 +518,7 @@ class ValueSet:
|
|||||||
return ValueSet.from_sets(_getitem(c, *args, **kwargs) for c in self._set)
|
return ValueSet.from_sets(_getitem(c, *args, **kwargs) for c in self._set)
|
||||||
|
|
||||||
def try_merge(self, function_name):
|
def try_merge(self, function_name):
|
||||||
value_set = self.__class__([])
|
value_set = ValueSet([])
|
||||||
for c in self._set:
|
for c in self._set:
|
||||||
try:
|
try:
|
||||||
method = getattr(c, function_name)
|
method = getattr(c, function_name)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ def _is_type(obj):
|
|||||||
|
|
||||||
|
|
||||||
def _shadowed_dict(klass):
|
def _shadowed_dict(klass):
|
||||||
dict_attr = type.__dict__["__dict__"]
|
dict_attr = type.__dict__["__dict__"] # type: ignore[index]
|
||||||
for entry in _static_getmro(klass):
|
for entry in _static_getmro(klass):
|
||||||
try:
|
try:
|
||||||
class_dict = dict_attr.__get__(entry)["__dict__"]
|
class_dict = dict_attr.__get__(entry)["__dict__"]
|
||||||
@@ -54,7 +54,7 @@ def _shadowed_dict(klass):
|
|||||||
|
|
||||||
|
|
||||||
def _static_getmro(klass):
|
def _static_getmro(klass):
|
||||||
mro = type.__dict__['__mro__'].__get__(klass)
|
mro = type.__dict__['__mro__'].__get__(klass) # type: ignore[index]
|
||||||
if not isinstance(mro, (tuple, list)):
|
if not isinstance(mro, (tuple, list)):
|
||||||
# There are unfortunately no tests for this, I was not able to
|
# There are unfortunately no tests for this, I was not able to
|
||||||
# reproduce this in pure Python. However should still solve the issue
|
# reproduce this in pure Python. However should still solve the issue
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import traceback
|
|||||||
import weakref
|
import weakref
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Dict, TYPE_CHECKING
|
from typing import Dict, TYPE_CHECKING, Any
|
||||||
|
|
||||||
from jedi._compatibility import pickle_dump, pickle_load
|
from jedi._compatibility import pickle_dump, pickle_load
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
@@ -52,7 +52,7 @@ PICKLE_PROTOCOL = 4
|
|||||||
|
|
||||||
|
|
||||||
def _GeneralizedPopen(*args, **kwargs):
|
def _GeneralizedPopen(*args, **kwargs):
|
||||||
if os.name == 'nt':
|
if sys.platform == "win32":
|
||||||
try:
|
try:
|
||||||
# Was introduced in Python 3.7.
|
# Was introduced in Python 3.7.
|
||||||
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW
|
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW
|
||||||
@@ -104,6 +104,8 @@ def _cleanup_process(process, thread):
|
|||||||
|
|
||||||
|
|
||||||
class _InferenceStateProcess:
|
class _InferenceStateProcess:
|
||||||
|
get_compiled_method_return: Any
|
||||||
|
|
||||||
def __init__(self, inference_state: 'InferenceState') -> None:
|
def __init__(self, inference_state: 'InferenceState') -> None:
|
||||||
self._inference_state_weakref = weakref.ref(inference_state)
|
self._inference_state_weakref = weakref.ref(inference_state)
|
||||||
self._handles: Dict[int, AccessHandle] = {}
|
self._handles: Dict[int, AccessHandle] = {}
|
||||||
|
|||||||
@@ -158,7 +158,10 @@ def _find_module(string, path=None, full_name=None, is_global_search=True):
|
|||||||
if loader is None and not spec.has_location:
|
if loader is None and not spec.has_location:
|
||||||
# This is a namespace package.
|
# This is a namespace package.
|
||||||
full_name = string if not path else full_name
|
full_name = string if not path else full_name
|
||||||
implicit_ns_info = ImplicitNSInfo(full_name, spec.submodule_search_locations._path)
|
implicit_ns_info = ImplicitNSInfo(
|
||||||
|
full_name,
|
||||||
|
spec.submodule_search_locations._path, # type: ignore[union-attr]
|
||||||
|
)
|
||||||
return implicit_ns_info, True
|
return implicit_ns_info, True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ def create_from_name(inference_state, compiled_value, name):
|
|||||||
value = create_cached_compiled_value(
|
value = create_cached_compiled_value(
|
||||||
inference_state,
|
inference_state,
|
||||||
access_path,
|
access_path,
|
||||||
parent_context=None if value is None else value.as_context(),
|
parent_context=None if value is None else value.as_context(), # type: ignore # TODO
|
||||||
)
|
)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -610,7 +610,7 @@ def create_from_access_path(inference_state, access_path):
|
|||||||
value = create_cached_compiled_value(
|
value = create_cached_compiled_value(
|
||||||
inference_state,
|
inference_state,
|
||||||
access,
|
access,
|
||||||
parent_context=None if value is None else value.as_context()
|
parent_context=None if value is None else value.as_context() # type: ignore # TODO
|
||||||
)
|
)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional, Any
|
||||||
|
|
||||||
from parso.python.tree import Name
|
from parso.python.tree import Name
|
||||||
|
|
||||||
@@ -16,6 +16,8 @@ from jedi import parser_utils
|
|||||||
|
|
||||||
class AbstractContext:
|
class AbstractContext:
|
||||||
# Must be defined: inference_state and tree_node and parent_context as an attribute/property
|
# Must be defined: inference_state and tree_node and parent_context as an attribute/property
|
||||||
|
tree_node: Any
|
||||||
|
parent_context: Any
|
||||||
|
|
||||||
def __init__(self, inference_state):
|
def __init__(self, inference_state):
|
||||||
self.inference_state = inference_state
|
self.inference_state = inference_state
|
||||||
@@ -218,6 +220,13 @@ class ValueContext(AbstractContext):
|
|||||||
|
|
||||||
|
|
||||||
class TreeContextMixin:
|
class TreeContextMixin:
|
||||||
|
tree_node: Any
|
||||||
|
is_module: Any
|
||||||
|
get_value: Any
|
||||||
|
inference_state: Any
|
||||||
|
is_class: Any
|
||||||
|
parent_context: Any
|
||||||
|
|
||||||
def infer_node(self, node):
|
def infer_node(self, node):
|
||||||
from jedi.inference.syntax_tree import infer_node
|
from jedi.inference.syntax_tree import infer_node
|
||||||
return infer_node(self, node)
|
return infer_node(self, node)
|
||||||
@@ -300,7 +309,6 @@ class TreeContextMixin:
|
|||||||
class FunctionContext(TreeContextMixin, ValueContext):
|
class FunctionContext(TreeContextMixin, ValueContext):
|
||||||
def get_filters(self, until_position=None, origin_scope=None):
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
yield ParserTreeFilter(
|
yield ParserTreeFilter(
|
||||||
self.inference_state,
|
|
||||||
parent_context=self,
|
parent_context=self,
|
||||||
until_position=until_position,
|
until_position=until_position,
|
||||||
origin_scope=origin_scope
|
origin_scope=origin_scope
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ class DocstringModuleContext(ModuleContext):
|
|||||||
super().__init__(module_value)
|
super().__init__(module_value)
|
||||||
self._in_module_context = in_module_context
|
self._in_module_context = in_module_context
|
||||||
|
|
||||||
def get_filters(self, origin_scope=None, until_position=None):
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
yield from super().get_filters(until_position=until_position)
|
yield from super().get_filters(until_position=until_position)
|
||||||
yield from self._in_module_context.get_filters()
|
yield from self._in_module_context.get_filters()
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ def _search_function_arguments(module_context, funcdef, string_name):
|
|||||||
if string_name == '__init__':
|
if string_name == '__init__':
|
||||||
cls = get_parent_scope(funcdef)
|
cls = get_parent_scope(funcdef)
|
||||||
if cls.type == 'classdef':
|
if cls.type == 'classdef':
|
||||||
string_name = cls.name.value
|
string_name = cls.name.value # type: ignore[union-attr]
|
||||||
compare_node = cls
|
compare_node = cls
|
||||||
|
|
||||||
found_arguments = False
|
found_arguments = False
|
||||||
@@ -203,7 +203,7 @@ def _check_name_for_execution(inference_state, context, compare_node, name, trai
|
|||||||
# Here we're trying to find decorators by checking the first
|
# Here we're trying to find decorators by checking the first
|
||||||
# parameter. It's not very generic though. Should find a better
|
# parameter. It's not very generic though. Should find a better
|
||||||
# solution that also applies to nested decorators.
|
# solution that also applies to nested decorators.
|
||||||
param_names = value.parent_context.get_param_names()
|
param_names = value.parent_context.get_param_names() # type: ignore[attr-defined]
|
||||||
if len(param_names) != 1:
|
if len(param_names) != 1:
|
||||||
continue
|
continue
|
||||||
values = param_names[0].infer()
|
values = param_names[0].infer()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Filters are objects that you can use to filter names in different scopes. They
|
|||||||
are needed for name resolution.
|
are needed for name resolution.
|
||||||
"""
|
"""
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from typing import List, MutableMapping, Type
|
from typing import MutableMapping, Type, Any
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
from parso.python.tree import Name, UsedNamesMapping
|
from parso.python.tree import Name, UsedNamesMapping
|
||||||
@@ -16,8 +16,8 @@ from jedi.inference.utils import to_list
|
|||||||
from jedi.inference.names import TreeNameDefinition, ParamName, \
|
from jedi.inference.names import TreeNameDefinition, ParamName, \
|
||||||
AnonymousParamName, AbstractNameDefinition, NameWrapper
|
AnonymousParamName, AbstractNameDefinition, NameWrapper
|
||||||
|
|
||||||
_definition_name_cache: MutableMapping[UsedNamesMapping, List[Name]]
|
_definition_name_cache: 'MutableMapping[UsedNamesMapping, dict[str, tuple[Name, ...]]]' \
|
||||||
_definition_name_cache = weakref.WeakKeyDictionary()
|
= weakref.WeakKeyDictionary()
|
||||||
|
|
||||||
|
|
||||||
class AbstractFilter:
|
class AbstractFilter:
|
||||||
@@ -346,6 +346,9 @@ class _OverwriteMeta(type):
|
|||||||
|
|
||||||
|
|
||||||
class _AttributeOverwriteMixin:
|
class _AttributeOverwriteMixin:
|
||||||
|
overwritten_methods: Any
|
||||||
|
_wrapped_value: Any
|
||||||
|
|
||||||
def get_filters(self, *args, **kwargs):
|
def get_filters(self, *args, **kwargs):
|
||||||
yield SpecialMethodFilter(self, self.overwritten_methods, self._wrapped_value)
|
yield SpecialMethodFilter(self, self.overwritten_methods, self._wrapped_value)
|
||||||
yield from self._wrapped_value.get_filters(*args, **kwargs)
|
yield from self._wrapped_value.get_filters(*args, **kwargs)
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
|||||||
|
|
||||||
@to_list
|
@to_list
|
||||||
def py__bases__(self):
|
def py__bases__(self):
|
||||||
for base in self._wrapped_value.py__bases__():
|
for base in self._wrapped_value.py__bases__(): # type: ignore[attr-defined]
|
||||||
yield _LazyGenericBaseClass(self, base, self._generics_manager)
|
yield _LazyGenericBaseClass(self, base, self._generics_manager)
|
||||||
|
|
||||||
def _create_instance_with_generics(self, generics_manager):
|
def _create_instance_with_generics(self, generics_manager):
|
||||||
@@ -384,7 +384,7 @@ class BaseTypingValue(LazyValueWrapper):
|
|||||||
return _PseudoTreeNameClass(self.parent_context, self._tree_name)
|
return _PseudoTreeNameClass(self.parent_context, self._tree_name)
|
||||||
|
|
||||||
def get_signatures(self):
|
def get_signatures(self):
|
||||||
return self._wrapped_value.get_signatures()
|
return self._wrapped_value.get_signatures() # type: ignore[attr-defined]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s(%s)' % (self.__class__.__name__, self._tree_name.value)
|
return '%s(%s)' % (self.__class__.__name__, self._tree_name.value)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
This module is about generics, like the `int` in `List[int]`. It's not about
|
This module is about generics, like the `int` in `List[int]`. It's not about
|
||||||
the Generic class.
|
the Generic class.
|
||||||
"""
|
"""
|
||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
@@ -24,6 +25,14 @@ def _resolve_forward_references(context, value_set):
|
|||||||
|
|
||||||
|
|
||||||
class _AbstractGenericManager:
|
class _AbstractGenericManager:
|
||||||
|
@abstractmethod
|
||||||
|
def __getitem__(self, index):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def to_tuple(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def get_index_and_execute(self, index):
|
def get_index_and_execute(self, index):
|
||||||
try:
|
try:
|
||||||
return self[index].execute_annotation()
|
return self[index].execute_annotation()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ values.
|
|||||||
This file deals with all the typing.py cases.
|
This file deals with all the typing.py cases.
|
||||||
"""
|
"""
|
||||||
import itertools
|
import itertools
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.compiled import builtin_from_name, create_simple_object
|
from jedi.inference.compiled import builtin_from_name, create_simple_object
|
||||||
@@ -186,6 +187,8 @@ class ProxyTypingValue(BaseTypingValue):
|
|||||||
|
|
||||||
|
|
||||||
class _TypingClassMixin(ClassMixin):
|
class _TypingClassMixin(ClassMixin):
|
||||||
|
_tree_name: Any
|
||||||
|
|
||||||
def py__bases__(self):
|
def py__bases__(self):
|
||||||
return [LazyKnownValues(
|
return [LazyKnownValues(
|
||||||
self.inference_state.builtins_module.py__getattribute__('object')
|
self.inference_state.builtins_module.py__getattribute__('object')
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import os
|
|||||||
from itertools import chain
|
from itertools import chain
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from parso.python import tree
|
from parso import tree
|
||||||
|
|
||||||
|
|
||||||
def is_stdlib_path(path):
|
def is_stdlib_path(path):
|
||||||
# Python standard library paths look like this:
|
# Python standard library paths look like this:
|
||||||
# /usr/lib/python3.9/...
|
# /usr/lib/python3.14/...
|
||||||
# TODO The implementation below is probably incorrect and not complete.
|
# TODO The implementation below is probably incorrect and not complete.
|
||||||
parts = path.parts
|
parts = path.parts
|
||||||
if 'dist-packages' in parts or 'site-packages' in parts:
|
if 'dist-packages' in parts or 'site-packages' in parts:
|
||||||
|
|||||||
@@ -370,16 +370,16 @@ def import_module_by_names(inference_state, import_names, sys_path=None,
|
|||||||
i.value if isinstance(i, tree.Name) else i
|
i.value if isinstance(i, tree.Name) else i
|
||||||
for i in import_names
|
for i in import_names
|
||||||
)
|
)
|
||||||
value_set = [None]
|
base = [None]
|
||||||
for i, name in enumerate(import_names):
|
for i, name in enumerate(import_names):
|
||||||
value_set = ValueSet.from_sets([
|
base = value_set = ValueSet.from_sets([
|
||||||
import_module(
|
import_module(
|
||||||
inference_state,
|
inference_state,
|
||||||
str_import_names[:i+1],
|
str_import_names[:i+1],
|
||||||
parent_module_value,
|
parent_module_value,
|
||||||
sys_path,
|
sys_path,
|
||||||
prefer_stubs=prefer_stubs,
|
prefer_stubs=prefer_stubs, # type: ignore[call-arg]
|
||||||
) for parent_module_value in value_set
|
) for parent_module_value in base
|
||||||
])
|
])
|
||||||
if not value_set:
|
if not value_set:
|
||||||
message = 'No module named ' + '.'.join(str_import_names)
|
message = 'No module named ' + '.'.join(str_import_names)
|
||||||
@@ -474,7 +474,7 @@ def _load_python_module(inference_state, file_io,
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _load_builtin_module(inference_state, import_names=None, sys_path=None):
|
def _load_builtin_module(inference_state, import_names, sys_path):
|
||||||
project = inference_state.project
|
project = inference_state.project
|
||||||
if sys_path is None:
|
if sys_path is None:
|
||||||
sys_path = inference_state.get_sys_path()
|
sys_path = inference_state.get_sys_path()
|
||||||
|
|||||||
+21
-10
@@ -1,9 +1,8 @@
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from inspect import Parameter
|
from inspect import Parameter
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple, Any
|
||||||
|
|
||||||
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
|
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
|
||||||
from jedi.inference.utils import unite
|
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.inference.cache import inference_state_method_cache
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
from jedi.inference import docstrings
|
from jedi.inference import docstrings
|
||||||
@@ -37,7 +36,6 @@ class AbstractNameDefinition:
|
|||||||
def infer(self):
|
def infer(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def goto(self):
|
def goto(self):
|
||||||
# Typically names are already definitions and therefore a goto on that
|
# Typically names are already definitions and therefore a goto on that
|
||||||
# name will always result on itself.
|
# name will always result on itself.
|
||||||
@@ -105,6 +103,9 @@ class AbstractArbitraryName(AbstractNameDefinition):
|
|||||||
|
|
||||||
|
|
||||||
class AbstractTreeName(AbstractNameDefinition):
|
class AbstractTreeName(AbstractNameDefinition):
|
||||||
|
tree_name: Any
|
||||||
|
parent_context: Any
|
||||||
|
|
||||||
def __init__(self, parent_context, tree_name):
|
def __init__(self, parent_context, tree_name):
|
||||||
self.parent_context = parent_context
|
self.parent_context = parent_context
|
||||||
self.tree_name = tree_name
|
self.tree_name = tree_name
|
||||||
@@ -194,10 +195,11 @@ class AbstractTreeName(AbstractNameDefinition):
|
|||||||
new_dotted = deep_ast_copy(par)
|
new_dotted = deep_ast_copy(par)
|
||||||
new_dotted.children[index - 1:] = []
|
new_dotted.children[index - 1:] = []
|
||||||
values = context.infer_node(new_dotted)
|
values = context.infer_node(new_dotted)
|
||||||
return unite(
|
return [
|
||||||
value.goto(name, name_context=context)
|
n
|
||||||
for value in values
|
for value in values
|
||||||
)
|
for n in value.goto(name, name_context=context)
|
||||||
|
]
|
||||||
|
|
||||||
if node_type == 'trailer' and par.children[0] == '.':
|
if node_type == 'trailer' and par.children[0] == '.':
|
||||||
values = infer_call_of_leaf(context, name, cut_own_trailer=True)
|
values = infer_call_of_leaf(context, name, cut_own_trailer=True)
|
||||||
@@ -222,6 +224,9 @@ class AbstractTreeName(AbstractNameDefinition):
|
|||||||
|
|
||||||
|
|
||||||
class ValueNameMixin:
|
class ValueNameMixin:
|
||||||
|
_value: Any
|
||||||
|
parent_context: Any
|
||||||
|
|
||||||
def infer(self):
|
def infer(self):
|
||||||
return ValueSet([self._value])
|
return ValueSet([self._value])
|
||||||
|
|
||||||
@@ -240,7 +245,7 @@ class ValueNameMixin:
|
|||||||
def get_root_context(self):
|
def get_root_context(self):
|
||||||
if self.parent_context is None: # A module
|
if self.parent_context is None: # A module
|
||||||
return self._value.as_context()
|
return self._value.as_context()
|
||||||
return super().get_root_context()
|
return super().get_root_context() # type: ignore
|
||||||
|
|
||||||
def get_defining_qualified_value(self):
|
def get_defining_qualified_value(self):
|
||||||
context = self.parent_context
|
context = self.parent_context
|
||||||
@@ -357,14 +362,16 @@ class TreeNameDefinition(AbstractTreeName):
|
|||||||
|
|
||||||
|
|
||||||
class _ParamMixin:
|
class _ParamMixin:
|
||||||
|
get_kind: Any
|
||||||
|
|
||||||
def maybe_positional_argument(self, include_star=True):
|
def maybe_positional_argument(self, include_star=True):
|
||||||
options = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
|
options: list[int] = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
|
||||||
if include_star:
|
if include_star:
|
||||||
options.append(Parameter.VAR_POSITIONAL)
|
options.append(Parameter.VAR_POSITIONAL)
|
||||||
return self.get_kind() in options
|
return self.get_kind() in options
|
||||||
|
|
||||||
def maybe_keyword_argument(self, include_stars=True):
|
def maybe_keyword_argument(self, include_stars=True):
|
||||||
options = [Parameter.KEYWORD_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
|
options: list[int] = [Parameter.KEYWORD_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
|
||||||
if include_stars:
|
if include_stars:
|
||||||
options.append(Parameter.VAR_KEYWORD)
|
options.append(Parameter.VAR_KEYWORD)
|
||||||
return self.get_kind() in options
|
return self.get_kind() in options
|
||||||
@@ -629,6 +636,10 @@ class NameWrapper:
|
|||||||
|
|
||||||
|
|
||||||
class StubNameMixin:
|
class StubNameMixin:
|
||||||
|
api_type: str
|
||||||
|
tree_name: Any
|
||||||
|
infer: Any
|
||||||
|
|
||||||
def py__doc__(self):
|
def py__doc__(self):
|
||||||
from jedi.inference.gradual.conversion import convert_names
|
from jedi.inference.gradual.conversion import convert_names
|
||||||
# Stubs are not complicated and we can just follow simple statements
|
# Stubs are not complicated and we can just follow simple statements
|
||||||
@@ -640,7 +651,7 @@ class StubNameMixin:
|
|||||||
|
|
||||||
names = convert_names(names, prefer_stub_to_compiled=False)
|
names = convert_names(names, prefer_stub_to_compiled=False)
|
||||||
if self in names:
|
if self in names:
|
||||||
return super().py__doc__()
|
return super().py__doc__() # type: ignore
|
||||||
else:
|
else:
|
||||||
# We have signatures ourselves in stubs, so don't use signatures
|
# We have signatures ourselves in stubs, so don't use signatures
|
||||||
# from the implementation.
|
# from the implementation.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from inspect import Parameter
|
from inspect import Parameter
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
@@ -6,6 +7,10 @@ from jedi import parser_utils
|
|||||||
|
|
||||||
|
|
||||||
class _SignatureMixin:
|
class _SignatureMixin:
|
||||||
|
get_param_names: Any
|
||||||
|
name: Any
|
||||||
|
annotation_string: Any
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
def param_strings():
|
def param_strings():
|
||||||
is_positional = False
|
is_positional = False
|
||||||
@@ -36,6 +41,8 @@ class _SignatureMixin:
|
|||||||
|
|
||||||
|
|
||||||
class AbstractSignature(_SignatureMixin):
|
class AbstractSignature(_SignatureMixin):
|
||||||
|
_function_value: Any
|
||||||
|
|
||||||
def __init__(self, value, is_bound=False):
|
def __init__(self, value, is_bound=False):
|
||||||
self.value = value
|
self.value = value
|
||||||
self.is_bound = is_bound
|
self.is_bound = is_bound
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ def infer_node(context, element):
|
|||||||
if isinstance(context, CompForContext):
|
if isinstance(context, CompForContext):
|
||||||
return _infer_node(context, element)
|
return _infer_node(context, element)
|
||||||
|
|
||||||
|
name_dicts = [{}]
|
||||||
if_stmt = element
|
if_stmt = element
|
||||||
while if_stmt is not None:
|
while if_stmt is not None:
|
||||||
if_stmt = if_stmt.parent
|
if_stmt = if_stmt.parent
|
||||||
@@ -104,7 +105,6 @@ def infer_node(context, element):
|
|||||||
if predefined_if_name_dict is None and if_stmt \
|
if predefined_if_name_dict is None and if_stmt \
|
||||||
and if_stmt.type == 'if_stmt' and context.inference_state.is_analysis:
|
and if_stmt.type == 'if_stmt' and context.inference_state.is_analysis:
|
||||||
if_stmt_test = if_stmt.children[1]
|
if_stmt_test = if_stmt.children[1]
|
||||||
name_dicts = [{}]
|
|
||||||
# If we already did a check, we don't want to do it again -> If
|
# If we already did a check, we don't want to do it again -> If
|
||||||
# value.predefined_names is filled, we stop.
|
# value.predefined_names is filled, we stop.
|
||||||
# We don't want to check the if stmt itself, it's just about
|
# We don't want to check the if stmt itself, it's just about
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ class PushBackIterator:
|
|||||||
def __init__(self, iterator):
|
def __init__(self, iterator):
|
||||||
self.pushes = []
|
self.pushes = []
|
||||||
self.iterator = iterator
|
self.iterator = iterator
|
||||||
self.current = None
|
|
||||||
|
|
||||||
def push_back(self, value):
|
def push_back(self, value):
|
||||||
self.pushes.append(value)
|
self.pushes.append(value)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from typing import Any
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass
|
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass
|
||||||
from jedi.inference import compiled
|
from jedi.inference import compiled
|
||||||
@@ -53,6 +55,10 @@ class FunctionAndClassBase(TreeValue):
|
|||||||
|
|
||||||
class FunctionMixin:
|
class FunctionMixin:
|
||||||
api_type = 'function'
|
api_type = 'function'
|
||||||
|
tree_node: Any
|
||||||
|
py__class__: Any
|
||||||
|
as_context: Any
|
||||||
|
get_signature_functions: Any
|
||||||
|
|
||||||
def get_filters(self, origin_scope=None):
|
def get_filters(self, origin_scope=None):
|
||||||
cls = self.py__class__()
|
cls = self.py__class__()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from abc import abstractproperty
|
from abc import abstractproperty
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import settings
|
from jedi import settings
|
||||||
@@ -187,6 +188,9 @@ class CompiledInstance(AbstractInstanceValue):
|
|||||||
|
|
||||||
|
|
||||||
class _BaseTreeInstance(AbstractInstanceValue):
|
class _BaseTreeInstance(AbstractInstanceValue):
|
||||||
|
get_defined_names: Any
|
||||||
|
_arguments: Any
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def array_type(self):
|
def array_type(self):
|
||||||
name = self.class_value.py__name__()
|
name = self.class_value.py__name__()
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
Contains all classes and functions to deal with lists, dicts, generators and
|
Contains all classes and functions to deal with lists, dicts, generators and
|
||||||
iterators in general.
|
iterators in general.
|
||||||
"""
|
"""
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from jedi.inference import compiled
|
from jedi.inference import compiled
|
||||||
from jedi.inference import analysis
|
from jedi.inference import analysis
|
||||||
from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues, \
|
from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues, \
|
||||||
@@ -20,6 +22,9 @@ from jedi.inference.value.dynamic_arrays import check_array_additions
|
|||||||
|
|
||||||
|
|
||||||
class IterableMixin:
|
class IterableMixin:
|
||||||
|
py__iter__: Any
|
||||||
|
inference_state: Any
|
||||||
|
|
||||||
def py__next__(self, contextualized_node=None):
|
def py__next__(self, contextualized_node=None):
|
||||||
return self.py__iter__(contextualized_node)
|
return self.py__iter__(contextualized_node)
|
||||||
|
|
||||||
@@ -128,6 +133,12 @@ def comprehension_from_atom(inference_state, value, atom):
|
|||||||
|
|
||||||
|
|
||||||
class ComprehensionMixin:
|
class ComprehensionMixin:
|
||||||
|
_defining_context: Any
|
||||||
|
_entry_node: Any
|
||||||
|
array_type: Any
|
||||||
|
_value_node: Any
|
||||||
|
_sync_comp_for_node: Any
|
||||||
|
|
||||||
@inference_state_method_cache()
|
@inference_state_method_cache()
|
||||||
def _get_comp_for_context(self, parent_context, comp_for):
|
def _get_comp_for_context(self, parent_context, comp_for):
|
||||||
return CompForContext(parent_context, comp_for)
|
return CompForContext(parent_context, comp_for)
|
||||||
@@ -176,6 +187,8 @@ class ComprehensionMixin:
|
|||||||
|
|
||||||
|
|
||||||
class _DictMixin:
|
class _DictMixin:
|
||||||
|
get_mapping_item_values: Any
|
||||||
|
|
||||||
def _get_generics(self):
|
def _get_generics(self):
|
||||||
return tuple(c_set.py__class__() for c_set in self.get_mapping_item_values())
|
return tuple(c_set.py__class__() for c_set in self.get_mapping_item_values())
|
||||||
|
|
||||||
@@ -220,7 +233,7 @@ class Sequence(LazyAttributeOverwrite, IterableMixin):
|
|||||||
class _BaseComprehension(ComprehensionMixin):
|
class _BaseComprehension(ComprehensionMixin):
|
||||||
def __init__(self, inference_state, defining_context, sync_comp_for_node, entry_node):
|
def __init__(self, inference_state, defining_context, sync_comp_for_node, entry_node):
|
||||||
assert sync_comp_for_node.type == 'sync_comp_for'
|
assert sync_comp_for_node.type == 'sync_comp_for'
|
||||||
super().__init__(inference_state)
|
super().__init__(inference_state) # type: ignore[call-arg]
|
||||||
self._defining_context = defining_context
|
self._defining_context = defining_context
|
||||||
self._sync_comp_for_node = sync_comp_for_node
|
self._sync_comp_for_node = sync_comp_for_node
|
||||||
self._entry_node = entry_node
|
self._entry_node = entry_node
|
||||||
@@ -248,6 +261,9 @@ class GeneratorComprehension(_BaseComprehension, GeneratorBase):
|
|||||||
|
|
||||||
|
|
||||||
class _DictKeyMixin:
|
class _DictKeyMixin:
|
||||||
|
_dict_keys: Any
|
||||||
|
_dict_values: Any
|
||||||
|
|
||||||
# TODO merge with _DictMixin?
|
# TODO merge with _DictMixin?
|
||||||
def get_mapping_item_values(self):
|
def get_mapping_item_values(self):
|
||||||
return self._dict_keys(), self._dict_values()
|
return self._dict_keys(), self._dict_values()
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ py__doc__() Returns the docstring for a value.
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple, TYPE_CHECKING, Any
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.parser_utils import get_cached_parent_scope, expr_is_dotted, \
|
from jedi.parser_utils import get_cached_parent_scope, expr_is_dotted, \
|
||||||
@@ -61,6 +61,9 @@ from inspect import Parameter
|
|||||||
from jedi.inference.names import BaseTreeParamName
|
from jedi.inference.names import BaseTreeParamName
|
||||||
from jedi.inference.signature import AbstractSignature
|
from jedi.inference.signature import AbstractSignature
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from jedi.inference import InferenceState
|
||||||
|
|
||||||
|
|
||||||
class ClassName(TreeNameDefinition):
|
class ClassName(TreeNameDefinition):
|
||||||
def __init__(self, class_value, tree_name, name_context, apply_decorators):
|
def __init__(self, class_value, tree_name, name_context, apply_decorators):
|
||||||
@@ -197,6 +200,15 @@ def get_dataclass_param_names(cls) -> List[DataclassParamName]:
|
|||||||
|
|
||||||
|
|
||||||
class ClassMixin:
|
class ClassMixin:
|
||||||
|
tree_node: Any
|
||||||
|
parent_context: Any
|
||||||
|
inference_state: InferenceState
|
||||||
|
py__bases__: Any
|
||||||
|
get_metaclasses: Any
|
||||||
|
get_metaclass_filters: Any
|
||||||
|
get_metaclass_signatures: Any
|
||||||
|
list_type_vars: Any
|
||||||
|
|
||||||
def is_class(self):
|
def is_class(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -682,6 +694,9 @@ class ClassValue(ClassMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
|
|||||||
"""
|
"""
|
||||||
bases_arguments = self._get_bases_arguments()
|
bases_arguments = self._get_bases_arguments()
|
||||||
|
|
||||||
|
if bases_arguments is None:
|
||||||
|
return None
|
||||||
|
|
||||||
if bases_arguments.argument_node.type != "arglist":
|
if bases_arguments.argument_node.type != "arglist":
|
||||||
# If it is not inheriting from the base model and having
|
# If it is not inheriting from the base model and having
|
||||||
# extra parameters, then init behavior is not changed.
|
# extra parameters, then init behavior is not changed.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional, TYPE_CHECKING, Any
|
||||||
|
|
||||||
from jedi.inference.cache import inference_state_method_cache
|
from jedi.inference.cache import inference_state_method_cache
|
||||||
from jedi.inference.names import AbstractNameDefinition, ModuleName
|
from jedi.inference.names import AbstractNameDefinition, ModuleName
|
||||||
@@ -13,6 +13,9 @@ from jedi.inference.compiled import create_simple_object
|
|||||||
from jedi.inference.base_value import ValueSet
|
from jedi.inference.base_value import ValueSet
|
||||||
from jedi.inference.context import ModuleContext
|
from jedi.inference.context import ModuleContext
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from jedi.inference import InferenceState
|
||||||
|
|
||||||
|
|
||||||
class _ModuleAttributeName(AbstractNameDefinition):
|
class _ModuleAttributeName(AbstractNameDefinition):
|
||||||
"""
|
"""
|
||||||
@@ -35,6 +38,11 @@ class _ModuleAttributeName(AbstractNameDefinition):
|
|||||||
|
|
||||||
|
|
||||||
class SubModuleDictMixin:
|
class SubModuleDictMixin:
|
||||||
|
inference_state: "InferenceState"
|
||||||
|
is_package: Any
|
||||||
|
py__path__: Any
|
||||||
|
as_context: Any
|
||||||
|
|
||||||
@inference_state_method_cache()
|
@inference_state_method_cache()
|
||||||
def sub_modules_dict(self):
|
def sub_modules_dict(self):
|
||||||
"""
|
"""
|
||||||
@@ -57,6 +65,10 @@ class SubModuleDictMixin:
|
|||||||
|
|
||||||
class ModuleMixin(SubModuleDictMixin):
|
class ModuleMixin(SubModuleDictMixin):
|
||||||
_module_name_class = ModuleName
|
_module_name_class = ModuleName
|
||||||
|
tree_node: Any
|
||||||
|
string_names: Any
|
||||||
|
sub_modules_dict: Any
|
||||||
|
py__file__: Any
|
||||||
|
|
||||||
def get_filters(self, origin_scope=None):
|
def get_filters(self, origin_scope=None):
|
||||||
yield MergedFilter(
|
yield MergedFilter(
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ def get_parent_scope(node, include_flows=False):
|
|||||||
# the if, but the parent of the if.
|
# the if, but the parent of the if.
|
||||||
if not (scope.type == 'if_stmt'
|
if not (scope.type == 'if_stmt'
|
||||||
and any(n.start_pos <= node.start_pos < n.end_pos
|
and any(n.start_pos <= node.start_pos < n.end_pos
|
||||||
for n in scope.get_test_nodes())):
|
for n in scope.get_test_nodes())): # type: ignore[attr-defined]
|
||||||
return scope
|
return scope
|
||||||
|
|
||||||
scope = scope.parent
|
scope = scope.parent
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Module is used to infer Django model fields.
|
Module is used to infer Django model fields.
|
||||||
"""
|
"""
|
||||||
from inspect import Parameter
|
from inspect import Parameter
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.inference.cache import inference_state_function_cache
|
from jedi.inference.cache import inference_state_function_cache
|
||||||
@@ -140,7 +141,7 @@ def _new_dict_filter(cls, is_instance):
|
|||||||
include_metaclasses=False,
|
include_metaclasses=False,
|
||||||
include_type_when_class=False)
|
include_type_when_class=False)
|
||||||
)
|
)
|
||||||
dct = {
|
dct: dict[str, Any] = {
|
||||||
name.string_name: DjangoModelName(cls, name, is_instance)
|
name.string_name: DjangoModelName(cls, name, is_instance)
|
||||||
for filter_ in reversed(filters)
|
for filter_ in reversed(filters)
|
||||||
for name in filter_.values()
|
for name in filter_.values()
|
||||||
|
|||||||
+7
-21
@@ -138,28 +138,14 @@ def _find_pytest_plugin_modules() -> List[List[str]]:
|
|||||||
|
|
||||||
See https://docs.pytest.org/en/stable/how-to/writing_plugins.html#setuptools-entry-points
|
See https://docs.pytest.org/en/stable/how-to/writing_plugins.html#setuptools-entry-points
|
||||||
"""
|
"""
|
||||||
if sys.version_info >= (3, 8):
|
from importlib.metadata import entry_points
|
||||||
from importlib.metadata import entry_points
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 10):
|
|
||||||
pytest_entry_points = entry_points(group="pytest11")
|
|
||||||
else:
|
|
||||||
pytest_entry_points = entry_points().get("pytest11", ())
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 9):
|
|
||||||
return [ep.module.split(".") for ep in pytest_entry_points]
|
|
||||||
else:
|
|
||||||
# Python 3.8 doesn't have `EntryPoint.module`. Implement equivalent
|
|
||||||
# to what Python 3.9 does (with additional None check to placate `mypy`)
|
|
||||||
matches = [
|
|
||||||
ep.pattern.match(ep.value)
|
|
||||||
for ep in pytest_entry_points
|
|
||||||
]
|
|
||||||
return [x.group('module').split(".") for x in matches if x]
|
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 10):
|
||||||
|
pytest_entry_points = entry_points(group="pytest11")
|
||||||
else:
|
else:
|
||||||
from pkg_resources import iter_entry_points
|
pytest_entry_points = entry_points().get("pytest11", ())
|
||||||
return [ep.module_name.split(".") for ep in iter_entry_points(group="pytest11")]
|
|
||||||
|
return [ep.module.split(".") for ep in pytest_entry_points]
|
||||||
|
|
||||||
|
|
||||||
@inference_state_method_cache()
|
@inference_state_method_cache()
|
||||||
@@ -192,7 +178,7 @@ def _iter_pytest_modules(module_context, skip_own_module=False):
|
|||||||
folder = folder.get_parent_folder()
|
folder = folder.get_parent_folder()
|
||||||
|
|
||||||
# prevent an infinite for loop if the same parent folder is return twice
|
# prevent an infinite for loop if the same parent folder is return twice
|
||||||
if last_folder is not None and folder.path == last_folder.path:
|
if last_folder is not None and folder.path == last_folder.path: # type: ignore # TODO
|
||||||
break
|
break
|
||||||
last_folder = folder # keep track of the last found parent name
|
last_folder = folder # keep track of the last found parent name
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ def execute(callback):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
return func(value, arguments=arguments, callback=call)
|
return func(value, arguments=arguments, callback=call) # type: ignore
|
||||||
return call()
|
return call()
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|||||||
+12
-30
@@ -1,32 +1,14 @@
|
|||||||
[tool.mypy]
|
[tool.zuban]
|
||||||
# Exclude our copies of external stubs
|
strict = true
|
||||||
exclude = "^jedi/third_party"
|
enable_error_code = ["ignore-without-code"]
|
||||||
|
|
||||||
show_error_codes = true
|
# Revert some --strict specific flags:
|
||||||
enable_error_code = "ignore-without-code"
|
allow_untyped_calls = true
|
||||||
|
allow_untyped_defs = true
|
||||||
# Ensure generics are explicit about what they are (e.g: `List[str]` rather than
|
allow_incomplete_defs = true
|
||||||
# just `List`)
|
allow_untyped_globals = true
|
||||||
disallow_any_generics = true
|
untyped_strict_optional = false
|
||||||
|
|
||||||
disallow_subclassing_any = true
|
|
||||||
|
|
||||||
# Avoid creating future gotchas emerging from bad typing
|
|
||||||
warn_redundant_casts = true
|
|
||||||
warn_unused_ignores = true
|
|
||||||
warn_return_any = true
|
|
||||||
warn_unused_configs = true
|
|
||||||
|
|
||||||
warn_unreachable = true
|
|
||||||
|
|
||||||
# Require values to be explicitly re-exported; this makes things easier for
|
|
||||||
# Flake8 too and avoids accidentally importing thing from the "wrong" place
|
|
||||||
# (which helps avoid circular imports)
|
|
||||||
implicit_reexport = false
|
|
||||||
|
|
||||||
strict_equality = true
|
|
||||||
|
|
||||||
[[tool.mypy.overrides]]
|
|
||||||
# Various __init__.py files which contain re-exports we want to implicitly make.
|
|
||||||
module = ["jedi", "jedi.inference.compiled", "jedi.inference.value", "parso"]
|
|
||||||
implicit_reexport = true
|
implicit_reexport = true
|
||||||
|
|
||||||
|
# Exclude our copies of external stubs
|
||||||
|
exclude = "^jedi/third_party|^test/(completion|refactor|static_analysis|examples)/"
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""
|
|
||||||
Profile a piece of Python code with ``cProfile`` that uses the diff parser.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
profile.py <file> [-d] [-s <sort>]
|
|
||||||
profile.py -h | --help
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h --help Show this screen.
|
|
||||||
-d --debug Enable Jedi internal debugging.
|
|
||||||
-s <sort> Sort the profile results, e.g. cumtime, name [default: time].
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cProfile
|
|
||||||
|
|
||||||
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.common import splitlines
|
|
||||||
import jedi
|
|
||||||
|
|
||||||
|
|
||||||
def run(parser, lines):
|
|
||||||
diff_parser = DiffParser(parser)
|
|
||||||
diff_parser.update(lines)
|
|
||||||
# Make sure used_names is loaded
|
|
||||||
parser.module.used_names
|
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
if args['--debug']:
|
|
||||||
jedi.set_debug_function(notices=True)
|
|
||||||
|
|
||||||
with open(args['<file>']) as f:
|
|
||||||
code = f.read()
|
|
||||||
grammar = load_grammar()
|
|
||||||
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.
|
|
||||||
lines = splitlines(code, keepends=True)
|
|
||||||
cProfile.runctx('run(parser, lines)', globals(), locals(), sort=args['-s'])
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
args = docopt(__doc__)
|
|
||||||
main(args)
|
|
||||||
@@ -13,7 +13,7 @@ Note: This requires the psutil library, available on PyPI.
|
|||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import psutil
|
import psutil # type: ignore[import-untyped]
|
||||||
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/..'))
|
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/..'))
|
||||||
import jedi
|
import jedi
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ def main(args):
|
|||||||
run(code, i, infer=infer)
|
run(code, i, infer=infer)
|
||||||
|
|
||||||
if args['--precision']:
|
if args['--precision']:
|
||||||
pstats.f8 = f8
|
pstats.f8 = f8 # type: ignore[attr-defined] # TODO this does not seem to exist?!
|
||||||
|
|
||||||
jedi.set_debug_function(notices=args['--debug'])
|
jedi.set_debug_function(notices=args['--debug'])
|
||||||
if args['--omit']:
|
if args['--omit']:
|
||||||
|
|||||||
+2
-2
@@ -17,11 +17,11 @@ import sys
|
|||||||
try:
|
try:
|
||||||
import urllib.request as urllib2
|
import urllib.request as urllib2
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import urllib2
|
import urllib2 # type: ignore[import-not-found, no-redef]
|
||||||
import gc
|
import gc
|
||||||
from os.path import abspath, dirname
|
from os.path import abspath, dirname
|
||||||
|
|
||||||
import objgraph
|
import objgraph # type: ignore[import-untyped]
|
||||||
|
|
||||||
sys.path.insert(0, dirname(dirname(abspath(__file__))))
|
sys.path.insert(0, dirname(dirname(abspath(__file__))))
|
||||||
import jedi
|
import jedi
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ setup(name='jedi',
|
|||||||
keywords='python completion refactoring vim',
|
keywords='python completion refactoring vim',
|
||||||
long_description=readme,
|
long_description=readme,
|
||||||
packages=find_packages(exclude=['test', 'test.*']),
|
packages=find_packages(exclude=['test', 'test.*']),
|
||||||
python_requires='>=3.8',
|
python_requires='>=3.10',
|
||||||
# Python 3.13 grammars are added to parso in 0.8.4
|
# Python 3.13 grammars are added to parso in 0.8.4
|
||||||
install_requires=['parso>=0.8.5,<0.9.0'],
|
install_requires=['parso>=0.8.6,<0.9.0'],
|
||||||
extras_require={
|
extras_require={
|
||||||
'testing': [
|
'dev': [
|
||||||
'pytest<9.0.0',
|
'pytest<9.0.0',
|
||||||
# docopt for sith doctests
|
# docopt for sith doctests
|
||||||
'docopt',
|
'docopt',
|
||||||
@@ -48,42 +48,41 @@ setup(name='jedi',
|
|||||||
'Django',
|
'Django',
|
||||||
'attrs',
|
'attrs',
|
||||||
'typing_extensions',
|
'typing_extensions',
|
||||||
],
|
|
||||||
'qa': [
|
|
||||||
# latest version on 2025-06-16
|
# latest version on 2025-06-16
|
||||||
'flake8==7.2.0',
|
'flake8==7.1.2',
|
||||||
# latest version supporting Python 3.6
|
'zuban==0.7.0',
|
||||||
'mypy==1.16',
|
|
||||||
# Arbitrary pins, latest at the time of pinning
|
# Arbitrary pins, latest at the time of pinning
|
||||||
'types-setuptools==80.9.0.20250529',
|
'types-setuptools==80.9.0.20250529',
|
||||||
],
|
],
|
||||||
'docs': [
|
'docs': [
|
||||||
# Just pin all of these.
|
# Just pin all of these.
|
||||||
'Jinja2==2.11.3',
|
'alabaster==1.0.0',
|
||||||
'MarkupSafe==1.1.1',
|
'babel==2.18.0',
|
||||||
'Pygments==2.8.1',
|
'certifi==2026.4.22',
|
||||||
'alabaster==0.7.12',
|
'charset-normalizer==3.4.7',
|
||||||
'babel==2.9.1',
|
'docutils==0.22.4',
|
||||||
'chardet==4.0.0',
|
'idna==3.13',
|
||||||
'commonmark==0.8.1',
|
'imagesize==2.0.0',
|
||||||
'docutils==0.17.1',
|
'iniconfig==2.3.0',
|
||||||
'future==0.18.2',
|
'Jinja2==3.1.6',
|
||||||
'idna==2.10',
|
'MarkupSafe==3.0.3',
|
||||||
'imagesize==1.2.0',
|
'packaging==26.2',
|
||||||
'mock==1.0.1',
|
'pluggy==1.6.0',
|
||||||
'packaging==20.9',
|
'Pygments==2.20.0',
|
||||||
'pyparsing==2.4.7',
|
'pytest==9.0.3',
|
||||||
'pytz==2021.1',
|
'requests==2.33.1',
|
||||||
'readthedocs-sphinx-ext==2.1.4',
|
'roman-numerals==4.1.0',
|
||||||
'recommonmark==0.5.0',
|
'snowballstemmer==3.0.1',
|
||||||
'requests==2.25.1',
|
'Sphinx==9.1.0',
|
||||||
'six==1.15.0',
|
'sphinx_rtd_theme==3.1.0',
|
||||||
'snowballstemmer==2.1.0',
|
'sphinxcontrib-applehelp==2.0.0',
|
||||||
'sphinx==1.8.5',
|
'sphinxcontrib-devhelp==2.0.0',
|
||||||
'sphinx-rtd-theme==0.4.3',
|
'sphinxcontrib-htmlhelp==2.1.0',
|
||||||
'sphinxcontrib-serializinghtml==1.1.4',
|
'sphinxcontrib-jquery==4.1',
|
||||||
'sphinxcontrib-websupport==1.2.4',
|
'sphinxcontrib-jsmath==1.0.1',
|
||||||
'urllib3==1.26.4',
|
'sphinxcontrib-qthelp==2.0.0',
|
||||||
|
'sphinxcontrib-serializinghtml==2.0.0',
|
||||||
|
'urllib3==2.6.3',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
package_data={'jedi': ['*.pyi', 'third_party/typeshed/LICENSE',
|
package_data={'jedi': ['*.pyi', 'third_party/typeshed/LICENSE',
|
||||||
@@ -96,8 +95,6 @@ setup(name='jedi',
|
|||||||
'License :: OSI Approved :: MIT License',
|
'License :: OSI Approved :: MIT License',
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.8',
|
|
||||||
'Programming Language :: Python :: 3.9',
|
|
||||||
'Programming Language :: Python :: 3.10',
|
'Programming Language :: Python :: 3.10',
|
||||||
'Programming Language :: Python :: 3.11',
|
'Programming Language :: Python :: 3.11',
|
||||||
'Programming Language :: Python :: 3.12',
|
'Programming Language :: Python :: 3.12',
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ Usage:
|
|||||||
Options:
|
Options:
|
||||||
-h --help Show this screen.
|
-h --help Show this screen.
|
||||||
--record=<file> Exceptions are recorded in here [default: record.json].
|
--record=<file> Exceptions are recorded in here [default: record.json].
|
||||||
-f, --fs-cache By default, file system cache is off for reproducibility.
|
|
||||||
-n, --maxtries=<nr> Maximum of random tries [default: 100]
|
-n, --maxtries=<nr> Maximum of random tries [default: 100]
|
||||||
-d, --debug Jedi print debugging when an error is raised.
|
-d, --debug Jedi print debugging when an error is raised.
|
||||||
-s Shows the path/line numbers of every completion before it starts.
|
-s Shows the path/line numbers of every completion before it starts.
|
||||||
@@ -187,7 +186,6 @@ def main(arguments):
|
|||||||
'pudb' if arguments['--pudb'] else None
|
'pudb' if arguments['--pudb'] else None
|
||||||
record = arguments['--record']
|
record = arguments['--record']
|
||||||
|
|
||||||
jedi.settings.use_filesystem_cache = arguments['--fs-cache']
|
|
||||||
if arguments['--debug']:
|
if arguments['--debug']:
|
||||||
jedi.set_debug_function()
|
jedi.set_debug_function()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# For assignment expressions / named expressions / walrus operators / whatever
|
# For assignment expressions / named expressions / walrus operators / whatever
|
||||||
# they are called.
|
# they are called.
|
||||||
|
|
||||||
# python >= 3.8
|
|
||||||
b = (a:=1, a)
|
b = (a:=1, a)
|
||||||
|
|
||||||
#? int()
|
#? int()
|
||||||
|
|||||||
@@ -476,8 +476,6 @@ dynamic_annotation('')
|
|||||||
# TypeDict
|
# TypeDict
|
||||||
# -------------------------
|
# -------------------------
|
||||||
|
|
||||||
# python >= 3.8
|
|
||||||
|
|
||||||
class Foo(typing.TypedDict):
|
class Foo(typing.TypedDict):
|
||||||
foo: str
|
foo: str
|
||||||
bar: typing.List[float]
|
bar: typing.List[float]
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# python >= 3.9
|
|
||||||
|
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
|
||||||
# This is just a dummy and very meaningless thing to use with to the Annotated
|
# This is just a dummy and very meaningless thing to use with to the Annotated
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# python >= 3.8
|
|
||||||
|
|
||||||
def positional_only_call(a, /, b):
|
def positional_only_call(a, /, b):
|
||||||
#? str()
|
#? str()
|
||||||
a
|
a
|
||||||
|
|||||||
@@ -459,8 +459,6 @@ X().just_partial('')[0]
|
|||||||
#? str()
|
#? str()
|
||||||
X().just_partial('')[1]
|
X().just_partial('')[1]
|
||||||
|
|
||||||
# python >= 3.8
|
|
||||||
|
|
||||||
@functools.lru_cache
|
@functools.lru_cache
|
||||||
def x() -> int: ...
|
def x() -> int: ...
|
||||||
@functools.lru_cache()
|
@functools.lru_cache()
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ from jedi.api.interpreter import MixedModuleContext
|
|||||||
# For interpreter tests sometimes the path of this directory is in the sys
|
# For interpreter tests sometimes the path of this directory is in the sys
|
||||||
# path, which we definitely don't want. So just remove it globally.
|
# path, which we definitely don't want. So just remove it globally.
|
||||||
try:
|
try:
|
||||||
sys.path.remove(helpers.test_dir)
|
sys.path.remove(str(helpers.test_dir))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
sys.path[0:0] = [
|
sys.path[0:0] = [
|
||||||
'/usr/lib/python3.8/site-packages',
|
'/usr/lib/python3.14/site-packages',
|
||||||
'/tmp/.buildout/eggs/important_package.egg'
|
'/tmp/.buildout/eggs/important_package.egg'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -168,6 +168,8 @@ class BaseTestCase(object):
|
|||||||
|
|
||||||
|
|
||||||
class IntegrationTestCase(BaseTestCase):
|
class IntegrationTestCase(BaseTestCase):
|
||||||
|
source: str # Defined as a side effect
|
||||||
|
|
||||||
def __init__(self, test_type, correct, line_nr, column, start, line,
|
def __init__(self, test_type, correct, line_nr, column, start, line,
|
||||||
path=None, skip_version_info=None):
|
path=None, skip_version_info=None):
|
||||||
super().__init__(skip_version_info)
|
super().__init__(skip_version_info)
|
||||||
@@ -446,7 +448,7 @@ Options:
|
|||||||
--pdb Enable pdb debugging on fail.
|
--pdb Enable pdb debugging on fail.
|
||||||
-d, --debug Enable text output debugging (please install ``colorama``).
|
-d, --debug Enable text output debugging (please install ``colorama``).
|
||||||
--thirdparty Also run thirdparty tests (in ``completion/thirdparty``).
|
--thirdparty Also run thirdparty tests (in ``completion/thirdparty``).
|
||||||
--env <dotted> A Python version, like 3.9, 3.8, etc.
|
--env <dotted> A Python version, like 3.14, 3.13, etc.
|
||||||
"""
|
"""
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import docopt
|
import docopt
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ def test_added_equals_to_params(Script):
|
|||||||
|
|
||||||
def test_builtin_module_with_path(Script):
|
def test_builtin_module_with_path(Script):
|
||||||
"""
|
"""
|
||||||
This test simply tests if a module from /usr/lib/python3.8/lib-dynload/ has
|
This test simply tests if a module from /usr/lib/python3.14/lib-dynload/ has
|
||||||
a path or not. It shouldn't have a module_path, because that is just
|
a path or not. It shouldn't have a module_path, because that is just
|
||||||
confusing.
|
confusing.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import os
|
|||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from itertools import count
|
from itertools import count
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -301,7 +302,7 @@ def test_file_path_should_have_completions(Script):
|
|||||||
assert Script('r"').complete() # See GH #1503
|
assert Script('r"').complete() # See GH #1503
|
||||||
|
|
||||||
|
|
||||||
_dict_keys_completion_tests = [
|
_dict_keys_completion_tests: "list[tuple[str, int | None, list[str | Any]]]" = [
|
||||||
('ints[', 5, ['1', '50', Ellipsis]),
|
('ints[', 5, ['1', '50', Ellipsis]),
|
||||||
('ints[]', 5, ['1', '50', Ellipsis]),
|
('ints[]', 5, ['1', '50', Ellipsis]),
|
||||||
('ints[1]', 5, ['1', '50', Ellipsis]),
|
('ints[1]', 5, ['1', '50', Ellipsis]),
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ def test_find_system_environments():
|
|||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'version',
|
'version',
|
||||||
['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
|
['3.10', '3.11', '3.12', '3.13']
|
||||||
)
|
)
|
||||||
def test_versions(version):
|
def test_versions(version):
|
||||||
try:
|
try:
|
||||||
env = get_system_environment(version)
|
env = get_system_environment(version)
|
||||||
except InvalidPythonEnvironment:
|
except InvalidPythonEnvironment:
|
||||||
if int(version.replace('.', '')) == str(sys.version_info[0]) + str(sys.version_info[1]):
|
if version.replace('.', '') == str(sys.version_info[0]) + str(sys.version_info[1]):
|
||||||
# At least the current version has to work
|
# At least the current version has to work
|
||||||
raise
|
raise
|
||||||
pytest.skip()
|
pytest.skip()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ There are three kinds of test:
|
|||||||
|
|
||||||
import textwrap
|
import textwrap
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -22,6 +23,8 @@ import jedi
|
|||||||
|
|
||||||
|
|
||||||
class MixinTestFullName(object):
|
class MixinTestFullName(object):
|
||||||
|
assertEqual: Any
|
||||||
|
|
||||||
operation = None
|
operation = None
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ def test_numpy_like_non_zero():
|
|||||||
|
|
||||||
def test_nested_resolve():
|
def test_nested_resolve():
|
||||||
class XX:
|
class XX:
|
||||||
def x():
|
def x(): # type: ignore[misc]
|
||||||
pass
|
pass
|
||||||
|
|
||||||
cls = get_completion('XX', locals())
|
cls = get_completion('XX', locals())
|
||||||
@@ -92,7 +92,7 @@ def test_side_effect_completion():
|
|||||||
Python code, however we want references to Python code as well. Therefore
|
Python code, however we want references to Python code as well. Therefore
|
||||||
we need some mixed kind of magic for tests.
|
we need some mixed kind of magic for tests.
|
||||||
"""
|
"""
|
||||||
_GlobalNameSpace.SideEffectContainer.foo = 1
|
_GlobalNameSpace.SideEffectContainer.foo = 1 # type: ignore[attr-defined]
|
||||||
side_effect = get_completion('SideEffectContainer', _GlobalNameSpace.__dict__)
|
side_effect = get_completion('SideEffectContainer', _GlobalNameSpace.__dict__)
|
||||||
|
|
||||||
# It's a class that contains MixedObject.
|
# It's a class that contains MixedObject.
|
||||||
@@ -166,7 +166,7 @@ def test_getitem_side_effects():
|
|||||||
# Possible side effects here, should therefore not call this.
|
# Possible side effects here, should therefore not call this.
|
||||||
if True:
|
if True:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
return index
|
return index # type: ignore[unreachable]
|
||||||
|
|
||||||
foo = Foo2()
|
foo = Foo2()
|
||||||
_assert_interpreter_complete('foo["asdf"].upper', locals(), ['upper'])
|
_assert_interpreter_complete('foo["asdf"].upper', locals(), ['upper'])
|
||||||
@@ -198,7 +198,7 @@ def test__getattr__completions(allow_unsafe_getattr, class_is_findable):
|
|||||||
raise AttributeError(name)
|
raise AttributeError(name)
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
return ['foo', 'fbar'] + object.__dir__(self)
|
return ['foo', 'fbar'] + object.__dir__(self) # type: ignore[operator]
|
||||||
|
|
||||||
if not class_is_findable:
|
if not class_is_findable:
|
||||||
CompleteGetattr.__name__ = "something_somewhere"
|
CompleteGetattr.__name__ = "something_somewhere"
|
||||||
@@ -388,7 +388,7 @@ def test_dir_magic_method(allow_unsafe_getattr):
|
|||||||
raise AttributeError(name)
|
raise AttributeError(name)
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
return ['foo', 'bar'] + object.__dir__(self)
|
return ['foo', 'bar'] + object.__dir__(self) # type: ignore[operator]
|
||||||
|
|
||||||
itp = jedi.Interpreter("ca.", [{'ca': CompleteAttrs()}])
|
itp = jedi.Interpreter("ca.", [{'ca': CompleteAttrs()}])
|
||||||
completions = itp.complete()
|
completions = itp.complete()
|
||||||
@@ -410,7 +410,7 @@ def test_dir_magic_method(allow_unsafe_getattr):
|
|||||||
def test_name_not_findable():
|
def test_name_not_findable():
|
||||||
class X():
|
class X():
|
||||||
if 0:
|
if 0:
|
||||||
NOT_FINDABLE # noqa: F821
|
NOT_FINDABLE # type: ignore[unreachable] # noqa: F821
|
||||||
|
|
||||||
def hidden(self):
|
def hidden(self):
|
||||||
return
|
return
|
||||||
@@ -493,7 +493,7 @@ def test__wrapped__():
|
|||||||
|
|
||||||
def test_illegal_class_instance():
|
def test_illegal_class_instance():
|
||||||
class X:
|
class X:
|
||||||
__class__ = 1
|
__class__ = 1 # type: ignore[assignment]
|
||||||
X.__name__ = 'asdf'
|
X.__name__ = 'asdf'
|
||||||
d, = jedi.Interpreter('foo', [{'foo': X()}]).infer()
|
d, = jedi.Interpreter('foo', [{'foo': X()}]).infer()
|
||||||
v, = d._name.infer()
|
v, = d._name.infer()
|
||||||
@@ -537,7 +537,7 @@ def test_partial_signatures(code, expected, index):
|
|||||||
|
|
||||||
def test_type_var():
|
def test_type_var():
|
||||||
"""This was an issue before, see Github #1369"""
|
"""This was an issue before, see Github #1369"""
|
||||||
x = typing.TypeVar('myvar')
|
x = typing.TypeVar('myvar') # type: ignore[misc]
|
||||||
def_, = jedi.Interpreter('x', [locals()]).infer()
|
def_, = jedi.Interpreter('x', [locals()]).infer()
|
||||||
assert def_.name == 'TypeVar'
|
assert def_.name == 'TypeVar'
|
||||||
|
|
||||||
@@ -576,7 +576,7 @@ def test_dict_completion(code, column, expected):
|
|||||||
strs = {'asdf': 1, """foo""": 2, r'fbar': 3}
|
strs = {'asdf': 1, """foo""": 2, r'fbar': 3}
|
||||||
mixed = {1: 2, 1.10: 4, None: 6, r'a\sdf': 8, b'foo': 9}
|
mixed = {1: 2, 1.10: 4, None: 6, r'a\sdf': 8, b'foo': 9}
|
||||||
|
|
||||||
class Inherited(dict):
|
class Inherited(dict): # type: ignore[type-arg]
|
||||||
pass
|
pass
|
||||||
inherited = Inherited(blablu=3)
|
inherited = Inherited(blablu=3)
|
||||||
|
|
||||||
@@ -624,10 +624,10 @@ def test_dunders(class_is_findable, code, expected, allow_unsafe_getattr):
|
|||||||
def __getitem__(self, key) -> int:
|
def __getitem__(self, key) -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def __iter__(self, key) -> Iterator[str]:
|
def __iter__(self, key) -> Iterator[str]: # type: ignore[empty-body]
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __next__(self, key) -> float:
|
def __next__(self, key) -> float: # type: ignore[empty-body]
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not class_is_findable:
|
if not class_is_findable:
|
||||||
@@ -810,11 +810,11 @@ def test_try_to_use_return_annotation_for_property(class_is_findable):
|
|||||||
raise BaseException
|
raise BaseException
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def with_annotation_garbage1(self) -> 'asldjflksjdfljdslkjfsl': # noqa
|
def with_annotation_garbage1(self) -> 'asldjflksjdfljdslkjfsl': # type: ignore[name-defined] # noqa
|
||||||
return Hello()
|
return Hello()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def with_annotation_garbage2(self) -> 'sdf$@@$5*+8': # noqa
|
def with_annotation_garbage2(self) -> 'sdf & 8': # type: ignore[valid-type] # noqa
|
||||||
return Hello()
|
return Hello()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ def test_rename_mod(Script, dir_with_content):
|
|||||||
''').format(dir=dir_with_content)
|
''').format(dir=dir_with_content)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif('sys.version_info[:2] < (3, 8)', message="Python 3.8 introduces dirs_exist_ok")
|
|
||||||
def test_namespace_package(Script, tmpdir):
|
def test_namespace_package(Script, tmpdir):
|
||||||
origin = get_example_dir('implicit_namespace_package')
|
origin = get_example_dir('implicit_namespace_package')
|
||||||
shutil.copytree(origin, tmpdir.strpath, dirs_exist_ok=True)
|
shutil.copytree(origin, tmpdir.strpath, dirs_exist_ok=True)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class SomeClass:
|
|||||||
def twice(self, b):
|
def twice(self, b):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def some_function():
|
def some_function(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ def test_path_from_sys_path_assignment(Script):
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
sys.path[0:0] = [
|
sys.path[0:0] = [
|
||||||
{os.path.abspath('/usr/lib/python3.8/site-packages')!r},
|
{os.path.abspath('/usr/lib/python3.14/site-packages')!r},
|
||||||
{os.path.abspath('/home/test/.buildout/eggs/important_package.egg')!r},
|
{os.path.abspath('/home/test/.buildout/eggs/important_package.egg')!r},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ import jedi
|
|||||||
from ..helpers import test_dir
|
from ..helpers import test_dir
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import numpydoc # NOQA
|
import numpydoc # type: ignore[import-not-found] # NOQA
|
||||||
except ImportError:
|
except ImportError:
|
||||||
numpydoc_unavailable = True
|
numpydoc_unavailable = True
|
||||||
else:
|
else:
|
||||||
numpydoc_unavailable = False
|
numpydoc_unavailable = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import numpy # NOQA
|
import numpy # type: ignore[import-not-found] # NOQA
|
||||||
except ImportError:
|
except ImportError:
|
||||||
numpy_unavailable = True
|
numpy_unavailable = True
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ def test_get_signatures_stdlib(Script):
|
|||||||
assert len(sigs[0].params) == 1
|
assert len(sigs[0].params) == 1
|
||||||
|
|
||||||
|
|
||||||
# Check only on linux 64 bit platform and Python3.8.
|
# TODO This is currently only checked on linux 64 bit platform and Python3.8,
|
||||||
|
# which we don't support anymore, this test should be rewritten (or the
|
||||||
|
# extension recreated).
|
||||||
@pytest.mark.parametrize('load_unsafe_extensions', [False, True])
|
@pytest.mark.parametrize('load_unsafe_extensions', [False, True])
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
'sys.platform != "linux" or sys.maxsize <= 2**32 or sys.version_info[:2] != (3, 8)',
|
'sys.platform != "linux" or sys.maxsize <= 2**32 or sys.version_info[:2] != (3, 8)',
|
||||||
@@ -48,7 +50,8 @@ def test_init_extension_module(Script, load_unsafe_extensions):
|
|||||||
`__init__.cpython-38m.so` by compiling it (create a virtualenv and run
|
`__init__.cpython-38m.so` by compiling it (create a virtualenv and run
|
||||||
`setup.py install`.
|
`setup.py install`.
|
||||||
|
|
||||||
This is also why this test only runs on certain systems and Python 3.8.
|
This is also why this test only runs on certain systems and a specific
|
||||||
|
Python version.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
project = jedi.Project(get_example_dir(), load_unsafe_extensions=load_unsafe_extensions)
|
project = jedi.Project(get_example_dir(), load_unsafe_extensions=load_unsafe_extensions)
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ def test_goto_stubs_on_itself(Script, code, type_):
|
|||||||
|
|
||||||
def test_module_exists_only_as_stub(Script):
|
def test_module_exists_only_as_stub(Script):
|
||||||
try:
|
try:
|
||||||
import redis # noqa: F401
|
import redis # type: ignore[import-untyped] # noqa: F401
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ def test_find_module_basic():
|
|||||||
|
|
||||||
def test_find_module_package():
|
def test_find_module_package():
|
||||||
file_io, is_package = _find_module('json')
|
file_io, is_package = _find_module('json')
|
||||||
assert file_io.path.parts[-2:] == ('json', '__init__.py')
|
assert file_io.path.parts[-2:] == ('json', '__init__.py') # type: ignore[union-attr]
|
||||||
assert is_package is True
|
assert is_package is True
|
||||||
|
|
||||||
|
|
||||||
def test_find_module_not_package():
|
def test_find_module_not_package():
|
||||||
file_io, is_package = _find_module('io')
|
file_io, is_package = _find_module('io')
|
||||||
assert file_io.path.name == 'io.py'
|
assert file_io.path.name == 'io.py' # type: ignore[union-attr]
|
||||||
assert is_package is False
|
assert is_package is False
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,10 +56,10 @@ def test_generics_methods(code, expected, class_findable):
|
|||||||
class Reader(Generic[T]):
|
class Reader(Generic[T]):
|
||||||
@classmethod
|
@classmethod
|
||||||
def read(cls) -> T:
|
def read(cls) -> T:
|
||||||
return cls()
|
return cls() # type: ignore[return-value]
|
||||||
|
|
||||||
def method(self) -> T:
|
def method(self) -> T:
|
||||||
return 1
|
return 1 # type: ignore[return-value]
|
||||||
|
|
||||||
class Foo(Reader[str]):
|
class Foo(Reader[str]):
|
||||||
def transform(self) -> int:
|
def transform(self) -> int:
|
||||||
@@ -94,7 +94,7 @@ def test_signature():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
from inspect import Signature, Parameter
|
from inspect import Signature, Parameter
|
||||||
some_signature.__signature__ = Signature([
|
some_signature.__signature__ = Signature([ # type: ignore[attr-defined]
|
||||||
Parameter('bar', kind=Parameter.KEYWORD_ONLY, default=1)
|
Parameter('bar', kind=Parameter.KEYWORD_ONLY, default=1)
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ def test_signature():
|
|||||||
def test_compiled_signature_annotation_string():
|
def test_compiled_signature_annotation_string():
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
def func(x: typing.Type, y: typing.Union[typing.Type, int]):
|
def func(x: typing.Type, y: typing.Union[typing.Type, int]): # type: ignore[type-arg]
|
||||||
pass
|
pass
|
||||||
func.__name__ = 'not_func'
|
func.__name__ = 'not_func'
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from textwrap import dedent
|
|||||||
from operator import eq, ge, lt
|
from operator import eq, ge, lt
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -405,7 +406,7 @@ def test_wraps_signature(Script, code, signature):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_dataclass_signature(
|
def test_dataclass_signature(
|
||||||
Script, skip_pre_python37, start, start_params, include_params, environment
|
Script, start, start_params, include_params, environment
|
||||||
):
|
):
|
||||||
if environment.version_info < (3, 8):
|
if environment.version_info < (3, 8):
|
||||||
# Final is not yet supported
|
# Final is not yet supported
|
||||||
@@ -448,7 +449,7 @@ def test_dataclass_signature(
|
|||||||
assert price.name == price_type_infer
|
assert price.name == price_type_infer
|
||||||
|
|
||||||
|
|
||||||
dataclass_transform_cases = [
|
dataclass_transform_cases: list[Any] = [
|
||||||
# Attributes on the decorated class and its base classes
|
# Attributes on the decorated class and its base classes
|
||||||
# are not considered to be fields.
|
# are not considered to be fields.
|
||||||
# 1/ Declare dataclass transformer
|
# 1/ Declare dataclass transformer
|
||||||
@@ -724,7 +725,7 @@ ids = [
|
|||||||
'start, start_params, include_params', dataclass_transform_cases, ids=ids
|
'start, start_params, include_params', dataclass_transform_cases, ids=ids
|
||||||
)
|
)
|
||||||
def test_extensions_dataclass_transform_signature(
|
def test_extensions_dataclass_transform_signature(
|
||||||
Script, skip_pre_python37, start, start_params, include_params, environment
|
Script, start, start_params, include_params, environment
|
||||||
):
|
):
|
||||||
has_typing_ext = bool(Script('import typing_extensions').infer())
|
has_typing_ext = bool(Script('import typing_extensions').infer())
|
||||||
if not has_typing_ext:
|
if not has_typing_ext:
|
||||||
@@ -845,7 +846,7 @@ def test_dataclass_transform_signature(
|
|||||||
],
|
],
|
||||||
ids=["define", "frozen", "define_customized", "define_subclass", "define_both"]
|
ids=["define", "frozen", "define_customized", "define_subclass", "define_both"]
|
||||||
)
|
)
|
||||||
def test_attrs_signature(Script, skip_pre_python37, start, start_params):
|
def test_attrs_signature(Script, start, start_params):
|
||||||
has_attrs = bool(Script('import attrs').infer())
|
has_attrs = bool(Script('import attrs').infer())
|
||||||
if not has_attrs:
|
if not has_attrs:
|
||||||
raise pytest.skip("attrs needed in target environment to run this test")
|
raise pytest.skip("attrs needed in target environment to run this test")
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ def test_hex_values_in_docstring():
|
|||||||
('lambda x, y, z: x + y * z\n', '<lambda>(x, y, z)')
|
('lambda x, y, z: x + y * z\n', '<lambda>(x, y, z)')
|
||||||
])
|
])
|
||||||
def test_get_signature(code, signature):
|
def test_get_signature(code, signature):
|
||||||
node = parse(code, version='3.8').children[0]
|
node = parse(code, version='3.14').children[0]
|
||||||
if node.type == 'simple_stmt':
|
if node.type == 'simple_stmt':
|
||||||
node = node.children[0]
|
node = node.children[0]
|
||||||
assert parser_utils.get_signature(node) == signature
|
assert parser_utils.get_signature(node) == signature
|
||||||
|
|||||||
+8
-6
@@ -1,7 +1,9 @@
|
|||||||
|
from typing import Any
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import readline
|
import readline
|
||||||
except ImportError:
|
except ImportError:
|
||||||
readline = False
|
readline = False # type: ignore[assignment]
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from jedi import utils
|
from jedi import utils
|
||||||
@@ -15,7 +17,7 @@ class TestSetupReadline(unittest.TestCase):
|
|||||||
def setUp(self, *args, **kwargs):
|
def setUp(self, *args, **kwargs):
|
||||||
super().setUp(*args, **kwargs)
|
super().setUp(*args, **kwargs)
|
||||||
|
|
||||||
self.namespace = self.NameSpace()
|
self.namespace: Any = self.NameSpace()
|
||||||
utils.setup_readline(self.namespace)
|
utils.setup_readline(self.namespace)
|
||||||
|
|
||||||
def complete(self, text):
|
def complete(self, text):
|
||||||
@@ -47,8 +49,8 @@ class TestSetupReadline(unittest.TestCase):
|
|||||||
def test_modules(self):
|
def test_modules(self):
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
self.namespace.sys = sys
|
self.namespace.sys = sys # type: ignore[attr-defined]
|
||||||
self.namespace.os = os
|
self.namespace.os = os # type: ignore[attr-defined]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
assert self.complete('os.path.join') == ['os.path.join']
|
assert self.complete('os.path.join') == ['os.path.join']
|
||||||
@@ -58,8 +60,8 @@ class TestSetupReadline(unittest.TestCase):
|
|||||||
c = {'os.' + d for d in dir(os) if d.startswith('ch')}
|
c = {'os.' + d for d in dir(os) if d.startswith('ch')}
|
||||||
assert set(self.complete('os.ch')) == set(c)
|
assert set(self.complete('os.ch')) == set(c)
|
||||||
finally:
|
finally:
|
||||||
del self.namespace.sys
|
del self.namespace.sys # type: ignore[attr-defined]
|
||||||
del self.namespace.os
|
del self.namespace.os # type: ignore[attr-defined]
|
||||||
|
|
||||||
def test_calls(self):
|
def test_calls(self):
|
||||||
s = 'str(bytes'
|
s = 'str(bytes'
|
||||||
|
|||||||
Reference in New Issue
Block a user