pyallel 0.14.0__tar.gz → 0.15.0__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.
- {pyallel-0.14.0 → pyallel-0.15.0}/PKG-INFO +5 -2
- {pyallel-0.14.0 → pyallel-0.15.0}/README.md +4 -1
- {pyallel-0.14.0 → pyallel-0.15.0}/pyproject.toml +1 -1
- pyallel-0.15.0/src/pyallel/colours.py +32 -0
- pyallel-0.15.0/src/pyallel/constants.py +21 -0
- {pyallel-0.14.0 → pyallel-0.15.0}/src/pyallel/main.py +13 -5
- {pyallel-0.14.0 → pyallel-0.15.0}/src/pyallel/parser.py +8 -0
- {pyallel-0.14.0 → pyallel-0.15.0}/src/pyallel/process.py +69 -64
- pyallel-0.14.0/src/pyallel/constants.py +0 -55
- {pyallel-0.14.0 → pyallel-0.15.0}/LICENSE +0 -0
- {pyallel-0.14.0 → pyallel-0.15.0}/src/pyallel/__init__.py +0 -0
- {pyallel-0.14.0 → pyallel-0.15.0}/src/pyallel/errors.py +0 -0
- {pyallel-0.14.0 → pyallel-0.15.0}/src/pyallel/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyallel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: Run and handle the output of multiple executables in pyallel (as in parallel)
|
|
5
5
|
Home-page: https://github.com/Danthewaann/pyallel
|
|
6
6
|
License: MIT
|
|
@@ -40,7 +40,7 @@ pip install pyallel
|
|
|
40
40
|
Once installed, you can run `pyallel` to see usage information, like so:
|
|
41
41
|
|
|
42
42
|
```
|
|
43
|
-
usage: pyallel [-h] [-t] [-n] [-V] [-v] [commands ...]
|
|
43
|
+
usage: pyallel [-h] [-t] [-n] [-V] [-v] [--colour {yes,no,auto}] [commands ...]
|
|
44
44
|
|
|
45
45
|
Run and handle the output of multiple executables in pyallel (as in parallel)
|
|
46
46
|
|
|
@@ -58,6 +58,8 @@ options:
|
|
|
58
58
|
run in non-interactive mode
|
|
59
59
|
-V, --verbose run in verbose mode
|
|
60
60
|
-v, --version print version and exit
|
|
61
|
+
--colour {yes,no,auto}
|
|
62
|
+
colour terminal output, defaults to "auto"
|
|
61
63
|
```
|
|
62
64
|
|
|
63
65
|
Currently you can provide a variable number of `commands` to run to `pyallel`, like so:
|
|
@@ -94,6 +96,7 @@ pyallel "MYPY_FORCE_COLOR=1 mypy ." \
|
|
|
94
96
|
- [x] Maybe make tail mode followed by an optional dump of all the command output once it
|
|
95
97
|
finishes the default behaviour?
|
|
96
98
|
- [x] Add graceful Ctrl-C interrupt handling to streamed modes
|
|
99
|
+
- [x] Add a `--colour` flag to configure pyallel print colours
|
|
97
100
|
- [ ] Setup build system to convert `pyallel` into a single file executable for ease of
|
|
98
101
|
use and distribution
|
|
99
102
|
- [ ] Add custom parsing of command output to support filtering for errors (like vim's
|
|
@@ -19,7 +19,7 @@ pip install pyallel
|
|
|
19
19
|
Once installed, you can run `pyallel` to see usage information, like so:
|
|
20
20
|
|
|
21
21
|
```
|
|
22
|
-
usage: pyallel [-h] [-t] [-n] [-V] [-v] [commands ...]
|
|
22
|
+
usage: pyallel [-h] [-t] [-n] [-V] [-v] [--colour {yes,no,auto}] [commands ...]
|
|
23
23
|
|
|
24
24
|
Run and handle the output of multiple executables in pyallel (as in parallel)
|
|
25
25
|
|
|
@@ -37,6 +37,8 @@ options:
|
|
|
37
37
|
run in non-interactive mode
|
|
38
38
|
-V, --verbose run in verbose mode
|
|
39
39
|
-v, --version print version and exit
|
|
40
|
+
--colour {yes,no,auto}
|
|
41
|
+
colour terminal output, defaults to "auto"
|
|
40
42
|
```
|
|
41
43
|
|
|
42
44
|
Currently you can provide a variable number of `commands` to run to `pyallel`, like so:
|
|
@@ -73,6 +75,7 @@ pyallel "MYPY_FORCE_COLOR=1 mypy ." \
|
|
|
73
75
|
- [x] Maybe make tail mode followed by an optional dump of all the command output once it
|
|
74
76
|
finishes the default behaviour?
|
|
75
77
|
- [x] Add graceful Ctrl-C interrupt handling to streamed modes
|
|
78
|
+
- [x] Add a `--colour` flag to configure pyallel print colours
|
|
76
79
|
- [ ] Setup build system to convert `pyallel` into a single file executable for ease of
|
|
77
80
|
use and distribution
|
|
78
81
|
- [ ] Add custom parsing of command output to support filtering for errors (like vim's
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, fields
|
|
4
|
+
from typing import Literal
|
|
5
|
+
from pyallel import constants
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class Colours:
|
|
10
|
+
white_bold: str = "\033[1m"
|
|
11
|
+
green_bold: str = "\033[1;32m"
|
|
12
|
+
blue_bold: str = "\033[1;34m"
|
|
13
|
+
red_bold: str = "\033[1;31m"
|
|
14
|
+
yellow_bold: str = "\033[1;33m"
|
|
15
|
+
clear_line: str = "\033[2K"
|
|
16
|
+
clear_screen: str = "\033[2J"
|
|
17
|
+
save_cursor: str = "\033[s"
|
|
18
|
+
restore_cursor: str = "\033[u"
|
|
19
|
+
up_line: str = "\033[1F"
|
|
20
|
+
reset_colour: str = "\033[0m"
|
|
21
|
+
dim_on: str = "\033[2m"
|
|
22
|
+
dim_off: str = "\033[22m"
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def from_colour(cls, colour: Literal["yes", "no", "auto"]) -> Colours:
|
|
26
|
+
colours = cls()
|
|
27
|
+
|
|
28
|
+
if colour == "no" or colour == "auto" and not constants.IN_TTY:
|
|
29
|
+
for field in fields(colours):
|
|
30
|
+
setattr(colours, field.name, "")
|
|
31
|
+
|
|
32
|
+
return colours
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
IN_TTY = sys.stdout.isatty()
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
if IN_TTY:
|
|
8
|
+
|
|
9
|
+
def LINES() -> int:
|
|
10
|
+
return os.get_terminal_size().lines
|
|
11
|
+
|
|
12
|
+
else:
|
|
13
|
+
|
|
14
|
+
def LINES() -> int:
|
|
15
|
+
return sys.maxsize
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
ICONS = ("/", "-", "\\", "|")
|
|
19
|
+
# Unicode character bytes to render different symbols in the terminal
|
|
20
|
+
TICK = "\u2713"
|
|
21
|
+
X = "\u2717"
|
|
@@ -3,21 +3,26 @@ from __future__ import annotations
|
|
|
3
3
|
import sys
|
|
4
4
|
import traceback
|
|
5
5
|
import importlib.metadata
|
|
6
|
+
from pyallel.colours import Colours
|
|
6
7
|
from pyallel.errors import InvalidExecutableErrors
|
|
7
8
|
|
|
8
9
|
from pyallel.parser import Arguments, create_parser
|
|
9
10
|
from pyallel.process import ProcessGroup
|
|
10
|
-
from pyallel import constants
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def main_loop(
|
|
14
14
|
*commands: str,
|
|
15
|
+
colours: Colours,
|
|
15
16
|
interactive: bool = False,
|
|
16
17
|
timer: bool = False,
|
|
17
18
|
verbose: bool = False,
|
|
18
19
|
) -> int:
|
|
19
20
|
process_group = ProcessGroup.from_commands(
|
|
20
|
-
*commands,
|
|
21
|
+
*commands,
|
|
22
|
+
colours=colours,
|
|
23
|
+
interactive=interactive,
|
|
24
|
+
timer=timer,
|
|
25
|
+
verbose=verbose,
|
|
21
26
|
)
|
|
22
27
|
|
|
23
28
|
return process_group.stream()
|
|
@@ -36,10 +41,13 @@ def run(*args: str) -> int:
|
|
|
36
41
|
parser.print_help()
|
|
37
42
|
return 2
|
|
38
43
|
|
|
44
|
+
colours = Colours.from_colour(parsed_args.colour)
|
|
45
|
+
|
|
39
46
|
message = None
|
|
40
47
|
try:
|
|
41
48
|
exit_code = main_loop(
|
|
42
49
|
*parsed_args.commands,
|
|
50
|
+
colours=colours,
|
|
43
51
|
interactive=parsed_args.interactive,
|
|
44
52
|
timer=parsed_args.timer,
|
|
45
53
|
verbose=parsed_args.verbose,
|
|
@@ -53,11 +61,11 @@ def run(*args: str) -> int:
|
|
|
53
61
|
|
|
54
62
|
if exit_code == 1:
|
|
55
63
|
if not message:
|
|
56
|
-
print(f"{
|
|
64
|
+
print(f"{colours.red_bold}A command failed!{colours.reset_colour}")
|
|
57
65
|
else:
|
|
58
|
-
print(f"{
|
|
66
|
+
print(f"{colours.red_bold}Error: {message}{colours.reset_colour}")
|
|
59
67
|
elif exit_code == 0:
|
|
60
|
-
print(f"{
|
|
68
|
+
print(f"{colours.green_bold}Success!{colours.reset_colour}")
|
|
61
69
|
|
|
62
70
|
return exit_code
|
|
63
71
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from argparse import ArgumentParser, RawTextHelpFormatter
|
|
4
|
+
from typing import Literal
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class Arguments:
|
|
8
|
+
colour: Literal["yes", "no", "auto"]
|
|
7
9
|
commands: list[str]
|
|
8
10
|
interactive: bool
|
|
9
11
|
timer: bool
|
|
@@ -67,5 +69,11 @@ def create_parser() -> ArgumentParser:
|
|
|
67
69
|
action="store_true",
|
|
68
70
|
default=False,
|
|
69
71
|
)
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"--colour",
|
|
74
|
+
help="colour terminal output, defaults to \"%(default)s\"",
|
|
75
|
+
choices=("yes", "no", "auto"),
|
|
76
|
+
default="auto",
|
|
77
|
+
)
|
|
70
78
|
|
|
71
79
|
return parser
|
|
@@ -13,19 +13,10 @@ from typing import Any, BinaryIO
|
|
|
13
13
|
from pyallel import constants
|
|
14
14
|
|
|
15
15
|
from dataclasses import dataclass, field
|
|
16
|
+
from pyallel.colours import Colours
|
|
16
17
|
from pyallel.errors import InvalidExecutableErrors, InvalidExecutableError
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
def prefix(output: str, keepend: bool = True) -> str:
|
|
20
|
-
prefixed_output = "\n".join(
|
|
21
|
-
f"{constants.DIM_ON}=>{constants.DIM_OFF} {line}{constants.RESET_COLOUR}"
|
|
22
|
-
for line in output.splitlines()
|
|
23
|
-
)
|
|
24
|
-
if keepend and output and output[-1] == "\n":
|
|
25
|
-
prefixed_output += "\n"
|
|
26
|
-
return prefixed_output
|
|
27
|
-
|
|
28
|
-
|
|
29
20
|
def format_time_taken(time_taken: float) -> str:
|
|
30
21
|
time_taken = round(time_taken, 1)
|
|
31
22
|
seconds = time_taken % (24 * 3600)
|
|
@@ -33,47 +24,6 @@ def format_time_taken(time_taken: float) -> str:
|
|
|
33
24
|
return f"{seconds}s"
|
|
34
25
|
|
|
35
26
|
|
|
36
|
-
def get_command_status(
|
|
37
|
-
process: Process,
|
|
38
|
-
icon: str | None = None,
|
|
39
|
-
passed: bool | None = None,
|
|
40
|
-
verbose: bool = False,
|
|
41
|
-
timer: bool = False,
|
|
42
|
-
) -> str:
|
|
43
|
-
if passed is True:
|
|
44
|
-
colour = constants.GREEN_BOLD
|
|
45
|
-
msg = "done"
|
|
46
|
-
icon = icon or constants.TICK
|
|
47
|
-
elif passed is False:
|
|
48
|
-
colour = constants.RED_BOLD
|
|
49
|
-
msg = "failed"
|
|
50
|
-
icon = icon or constants.X
|
|
51
|
-
else:
|
|
52
|
-
colour = constants.WHITE_BOLD
|
|
53
|
-
msg = "running"
|
|
54
|
-
icon = icon or ""
|
|
55
|
-
if not icon:
|
|
56
|
-
msg += "..."
|
|
57
|
-
|
|
58
|
-
output = f"[{constants.BLUE_BOLD}{process.name}"
|
|
59
|
-
|
|
60
|
-
if verbose:
|
|
61
|
-
output += f" {' '.join(process.args)}"
|
|
62
|
-
|
|
63
|
-
output += f"{constants.RESET_COLOUR}]{colour} {msg} {icon}{constants.RESET_COLOUR}"
|
|
64
|
-
|
|
65
|
-
if timer:
|
|
66
|
-
end = process.end
|
|
67
|
-
if not process.end:
|
|
68
|
-
end = time.perf_counter()
|
|
69
|
-
elapsed = end - process.start
|
|
70
|
-
output += (
|
|
71
|
-
f" ({constants.DIM_ON}{format_time_taken(elapsed)}{constants.DIM_OFF})"
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
return output
|
|
75
|
-
|
|
76
|
-
|
|
77
27
|
@dataclass
|
|
78
28
|
class ProcessGroup:
|
|
79
29
|
processes: list[Process]
|
|
@@ -87,6 +37,7 @@ class ProcessGroup:
|
|
|
87
37
|
interrupt_count: int = 0
|
|
88
38
|
passed: bool = True
|
|
89
39
|
icon: int = 0
|
|
40
|
+
colours: Colours = field(default_factory=Colours)
|
|
90
41
|
|
|
91
42
|
def stream(self) -> int:
|
|
92
43
|
for process in self.processes:
|
|
@@ -125,7 +76,9 @@ class ProcessGroup:
|
|
|
125
76
|
running_process = None
|
|
126
77
|
interrupted = False
|
|
127
78
|
|
|
128
|
-
print(
|
|
79
|
+
print(
|
|
80
|
+
f"{self.colours.white_bold}Running commands...{self.colours.reset_colour}\n"
|
|
81
|
+
)
|
|
129
82
|
|
|
130
83
|
while True:
|
|
131
84
|
output = ""
|
|
@@ -134,7 +87,7 @@ class ProcessGroup:
|
|
|
134
87
|
running_process is None
|
|
135
88
|
and process.id not in self.completed_processes
|
|
136
89
|
):
|
|
137
|
-
output +=
|
|
90
|
+
output += self._get_command_status(process, verbose=self.verbose)
|
|
138
91
|
output += "\n"
|
|
139
92
|
running_process = process
|
|
140
93
|
elif running_process is not process:
|
|
@@ -146,14 +99,14 @@ class ProcessGroup:
|
|
|
146
99
|
process_output = process.readline().decode()
|
|
147
100
|
|
|
148
101
|
if not self.output[process.id] and process_output:
|
|
149
|
-
process_output =
|
|
102
|
+
process_output = self._prefix(process_output)
|
|
150
103
|
self.output[process.id].append(process_output)
|
|
151
104
|
output += process_output
|
|
152
105
|
elif process_output:
|
|
153
106
|
if self.output[process.id][-1][-1] != "\n":
|
|
154
107
|
self.output[process.id][-1] += process_output
|
|
155
108
|
else:
|
|
156
|
-
process_output =
|
|
109
|
+
process_output = self._prefix(process_output)
|
|
157
110
|
self.output[process.id].append(process_output)
|
|
158
111
|
output += process_output
|
|
159
112
|
|
|
@@ -162,9 +115,9 @@ class ProcessGroup:
|
|
|
162
115
|
self.passed = False
|
|
163
116
|
process_output = process.read().decode()
|
|
164
117
|
if process_output:
|
|
165
|
-
output +=
|
|
118
|
+
output += self._prefix(process_output)
|
|
166
119
|
|
|
167
|
-
output +=
|
|
120
|
+
output += self._get_command_status(
|
|
168
121
|
process,
|
|
169
122
|
passed=process.return_code() == 0,
|
|
170
123
|
verbose=self.verbose,
|
|
@@ -182,7 +135,7 @@ class ProcessGroup:
|
|
|
182
135
|
and self.output[process.id][-1][-1] != "\n"
|
|
183
136
|
):
|
|
184
137
|
output += "\n"
|
|
185
|
-
output += f"\n{
|
|
138
|
+
output += f"\n{self.colours.yellow_bold}Interrupt!{self.colours.reset_colour}\n\n"
|
|
186
139
|
interrupted = True
|
|
187
140
|
|
|
188
141
|
if output:
|
|
@@ -194,13 +147,61 @@ class ProcessGroup:
|
|
|
194
147
|
time.sleep(0.01)
|
|
195
148
|
|
|
196
149
|
if self.interrupt_count == 2:
|
|
197
|
-
print(f"{
|
|
150
|
+
print(f"{self.colours.red_bold}Abort!{self.colours.reset_colour}")
|
|
198
151
|
|
|
199
152
|
if not self.exit_code and not self.passed:
|
|
200
153
|
self.exit_code = 1
|
|
201
154
|
|
|
202
155
|
return self.exit_code
|
|
203
156
|
|
|
157
|
+
def _prefix(self, output: str, keepend: bool = True) -> str:
|
|
158
|
+
prefixed_output = "\n".join(
|
|
159
|
+
f"{self.colours.dim_on}=>{self.colours.dim_off} {line}{self.colours.reset_colour}"
|
|
160
|
+
for line in output.splitlines()
|
|
161
|
+
)
|
|
162
|
+
if keepend and output and output[-1] == "\n":
|
|
163
|
+
prefixed_output += "\n"
|
|
164
|
+
return prefixed_output
|
|
165
|
+
|
|
166
|
+
def _get_command_status(
|
|
167
|
+
self,
|
|
168
|
+
process: Process,
|
|
169
|
+
icon: str | None = None,
|
|
170
|
+
passed: bool | None = None,
|
|
171
|
+
verbose: bool = False,
|
|
172
|
+
timer: bool = False,
|
|
173
|
+
) -> str:
|
|
174
|
+
if passed is True:
|
|
175
|
+
colour = self.colours.green_bold
|
|
176
|
+
msg = "done"
|
|
177
|
+
icon = icon or constants.TICK
|
|
178
|
+
elif passed is False:
|
|
179
|
+
colour = self.colours.red_bold
|
|
180
|
+
msg = "failed"
|
|
181
|
+
icon = icon or constants.X
|
|
182
|
+
else:
|
|
183
|
+
colour = self.colours.white_bold
|
|
184
|
+
msg = "running"
|
|
185
|
+
icon = icon or ""
|
|
186
|
+
if not icon:
|
|
187
|
+
msg += "..."
|
|
188
|
+
|
|
189
|
+
output = f"[{self.colours.blue_bold}{process.name}"
|
|
190
|
+
|
|
191
|
+
if verbose:
|
|
192
|
+
output += f" {' '.join(process.args)}"
|
|
193
|
+
|
|
194
|
+
output += f"{self.colours.reset_colour}]{colour} {msg} {icon}{self.colours.reset_colour}"
|
|
195
|
+
|
|
196
|
+
if timer:
|
|
197
|
+
end = process.end
|
|
198
|
+
if not process.end:
|
|
199
|
+
end = time.perf_counter()
|
|
200
|
+
elapsed = end - process.start
|
|
201
|
+
output += f" ({self.colours.dim_on}{format_time_taken(elapsed)}{self.colours.dim_off})"
|
|
202
|
+
|
|
203
|
+
return output
|
|
204
|
+
|
|
204
205
|
def _handle_signal(self, signum: int, _frame: Any) -> None:
|
|
205
206
|
for process in self.processes:
|
|
206
207
|
if self.interrupt_count == 0:
|
|
@@ -215,6 +216,7 @@ class ProcessGroup:
|
|
|
215
216
|
def from_commands(
|
|
216
217
|
cls,
|
|
217
218
|
*commands: str,
|
|
219
|
+
colours: Colours,
|
|
218
220
|
interactive: bool = False,
|
|
219
221
|
timer: bool = False,
|
|
220
222
|
verbose: bool = False,
|
|
@@ -236,6 +238,7 @@ class ProcessGroup:
|
|
|
236
238
|
interactive=interactive,
|
|
237
239
|
timer=timer,
|
|
238
240
|
verbose=verbose,
|
|
241
|
+
colours=colours,
|
|
239
242
|
)
|
|
240
243
|
|
|
241
244
|
signal.signal(signal.SIGINT, process_group._handle_signal)
|
|
@@ -266,7 +269,7 @@ class ProcessGroup:
|
|
|
266
269
|
self.completed_processes.add(process.id)
|
|
267
270
|
if process.return_code() != 0:
|
|
268
271
|
self.passed = False
|
|
269
|
-
output +=
|
|
272
|
+
output += self._get_command_status(
|
|
270
273
|
process,
|
|
271
274
|
passed=process.return_code() == 0,
|
|
272
275
|
verbose=self.verbose,
|
|
@@ -274,7 +277,7 @@ class ProcessGroup:
|
|
|
274
277
|
)
|
|
275
278
|
output += "\n"
|
|
276
279
|
else:
|
|
277
|
-
output +=
|
|
280
|
+
output += self._get_command_status(
|
|
278
281
|
process,
|
|
279
282
|
icon=constants.ICONS[self.icon],
|
|
280
283
|
verbose=self.verbose,
|
|
@@ -293,7 +296,7 @@ class ProcessGroup:
|
|
|
293
296
|
process_output.splitlines()[-self.process_lines[i - 1] :]
|
|
294
297
|
)
|
|
295
298
|
process_output += "\n"
|
|
296
|
-
output +=
|
|
299
|
+
output += self._prefix(process_output)
|
|
297
300
|
if output and output[-1] != "\n":
|
|
298
301
|
output += "\n"
|
|
299
302
|
if i != num_processes:
|
|
@@ -303,9 +306,11 @@ class ProcessGroup:
|
|
|
303
306
|
return output
|
|
304
307
|
|
|
305
308
|
if self.interrupt_count == 1:
|
|
306
|
-
output +=
|
|
309
|
+
output += (
|
|
310
|
+
f"\n{self.colours.yellow_bold}Interrupt!{self.colours.reset_colour}"
|
|
311
|
+
)
|
|
307
312
|
elif self.interrupt_count == 2:
|
|
308
|
-
output += f"\n{
|
|
313
|
+
output += f"\n{self.colours.red_bold}Abort!{self.colours.reset_colour}"
|
|
309
314
|
|
|
310
315
|
return output
|
|
311
316
|
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import sys
|
|
3
|
-
|
|
4
|
-
IN_TTY = sys.stdout.isatty()
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if IN_TTY:
|
|
8
|
-
WHITE_BOLD = "\033[1m"
|
|
9
|
-
GREEN_BOLD = "\033[1;32m"
|
|
10
|
-
BLUE_BOLD = "\033[1;34m"
|
|
11
|
-
RED_BOLD = "\033[1;31m"
|
|
12
|
-
YELLOW_BOLD = "\033[1;33m"
|
|
13
|
-
CLEAR_LINE = "\033[2K"
|
|
14
|
-
CLEAR_SCREEN = "\033[2J"
|
|
15
|
-
SAVE_CURSOR = "\033[s"
|
|
16
|
-
RESTORE_CURSOR = "\033[u"
|
|
17
|
-
UP_LINE = "\033[1F"
|
|
18
|
-
RESET_COLOUR = "\033[0m"
|
|
19
|
-
CARRIAGE_RETURN = "\r"
|
|
20
|
-
DIM_ON = "\033[2m"
|
|
21
|
-
DIM_OFF = "\033[22m"
|
|
22
|
-
|
|
23
|
-
def COLUMNS() -> int:
|
|
24
|
-
return os.get_terminal_size().columns
|
|
25
|
-
|
|
26
|
-
def LINES() -> int:
|
|
27
|
-
return os.get_terminal_size().lines
|
|
28
|
-
|
|
29
|
-
else:
|
|
30
|
-
WHITE_BOLD = ""
|
|
31
|
-
GREEN_BOLD = ""
|
|
32
|
-
BLUE_BOLD = ""
|
|
33
|
-
RED_BOLD = ""
|
|
34
|
-
YELLOW_BOLD = ""
|
|
35
|
-
CLEAR_LINE = ""
|
|
36
|
-
CLEAR_SCREEN = ""
|
|
37
|
-
SAVE_CURSOR = ""
|
|
38
|
-
RESTORE_CURSOR = ""
|
|
39
|
-
UP_LINE = ""
|
|
40
|
-
RESET_COLOUR = ""
|
|
41
|
-
CARRIAGE_RETURN = ""
|
|
42
|
-
DIM_ON = ""
|
|
43
|
-
DIM_OFF = ""
|
|
44
|
-
|
|
45
|
-
def COLUMNS() -> int:
|
|
46
|
-
return sys.maxsize
|
|
47
|
-
|
|
48
|
-
def LINES() -> int:
|
|
49
|
-
return sys.maxsize
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
ICONS = ("/", "-", "\\", "|")
|
|
53
|
-
# Unicode character bytes to render different symbols in the terminal
|
|
54
|
-
TICK = "\u2713"
|
|
55
|
-
X = "\u2717"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|