Skip to content

[WIP] Do not allow untyped calls anywhere in the mypy config #13699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,6 @@ disable_error_code = [
"annotation-unchecked",
]
disallow_incomplete_defs = false
disallow_untyped_calls = false
disallow_untyped_defs = false

[[tool.mypy.overrides]]
Expand Down
14 changes: 9 additions & 5 deletions tests/test_builders/test_build_latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@


# only run latex if all needed packages are there
def kpsetest(*filenames):
def kpsetest(*filenames: str) -> bool:
try:
subprocess.run(['kpsewhich', *list(filenames)], capture_output=True, check=True) # NoQA: S607
return True
Expand All @@ -55,7 +55,11 @@ def kpsetest(*filenames):


# compile latex document with app.config.latex_engine
def compile_latex_document(app, filename='projectnamenotset.tex', docclass='manual'):
def compile_latex_document(
app: SphinxTestApp,
filename: str = 'projectnamenotset.tex',
docclass: str = 'manual',
) -> None:
# now, try to run latex over it
try:
with chdir(app.outdir):
Expand Down Expand Up @@ -1570,7 +1574,7 @@ def test_latex_table_tabulars(app: SphinxTestApp) -> None:
content = re.sub(r'\\sphinxstepscope', '', content) # filter a separator
tables[sectname] = content.strip()

def get_expected(name):
def get_expected(name: str) -> str:
return (
(app.srcdir / 'expects' / (name + '.tex'))
.read_text(encoding='utf8')
Expand Down Expand Up @@ -1648,7 +1652,7 @@ def test_latex_table_longtable(app: SphinxTestApp) -> None:
content = re.sub(r'\\sphinxstepscope', '', content) # filter a separator
tables[sectname] = content.strip()

def get_expected(name):
def get_expected(name: str) -> str:
return (
(app.srcdir / 'expects' / (name + '.tex'))
.read_text(encoding='utf8')
Expand Down Expand Up @@ -1715,7 +1719,7 @@ def test_latex_table_complex_tables(app: SphinxTestApp) -> None:
sectname, _, content = chap.partition('}')
tables[sectname] = content.strip()

def get_expected(name):
def get_expected(name: str) -> str:
return (
(app.srcdir / 'expects' / (name + '.tex'))
.read_text(encoding='utf8')
Expand Down
28 changes: 15 additions & 13 deletions tests/test_domains/test_domain_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from sphinx.writers.text import STDINDENT

if TYPE_CHECKING:
from collections.abc import Generator
from io import StringIO


Expand All @@ -41,15 +42,15 @@ class Config:
c_extra_keywords = _macro_keywords


def parse(name, string):
parser = DefinitionParser(string, location=None, config=Config())
def parse(name: str, string: str):
parser = DefinitionParser(string, location=None, config=Config()) # type: ignore[arg-type]
parser.allowFallbackExpressionParsing = False
ast = parser.parse_declaration(name, name)
parser.assert_end()
return ast


def _check(name, input, id_dict, output, key, as_text_output):
def _check(name: str, input: str, id_dict, output, key, as_text_output):
if key is None:
key = name
key += ' '
Expand Down Expand Up @@ -102,14 +103,13 @@ def _check(name, input, id_dict, output, key, as_text_output):
# except NoOldIdError:
# id_actual.append(None)

res = [True]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was redefining a variable, so I just renamed it here to create a new variable.

for i in range(1, _max_id + 1):
res.append(id_expected[i] == id_actual[i])
res_bools = [True]
res_bools.extend(id_expected[i] == id_actual[i] for i in range(1, _max_id + 1))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ruff made/required this change


if not all(res):
if not all(res_bools):
print('input: %s' % input.rjust(20))
for i in range(1, _max_id + 1):
if res[i]:
if res_bools[i]:
continue
print('Error in id version %d.' % i)
print('result: %s' % id_actual[i])
Expand All @@ -118,7 +118,9 @@ def _check(name, input, id_dict, output, key, as_text_output):
raise DefinitionError


def check(name, input, id_dict, output=None, key=None, as_text_output=None):
def check(
name: str, input, id_dict, output=None, key=None, as_text_output=None
) -> None:
if output is None:
output = input
# First, check without semicolon
Expand All @@ -136,8 +138,8 @@ def check(name, input, id_dict, output=None, key=None, as_text_output=None):


def test_domain_c_ast_expressions() -> None:
def expr_check(expr, output=None):
parser = DefinitionParser(expr, location=None, config=Config())
def expr_check(expr: str, output: str | None = None) -> None:
parser = DefinitionParser(expr, location=None, config=Config()) # type: ignore[arg-type]
parser.allowFallbackExpressionParsing = False
ast = parser.parse_expression()
parser.assert_end()
Expand Down Expand Up @@ -337,8 +339,8 @@ def expr_check(expr, output=None):


def test_domain_c_ast_fundamental_types() -> None:
def types():
def signed(t):
def types() -> Generator[str]:
def signed(t: str) -> Generator[str]:
yield t
yield 'signed ' + t
yield 'unsigned ' + t
Expand Down
44 changes: 27 additions & 17 deletions tests/test_domains/test_domain_cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,25 @@
if TYPE_CHECKING:
from io import StringIO

from sphinx.domains.cpp._ast import ASTDeclaration

def parse(name, string):

def parse(name: str, string: str) -> ASTDeclaration:
class Config:
cpp_id_attributes = ['id_attr']
cpp_paren_attributes = ['paren_attr']

parser = DefinitionParser(string, location=None, config=Config())
parser = DefinitionParser(string, location=None, config=Config()) # type: ignore[arg-type]
parser.allowFallbackExpressionParsing = False
ast = parser.parse_declaration(name, name)
parser.assert_end()
# The scopedness would usually have been set by CPPEnumObject
if name == 'enum':
ast.scoped = None # simulate unscoped enum
ast.scoped = None # type: ignore[attr-defined] # simulate unscoped enum
return ast


def _check(name, input, id_dict, output, key, as_text_output):
def _check(name, input: str, id_dict: dict[int, str], output, key, as_text_output):
if key is None:
key = name
key += ' '
Expand Down Expand Up @@ -80,7 +82,7 @@ def _check(name, input, id_dict, output, key, as_text_output):
parent_node = addnodes.desc()
signode = addnodes.desc_signature(input, '')
parent_node += signode
ast.describe_signature(signode, 'lastIsName', symbol, options={})
ast.describe_signature(signode, 'lastIsName', symbol, options={}) # type: ignore[arg-type]
res_as_text = parent_node.astext()
if res_as_text != output_as_text:
print()
Expand All @@ -90,13 +92,13 @@ def _check(name, input, id_dict, output, key, as_text_output):
print('Node:', parent_node)
raise DefinitionError

id_expected = [None]
id_expected: list[str | None] = [None]
for i in range(1, _max_id + 1):
if i in id_dict:
id_expected.append(id_dict[i])
else:
id_expected.append(id_expected[i - 1])
id_actual = [None]
id_actual: list[str | None] = [None]
for i in range(1, _max_id + 1):
try:
id = ast.get_id(version=i)
Expand All @@ -105,14 +107,13 @@ def _check(name, input, id_dict, output, key, as_text_output):
except NoOldIdError:
id_actual.append(None)

res = [True]
for i in range(1, _max_id + 1):
res.append(id_expected[i] == id_actual[i])
res_bools = [True]
res_bools.extend(id_expected[i] == id_actual[i] for i in range(1, _max_id + 1))

if not all(res):
if not all(res_bools):
print('input: %s' % input.rjust(20))
for i in range(1, _max_id + 1):
if res[i]:
if res_bools[i]:
continue
print('Error in id version %d.' % i)
print('result: %s' % id_actual[i])
Expand All @@ -121,7 +122,14 @@ def _check(name, input, id_dict, output, key, as_text_output):
raise DefinitionError


def check(name, input, id_dict, output=None, key=None, as_text_output=None):
def check(
name: str,
input: str,
id_dict: dict[int, str],
output=None,
key=None,
as_text_output=None,
) -> None:
if output is None:
output = input
# First, check without semicolon
Expand Down Expand Up @@ -177,7 +185,7 @@ def make_id_v2():


def test_domain_cpp_ast_expressions() -> None:
def expr_check(expr, id, id4=None):
def expr_check(expr: str, id: str, id4: str | None = None):
ids = 'IE1CIA%s_1aE'
# call .format() on the expr to unescape double curly braces
id_dict = {2: ids % expr.format(), 3: ids % id}
Expand All @@ -189,7 +197,7 @@ class Config:
cpp_id_attributes = ['id_attr']
cpp_paren_attributes = ['paren_attr']

parser = DefinitionParser(expr, location=None, config=Config())
parser = DefinitionParser(expr, location=None, config=Config()) # type: ignore[arg-type]
parser.allowFallbackExpressionParsing = False
ast = parser.parse_expression()
res = str(ast)
Expand Down Expand Up @@ -1472,12 +1480,12 @@ def test_domain_cpp_ast_attributes() -> None:
check('enumerator', '{key}Foo [[attr1]] [[attr2]] = 42', {2: '3Foo'})


def check_ast_xref_parsing(target):
def check_ast_xref_parsing(target: str) -> None:
class Config:
cpp_id_attributes = ['id_attr']
cpp_paren_attributes = ['paren_attr']

parser = DefinitionParser(target, location='', config=Config())
parser = DefinitionParser(target, location='', config=Config()) # type: ignore[arg-type]
parser.parse_xref_object()
parser.assert_end()

Expand Down Expand Up @@ -1518,6 +1526,8 @@ def test_domain_cpp_ast_xref_parsing() -> None:
def test_domain_cpp_template_parameters_is_pack(param: str, is_pack: bool):
def parse_template_parameter(param: str):
ast = parse('type', 'template<' + param + '> X')
assert ast.templatePrefix is not None
assert ast.templatePrefix.templates is not None
return ast.templatePrefix.templates[0].params[0]

ast = parse_template_parameter(param)
Expand Down
12 changes: 8 additions & 4 deletions tests/test_extensions/test_ext_intersphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ def __iter__(self) -> NoReturn:
raise NotImplementedError


def fake_node(domain, type, target, content, **attrs):
def fake_node(
domain: str, type: str, target: str, content: str, **attrs
) -> tuple[addnodes.pending_xref, nodes.emphasis]:
contnode = nodes.emphasis(content, content)
node = addnodes.pending_xref('')
node['reftarget'] = target
Expand All @@ -62,12 +64,14 @@ def fake_node(domain, type, target, content, **attrs):
return node, contnode


def reference_check(app, *args, **kwds):
def reference_check(app: SphinxTestApp, *args, **kwds):
node, contnode = fake_node(*args, **kwds)
return missing_reference(app, app.env, node, contnode)


def set_config(app, mapping):
def set_config(
app: SphinxTestApp, mapping: dict[str, tuple[str, str | list[str]]]
) -> None:
# copy *mapping* so that normalization does not alter it
app.config.intersphinx_mapping = mapping.copy()
app.config.intersphinx_cache_limit = 0
Expand Down Expand Up @@ -544,7 +548,7 @@ def test_validate_intersphinx_mapping_warnings(app: SphinxTestApp) -> None:
'good-target-1': ('e.example', None), # valid inventory location (None)
'good-target-2': ('f.example', ('x',)), # valid inventory location (sequence input)
} # fmt: skip
set_config(app, bad_intersphinx_mapping)
set_config(app, bad_intersphinx_mapping) # type: ignore[arg-type]

# normalise the inventory and check if it's done correctly
with pytest.raises(
Expand Down
15 changes: 9 additions & 6 deletions tests/test_util/test_util_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import functools
import types
from inspect import Parameter
from typing import Callable, List, Optional, Union # NoQA: UP035
from typing import TYPE_CHECKING, Callable, List, Optional, Union # NoQA: UP035

import pytest

Expand All @@ -20,6 +20,9 @@
)
from sphinx.util.typing import stringify_annotation

if TYPE_CHECKING:
from typing import Any


class Base:
def meth(self):
Expand Down Expand Up @@ -98,7 +101,7 @@ def __call__(self):
pass


def _decorator(f):
def _decorator(f: Callable[[], Any]) -> Callable[[], Any]:
@functools.wraps(f)
def wrapper():
return f()
Expand Down Expand Up @@ -658,10 +661,10 @@ def test_recursive_collection_description():

def test_dict_customtype() -> None:
class CustomType:
def __init__(self, value):
def __init__(self, value: int) -> None:
self._value = value

def __repr__(self):
def __repr__(self) -> str:
return '<CustomType(%r)>' % self._value

dictionary = {CustomType(2): 2, CustomType(1): 1}
Expand Down Expand Up @@ -985,8 +988,8 @@ def my_method(self):
assert not inspect.is_builtin_class_method(MyInt, 'does_not_exist')
assert not inspect.is_builtin_class_method(4, 'still does not crash')

class ObjectWithMroAttr:
def __init__(self, mro_attr):
class ObjectWithMroAttr: # noqa: B903
def __init__(self, mro_attr: list[int]) -> None:
self.__mro__ = mro_attr

assert not inspect.is_builtin_class_method(
Expand Down
Loading