Skip to content

Commit

Permalink
test: add sams suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
kuwv committed Feb 11, 2023
2 parents 0a23f95 + 0b6a448 commit f24e290
Show file tree
Hide file tree
Showing 19 changed files with 214 additions and 610 deletions.
2 changes: 1 addition & 1 deletion dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ icecream>=2.1
# typing
mypy==0.971
typed-ast==1.5.4
types-PyYAML==6
types-PyYAML==6.0.12.4
6 changes: 3 additions & 3 deletions invoke/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any
from typing import Any, Optional

from ._version import __version_info__, __version__ # noqa
from .collection import Collection # noqa
Expand Down Expand Up @@ -31,7 +31,7 @@
from .watchers import FailingResponder, Responder, StreamWatcher # noqa


def run(command: str, **kwargs: Any) -> Any:
def run(command: str, **kwargs: Any) -> Optional[Result]:
"""
Run ``command`` in a subprocess and return a `.Result` object.
Expand All @@ -50,7 +50,7 @@ def run(command: str, **kwargs: Any) -> Any:
return Context().run(command, **kwargs)


def sudo(command: str, **kwargs: Any) -> Any:
def sudo(command: str, **kwargs: Any) -> Optional[Result]:
"""
Run ``command`` in a ``sudo`` subprocess and return a `.Result` object.
Expand Down
6 changes: 3 additions & 3 deletions invoke/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,15 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
for name, obj in kwargs.items():
self._add_object(obj, name)

def _add_object(self, obj: Any, name: Optional[str] = None) -> Callable:
def _add_object(self, obj: Any, name: Optional[str] = None) -> None:
method: Callable
if isinstance(obj, Task):
method = self.add_task
elif isinstance(obj, (Collection, ModuleType)):
method = self.add_collection
else:
raise TypeError("No idea how to insert {!r}!".format(type(obj)))
return method(obj, name=name)
method(obj, name=name)

def __repr__(self) -> str:
task_names = list(self.tasks.keys())
Expand Down Expand Up @@ -510,7 +510,7 @@ def _transform_lexicon(self, old: Lexicon) -> Lexicon:
return new

@property
def task_names(self) -> Dict[str, Any]:
def task_names(self) -> Dict[str, List[str]]:
"""
Return all task identifiers for this collection as a one-level dict.
Expand Down
5 changes: 2 additions & 3 deletions invoke/completion/complete.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import os
import re
import shlex
from typing import TYPE_CHECKING, Union
from typing import TYPE_CHECKING

from ..exceptions import Exit, ParseError
from ..util import debug, task_name_sort_key
Expand Down Expand Up @@ -38,8 +38,7 @@ def complete(
# Use last seen context in case of failure (required for
# otherwise-invalid partial invocations being completed).

# FIXME: this seems wonky
contexts: Union[List[ParserContext], ParseResult]
contexts: List[ParserContext]
try:
debug("Seeking context name in tokens: {!r}".format(tokens))
contexts = parser.parse_argv(tokens)
Expand Down
12 changes: 6 additions & 6 deletions invoke/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
try:
from importlib.machinery import SourceFileLoader
except ImportError: # PyPy3
from importlib._bootstrap import ( # type: ignore
from importlib._bootstrap import ( # type: ignore[no-redef]
_SourceFileLoader as SourceFileLoader,
)

Expand Down Expand Up @@ -1030,7 +1030,7 @@ def clone(self, into: Optional[Type["Config"]] = None) -> "Config":
# instantiation" and "I want cloning to not trigger certain things like
# external data source loading".
# NOTE: this will include lazy=True, see end of method
new = klass(**self._clone_init_kwargs(into=into)) # type: ignore
new = klass(**self._clone_init_kwargs(into=into))
# Copy/merge/etc all 'private' data sources and attributes
for name in """
collection
Expand Down Expand Up @@ -1074,7 +1074,7 @@ def clone(self, into: Optional[Type["Config"]] = None) -> "Config":
return new

def _clone_init_kwargs(
self, into: Optional["Config"] = None
self, into: Optional[Type["Config"]] = None
) -> Dict[str, Any]:
"""
Supply kwargs suitable for initializing a new clone of this object.
Expand Down Expand Up @@ -1227,15 +1227,15 @@ def merge_dicts(
return base


def _merge_error(orig: str, new_: Any) -> AmbiguousMergeError:
def _merge_error(orig: object, new: object) -> AmbiguousMergeError:
return AmbiguousMergeError(
"Can't cleanly merge {} with {}".format(
_format_mismatch(orig), _format_mismatch(new_)
_format_mismatch(orig), _format_mismatch(new)
)
)


def _format_mismatch(x: Any) -> str:
def _format_mismatch(x: object) -> str:
return "{} ({!r})".format(type(x), x)


Expand Down
4 changes: 2 additions & 2 deletions invoke/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ def __init__(self, config: Optional[Config] = None) -> None:
self._set(command_cwds=command_cwds)

@property
def config(self) -> Any:
def config(self) -> Config:
# Allows Context to expose a .config attribute even though DataProxy
# otherwise considers it a config key.
return self._config

@config.setter
def config(self, value: Any) -> None:
def config(self, value: Config) -> None:
# NOTE: mostly used by client libraries needing to tweak a Context's
# config at execution time; i.e. a Context subclass that bears its own
# unique data may want to be stood up when parameterizing/expanding a
Expand Down
26 changes: 13 additions & 13 deletions invoke/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"""

import os
from typing import TYPE_CHECKING, Any, Dict, List
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Mapping, Sequence

from .exceptions import UncastableEnvVar, AmbiguousEnvVar
from .util import debug
Expand Down Expand Up @@ -46,7 +46,7 @@ def load(self) -> Dict[str, Any]:
return self.data

def _crawl(
self, key_path: List[str], env_vars: Dict[str, Any]
self, key_path: List[str], env_vars: Mapping[str, Sequence[str]]
) -> Dict[str, Any]:
"""
Examine config at location ``key_path`` & return potential env vars.
Expand All @@ -61,7 +61,7 @@ def _crawl(
Returns another dictionary of new keypairs as per above.
"""
new_vars: Dict[str, Any] = {}
new_vars: Dict[str, List[str]] = {}
obj = self._path_get(key_path)
# Sub-dict -> recurse
if (
Expand All @@ -85,18 +85,18 @@ def _crawl(
new_vars[self._to_env_var(key_path)] = key_path
return new_vars

def _to_env_var(self, key_path: List[str]) -> str:
def _to_env_var(self, key_path: Iterable[str]) -> str:
return "_".join(key_path).upper()

def _path_get(self, key_path: List[str]) -> "Config":
def _path_get(self, key_path: Iterable[str]) -> "Config":
# Gets are from self._config because that's what determines valid env
# vars and/or values for typecasting.
obj = self._config
for key in key_path:
obj = obj[key]
return obj

def _path_set(self, key_path: List[str], value: str) -> None:
def _path_set(self, key_path: Sequence[str], value: str) -> None:
# Sets are to self.data since that's what we are presenting to the
# outer config object and debugging.
obj = self.data
Expand All @@ -105,19 +105,19 @@ def _path_set(self, key_path: List[str], value: str) -> None:
obj[key] = {}
obj = obj[key]
old = self._path_get(key_path)
new_ = self._cast(old, value)
obj[key_path[-1]] = new_
new = self._cast(old, value)
obj[key_path[-1]] = new

def _cast(self, old: Any, new_: Any) -> Any:
def _cast(self, old: Any, new: Any) -> Any:
if isinstance(old, bool):
return new_ not in ("0", "")
return new not in ("0", "")
elif isinstance(old, str):
return new_
return new
elif old is None:
return new_
return new
elif isinstance(old, (list, tuple)):
err = "Can't adapt an environment string into a {}!"
err = err.format(type(old))
raise UncastableEnvVar(err)
else:
return old.__class__(new_)
return old.__class__(new)
12 changes: 6 additions & 6 deletions invoke/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def execute(
# an appropriate one; e.g. subclasses might use extra data from
# being parameterized), handing in this config for use there.
context = call.make_context(config)
args = (context,) + call.args
args = (context, *call.args)
result = call.task(*args, **call.kwargs)
if autoprint:
print(result)
Expand All @@ -160,19 +160,19 @@ def normalize(
"""
calls = []
for task in tasks:
name: Optional[str]
if isinstance(task, str):
name = task
kwargs = {}
elif isinstance(task, ParserContext):
# FIXME: task.name can be none here
name = task.name # type: ignore
name = task.name
kwargs = task.as_kwargs
else:
name, kwargs = task
c = Call(task=self.collection[name], kwargs=kwargs, called_as=name)
c = Call(self.collection[name], kwargs=kwargs, called_as=name)
calls.append(c)
if not tasks and self.collection.default is not None:
calls = [Call(task=self.collection[self.collection.default])]
calls = [Call(self.collection[self.collection.default])]
return calls

def dedupe(self, calls: List["Call"]) -> List["Call"]:
Expand Down Expand Up @@ -213,7 +213,7 @@ def expand_calls(self, calls: List["Call"]) -> List["Call"]:
# Normalize to Call (this method is sometimes called with pre/post
# task lists, which may contain 'raw' Task objects)
if isinstance(call, Task):
call = Call(task=call)
call = Call(call)
debug("Expanding task-call {!r}".format(call))
# TODO: this is where we _used_ to call Executor.config_for(call,
# config)...
Expand Down
2 changes: 1 addition & 1 deletion invoke/parser/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
try:
from ..vendor.lexicon import Lexicon
except ImportError:
from lexicon import Lexicon # type: ignore
from lexicon import Lexicon # type: ignore[no-redef]

from .argument import Argument

Expand Down
14 changes: 9 additions & 5 deletions invoke/parser/parser.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import copy
from collections import UserList
from typing import TYPE_CHECKING, Any, Iterable, List, Optional

try:
from ..vendor.lexicon import Lexicon
from ..vendor.fluidity import StateMachine, state, transition
except ImportError:
from lexicon import Lexicon # type: ignore
from fluidity import StateMachine, state, transition # type: ignore
from lexicon import Lexicon # type: ignore[no-redef]
from fluidity import ( # type: ignore[no-redef]
StateMachine,
state,
transition,
)

from ..exceptions import ParseError
from ..util import debug
Expand All @@ -24,7 +27,7 @@ def is_long_flag(value: str) -> bool:
return value.startswith("--")


class ParseResult(UserList):
class ParseResult(List["ParserContext"]):
"""
List-like object with some extra parse-related attributes.
Expand Down Expand Up @@ -109,7 +112,8 @@ def parse_argv(self, argv: List[str]) -> ParseResult:
.. versionadded:: 1.0
"""
machine = ParseMachine(
initial=self.initial, # type: ignore # FIXME: should not be none
# FIXME: initial should not be none
initial=self.initial, # type: ignore[arg-type]
contexts=self.contexts,
ignore_unknown=self.ignore_unknown,
)
Expand Down
32 changes: 20 additions & 12 deletions invoke/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@
import sys
import textwrap
from importlib import import_module # buffalo buffalo
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
from typing import (
TYPE_CHECKING,
Any,
Dict,
List,
Optional,
Sequence,
Tuple,
Type,
)

from . import Collection, Config, Executor, FilesystemLoader
from .completion.complete import complete, print_completion_script
Expand All @@ -15,7 +24,6 @@
from .util import debug, enable_logging, helpline

if TYPE_CHECKING:
from .context import Context
from .loader import Loader
from .parser import ParseResult
from .util import Lexicon
Expand Down Expand Up @@ -185,9 +193,9 @@ def __init__(
namespace: Optional["Collection"] = None,
name: Optional[str] = None,
binary: Optional[str] = None,
loader_class: Optional["Loader"] = None,
executor_class: Optional["Executor"] = None,
config_class: Optional["Config"] = None,
loader_class: Optional[Type["Loader"]] = None,
executor_class: Optional[Type["Executor"]] = None,
config_class: Optional[Type["Config"]] = None,
binary_names: Optional[List[str]] = None,
) -> None:
"""
Expand Down Expand Up @@ -289,7 +297,7 @@ def create_config(self) -> None:
.. versionadded:: 1.0
"""
self.config = self.config_class() # type: ignore
self.config = self.config_class()

def update_config(self, merge: bool = True) -> None:
"""
Expand Down Expand Up @@ -571,9 +579,7 @@ def execute(self) -> None:
# "normal" but also its own possible source of bugs/confusion...
module = import_module(module_path)
klass = getattr(module, class_name)
executor = klass( # type: ignore
self.collection, self.config, self.core
)
executor = klass(self.collection, self.config, self.core)
executor.execute(*self.tasks)

def normalize_argv(self, argv: Optional[List[str]]) -> None:
Expand Down Expand Up @@ -723,7 +729,7 @@ def load_collection(self) -> None:
raise Exit("Can't find any collection named {!r}!".format(e.name))

def _update_core_context(
self, context: "Context", new_args: Dict[str, Any]
self, context: ParserContext, new_args: Dict[str, Any]
) -> None:
# Update core context w/ core_via_task args, if and only if the
# via-task version of the arg was truly given a value.
Expand Down Expand Up @@ -919,7 +925,7 @@ def task_list_opener(self, extra: str = "") -> str:
return text

def display_with_columns(
self, pairs: List[Tuple[str, Optional[str]]], extra: str = ""
self, pairs: Sequence[Tuple[str, Optional[str]]], extra: str = ""
) -> None:
root = self.list_root
print("{}:\n".format(self.task_list_opener(extra=extra)))
Expand All @@ -935,7 +941,9 @@ def display_with_columns(
# TODO: trim/prefix dots
print("Default{} task: {}\n".format(specific, default))

def print_columns(self, tuples: List[Tuple[str, Optional[str]]]) -> None:
def print_columns(
self, tuples: Sequence[Tuple[str, Optional[str]]]
) -> None:
"""
Print tabbed columns from (name, help) ``tuples``.
Expand Down
Loading

0 comments on commit f24e290

Please sign in to comment.