diff options
-rwxr-xr-x | doc/exts/pylint_extensions.py | 58 | ||||
-rw-r--r-- | pylint/checkers/base_checker.py | 6 | ||||
-rw-r--r-- | pylint/checkers/imports.py | 37 | ||||
-rw-r--r-- | pylint/checkers/spelling.py | 2 | ||||
-rw-r--r-- | pylint/checkers/variables.py | 16 | ||||
-rw-r--r-- | pylint/config/__init__.py | 6 | ||||
-rw-r--r-- | pylint/config/arguments_manager.py | 10 | ||||
-rw-r--r-- | pylint/config/configuration_mixin.py | 9 | ||||
-rw-r--r-- | pylint/config/option.py | 21 | ||||
-rw-r--r-- | pylint/config/option_manager_mixin.py | 13 | ||||
-rw-r--r-- | pylint/config/option_parser.py | 2 | ||||
-rw-r--r-- | pylint/config/options_provider_mixin.py | 2 | ||||
-rw-r--r-- | setup.cfg | 1 | ||||
-rw-r--r-- | tests/lint/unittest_expand_modules.py | 6 | ||||
-rw-r--r-- | tests/pyreverse/test_utils.py | 10 | ||||
-rw-r--r-- | tests/reporters/unittest_reporting.py | 5 | ||||
-rw-r--r-- | tests/test_func.py | 4 |
17 files changed, 132 insertions, 76 deletions
diff --git a/doc/exts/pylint_extensions.py b/doc/exts/pylint_extensions.py index a973e1b13..e5949b1ed 100755 --- a/doc/exts/pylint_extensions.py +++ b/doc/exts/pylint_extensions.py @@ -6,22 +6,42 @@ """Script used to generate the extensions file before building the actual documentation.""" +from __future__ import annotations + import os import re import sys import warnings -from typing import Optional +from typing import Any import sphinx from sphinx.application import Sphinx +from pylint.checkers import BaseChecker from pylint.constants import MAIN_CHECKER_NAME from pylint.lint import PyLinter +from pylint.typing import MessageDefinitionTuple, OptionDict, ReportsCallable from pylint.utils import get_rst_title +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + + +class _CheckerInfo(TypedDict): + """Represents data about a checker.""" + + checker: BaseChecker + options: list[tuple[str, OptionDict, Any]] + msgs: dict[str, MessageDefinitionTuple] + reports: list[tuple[str, str, ReportsCallable]] + doc: str + module: str + # pylint: disable-next=unused-argument -def builder_inited(app: Optional[Sphinx]) -> None: +def builder_inited(app: Sphinx | None) -> None: """Output full documentation in ReST format for all extension modules.""" # PACKAGE/docs/exts/pylint_extensions.py --> PACKAGE/ base_path = os.path.dirname( @@ -30,7 +50,7 @@ def builder_inited(app: Optional[Sphinx]) -> None: # PACKAGE/ --> PACKAGE/pylint/extensions ext_path = os.path.join(base_path, "pylint", "extensions") modules = [] - doc_files = {} + doc_files: dict[str, str] = {} for filename in os.listdir(ext_path): name, ext = os.path.splitext(filename) if name[0] == "_": @@ -79,18 +99,26 @@ def builder_inited(app: Optional[Sphinx]) -> None: checker, information = checker_information j = -1 checker = information["checker"] - del information["checker"] if i == max_len - 1: # Remove the \n\n at the end of the file j = -3 print( - checker.get_full_documentation(**information, show_options=False)[:j], + checker.get_full_documentation( + msgs=information["msgs"], + options=information["options"], + reports=information["reports"], + doc=information["doc"], + module=information["module"], + show_options=False, + )[:j], file=stream, ) -def get_plugins_info(linter, doc_files): - by_checker = {} +def get_plugins_info( + linter: PyLinter, doc_files: dict[str, str] +) -> dict[BaseChecker, _CheckerInfo]: + by_checker: dict[BaseChecker, _CheckerInfo] = {} for checker in linter.get_checkers(): if checker.name == MAIN_CHECKER_NAME: continue @@ -116,14 +144,14 @@ def get_plugins_info(linter, doc_files): except KeyError: with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=DeprecationWarning) - by_checker[checker] = { - "checker": checker, - "options": list(checker.options_and_values()), - "msgs": dict(checker.msgs), - "reports": list(checker.reports), - "doc": doc, - "module": module, - } + by_checker[checker] = _CheckerInfo( + checker=checker, + options=list(checker.options_and_values()), + msgs=dict(checker.msgs), + reports=list(checker.reports), + doc=doc, + module=module, + ) return by_checker diff --git a/pylint/checkers/base_checker.py b/pylint/checkers/base_checker.py index 778345de8..e075ea413 100644 --- a/pylint/checkers/base_checker.py +++ b/pylint/checkers/base_checker.py @@ -7,7 +7,7 @@ from __future__ import annotations import abc import functools import warnings -from collections.abc import Iterator +from collections.abc import Iterable, Sequence from inspect import cleandoc from tokenize import TokenInfo from typing import TYPE_CHECKING, Any @@ -105,8 +105,8 @@ class BaseChecker(_ArgumentsProvider): def get_full_documentation( self, msgs: dict[str, MessageDefinitionTuple], - options: Iterator[tuple[str, OptionDict, Any]], - reports: tuple[tuple[str, str, ReportsCallable], ...], + options: Iterable[tuple[str, OptionDict, Any]], + reports: Sequence[tuple[str, str, ReportsCallable]], doc: str | None = None, module: str | None = None, show_options: bool = True, diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py index 7cab78586..256d973ce 100644 --- a/pylint/checkers/imports.py +++ b/pylint/checkers/imports.py @@ -11,8 +11,8 @@ import copy import os import sys from collections import defaultdict -from collections.abc import Sequence -from typing import TYPE_CHECKING, Any +from collections.abc import ItemsView, Sequence +from typing import TYPE_CHECKING, Any, Dict, List, Union import astroid from astroid import nodes @@ -37,6 +37,9 @@ from pylint.utils.linterstats import LinterStats if TYPE_CHECKING: from pylint.lint import PyLinter +# The dictionary with Any should actually be a _ImportTree again +# but mypy doesn't support recursive types yet +_ImportTree = Dict[str, Union[List[Dict[str, Any]], List[str]]] DEPRECATED_MODULES = { (0, 0, 0): {"tkinter.tix", "fpectl"}, @@ -148,35 +151,37 @@ def _ignore_import_failure( # utilities to represents import dependencies as tree and dot graph ########### -def _make_tree_defs(mod_files_list): +def _make_tree_defs(mod_files_list: ItemsView[str, set[str]]) -> _ImportTree: """Get a list of 2-uple (module, list_of_files_which_import_this_module), it will return a dictionary to represent this as a tree. """ - tree_defs = {} + tree_defs: _ImportTree = {} for mod, files in mod_files_list: - node = (tree_defs, ()) + node: list[_ImportTree | list[str]] = [tree_defs, []] for prefix in mod.split("."): - node = node[0].setdefault(prefix, [{}, []]) + assert isinstance(node[0], dict) + node = node[0].setdefault(prefix, ({}, [])) # type: ignore[arg-type,assignment] + assert isinstance(node[1], list) node[1] += files return tree_defs -def _repr_tree_defs(data, indent_str=None): +def _repr_tree_defs(data: _ImportTree, indent_str: str | None = None) -> str: """Return a string which represents imports as a tree.""" lines = [] nodes_items = data.items() for i, (mod, (sub, files)) in enumerate(sorted(nodes_items, key=lambda x: x[0])): - files = "" if not files else f"({','.join(sorted(files))})" + files_list = "" if not files else f"({','.join(sorted(files))})" if indent_str is None: - lines.append(f"{mod} {files}") + lines.append(f"{mod} {files_list}") sub_indent_str = " " else: - lines.append(rf"{indent_str}\-{mod} {files}") + lines.append(rf"{indent_str}\-{mod} {files_list}") if i == len(nodes_items) - 1: sub_indent_str = f"{indent_str} " else: sub_indent_str = f"{indent_str}| " - if sub: + if sub and isinstance(sub, dict): lines.append(_repr_tree_defs(sub, sub_indent_str)) return "\n".join(lines) @@ -420,7 +425,7 @@ class ImportsChecker(DeprecatedMixin, BaseChecker): def __init__(self, linter: PyLinter) -> None: BaseChecker.__init__(self, linter) self.import_graph: defaultdict[str, set[str]] = defaultdict(set) - self._imports_stack: list[tuple[Any, Any]] = [] + self._imports_stack: list[tuple[ImportNode, str]] = [] self._first_non_import_node = None self._module_pkg: dict[ Any, Any @@ -696,7 +701,7 @@ class ImportsChecker(DeprecatedMixin, BaseChecker): imports = [import_node for (import_node, _) in imports] return any(astroid.are_exclusive(import_node, node) for import_node in imports) - def _check_imports_order(self, _module_node): + def _check_imports_order(self, _module_node: nodes.Module): """Checks imports of module `node` are grouped by category. Imports must follow this order: standard, 3rd party, local @@ -707,9 +712,9 @@ class ImportsChecker(DeprecatedMixin, BaseChecker): # need of a list that holds third or first party ordered import external_imports = [] local_imports = [] - third_party_not_ignored = [] - first_party_not_ignored = [] - local_not_ignored = [] + third_party_not_ignored: list[tuple[ImportNode, str]] = [] + first_party_not_ignored: list[tuple[ImportNode, str]] = [] + local_not_ignored: list[tuple[ImportNode, str]] = [] isort_driver = IsortDriver(self.linter.config) for node, modname in self._imports_stack: if modname.startswith("."): diff --git a/pylint/checkers/spelling.py b/pylint/checkers/spelling.py index e16377ab7..267efd7e5 100644 --- a/pylint/checkers/spelling.py +++ b/pylint/checkers/spelling.py @@ -133,6 +133,8 @@ class ForwardSlashChunker(Chunker): 'after'. """ + _text: str + def next(self): while True: if not self._text: diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 0644b4d07..b0600ea54 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -527,15 +527,15 @@ class NamesConsumer: ) self.node = node - def __repr__(self): - to_consumes = [f"{k}->{v}" for k, v in self._atomic.to_consume.items()] - consumed = [f"{k}->{v}" for k, v in self._atomic.consumed.items()] - consumed_uncertain = [ + def __repr__(self) -> str: + _to_consumes = [f"{k}->{v}" for k, v in self._atomic.to_consume.items()] + _consumed = [f"{k}->{v}" for k, v in self._atomic.consumed.items()] + _consumed_uncertain = [ f"{k}->{v}" for k, v in self._atomic.consumed_uncertain.items() ] - to_consumes = ", ".join(to_consumes) - consumed = ", ".join(consumed) - consumed_uncertain = ", ".join(consumed_uncertain) + to_consumes = ", ".join(_to_consumes) + consumed = ", ".join(_consumed) + consumed_uncertain = ", ".join(_consumed_uncertain) return f""" to_consume : {to_consumes} consumed : {consumed} @@ -2838,7 +2838,7 @@ class VariablesChecker(BaseChecker): consumed = [] # [(scope_locals, consumed_key)] metaclass = klass.metaclass() - name = None + name = "" if isinstance(klass._metaclass, nodes.Name): name = klass._metaclass.name elif isinstance(klass._metaclass, nodes.Attribute) and klass._metaclass.expr: diff --git a/pylint/config/__init__.py b/pylint/config/__init__.py index 7dc96f0cf..9a0d71f40 100644 --- a/pylint/config/__init__.py +++ b/pylint/config/__init__.py @@ -31,8 +31,10 @@ from pylint.config.find_default_config_files import ( ) from pylint.config.option import Option from pylint.config.option_manager_mixin import OptionsManagerMixIn -from pylint.config.option_parser import OptionParser -from pylint.config.options_provider_mixin import OptionsProviderMixIn +from pylint.config.option_parser import OptionParser # type: ignore[attr-defined] +from pylint.config.options_provider_mixin import ( # type: ignore[attr-defined] + OptionsProviderMixIn, +) from pylint.constants import PYLINT_HOME, USER_HOME from pylint.utils import LinterStats diff --git a/pylint/config/arguments_manager.py b/pylint/config/arguments_manager.py index eda1a583d..92bbfac0f 100644 --- a/pylint/config/arguments_manager.py +++ b/pylint/config/arguments_manager.py @@ -38,8 +38,10 @@ from pylint.config.exceptions import ( ) from pylint.config.help_formatter import _HelpFormatter from pylint.config.option import Option -from pylint.config.option_parser import OptionParser -from pylint.config.options_provider_mixin import OptionsProviderMixIn +from pylint.config.option_parser import OptionParser # type: ignore[attr-defined] +from pylint.config.options_provider_mixin import ( # type: ignore[attr-defined] + OptionsProviderMixIn, +) from pylint.config.utils import _convert_option_to_argument, _parse_rich_type_value from pylint.constants import MAIN_CHECKER_NAME from pylint.typing import DirectoryNamespaceDict, OptionDict @@ -287,7 +289,7 @@ class _ArgumentsManager: ) # command line parser self.cmdline_parser = OptionParser(Option, usage=usage) - self.cmdline_parser.options_manager = self # type: ignore[attr-defined] + self.cmdline_parser.options_manager = self self._optik_option_attrs = set(self.cmdline_parser.option_class.ATTRS) def register_options_provider( @@ -632,7 +634,7 @@ class _ArgumentsManager: if value is None: continue setattr(config, attr, value) - return args + return args # type: ignore[return-value] def help(self, level: int | None = None) -> str: """Return the usage string based on the available options.""" diff --git a/pylint/config/configuration_mixin.py b/pylint/config/configuration_mixin.py index 7854ff733..e92faa2d6 100644 --- a/pylint/config/configuration_mixin.py +++ b/pylint/config/configuration_mixin.py @@ -3,9 +3,12 @@ # Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt import warnings +from typing import Any from pylint.config.option_manager_mixin import OptionsManagerMixIn -from pylint.config.options_provider_mixin import OptionsProviderMixIn +from pylint.config.options_provider_mixin import ( # type: ignore[attr-defined] + OptionsProviderMixIn, +) class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): @@ -13,7 +16,7 @@ class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): manager / providers model. """ - def __init__(self, *args, **kwargs): + def __init__(self, *args: Any, **kwargs: Any) -> None: # TODO: 3.0: Remove deprecated class warnings.warn( "ConfigurationMixIn has been deprecated and will be removed in pylint 3.0", @@ -24,7 +27,7 @@ class ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn): OptionsManagerMixIn.__init__(self, *args, **kwargs) OptionsProviderMixIn.__init__(self) if not getattr(self, "option_groups", None): - self.option_groups = [] + self.option_groups: list[tuple[str, str]] = [] for _, optdict in self.options: try: gdef = (optdict["group"].upper(), "") diff --git a/pylint/config/option.py b/pylint/config/option.py index 1cef7aba2..b3924c4aa 100644 --- a/pylint/config/option.py +++ b/pylint/config/option.py @@ -9,7 +9,7 @@ import optparse # pylint: disable=deprecated-module import pathlib import re import warnings -from collections.abc import Sequence +from collections.abc import Callable, Sequence from re import Pattern from typing import Any @@ -107,7 +107,7 @@ def _py_version_validator(_, name, value): return value -VALIDATORS = { +VALIDATORS: dict[str, Callable[[Any, str, Any], Any] | Callable[[Any], Any]] = { "string": utils._unquote, "int": int, "float": float, @@ -128,14 +128,14 @@ VALIDATORS = { } -def _call_validator(opttype, optdict, option, value): +def _call_validator(opttype: str, optdict: Any, option: str, value: Any) -> Any: if opttype not in VALIDATORS: raise Exception(f'Unsupported type "{opttype}"') try: - return VALIDATORS[opttype](optdict, option, value) + return VALIDATORS[opttype](optdict, option, value) # type: ignore[call-arg] except TypeError: try: - return VALIDATORS[opttype](value) + return VALIDATORS[opttype](value) # type: ignore[call-arg] except Exception as e: raise optparse.OptionValueError( f"{option} value ({value!r}) should be of type {opttype}" @@ -186,23 +186,23 @@ class Option(optparse.Option): DeprecationWarning, ) super().__init__(*opts, **attrs) - if hasattr(self, "hide") and self.hide: + if hasattr(self, "hide") and self.hide: # type: ignore[attr-defined] self.help = optparse.SUPPRESS_HELP def _check_choice(self): if self.type in {"choice", "multiple_choice", "confidence"}: - if self.choices is None: + if self.choices is None: # type: ignore[attr-defined] raise optparse.OptionError( "must supply a list of choices for type 'choice'", self ) - if not isinstance(self.choices, (tuple, list)): + if not isinstance(self.choices, (tuple, list)): # type: ignore[attr-defined] raise optparse.OptionError( # pylint: disable-next=consider-using-f-string "choices must be a list of strings ('%s' supplied)" - % str(type(self.choices)).split("'")[1], + % str(type(self.choices)).split("'")[1], # type: ignore[attr-defined] self, ) - elif self.choices is not None: + elif self.choices is not None: # type: ignore[attr-defined] raise optparse.OptionError( f"must not supply choices for type {self.type!r}", self ) @@ -210,6 +210,7 @@ class Option(optparse.Option): optparse.Option.CHECK_METHODS[2] = _check_choice # type: ignore[index] def process(self, opt, value, values, parser): # pragma: no cover # Argparse + assert isinstance(self.dest, str) if self.callback and self.callback.__module__ == "pylint.lint.run": return 1 # First, convert the value(s) to the right type. Howl if any diff --git a/pylint/config/option_manager_mixin.py b/pylint/config/option_manager_mixin.py index 2f0aac75f..a07865ff6 100644 --- a/pylint/config/option_manager_mixin.py +++ b/pylint/config/option_manager_mixin.py @@ -2,6 +2,7 @@ # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE # Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt + # pylint: disable=duplicate-code from __future__ import annotations @@ -19,7 +20,7 @@ from typing import Any, TextIO from pylint import utils from pylint.config.option import Option -from pylint.config.option_parser import OptionParser +from pylint.config.option_parser import OptionParser # type: ignore[attr-defined] from pylint.typing import OptionDict if sys.version_info >= (3, 11): @@ -56,10 +57,10 @@ def _patch_optparse(): # pylint: disable = redefined-variable-type orig_default = optparse.HelpFormatter try: - optparse.HelpFormatter.expand_default = _expand_default + optparse.HelpFormatter.expand_default = _expand_default # type: ignore[assignment] yield finally: - optparse.HelpFormatter.expand_default = orig_default + optparse.HelpFormatter.expand_default = orig_default # type: ignore[assignment] class OptionsManagerMixIn: @@ -131,7 +132,7 @@ class OptionsManagerMixIn: # add section to the config file if ( group_name != "DEFAULT" - and group_name not in self.cfgfile_parser._sections + and group_name not in self.cfgfile_parser._sections # type: ignore[attr-defined] ): self.cfgfile_parser.add_section(group_name) # add provider's specific options @@ -256,11 +257,11 @@ class OptionsManagerMixIn: with open(config_file, encoding="utf_8_sig") as fp: parser.read_file(fp) # normalize each section's title - for sect, values in list(parser._sections.items()): + for sect, values in list(parser._sections.items()): # type: ignore[attr-defined] if sect.startswith("pylint."): sect = sect[len("pylint.") :] if not sect.isupper() and values: - parser._sections[sect.upper()] = values + parser._sections[sect.upper()] = values # type: ignore[attr-defined] if not verbose: return diff --git a/pylint/config/option_parser.py b/pylint/config/option_parser.py index b58fad3a4..78984db34 100644 --- a/pylint/config/option_parser.py +++ b/pylint/config/option_parser.py @@ -2,6 +2,8 @@ # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE # Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt +# type: ignore # Deprecated module. + import optparse # pylint: disable=deprecated-module import warnings diff --git a/pylint/config/options_provider_mixin.py b/pylint/config/options_provider_mixin.py index 5b20a290f..ef85149a9 100644 --- a/pylint/config/options_provider_mixin.py +++ b/pylint/config/options_provider_mixin.py @@ -2,6 +2,8 @@ # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE # Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt +# type: ignore # Deprecated module. + import optparse # pylint: disable=deprecated-module import warnings @@ -45,6 +45,7 @@ warn_unused_ignores = True disallow_any_generics = True show_error_codes = True enable_error_code = ignore-without-code +check_untyped_defs = True [mypy-astroid.*] ignore_missing_imports = True diff --git a/tests/lint/unittest_expand_modules.py b/tests/lint/unittest_expand_modules.py index 15f72d0c5..6a3123aab 100644 --- a/tests/lint/unittest_expand_modules.py +++ b/tests/lint/unittest_expand_modules.py @@ -119,7 +119,8 @@ class TestExpandModules(CheckerTestCase): @set_config(ignore_paths="") def test_expand_modules(self, files_or_modules, expected): """Test expand_modules with the default value of ignore-paths.""" - ignore_list, ignore_list_re = [], [] + ignore_list: list[str] = [] + ignore_list_re: list[re.Pattern[str]] = [] modules, errors = expand_modules( files_or_modules, ignore_list, @@ -145,7 +146,8 @@ class TestExpandModules(CheckerTestCase): @set_config(ignore_paths=".*/lint/.*") def test_expand_modules_with_ignore(self, files_or_modules, expected): """Test expand_modules with a non-default value of ignore-paths.""" - ignore_list, ignore_list_re = [], [] + ignore_list: list[str] = [] + ignore_list_re: list[re.Pattern[str]] = [] modules, errors = expand_modules( files_or_modules, ignore_list, diff --git a/tests/pyreverse/test_utils.py b/tests/pyreverse/test_utils.py index 70d95346f..adf7579b1 100644 --- a/tests/pyreverse/test_utils.py +++ b/tests/pyreverse/test_utils.py @@ -48,8 +48,10 @@ def test_get_visibility(names, expected): ) def test_get_annotation_annassign(assign, label): """AnnAssign.""" - node = astroid.extract_node(assign) - got = get_annotation(node.value).name + node: nodes.AnnAssign = astroid.extract_node(assign) + annotation = get_annotation(node.value) + assert annotation is not None + got = annotation.name assert isinstance(node, nodes.AnnAssign) assert got == label, f"got {got} instead of {label} for value {node}" @@ -75,7 +77,9 @@ def test_get_annotation_assignattr(init_method, label): instance_attrs = node.instance_attrs for assign_attrs in instance_attrs.values(): for assign_attr in assign_attrs: - got = get_annotation(assign_attr).name + annotation = get_annotation(assign_attr) + assert annotation is not None + got = annotation.name assert isinstance(assign_attr, nodes.AssignAttr) assert got == label, f"got {got} instead of {label} for value {node}" diff --git a/tests/reporters/unittest_reporting.py b/tests/reporters/unittest_reporting.py index ebc4a225f..c81590359 100644 --- a/tests/reporters/unittest_reporting.py +++ b/tests/reporters/unittest_reporting.py @@ -17,7 +17,7 @@ import pytest from pylint import checkers from pylint.lint import PyLinter -from pylint.reporters import BaseReporter +from pylint.reporters import BaseReporter, MultiReporter from pylint.reporters.text import ParseableTextReporter, TextReporter from pylint.typing import FileItem @@ -195,6 +195,7 @@ def test_multi_format_output(tmp_path): linter.reporter.writeln("direct output") # Ensure the output files are flushed and closed + assert isinstance(linter.reporter, MultiReporter) linter.reporter.close_output_files() del linter.reporter @@ -337,5 +338,5 @@ def test_display_results_is_renamed(): reporter = CustomReporter() with pytest.raises(AttributeError) as exc: # pylint: disable=no-member - reporter.display_results() + reporter.display_results() # type: ignore[attr-defined] assert "no attribute 'display_results'" in str(exc) diff --git a/tests/test_func.py b/tests/test_func.py index 23f5ff102..b799cf12b 100644 --- a/tests/test_func.py +++ b/tests/test_func.py @@ -100,7 +100,7 @@ class LintTestUpdate(LintTestUsingModule): except OSError: expected = "" if got != expected: - with open(self.output, "w", encoding="utf-8") as f: + with open(self.output or "", "w", encoding="utf-8") as f: f.write(got) @@ -109,7 +109,7 @@ def gen_tests(filter_rgx): is_to_run = re.compile(filter_rgx).search else: is_to_run = ( - lambda x: 1 # pylint: disable=unnecessary-lambda-assignment + lambda x: 1 # type: ignore[assignment] # pylint: disable=unnecessary-lambda-assignment ) # noqa: E731 We're going to throw all this anyway tests = [] for module_file, messages_file in _get_tests_info(INPUT_DIR, MSG_DIR, "func_", ""): |