chad-console 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ali
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,66 @@
1
+ Metadata-Version: 2.4
2
+ Name: chad-console
3
+ Version: 0.1.0
4
+ Summary: Intercepts print() and input() calls, routing them to a beautiful dark-mode GUI console.
5
+ Project-URL: Homepage, https://github.com/m-ali04/chad-console
6
+ Project-URL: Repository, https://github.com/m-ali04/chad-console
7
+ Project-URL: Issues, https://github.com/m-ali04/chad-console/issues
8
+ Author-email: m-ali04 <m-ali04@users.noreply.github.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: chad-console,console,customtkinter,developer-tools,gui,pretty-print
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Software Development :: User Interfaces
23
+ Requires-Python: >=3.12
24
+ Requires-Dist: customtkinter>=5.2
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == 'dev'
27
+ Requires-Dist: ruff>=0.4; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # ✦ ChadConsole
31
+
32
+ > Intercepts `print()` and `input()` — routes them to a beautiful dark-mode GUI.
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install chadconsole
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ```python
43
+ import chadconsole # That's it. All prints now go to the GUI.
44
+
45
+ print("Hello, world!")
46
+ print({"key": "value", "nested": [1, 2, 3]})
47
+
48
+ for i in range(5):
49
+ print("*" * (i + 1))
50
+
51
+ name = input("What's your name? ")
52
+ print(f"Welcome, {name}!")
53
+ ```
54
+
55
+ ## Features
56
+
57
+ - **Zero config** — just `import chadconsole` at the top of your script
58
+ - **Auto type detection** — lists, dicts, tuples get special formatted rendering
59
+ - **Loop grouping** — `print()` calls inside `for` loops are automatically batched into a single visual block (bytecode-based detection, no `time.sleep()` needed)
60
+ - **Input interception** — `input()` calls display a floating entry field in the GUI
61
+ - **Dark neumorphic UI** — premium design with blue accents and monospace code rendering
62
+ - **Thread-safe** — your script runs normally; the GUI runs in a background thread
63
+
64
+ ## License
65
+
66
+ MIT
@@ -0,0 +1,37 @@
1
+ # ✦ ChadConsole
2
+
3
+ > Intercepts `print()` and `input()` — routes them to a beautiful dark-mode GUI.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install chadconsole
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ import chadconsole # That's it. All prints now go to the GUI.
15
+
16
+ print("Hello, world!")
17
+ print({"key": "value", "nested": [1, 2, 3]})
18
+
19
+ for i in range(5):
20
+ print("*" * (i + 1))
21
+
22
+ name = input("What's your name? ")
23
+ print(f"Welcome, {name}!")
24
+ ```
25
+
26
+ ## Features
27
+
28
+ - **Zero config** — just `import chadconsole` at the top of your script
29
+ - **Auto type detection** — lists, dicts, tuples get special formatted rendering
30
+ - **Loop grouping** — `print()` calls inside `for` loops are automatically batched into a single visual block (bytecode-based detection, no `time.sleep()` needed)
31
+ - **Input interception** — `input()` calls display a floating entry field in the GUI
32
+ - **Dark neumorphic UI** — premium design with blue accents and monospace code rendering
33
+ - **Thread-safe** — your script runs normally; the GUI runs in a background thread
34
+
35
+ ## License
36
+
37
+ MIT
@@ -0,0 +1,97 @@
1
+ """Integration test for chadconsole interceptors (no GUI)."""
2
+ import sys, queue
3
+ sys.path.insert(0, "src")
4
+
5
+ from chadconsole.core_interceptor import install, uninstall
6
+ from chadconsole.data_analyzer import Payload
7
+ import builtins
8
+
9
+ out = sys.__stdout__
10
+
11
+ # Install interceptors with a test queue
12
+ q = queue.Queue()
13
+ handler = install(q)
14
+
15
+ def drain():
16
+ items = []
17
+ while not q.empty():
18
+ items.append(q.get_nowait())
19
+ return items
20
+
21
+ # === Test 1: Simple prints (NOT in loop) ===
22
+ builtins.print("Hello World")
23
+ builtins.print("Standard output")
24
+
25
+ items = drain()
26
+ out.write(f"Test 1 — Got {len(items)} payloads (expected 2)\n")
27
+ for p in items:
28
+ out.write(f" tag={p.tag!r} content={p.content!r}\n")
29
+ assert len(items) == 2, f"Expected 2, got {len(items)}"
30
+ assert all(p.tag == "standard" for p in items)
31
+ out.write(" PASS\n\n")
32
+
33
+ # === Test 2: List/dict/tuple prints ===
34
+ builtins.print([1, 2, 3])
35
+ builtins.print({"a": 1, "b": 2})
36
+ builtins.print((10, 20))
37
+
38
+ items = drain()
39
+ out.write(f"Test 2 — Got {len(items)} payloads (expected 3)\n")
40
+ for p in items:
41
+ out.write(f" tag={p.tag!r}\n")
42
+ assert len(items) == 3
43
+ assert items[0].tag == "list"
44
+ assert items[1].tag == "dictionary"
45
+ assert items[2].tag == "tuple"
46
+ out.write(" PASS\n\n")
47
+
48
+ # === Test 3: For loop prints (should be grouped) ===
49
+ for i in range(5):
50
+ builtins.print(f"Line {i}")
51
+
52
+ # Non-loop print triggers flush of loop buffer
53
+ builtins.print("After loop")
54
+
55
+ items = drain()
56
+ out.write(f"Test 3 — Got {len(items)} payloads (expected 2: loop_pattern + standard)\n")
57
+ for p in items:
58
+ out.write(f" tag={p.tag!r} content={repr(p.content[:60])}\n")
59
+ assert len(items) == 2, f"Expected 2, got {len(items)}: {[p.tag for p in items]}"
60
+ assert items[0].tag == "loop_pattern"
61
+ assert items[1].tag == "standard"
62
+ loop_lines = items[0].content.split("\n")
63
+ assert len(loop_lines) == 5, f"Expected 5 lines in loop, got {len(loop_lines)}"
64
+ out.write(" PASS\n\n")
65
+
66
+ # === Test 4: Two separate loops flush correctly ===
67
+ for i in range(3):
68
+ builtins.print(f"Loop A line {i}")
69
+
70
+ for i in range(2):
71
+ builtins.print(f"Loop B line {i}")
72
+
73
+ builtins.print("done")
74
+
75
+ items = drain()
76
+ out.write(f"Test 4 — Got {len(items)} payloads (expected 3: 2x loop_pattern + standard)\n")
77
+ for p in items:
78
+ out.write(f" tag={p.tag!r} content={repr(p.content[:60])}\n")
79
+ assert len(items) == 3, f"Got {len(items)}: {[p.tag for p in items]}"
80
+ assert items[0].tag == "loop_pattern"
81
+ assert items[1].tag == "loop_pattern"
82
+ assert items[2].tag == "standard"
83
+ out.write(" PASS\n\n")
84
+
85
+ # === Test 5: Mixed print (multiple args) ===
86
+ builtins.print("Total:", 42, "items")
87
+
88
+ items = drain()
89
+ out.write(f"Test 5 — Got {len(items)} payloads (expected 1)\n")
90
+ assert len(items) == 1
91
+ assert items[0].tag == "standard"
92
+ assert items[0].content == "Total: 42 items"
93
+ out.write(f" content={items[0].content!r} PASS\n\n")
94
+
95
+ uninstall()
96
+ out.write("=" * 40 + "\n")
97
+ out.write("ALL TESTS PASSED!\n")
@@ -0,0 +1,6 @@
1
+ === Starting import ===
2
+ === Import OK ===
3
+ === Printing standard text ===
4
+ === Calling input() ===
5
+ === Input returned: ali ===
6
+ === Keeping alive ===
@@ -0,0 +1,13 @@
1
+ """
2
+ error_test.py — Tests error display in ChadConsole
3
+ """
4
+ import sys
5
+ sys.path.insert(0, "src")
6
+
7
+ import chadconsole
8
+
9
+ print("Starting error test...")
10
+ print("This line is fine ✓")
11
+
12
+ # This will cause a NameError — undefined variable
13
+ print(232 + 23)
@@ -0,0 +1,4 @@
1
+ import chadconsole
2
+
3
+ for i in range(10):
4
+ print(f"Line {i + 1}")
@@ -0,0 +1,23 @@
1
+ import chadconsole
2
+
3
+ a = [2,5,2,5,6,41,78]
4
+
5
+
6
+ b = (6,78,34,90,143)
7
+
8
+ c = {5,7,0,2}
9
+
10
+ d = {"name": "Ali", "age": 20, "city": "Karachi"}
11
+
12
+ e = "Heleloow World"
13
+
14
+ print(e)
15
+
16
+ for i in d:
17
+ print(i)
18
+
19
+ print(a)
20
+ print(b)
21
+ print(c)
22
+ print(d)
23
+
@@ -0,0 +1,45 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "chad-console"
7
+ version = "0.1.0"
8
+ description = "Intercepts print() and input() calls, routing them to a beautiful dark-mode GUI console."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.12"
12
+ authors = [
13
+ { name = "m-ali04", email = "m-ali04@users.noreply.github.com" },
14
+ ]
15
+ keywords = ["console", "gui", "developer-tools", "pretty-print", "customtkinter", "chad-console"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ "Topic :: Software Development :: User Interfaces",
28
+ ]
29
+ dependencies = [
30
+ "customtkinter>=5.2",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=7.0",
36
+ "ruff>=0.4",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/m-ali04/chad-console"
41
+ Repository = "https://github.com/m-ali04/chad-console"
42
+ Issues = "https://github.com/m-ali04/chad-console/issues"
43
+
44
+ [tool.hatch.build.targets.wheel]
45
+ packages = ["src/chadconsole"]
@@ -0,0 +1,79 @@
1
+ """
2
+ chadconsole
3
+ ~~~~~~~~~~~
4
+
5
+ Just ``import chadconsole`` and all your print() and input() calls
6
+ are routed to a beautiful dark-mode GUI window.
7
+
8
+ Architecture:
9
+ 1. A shared queue.Queue connects the script thread to the UI thread.
10
+ 2. core_interceptor replaces sys.stdout, builtins.print, builtins.input.
11
+ 3. ui_engine.PrettyConsoleApp runs Tk mainloop in a NON-daemon thread
12
+ so the window stays alive even after the user's script finishes.
13
+ 4. The user's script continues executing on the main thread.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ __version__ = "0.1.0"
19
+ __all__: list[str] = []
20
+
21
+ import atexit
22
+ import os
23
+ import queue
24
+ import sys
25
+ import threading
26
+
27
+ from chadconsole.core_interceptor import install, uninstall
28
+ from chadconsole.ui_engine import PrettyConsoleApp
29
+
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # Shared communication channel
33
+ # ---------------------------------------------------------------------------
34
+
35
+ _output_queue: queue.Queue = queue.Queue()
36
+
37
+ # ---------------------------------------------------------------------------
38
+ # Install interceptors
39
+ # ---------------------------------------------------------------------------
40
+
41
+ _input_handler = install(_output_queue)
42
+
43
+ # ---------------------------------------------------------------------------
44
+ # Launch the UI in a NON-daemon thread (keeps process alive until window closes)
45
+ # ---------------------------------------------------------------------------
46
+
47
+ _app: PrettyConsoleApp | None = None
48
+ _ui_ready = threading.Event()
49
+
50
+
51
+ def _run_ui() -> None:
52
+ """Entry point for the UI thread.
53
+
54
+ This is a NON-daemon thread so the window stays open even after the
55
+ user's main script finishes executing. The process exits only when
56
+ the user closes the GUI window.
57
+ """
58
+ global _app
59
+ try:
60
+ _app = PrettyConsoleApp(_output_queue)
61
+ _app.set_input_handler(_input_handler)
62
+ _ui_ready.set()
63
+ _app.mainloop()
64
+ except Exception:
65
+ import traceback
66
+ sys.__stderr__.write(f"[ChadConsole] UI thread crashed:\n{traceback.format_exc()}\n")
67
+ _ui_ready.set() # Unblock main thread even on failure
68
+ finally:
69
+ # When the window is closed (mainloop exits), clean up and exit
70
+ uninstall()
71
+ os._exit(0) # Clean exit — suppresses Tcl_AsyncDelete noise
72
+
73
+
74
+ # NON-daemon thread: process stays alive until this thread ends (window closed)
75
+ _ui_thread = threading.Thread(target=_run_ui, daemon=False, name="ChadConsole-UI")
76
+ _ui_thread.start()
77
+
78
+ # Wait for the UI to be ready before the script proceeds
79
+ _ui_ready.wait(timeout=5.0)