-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrand.py
More file actions
executable file
·145 lines (122 loc) · 6.05 KB
/
Copy pathrand.py
File metadata and controls
executable file
·145 lines (122 loc) · 6.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python3
#[x-cmds]: UPDATE
"""Generate a truly random number with a specific number of digits or within a range.
Provide either the number of digits or a min and max range."""
from typing import Optional
from xulbux.console import ProgressBar
from xulbux import FormatCodes, Console
import secrets
import sys
sys.set_int_max_str_digits(0) # 0 = NO LIMIT
ARGS = Console.get_args({
"digits_or_min_max": "before",
"batch_gen": {"-b", "--batch", "--batch-gen"},
"format": {"-f", "--format"},
"help": {"-h", "--help"},
})
def print_help():
help_text = """
[b|in|bg:black]( Random — Generate truly random numbers )
[b](Usage:) [br:green](rand) [br:cyan](<num> <num_2>) [br:blue]([options])
[b](Arguments:)
[br:cyan](num) Number of digits or start of range
[br:cyan](num_2) End of range [dim]((optional))
[b](Options:)
[br:blue](-b), [br:blue](--batch-gen[dim](=)N) Generate multiple random numbers
[br:blue](-f), [br:blue](--format) Format numbers with commas as thousand separators
[b](Examples:)
[br:green](rand) [br:cyan](10) [dim](# [i](Generate a random number with 10 digits))
[br:green](rand) [br:cyan](-100 100) [dim](# [i](Generate a random number between -100 and 100))
[br:green](rand) [br:cyan](5) [br:blue](--batch-gen[dim](=)3) [dim](# [i](Generate 3 random numbers with 5 digits))
[br:green](rand) [br:cyan](10) [br:blue](--format) [dim](# [i](Generate a comma-formatted random number with 10 digits))
"""
FormatCodes.print(help_text)
def gen_random_int(digits: Optional[int] = None, min_val: Optional[int] = None, max_val: Optional[int] = None) -> int:
# RANDOM NUMBER WITH SPECIFIC AMOUNT OF DIGITS
if digits is not None:
if digits <= 0:
raise ValueError("The number of decimal places must be a positive integer.")
random_int = secrets.randbelow((10**digits - 1) - (min_value := 10**(digits - 1)) + 1) + min_value
# RANDOM NUMBER WITHIN A SPECIFIED RANGE
elif min_val is not None and max_val is not None:
if min_val >= max_val:
raise ValueError("The minimum value must be less than the maximum value.")
random_int = secrets.randbelow(max_val - min_val + 1) + min_val
# INVALID USAGE
else:
raise ValueError("Either 'digits' or both 'min_val' and 'max_val' must be provided.")
return random_int
def main():
if ARGS.help.exists or len(ARGS.digits_or_min_max.values) == 0:
print_help()
return
print()
batch = (
int(v) \
if (v := ARGS.batch_gen.get(0)) and v.replace("_", "").isdigit()
else 1
)
match len(ARGS.digits_or_min_max.values):
case 1:
digits = int(ARGS.digits_or_min_max.values[0])
FormatCodes.print("[dim](generating...)", end="")
if batch > 1:
random_ints: list[str] = []
with ProgressBar().progress_context(batch, "generating...") as update_progress:
update_progress(0)
for i in range(batch):
random_int = gen_random_int(digits=digits)
random_ints.append(f"{random_int:{',' if ARGS.format.exists else ''}}\n")
update_progress(i + 1)
FormatCodes.print("\x1b[2K\r[dim](formatting...)", end="")
FormatCodes.print(f"\x1b[2K\r[br:blue]{'\n'.join(random_ints)}[_]")
else:
random_int = gen_random_int(digits=digits)
FormatCodes.print(f"\x1b[2K\r[br:blue]({random_int:{',' if ARGS.format.exists else ''}})\n")
case 2:
min_val = int(ARGS.digits_or_min_max.values[0])
max_val = int(ARGS.digits_or_min_max.values[1])
if min_val >= max_val:
Console.exit(
"[b](Invalid range:) The minimum value must be less than the maximum value",
start="\n",
end="\n\n",
exit_code=1,
)
FormatCodes.print("[dim](generating...)", end="")
if batch > 1:
random_ints, lowest_int, highest_int = [], max_val + 1, min_val - 1
with ProgressBar().progress_context(batch, "generating...") as update_progress:
for i in range(batch):
random_int = gen_random_int(min_val=min_val, max_val=max_val)
random_ints.append(f"{random_int:{',' if ARGS.format.exists else ''}}\n")
if random_int < lowest_int: lowest_int = random_int
if random_int > highest_int: highest_int = random_int
update_progress(i + 1)
FormatCodes.print("\x1b[2K\r[dim](formatting...)", end="")
FormatCodes.print(f"\x1b[2K\r[br:blue]{'\n'.join(random_ints)}")
FormatCodes.print(
f"[b|dim](lowest:) {'' if lowest_int < 0 else ' '}[dim]({lowest_int:{',' if ARGS.format.exists else ''}})\n"
f"[b|dim](highest:) {'' if highest_int < 0 else ' '}[dim]{highest_int:{',' if ARGS.format.exists else ''}}[_]\n"
)
else:
random_int = gen_random_int(min_val=min_val, max_val=max_val)
FormatCodes.print(f"\x1b[2K\r[br:blue]({random_int:{',' if ARGS.format.exists else ''}})\n")
case _:
Console.exit(
"[b](Too many arguments:) Provide either the number of digits or a min and max range",
start="\n",
end="\n\n",
exit_code=1,
)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
FormatCodes.print("\x1b[2K\r[b|br:red](✗)\n")
except MemoryError:
Console.fail("[b](MemoryError:) The operation ran out of memory", start="\x1b[2K\r", end="\n\n")
except OverflowError as exc:
Console.fail(f"[b](OverflowError:) {exc}", start="\x1b[2K\r", end="\n\n")
except Exception as exc:
Console.fail(exc, start="\x1b[2K\r", end="\n\n")