mirror of
https://github.com/davidhalter/jedi.git
synced 2026-04-27 12:31:26 +08:00
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:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, windows-2022]
|
||||
python-version: ["3.13", "3.12", "3.11", "3.10", "3.9", "3.8"]
|
||||
environment: ['3.8', '3.13', '3.12', '3.11', '3.10', '3.9', 'interpreter']
|
||||
python-version: ["3.13", "3.12", "3.11", "3.10"]
|
||||
environment: ['3.13', '3.12', '3.11', '3.10', 'interpreter']
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
allow-prereleases: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: 'pip install .[testing]'
|
||||
run: 'pip install .[dev]'
|
||||
|
||||
- name: Run tests
|
||||
run: python -m pytest
|
||||
@@ -43,12 +43,12 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: 'pip install .[qa]'
|
||||
run: 'pip install .[dev]'
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
python -m flake8 jedi test setup.py
|
||||
python -m mypy jedi sith.py setup.py
|
||||
zuban check
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: 'pip install .[testing] coverage'
|
||||
run: 'pip install .[dev] coverage'
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
|
||||
+2
-2
@@ -14,8 +14,8 @@ sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
os: ubuntu-24.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
python: "3.14"
|
||||
apt_packages:
|
||||
- graphviz
|
||||
|
||||
+3
-3
@@ -102,7 +102,7 @@ Features and Limitations
|
||||
Jedi's features are listed here:
|
||||
`Features <https://jedi.readthedocs.org/en/latest/docs/features.html>`_.
|
||||
|
||||
You can run Jedi on 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
|
||||
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
|
||||
very well.
|
||||
@@ -183,10 +183,10 @@ The test suite uses ``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::
|
||||
|
||||
python3.8 -m pytest
|
||||
python3.14 -m pytest
|
||||
|
||||
For more detailed information visit the `testing documentation
|
||||
<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.")
|
||||
|
||||
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',
|
||||
help="Don't use subprocesses to guarantee having safe "
|
||||
"code execution. Useful for debugging.")
|
||||
@@ -133,11 +133,13 @@ def goto_or_help(request, Script):
|
||||
|
||||
@pytest.fixture(scope='session', params=['goto', 'help', 'infer'])
|
||||
def goto_or_help_or_infer(request, Script):
|
||||
def do(code, *args, **kwargs):
|
||||
return getattr(Script(code), request.param)(*args, **kwargs)
|
||||
class GotoOrHelpOrInfer:
|
||||
def __call__(self, code, *args, **kwargs):
|
||||
return getattr(Script(code), request.param)(*args, **kwargs)
|
||||
|
||||
do.type = request.param
|
||||
return do
|
||||
type = request.param
|
||||
|
||||
return GotoOrHelpOrInfer()
|
||||
|
||||
|
||||
@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
|
||||
# they should for all Python versions.
|
||||
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'''
|
||||
>>> script = jedi.Script(code, path='example.py')
|
||||
>>> 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
|
||||
[<Completion: load>, <Completion: loads>]
|
||||
|
||||
@@ -16,7 +16,7 @@ Jedi's main API calls and features are:
|
||||
Basic Features
|
||||
--------------
|
||||
|
||||
- Python 3.8+ support
|
||||
- Python 3.10+ support
|
||||
- Ignores syntax errors and wrong indentation
|
||||
- Can deal with complex module / function / class structures
|
||||
- Great ``virtualenv``/``venv`` support
|
||||
|
||||
@@ -7,10 +7,10 @@ The test suite depends on ``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::
|
||||
|
||||
python3.8 -m pytest
|
||||
python3.14 -m pytest
|
||||
|
||||
Tests are also run automatically on `GitHub 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
|
||||
--------------
|
||||
----------------
|
||||
|
||||
- `jedi-language-server <https://github.com/pappasam/jedi-language-server>`_
|
||||
- `python-language-server <https://github.com/palantir/python-language-server>`_ (currently unmaintained)
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ class BaseName:
|
||||
@property
|
||||
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()
|
||||
if module.is_stub() or not module.is_compiled():
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import re
|
||||
from textwrap import dedent
|
||||
from typing import Any
|
||||
from inspect import Parameter
|
||||
|
||||
from parso.python.token import PythonTokenTypes
|
||||
@@ -265,7 +266,7 @@ class Completion:
|
||||
elif type_ == 'for_stmt':
|
||||
allowed_transitions.append('else')
|
||||
|
||||
completion_names = []
|
||||
completion_names: list[Any] = []
|
||||
|
||||
kwargs_only = False
|
||||
if any(t in allowed_transitions for t in (PythonTokenTypes.NAME,
|
||||
|
||||
+29
-25
@@ -8,7 +8,7 @@ import hashlib
|
||||
import filecmp
|
||||
from collections import namedtuple
|
||||
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.inference.compiled.subprocess import CompiledSubprocess, \
|
||||
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
|
||||
|
||||
_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']
|
||||
_CONDA_VAR = 'CONDA_PREFIX'
|
||||
_CURRENT_VERSION = '%s.%s' % (sys.version_info.major, sys.version_info.minor)
|
||||
@@ -36,6 +36,9 @@ class InvalidPythonEnvironment(Exception):
|
||||
|
||||
|
||||
class _BaseEnvironment:
|
||||
version_info: Any
|
||||
executable: Any
|
||||
|
||||
@memoize_method
|
||||
def get_grammar(self):
|
||||
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
|
||||
# compare them.
|
||||
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 environment
|
||||
|
||||
@@ -355,7 +358,7 @@ def get_system_environment(version, *, env_vars=None):
|
||||
return SameEnvironment()
|
||||
return Environment(exe)
|
||||
|
||||
if os.name == 'nt':
|
||||
if sys.platform == "win32":
|
||||
for exe in _get_executables_from_windows_registry(version):
|
||||
try:
|
||||
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.
|
||||
"""
|
||||
|
||||
if os.name == 'nt':
|
||||
if sys.platform == "win32":
|
||||
pythons = [os.path.join(path, 'Scripts', 'python.exe'), os.path.join(path, 'python.exe')]
|
||||
else:
|
||||
pythons = [os.path.join(path, 'bin', 'python')]
|
||||
@@ -397,27 +400,28 @@ def _get_executable_path(path, safe=True):
|
||||
return python
|
||||
|
||||
|
||||
def _get_executables_from_windows_registry(version):
|
||||
import winreg
|
||||
if sys.platform == "win32":
|
||||
def _get_executables_from_windows_registry(version):
|
||||
import winreg
|
||||
|
||||
# TODO: support Python Anaconda.
|
||||
sub_keys = [
|
||||
r'SOFTWARE\Python\PythonCore\{version}\InstallPath',
|
||||
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath',
|
||||
r'SOFTWARE\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 sub_key in sub_keys:
|
||||
sub_key = sub_key.format(version=version)
|
||||
try:
|
||||
with winreg.OpenKey(root_key, sub_key) as key:
|
||||
prefix = winreg.QueryValueEx(key, '')[0]
|
||||
exe = os.path.join(prefix, 'python.exe')
|
||||
if os.path.isfile(exe):
|
||||
yield exe
|
||||
except WindowsError:
|
||||
pass
|
||||
# TODO: support Python Anaconda.
|
||||
sub_keys = [
|
||||
r'SOFTWARE\Python\PythonCore\{version}\InstallPath',
|
||||
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath',
|
||||
r'SOFTWARE\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 sub_key in sub_keys:
|
||||
sub_key = sub_key.format(version=version)
|
||||
try:
|
||||
with winreg.OpenKey(root_key, sub_key) as key:
|
||||
prefix = winreg.QueryValueEx(key, '')[0]
|
||||
exe = os.path.join(prefix, 'python.exe')
|
||||
if os.path.isfile(exe):
|
||||
yield exe
|
||||
except WindowsError:
|
||||
pass
|
||||
|
||||
|
||||
def _assert_safe(executable_path, safe):
|
||||
|
||||
@@ -41,7 +41,7 @@ def imitate_pydoc(string):
|
||||
|
||||
try:
|
||||
# is a tuple now
|
||||
label, related = string
|
||||
label, related = string # type: ignore[misc]
|
||||
except TypeError:
|
||||
return ''
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ just use IPython instead::
|
||||
Then you will be able to use Jedi completer in your Python interpreter::
|
||||
|
||||
$ 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
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> import os
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ def time_cache(seconds):
|
||||
cache[key] = time.time(), result
|
||||
return result
|
||||
|
||||
wrapper.clear_cache = lambda: cache.clear()
|
||||
wrapper.clear_cache = lambda: cache.clear() # type: ignore[attr-defined]
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ try:
|
||||
# pytest resets the stream at the end - causes troubles. Since
|
||||
# after every output the stream is reset automatically we don't
|
||||
# need this.
|
||||
initialise.atexit_done = True
|
||||
initialise.atexit_done = True # type: ignore[attr-defined]
|
||||
try:
|
||||
init(strip=False)
|
||||
except Exception:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from parso import file_io
|
||||
|
||||
@@ -58,6 +59,8 @@ class FolderIO(AbstractFolderIO):
|
||||
|
||||
|
||||
class FileIOFolderMixin:
|
||||
path: Any
|
||||
|
||||
def get_parent_folder(self):
|
||||
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
|
||||
that are not used are just being ignored.
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
import parso
|
||||
from jedi.file_io import FileIO
|
||||
|
||||
@@ -82,6 +84,8 @@ from jedi.plugins import plugin_manager
|
||||
|
||||
|
||||
class InferenceState:
|
||||
analysis_modules: "list[Any]"
|
||||
|
||||
def __init__(self, project, environment=None, script_path=None):
|
||||
if environment is None:
|
||||
environment = project.get_environment()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import re
|
||||
from itertools import zip_longest
|
||||
from typing import Any
|
||||
|
||||
from parso.python import tree
|
||||
|
||||
@@ -134,7 +135,7 @@ class _AbstractArgumentsMixin:
|
||||
|
||||
class AbstractArguments(_AbstractArgumentsMixin):
|
||||
context = None
|
||||
argument_node = None
|
||||
argument_node: Any = None
|
||||
trailer = None
|
||||
|
||||
|
||||
@@ -164,6 +165,8 @@ def unpack_arglist(arglist):
|
||||
|
||||
|
||||
class TreeArguments(AbstractArguments):
|
||||
context: Any
|
||||
|
||||
def __init__(self, inference_state, context, argument_node, trailer=None):
|
||||
"""
|
||||
:param argument_node: May be an argument_node or a list of nodes.
|
||||
|
||||
@@ -9,6 +9,7 @@ just one.
|
||||
from functools import reduce
|
||||
from operator import add
|
||||
from itertools import zip_longest
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from parso.python.tree import Name
|
||||
|
||||
@@ -21,12 +22,25 @@ from jedi.cache import memoize_method
|
||||
|
||||
sentinel = object()
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from jedi.inference import InferenceState
|
||||
|
||||
|
||||
class HasNoContext(Exception):
|
||||
pass
|
||||
|
||||
|
||||
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):
|
||||
value = self
|
||||
if value.parent_context is None:
|
||||
@@ -337,11 +351,16 @@ class _ValueWrapperBase(HelperValueMixin):
|
||||
|
||||
|
||||
class LazyValueWrapper(_ValueWrapperBase):
|
||||
@safe_property
|
||||
@memoize_method
|
||||
def _wrapped_value(self):
|
||||
with debug.increase_indent_cm('Resolve lazy value wrapper'):
|
||||
return self._get_wrapped_value()
|
||||
if TYPE_CHECKING:
|
||||
@property
|
||||
def _wrapped_value(self) -> Any:
|
||||
return
|
||||
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):
|
||||
return '<%s>' % (self.__class__.__name__)
|
||||
@@ -499,7 +518,7 @@ class ValueSet:
|
||||
return ValueSet.from_sets(_getitem(c, *args, **kwargs) for c in self._set)
|
||||
|
||||
def try_merge(self, function_name):
|
||||
value_set = self.__class__([])
|
||||
value_set = ValueSet([])
|
||||
for c in self._set:
|
||||
try:
|
||||
method = getattr(c, function_name)
|
||||
|
||||
@@ -39,7 +39,7 @@ def _is_type(obj):
|
||||
|
||||
|
||||
def _shadowed_dict(klass):
|
||||
dict_attr = type.__dict__["__dict__"]
|
||||
dict_attr = type.__dict__["__dict__"] # type: ignore[index]
|
||||
for entry in _static_getmro(klass):
|
||||
try:
|
||||
class_dict = dict_attr.__get__(entry)["__dict__"]
|
||||
@@ -54,7 +54,7 @@ def _shadowed_dict(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)):
|
||||
# There are unfortunately no tests for this, I was not able to
|
||||
# reproduce this in pure Python. However should still solve the issue
|
||||
|
||||
@@ -33,7 +33,7 @@ import traceback
|
||||
import weakref
|
||||
from functools import partial
|
||||
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 import debug
|
||||
@@ -52,7 +52,7 @@ PICKLE_PROTOCOL = 4
|
||||
|
||||
|
||||
def _GeneralizedPopen(*args, **kwargs):
|
||||
if os.name == 'nt':
|
||||
if sys.platform == "win32":
|
||||
try:
|
||||
# Was introduced in Python 3.7.
|
||||
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW
|
||||
@@ -104,6 +104,8 @@ def _cleanup_process(process, thread):
|
||||
|
||||
|
||||
class _InferenceStateProcess:
|
||||
get_compiled_method_return: Any
|
||||
|
||||
def __init__(self, inference_state: 'InferenceState') -> None:
|
||||
self._inference_state_weakref = weakref.ref(inference_state)
|
||||
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:
|
||||
# This is a namespace package.
|
||||
full_name = string if not path else full_name
|
||||
implicit_ns_info = ImplicitNSInfo(full_name, spec.submodule_search_locations._path)
|
||||
implicit_ns_info = ImplicitNSInfo(
|
||||
full_name,
|
||||
spec.submodule_search_locations._path, # type: ignore[union-attr]
|
||||
)
|
||||
return implicit_ns_info, True
|
||||
break
|
||||
|
||||
|
||||
@@ -592,7 +592,7 @@ def create_from_name(inference_state, compiled_value, name):
|
||||
value = create_cached_compiled_value(
|
||||
inference_state,
|
||||
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
|
||||
|
||||
@@ -610,7 +610,7 @@ def create_from_access_path(inference_state, access_path):
|
||||
value = create_cached_compiled_value(
|
||||
inference_state,
|
||||
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
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from abc import abstractmethod
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Optional, Any
|
||||
|
||||
from parso.python.tree import Name
|
||||
|
||||
@@ -16,6 +16,8 @@ from jedi import parser_utils
|
||||
|
||||
class AbstractContext:
|
||||
# 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):
|
||||
self.inference_state = inference_state
|
||||
@@ -218,6 +220,13 @@ class ValueContext(AbstractContext):
|
||||
|
||||
|
||||
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):
|
||||
from jedi.inference.syntax_tree import infer_node
|
||||
return infer_node(self, node)
|
||||
@@ -300,7 +309,6 @@ class TreeContextMixin:
|
||||
class FunctionContext(TreeContextMixin, ValueContext):
|
||||
def get_filters(self, until_position=None, origin_scope=None):
|
||||
yield ParserTreeFilter(
|
||||
self.inference_state,
|
||||
parent_context=self,
|
||||
until_position=until_position,
|
||||
origin_scope=origin_scope
|
||||
|
||||
@@ -16,6 +16,6 @@ class DocstringModuleContext(ModuleContext):
|
||||
super().__init__(module_value)
|
||||
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 self._in_module_context.get_filters()
|
||||
|
||||
@@ -109,7 +109,7 @@ def _search_function_arguments(module_context, funcdef, string_name):
|
||||
if string_name == '__init__':
|
||||
cls = get_parent_scope(funcdef)
|
||||
if cls.type == 'classdef':
|
||||
string_name = cls.name.value
|
||||
string_name = cls.name.value # type: ignore[union-attr]
|
||||
compare_node = cls
|
||||
|
||||
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
|
||||
# parameter. It's not very generic though. Should find a better
|
||||
# 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:
|
||||
continue
|
||||
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.
|
||||
"""
|
||||
from abc import abstractmethod
|
||||
from typing import List, MutableMapping, Type
|
||||
from typing import MutableMapping, Type, Any
|
||||
import weakref
|
||||
|
||||
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, \
|
||||
AnonymousParamName, AbstractNameDefinition, NameWrapper
|
||||
|
||||
_definition_name_cache: MutableMapping[UsedNamesMapping, List[Name]]
|
||||
_definition_name_cache = weakref.WeakKeyDictionary()
|
||||
_definition_name_cache: 'MutableMapping[UsedNamesMapping, dict[str, tuple[Name, ...]]]' \
|
||||
= weakref.WeakKeyDictionary()
|
||||
|
||||
|
||||
class AbstractFilter:
|
||||
@@ -346,6 +346,9 @@ class _OverwriteMeta(type):
|
||||
|
||||
|
||||
class _AttributeOverwriteMixin:
|
||||
overwritten_methods: Any
|
||||
_wrapped_value: Any
|
||||
|
||||
def get_filters(self, *args, **kwargs):
|
||||
yield SpecialMethodFilter(self, self.overwritten_methods, self._wrapped_value)
|
||||
yield from self._wrapped_value.get_filters(*args, **kwargs)
|
||||
|
||||
@@ -195,7 +195,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
|
||||
|
||||
@to_list
|
||||
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)
|
||||
|
||||
def _create_instance_with_generics(self, generics_manager):
|
||||
@@ -384,7 +384,7 @@ class BaseTypingValue(LazyValueWrapper):
|
||||
return _PseudoTreeNameClass(self.parent_context, self._tree_name)
|
||||
|
||||
def get_signatures(self):
|
||||
return self._wrapped_value.get_signatures()
|
||||
return self._wrapped_value.get_signatures() # type: ignore[attr-defined]
|
||||
|
||||
def __repr__(self):
|
||||
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
|
||||
the Generic class.
|
||||
"""
|
||||
from abc import abstractmethod
|
||||
|
||||
from jedi import debug
|
||||
from jedi.cache import memoize_method
|
||||
@@ -24,6 +25,14 @@ def _resolve_forward_references(context, value_set):
|
||||
|
||||
|
||||
class _AbstractGenericManager:
|
||||
@abstractmethod
|
||||
def __getitem__(self, index):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def to_tuple(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_index_and_execute(self, index):
|
||||
try:
|
||||
return self[index].execute_annotation()
|
||||
|
||||
@@ -6,6 +6,7 @@ values.
|
||||
This file deals with all the typing.py cases.
|
||||
"""
|
||||
import itertools
|
||||
from typing import Any
|
||||
|
||||
from jedi import debug
|
||||
from jedi.inference.compiled import builtin_from_name, create_simple_object
|
||||
@@ -186,6 +187,8 @@ class ProxyTypingValue(BaseTypingValue):
|
||||
|
||||
|
||||
class _TypingClassMixin(ClassMixin):
|
||||
_tree_name: Any
|
||||
|
||||
def py__bases__(self):
|
||||
return [LazyKnownValues(
|
||||
self.inference_state.builtins_module.py__getattribute__('object')
|
||||
|
||||
@@ -5,12 +5,12 @@ import os
|
||||
from itertools import chain
|
||||
from contextlib import contextmanager
|
||||
|
||||
from parso.python import tree
|
||||
from parso import tree
|
||||
|
||||
|
||||
def is_stdlib_path(path):
|
||||
# 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.
|
||||
parts = path.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
|
||||
for i in import_names
|
||||
)
|
||||
value_set = [None]
|
||||
base = [None]
|
||||
for i, name in enumerate(import_names):
|
||||
value_set = ValueSet.from_sets([
|
||||
base = value_set = ValueSet.from_sets([
|
||||
import_module(
|
||||
inference_state,
|
||||
str_import_names[:i+1],
|
||||
parent_module_value,
|
||||
sys_path,
|
||||
prefer_stubs=prefer_stubs,
|
||||
) for parent_module_value in value_set
|
||||
prefer_stubs=prefer_stubs, # type: ignore[call-arg]
|
||||
) for parent_module_value in base
|
||||
])
|
||||
if not value_set:
|
||||
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
|
||||
if sys_path is None:
|
||||
sys_path = inference_state.get_sys_path()
|
||||
|
||||
+21
-10
@@ -1,9 +1,8 @@
|
||||
from abc import abstractmethod
|
||||
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.inference.utils import unite
|
||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||
from jedi.inference.cache import inference_state_method_cache
|
||||
from jedi.inference import docstrings
|
||||
@@ -37,7 +36,6 @@ class AbstractNameDefinition:
|
||||
def infer(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def goto(self):
|
||||
# Typically names are already definitions and therefore a goto on that
|
||||
# name will always result on itself.
|
||||
@@ -105,6 +103,9 @@ class AbstractArbitraryName(AbstractNameDefinition):
|
||||
|
||||
|
||||
class AbstractTreeName(AbstractNameDefinition):
|
||||
tree_name: Any
|
||||
parent_context: Any
|
||||
|
||||
def __init__(self, parent_context, tree_name):
|
||||
self.parent_context = parent_context
|
||||
self.tree_name = tree_name
|
||||
@@ -194,10 +195,11 @@ class AbstractTreeName(AbstractNameDefinition):
|
||||
new_dotted = deep_ast_copy(par)
|
||||
new_dotted.children[index - 1:] = []
|
||||
values = context.infer_node(new_dotted)
|
||||
return unite(
|
||||
value.goto(name, name_context=context)
|
||||
return [
|
||||
n
|
||||
for value in values
|
||||
)
|
||||
for n in value.goto(name, name_context=context)
|
||||
]
|
||||
|
||||
if node_type == 'trailer' and par.children[0] == '.':
|
||||
values = infer_call_of_leaf(context, name, cut_own_trailer=True)
|
||||
@@ -222,6 +224,9 @@ class AbstractTreeName(AbstractNameDefinition):
|
||||
|
||||
|
||||
class ValueNameMixin:
|
||||
_value: Any
|
||||
parent_context: Any
|
||||
|
||||
def infer(self):
|
||||
return ValueSet([self._value])
|
||||
|
||||
@@ -240,7 +245,7 @@ class ValueNameMixin:
|
||||
def get_root_context(self):
|
||||
if self.parent_context is None: # A module
|
||||
return self._value.as_context()
|
||||
return super().get_root_context()
|
||||
return super().get_root_context() # type: ignore
|
||||
|
||||
def get_defining_qualified_value(self):
|
||||
context = self.parent_context
|
||||
@@ -357,14 +362,16 @@ class TreeNameDefinition(AbstractTreeName):
|
||||
|
||||
|
||||
class _ParamMixin:
|
||||
get_kind: Any
|
||||
|
||||
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:
|
||||
options.append(Parameter.VAR_POSITIONAL)
|
||||
return self.get_kind() in options
|
||||
|
||||
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:
|
||||
options.append(Parameter.VAR_KEYWORD)
|
||||
return self.get_kind() in options
|
||||
@@ -629,6 +636,10 @@ class NameWrapper:
|
||||
|
||||
|
||||
class StubNameMixin:
|
||||
api_type: str
|
||||
tree_name: Any
|
||||
infer: Any
|
||||
|
||||
def py__doc__(self):
|
||||
from jedi.inference.gradual.conversion import convert_names
|
||||
# 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)
|
||||
if self in names:
|
||||
return super().py__doc__()
|
||||
return super().py__doc__() # type: ignore
|
||||
else:
|
||||
# We have signatures ourselves in stubs, so don't use signatures
|
||||
# from the implementation.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from inspect import Parameter
|
||||
from typing import Any
|
||||
|
||||
from jedi.cache import memoize_method
|
||||
from jedi import debug
|
||||
@@ -6,6 +7,10 @@ from jedi import parser_utils
|
||||
|
||||
|
||||
class _SignatureMixin:
|
||||
get_param_names: Any
|
||||
name: Any
|
||||
annotation_string: Any
|
||||
|
||||
def to_string(self):
|
||||
def param_strings():
|
||||
is_positional = False
|
||||
@@ -36,6 +41,8 @@ class _SignatureMixin:
|
||||
|
||||
|
||||
class AbstractSignature(_SignatureMixin):
|
||||
_function_value: Any
|
||||
|
||||
def __init__(self, value, is_bound=False):
|
||||
self.value = value
|
||||
self.is_bound = is_bound
|
||||
|
||||
@@ -89,6 +89,7 @@ def infer_node(context, element):
|
||||
if isinstance(context, CompForContext):
|
||||
return _infer_node(context, element)
|
||||
|
||||
name_dicts = [{}]
|
||||
if_stmt = element
|
||||
while if_stmt is not None:
|
||||
if_stmt = if_stmt.parent
|
||||
@@ -104,7 +105,6 @@ def infer_node(context, element):
|
||||
if predefined_if_name_dict is None and if_stmt \
|
||||
and if_stmt.type == 'if_stmt' and context.inference_state.is_analysis:
|
||||
if_stmt_test = if_stmt.children[1]
|
||||
name_dicts = [{}]
|
||||
# If we already did a check, we don't want to do it again -> If
|
||||
# value.predefined_names is filled, we stop.
|
||||
# We don't want to check the if stmt itself, it's just about
|
||||
|
||||
@@ -74,7 +74,6 @@ class PushBackIterator:
|
||||
def __init__(self, iterator):
|
||||
self.pushes = []
|
||||
self.iterator = iterator
|
||||
self.current = None
|
||||
|
||||
def push_back(self, value):
|
||||
self.pushes.append(value)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Any
|
||||
|
||||
from jedi import debug
|
||||
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass
|
||||
from jedi.inference import compiled
|
||||
@@ -53,6 +55,10 @@ class FunctionAndClassBase(TreeValue):
|
||||
|
||||
class FunctionMixin:
|
||||
api_type = 'function'
|
||||
tree_node: Any
|
||||
py__class__: Any
|
||||
as_context: Any
|
||||
get_signature_functions: Any
|
||||
|
||||
def get_filters(self, origin_scope=None):
|
||||
cls = self.py__class__()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from abc import abstractproperty
|
||||
from typing import Any
|
||||
|
||||
from jedi import debug
|
||||
from jedi import settings
|
||||
@@ -187,6 +188,9 @@ class CompiledInstance(AbstractInstanceValue):
|
||||
|
||||
|
||||
class _BaseTreeInstance(AbstractInstanceValue):
|
||||
get_defined_names: Any
|
||||
_arguments: Any
|
||||
|
||||
@property
|
||||
def array_type(self):
|
||||
name = self.class_value.py__name__()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
Contains all classes and functions to deal with lists, dicts, generators and
|
||||
iterators in general.
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
from jedi.inference import compiled
|
||||
from jedi.inference import analysis
|
||||
from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues, \
|
||||
@@ -20,6 +22,9 @@ from jedi.inference.value.dynamic_arrays import check_array_additions
|
||||
|
||||
|
||||
class IterableMixin:
|
||||
py__iter__: Any
|
||||
inference_state: Any
|
||||
|
||||
def py__next__(self, contextualized_node=None):
|
||||
return self.py__iter__(contextualized_node)
|
||||
|
||||
@@ -128,6 +133,12 @@ def comprehension_from_atom(inference_state, value, atom):
|
||||
|
||||
|
||||
class ComprehensionMixin:
|
||||
_defining_context: Any
|
||||
_entry_node: Any
|
||||
array_type: Any
|
||||
_value_node: Any
|
||||
_sync_comp_for_node: Any
|
||||
|
||||
@inference_state_method_cache()
|
||||
def _get_comp_for_context(self, parent_context, comp_for):
|
||||
return CompForContext(parent_context, comp_for)
|
||||
@@ -176,6 +187,8 @@ class ComprehensionMixin:
|
||||
|
||||
|
||||
class _DictMixin:
|
||||
get_mapping_item_values: Any
|
||||
|
||||
def _get_generics(self):
|
||||
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):
|
||||
def __init__(self, inference_state, defining_context, sync_comp_for_node, entry_node):
|
||||
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._sync_comp_for_node = sync_comp_for_node
|
||||
self._entry_node = entry_node
|
||||
@@ -248,6 +261,9 @@ class GeneratorComprehension(_BaseComprehension, GeneratorBase):
|
||||
|
||||
|
||||
class _DictKeyMixin:
|
||||
_dict_keys: Any
|
||||
_dict_values: Any
|
||||
|
||||
# TODO merge with _DictMixin?
|
||||
def get_mapping_item_values(self):
|
||||
return self._dict_keys(), self._dict_values()
|
||||
|
||||
@@ -38,7 +38,7 @@ py__doc__() Returns the docstring for a value.
|
||||
"""
|
||||
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.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.signature import AbstractSignature
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from jedi.inference import InferenceState
|
||||
|
||||
|
||||
class ClassName(TreeNameDefinition):
|
||||
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:
|
||||
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):
|
||||
return True
|
||||
|
||||
@@ -682,6 +694,9 @@ class ClassValue(ClassMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
|
||||
"""
|
||||
bases_arguments = self._get_bases_arguments()
|
||||
|
||||
if bases_arguments is None:
|
||||
return None
|
||||
|
||||
if bases_arguments.argument_node.type != "arglist":
|
||||
# If it is not inheriting from the base model and having
|
||||
# extra parameters, then init behavior is not changed.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
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.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.context import ModuleContext
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from jedi.inference import InferenceState
|
||||
|
||||
|
||||
class _ModuleAttributeName(AbstractNameDefinition):
|
||||
"""
|
||||
@@ -35,6 +38,11 @@ class _ModuleAttributeName(AbstractNameDefinition):
|
||||
|
||||
|
||||
class SubModuleDictMixin:
|
||||
inference_state: "InferenceState"
|
||||
is_package: Any
|
||||
py__path__: Any
|
||||
as_context: Any
|
||||
|
||||
@inference_state_method_cache()
|
||||
def sub_modules_dict(self):
|
||||
"""
|
||||
@@ -57,6 +65,10 @@ class SubModuleDictMixin:
|
||||
|
||||
class ModuleMixin(SubModuleDictMixin):
|
||||
_module_name_class = ModuleName
|
||||
tree_node: Any
|
||||
string_names: Any
|
||||
sub_modules_dict: Any
|
||||
py__file__: Any
|
||||
|
||||
def get_filters(self, origin_scope=None):
|
||||
yield MergedFilter(
|
||||
|
||||
@@ -259,7 +259,7 @@ def get_parent_scope(node, include_flows=False):
|
||||
# the if, but the parent of the if.
|
||||
if not (scope.type == 'if_stmt'
|
||||
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
|
||||
|
||||
scope = scope.parent
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Module is used to infer Django model fields.
|
||||
"""
|
||||
from inspect import Parameter
|
||||
from typing import Any
|
||||
|
||||
from jedi import debug
|
||||
from jedi.inference.cache import inference_state_function_cache
|
||||
@@ -140,7 +141,7 @@ def _new_dict_filter(cls, is_instance):
|
||||
include_metaclasses=False,
|
||||
include_type_when_class=False)
|
||||
)
|
||||
dct = {
|
||||
dct: dict[str, Any] = {
|
||||
name.string_name: DjangoModelName(cls, name, is_instance)
|
||||
for filter_ in reversed(filters)
|
||||
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
|
||||
"""
|
||||
if sys.version_info >= (3, 8):
|
||||
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]
|
||||
from importlib.metadata import entry_points
|
||||
|
||||
if sys.version_info >= (3, 10):
|
||||
pytest_entry_points = entry_points(group="pytest11")
|
||||
else:
|
||||
from pkg_resources import iter_entry_points
|
||||
return [ep.module_name.split(".") for ep in iter_entry_points(group="pytest11")]
|
||||
pytest_entry_points = entry_points().get("pytest11", ())
|
||||
|
||||
return [ep.module.split(".") for ep in pytest_entry_points]
|
||||
|
||||
|
||||
@inference_state_method_cache()
|
||||
@@ -192,7 +178,7 @@ def _iter_pytest_modules(module_context, skip_own_module=False):
|
||||
folder = folder.get_parent_folder()
|
||||
|
||||
# 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
|
||||
last_folder = folder # keep track of the last found parent name
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ def execute(callback):
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
return func(value, arguments=arguments, callback=call)
|
||||
return func(value, arguments=arguments, callback=call) # type: ignore
|
||||
return call()
|
||||
|
||||
return wrapper
|
||||
|
||||
+12
-30
@@ -1,32 +1,14 @@
|
||||
[tool.mypy]
|
||||
# Exclude our copies of external stubs
|
||||
exclude = "^jedi/third_party"
|
||||
[tool.zuban]
|
||||
strict = true
|
||||
enable_error_code = ["ignore-without-code"]
|
||||
|
||||
show_error_codes = true
|
||||
enable_error_code = "ignore-without-code"
|
||||
|
||||
# Ensure generics are explicit about what they are (e.g: `List[str]` rather than
|
||||
# just `List`)
|
||||
disallow_any_generics = true
|
||||
|
||||
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"]
|
||||
# Revert some --strict specific flags:
|
||||
allow_untyped_calls = true
|
||||
allow_untyped_defs = true
|
||||
allow_incomplete_defs = true
|
||||
allow_untyped_globals = true
|
||||
untyped_strict_optional = false
|
||||
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 sys
|
||||
import os
|
||||
import psutil
|
||||
import psutil # type: ignore[import-untyped]
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/..'))
|
||||
import jedi
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ def main(args):
|
||||
run(code, i, infer=infer)
|
||||
|
||||
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'])
|
||||
if args['--omit']:
|
||||
|
||||
+2
-2
@@ -17,11 +17,11 @@ import sys
|
||||
try:
|
||||
import urllib.request as urllib2
|
||||
except ImportError:
|
||||
import urllib2
|
||||
import urllib2 # type: ignore[import-not-found, no-redef]
|
||||
import gc
|
||||
from os.path import abspath, dirname
|
||||
|
||||
import objgraph
|
||||
import objgraph # type: ignore[import-untyped]
|
||||
|
||||
sys.path.insert(0, dirname(dirname(abspath(__file__))))
|
||||
import jedi
|
||||
|
||||
@@ -35,11 +35,11 @@ setup(name='jedi',
|
||||
keywords='python completion refactoring vim',
|
||||
long_description=readme,
|
||||
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
|
||||
install_requires=['parso>=0.8.5,<0.9.0'],
|
||||
install_requires=['parso>=0.8.6,<0.9.0'],
|
||||
extras_require={
|
||||
'testing': [
|
||||
'dev': [
|
||||
'pytest<9.0.0',
|
||||
# docopt for sith doctests
|
||||
'docopt',
|
||||
@@ -48,42 +48,41 @@ setup(name='jedi',
|
||||
'Django',
|
||||
'attrs',
|
||||
'typing_extensions',
|
||||
],
|
||||
'qa': [
|
||||
# latest version on 2025-06-16
|
||||
'flake8==7.2.0',
|
||||
# latest version supporting Python 3.6
|
||||
'mypy==1.16',
|
||||
'flake8==7.1.2',
|
||||
'zuban==0.7.0',
|
||||
# Arbitrary pins, latest at the time of pinning
|
||||
'types-setuptools==80.9.0.20250529',
|
||||
],
|
||||
'docs': [
|
||||
# Just pin all of these.
|
||||
'Jinja2==2.11.3',
|
||||
'MarkupSafe==1.1.1',
|
||||
'Pygments==2.8.1',
|
||||
'alabaster==0.7.12',
|
||||
'babel==2.9.1',
|
||||
'chardet==4.0.0',
|
||||
'commonmark==0.8.1',
|
||||
'docutils==0.17.1',
|
||||
'future==0.18.2',
|
||||
'idna==2.10',
|
||||
'imagesize==1.2.0',
|
||||
'mock==1.0.1',
|
||||
'packaging==20.9',
|
||||
'pyparsing==2.4.7',
|
||||
'pytz==2021.1',
|
||||
'readthedocs-sphinx-ext==2.1.4',
|
||||
'recommonmark==0.5.0',
|
||||
'requests==2.25.1',
|
||||
'six==1.15.0',
|
||||
'snowballstemmer==2.1.0',
|
||||
'sphinx==1.8.5',
|
||||
'sphinx-rtd-theme==0.4.3',
|
||||
'sphinxcontrib-serializinghtml==1.1.4',
|
||||
'sphinxcontrib-websupport==1.2.4',
|
||||
'urllib3==1.26.4',
|
||||
'alabaster==1.0.0',
|
||||
'babel==2.18.0',
|
||||
'certifi==2026.4.22',
|
||||
'charset-normalizer==3.4.7',
|
||||
'docutils==0.22.4',
|
||||
'idna==3.13',
|
||||
'imagesize==2.0.0',
|
||||
'iniconfig==2.3.0',
|
||||
'Jinja2==3.1.6',
|
||||
'MarkupSafe==3.0.3',
|
||||
'packaging==26.2',
|
||||
'pluggy==1.6.0',
|
||||
'Pygments==2.20.0',
|
||||
'pytest==9.0.3',
|
||||
'requests==2.33.1',
|
||||
'roman-numerals==4.1.0',
|
||||
'snowballstemmer==3.0.1',
|
||||
'Sphinx==9.1.0',
|
||||
'sphinx_rtd_theme==3.1.0',
|
||||
'sphinxcontrib-applehelp==2.0.0',
|
||||
'sphinxcontrib-devhelp==2.0.0',
|
||||
'sphinxcontrib-htmlhelp==2.1.0',
|
||||
'sphinxcontrib-jquery==4.1',
|
||||
'sphinxcontrib-jsmath==1.0.1',
|
||||
'sphinxcontrib-qthelp==2.0.0',
|
||||
'sphinxcontrib-serializinghtml==2.0.0',
|
||||
'urllib3==2.6.3',
|
||||
],
|
||||
},
|
||||
package_data={'jedi': ['*.pyi', 'third_party/typeshed/LICENSE',
|
||||
@@ -96,8 +95,6 @@ setup(name='jedi',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
'Programming Language :: Python :: 3.12',
|
||||
|
||||
@@ -35,7 +35,6 @@ Usage:
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--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]
|
||||
-d, --debug Jedi print debugging when an error is raised.
|
||||
-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
|
||||
record = arguments['--record']
|
||||
|
||||
jedi.settings.use_filesystem_cache = arguments['--fs-cache']
|
||||
if arguments['--debug']:
|
||||
jedi.set_debug_function()
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# For assignment expressions / named expressions / walrus operators / whatever
|
||||
# they are called.
|
||||
|
||||
# python >= 3.8
|
||||
b = (a:=1, a)
|
||||
|
||||
#? int()
|
||||
|
||||
@@ -476,8 +476,6 @@ dynamic_annotation('')
|
||||
# TypeDict
|
||||
# -------------------------
|
||||
|
||||
# python >= 3.8
|
||||
|
||||
class Foo(typing.TypedDict):
|
||||
foo: str
|
||||
bar: typing.List[float]
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# python >= 3.9
|
||||
|
||||
from typing import 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):
|
||||
#? str()
|
||||
a
|
||||
|
||||
@@ -459,8 +459,6 @@ X().just_partial('')[0]
|
||||
#? str()
|
||||
X().just_partial('')[1]
|
||||
|
||||
# python >= 3.8
|
||||
|
||||
@functools.lru_cache
|
||||
def x() -> int: ...
|
||||
@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
|
||||
# path, which we definitely don't want. So just remove it globally.
|
||||
try:
|
||||
sys.path.remove(helpers.test_dir)
|
||||
sys.path.remove(str(helpers.test_dir))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import sys
|
||||
sys.path[0:0] = [
|
||||
'/usr/lib/python3.8/site-packages',
|
||||
'/usr/lib/python3.14/site-packages',
|
||||
'/tmp/.buildout/eggs/important_package.egg'
|
||||
]
|
||||
|
||||
|
||||
+3
-1
@@ -168,6 +168,8 @@ class BaseTestCase(object):
|
||||
|
||||
|
||||
class IntegrationTestCase(BaseTestCase):
|
||||
source: str # Defined as a side effect
|
||||
|
||||
def __init__(self, test_type, correct, line_nr, column, start, line,
|
||||
path=None, skip_version_info=None):
|
||||
super().__init__(skip_version_info)
|
||||
@@ -446,7 +448,7 @@ Options:
|
||||
--pdb Enable pdb debugging on fail.
|
||||
-d, --debug Enable text output debugging (please install ``colorama``).
|
||||
--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__':
|
||||
import docopt
|
||||
|
||||
@@ -523,7 +523,7 @@ def test_added_equals_to_params(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
|
||||
confusing.
|
||||
"""
|
||||
|
||||
@@ -3,6 +3,7 @@ import os
|
||||
from textwrap import dedent
|
||||
from itertools import count
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -301,7 +302,7 @@ def test_file_path_should_have_completions(Script):
|
||||
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[1]', 5, ['1', '50', Ellipsis]),
|
||||
|
||||
@@ -26,13 +26,13 @@ def test_find_system_environments():
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'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):
|
||||
try:
|
||||
env = get_system_environment(version)
|
||||
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
|
||||
raise
|
||||
pytest.skip()
|
||||
|
||||
@@ -15,6 +15,7 @@ There are three kinds of test:
|
||||
|
||||
import textwrap
|
||||
from unittest import TestCase
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -22,6 +23,8 @@ import jedi
|
||||
|
||||
|
||||
class MixinTestFullName(object):
|
||||
assertEqual: Any
|
||||
|
||||
operation = None
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
||||
@@ -78,7 +78,7 @@ def test_numpy_like_non_zero():
|
||||
|
||||
def test_nested_resolve():
|
||||
class XX:
|
||||
def x():
|
||||
def x(): # type: ignore[misc]
|
||||
pass
|
||||
|
||||
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
|
||||
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__)
|
||||
|
||||
# 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.
|
||||
if True:
|
||||
raise NotImplementedError()
|
||||
return index
|
||||
return index # type: ignore[unreachable]
|
||||
|
||||
foo = Foo2()
|
||||
_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)
|
||||
|
||||
def __dir__(self):
|
||||
return ['foo', 'fbar'] + object.__dir__(self)
|
||||
return ['foo', 'fbar'] + object.__dir__(self) # type: ignore[operator]
|
||||
|
||||
if not class_is_findable:
|
||||
CompleteGetattr.__name__ = "something_somewhere"
|
||||
@@ -388,7 +388,7 @@ def test_dir_magic_method(allow_unsafe_getattr):
|
||||
raise AttributeError(name)
|
||||
|
||||
def __dir__(self):
|
||||
return ['foo', 'bar'] + object.__dir__(self)
|
||||
return ['foo', 'bar'] + object.__dir__(self) # type: ignore[operator]
|
||||
|
||||
itp = jedi.Interpreter("ca.", [{'ca': CompleteAttrs()}])
|
||||
completions = itp.complete()
|
||||
@@ -410,7 +410,7 @@ def test_dir_magic_method(allow_unsafe_getattr):
|
||||
def test_name_not_findable():
|
||||
class X():
|
||||
if 0:
|
||||
NOT_FINDABLE # noqa: F821
|
||||
NOT_FINDABLE # type: ignore[unreachable] # noqa: F821
|
||||
|
||||
def hidden(self):
|
||||
return
|
||||
@@ -493,7 +493,7 @@ def test__wrapped__():
|
||||
|
||||
def test_illegal_class_instance():
|
||||
class X:
|
||||
__class__ = 1
|
||||
__class__ = 1 # type: ignore[assignment]
|
||||
X.__name__ = 'asdf'
|
||||
d, = jedi.Interpreter('foo', [{'foo': X()}]).infer()
|
||||
v, = d._name.infer()
|
||||
@@ -537,7 +537,7 @@ def test_partial_signatures(code, expected, index):
|
||||
|
||||
def test_type_var():
|
||||
"""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()
|
||||
assert def_.name == 'TypeVar'
|
||||
|
||||
@@ -576,7 +576,7 @@ def test_dict_completion(code, column, expected):
|
||||
strs = {'asdf': 1, """foo""": 2, r'fbar': 3}
|
||||
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
|
||||
inherited = Inherited(blablu=3)
|
||||
|
||||
@@ -624,10 +624,10 @@ def test_dunders(class_is_findable, code, expected, allow_unsafe_getattr):
|
||||
def __getitem__(self, key) -> int:
|
||||
return 1
|
||||
|
||||
def __iter__(self, key) -> Iterator[str]:
|
||||
def __iter__(self, key) -> Iterator[str]: # type: ignore[empty-body]
|
||||
pass
|
||||
|
||||
def __next__(self, key) -> float:
|
||||
def __next__(self, key) -> float: # type: ignore[empty-body]
|
||||
pass
|
||||
|
||||
if not class_is_findable:
|
||||
@@ -810,11 +810,11 @@ def test_try_to_use_return_annotation_for_property(class_is_findable):
|
||||
raise BaseException
|
||||
|
||||
@property
|
||||
def with_annotation_garbage1(self) -> 'asldjflksjdfljdslkjfsl': # noqa
|
||||
def with_annotation_garbage1(self) -> 'asldjflksjdfljdslkjfsl': # type: ignore[name-defined] # noqa
|
||||
return Hello()
|
||||
|
||||
@property
|
||||
def with_annotation_garbage2(self) -> 'sdf$@@$5*+8': # noqa
|
||||
def with_annotation_garbage2(self) -> 'sdf & 8': # type: ignore[valid-type] # noqa
|
||||
return Hello()
|
||||
|
||||
@property
|
||||
|
||||
@@ -54,7 +54,6 @@ def test_rename_mod(Script, 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):
|
||||
origin = get_example_dir('implicit_namespace_package')
|
||||
shutil.copytree(origin, tmpdir.strpath, dirs_exist_ok=True)
|
||||
|
||||
@@ -13,7 +13,7 @@ class SomeClass:
|
||||
def twice(self, b):
|
||||
pass
|
||||
|
||||
def some_function():
|
||||
def some_function(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ def test_path_from_sys_path_assignment(Script):
|
||||
|
||||
import sys
|
||||
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},
|
||||
]
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@ import jedi
|
||||
from ..helpers import test_dir
|
||||
|
||||
try:
|
||||
import numpydoc # NOQA
|
||||
import numpydoc # type: ignore[import-not-found] # NOQA
|
||||
except ImportError:
|
||||
numpydoc_unavailable = True
|
||||
else:
|
||||
numpydoc_unavailable = False
|
||||
|
||||
try:
|
||||
import numpy # NOQA
|
||||
import numpy # type: ignore[import-not-found] # NOQA
|
||||
except ImportError:
|
||||
numpy_unavailable = True
|
||||
else:
|
||||
|
||||
@@ -31,7 +31,9 @@ def test_get_signatures_stdlib(Script):
|
||||
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.skipif(
|
||||
'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
|
||||
`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)
|
||||
|
||||
@@ -222,7 +222,7 @@ def test_goto_stubs_on_itself(Script, code, type_):
|
||||
|
||||
def test_module_exists_only_as_stub(Script):
|
||||
try:
|
||||
import redis # noqa: F401
|
||||
import redis # type: ignore[import-untyped] # noqa: F401
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
|
||||
@@ -30,13 +30,13 @@ def test_find_module_basic():
|
||||
|
||||
def test_find_module_package():
|
||||
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
|
||||
|
||||
|
||||
def test_find_module_not_package():
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -56,10 +56,10 @@ def test_generics_methods(code, expected, class_findable):
|
||||
class Reader(Generic[T]):
|
||||
@classmethod
|
||||
def read(cls) -> T:
|
||||
return cls()
|
||||
return cls() # type: ignore[return-value]
|
||||
|
||||
def method(self) -> T:
|
||||
return 1
|
||||
return 1 # type: ignore[return-value]
|
||||
|
||||
class Foo(Reader[str]):
|
||||
def transform(self) -> int:
|
||||
@@ -94,7 +94,7 @@ def test_signature():
|
||||
pass
|
||||
|
||||
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)
|
||||
])
|
||||
|
||||
@@ -105,7 +105,7 @@ def test_signature():
|
||||
def test_compiled_signature_annotation_string():
|
||||
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
|
||||
func.__name__ = 'not_func'
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ from textwrap import dedent
|
||||
from operator import eq, ge, lt
|
||||
import re
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -405,7 +406,7 @@ def test_wraps_signature(Script, code, 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):
|
||||
# Final is not yet supported
|
||||
@@ -448,7 +449,7 @@ def test_dataclass_signature(
|
||||
assert price.name == price_type_infer
|
||||
|
||||
|
||||
dataclass_transform_cases = [
|
||||
dataclass_transform_cases: list[Any] = [
|
||||
# Attributes on the decorated class and its base classes
|
||||
# are not considered to be fields.
|
||||
# 1/ Declare dataclass transformer
|
||||
@@ -724,7 +725,7 @@ ids = [
|
||||
'start, start_params, include_params', dataclass_transform_cases, ids=ids
|
||||
)
|
||||
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())
|
||||
if not has_typing_ext:
|
||||
@@ -845,7 +846,7 @@ def test_dataclass_transform_signature(
|
||||
],
|
||||
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())
|
||||
if not has_attrs:
|
||||
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)')
|
||||
])
|
||||
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':
|
||||
node = node.children[0]
|
||||
assert parser_utils.get_signature(node) == signature
|
||||
|
||||
+8
-6
@@ -1,7 +1,9 @@
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
import readline
|
||||
except ImportError:
|
||||
readline = False
|
||||
readline = False # type: ignore[assignment]
|
||||
import unittest
|
||||
|
||||
from jedi import utils
|
||||
@@ -15,7 +17,7 @@ class TestSetupReadline(unittest.TestCase):
|
||||
def setUp(self, *args, **kwargs):
|
||||
super().setUp(*args, **kwargs)
|
||||
|
||||
self.namespace = self.NameSpace()
|
||||
self.namespace: Any = self.NameSpace()
|
||||
utils.setup_readline(self.namespace)
|
||||
|
||||
def complete(self, text):
|
||||
@@ -47,8 +49,8 @@ class TestSetupReadline(unittest.TestCase):
|
||||
def test_modules(self):
|
||||
import sys
|
||||
import os
|
||||
self.namespace.sys = sys
|
||||
self.namespace.os = os
|
||||
self.namespace.sys = sys # type: ignore[attr-defined]
|
||||
self.namespace.os = os # type: ignore[attr-defined]
|
||||
|
||||
try:
|
||||
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')}
|
||||
assert set(self.complete('os.ch')) == set(c)
|
||||
finally:
|
||||
del self.namespace.sys
|
||||
del self.namespace.os
|
||||
del self.namespace.sys # type: ignore[attr-defined]
|
||||
del self.namespace.os # type: ignore[attr-defined]
|
||||
|
||||
def test_calls(self):
|
||||
s = 'str(bytes'
|
||||
|
||||
Reference in New Issue
Block a user