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

Upgrade typehints to support disallow-untyped-defs flag #282

Merged
merged 5 commits into from
Feb 19, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
[run]
branch = True
omit =
nox/_typing.py

[report]
exclude_lines =
pragma: no cover
if _typing.TYPE_CHECKING:
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.mypy_cache/
.vscode/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
6 changes: 6 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[settings]
multi_line_output=3
include_trailing_comma=True
force_grid_wrap=0
use_parentheses=True
line_length=88
8 changes: 4 additions & 4 deletions nox/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@

import sys

from nox import _options, tasks, workflow
from nox.logger import setup_logging

try:
import importlib.metadata as metadata # type: ignore
except ImportError: # pragma: no cover
import importlib_metadata as metadata # type: ignore

from nox import _options, tasks, workflow
from nox.logger import setup_logging


def main():
def main() -> None:
args = _options.options.parse_args()

if args.help:
Expand Down
38 changes: 20 additions & 18 deletions nox/_option_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import collections
import functools
from argparse import ArgumentError, ArgumentParser, Namespace, _ArgumentGroup
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

import argcomplete # type: ignore

Expand Down Expand Up @@ -60,27 +60,27 @@ class Option:
def __init__(
self,
name: str,
*flags,
help: str = None,
group: str = None,
*flags: str,
help: Optional[str] = None,
group: Optional[str] = None,
noxfile: bool = False,
merge_func: Callable[[Namespace, Namespace], Any] = None,
finalizer_func: Callable[[Any, Namespace], Any] = None,
merge_func: Optional[Callable[[Namespace, Namespace], Any]] = None,
finalizer_func: Optional[Callable[[Any, Namespace], Any]] = None,
default: Union[Any, Callable[[], Any]] = None,
hidden: bool = False,
completer: Callable[..., List[str]] = None,
**kwargs
completer: Optional[Callable[..., List[str]]] = None,
**kwargs: Any
) -> None:
self.name = name
self.flags = flags # type: Sequence[str]
self.flags = flags
self.help = help
self.group = group
self.noxfile = noxfile
self.merge_func = merge_func
self.finalizer_func = finalizer_func
self.hidden = hidden
self.completer = completer
self.kwargs = kwargs # type: Dict[str, Any]
self.kwargs = kwargs
self._default = default

@property
Expand Down Expand Up @@ -140,7 +140,7 @@ def make_flag_pair(
name: str,
enable_flags: Union[Tuple[str, str], Tuple[str]],
disable_flags: Tuple[str],
**kwargs
**kwargs: Any
) -> Tuple[Option, Option]:
"""Returns two options - one to enable a behavior and another to disable it.

Expand Down Expand Up @@ -174,15 +174,17 @@ class OptionSet:
finalization, callable defaults, and strongly typed namespaces for tests.
"""

def __init__(self, *args, **kwargs) -> None:
def __init__(self, *args: Any, **kwargs: Any) -> None:
self.parser_args = args
self.parser_kwargs = kwargs
self.options = collections.OrderedDict() # type: Dict[str, Option]
self.options = (
collections.OrderedDict()
) # type: collections.OrderedDict[str, Option]
self.groups = (
collections.OrderedDict()
) # type: Dict[str, Tuple[Tuple[Any, ...], Dict[str, Any]]]
) # type: collections.OrderedDict[str, Tuple[Tuple[Any, ...], Dict[str, Any]]]

def add_options(self, *args) -> None:
def add_options(self, *args: Option) -> None:
"""Adds a sequence of Options to the OptionSet.

Args:
Expand All @@ -191,7 +193,7 @@ def add_options(self, *args) -> None:
for option in args:
self.options[option.name] = option

def add_group(self, name: str, *args, **kwargs) -> None:
def add_group(self, name: str, *args: Any, **kwargs: Any) -> None:
"""Adds a new argument group.

When :func:`parser` is invoked, the OptionSet will turn all distinct
Expand Down Expand Up @@ -233,7 +235,7 @@ def parser(self) -> ArgumentParser:

return parser

def print_help(self):
def print_help(self) -> None:
return self.parser().print_help()

def _finalize_args(self, args: Namespace) -> None:
Expand All @@ -260,7 +262,7 @@ def parse_args(self) -> Namespace:
parser.error(str(err))
return args

def namespace(self, **kwargs):
def namespace(self, **kwargs: Any) -> argparse.Namespace:
"""Return a namespace that contains all of the options in this set.

kwargs can be used to set values and does so in a checked way - you
Expand Down
22 changes: 14 additions & 8 deletions nox/_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import functools
import os
import sys
from typing import List
from typing import Any, List, Optional, Sequence, Union

from nox import _option_set
from nox.tasks import discover_manifest, filter_manifest, load_nox_module
Expand All @@ -39,7 +39,9 @@
)


def _sessions_and_keywords_merge_func(key, command_args, noxfile_args):
def _sessions_and_keywords_merge_func(
key: str, command_args: argparse.Namespace, noxfile_args: argparse.Namespace
) -> List[str]:
"""Only return the Noxfile value for sessions/keywords if neither sessions
or keywords are specified on the command-line.

Expand All @@ -56,7 +58,9 @@ def _sessions_and_keywords_merge_func(key, command_args, noxfile_args):
return getattr(command_args, key)


def _envdir_merge_func(command_args, noxfile_args):
def _envdir_merge_func(
command_args: argparse.Namespace, noxfile_args: argparse.Namespace
) -> str:
"""Ensure that there is always some envdir.

Args:
Expand All @@ -68,14 +72,14 @@ def _envdir_merge_func(command_args, noxfile_args):
return command_args.envdir or noxfile_args.envdir or ".nox"


def _sessions_default():
def _sessions_default() -> Optional[List[str]]:
"""Looks at the NOXSESSION env var to set the default value for sessions."""
nox_env = os.environ.get("NOXSESSION")
env_sessions = nox_env.split(",") if nox_env else None
return env_sessions


def _color_finalizer(value, args):
def _color_finalizer(value: bool, args: argparse.Namespace) -> bool:
"""Figures out the correct value for "color" based on the two color flags.

Args:
Expand All @@ -99,7 +103,9 @@ def _color_finalizer(value, args):
return sys.stdout.isatty()


def _posargs_finalizer(value, args):
def _posargs_finalizer(
value: Sequence[Any], args: argparse.Namespace
) -> Union[Sequence[Any], List[Any]]:
"""Removes the leading "--"s in the posargs array (if any) and asserts that
remaining arguments came after a "--".
"""
Expand All @@ -124,11 +130,11 @@ def _posargs_finalizer(value, args):


def _session_completer(
prefix: str, parsed_args: argparse.Namespace, **kwargs
prefix: str, parsed_args: argparse.Namespace, **kwargs: Any
) -> List[str]:
global_config = parsed_args
module = load_nox_module(global_config)
manifest = discover_manifest(module, global_config)
manifest = discover_manifest(module, global_config) # type: ignore
filtered_manifest = filter_manifest(manifest, global_config)
if isinstance(filtered_manifest, int):
return []
Expand Down
51 changes: 35 additions & 16 deletions nox/_parametrize.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import functools
import itertools
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union


class Param:
Expand All @@ -27,7 +28,12 @@ class Param:
it will be generated from the parameters.
"""

def __init__(self, *args, arg_names=None, id=None):
def __init__(
self,
*args: Any,
arg_names: Optional[Sequence[str]] = None,
id: Optional[str] = None
) -> None:
self.args = tuple(args)
self.id = id

Expand All @@ -37,10 +43,10 @@ def __init__(self, *args, arg_names=None, id=None):
self.arg_names = tuple(arg_names)

@property
def call_spec(self):
def call_spec(self) -> Dict[str, Any]:
return dict(zip(self.arg_names, self.args))

def __str__(self):
def __str__(self) -> str:
if self.id:
return self.id
else:
Expand All @@ -51,16 +57,16 @@ def __str__(self):

__repr__ = __str__

def copy(self):
def copy(self) -> "Param":
new = self.__class__(*self.args, arg_names=self.arg_names, id=self.id)
return new

def update(self, other):
def update(self, other: "Param") -> None:
self.id = ", ".join([str(self), str(other)])
self.args = self.args + other.args
self.arg_names = self.arg_names + other.arg_names

def __eq__(self, other):
def __eq__(self, other: object) -> bool:
if isinstance(other, self.__class__):
return (
self.args == other.args
Expand All @@ -73,14 +79,21 @@ def __eq__(self, other):
raise NotImplementedError


def _apply_param_specs(param_specs, f):
def _apply_param_specs(param_specs: List[Param], f: Any) -> Any:
previous_param_specs = getattr(f, "parametrize", None)
new_param_specs = update_param_specs(previous_param_specs, param_specs)
setattr(f, "parametrize", new_param_specs)
return f


def parametrize_decorator(arg_names, arg_values_list, ids=None):
ArgValue = Union[Param, Iterable[Any]]


def parametrize_decorator(
arg_names: Union[str, List[str], Tuple[str]],
arg_values_list: Union[Iterable[ArgValue], ArgValue],
ids: Optional[Iterable[Optional[str]]] = None,
) -> Callable[[Any], Any]:
"""Parametrize a session.

Add new invocations to the underlying session function using the list of
Expand Down Expand Up @@ -124,8 +137,10 @@ def parametrize_decorator(arg_names, arg_values_list, ids=None):
ids = []

# Generate params for each item in the param_args_values list.
param_specs = []
for param_arg_values, param_id in itertools.zip_longest(arg_values_list, ids):
param_specs = [] # type: List[Param]
for param_arg_values, param_id in itertools.zip_longest(
arg_values_list, ids # type: ignore
):
if isinstance(param_arg_values, Param):
param_spec = param_arg_values
param_spec.arg_names = tuple(arg_names)
Expand All @@ -137,7 +152,9 @@ def parametrize_decorator(arg_names, arg_values_list, ids=None):
return functools.partial(_apply_param_specs, param_specs)


def update_param_specs(param_specs, new_specs):
def update_param_specs(
param_specs: Iterable[Param], new_specs: List[Param]
) -> List[Param]:
"""Produces all combinations of the given sets of specs."""
if not param_specs:
return new_specs
Expand All @@ -152,21 +169,23 @@ def update_param_specs(param_specs, new_specs):
return combined_specs


def generate_calls(func, param_specs):
def generate_calls(
func: Callable[..., Any], param_specs: Iterable[Param]
) -> List[Callable[..., Any]]:
calls = []
for param_spec in param_specs:

def make_call_wrapper(param_spec):
def make_call_wrapper(param_spec: Param) -> Callable[..., Any]:
@functools.wraps(func)
def call_wrapper(*args, **kwargs):
def call_wrapper(*args: Any, **kwargs: Any) -> Any:
kwargs.update(param_spec.call_spec)
return func(*args, **kwargs)

return call_wrapper

call = make_call_wrapper(param_spec)
call.session_signature = "({})".format(param_spec)
call.param_spec = param_spec
call.session_signature = "({})".format(param_spec) # type: ignore
call.param_spec = param_spec # type: ignore
calls.append(call)

return calls
17 changes: 17 additions & 0 deletions nox/_typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
__all__ = ["TYPE_CHECKING", "NoReturn"]

try:
from typing import TYPE_CHECKING
except ImportError:
try:
from typing_extensions import TYPE_CHECKING
except ImportError:
TYPE_CHECKING = False

try:
from typing import NoReturn
except ImportError:
try:
from typing_extensions import NoReturn
except ImportError:
pass
Loading