Skip to content

Commit

Permalink
Fix mypy failures
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sirosen committed Dec 16, 2024
1 parent f300925 commit 30aaf86
Show file tree
Hide file tree
Showing 19 changed files with 114 additions and 56 deletions.
4 changes: 3 additions & 1 deletion nose2/config.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

TRUE_VALS = {"1", "t", "true", "on", "yes", "y"}
__unittest = True

Expand All @@ -13,7 +15,7 @@ class Config:

def __init__(self, items) -> None:
self._items = items
self._mvd = {}
self._mvd: dict[str, list[str]] = {}
for k, v in items:
self._mvd.setdefault(k, []).append(v)

Expand Down
31 changes: 19 additions & 12 deletions nose2/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

from nose2 import config, util

if t.TYPE_CHECKING:
from nose2.session import Session

log = logging.getLogger(__name__)
__unittest = True

Expand Down Expand Up @@ -98,8 +101,12 @@ class Plugin(metaclass=PluginMeta):
"""

alwaysOn = False
registered = False
# annotate instance vars created via PluginMeta
session: Session
config: config.Config

alwaysOn: bool = False
registered: bool = False

def register(self):
"""Register with appropriate hooks.
Expand Down Expand Up @@ -226,7 +233,7 @@ class Hook:

def __init__(self, method) -> None:
self.method = method
self.plugins = []
self.plugins: list[Plugin] = []

def __call__(self, event):
for plugin in self.plugins[:]:
Expand Down Expand Up @@ -320,7 +327,7 @@ class PluginInterface:
hookClass: type[Hook] = Hook

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

def addMethod(self, method):
"""Add a method to the available method.
Expand Down Expand Up @@ -840,7 +847,7 @@ class LoadFromModuleEvent(Event):
def __init__(self, loader, module, **kw) -> None:
self.loader = loader
self.module = module
self.extraTests = []
self.extraTests: list[unittest.TestCase] = []
super().__init__(**kw)


Expand Down Expand Up @@ -883,7 +890,7 @@ class LoadFromTestCaseEvent(Event):
def __init__(self, loader, testCase, **kw) -> None:
self.loader = loader
self.testCase = testCase
self.extraTests = []
self.extraTests: list[unittest.TestCase] = []
super().__init__(**kw)


Expand Down Expand Up @@ -922,7 +929,7 @@ def __init__(self, loader, names, module, **kw) -> None:
self.loader = loader
self.names = names
self.module = module
self.extraTests = []
self.extraTests: list[unittest.TestCase] = []
super().__init__(**kw)

def __str__(self):
Expand Down Expand Up @@ -964,7 +971,7 @@ def __init__(self, loader, name, module, **kw) -> None:
self.loader = loader
self.name = name
self.module = module
self.extraTests = []
self.extraTests: list[unittest.TestCase] = []
super().__init__(**kw)


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

def __init__(self, loader, name, path, pattern, topLevelDirectory, **kw) -> None:
self.extraTests = []
self.extraTests: list[unittest.TestCase] = []
self.path = path
self.loader = loader
self.name = name
Expand Down Expand Up @@ -1105,8 +1112,8 @@ def __init__(self, loader, testCase, isTestMethod, **kw) -> None:
self.loader = loader
self.testCase = testCase
self.testMethodPrefix = None
self.extraNames = []
self.excludedNames = []
self.extraNames: list[str] = []
self.excludedNames: list[str] = []
self.isTestMethod = isTestMethod
super().__init__(**kw)

Expand Down Expand Up @@ -1212,7 +1219,7 @@ class OutcomeDetailEvent(Event):

def __init__(self, outcomeEvent, **kw) -> None:
self.outcomeEvent = outcomeEvent
self.extraDetail = []
self.extraDetail: list[str] = []
super().__init__(**kw)


Expand Down
11 changes: 7 additions & 4 deletions nose2/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from __future__ import annotations

import logging
import os
import sys
import typing as t
import unittest

from nose2 import events, loader, plugins, runner, session, util
Expand Down Expand Up @@ -71,16 +74,16 @@ class PluggableTestProgram(unittest.TestProgram):
_currentSession = None
loaderClass = loader.PluggableTestLoader
runnerClass = runner.PluggableTestRunner
defaultPlugins = plugins.DEFAULT_PLUGINS
excludePlugins = ()
defaultPlugins: t.ClassVar[t.Sequence[str]] = plugins.DEFAULT_PLUGINS
excludePlugins: t.ClassVar[t.Sequence[str]] = ()

# XXX override __init__ to warn that testLoader and testRunner are ignored?
def __init__(self, **kw) -> None:
plugins = kw.pop("plugins", [])
exclude = kw.pop("excludePlugins", [])
hooks = kw.pop("extraHooks", [])
self.defaultPlugins = list(self.defaultPlugins)
self.excludePlugins = list(self.excludePlugins)
self.defaultPlugins: list[str] = list(self.defaultPlugins) # type: ignore[misc]
self.excludePlugins: list[str] = list(self.excludePlugins) # type: ignore[misc]
self.extraHooks = hooks
self.defaultPlugins.extend(plugins)
self.excludePlugins.extend(exclude)
Expand Down
7 changes: 5 additions & 2 deletions nose2/plugins/attrib.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from __future__ import annotations

import logging
import typing as t
from unittest import TestSuite

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

def __init__(self) -> None:
self.attribs = []
self.eval_attribs = []
self.attribs: list[tuple[str, t.Callable[..., t.Any]]] = []
self.eval_attribs: list[str] = []
self.addArgument(
self.attribs, "A", "attribute", "Select tests with matching attribute"
)
Expand Down
4 changes: 3 additions & 1 deletion nose2/plugins/layers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import logging
import re
from collections import OrderedDict
Expand Down Expand Up @@ -205,7 +207,7 @@ def __init__(self) -> None:
"highlight-words", ["A", "having", "should"]
)
self.highlight_re = re.compile(r"\b(%s)\b" % "|".join(self.highlight_words))
self.layersReported = set()
self.layersReported: set[LayerSuite] = set()

def reportStartTest(self, event):
if self.session.verbosity < 2:
Expand Down
23 changes: 18 additions & 5 deletions nose2/plugins/loader/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def test_gen():
import logging
import sys
import types
import typing as t
import unittest

from nose2 import exceptions, util
Expand Down Expand Up @@ -228,20 +229,32 @@ def createTest(name):


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

_testFunc = property(
lambda self: getattr(self, self._funcName), lambda self, func: None
)
@property
def _testFunc(self) -> t.Callable[..., t.Any]:
return getattr(self, self._funcName)

@_testFunc.setter
def _testFunc(self, newfunc: t.Callable[..., t.Any]) -> None:
pass

def __repr__(self):
return self._funcName

id = __str__ = __repr__


def _placeholder_func() -> None:
"""
A no-op defined for use inside of GeneratorFunctionCase init.
"""


def GeneratorMethodCase(cls):
class _GeneratorMethodCase(GeneratorFunctionCase):
if util.has_class_fixtures(cls):
Expand Down
9 changes: 6 additions & 3 deletions nose2/plugins/mp.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from __future__ import annotations

import logging
import multiprocessing
import multiprocessing.connection as connection
import os
import select
import sys
import typing as t
import unittest
from collections.abc import Sequence

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

self.cases = {}
self.cases: dict[str, unittest.TestCase] = {}

@property
def procs(self):
Expand Down Expand Up @@ -458,7 +461,7 @@ def registerInSubprocess(self, event):
"""

def __init__(self, **metadata) -> None:
self.pluginClasses = []
self.pluginClasses: list[type[events.Plugin]] = []
super().__init__(**metadata)


Expand Down Expand Up @@ -487,7 +490,7 @@ class RecordingPluginInterface(events.PluginInterface):

def __init__(self) -> None:
super().__init__()
self.events = []
self.events: list[tuple[t.Callable[..., t.Any], events.Event]] = []

def log(self, method, event):
self.events.append((method, event))
Expand Down
5 changes: 4 additions & 1 deletion nose2/plugins/prettyassert.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
"""

from __future__ import annotations

import collections
import inspect
import io
import re
import textwrap
import tokenize
import typing as t

from nose2 import events

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

# the previous token seen as a tuple of (tok_type, token_name)
# (or None when we start)
Expand Down
4 changes: 3 additions & 1 deletion nose2/plugins/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
# unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All
# Rights Reserved. See: http://docs.python.org/license.html

from __future__ import annotations

import sys
import unittest

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

def __init__(self) -> None:
self.testsRun = 0
self.reportCategories = {
self.reportCategories: dict[str, list[events.Event]] = {
"failures": [],
"errors": [],
"skipped": [],
Expand Down
6 changes: 4 additions & 2 deletions nose2/plugins/testid.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"""

from __future__ import annotations

import os
import pickle
import re
Expand All @@ -30,8 +32,8 @@ class TestId(Plugin):

def __init__(self) -> None:
self.idfile = self.config.as_str("id-file", ".noseids")
self.ids = {}
self.tests = {}
self.ids: dict[str, str] = {}
self.tests: dict[str, str] = {}
if not os.path.isabs(self.idfile):
# FIXME expand-user?
self.idfile = os.path.join(os.getcwd(), self.idfile)
Expand Down
6 changes: 4 additions & 2 deletions nose2/session.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import argparse
import logging
import os
Expand Down Expand Up @@ -80,7 +82,7 @@ def __init__(self) -> None:
)
self.config = ConfigParser()
self.hooks = events.PluginInterface()
self.plugins = []
self.plugins: list[events.Plugin] = []
# this will be reset later, whenever handleCfgArgs happens, but it
# starts at 1 so that it always has a non-negative integer value
self.verbosity = 1
Expand All @@ -89,7 +91,7 @@ def __init__(self) -> None:
self.testResult = None
self.testLoader = None
self.logLevel = logging.WARN
self.configCache = {}
self.configCache: dict[str, dict[str, config.Config]] = {}

def get(self, section):
"""Get a config section.
Expand Down
13 changes: 8 additions & 5 deletions nose2/sphinxext.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from __future__ import annotations

import types
import typing as t

from docutils import nodes
from docutils.parsers.rst import Directive, directives
Expand Down Expand Up @@ -174,7 +177,7 @@ def setup(app):
class ConfigBucket:
def __init__(self) -> None:
self.section = None
self.vars = {}
self.vars: dict[str, dict[str, t.Any]] = {}

def __call__(self, items):
self.vars = dict(items)
Expand Down Expand Up @@ -219,10 +222,10 @@ def get(self, item, default=DEFAULT):

class OptBucket:
def __init__(self, doc=None, prog="nosetests") -> None:
self.seen = set()
self.opts = []
self.doc = doc
self.prog = prog
self.seen: set[t.Any] = set()
self.opts: list[Opt] = []
self.doc: str | None = doc
self.prog: str = prog

def __iter__(self):
return iter(self.opts)
Expand Down
Loading

0 comments on commit 30aaf86

Please sign in to comment.