Skip to content

Commit

Permalink
Add type hints, update few functions (#728)
Browse files Browse the repository at this point in the history
Signed-off-by: Stanislav Filin <[email protected]>
  • Loading branch information
stasfilin authored Jul 16, 2023
1 parent 6866ed4 commit 274df9b
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 35 deletions.
38 changes: 23 additions & 15 deletions nox/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,34 @@
from __future__ import annotations

import sys
from typing import Any

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


def execute_workflow(args: Any) -> int:
"""
Execute the appropriate tasks.
"""

return workflow.execute(
global_config=args,
workflow=(
tasks.load_nox_module,
tasks.merge_noxfile_options,
tasks.discover_manifest,
tasks.filter_manifest,
tasks.honor_list_request,
tasks.run_manifest,
tasks.print_summary,
tasks.create_report,
tasks.final_reduce,
),
)


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

Expand All @@ -43,21 +65,7 @@ def main() -> None:
color=args.color, verbose=args.verbose, add_timestamp=args.add_timestamp
)

# Execute the appropriate tasks.
exit_code = workflow.execute(
global_config=args,
workflow=(
tasks.load_nox_module,
tasks.merge_noxfile_options,
tasks.discover_manifest,
tasks.filter_manifest,
tasks.honor_list_request,
tasks.run_manifest,
tasks.print_summary,
tasks.create_report,
tasks.final_reduce,
),
)
exit_code = execute_workflow(args)

# Done; exit.
sys.exit(exit_code)
Expand Down
28 changes: 21 additions & 7 deletions nox/_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,23 @@
if TYPE_CHECKING:
from ._parametrize import Param

T = TypeVar("T", bound=Callable[..., Any])


class FunctionDecorator:
"""This is a function decorator."""

def __new__(
cls, func: Callable[..., Any], *args: Any, **kwargs: Any
cls: Any, func: Callable[..., Any], *args: Any, **kwargs: Any
) -> FunctionDecorator:
obj = super().__new__(cls)
return functools.wraps(func)(obj)


T = TypeVar("T", bound=Callable[..., Any])
functools.update_wrapper(obj, func)
return cast(FunctionDecorator, obj)


def _copy_func(src: T, name: str | None = None) -> T:
"""This function copies another function, optionally with a new name."""

dst = types.FunctionType(
src.__code__,
src.__globals__,
Expand All @@ -53,6 +57,8 @@ def _copy_func(src: T, name: str | None = None) -> T:


class Func(FunctionDecorator):
"""This is a function decorator that adds additional Nox-specific metadata."""

def __init__(
self,
func: Callable[..., Any],
Expand All @@ -63,7 +69,7 @@ def __init__(
venv_params: Any = None,
should_warn: Mapping[str, Any] | None = None,
tags: Sequence[str] | None = None,
):
) -> None:
self.func = func
self.python = python
self.reuse_venv = reuse_venv
Expand All @@ -77,6 +83,8 @@ def __call__(self, *args: Any, **kwargs: Any) -> Any:
return self.func(*args, **kwargs)

def copy(self, name: str | None = None) -> Func:
"""Copy this function with a new name."""

return Func(
_copy_func(self.func, name),
self.python,
Expand All @@ -90,6 +98,8 @@ def copy(self, name: str | None = None) -> Func:


class Call(Func):
"""This represents a call of a function with a particular set of arguments."""

def __init__(self, func: Func, param_spec: Param) -> None:
call_spec = param_spec.call_spec
session_signature = f"({param_spec})"
Expand Down Expand Up @@ -124,5 +134,9 @@ def __call__(self, *args: Any, **kwargs: Any) -> Any:
return super().__call__(*args, **kwargs)

@classmethod
def generate_calls(cls, func: Func, param_specs: Iterable[Param]) -> list[Call]:
def generate_calls(
cls: type[Call], func: Func, param_specs: Iterable[Param]
) -> list[Call]:
"""Generates a list of calls based on the function and parameters."""

return [cls(func, param_spec) for param_spec in param_specs]
6 changes: 4 additions & 2 deletions nox/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
else: # pragma: no cover
from typing import Literal

ExternalType = Literal["error", True, False]


class CommandFailed(Exception):
"""Raised when an executed command returns a non-success status code."""
Expand All @@ -53,7 +55,7 @@ def which(program: str | os.PathLike[str], paths: Sequence[str] | None) -> str:
raise CommandFailed(f"Program {program} not found")


def _clean_env(env: Mapping[str, str] | None) -> dict[str, str] | None:
def _clean_env(env: Mapping[str, str] | None = None) -> dict[str, str] | None:
if env is None:
return None

Expand All @@ -80,7 +82,7 @@ def run(
paths: Sequence[str] | None = None,
success_codes: Iterable[int] | None = None,
log: bool = True,
external: Literal["error"] | bool = False,
external: ExternalType = False,
**popen_kws: Any,
) -> str | bool:
"""Run a command-line program."""
Expand Down
16 changes: 8 additions & 8 deletions nox/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,25 @@ def session_decorator(__func: F) -> F:
@overload
def session_decorator(
__func: None = ...,
python: Python = ...,
py: Python = ...,
python: Python | None = ...,
py: Python | None = ...,
reuse_venv: bool | None = ...,
name: str | None = ...,
venv_backend: Any = ...,
venv_params: Any = ...,
venv_backend: Any | None = ...,
venv_params: Any | None = ...,
tags: Sequence[str] | None = ...,
) -> Callable[[F], F]:
...


def session_decorator(
func: F | None = None,
python: Python = None,
py: Python = None,
python: Python | None = None,
py: Python | None = None,
reuse_venv: bool | None = None,
name: str | None = None,
venv_backend: Any = None,
venv_params: Any = None,
venv_backend: Any | None = None,
venv_params: Any | None = None,
tags: Sequence[str] | None = None,
) -> F | Callable[[F], F]:
"""Designate the decorated function as a session."""
Expand Down
11 changes: 9 additions & 2 deletions nox/tox_to_nox.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@


def wrapjoin(seq: Iterator[Any]) -> str:
"""Wrap each item in single quotes and join them with a comma."""
return ", ".join([f"'{item}'" for item in seq])


def fixname(envname: str) -> str:
"""Replace dashes with underscores and check if the result is a valid identifier."""
envname = envname.replace("-", "_")
if not envname.isidentifier():
print(
Expand All @@ -44,6 +46,12 @@ def fixname(envname: str) -> str:
return envname


def write_output_to_file(output: str, filename: str) -> None:
"""Write output to a file."""
with open(filename, "w") as outfile:
outfile.write(output)


def main() -> None:
parser = argparse.ArgumentParser(description="Converts toxfiles to noxfiles.")
parser.add_argument("--output", default="noxfile.py")
Expand All @@ -53,5 +61,4 @@ def main() -> None:
config = tox.config.parseconfig([])
output = _TEMPLATE.render(config=config, wrapjoin=wrapjoin, fixname=fixname)

with open(args.output, "w") as outfile:
outfile.write(output)
write_output_to_file(output, args.output)
3 changes: 2 additions & 1 deletion nox/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ def execute(
args: list[Any] = []
if return_value is not None:
args.append(return_value)
return_value = function_(*args, global_config=global_config)
kwargs: dict[str, Any] = {"global_config": global_config}
return_value = function_(*args, **kwargs)

# If we got an integer value as a result, abort task processing
# and return it.
Expand Down

0 comments on commit 274df9b

Please sign in to comment.