Merge pull request #1642 from PeterJCLaw/mypy

Add an initial mypy config
This commit is contained in:
Dave Halter
2020-08-05 01:09:49 +02:00
committed by GitHub
28 changed files with 120 additions and 60 deletions

View File

@@ -30,8 +30,8 @@ matrix:
install:
- 'pip install .[qa]'
script:
# Ignore F401, which are unused imports. flake8 is a primitive tool and is sometimes wrong.
- 'flake8 --extend-ignore F401 jedi setup.py'
- 'flake8 jedi setup.py'
- 'mypy jedi sith.py'
install:
- sudo apt-get -y install python3-venv
- pip install .[testing]

View File

@@ -15,18 +15,18 @@ the interesting information about all operations.
"""
import re
import warnings
from pathlib import Path
from typing import Optional
from parso.python.tree import search_ancestor
from parso.tree import search_ancestor
from jedi import settings
from jedi import debug
from jedi.inference.utils import unite
from jedi.cache import memoize_method
from jedi.inference import imports
from jedi.inference.imports import ImportName
from jedi.inference.compiled.mixed import MixedName
from jedi.inference.gradual.typeshed import StubModuleValue
from jedi.inference.names import ImportName, SubModuleName
from jedi.inference.gradual.stub_value import StubModuleValue
from jedi.inference.gradual.conversion import convert_names, convert_values
from jedi.inference.base_value import ValueSet
from jedi.api.keywords import KeywordName
@@ -93,17 +93,15 @@ class BaseName:
return self._name.get_root_context()
@property
def module_path(self) -> Optional[str]:
def module_path(self) -> Optional[Path]:
"""
Shows the file path of a module. e.g. ``/usr/lib/python3.9/os.py``
:rtype: str or None
"""
module = self._get_module_context()
if module.is_stub() or not module.is_compiled():
# Compiled modules should not return a module path even if they
# have one.
path = self._get_module_context().py__file__()
path: Optional[Path] = self._get_module_context().py__file__()
if path is not None:
return path
@@ -186,7 +184,7 @@ class BaseName:
tree_name.is_definition():
resolve = True
if isinstance(self._name, imports.SubModuleName) or resolve:
if isinstance(self._name, SubModuleName) or resolve:
for value in self._name.infer():
return value.api_type
return self._name.api_type
@@ -497,7 +495,7 @@ class BaseName:
return [self if n == self._name else Name(self._inference_state, n)
for n in resulting_names]
@property
@property # type: ignore[misc]
@memoize_method
def params(self):
warnings.warn(

View File

@@ -1,7 +1,13 @@
_cache = {}
from typing import Dict, Tuple, Callable
CacheValues = Tuple[str, str, str]
CacheValuesCallback = Callable[[], CacheValues]
def save_entry(module_name, name, cache):
_cache: Dict[str, Dict[str, CacheValues]] = {}
def save_entry(module_name: str, name: str, cache: CacheValues) -> None:
try:
module_cache = _cache[module_name]
except KeyError:
@@ -9,8 +15,8 @@ def save_entry(module_name, name, cache):
module_cache[name] = cache
def _create_get_from_cache(number):
def _get_from_cache(module_name, name, get_cache_values):
def _create_get_from_cache(number: int) -> Callable[[str, str, CacheValuesCallback], str]:
def _get_from_cache(module_name: str, name: str, get_cache_values: CacheValuesCallback) -> str:
try:
return _cache[module_name][name][number]
except KeyError:

View File

@@ -384,7 +384,8 @@ def _get_executable_path(path, safe=True):
def _get_executables_from_windows_registry(version):
import winreg
# https://github.com/python/typeshed/pull/3794 adds winreg
import winreg # type: ignore[import]
# TODO: support Python Anaconda.
sub_keys = [

View File

@@ -1,10 +1,13 @@
import pydoc
from contextlib import suppress
from typing import Dict, Optional
from jedi.inference.names import AbstractArbitraryName
try:
from pydoc_data import topics as pydoc_topics
# https://github.com/python/typeshed/pull/4351 adds pydoc_data
from pydoc_data import topics # type: ignore[import]
pydoc_topics: Optional[Dict[str, str]] = topics.topics
except ImportError:
# Python 3.6.8 embeddable does not have pydoc_data.
pydoc_topics = None
@@ -44,6 +47,6 @@ def imitate_pydoc(string):
return ''
try:
return pydoc_topics.topics[label].strip() if pydoc_topics else ''
return pydoc_topics[label].strip() if pydoc_topics else ''
except KeyError:
return ''

View File

@@ -13,14 +13,15 @@ these variables are being cleaned after every API usage.
"""
import time
from functools import wraps
from typing import Any, Dict, Tuple
from jedi import settings
from parso.cache import parser_cache
_time_caches = {}
_time_caches: Dict[str, Dict[Any, Tuple[float, Any]]] = {}
def clear_time_caches(delete_all=False):
def clear_time_caches(delete_all: bool = False) -> None:
""" Jedi caches many things, that should be completed after each completion
finishes.

View File

@@ -1,6 +1,7 @@
import os
import time
from contextlib import contextmanager
from typing import Callable, Optional
_inited = False
@@ -20,7 +21,7 @@ try:
raise ImportError
else:
# Use colorama for nicer console output.
from colorama import Fore, init
from colorama import Fore, init # type: ignore[import]
from colorama import initialise
def _lazy_colorama_init(): # noqa: F811
@@ -45,7 +46,7 @@ try:
_inited = True
except ImportError:
class Fore:
class Fore: # type: ignore[no-redef]
RED = ''
GREEN = ''
YELLOW = ''
@@ -62,7 +63,7 @@ enable_warning = False
enable_notice = False
# callback, interface: level, str
debug_function = None
debug_function: Optional[Callable[[str, str], None]] = None
_debug_indent = 0
_start_time = time.time()

View File

@@ -120,14 +120,15 @@ class InferenceState:
debug.dbg('execute result: %s in %s', value_set, value)
return value_set
@property
# mypy doesn't suppport decorated propeties (https://github.com/python/mypy/issues/1362)
@property # type: ignore[misc]
@inference_state_function_cache()
def builtins_module(self):
module_name = 'builtins'
builtins_module, = self.import_module((module_name,), sys_path=())
return builtins_module
@property
@property # type: ignore[misc]
@inference_state_function_cache()
def typing_module(self):
typing_module, = self.import_module(('typing',))

View File

@@ -1,3 +1,6 @@
# This file also re-exports symbols for wider use. We configure mypy and flake8
# to be aware that this file does this.
from jedi.inference.compiled.value import CompiledValue, CompiledName, \
CompiledValueFilter, CompiledValueName, create_from_access_path
from jedi.inference.base_value import LazyValueWrapper

View File

@@ -29,19 +29,19 @@ _MAIN_PATH = os.path.join(os.path.dirname(__file__), '__main__.py')
PICKLE_PROTOCOL = 4
class _GeneralizedPopen(subprocess.Popen):
def __init__(self, *args, **kwargs):
if os.name == 'nt':
try:
# Was introduced in Python 3.7.
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW
except AttributeError:
CREATE_NO_WINDOW = 0x08000000
kwargs['creationflags'] = CREATE_NO_WINDOW
# The child process doesn't need file descriptors except 0, 1, 2.
# This is unix only.
kwargs['close_fds'] = 'posix' in sys.builtin_module_names
super().__init__(*args, **kwargs)
def _GeneralizedPopen(*args, **kwargs):
if os.name == 'nt':
try:
# Was introduced in Python 3.7.
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW
except AttributeError:
CREATE_NO_WINDOW = 0x08000000
kwargs['creationflags'] = CREATE_NO_WINDOW
# The child process doesn't need file descriptors except 0, 1, 2.
# This is unix only.
kwargs['close_fds'] = 'posix' in sys.builtin_module_names
return subprocess.Popen(*args, **kwargs)
def _enqueue_output(out, queue_):

View File

@@ -1,5 +1,6 @@
import os
import sys
from importlib.abc import MetaPathFinder
from importlib.machinery import PathFinder
# Remove the first entry, because it's simply a directory entry that equals
@@ -16,7 +17,7 @@ def _get_paths():
return {'jedi': _jedi_path, 'parso': _parso_path}
class _ExactImporter:
class _ExactImporter(MetaPathFinder):
def __init__(self, path_dct):
self._path_dct = path_dct

View File

@@ -50,7 +50,7 @@ def _get_numpy_doc_string_cls():
global _numpy_doc_string_cache
if isinstance(_numpy_doc_string_cache, (ImportError, SyntaxError)):
raise _numpy_doc_string_cache
from numpydoc.docscrape import NumpyDocString
from numpydoc.docscrape import NumpyDocString # type: ignore[import]
_numpy_doc_string_cache = NumpyDocString
return _numpy_doc_string_cache

View File

@@ -3,9 +3,11 @@ 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
import weakref
from parso.tree import search_ancestor
from parso.python.tree import Name, UsedNamesMapping
from jedi.inference import flow_analysis
from jedi.inference.base_value import ValueSet, ValueWrapper, \
@@ -13,8 +15,9 @@ from jedi.inference.base_value import ValueSet, ValueWrapper, \
from jedi.parser_utils import get_cached_parent_scope
from jedi.inference.utils import to_list
from jedi.inference.names import TreeNameDefinition, ParamName, \
AnonymousParamName, AbstractNameDefinition
AnonymousParamName, AbstractNameDefinition, NameWrapper
_definition_name_cache: MutableMapping[UsedNamesMapping, List[Name]]
_definition_name_cache = weakref.WeakKeyDictionary()
@@ -36,7 +39,7 @@ class AbstractFilter:
class FilterWrapper:
name_wrapper_class = None
name_wrapper_class: Type[NameWrapper]
def __init__(self, wrapped_filter):
self._wrapped_filter = wrapped_filter

View File

@@ -1,12 +1,14 @@
from typing import Dict, Optional
from jedi.parser_utils import get_flow_branch_keyword, is_scope, get_parent_scope
from jedi.inference.recursion import execution_allowed
from jedi.inference.helpers import is_big_annoying_library
class Status:
lookup_table = {}
lookup_table: Dict[Optional[bool], 'Status'] = {}
def __init__(self, value, name):
def __init__(self, value: Optional[bool], name: str) -> None:
self._value = value
self._name = name
Status.lookup_table[value] = self

View File

@@ -2,6 +2,7 @@ import os
import re
from functools import wraps
from collections import namedtuple
from typing import Dict, Mapping, Tuple
from pathlib import Path
from jedi import settings
@@ -74,7 +75,7 @@ def _get_typeshed_directories(version_info):
yield PathInfo(str(base_path.joinpath(check_version)), is_third_party)
_version_cache = {}
_version_cache: Dict[Tuple[int, int], Mapping[str, PathInfo]] = {}
def _cache_stub_file_map(version_info):

View File

@@ -1,4 +1,3 @@
import os
from pathlib import Path
from jedi.inference.gradual.typeshed import TYPESHED_PATH, create_stub_module

View File

@@ -1,5 +1,6 @@
from abc import abstractmethod
from inspect import Parameter
from typing import Optional, Tuple
from parso.tree import search_ancestor
@@ -24,8 +25,8 @@ def _merge_name_docs(names):
class AbstractNameDefinition:
start_pos = None
string_name = None
start_pos: Optional[Tuple[int, int]] = None
string_name: str
parent_context = None
tree_name = None
is_value_name = True

View File

@@ -5,7 +5,8 @@ from parso import python_bytes_to_unicode
from jedi.debug import dbg
from jedi.file_io import KnownContentFileIO
from jedi.inference.imports import SubModuleName, load_module_from_path
from jedi.inference.names import SubModuleName
from jedi.inference.imports import load_module_from_path
from jedi.inference.filters import ParserTreeFilter
from jedi.inference.gradual.conversion import convert_names

View File

@@ -14,8 +14,8 @@ from jedi import debug
_BUILDOUT_PATH_INSERTION_LIMIT = 10
def _abs_path(module_context, path: str):
path = Path(path)
def _abs_path(module_context, str_path: str):
path = Path(str_path)
if path.is_absolute():
return path

View File

@@ -1,3 +1,6 @@
# Re-export symbols for wider use. We configure mypy and flake8 to be aware that
# this file does this.
from jedi.inference.value.module import ModuleValue
from jedi.inference.value.klass import ClassValue
from jedi.inference.value.function import FunctionValue, \

View File

@@ -1,6 +1,6 @@
from abc import abstractproperty
from parso.python.tree import search_ancestor
from parso.tree import search_ancestor
from jedi import debug
from jedi import settings

View File

@@ -1,5 +1,6 @@
import os
from pathlib import Path
from typing import Optional
from jedi.inference.cache import inference_state_method_cache
from jedi.inference.names import AbstractNameDefinition, ModuleName
@@ -79,7 +80,7 @@ class ModuleMixin(SubModuleDictMixin):
def is_stub(self):
return False
@property
@property # type: ignore[misc]
@inference_state_method_cache()
def name(self):
return self._module_name_class(self, self.string_names[-1])
@@ -145,7 +146,7 @@ class ModuleValue(ModuleMixin, TreeValue):
)
self.file_io = file_io
if file_io is None:
self._path = None
self._path: Optional[Path] = None
else:
self._path = Path(file_io.path)
self.string_names = string_names # Optional[Tuple[str, ...]]
@@ -165,7 +166,7 @@ class ModuleValue(ModuleMixin, TreeValue):
return None
return '.'.join(self.string_names)
def py__file__(self) -> Path:
def py__file__(self) -> Optional[Path]:
"""
In contrast to Python's __file__ can be None.
"""

View File

@@ -38,7 +38,7 @@ class ImplicitNamespaceValue(Value, SubModuleDictMixin):
def get_qualified_names(self):
return ()
@property
@property # type: ignore[misc]
@inference_state_method_cache()
def name(self):
string_name = self.py__package__()[-1]

View File

@@ -1,6 +1,6 @@
from pathlib import Path
from parso.python.tree import search_ancestor
from parso.tree import search_ancestor
from jedi.inference.cache import inference_state_method_cache
from jedi.inference.imports import load_module_from_path
from jedi.inference.filters import ParserTreeFilter

View File

@@ -2,7 +2,7 @@
Utilities for end-users.
"""
import __main__
import __main__ # type: ignore[import]
from collections import namedtuple
import logging
import traceback

View File

@@ -15,7 +15,40 @@ ignore =
W503,
# Single letter loop variables are often fine
E741,
per-file-ignores =
# Ignore apparently unused imports in files where we're (implicitly)
# re-exporting them.
jedi/__init__.py:F401
jedi/inference/compiled/__init__.py:F401
jedi/inference/value/__init__.py:F401
exclude = jedi/third_party/* .tox/*
[pycodestyle]
max-line-length = 100
[mypy]
# 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
[mypy-jedi,jedi.inference.compiled,jedi.inference.value]
# Various __init__.py files which contain re-exports we want to implicitly make.
implicit_reexport = True

View File

@@ -44,6 +44,7 @@ setup(name='jedi',
],
'qa': [
'flake8==3.8.3',
'mypy==0.782',
],
},
package_data={'jedi': ['*.pyi', 'third_party/typeshed/LICENSE',

View File

@@ -44,7 +44,7 @@ Options:
--pudb Launch pudb when error is raised.
"""
from docopt import docopt
from docopt import docopt # type: ignore[import]
import json
import os