ConsoleFramework 0.9.2__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.
@@ -0,0 +1,771 @@
1
+ """
2
+ ConsoleFramework - The best Console Library of the Python.
3
+ By: Suleiman
4
+ Copyright © Suleiman 2026
5
+ All rights are reserved.
6
+ """
7
+ import os
8
+ import sys
9
+ import time
10
+ import math
11
+ import random
12
+ import socket
13
+ import subprocess as CMD
14
+ import threading
15
+ from http.server import HTTPServer, BaseHTTPRequestHandler
16
+ import urllib.request
17
+ import urllib.parse
18
+ class Colors:
19
+ RESET = "\033[0m"
20
+ RED = "\033[31m"
21
+ GREEN = "\033[32m"
22
+ BLUE = "\033[34m"
23
+ CYAN = "\033[36m"
24
+ MAGENTA = "\033[35m"
25
+ YELLOW = "\033[33m"
26
+ WHITE = "\033[37m"
27
+ BLACK = "\033[30m"
28
+ BG_RED = "\033[41m"
29
+ BG_GREEN = "\033[42m"
30
+ BG_BLUE = "\033[44m"
31
+ BG_CYAN = "\033[46m"
32
+ BG_MAGENTA = "\033[45m"
33
+ BG_YELLOW = "\033[43m"
34
+ BG_WHITE = "\033[47m"
35
+ BG_BLACK = "\033[40m"
36
+ BOLD = "\033[1m"
37
+ DIM = "\033[2m"
38
+ ITALIC = "\033[3m"
39
+ UNDERLINE = "\033[4m"
40
+ BLINK = "\033[5m"
41
+ REVERSE = "\033[7m"
42
+ HIDDEN = "\033[8m"
43
+ STRIKE = "\033[9m"
44
+
45
+ @staticmethod
46
+ def rgb(r, g, b):
47
+ return f"\033[38;2;{r};{g};{b}m"
48
+
49
+ @staticmethod
50
+ def bg_rgb(r, g, b):
51
+ return f"\033[48;2;{r};{g};{b}m"
52
+
53
+ @staticmethod
54
+ def colorize(text, color, reset=True):
55
+ reset_code = Colors.RESET if reset else ""
56
+ return f"{color}{text}{reset_code}"
57
+
58
+ class Render:
59
+ @staticmethod
60
+ def DrawPic(points=None, width=80, height=25, clear_before_draw=False, default_char=' '):
61
+ if clear_before_draw:
62
+ os.system("cls" if os.name == "nt" else "clear")
63
+ field = [[default_char for _ in range(width)] for _ in range(height)]
64
+ if points:
65
+ for item in points:
66
+ if len(item) >= 3:
67
+ x, y, char = item[0], item[1], item[2]
68
+ if 0 <= x < width and 0 <= y < height:
69
+ if len(item) == 4:
70
+ color = item[3]
71
+ field[y][x] = f"{color}{char}{Colors.RESET}"
72
+ elif len(item) == 5:
73
+ color, bg = item[3], item[4]
74
+ field[y][x] = f"{color}{bg}{char}{Colors.RESET}"
75
+ else:
76
+ field[y][x] = char
77
+ for row in field:
78
+ print(''.join(row))
79
+ @staticmethod
80
+ def _apply_color(points, color=None, bg=None):
81
+ if color is None and bg is None:
82
+ return points
83
+ result = []
84
+ for p in points:
85
+ if len(p) == 3:
86
+ x, y, char = p
87
+ if color and bg:
88
+ result.append((x, y, char, color, bg))
89
+ elif color:
90
+ result.append((x, y, char, color))
91
+ else:
92
+ result.append((x, y, char, Colors.BG_BLACK + bg))
93
+ else:
94
+ result.append(p)
95
+ return result
96
+
97
+ @staticmethod
98
+ def get_line_points(x1, y1, x2, y2, char='#', color=None, bg=None):
99
+ points = []
100
+ dx = abs(x2 - x1)
101
+ dy = abs(y2 - y1)
102
+ sx = 1 if x1 < x2 else -1
103
+ sy = 1 if y1 < y2 else -1
104
+ err = dx - dy
105
+ while True:
106
+ points.append((x1, y1, char))
107
+ if x1 == x2 and y1 == y2:
108
+ break
109
+ e2 = err * 2
110
+ if e2 > -dy:
111
+ err -= dy
112
+ x1 += sx
113
+ if e2 < dx:
114
+ err += dx
115
+ y1 += sy
116
+ return Render._apply_color(points, color, bg)
117
+
118
+ @staticmethod
119
+ def get_circle_points(cx, cy, r, char='#', color=None, bg=None):
120
+ points = []
121
+ for angle in range(0, 360, 5):
122
+ rad = angle * math.pi / 180
123
+ x = int(cx + r * math.cos(rad))
124
+ y = int(cy + r * math.sin(rad))
125
+ points.append((x, y, char))
126
+ return Render._apply_color(points, color, bg)
127
+
128
+ @staticmethod
129
+ def get_filled_circle_points(cx, cy, r, char='#', color=None, bg=None):
130
+ points = []
131
+ for y in range(cy - r, cy + r + 1):
132
+ for x in range(cx - r, cx + r + 1):
133
+ if (x - cx) ** 2 + (y - cy) ** 2 <= r ** 2:
134
+ points.append((x, y, char))
135
+ return Render._apply_color(points, color, bg)
136
+
137
+ @staticmethod
138
+ def get_rect_points(x1, y1, x2, y2, char='#', color=None, bg=None):
139
+ points = []
140
+ for x in range(x1, x2 + 1):
141
+ points.append((x, y1, char))
142
+ points.append((x, y2, char))
143
+ for y in range(y1, y2 + 1):
144
+ points.append((x1, y, char))
145
+ points.append((x2, y, char))
146
+ return Render._apply_color(points, color, bg)
147
+
148
+ @staticmethod
149
+ def get_fill_rect_points(x1, y1, x2, y2, char='#', color=None, bg=None):
150
+ points = []
151
+ for y in range(y1, y2 + 1):
152
+ for x in range(x1, x2 + 1):
153
+ points.append((x, y, char))
154
+ return Render._apply_color(points, color, bg)
155
+
156
+ @staticmethod
157
+ def get_text_points(x, y, text, char=None, color=None, bg=None):
158
+ points = []
159
+ if char is None:
160
+ for i, ch in enumerate(text):
161
+ points.append((x + i, y, ch))
162
+ else:
163
+ for i in range(len(text)):
164
+ points.append((x + i, y, char))
165
+ return Render._apply_color(points, color, bg)
166
+
167
+ @staticmethod
168
+ def get_triangle_points(x1, y1, x2, y2, x3, y3, char='#', color=None, bg=None):
169
+ points = []
170
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
171
+ points.extend(Render.get_line_points(x2, y2, x3, y3, char))
172
+ points.extend(Render.get_line_points(x3, y3, x1, y1, char))
173
+ return Render._apply_color(points, color, bg)
174
+
175
+ @staticmethod
176
+ def get_filled_triangle_points(x1, y1, x2, y2, x3, y3, char='#', color=None, bg=None):
177
+ points = []
178
+ min_x = min(x1, x2, x3)
179
+ max_x = max(x1, x2, x3)
180
+ min_y = min(y1, y2, y3)
181
+ max_y = max(y1, y2, y3)
182
+ for y in range(min_y, max_y + 1):
183
+ for x in range(min_x, max_x + 1):
184
+ if Render._point_in_triangle(x, y, x1, y1, x2, y2, x3, y3):
185
+ points.append((x, y, char))
186
+ return Render._apply_color(points, color, bg)
187
+
188
+ @staticmethod
189
+ def get_heart_points(cx, cy, size=5, char='#', color=None, bg=None):
190
+ points = []
191
+ for y in range(-size, size + 1):
192
+ for x in range(-size, size + 1):
193
+ if ((x * x + y * y - size * size) ** 3 <= size * size * x * x * y * y * 0.5):
194
+ points.append((cx + x, cy - y, char))
195
+ return Render._apply_color(points, color, bg)
196
+
197
+ @staticmethod
198
+ def get_star_points(cx, cy, radius=5, points_count=5, char='*', color=None, bg=None):
199
+ points = []
200
+ angle = -math.pi / 2
201
+ step = math.pi / points_count
202
+ outer_points = []
203
+ inner_points = []
204
+ for i in range(points_count * 2):
205
+ r = radius if i % 2 == 0 else radius * 0.4
206
+ x = cx + r * math.cos(angle + i * step)
207
+ y = cy + r * math.sin(angle + i * step)
208
+ if i % 2 == 0:
209
+ outer_points.append((x, y))
210
+ else:
211
+ inner_points.append((x, y))
212
+ for i in range(points_count):
213
+ p1 = outer_points[i]
214
+ p2 = inner_points[i]
215
+ p3 = outer_points[(i + 1) % points_count]
216
+ points.extend(Render.get_line_points(int(p1[0]), int(p1[1]), int(p2[0]), int(p2[1]), char))
217
+ points.extend(Render.get_line_points(int(p2[0]), int(p2[1]), int(p3[0]), int(p3[1]), char))
218
+ return Render._apply_color(points, color, bg)
219
+
220
+ @staticmethod
221
+ def get_bezier_points(x1, y1, x2, y2, x3, y3, steps=20, char='#', color=None, bg=None):
222
+ points = []
223
+ for t in range(steps + 1):
224
+ t = t / steps
225
+ x = (1 - t) ** 2 * x1 + 2 * (1 - t) * t * x2 + t ** 2 * x3
226
+ y = (1 - t) ** 2 * y1 + 2 * (1 - t) * t * y2 + t ** 2 * y3
227
+ points.append((int(x), int(y), char))
228
+ return Render._apply_color(points, color, bg)
229
+
230
+ @staticmethod
231
+ def get_wave_points(cx, cy, amplitude=5, length=20, char='~', color=None, bg=None):
232
+ points = []
233
+ for x in range(length):
234
+ y = cy + int(amplitude * math.sin(x * 0.5))
235
+ points.append((cx + x, y, char))
236
+ return Render._apply_color(points, color, bg)
237
+
238
+ @staticmethod
239
+ def get_spiral_points(cx, cy, turns=3, radius=10, step=0.1, char='*', color=None, bg=None):
240
+ points = []
241
+ angle = 0
242
+ r = 0
243
+ while r < radius:
244
+ x = int(cx + r * math.cos(angle))
245
+ y = int(cy + r * math.sin(angle))
246
+ points.append((x, y, char))
247
+ angle += step
248
+ r += step * 2
249
+ return Render._apply_color(points, color, bg)
250
+
251
+ @staticmethod
252
+ def get_grid_points(x1, y1, x2, y2, step=2, char='+', color=None, bg=None):
253
+ points = []
254
+ for x in range(x1, x2 + 1, step):
255
+ for y in range(y1, y2 + 1, step):
256
+ points.append((x, y, char))
257
+ return Render._apply_color(points, color, bg)
258
+
259
+ @staticmethod
260
+ def get_noise_points(cx, cy, radius, count=50, char='.', color=None, bg=None):
261
+ points = []
262
+ for _ in range(count):
263
+ angle = random.uniform(0, 2 * math.pi)
264
+ r = random.uniform(0, radius)
265
+ x = int(cx + r * math.cos(angle))
266
+ y = int(cy + r * math.sin(angle))
267
+ points.append((x, y, char))
268
+ return Render._apply_color(points, color, bg)
269
+
270
+ # ---- 3D ----
271
+ @staticmethod
272
+ def _point_in_triangle(px, py, x1, y1, x2, y2, x3, y3):
273
+ def sign(a, b, c):
274
+ return (a[0] - c[0]) * (b[1] - c[1]) - (b[0] - c[0]) * (a[1] - c[1])
275
+ p = (px, py)
276
+ d1 = sign(p, (x2, y2), (x1, y1))
277
+ d2 = sign(p, (x3, y3), (x2, y2))
278
+ d3 = sign(p, (x1, y1), (x3, y3))
279
+ has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
280
+ has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)
281
+ return not (has_neg and has_pos)
282
+
283
+ @staticmethod
284
+ def _rotx(x, y, z, angle):
285
+ rad = math.radians(angle)
286
+ cos_a = math.cos(rad)
287
+ sin_a = math.sin(rad)
288
+ y_new = y * cos_a - z * sin_a
289
+ z_new = y * sin_a + z * cos_a
290
+ return x, y_new, z_new
291
+
292
+ @staticmethod
293
+ def _roty(x, y, z, angle):
294
+ rad = math.radians(angle)
295
+ cos_a = math.cos(rad)
296
+ sin_a = math.sin(rad)
297
+ x_new = x * cos_a + z * sin_a
298
+ z_new = -x * sin_a + z * cos_a
299
+ return x_new, y, z_new
300
+
301
+ @staticmethod
302
+ def _rotz(x, y, z, angle):
303
+ rad = math.radians(angle)
304
+ cos_a = math.cos(rad)
305
+ sin_a = math.sin(rad)
306
+ x_new = x * cos_a - y * sin_a
307
+ y_new = x * sin_a + y * cos_a
308
+ return x_new, y_new, z
309
+
310
+ @staticmethod
311
+ def _project_3d(x, y, z, rotx, roty, rotz, scale, cx, cy):
312
+ x, y, z = Render._rotx(x, y, z, rotx)
313
+ x, y, z = Render._roty(x, y, z, roty)
314
+ x, y, z = Render._rotz(x, y, z, rotz)
315
+ x2d = int(x * scale + cx)
316
+ y2d = int(-y * scale + cy)
317
+ return x2d, y2d
318
+
319
+ @staticmethod
320
+ def get_cube_3d_points(size=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', color=None, bg=None):
321
+ s = size / 2
322
+ vertices = [
323
+ (-s, -s, -s), (s, -s, -s), (s, s, -s), (-s, s, -s),
324
+ (-s, -s, s), (s, -s, s), (s, s, s), (-s, s, s)
325
+ ]
326
+ edges = [
327
+ (0,1), (1,2), (2,3), (3,0),
328
+ (4,5), (5,6), (6,7), (7,4),
329
+ (0,4), (1,5), (2,6), (3,7)
330
+ ]
331
+ points = []
332
+ projected = []
333
+ for v in vertices:
334
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
335
+ projected.append((x2d, y2d))
336
+ for edge in edges:
337
+ x1, y1 = projected[edge[0]]
338
+ x2, y2 = projected[edge[1]]
339
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
340
+ return Render._apply_color(points, color, bg)
341
+
342
+ @staticmethod
343
+ def get_pyramid_3d_points(size=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', color=None, bg=None):
344
+ s = size / 2
345
+ vertices = [
346
+ (-s, -s, -s), (s, -s, -s), (s, -s, s), (-s, -s, s),
347
+ (0, s, 0)
348
+ ]
349
+ edges = [
350
+ (0,1), (1,2), (2,3), (3,0),
351
+ (0,4), (1,4), (2,4), (3,4)
352
+ ]
353
+ points = []
354
+ projected = []
355
+ for v in vertices:
356
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
357
+ projected.append((x2d, y2d))
358
+ for edge in edges:
359
+ x1, y1 = projected[edge[0]]
360
+ x2, y2 = projected[edge[1]]
361
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
362
+ return Render._apply_color(points, color, bg)
363
+
364
+ @staticmethod
365
+ def get_cylinder_3d_points(radius=5, height=10, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', color=None, bg=None):
366
+ points = []
367
+ top_points = []
368
+ bottom_points = []
369
+ for i in range(segments):
370
+ rad = i / segments * 2 * math.pi
371
+ x = radius * math.cos(rad)
372
+ z = radius * math.sin(rad)
373
+ top_points.append((x, height/2, z))
374
+ bottom_points.append((x, -height/2, z))
375
+ all_vertices = top_points + bottom_points
376
+ projected = []
377
+ for v in all_vertices:
378
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
379
+ projected.append((x2d, y2d))
380
+ for i in range(segments):
381
+ j = (i + 1) % segments
382
+ x1, y1 = projected[i]
383
+ x2, y2 = projected[j]
384
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
385
+ x1, y1 = projected[i + segments]
386
+ x2, y2 = projected[j + segments]
387
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
388
+ x1, y1 = projected[i]
389
+ x2, y2 = projected[i + segments]
390
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
391
+ return Render._apply_color(points, color, bg)
392
+
393
+ @staticmethod
394
+ def get_sphere_3d_points(radius=5, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', color=None, bg=None):
395
+ points = []
396
+ for i in range(segments):
397
+ theta = i / segments * math.pi
398
+ for j in range(segments):
399
+ phi = j / segments * 2 * math.pi
400
+ x = radius * math.sin(theta) * math.cos(phi)
401
+ y = radius * math.cos(theta)
402
+ z = radius * math.sin(theta) * math.sin(phi)
403
+ x2d, y2d = Render._project_3d(x, y, z, rotx, roty, rotz, scale, cx, cy)
404
+ points.append((x2d, y2d, char))
405
+ return Render._apply_color(points, color, bg)
406
+
407
+ @staticmethod
408
+ def get_cone_3d_points(radius=5, height=10, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', color=None, bg=None):
409
+ points = []
410
+ base_points = []
411
+ for i in range(segments):
412
+ rad = i / segments * 2 * math.pi
413
+ x = radius * math.cos(rad)
414
+ z = radius * math.sin(rad)
415
+ base_points.append((x, -height/2, z))
416
+ apex = (0, height/2, 0)
417
+ all_vertices = base_points + [apex]
418
+ projected = []
419
+ for v in all_vertices:
420
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
421
+ projected.append((x2d, y2d))
422
+ for i in range(segments):
423
+ j = (i + 1) % segments
424
+ x1, y1 = projected[i]
425
+ x2, y2 = projected[j]
426
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
427
+ x1, y1 = projected[i]
428
+ x2, y2 = projected[-1]
429
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
430
+ return Render._apply_color(points, color, bg)
431
+
432
+ @staticmethod
433
+ def get_torus_3d_points(radius=8, tube=3, segments=16, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', color=None, bg=None):
434
+ points = []
435
+ for i in range(segments):
436
+ theta = i / segments * 2 * math.pi
437
+ for j in range(segments):
438
+ phi = j / segments * 2 * math.pi
439
+ x = (radius + tube * math.cos(phi)) * math.cos(theta)
440
+ y = tube * math.sin(phi)
441
+ z = (radius + tube * math.cos(phi)) * math.sin(theta)
442
+ x2d, y2d = Render._project_3d(x, y, z, rotx, roty, rotz, scale, cx, cy)
443
+ points.append((x2d, y2d, char))
444
+ return Render._apply_color(points, color, bg)
445
+
446
+ @staticmethod
447
+ def get_ico_sphere_3d_points(radius=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', color=None, bg=None):
448
+ points = []
449
+ phi = (1 + math.sqrt(5)) / 2
450
+ vertices = [
451
+ (-1, phi, 0), ( 1, phi, 0), (-1, -phi, 0), ( 1, -phi, 0),
452
+ ( 0, -1, phi), ( 0, 1, phi), ( 0, -1, -phi), ( 0, 1, -phi),
453
+ ( phi, 0, -1), ( phi, 0, 1), (-phi, 0, -1), (-phi, 0, 1)
454
+ ]
455
+ vertices = [(x * radius / 1.618, y * radius / 1.618, z * radius / 1.618) for x, y, z in vertices]
456
+ edges = [
457
+ (0,1), (0,4), (0,5), (0,10), (0,11),
458
+ (1,2), (1,5), (1,7), (1,8), (1,9),
459
+ (2,3), (2,6), (2,7), (2,10), (2,11),
460
+ (3,4), (3,6), (3,8), (3,9), (3,11),
461
+ (4,5), (4,9), (4,11),
462
+ (5,7), (5,9),
463
+ (6,7), (6,10),
464
+ (7,8),
465
+ (8,9), (8,10),
466
+ (10,11)
467
+ ]
468
+ projected = []
469
+ for v in vertices:
470
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
471
+ projected.append((x2d, y2d))
472
+ for edge in edges:
473
+ x1, y1 = projected[edge[0]]
474
+ x2, y2 = projected[edge[1]]
475
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
476
+ return Render._apply_color(points, color, bg)
477
+
478
+ class Animate:
479
+ @staticmethod
480
+ def clear_screen():
481
+ os.system("cls" if os.name == "nt" else "clear")
482
+
483
+ @staticmethod
484
+ def animate_print(text, delay=0.05, end="\n", flush=True, backspace_effect=False):
485
+ if backspace_effect:
486
+ for ch in text:
487
+ sys.stdout.write(ch)
488
+ sys.stdout.flush()
489
+ time.sleep(delay)
490
+ time.sleep(0.2)
491
+ for _ in text:
492
+ sys.stdout.write("\b \b")
493
+ sys.stdout.flush()
494
+ time.sleep(delay / 2)
495
+ for ch in text:
496
+ sys.stdout.write(ch)
497
+ sys.stdout.flush()
498
+ time.sleep(delay)
499
+ else:
500
+ for ch in text:
501
+ sys.stdout.write(ch)
502
+ if flush:
503
+ sys.stdout.flush()
504
+ time.sleep(delay)
505
+ sys.stdout.write(end)
506
+ if flush:
507
+ sys.stdout.flush()
508
+
509
+ @staticmethod
510
+ def spinning_cursor(message="Loading", duration=3.0, delay=0.1, frames=None, clear_before=False):
511
+ if clear_before:
512
+ Animate.clear_screen()
513
+ if frames is None:
514
+ frames = ["|", "/", "-", "\\"]
515
+ end_time = time.time() + duration
516
+ idx = 0
517
+ while time.time() < end_time:
518
+ frame = frames[idx % len(frames)]
519
+ sys.stdout.write(f"\r{message} {frame} ")
520
+ sys.stdout.flush()
521
+ time.sleep(delay)
522
+ idx += 1
523
+ sys.stdout.write("\r" + " " * (len(message) + 3) + "\r")
524
+ sys.stdout.flush()
525
+
526
+ @staticmethod
527
+ def countdown(seconds, message="Countdown", clear_before=False):
528
+ if clear_before:
529
+ Animate.clear_screen()
530
+ for remaining in range(seconds, 0, -1):
531
+ sys.stdout.write(f"\r{message}: {remaining:2d} seconds remaining ")
532
+ sys.stdout.flush()
533
+ time.sleep(1)
534
+ sys.stdout.write(f"\r{message}: 0 seconds remaining! Done!\n")
535
+ sys.stdout.flush()
536
+
537
+ class Keyboard:
538
+ @staticmethod
539
+ def GetKey():
540
+ try:
541
+ import termios
542
+ import tty
543
+ fd = sys.stdin.fileno()
544
+ old = termios.tcgetattr(fd)
545
+ try:
546
+ tty.setraw(fd)
547
+ return sys.stdin.read(1)
548
+ finally:
549
+ termios.tcsetattr(fd, termios.TCSADRAIN, old)
550
+ except:
551
+ import msvcrt
552
+ return msvcrt.getch().decode()
553
+
554
+ class ConsoleInfo:
555
+ @staticmethod
556
+ def GetConsole():
557
+ return sys.stdout
558
+
559
+ @staticmethod
560
+ def GetPipVer():
561
+ try:
562
+ result = CMD.run(['python', '-m', 'pip', '--version'], capture_output=True, text=True, check=True)
563
+ return result.stdout.strip()
564
+ except:
565
+ return "Error: pip not found"
566
+
567
+ class Process:
568
+ @staticmethod
569
+ def StartPyCode(code, wait=False, args=None, python="python"):
570
+ try:
571
+ cmd = [python, "-c", code]
572
+ if args:
573
+ cmd.extend(args)
574
+ if wait:
575
+ proc = CMD.run(cmd, capture_output=True, text=True)
576
+ return proc
577
+ else:
578
+ proc = CMD.Popen(cmd)
579
+ return proc
580
+ except Exception as e:
581
+ print(f"Error executing code: {e}")
582
+ return None
583
+
584
+ @staticmethod
585
+ def KillPyScript(pid):
586
+ try:
587
+ os.kill(pid, 15)
588
+ time.sleep(0.2)
589
+ return True
590
+ except ProcessLookupError:
591
+ print(f"Process {pid} not found")
592
+ return False
593
+ except PermissionError:
594
+ print(f"Permission denied to kill process {pid}")
595
+ return False
596
+ except Exception as e:
597
+ print(f"Error killing process: {e}")
598
+ return False
599
+
600
+ @staticmethod
601
+ def KillPyScriptForce(pid):
602
+ try:
603
+ os.kill(pid, 9)
604
+ return True
605
+ except ProcessLookupError:
606
+ print(f"Process {pid} not found")
607
+ return False
608
+ except PermissionError:
609
+ print(f"Permission denied to kill process {pid}")
610
+ return False
611
+ except Exception as e:
612
+ print(f"Error killing process: {e}")
613
+ return False
614
+
615
+ @staticmethod
616
+ def IsRunning(pid):
617
+ try:
618
+ os.kill(pid, 0)
619
+ return True
620
+ except ProcessLookupError:
621
+ return False
622
+ except PermissionError:
623
+ return True
624
+
625
+ @staticmethod
626
+ def GetProcessList():
627
+ try:
628
+ result = CMD.run(['ps', '-e', '-o', 'pid,comm'], capture_output=True, text=True)
629
+ lines = result.stdout.strip().split('\n')[1:]
630
+ processes = []
631
+ for line in lines:
632
+ parts = line.strip().split(' ', 1)
633
+ if len(parts) == 2:
634
+ pid = int(parts[0])
635
+ name = parts[1]
636
+ processes.append({'pid': pid, 'name': name})
637
+ return processes
638
+ except Exception:
639
+ return []
640
+
641
+ @staticmethod
642
+ def GetProcessInfo(pid):
643
+ try:
644
+ result = CMD.run(['ps', '-p', str(pid), '-o', 'pid,comm,%cpu,%mem,etime'], capture_output=True, text=True)
645
+ lines = result.stdout.strip().split('\n')
646
+ if len(lines) < 2:
647
+ return None
648
+ parts = lines[1].strip().split()
649
+ if len(parts) >= 5:
650
+ return {
651
+ 'pid': int(parts[0]),
652
+ 'name': parts[1],
653
+ 'cpu': parts[2],
654
+ 'memory': parts[3],
655
+ 'time': parts[4]
656
+ }
657
+ return None
658
+ except Exception:
659
+ return None
660
+
661
+ @staticmethod
662
+ def WaitForProcess(pid, timeout=None):
663
+ start_time = time.time()
664
+ while Process.IsRunning(pid):
665
+ if timeout and (time.time() - start_time) > timeout:
666
+ return False
667
+ time.sleep(0.5)
668
+ return True
669
+
670
+ @staticmethod
671
+ def GetCurrentPID():
672
+ return os.getpid()
673
+
674
+ class Channel:
675
+ def __init__(self):
676
+ self.connection = None
677
+ self.host = None
678
+ self.port = None
679
+ self.is_server = False
680
+
681
+ @staticmethod
682
+ def _get(url, timeout=5):
683
+ try:
684
+ import urllib.request
685
+ with urllib.request.urlopen(url, timeout=timeout) as response:
686
+ return response.read().decode()
687
+ except Exception:
688
+ return None
689
+
690
+ @staticmethod
691
+ def GetPublicIP():
692
+ ip = Channel._get('https://api.ipify.org')
693
+ return ip
694
+
695
+ def Connect(self, host='127.0.0.1', port=54321):
696
+ self.host = host
697
+ self.port = port
698
+ try:
699
+ self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
700
+ self.connection.connect((host, port))
701
+ return self.connection
702
+ except Exception as e:
703
+ print(f"[Error] Connection failed: {e}")
704
+ return None
705
+
706
+ def ConnectPublic(self, port=54321):
707
+ public_ip = Channel.GetPublicIP()
708
+ if not public_ip:
709
+ print("[Error] Could not get public IP")
710
+ return None
711
+ return self.Connect(host=public_ip, port=port)
712
+
713
+ def CreateServer(self, port=54321):
714
+ self.is_server = True
715
+ self.port = port
716
+ try:
717
+ server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
718
+ server.bind(('0.0.0.0', port))
719
+ server.listen(1)
720
+ self.connection, addr = server.accept()
721
+ return self.connection
722
+ except Exception as e:
723
+ print(f"[Error] Server failed: {e}")
724
+ return None
725
+
726
+ def Disconnect(self):
727
+ if self.connection:
728
+ self.connection.close()
729
+ self.connection = None
730
+
731
+ def Send(self, message):
732
+ if not self.connection:
733
+ return False
734
+ try:
735
+ if isinstance(message, str):
736
+ message = message.encode()
737
+ self.connection.send(message + b'\n')
738
+ return True
739
+ except Exception:
740
+ return False
741
+
742
+ def Receive(self):
743
+ if not self.connection:
744
+ return None
745
+ try:
746
+ data = self.connection.recv(1024).decode().strip()
747
+ return data
748
+ except Exception:
749
+ return None
750
+
751
+ class Web:
752
+ @staticmethod
753
+ def StartHTMLCode(html_content, port=None):
754
+ if port is None:
755
+ port = Web._get_free_port()
756
+ class Handler(BaseHTTPRequestHandler):
757
+ def do_GET(self):
758
+ self.send_response(200)
759
+ self.send_header("Content-type", "text/html")
760
+ self.end_headers()
761
+ self.wfile.write(html_content.encode("utf-8"))
762
+ server = HTTPServer(("127.0.0.1", port), Handler)
763
+ thread = threading.Thread(target=server.serve_forever, daemon=True)
764
+ thread.start()
765
+ return port
766
+ @staticmethod
767
+ def _get_free_port():
768
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
769
+ s.bind(("", 0))
770
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
771
+ return s.getsockname()[1]
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: ConsoleFramework
3
+ Version: 0.9.2
4
+ Summary: The best Console Library of the Python.
5
+ Author: Suleiman
6
+ Author-email: steal.apet@mail.ru
7
+ License: MIT
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/plain
13
+ License-File: LICENSE
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: classifier
17
+ Dynamic: description
18
+ Dynamic: description-content-type
19
+ Dynamic: license
20
+ Dynamic: license-file
21
+ Dynamic: requires-python
22
+ Dynamic: summary
23
+
24
+ ConsoleFramework - Pure Python library for console rendering, animations, processes and more. In this module ONLY standart python, no other modules.
@@ -0,0 +1,6 @@
1
+ ConsoleFramework/__init__.py,sha256=s6-BS6Lle3GIg-rk1Y7RHI2z2EracMjnobpi6BStLBE,27076
2
+ consoleframework-0.9.2.dist-info/licenses/LICENSE,sha256=XABCXMEhX5-sSW6dVui3V35LHqtlwNF4Rj0Rfhuo4_8,1064
3
+ consoleframework-0.9.2.dist-info/METADATA,sha256=OWuy19ZkBCf3wXg4JrndLvshZheV3A2Q1jTgOtlh2Hw,744
4
+ consoleframework-0.9.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
5
+ consoleframework-0.9.2.dist-info/top_level.txt,sha256=gA6Vt8NYCghRZGB3TIpgf-e9w61A1zfOrxTMf-ZEoh0,17
6
+ consoleframework-0.9.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Suleiman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ ConsoleFramework