From 71031e086de1d574b5f0640006a40791c4133a8d Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Tue, 12 Apr 2022 14:02:56 -0400 Subject: [PATCH 1/4] Add some missing generic arguments --- nox/sessions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nox/sessions.py b/nox/sessions.py index 3cb838c1..3ca3958a 100644 --- a/nox/sessions.py +++ b/nox/sessions.py @@ -108,7 +108,7 @@ class Status(enum.Enum): class _WorkingDirContext: - def __init__(self, dir: str | os.PathLike) -> None: + def __init__(self, dir: str | os.PathLike[str]) -> None: self._prev_working_dir = os.getcwd() os.chdir(dir) @@ -152,7 +152,7 @@ def name(self) -> str: return self._runner.friendly_name @property - def env(self) -> dict: + def env(self) -> dict[str, str]: """A dictionary of environment variables to pass into all commands.""" return self.virtualenv.env @@ -218,7 +218,7 @@ def invoked_from(self) -> str: """ return self._runner.global_config.invoked_from - def chdir(self, dir: str | os.PathLike) -> _WorkingDirContext: + def chdir(self, dir: str | os.PathLike[str]) -> _WorkingDirContext: """Change the current working directory. Can be used as a context manager to automatically restore the working directory:: @@ -238,7 +238,7 @@ def chdir(self, dir: str | os.PathLike) -> _WorkingDirContext: """An alias for :meth:`chdir`.""" def _run_func( - self, func: Callable, args: Iterable[Any], kwargs: Mapping[str, Any] + self, func: Callable[..., Any], args: Iterable[Any], kwargs: Mapping[str, Any] ) -> Any: """Legacy support for running a function through :func`run`.""" self.log(f"{func}(args={args!r}, kwargs={kwargs!r})") From 5017a8418bc808b727189a5995b2a8ae1e0f8faf Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 19 Apr 2022 15:00:38 -0400 Subject: [PATCH 2/4] fix(types): add full strict checking --- .pre-commit-config.yaml | 4 ++-- nox/_decorators.py | 19 +++++++++++-------- nox/_option_set.py | 8 ++++++-- nox/_options.py | 6 +++--- nox/_version.py | 2 +- nox/command.py | 8 ++++---- nox/logger.py | 4 ++-- nox/manifest.py | 3 +-- nox/popen.py | 6 +++--- nox/sessions.py | 2 +- nox/virtualenv.py | 2 +- pyproject.toml | 16 ++-------------- 12 files changed, 37 insertions(+), 43 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 053b2fb3..f9d8e306 100644 --- a/.pre-commit-config.yaml +++ b/.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.941 hooks: - id: mypy files: ^nox/ - args: [--show-error-codes] + args: [] additional_dependencies: - types-jinja2 - packaging diff --git a/nox/_decorators.py b/nox/_decorators.py index 9720ba49..19e29622 100644 --- a/nox/_decorators.py +++ b/nox/_decorators.py @@ -18,7 +18,7 @@ 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 @@ def __new__( 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, diff --git a/nox/_option_set.py b/nox/_option_set.py index 0f8675f5..0ffcc9d9 100644 --- a/nox/_option_set.py +++ b/nox/_option_set.py @@ -83,7 +83,11 @@ def __init__( 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 @@ def __init__( 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 diff --git a/nox/_options.py b/nox/_options.py index dc29a9d4..ce4290ed 100644 --- a/nox/_options.py +++ b/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( diff --git a/nox/_version.py b/nox/_version.py index 43c70329..ccb5bad2 100644 --- a/nox/_version.py +++ b/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 diff --git a/nox/command.py b/nox/command.py index 01bcc0b1..8a55c1fa 100644 --- a/nox/command.py +++ b/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, diff --git a/nox/logger.py b/nox/logger.py index f53adf65..cb2b909a 100644 --- a/nox/logger.py +++ b/nox/logger.py @@ -47,7 +47,7 @@ def format(self, record: Any) -> str: return super().format(record) -class NoxColoredFormatter(ColoredFormatter): +class NoxColoredFormatter(ColoredFormatter): # type: ignore[misc] def __init__( self, datefmt: Any = None, @@ -70,7 +70,7 @@ def __init__( 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] diff --git a/nox/manifest.py b/nox/manifest.py index a24c8f55..5cd4bc14 100644 --- a/nox/manifest.py +++ b/nox/manifest.py @@ -16,7 +16,6 @@ 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 @@ def notify( 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 diff --git a/nox/popen.py b/nox/popen.py index 2d174ac2..2b52134e 100644 --- a/nox/popen.py +++ b/nox/popen.py @@ -22,7 +22,7 @@ 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]: diff --git a/nox/sessions.py b/nox/sessions.py index 3ca3958a..4a2bf4cc 100644 --- a/nox/sessions.py +++ b/nox/sessions.py @@ -216,7 +216,7 @@ def invoked_from(self) -> str: 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. diff --git a/nox/virtualenv.py b/nox/virtualenv.py index 4233c7b8..8c5b05cf 100644 --- a/nox/virtualenv.py +++ b/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 diff --git a/pyproject.toml b/pyproject.toml index da5a9a5d..9a138ba1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,20 +24,8 @@ exclude_lines = [ [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 [[tool.mypy.overrides]] module = [ "argcomplete", "colorlog.*", "py", "tox.*" ] From 1f8731ad3fe6556d1885fd350ae5d464b712f77b Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 19 Apr 2022 15:03:27 -0400 Subject: [PATCH 3/4] fix(types): enable extra error checks --- nox/workflow.py | 2 +- pyproject.toml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/nox/workflow.py b/nox/workflow.py index ed577644..23da77c0 100644 --- a/nox/workflow.py +++ b/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] = [] diff --git a/pyproject.toml b/pyproject.toml index 9a138ba1..649a9d2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,8 @@ files = ["nox"] python_version = "3.7" 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.*" ] From 026fb92285c1620a5c75cc5c0d86fa4d5a8dd460 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 20 Apr 2022 12:36:32 -0400 Subject: [PATCH 4/4] Update .pre-commit-config.yaml --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f9d8e306..fed3f0a2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -63,7 +63,7 @@ repos: additional_dependencies: *flake8-dependencies - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.941 + rev: v0.942 hooks: - id: mypy files: ^nox/