tqrex 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.
tqrex-0.1.0/.coverage ADDED
Binary file
@@ -0,0 +1,49 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint:
11
+ name: Lint & type-check
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.11"
18
+ - name: Install dev deps
19
+ run: pip install -e ".[dev]"
20
+ - name: Ruff check
21
+ run: ruff check src/ tests/
22
+ - name: Ruff format
23
+ run: ruff format --check src/ tests/
24
+ - name: Mypy
25
+ run: mypy src/playgress
26
+
27
+ test:
28
+ name: Test — Python ${{ matrix.python-version }} / ${{ matrix.os }}
29
+ runs-on: ${{ matrix.os }}
30
+ strategy:
31
+ fail-fast: false
32
+ matrix:
33
+ os: [ubuntu-latest, macos-latest]
34
+ python-version: ["3.11", "3.12", "3.13"]
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+ - uses: actions/setup-python@v5
38
+ with:
39
+ python-version: ${{ matrix.python-version }}
40
+ - name: Install dev deps
41
+ run: pip install -e ".[dev]"
42
+ - name: Run tests (skip terminal-requiring tests in CI)
43
+ run: pytest -m "not terminal" --cov=playgress --cov-report=xml
44
+ - name: Upload coverage
45
+ uses: codecov/codecov-action@v4
46
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
47
+ with:
48
+ files: coverage.xml
49
+ fail_ci_if_error: false
tqrex-0.1.0/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ venv/
5
+ env/
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ .pytest_cache/
10
+ .ruff_cache/
tqrex-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mikhail Samoilov
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.
tqrex-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: tqrex
3
+ Version: 0.1.0
4
+ Summary: A progress bar that lets you play the Chrome T-Rex game in your terminal
5
+ Project-URL: Homepage, https://github.com/Samoilov2004/tqrex
6
+ Project-URL: Repository, https://github.com/Samoilov2004/tqrex
7
+ Project-URL: Issues, https://github.com/Samoilov2004/tqrex/issues
8
+ Project-URL: Changelog, https://github.com/Samoilov2004/tqrex/releases
9
+ Author: Mikhail Samoilov
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 Mikhail Samoilov
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: cli,dinosaur,fun,game,progress,progress-bar,terminal,tqdm,trex
33
+ Classifier: Development Status :: 3 - Alpha
34
+ Classifier: Environment :: Console
35
+ Classifier: Intended Audience :: Developers
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Programming Language :: Python :: 3.13
42
+ Classifier: Topic :: Games/Entertainment :: Arcade
43
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
44
+ Classifier: Topic :: Terminals
45
+ Classifier: Typing :: Typed
46
+ Requires-Python: >=3.11
47
+ Provides-Extra: dev
48
+ Requires-Dist: mypy>=1.11; extra == 'dev'
49
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
50
+ Requires-Dist: pytest>=8.0; extra == 'dev'
51
+ Requires-Dist: ruff>=0.5; extra == 'dev'
52
+ Description-Content-Type: text/markdown
53
+
54
+ # playgress
55
+
56
+ > A progress bar that lets you play the Chrome T-Rex game in your terminal.
57
+
58
+ ![demo](demo.gif)
59
+
60
+ Your long-running script doesn't have to be boring. **playgress** wraps any
61
+ iterable in a full T-Rex side-scroller — jump cacti, dodge birds, rack up a
62
+ high score — while your real work happens in the background. When the task
63
+ finishes the game keeps running until you decide to quit.
64
+
65
+ ---
66
+
67
+ ## Features
68
+
69
+ - **Zero runtime dependencies** — pure Python standard library
70
+ - **Drop-in `tqdm` replacement** — `track()` has the same call signature
71
+ - **`Progress` context manager** — for manual update control
72
+ - **60 FPS physics** — faithful gravity, jump arc, and speed curve from the
73
+ original Chrome dino
74
+ - **Autoplay AI** — built-in geometric look-ahead controller (`autoplay=True`)
75
+ - **Double-buffered renderer** — flicker-free diff-based redraw, single write
76
+ per frame
77
+ - **Cross-platform** — macOS, Linux, Windows (ANSI terminal required)
78
+ - **Python 3.11+**
79
+
80
+ ---
81
+
82
+ ## Installation
83
+
84
+ ```bash
85
+ pip install playgress
86
+ ```
87
+
88
+ Or for local development:
89
+
90
+ ```bash
91
+ git clone https://github.com/mikhail-samoilov/playgress
92
+ cd playgress
93
+ pip install -e ".[dev]"
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Quickstart
99
+
100
+ ### Drop-in replacement for `tqdm`
101
+
102
+ ```python
103
+ import time
104
+ from playgress import track
105
+
106
+ for item in track(range(100), description="Processing"):
107
+ time.sleep(0.05)
108
+ ```
109
+
110
+ ### Any iterable works
111
+
112
+ ```python
113
+ files = ["data_001.csv", "data_002.csv", ...]
114
+
115
+ for f in track(files, description="Crunching files"):
116
+ crunch(f)
117
+ ```
118
+
119
+ ### Manual control with the `Progress` context manager
120
+
121
+ ```python
122
+ from playgress import Progress
123
+
124
+ steps = ["Download", "Extract", "Build", "Install"]
125
+ with Progress(total=len(steps), description="Installing") as p:
126
+ for step in steps:
127
+ p.set_description(f"Step: {step}")
128
+ run(step)
129
+ p.update(1)
130
+ ```
131
+
132
+ ### Let the AI play for you
133
+
134
+ ```python
135
+ for epoch in track(range(200), description="Training", autoplay=True):
136
+ train_one_epoch(epoch)
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Keyboard controls
142
+
143
+ | Key | Action |
144
+ |-----|--------|
145
+ | `Space` / `↑` | Jump |
146
+ | `↓` | Duck on ground / fast-drop mid-air |
147
+ | `R` | Restart after game-over; replay after task completes |
148
+ | `Q` / `Ctrl-C` | Quit — unblocks the script |
149
+
150
+ > **Note:** The game keeps running after all items are processed so you can
151
+ > finish your current run. Press **Q** when you're done.
152
+
153
+ ---
154
+
155
+ ## Themes
156
+
157
+ The default theme uses prototype-verified ASCII art that renders crisply in
158
+ every monospace font:
159
+
160
+ ```
161
+ ++++ /|\/|\ <o=-
162
+ ++ ++Q+++ | | |
163
+ + +++++_ww
164
+ ++++++
165
+ | |
166
+ ```
167
+
168
+ An `EMOJI` theme (`theme=Theme.EMOJI`) for full Unicode width terminals is on
169
+ the roadmap.
170
+
171
+ ---
172
+
173
+ ## API reference
174
+
175
+ ### `track(iterable, *, description, total, theme, autoplay, disable)`
176
+
177
+ | Parameter | Type | Default | Description |
178
+ |-----------|------|---------|-------------|
179
+ | `iterable` | `Iterable[T]` | — | Items to iterate over |
180
+ | `description` | `str` | `"Processing..."` | Status line label |
181
+ | `total` | `int \| None` | `None` | Item count; auto-inferred from `len()` |
182
+ | `theme` | `Theme` | `Theme.AUTO` | Sprite theme |
183
+ | `autoplay` | `bool` | `False` | Enable AI controller |
184
+ | `disable` | `bool` | `False` | Skip game; yield items silently |
185
+
186
+ Returns a generator that yields items from `iterable` unchanged.
187
+
188
+ ### `Progress(total, description, theme, autoplay)`
189
+
190
+ | Method | Description |
191
+ |--------|-------------|
192
+ | `update(n=1)` | Advance by *n* steps (thread-safe) |
193
+ | `set_description(text)` | Update the status line label |
194
+ | `fraction` | Current progress as a float in `[0, 1]` |
195
+
196
+ ---
197
+
198
+ ## CI / non-interactive environments
199
+
200
+ When `stdout` is not a TTY (piped output, GitHub Actions, `pytest`) the game
201
+ is automatically bypassed and items are yielded with zero overhead. No
202
+ `disable=True` guard needed.
203
+
204
+ ---
205
+
206
+ ## How it works
207
+
208
+ ```
209
+ Main thread Game thread (60 FPS) Input thread
210
+ ────────── ──────────────────── ────────────
211
+ for item in track():
212
+ yield item ←→ read ProgressState ←← push InputEvent
213
+ completed += 1 run physics (termios raw mode /
214
+ render diff frame msvcrt poll)
215
+ shutdown.wait()
216
+ ```
217
+
218
+ Three threads, two shared objects: a `ProgressState` (protected by a
219
+ `threading.Lock`) and a `queue.Queue[InputEvent]` (lock-free). The game thread
220
+ owns all `GameState` mutations — no other thread touches it.
221
+
222
+ ---
223
+
224
+ ## License
225
+
226
+ MIT — see [LICENSE](LICENSE).
tqrex-0.1.0/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # playgress
2
+
3
+ > A progress bar that lets you play the Chrome T-Rex game in your terminal.
4
+
5
+ ![demo](demo.gif)
6
+
7
+ Your long-running script doesn't have to be boring. **playgress** wraps any
8
+ iterable in a full T-Rex side-scroller — jump cacti, dodge birds, rack up a
9
+ high score — while your real work happens in the background. When the task
10
+ finishes the game keeps running until you decide to quit.
11
+
12
+ ---
13
+
14
+ ## Features
15
+
16
+ - **Zero runtime dependencies** — pure Python standard library
17
+ - **Drop-in `tqdm` replacement** — `track()` has the same call signature
18
+ - **`Progress` context manager** — for manual update control
19
+ - **60 FPS physics** — faithful gravity, jump arc, and speed curve from the
20
+ original Chrome dino
21
+ - **Autoplay AI** — built-in geometric look-ahead controller (`autoplay=True`)
22
+ - **Double-buffered renderer** — flicker-free diff-based redraw, single write
23
+ per frame
24
+ - **Cross-platform** — macOS, Linux, Windows (ANSI terminal required)
25
+ - **Python 3.11+**
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install playgress
33
+ ```
34
+
35
+ Or for local development:
36
+
37
+ ```bash
38
+ git clone https://github.com/mikhail-samoilov/playgress
39
+ cd playgress
40
+ pip install -e ".[dev]"
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Quickstart
46
+
47
+ ### Drop-in replacement for `tqdm`
48
+
49
+ ```python
50
+ import time
51
+ from playgress import track
52
+
53
+ for item in track(range(100), description="Processing"):
54
+ time.sleep(0.05)
55
+ ```
56
+
57
+ ### Any iterable works
58
+
59
+ ```python
60
+ files = ["data_001.csv", "data_002.csv", ...]
61
+
62
+ for f in track(files, description="Crunching files"):
63
+ crunch(f)
64
+ ```
65
+
66
+ ### Manual control with the `Progress` context manager
67
+
68
+ ```python
69
+ from playgress import Progress
70
+
71
+ steps = ["Download", "Extract", "Build", "Install"]
72
+ with Progress(total=len(steps), description="Installing") as p:
73
+ for step in steps:
74
+ p.set_description(f"Step: {step}")
75
+ run(step)
76
+ p.update(1)
77
+ ```
78
+
79
+ ### Let the AI play for you
80
+
81
+ ```python
82
+ for epoch in track(range(200), description="Training", autoplay=True):
83
+ train_one_epoch(epoch)
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Keyboard controls
89
+
90
+ | Key | Action |
91
+ |-----|--------|
92
+ | `Space` / `↑` | Jump |
93
+ | `↓` | Duck on ground / fast-drop mid-air |
94
+ | `R` | Restart after game-over; replay after task completes |
95
+ | `Q` / `Ctrl-C` | Quit — unblocks the script |
96
+
97
+ > **Note:** The game keeps running after all items are processed so you can
98
+ > finish your current run. Press **Q** when you're done.
99
+
100
+ ---
101
+
102
+ ## Themes
103
+
104
+ The default theme uses prototype-verified ASCII art that renders crisply in
105
+ every monospace font:
106
+
107
+ ```
108
+ ++++ /|\/|\ <o=-
109
+ ++ ++Q+++ | | |
110
+ + +++++_ww
111
+ ++++++
112
+ | |
113
+ ```
114
+
115
+ An `EMOJI` theme (`theme=Theme.EMOJI`) for full Unicode width terminals is on
116
+ the roadmap.
117
+
118
+ ---
119
+
120
+ ## API reference
121
+
122
+ ### `track(iterable, *, description, total, theme, autoplay, disable)`
123
+
124
+ | Parameter | Type | Default | Description |
125
+ |-----------|------|---------|-------------|
126
+ | `iterable` | `Iterable[T]` | — | Items to iterate over |
127
+ | `description` | `str` | `"Processing..."` | Status line label |
128
+ | `total` | `int \| None` | `None` | Item count; auto-inferred from `len()` |
129
+ | `theme` | `Theme` | `Theme.AUTO` | Sprite theme |
130
+ | `autoplay` | `bool` | `False` | Enable AI controller |
131
+ | `disable` | `bool` | `False` | Skip game; yield items silently |
132
+
133
+ Returns a generator that yields items from `iterable` unchanged.
134
+
135
+ ### `Progress(total, description, theme, autoplay)`
136
+
137
+ | Method | Description |
138
+ |--------|-------------|
139
+ | `update(n=1)` | Advance by *n* steps (thread-safe) |
140
+ | `set_description(text)` | Update the status line label |
141
+ | `fraction` | Current progress as a float in `[0, 1]` |
142
+
143
+ ---
144
+
145
+ ## CI / non-interactive environments
146
+
147
+ When `stdout` is not a TTY (piped output, GitHub Actions, `pytest`) the game
148
+ is automatically bypassed and items are yielded with zero overhead. No
149
+ `disable=True` guard needed.
150
+
151
+ ---
152
+
153
+ ## How it works
154
+
155
+ ```
156
+ Main thread Game thread (60 FPS) Input thread
157
+ ────────── ──────────────────── ────────────
158
+ for item in track():
159
+ yield item ←→ read ProgressState ←← push InputEvent
160
+ completed += 1 run physics (termios raw mode /
161
+ render diff frame msvcrt poll)
162
+ shutdown.wait()
163
+ ```
164
+
165
+ Three threads, two shared objects: a `ProgressState` (protected by a
166
+ `threading.Lock`) and a `queue.Queue[InputEvent]` (lock-free). The game thread
167
+ owns all `GameState` mutations — no other thread touches it.
168
+
169
+ ---
170
+
171
+ ## License
172
+
173
+ MIT — see [LICENSE](LICENSE).
tqrex-0.1.0/demo.gif ADDED
Binary file
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ import time
5
+
6
+ from playgress import Progress, track
7
+ from playgress.config import Theme
8
+
9
+
10
+ def example_track() -> None:
11
+ """Process 60 items while playing the T-Rex game.
12
+
13
+ Keys during the game:
14
+ SPACE / ↑ jump
15
+ ↓ duck / fast-drop mid-air
16
+ R restart after game-over or after task completes
17
+ Q quit (unblocks the script)
18
+ """
19
+ files = [f"report_{i:04d}.csv" for i in range(60)]
20
+ for _f in track(files, description="Crunching reports"):
21
+ time.sleep(0.12) # simulate I/O work
22
+
23
+ def example_range() -> None:
24
+ """Iterate over range(100) — total is inferred automatically."""
25
+ for _i in track(range(100), description="Training epochs"):
26
+ time.sleep(0.05)
27
+
28
+ def example_context() -> None:
29
+ """Use Progress when you control the update timing explicitly."""
30
+ steps = ["Download", "Unpack", "Compile", "Link", "Install"]
31
+ with Progress(total=len(steps), description="Building package") as p:
32
+ for step in steps:
33
+ p.set_description(f"Step: {step}")
34
+ time.sleep(0.8)
35
+ p.update(1)
36
+
37
+ def example_autoplay() -> None:
38
+ """Let the AI controller play while your batch job runs."""
39
+ dataset = list(range(80))
40
+ for _d in track(dataset, description="Embedding vectors", autoplay=True):
41
+ time.sleep(0.08)
42
+
43
+ _EXAMPLES: dict[str, tuple[str, object]] = {
44
+ "track": ("Process 60 files (default)", example_track),
45
+ "range": ("Iterate range(100)", example_range),
46
+ "context": ("Manual Progress manager", example_context),
47
+ "autoplay": ("Autoplay AI controller", example_autoplay),
48
+ }
49
+
50
+ if __name__ == "__main__":
51
+ mode = sys.argv[1] if len(sys.argv) > 1 else "track"
52
+ if mode not in _EXAMPLES:
53
+ print(f"Unknown example '{mode}'. Choose from: {', '.join(_EXAMPLES)}")
54
+ sys.exit(1)
55
+ label, fn = _EXAMPLES[mode]
56
+ print(f"Running: {label}")
57
+ fn() # type: ignore[operator]
58
+ print("\nAll done. Goodbye!")