Skip to content

Commit 30aaf86

Browse files
committed
Fix mypy failures
Due to slyp adding `-> None` annotations, some unannotated collection types are flagged. This does not add broader annotations, only the ones needed to get back to a healthy mypy state. Minor changes are included to generator function tests, but most parts of the library are unchanged.
1 parent f300925 commit 30aaf86

19 files changed

+114
-56
lines changed

nose2/config.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
TRUE_VALS = {"1", "t", "true", "on", "yes", "y"}
24
__unittest = True
35

@@ -13,7 +15,7 @@ class Config:
1315

1416
def __init__(self, items) -> None:
1517
self._items = items
16-
self._mvd = {}
18+
self._mvd: dict[str, list[str]] = {}
1719
for k, v in items:
1820
self._mvd.setdefault(k, []).append(v)
1921

nose2/events.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
from nose2 import config, util
1414

15+
if t.TYPE_CHECKING:
16+
from nose2.session import Session
17+
1518
log = logging.getLogger(__name__)
1619
__unittest = True
1720

@@ -98,8 +101,12 @@ class Plugin(metaclass=PluginMeta):
98101
99102
"""
100103

101-
alwaysOn = False
102-
registered = False
104+
# annotate instance vars created via PluginMeta
105+
session: Session
106+
config: config.Config
107+
108+
alwaysOn: bool = False
109+
registered: bool = False
103110

104111
def register(self):
105112
"""Register with appropriate hooks.
@@ -226,7 +233,7 @@ class Hook:
226233

227234
def __init__(self, method) -> None:
228235
self.method = method
229-
self.plugins = []
236+
self.plugins: list[Plugin] = []
230237

231238
def __call__(self, event):
232239
for plugin in self.plugins[:]:
@@ -320,7 +327,7 @@ class PluginInterface:
320327
hookClass: type[Hook] = Hook
321328

322329
def __init__(self) -> None:
323-
self.hooks = {}
330+
self.hooks: dict[str, list[Hook]] = {}
324331

325332
def addMethod(self, method):
326333
"""Add a method to the available method.
@@ -840,7 +847,7 @@ class LoadFromModuleEvent(Event):
840847
def __init__(self, loader, module, **kw) -> None:
841848
self.loader = loader
842849
self.module = module
843-
self.extraTests = []
850+
self.extraTests: list[unittest.TestCase] = []
844851
super().__init__(**kw)
845852

846853

@@ -883,7 +890,7 @@ class LoadFromTestCaseEvent(Event):
883890
def __init__(self, loader, testCase, **kw) -> None:
884891
self.loader = loader
885892
self.testCase = testCase
886-
self.extraTests = []
893+
self.extraTests: list[unittest.TestCase] = []
887894
super().__init__(**kw)
888895

889896

@@ -922,7 +929,7 @@ def __init__(self, loader, names, module, **kw) -> None:
922929
self.loader = loader
923930
self.names = names
924931
self.module = module
925-
self.extraTests = []
932+
self.extraTests: list[unittest.TestCase] = []
926933
super().__init__(**kw)
927934

928935
def __str__(self):
@@ -964,7 +971,7 @@ def __init__(self, loader, name, module, **kw) -> None:
964971
self.loader = loader
965972
self.name = name
966973
self.module = module
967-
self.extraTests = []
974+
self.extraTests: list[unittest.TestCase] = []
968975
super().__init__(**kw)
969976

970977

@@ -1013,7 +1020,7 @@ class HandleFileEvent(Event):
10131020
_attrs = Event._attrs + ("loader", "name", "path", "pattern", "topLevelDirectory")
10141021

10151022
def __init__(self, loader, name, path, pattern, topLevelDirectory, **kw) -> None:
1016-
self.extraTests = []
1023+
self.extraTests: list[unittest.TestCase] = []
10171024
self.path = path
10181025
self.loader = loader
10191026
self.name = name
@@ -1105,8 +1112,8 @@ def __init__(self, loader, testCase, isTestMethod, **kw) -> None:
11051112
self.loader = loader
11061113
self.testCase = testCase
11071114
self.testMethodPrefix = None
1108-
self.extraNames = []
1109-
self.excludedNames = []
1115+
self.extraNames: list[str] = []
1116+
self.excludedNames: list[str] = []
11101117
self.isTestMethod = isTestMethod
11111118
super().__init__(**kw)
11121119

@@ -1212,7 +1219,7 @@ class OutcomeDetailEvent(Event):
12121219

12131220
def __init__(self, outcomeEvent, **kw) -> None:
12141221
self.outcomeEvent = outcomeEvent
1215-
self.extraDetail = []
1222+
self.extraDetail: list[str] = []
12161223
super().__init__(**kw)
12171224

12181225

nose2/main.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
from __future__ import annotations
2+
13
import logging
24
import os
35
import sys
6+
import typing as t
47
import unittest
58

69
from nose2 import events, loader, plugins, runner, session, util
@@ -71,16 +74,16 @@ class PluggableTestProgram(unittest.TestProgram):
7174
_currentSession = None
7275
loaderClass = loader.PluggableTestLoader
7376
runnerClass = runner.PluggableTestRunner
74-
defaultPlugins = plugins.DEFAULT_PLUGINS
75-
excludePlugins = ()
77+
defaultPlugins: t.ClassVar[t.Sequence[str]] = plugins.DEFAULT_PLUGINS
78+
excludePlugins: t.ClassVar[t.Sequence[str]] = ()
7679

7780
# XXX override __init__ to warn that testLoader and testRunner are ignored?
7881
def __init__(self, **kw) -> None:
7982
plugins = kw.pop("plugins", [])
8083
exclude = kw.pop("excludePlugins", [])
8184
hooks = kw.pop("extraHooks", [])
82-
self.defaultPlugins = list(self.defaultPlugins)
83-
self.excludePlugins = list(self.excludePlugins)
85+
self.defaultPlugins: list[str] = list(self.defaultPlugins) # type: ignore[misc]
86+
self.excludePlugins: list[str] = list(self.excludePlugins) # type: ignore[misc]
8487
self.extraHooks = hooks
8588
self.defaultPlugins.extend(plugins)
8689
self.excludePlugins.extend(exclude)

nose2/plugins/attrib.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
from __future__ import annotations
2+
13
import logging
4+
import typing as t
25
from unittest import TestSuite
36

47
from nose2.events import Plugin
@@ -11,8 +14,8 @@ class AttributeSelector(Plugin):
1114
"""Filter tests by attribute"""
1215

1316
def __init__(self) -> None:
14-
self.attribs = []
15-
self.eval_attribs = []
17+
self.attribs: list[tuple[str, t.Callable[..., t.Any]]] = []
18+
self.eval_attribs: list[str] = []
1619
self.addArgument(
1720
self.attribs, "A", "attribute", "Select tests with matching attribute"
1821
)

nose2/plugins/layers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import logging
24
import re
35
from collections import OrderedDict
@@ -205,7 +207,7 @@ def __init__(self) -> None:
205207
"highlight-words", ["A", "having", "should"]
206208
)
207209
self.highlight_re = re.compile(r"\b(%s)\b" % "|".join(self.highlight_words))
208-
self.layersReported = set()
210+
self.layersReported: set[LayerSuite] = set()
209211

210212
def reportStartTest(self, event):
211213
if self.session.verbosity < 2:

nose2/plugins/loader/generators.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def test_gen():
3030
import logging
3131
import sys
3232
import types
33+
import typing as t
3334
import unittest
3435

3536
from nose2 import exceptions, util
@@ -228,20 +229,32 @@ def createTest(name):
228229

229230

230231
class GeneratorFunctionCase(unittest.FunctionTestCase):
231-
def __init__(self, name, **args) -> None:
232+
def __init__(self, name: str, **args: t.Any) -> None:
232233
self._funcName = name
233-
unittest.FunctionTestCase.__init__(self, None, **args)
234+
# initialize with a placeholder, but it won't be used
235+
# it gets overwritten with `_testFunc` below
236+
unittest.FunctionTestCase.__init__(self, _placeholder_func, **args)
234237

235-
_testFunc = property(
236-
lambda self: getattr(self, self._funcName), lambda self, func: None
237-
)
238+
@property
239+
def _testFunc(self) -> t.Callable[..., t.Any]:
240+
return getattr(self, self._funcName)
241+
242+
@_testFunc.setter
243+
def _testFunc(self, newfunc: t.Callable[..., t.Any]) -> None:
244+
pass
238245

239246
def __repr__(self):
240247
return self._funcName
241248

242249
id = __str__ = __repr__
243250

244251

252+
def _placeholder_func() -> None:
253+
"""
254+
A no-op defined for use inside of GeneratorFunctionCase init.
255+
"""
256+
257+
245258
def GeneratorMethodCase(cls):
246259
class _GeneratorMethodCase(GeneratorFunctionCase):
247260
if util.has_class_fixtures(cls):

nose2/plugins/mp.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
from __future__ import annotations
2+
13
import logging
24
import multiprocessing
35
import multiprocessing.connection as connection
46
import os
57
import select
68
import sys
9+
import typing as t
710
import unittest
811
from collections.abc import Sequence
912

@@ -26,7 +29,7 @@ def __init__(self) -> None:
2629
self._procs = self.config.as_int("processes", 0)
2730
self.setAddress(self.config.as_str("bind_address", None))
2831

29-
self.cases = {}
32+
self.cases: dict[str, unittest.TestCase] = {}
3033

3134
@property
3235
def procs(self):
@@ -458,7 +461,7 @@ def registerInSubprocess(self, event):
458461
"""
459462

460463
def __init__(self, **metadata) -> None:
461-
self.pluginClasses = []
464+
self.pluginClasses: list[type[events.Plugin]] = []
462465
super().__init__(**metadata)
463466

464467

@@ -487,7 +490,7 @@ class RecordingPluginInterface(events.PluginInterface):
487490

488491
def __init__(self) -> None:
489492
super().__init__()
490-
self.events = []
493+
self.events: list[tuple[t.Callable[..., t.Any], events.Event]] = []
491494

492495
def log(self, method, event):
493496
self.events.append((method, event))

nose2/plugins/prettyassert.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@
1010
1111
"""
1212

13+
from __future__ import annotations
14+
1315
import collections
1416
import inspect
1517
import io
1618
import re
1719
import textwrap
1820
import tokenize
21+
import typing as t
1922

2023
from nose2 import events
2124

@@ -262,7 +265,7 @@ def __init__(self, frame_locals, frame_globals) -> None:
262265
# they were encountered
263266
# track which tokens we've seen to avoid duplicates if a name appears
264267
# twice, as in `assert x != x`
265-
self.seen_tokens = collections.OrderedDict()
268+
self.seen_tokens: dict[str, t.Any] = {}
266269

267270
# the previous token seen as a tuple of (tok_type, token_name)
268271
# (or None when we start)

nose2/plugins/result.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
# unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All
2727
# Rights Reserved. See: http://docs.python.org/license.html
2828

29+
from __future__ import annotations
30+
2931
import sys
3032
import unittest
3133

@@ -44,7 +46,7 @@ class ResultReporter(events.Plugin):
4446

4547
def __init__(self) -> None:
4648
self.testsRun = 0
47-
self.reportCategories = {
49+
self.reportCategories: dict[str, list[events.Event]] = {
4850
"failures": [],
4951
"errors": [],
5052
"skipped": [],

nose2/plugins/testid.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
1212
"""
1313

14+
from __future__ import annotations
15+
1416
import os
1517
import pickle
1618
import re
@@ -30,8 +32,8 @@ class TestId(Plugin):
3032

3133
def __init__(self) -> None:
3234
self.idfile = self.config.as_str("id-file", ".noseids")
33-
self.ids = {}
34-
self.tests = {}
35+
self.ids: dict[str, str] = {}
36+
self.tests: dict[str, str] = {}
3537
if not os.path.isabs(self.idfile):
3638
# FIXME expand-user?
3739
self.idfile = os.path.join(os.getcwd(), self.idfile)

0 commit comments

Comments
 (0)