1
0
forked from VimPlug/jedi

Introduce some stricter typing

This commit is contained in:
Dave Halter
2026-02-04 01:19:14 +01:00
parent c7481b3319
commit 30ef824abd
28 changed files with 171 additions and 67 deletions
+27 -23
View File
@@ -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, \
@@ -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)
@@ -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):
+1 -1
View File
@@ -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 ''
+3
View File
@@ -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))
+3
View File
@@ -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,7 @@ 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()
+3
View File
@@ -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
@@ -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.
+15 -1
View File
@@ -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:
@@ -499,7 +513,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)
@@ -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] = {}
+2 -2
View File
@@ -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
+10 -2
View File
@@ -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
+1 -1
View File
@@ -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()
+6 -3
View File
@@ -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)
+9
View File
@@ -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()
+3
View File
@@ -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')
+1 -1
View File
@@ -5,7 +5,7 @@ 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):
+1 -1
View File
@@ -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()
+18 -7
View File
@@ -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 n in value.goto(name, name_context=context)
for value in values for value in values
) ]
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])
@@ -357,6 +362,8 @@ 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 = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
if include_star: if include_star:
@@ -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.
+7
View File
@@ -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
+2 -2
View File
@@ -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
@@ -435,7 +435,7 @@ def _infer_expr_stmt(context, stmt, seek_name=None):
value_set = ValueSet(to_mod(v) for v in left_values) value_set = ValueSet(to_mod(v) for v in left_values)
else: else:
operator = copy.copy(first_operator) operator = copy.copy(first_operator)
operator.value = operator.value[:-1] operator.value = operator.value[:-1] # type: ignore[attor-defined]
for_stmt = stmt.search_ancestor('for_stmt') for_stmt = stmt.search_ancestor('for_stmt')
if for_stmt is not None and for_stmt.type == 'for_stmt' and value_set \ if for_stmt is not None and for_stmt.type == 'for_stmt' and value_set \
and parser_utils.for_stmt_defines_one_name(for_stmt): and parser_utils.for_stmt_defines_one_name(for_stmt):
-1
View File
@@ -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)
+6
View File
@@ -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__()
+3
View File
@@ -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,8 @@ class CompiledInstance(AbstractInstanceValue):
class _BaseTreeInstance(AbstractInstanceValue): class _BaseTreeInstance(AbstractInstanceValue):
get_defined_names: Any
@property @property
def array_type(self): def array_type(self):
name = self.class_value.py__name__() name = self.class_value.py__name__()
+16
View File
@@ -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())
@@ -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()
+13 -1
View File
@@ -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
+13 -1
View File
@@ -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(
+1 -1
View File
@@ -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
+1 -1
View File
@@ -192,7 +192,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
+1 -1
View File
@@ -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
+1 -15
View File
@@ -1,4 +1,4 @@
[tool.mypy] [tool.zuban]
# Exclude our copies of external stubs # Exclude our copies of external stubs
exclude = "^jedi/third_party" exclude = "^jedi/third_party"
@@ -8,25 +8,11 @@ enable_error_code = "ignore-without-code"
# Ensure generics are explicit about what they are (e.g: `List[str]` rather than # Ensure generics are explicit about what they are (e.g: `List[str]` rather than
# just `List`) # just `List`)
disallow_any_generics = true disallow_any_generics = true
disallow_subclassing_any = true disallow_subclassing_any = true
# Avoid creating future gotchas emerging from bad typing # Avoid creating future gotchas emerging from bad typing
warn_redundant_casts = true warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true warn_return_any = true
warn_unused_configs = 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 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