invoke-toolkit 0.0.66__tar.gz → 0.0.69__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/PKG-INFO +1 -1
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/collections.py +7 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/runners/rich.py +37 -6
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_collection.py +24 -0
- invoke_toolkit-0.0.69/tests/test_pty_stdin.py +24 -0
- invoke_toolkit-0.0.69/tests/test_release_guard.py +85 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/.gitignore +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/LICENSE.txt +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/README.md +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/pyproject.toml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/__main__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/completion.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/config/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/config/config.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/config/registry.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/config/schema.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/config/status_helper.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/context/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/context/async_tools.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/context/context.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/context/types.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/executor.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/config.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/create.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/dist.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/shell.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/field_resolvers.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/loader/entrypoint.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/log/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/log/logger.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/output/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/output/console.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/output/utils.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/parser.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/program/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/program/main.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/program/program.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/py.typed +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/runners/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/scripts/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/scripts/loader.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/tasks/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/tasks/autocomplete.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/tasks/cache.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/tasks/fields.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/tasks/fields.pyi +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/tasks/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/tasks/types.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/testing.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/utils/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/utils/fzf.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/utils/inspection.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/utils/singleton.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/utils/text.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/package-template/.gitignore.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/package-template/README.md.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/package-template/copier.yml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/package-template/pyproject.toml.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/package-template/src/{{package_slug}}/__init__.py.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/package-template/src/{{package_slug}}/tasks.py.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/provider-template/.gitignore.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/provider-template/README.md.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/provider-template/copier.yml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/provider-template/pyproject.toml.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/provider-template/src/{{package_slug}}/__init__.py.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/provider-template/tests/test_resolver.py.jinja +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/conftest.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/cached_completion/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/completion_with_config/.gitignore +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/completion_with_config/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/config_schema/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/enum_select_size/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/fzf_selector/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/literal_set_level/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/local_field_resolver/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/local_tasks/local_tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/local_tasks/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/extensions/conftest.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/extensions/test_config_tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/extensions/test_create.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/extensions/test_package_template_entrypoint.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/extensions/test_shell_tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/fixtures/future_fields.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/all-four/invoke.json +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/all-four/invoke.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/all-four/invoke.yml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/collection.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/echo.yaml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/json/invoke.json +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/json-and-python/invoke.json +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/json-and-python/invoke.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/no-dedupe.yaml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/no-echo.yaml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/package/invoke.yml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/package/tasks/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/python/invoke.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/runtime.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/three-of-em/invoke.json +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/three-of-em/invoke.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/three-of-em/invoke.yml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/underscores/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/yaml/explicit.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/yaml/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/yml/explicit.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/yml/invoke.yml +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/yml/tasks.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/has_modules.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/conftest.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/test_config.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/program/main.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/program/tasks/__init__.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/program/tasks/coll1.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/script/test_script.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/tasks/test_cache.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/tasks/test_extensions_config.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_alias_self_reference.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_annotated_help.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_async_edge_cases.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_async_support.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_cofig_class.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_collection_configure.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_completion_with_choices.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_config_helper.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_config_registry.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_config_schema.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_console.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_context_class.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_disable_status_cli.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_enum_arguments.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_executor.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_field_typing.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_fields.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_file_completion.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_global_context.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_help_flags.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_invoke_3_compat.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_invoke_compatibility.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_list_filter_flags.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_loader.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_parsing.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_proctitle.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_program_with_collection.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/test_toplevel.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/typecheck/fields.py +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/typecheck/fields_negative.py.fixture +0 -0
- {invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/utils/test_fzf.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: invoke-toolkit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.69
|
|
4
4
|
Summary: Extended APIs for PyInvoke: composable task plugins, typed CLI args, Rich output, shell completion, and PEP 723 script support
|
|
5
5
|
Project-URL: Documentation, https://github.com/D3f0/invoke-toolkit#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/D3f0/invoke-toolkit/issues
|
|
@@ -250,6 +250,13 @@ class ToolkitCollection(Collection):
|
|
|
250
250
|
if not local_tasks_file.exists():
|
|
251
251
|
debug(f"No local_tasks.py found at {local_tasks_file}")
|
|
252
252
|
return
|
|
253
|
+
if "local" in self.tasks:
|
|
254
|
+
logger.warning(
|
|
255
|
+
"Skipping local_tasks.py at %s because tasks.py already defines "
|
|
256
|
+
"the 'local' task namespace",
|
|
257
|
+
local_tasks_file,
|
|
258
|
+
)
|
|
259
|
+
return
|
|
253
260
|
|
|
254
261
|
debug(f"Loading local tasks from {local_tasks_file}")
|
|
255
262
|
|
|
@@ -3,15 +3,24 @@ Config object used for invoke attribute resolution
|
|
|
3
3
|
in tasks.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import array
|
|
7
|
+
import errno
|
|
6
8
|
import sys
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
9
|
+
from typing import IO, TYPE_CHECKING
|
|
8
10
|
|
|
9
|
-
from invoke.runners import Local
|
|
10
|
-
from invoke.util import debug
|
|
11
|
+
from invoke.runners import Local, ready_for_reading
|
|
12
|
+
from invoke.util import debug, has_fileno, isatty
|
|
11
13
|
from rich.syntax import Syntax
|
|
12
14
|
|
|
13
15
|
from invoke_toolkit.output import get_console
|
|
14
16
|
|
|
17
|
+
if sys.platform != "win32":
|
|
18
|
+
import fcntl
|
|
19
|
+
import termios
|
|
20
|
+
else:
|
|
21
|
+
fcntl = None # pylint: disable=invalid-name
|
|
22
|
+
termios = None # pylint: disable=invalid-name
|
|
23
|
+
|
|
15
24
|
if TYPE_CHECKING:
|
|
16
25
|
from invoke_toolkit.config.status_helper import StatusHelper
|
|
17
26
|
|
|
@@ -96,9 +105,31 @@ class OutputCapturingStream:
|
|
|
96
105
|
|
|
97
106
|
|
|
98
107
|
class NoStdoutRunner(Local):
|
|
99
|
-
"""Invoke runner
|
|
100
|
-
|
|
101
|
-
|
|
108
|
+
"""Invoke runner with output handling and safe POSIX stdin probing."""
|
|
109
|
+
|
|
110
|
+
def read_our_stdin(self, input_: IO) -> str | None:
|
|
111
|
+
"""Read stdin without Invoke's undersized POSIX ioctl buffer."""
|
|
112
|
+
if not ready_for_reading(input_):
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
bytes_to_read = 1
|
|
116
|
+
if sys.platform != "win32" and isatty(input_) and has_fileno(input_):
|
|
117
|
+
buffer = array.array("i", [0])
|
|
118
|
+
try:
|
|
119
|
+
fcntl.ioctl(input_, termios.FIONREAD, buffer, True)
|
|
120
|
+
bytes_to_read = max(buffer[0], 1)
|
|
121
|
+
except OSError:
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
bytes_ = input_.read(bytes_to_read)
|
|
126
|
+
except OSError as e:
|
|
127
|
+
if e.errno != errno.EBADF:
|
|
128
|
+
raise
|
|
129
|
+
bytes_ = None
|
|
130
|
+
if bytes_ and isinstance(bytes_, bytes):
|
|
131
|
+
bytes_ = self.decode(bytes_)
|
|
132
|
+
return bytes_
|
|
102
133
|
|
|
103
134
|
def echo(self, command):
|
|
104
135
|
if hasattr(self.context, "print"):
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import ast
|
|
2
|
+
import logging
|
|
2
3
|
import os
|
|
3
4
|
import subprocess
|
|
4
5
|
import sys
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from textwrap import dedent
|
|
8
|
+
from typing import Any, cast
|
|
7
9
|
|
|
10
|
+
from invoke_toolkit import Task, task
|
|
8
11
|
from invoke_toolkit.collections import ToolkitCollection
|
|
9
12
|
|
|
10
13
|
|
|
@@ -216,6 +219,27 @@ def test_load_local_tasks_without_main_tasks(tmp_path: Path):
|
|
|
216
219
|
assert "standalone-task" in local_col.tasks
|
|
217
220
|
|
|
218
221
|
|
|
222
|
+
def test_load_local_tasks_preserves_conflicting_main_task(tmp_path: Path, caplog):
|
|
223
|
+
"""A main task named local takes precedence over local_tasks.py."""
|
|
224
|
+
|
|
225
|
+
def main_task(ctx):
|
|
226
|
+
pass
|
|
227
|
+
|
|
228
|
+
decorated_main_task = cast(Task[Any], task()(main_task))
|
|
229
|
+
ns = ToolkitCollection()
|
|
230
|
+
ns.add_task(decorated_main_task, aliases=("local",))
|
|
231
|
+
(tmp_path / "local_tasks.py").write_text(
|
|
232
|
+
"from invoke_toolkit import task\n\n@task()\ndef local_task(ctx):\n pass\n"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
with caplog.at_level(logging.WARNING, logger="invoke"):
|
|
236
|
+
ns.load_local_tasks(search_path=tmp_path)
|
|
237
|
+
|
|
238
|
+
assert ns.tasks["local"] is decorated_main_task
|
|
239
|
+
assert "local" not in ns.collections
|
|
240
|
+
assert "Skipping local_tasks.py" in caplog.text
|
|
241
|
+
|
|
242
|
+
|
|
219
243
|
def test_load_local_tasks_from_multiple_directories_without_module_collision(
|
|
220
244
|
tmp_path: Path,
|
|
221
245
|
):
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tty
|
|
3
|
+
from contextlib import closing
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from invoke_toolkit import Context
|
|
8
|
+
from invoke_toolkit.runners.rich import NoStdoutRunner
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.mark.skipif(os.name == "nt", reason="PTYs are POSIX-only")
|
|
12
|
+
def test_read_our_stdin_handles_escape_sequence_from_pty():
|
|
13
|
+
master_fd, slave_fd = os.openpty()
|
|
14
|
+
try:
|
|
15
|
+
tty.setcbreak(slave_fd)
|
|
16
|
+
os.write(master_fd, b"\x1b[A")
|
|
17
|
+
stream = os.fdopen(slave_fd, "rb", closefd=False)
|
|
18
|
+
with closing(stream):
|
|
19
|
+
runner = NoStdoutRunner(Context())
|
|
20
|
+
runner.encoding = "utf-8"
|
|
21
|
+
assert runner.read_our_stdin(stream) == "\x1b[A"
|
|
22
|
+
finally:
|
|
23
|
+
os.close(master_fd)
|
|
24
|
+
os.close(slave_fd)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
REPOSITORY_ROOT = Path(__file__).parents[1]
|
|
9
|
+
GUARD = REPOSITORY_ROOT / "scripts" / "validate-release-tag.sh"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def run(command: list[str], cwd: Path) -> subprocess.CompletedProcess[str]:
|
|
13
|
+
return subprocess.run(command, cwd=cwd, check=True, capture_output=True, text=True)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.fixture
|
|
17
|
+
def release_repository(tmp_path: Path) -> Path:
|
|
18
|
+
remote = tmp_path / "remote.git"
|
|
19
|
+
repository = tmp_path / "repository"
|
|
20
|
+
|
|
21
|
+
run(["git", "init", "--bare", str(remote)], tmp_path)
|
|
22
|
+
run(["git", "clone", str(remote), str(repository)], tmp_path)
|
|
23
|
+
run(["git", "config", "user.email", "test@example.com"], repository)
|
|
24
|
+
run(["git", "config", "user.name", "Test User"], repository)
|
|
25
|
+
(repository / "README").write_text("initial\n")
|
|
26
|
+
run(["git", "add", "README"], repository)
|
|
27
|
+
run(["git", "commit", "-m", "initial"], repository)
|
|
28
|
+
run(["git", "branch", "-M", "main"], repository)
|
|
29
|
+
run(["git", "push", "-u", "origin", "main"], repository)
|
|
30
|
+
return repository
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def guard(tag_name: str, repository: Path) -> subprocess.CompletedProcess[str]:
|
|
34
|
+
output = repository / "github-output"
|
|
35
|
+
return subprocess.run(
|
|
36
|
+
[str(GUARD)],
|
|
37
|
+
cwd=repository,
|
|
38
|
+
env={**os.environ, "TAG_NAME": tag_name, "GITHUB_OUTPUT": str(output)},
|
|
39
|
+
capture_output=True,
|
|
40
|
+
text=True,
|
|
41
|
+
check=False,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_accepts_canonical_tag_at_origin_main(release_repository: Path) -> None:
|
|
46
|
+
run(["git", "tag", "v0.0.67"], release_repository)
|
|
47
|
+
run(["git", "push", "origin", "v0.0.67"], release_repository)
|
|
48
|
+
|
|
49
|
+
result = guard("v0.0.67", release_repository)
|
|
50
|
+
|
|
51
|
+
assert result.returncode == 0
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_rejects_noncanonical_uppercase_tag(release_repository: Path) -> None:
|
|
55
|
+
run(["git", "tag", "V0.0.67"], release_repository)
|
|
56
|
+
run(["git", "push", "origin", "V0.0.67"], release_repository)
|
|
57
|
+
|
|
58
|
+
result = guard("V0.0.67", release_repository)
|
|
59
|
+
|
|
60
|
+
assert result.returncode != 0
|
|
61
|
+
assert "canonical lowercase tag" in result.stderr
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_rejects_tag_behind_updated_origin_main(
|
|
65
|
+
release_repository: Path, tmp_path: Path
|
|
66
|
+
) -> None:
|
|
67
|
+
run(["git", "tag", "v0.0.67"], release_repository)
|
|
68
|
+
run(["git", "push", "origin", "v0.0.67"], release_repository)
|
|
69
|
+
|
|
70
|
+
updater = tmp_path / "updater"
|
|
71
|
+
run(
|
|
72
|
+
["git", "clone", str(release_repository.parent / "remote.git"), str(updater)],
|
|
73
|
+
tmp_path,
|
|
74
|
+
)
|
|
75
|
+
run(["git", "config", "user.email", "test@example.com"], updater)
|
|
76
|
+
run(["git", "config", "user.name", "Test User"], updater)
|
|
77
|
+
run(["git", "checkout", "main"], updater)
|
|
78
|
+
(updater / "README").write_text("updated\n")
|
|
79
|
+
run(["git", "commit", "-am", "advance main"], updater)
|
|
80
|
+
run(["git", "push"], updater)
|
|
81
|
+
|
|
82
|
+
result = guard("v0.0.67", release_repository)
|
|
83
|
+
|
|
84
|
+
assert result.returncode != 0
|
|
85
|
+
assert "does not point to origin/main" in result.stderr
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/__init__.py
RENAMED
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/config.py
RENAMED
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/create.py
RENAMED
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/src/invoke_toolkit/extensions/tasks/shell.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/package-template/pyproject.toml.jinja
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/provider-template/.gitignore.jinja
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/templates/provider-template/pyproject.toml.jinja
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/completion_with_config/.gitignore
RENAMED
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/completion_with_config/tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/examples/local_field_resolver/tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/extensions/test_package_template_entrypoint.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/collection.py
RENAMED
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/echo.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/no-echo.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/runtime.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/yaml/tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/configs/yml/tasks.py
RENAMED
|
File without changes
|
{invoke_toolkit-0.0.66 → invoke_toolkit-0.0.69}/tests/original_invoke/_support/has_modules.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|