py-wait-until 0.0.1__py3-none-any.whl

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.
File without changes
py_wait_until/main.py ADDED
@@ -0,0 +1,96 @@
1
+ import argparse
2
+ import subprocess
3
+ import sys
4
+ import time
5
+ from collections.abc import Generator, Sequence
6
+ from typing import TextIO
7
+
8
+ WAIT_DURATION_SECONDS = 0.1
9
+ ANSI_CLEAR_LINE = "\033[2K"
10
+ ANSI_HIDE_CURSOR = "\033[?25l"
11
+ ANSI_SHOW_CURSOR = "\033[?25h"
12
+
13
+
14
+ def _write_line(stream: TextIO, message: str) -> None:
15
+ """
16
+ Write and flush a line to the given stream.
17
+ """
18
+
19
+ stream.write(message)
20
+ stream.flush()
21
+
22
+
23
+ def _spinner() -> Generator[str]:
24
+ """
25
+ Return an infinite generator that yields spinner characters.
26
+ """
27
+
28
+ chars = ["|", "/", "-", "\\"]
29
+ index = -1
30
+ while True:
31
+ index += 1
32
+ yield chars[index % len(chars)]
33
+
34
+
35
+ def _wait_for_process(cmd: list[str]) -> int:
36
+ """
37
+ Execute a command and display a waiting message until it completes.
38
+ """
39
+
40
+ # Only show spinner if stdout is a TTY (interactive terminal)
41
+ if is_tty := sys.stdout.isatty():
42
+ _write_line(sys.stdout, ANSI_HIDE_CURSOR)
43
+
44
+ process = subprocess.Popen( # noqa: S603
45
+ cmd,
46
+ stdout=subprocess.PIPE,
47
+ stderr=subprocess.PIPE,
48
+ text=True,
49
+ )
50
+
51
+ spin = _spinner()
52
+ while process.poll() is None:
53
+ if is_tty:
54
+ _write_line(
55
+ sys.stdout,
56
+ f"\rWaiting for process to finish... {next(spin)}",
57
+ )
58
+ time.sleep(WAIT_DURATION_SECONDS)
59
+
60
+ if is_tty:
61
+ _write_line(sys.stdout, f"\r{ANSI_CLEAR_LINE}")
62
+ _write_line(sys.stdout, ANSI_SHOW_CURSOR)
63
+
64
+ stdout, stderr = process.communicate()
65
+ if stdout:
66
+ _write_line(sys.stdout, stdout)
67
+ if stderr:
68
+ _write_line(sys.stderr, stderr)
69
+
70
+ return process.returncode
71
+
72
+
73
+ def main(argv: Sequence[str] | None = None) -> int:
74
+ """
75
+ Wait until a command completes.
76
+ """
77
+
78
+ parser = argparse.ArgumentParser(
79
+ description="Wait until a command completes.",
80
+ )
81
+ parser.add_argument(
82
+ "command",
83
+ nargs=argparse.REMAINDER,
84
+ help="Command and arguments to execute",
85
+ )
86
+
87
+ args = parser.parse_args(argv)
88
+ if not args.command:
89
+ parser.print_help()
90
+ return 1
91
+
92
+ return _wait_for_process(args.command)
93
+
94
+
95
+ if __name__ == "__main__":
96
+ raise SystemExit(main()) # pragma: no cover
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.3
2
+ Name: py-wait-until
3
+ Version: 0.0.1
4
+ Summary: Print a loading spinner while another process is running.
5
+ Author: billwallis
6
+ Requires-Python: >=3.13
7
+ Description-Content-Type: text/markdown
8
+
9
+ <span align="center">
10
+
11
+ [![Python](https://img.shields.io/badge/Python-3.11+-blue.svg)](https://www.python.org/downloads/)
12
+ [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
13
+ [![tests](https://github.com/billwallis/py-wait-until/actions/workflows/tests.yaml/badge.svg)](https://github.com/billwallis/py-wait-until/actions/workflows/tests.yaml)
14
+ [![coverage](https://raw.githubusercontent.com/billwallis/py-wait-until/refs/heads/main/coverage.svg)](https://github.com/dbrgn/coverage-badge)
15
+
16
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
17
+ [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/billwallis/py-wait-until/main.svg)](https://results.pre-commit.ci/latest/github/billwallis/py-wait-until/main)
18
+ [![GitHub last commit](https://img.shields.io/github/last-commit/billwallis/py-wait-until)](https://shields.io/badges/git-hub-last-commit)
19
+
20
+ </span>
21
+
22
+ ---
23
+
24
+ # Wait Until
25
+
26
+ Print a loading spinner while another process is running.
27
+
28
+ ## Usage
29
+
30
+ Simply prepend `py-wait-until` to any command:
31
+
32
+ ```shell
33
+ py-wait-until python -c "import time; time.sleep(2)"
34
+ ```
35
+
36
+ ## Contributing
37
+
38
+ Install [uv](https://docs.astral.sh/uv/getting-started/installation/) and then install the dependencies:
39
+
40
+ ```bash
41
+ uvx --from poethepoet poe install
42
+ ```
@@ -0,0 +1,6 @@
1
+ py_wait_until/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ py_wait_until/main.py,sha256=eansiUoTZOUImJHIlfai7xW3PrsTrmJIm3iGt8TkOlM,2226
3
+ py_wait_until-0.0.1.dist-info/WHEEL,sha256=YUH1mBqsx8Dh2cQG2rlcuRYUhJddG9iClegy4IgnHik,79
4
+ py_wait_until-0.0.1.dist-info/entry_points.txt,sha256=ekKOf3eXkTa9pFubMq_7hXO3ct2xKP5eyzaGt2Vc7cs,59
5
+ py_wait_until-0.0.1.dist-info/METADATA,sha256=ae37rwzjsbQye8ad9KGdHb6ToPxQGY15UxPiOFT7l_E,1652
6
+ py_wait_until-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.11
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ py-wait-until = py_wait_until.main:main
3
+