Browse Source

fix(types): full strictness checking on mypy (#596)

* Add some missing generic arguments

* fix(types): add full strict checking

* fix(types): enable extra error checks

* Update .pre-commit-config.yaml

Co-authored-by: Robert Craigie <robert@craigie.dev>
Co-authored-by: Tom Fleet <tomfleet2018@gmail.com>
pull/600/head
Henry Schreiner 3 months ago committed by GitHub
parent
commit
af96f51a27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .pre-commit-config.yaml
  2. 19
      nox/_decorators.py
  3. 8
      nox/_option_set.py
  4. 6
      nox/_options.py
  5. 2
      nox/_version.py
  6. 8
      nox/command.py
  7. 4
      nox/logger.py
  8. 3
      nox/manifest.py
  9. 6
      nox/popen.py
  10. 2
      nox/sessions.py
  11. 2
      nox/virtualenv.py
  12. 2
      nox/workflow.py
  13. 18
      pyproject.toml

4
.pre-commit-config.yaml

@ -63,11 +63,11 @@ repos:
additional_dependencies: *flake8-dependencies
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.931
rev: v0.942
hooks:
- id: mypy
files: ^nox/
args: [--show-error-codes]
args: []
additional_dependencies:
- types-jinja2
- packaging

19
nox/_decorators.py

@ -18,7 +18,7 @@ import copy
import functools
import inspect
import types
from typing import Any, Callable, Iterable
from typing import Any, Callable, Iterable, TypeVar, cast
from . import _typing
@ -34,24 +34,27 @@ class FunctionDecorator:
return functools.wraps(func)(obj)
def _copy_func(src: Callable, name: str | None = None) -> Callable:
T = TypeVar("T", bound=Callable[..., Any])
def _copy_func(src: T, name: str | None = None) -> T:
dst = types.FunctionType(
src.__code__,
src.__globals__, # type: ignore[attr-defined]
src.__globals__,
name=name or src.__name__,
argdefs=src.__defaults__, # type: ignore[attr-defined]
closure=src.__closure__, # type: ignore[attr-defined]
argdefs=src.__defaults__,
closure=src.__closure__,
)
dst.__dict__.update(copy.deepcopy(src.__dict__))
dst = functools.update_wrapper(dst, src)
dst.__kwdefaults__ = src.__kwdefaults__ # type: ignore[attr-defined]
return dst
dst.__kwdefaults__ = src.__kwdefaults__
return cast(T, dst)
class Func(FunctionDecorator):
def __init__(
self,
func: Callable,
func: Callable[..., Any],
python: _typing.Python = None,
reuse_venv: bool | None = None,
name: str | None = None,

8
nox/_option_set.py

@ -83,7 +83,11 @@ class Option:
noxfile: bool = False,
merge_func: Callable[[Namespace, Namespace], Any] | None = None,
finalizer_func: Callable[[Any, Namespace], Any] | None = None,
default: Any | Callable[[], Any] = None,
default: bool
| str
| None
| list[str]
| Callable[[], bool | str | None | list[str]] = None,
hidden: bool = False,
completer: Callable[..., list[str]] | None = None,
**kwargs: Any,
@ -101,7 +105,7 @@ class Option:
self._default = default
@property
def default(self) -> bool | str | None:
def default(self) -> bool | str | None | list[str]:
if callable(self._default):
return self._default()
return self._default

6
nox/_options.py

@ -79,8 +79,8 @@ def _sessions_and_keywords_merge_func(
noxfile_Args (_option_set.Namespace): The options specified in the
Noxfile."""
if not command_args.sessions and not command_args.keywords:
return getattr(noxfile_args, key)
return getattr(command_args, key)
return getattr(noxfile_args, key) # type: ignore[no-any-return]
return getattr(command_args, key) # type: ignore[no-any-return]
def _default_venv_backend_merge_func(
@ -123,7 +123,7 @@ def _force_venv_backend_merge_func(
else:
return "none"
else:
return command_args.force_venv_backend or noxfile_args.force_venv_backend
return command_args.force_venv_backend or noxfile_args.force_venv_backend # type: ignore[no-any-return]
def _envdir_merge_func(

2
nox/_version.py

@ -37,7 +37,7 @@ class InvalidVersionSpecifier(Exception):
def get_nox_version() -> str:
"""Return the version of the installed Nox package."""
return metadata.version("nox") # type: ignore[no-untyped-call]
return metadata.version("nox") # type: ignore[no-untyped-call, no-any-return]
def _parse_string_constant(node: ast.AST) -> str | None: # pragma: no cover

8
nox/command.py

@ -46,18 +46,18 @@ def which(program: str, paths: list[str] | None) -> str:
full_path = py.path.local.sysfind(program, paths=paths)
if full_path:
return full_path.strpath
return full_path.strpath # type: ignore[no-any-return]
full_path = py.path.local.sysfind(program)
if full_path:
return full_path.strpath
return full_path.strpath # type: ignore[no-any-return]
logger.error(f"Program {program} not found.")
raise CommandFailed(f"Program {program} not found")
def _clean_env(env: dict | None) -> dict | None:
def _clean_env(env: dict[str, str] | None) -> dict[str, str] | None:
if env is None:
return None
@ -78,7 +78,7 @@ def _shlex_join(args: Sequence[str]) -> str:
def run(
args: Sequence[str],
*,
env: dict | None = None,
env: dict[str, str] | None = None,
silent: bool = False,
paths: list[str] | None = None,
success_codes: Iterable[int] | None = None,

4
nox/logger.py

@ -47,7 +47,7 @@ class NoxFormatter(logging.Formatter):
return super().format(record)
class NoxColoredFormatter(ColoredFormatter):
class NoxColoredFormatter(ColoredFormatter): # type: ignore[misc]
def __init__(
self,
datefmt: Any = None,
@ -70,7 +70,7 @@ class NoxColoredFormatter(ColoredFormatter):
def format(self, record: Any) -> str:
if record.levelname == "OUTPUT":
return self._simple_fmt.format(record)
return super().format(record)
return super().format(record) # type: ignore[no-any-return]
class LoggerWithSuccessAndOutput(logging.getLoggerClass()): # type: ignore[misc]

3
nox/manifest.py

@ -16,7 +16,6 @@ from __future__ import annotations
import argparse
import ast
import collections.abc
import itertools
from collections import OrderedDict
from typing import Any, Iterable, Iterator, Mapping, Sequence
@ -310,7 +309,7 @@ class Manifest:
raise ValueError(f"Session {session} not found.")
class KeywordLocals(collections.abc.Mapping):
class KeywordLocals(Mapping[str, bool]):
"""Eval locals using keywords.
When looking up a local variable the variable name is compared against

6
nox/popen.py

@ -22,7 +22,7 @@ from typing import IO, Mapping, Sequence
def shutdown_process(
proc: subprocess.Popen,
proc: subprocess.Popen[bytes],
interrupt_timeout: float | None,
terminate_timeout: float | None,
) -> tuple[bytes, bytes]:
@ -61,8 +61,8 @@ def popen(
args: Sequence[str],
env: Mapping[str, str] | None = None,
silent: bool = False,
stdout: int | IO | None = None,
stderr: int | IO = subprocess.STDOUT,
stdout: int | IO[str] | None = None,
stderr: int | IO[str] = subprocess.STDOUT,
interrupt_timeout: float | None = 0.3,
terminate_timeout: float | None = 0.2,
) -> tuple[int, str]:

2
nox/sessions.py

@ -216,7 +216,7 @@ class Session:
to the Noxfile's directory before running any sessions. This gives
you the original working directory that Nox was invoked form.
"""
return self._runner.global_config.invoked_from
return self._runner.global_config.invoked_from # type: ignore[no-any-return]
def chdir(self, dir: str | os.PathLike[str]) -> _WorkingDirContext:
"""Change the current working directory.

2
nox/virtualenv.py

@ -112,7 +112,7 @@ def locate_via_py(version: str) -> str | None:
py_exe = py.path.local.sysfind("py")
if py_exe is not None:
try:
return py_exe.sysexec("-" + version, "-c", script).strip()
return py_exe.sysexec("-" + version, "-c", script).strip() # type: ignore[no-any-return]
except py.process.cmdexec.Error:
return None
return None

2
nox/workflow.py

@ -42,7 +42,7 @@ def execute(
"""
try:
# Iterate over each task and run it.
return_value = None
return_value: Any = None
for function_ in workflow:
# Send the previous task's return value if there was one.
args: list[Any] = []

18
pyproject.toml

@ -34,20 +34,10 @@ testpaths = [
[tool.mypy]
files = ["nox"]
python_version = "3.7"
warn_unused_configs = true
disallow_any_generics = false
disallow_subclassing_any = false
disallow_untyped_calls = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = false
no_implicit_reexport = true
strict_equality = true
show_error_codes = true
strict = true
warn_unreachable = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
[[tool.mypy.overrides]]
module = [ "argcomplete", "colorlog.*", "py", "tox.*" ]

Loading…
Cancel
Save