Skip to content

Commit

Permalink
Merge branch '906-int'
Browse files Browse the repository at this point in the history
  • Loading branch information
bitprophet committed Feb 12, 2023
2 parents 4a48966 + e01da1a commit 0124f7e
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 31 deletions.
11 changes: 11 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ jobs:
- run: inv www.doctest
- orb/debug

typecheck:
executor:
name: orb/default
version: "3.6"
steps:
- orb/setup
- run: mypy .
- orb/debug


workflows:
main:
Expand All @@ -43,6 +52,8 @@ workflows:
name: Lint
- orb/format:
name: Style check
- typecheck:
name: Types check
- coverage:
name: Test
- regression:
Expand Down
1 change: 0 additions & 1 deletion dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ setuptools>56
icecream>=2.1
# typing
mypy==0.971
typed-ast==1.5.4
types-PyYAML==6.0.12.4
File renamed without changes.
19 changes: 6 additions & 13 deletions integration/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from pathlib import Path
import sys

import pytest
Expand All @@ -15,18 +16,13 @@ def _output_eq(cmd, expected):
assert run(cmd, hide=True).stdout == expected


def _setup(self):
self.cwd = os.getcwd()
# Enter integration/ so Invoke loads its local tasks.py
os.chdir(os.path.dirname(__file__))


class Main:
def setup(self):
# MEH
_setup(self)
def setup_method(self):
self.cwd = os.getcwd()
# Enter integration/_support as all support files are in there now
os.chdir(Path(__file__).parent / "_support")

def teardown(self):
def teardown_method(self):
os.chdir(self.cwd)

class basics:
Expand Down Expand Up @@ -86,7 +82,6 @@ def invocable_via_python_dash_m(self):
class funky_characters_in_stdout:
@only_utf8
def basic_nonstandard_characters(self):
os.chdir("_support")
# Crummy "doesn't explode with decode errors" test
cmd = ("type" if WINDOWS else "cat") + " tree.out"
run(cmd, hide="stderr")
Expand Down Expand Up @@ -117,7 +112,6 @@ def complex_nesting_under_ptys_doesnt_break(self):
def pty_puts_both_streams_in_stdout(self):
if WINDOWS:
return
os.chdir("_support")
err_echo = "{} err.py".format(sys.executable)
command = "echo foo && {} bar".format(err_echo)
r = run(command, hide="both", pty=True)
Expand Down Expand Up @@ -152,7 +146,6 @@ def false_as_optional_arg_default_value_works_okay(self):
# (Dis)proves #416. When bug present, parser gets very confused,
# asks "what the hell is 'whee'?". See also a unit test for
# Task.get_arguments.
os.chdir("_support")
for argstr, expected in (
("", "False"),
("--meh", "True"),
Expand Down
27 changes: 16 additions & 11 deletions invoke/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
Optional,
Tuple,
Type,
Union,
)

# Import some platform-specific things at top level so they can be mocked for
Expand Down Expand Up @@ -1075,7 +1074,7 @@ def start_timer(self, timeout: int) -> None:
self._timer = threading.Timer(timeout, self.kill)
self._timer.start()

def read_proc_stdout(self, num_bytes: int) -> Union[bytes, str, None]:
def read_proc_stdout(self, num_bytes: int) -> Optional[bytes]:
"""
Read ``num_bytes`` from the running process' stdout stream.
Expand All @@ -1087,7 +1086,7 @@ def read_proc_stdout(self, num_bytes: int) -> Union[bytes, str, None]:
"""
raise NotImplementedError

def read_proc_stderr(self, num_bytes: int) -> Union[bytes, str, None]:
def read_proc_stderr(self, num_bytes: int) -> Optional[bytes]:
"""
Read ``num_bytes`` from the running process' stderr stream.
Expand Down Expand Up @@ -1154,11 +1153,13 @@ def send_interrupt(self, interrupt: "KeyboardInterrupt") -> None:
"""
self.write_proc_stdin("\x03")

def returncode(self) -> int:
def returncode(self) -> Optional[int]:
"""
Return the numeric return/exit code resulting from command execution.
:returns: `int`
:returns:
`int`, if any reasonable return code could be determined, or
``None`` in corner cases where that was not possible.
.. versionadded:: 1.0
"""
Expand Down Expand Up @@ -1238,7 +1239,7 @@ def should_use_pty(self, pty: bool = False, fallback: bool = True) -> bool:
use_pty = False
return use_pty

def read_proc_stdout(self, num_bytes: int) -> Union[bytes, str, None]:
def read_proc_stdout(self, num_bytes: int) -> Optional[bytes]:
# Obtain useful read-some-bytes function
if self.using_pty:
# Need to handle spurious OSErrors on some Linux platforms.
Expand All @@ -1265,7 +1266,7 @@ def read_proc_stdout(self, num_bytes: int) -> Union[bytes, str, None]:
data = None
return data

def read_proc_stderr(self, num_bytes: int) -> Union[bytes, str, None]:
def read_proc_stderr(self, num_bytes: int) -> Optional[bytes]:
# NOTE: when using a pty, this will never be called.
# TODO: do we ever get those OSErrors on stderr? Feels like we could?
if self.process and self.process.stderr:
Expand All @@ -1280,7 +1281,9 @@ def _write_proc_stdin(self, data: bytes) -> None:
elif self.process and self.process.stdin:
fd = self.process.stdin.fileno()
else:
raise SubprocessPipeError("No stdin process exists")
raise SubprocessPipeError(
"Unable to write to missing subprocess or stdin!"
)
# Try to write, ignoring broken pipes if encountered (implies child
# process exited before the process piping stdin to us finished;
# there's nothing we can do about that!)
Expand All @@ -1298,7 +1301,9 @@ def close_proc_stdin(self) -> None:
elif self.process and self.process.stdin:
self.process.stdin.close()
else:
raise SubprocessPipeError("No stdin process exists")
raise SubprocessPipeError(
"Unable to close missing subprocess or stdin!"
)

def start(self, command: str, shell: str, env: Dict[str, Any]) -> None:
if self.using_pty:
Expand Down Expand Up @@ -1358,15 +1363,15 @@ def process_is_finished(self) -> bool:
else:
return self.process.poll() is not None

def returncode(self) -> int:
def returncode(self) -> Optional[int]:
if self.using_pty:
# No subprocess.returncode available; use WIFEXITED/WIFSIGNALED to
# determine whch of WEXITSTATUS / WTERMSIG to use.
# TODO: is it safe to just say "call all WEXITSTATUS/WTERMSIG and
# return whichever one of them is nondefault"? Probably not?
# NOTE: doing this in an arbitrary order should be safe since only
# one of the WIF* methods ought to ever return True.
code = 0
code = None
if os.WIFEXITED(self.status):
code = os.WEXITSTATUS(self.status)
elif os.WIFSIGNALED(self.status):
Expand Down
3 changes: 1 addition & 2 deletions invoke/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class Task(Generic[T]):
def __init__(
self,
body: Callable,
/,
name: Optional[str] = None,
aliases: Iterable[str] = (),
positional: Optional[Iterable[str]] = None,
Expand Down Expand Up @@ -484,7 +483,7 @@ def clone(
return klass(**data)


def call(task: "Task", /, *args: Any, **kwargs: Any) -> "Call":
def call(task: "Task", *args: Any, **kwargs: Any) -> "Call":
"""
Describes execution of a `.Task`, typically with pre-supplied arguments.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ disallow_untyped_defs = true
# "unused-awaitable",
#
exclude = [
"integration/", "tests/", "setup.py", "sites/www/conf.py"
"integration/", "tests/", "setup.py", "sites/www/conf.py", "build/",
]
ignore_missing_imports = true
# implicit_reexport = False
Expand Down
3 changes: 0 additions & 3 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ def test(
)


print('test', vars(test), type(test))


# TODO: replace with invocations' once the "call truly local tester" problem is
# solved (see other TODOs). For now this is just a copy/paste/modify.
@task(help=test.help) # type: ignore
Expand Down

0 comments on commit 0124f7e

Please sign in to comment.