Skip to content
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

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

Merged
merged 6 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ repos:
additional_dependencies: *flake8-dependencies

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.931
rev: v0.941
henryiii marked this conversation as resolved.
Show resolved Hide resolved
hooks:
- id: mypy
files: ^nox/
args: [--show-error-codes]
args: []
additional_dependencies:
- types-jinja2
- packaging
Expand Down
19 changes: 11 additions & 8 deletions nox/_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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__,
Comment on lines -40 to +43
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These were fixed upstream in typeshed and included in mypy 0.94x.

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,
Expand Down
8 changes: 6 additions & 2 deletions nox/_option_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This should probably be generic eventually - Option[str] would hold a str, etc. But didn't look into it.

hidden: bool = False,
completer: Callable[..., list[str]] | None = None,
**kwargs: Any,
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions nox/_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion nox/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions nox/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions nox/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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]
Expand Down
3 changes: 1 addition & 2 deletions nox/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions nox/popen.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand Down Expand Up @@ -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]:
Expand Down
10 changes: 5 additions & 5 deletions nox/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -216,9 +216,9 @@ 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) -> _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::
Expand All @@ -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})")
Expand Down
2 changes: 1 addition & 1 deletion nox/virtualenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion nox/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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] = []
Expand Down
18 changes: 4 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,10 @@ 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
warn_unreachable = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]

[[tool.mypy.overrides]]
module = [ "argcomplete", "colorlog.*", "py", "tox.*" ]
Expand Down