Skip to content

Commit 739cedf

Browse files
committed
Initial commit
1 parent 7ed8ac6 commit 739cedf

File tree

5,261 files changed

+813
-3768774
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

5,261 files changed

+813
-3768774
lines changed

.gitignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Python
2+
__pycache__/
3+
*.pyc
4+
*.pyo
5+
*.pyd
6+
7+
# Virtual environments
8+
.venv/
9+
venv/
10+
11+
# Logs
12+
logs/
13+
*.log
14+
15+
# Editor / OS
16+
.vscode/
17+
.DS_Store
18+
Thumbs.db
19+
20+
# PyInstaller
21+
build/
22+
dist/
23+
*.spec

MyApp.spec

Lines changed: 0 additions & 52 deletions
This file was deleted.

README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Pythonator
2+
3+
**Pythonator** is a simple desktop app for running and managing multiple Python scripts side-by-side without living in terminal tabs. It’s built for developers who want fast iteration, clear logs, and simple process control.
4+
5+
Think of it as a local “script runner” with a GUI.
6+
7+
<p align="left">
8+
<img alt="Python" src="https://img.shields.io/badge/Python-3.13%2B-blue" />
9+
<img alt="PyQt6" src="https://img.shields.io/badge/UI-PyQt6-41CD52" />
10+
<img alt="License" src="https://img.shields.io/badge/License-MIT-black" />
11+
</p>
12+
13+
---
14+
15+
## Screenshots
16+
<p align="center">
17+
<img src="screenshots/main.png" alt="Pythonator - Main window" width="92%">
18+
</p>
19+
20+
<p align="center">
21+
<img src="screenshots/logs.png" alt="Pythonator - Live logs & tabs" width="45%">
22+
<img src="screenshots/editor.png" alt="Pythonator - Built-in editor" width="45%">
23+
</p>
24+
25+
<details>
26+
<summary><b>Venv Setup & History</summary>
27+
<br/>
28+
<p align="center">
29+
<img src="screenshots/history-search.png" alt="Pythonator - History + Search mode" width="92%">
30+
</p>
31+
<p align="center">
32+
<img src="screenshots/venv.png" alt="Pythonator - Venv + deps setup" width="92%">
33+
</p>
34+
</details>
35+
36+
---
37+
38+
## What it does
39+
40+
* Run **multiple Python scripts** at the same time
41+
* Each script gets its **own live log tab**
42+
* Full **ANSI color support** (logs look like a real terminal)
43+
* **Start / stop / restart** scripts individually or all at once
44+
* Optional **auto-restart on crash**
45+
* **Per-script virtual environments**
46+
* Install dependencies from the UI
47+
* Built-in **Python editor** (syntax highlighting + autocomplete)
48+
* View **CPU and RAM usage** per running process
49+
* Persistent logs saved to disk
50+
51+
---
52+
53+
## Why it exists
54+
55+
Pythonator was made to remove the friction of:
56+
57+
* switching terminals
58+
* remembering which venv belongs to which script
59+
* scrolling through noisy logs
60+
* restarting crashed processes manually
61+
* running long lived services
62+
63+
It’s especially useful for:
64+
65+
* local bots
66+
* background workers
67+
* small services
68+
* experiments you want to keep running while you code
69+
70+
---
71+
72+
## Key features (quick list)
73+
74+
* **Workspace-based setup** — each script has its own config
75+
* **Live / history / search** log modes
76+
* **Safe process isolation** (no zombie processes)
77+
* **Cross-platform** (Windows, macOS, Linux)
78+
* Dark UI by default (no eye strain)
79+
80+
---
81+
82+
## Getting started
83+
84+
### Requirements
85+
86+
* Python 3.13+
87+
* `PyQt6` for the UI
88+
* `psutil` for CPU/RAM stats
89+
* `jedi` for editor autocomplete
90+
91+
### How to run it
92+
93+
```bash
94+
git clone <your-repo-url>
95+
cd <your-repo-folder>
96+
python app.py
97+
```
98+
99+
No installer, no magic — just run it.
100+
101+
---
102+
103+
## Typical workflow
104+
105+
1. Create a new workspace
106+
2. Point it at a Python script
107+
3. (Optional) Use the built-in script editor
108+
4. (Optional) Set a custom Python path
109+
5. (Optional) Add a startup command or flags
110+
6. Set up a venv
111+
7. Install dependencies
112+
8. Hit **Start**
113+
9. Watch logs stream in live
114+
115+
---
116+
117+
## License
118+
119+
MIT.
120+
Use it, fork it, break it, improve it.

app.py

Lines changed: 22 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,38 @@
1-
"""
2-
Application entry point with dark theme.
3-
"""
4-
"""
5-
Application entry point with dark theme.
6-
"""
7-
from version import __version__
1+
"""Pythonator - Python Bot Runner."""
2+
import sys, os
3+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
84

9-
import os
10-
import sys
11-
12-
# 🔒 GUARANTEE local imports work (main_window.py in same folder)
13-
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
14-
if BASE_DIR not in sys.path:
15-
sys.path.insert(0, BASE_DIR)
16-
17-
from PyQt6.QtGui import QIcon, QColor, QPalette, QFont
5+
from PyQt6.QtGui import QIcon, QColor, QPalette
186
from PyQt6.QtWidgets import QApplication, QStyleFactory
19-
7+
from config import STYLE
208
from main_window import MainWindow
219

22-
23-
def setup_dark_palette() -> QPalette:
24-
"""Create a dark theme palette."""
10+
def dark_palette() -> QPalette:
2511
pal = QPalette()
26-
27-
# Base colors
28-
dark = QColor(24, 24, 24)
29-
darker = QColor(18, 18, 18)
30-
light = QColor(220, 220, 220)
31-
mid = QColor(35, 35, 35)
32-
accent = QColor(70, 130, 220)
33-
34-
# Window
35-
pal.setColor(QPalette.ColorRole.Window, dark)
36-
pal.setColor(QPalette.ColorRole.WindowText, light)
37-
38-
# Base (input backgrounds)
39-
pal.setColor(QPalette.ColorRole.Base, darker)
40-
pal.setColor(QPalette.ColorRole.AlternateBase, dark)
41-
pal.setColor(QPalette.ColorRole.Text, light)
42-
43-
# Buttons
44-
pal.setColor(QPalette.ColorRole.Button, mid)
45-
pal.setColor(QPalette.ColorRole.ButtonText, light)
46-
47-
# Selection
48-
pal.setColor(QPalette.ColorRole.Highlight, accent)
49-
pal.setColor(QPalette.ColorRole.HighlightedText, QColor(255, 255, 255))
50-
51-
# Tooltips
52-
pal.setColor(QPalette.ColorRole.ToolTipBase, dark)
53-
pal.setColor(QPalette.ColorRole.ToolTipText, light)
54-
55-
# Links
56-
pal.setColor(QPalette.ColorRole.Link, accent)
57-
pal.setColor(QPalette.ColorRole.LinkVisited, QColor(180, 130, 220))
58-
59-
# Disabled
60-
pal.setColor(QPalette.ColorRole.PlaceholderText, QColor(128, 128, 128))
61-
12+
dark, darker, light, mid, accent = QColor(24,24,24), QColor(18,18,18), QColor(220,220,220), QColor(35,35,35), QColor(70,130,220)
13+
for role, color in [(QPalette.ColorRole.Window, dark), (QPalette.ColorRole.WindowText, light),
14+
(QPalette.ColorRole.Base, darker), (QPalette.ColorRole.AlternateBase, dark), (QPalette.ColorRole.Text, light),
15+
(QPalette.ColorRole.Button, mid), (QPalette.ColorRole.ButtonText, light),
16+
(QPalette.ColorRole.Highlight, accent), (QPalette.ColorRole.HighlightedText, QColor(255,255,255)),
17+
(QPalette.ColorRole.ToolTipBase, dark), (QPalette.ColorRole.ToolTipText, light),
18+
(QPalette.ColorRole.Link, accent), (QPalette.ColorRole.LinkVisited, QColor(180,130,220)),
19+
(QPalette.ColorRole.PlaceholderText, QColor(128,128,128))]:
20+
pal.setColor(role, color)
6221
return pal
6322

64-
6523
def main() -> int:
66-
"""Run the application."""
6724
app = QApplication(sys.argv)
68-
69-
# Style and theme
7025
app.setStyle(QStyleFactory.create("Fusion"))
71-
app.setPalette(setup_dark_palette())
72-
73-
# Application font
74-
font = app.font()
75-
font.setPointSize(10)
76-
app.setFont(font)
77-
78-
# Global stylesheet for consistent look
79-
app.setStyleSheet("""
80-
QToolTip {
81-
background-color: #252525;
82-
color: #ddd;
83-
border: 1px solid #444;
84-
padding: 4px;
85-
border-radius: 2px;
86-
}
87-
QScrollBar:vertical {
88-
background: #1a1a1a;
89-
width: 12px;
90-
margin: 0;
91-
}
92-
QScrollBar::handle:vertical {
93-
background: #404040;
94-
min-height: 20px;
95-
border-radius: 4px;
96-
margin: 2px;
97-
}
98-
QScrollBar::handle:vertical:hover {
99-
background: #505050;
100-
}
101-
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
102-
height: 0;
103-
}
104-
QScrollBar:horizontal {
105-
background: #1a1a1a;
106-
height: 12px;
107-
margin: 0;
108-
}
109-
QScrollBar::handle:horizontal {
110-
background: #404040;
111-
min-width: 20px;
112-
border-radius: 4px;
113-
margin: 2px;
114-
}
115-
QScrollBar::handle:horizontal:hover {
116-
background: #505050;
117-
}
118-
QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
119-
width: 0;
120-
}
121-
QMessageBox {
122-
background-color: #1a1a1a;
123-
}
124-
QMessageBox QLabel {
125-
color: #ddd;
126-
}
127-
""")
128-
129-
# Try to set window icon
130-
try:
131-
app.setWindowIcon(QIcon("icon.ico"))
132-
except Exception:
133-
pass
134-
135-
# Create and show main window
26+
app.setPalette(dark_palette())
27+
font = app.font(); font.setPointSize(10); app.setFont(font)
28+
app.setStyleSheet(STYLE)
29+
try: app.setWindowIcon(QIcon("icon.ico"))
30+
except: pass
13631
window = MainWindow()
137-
try:
138-
window.setWindowIcon(QIcon("icon.ico"))
139-
except Exception:
140-
pass
32+
try: window.setWindowIcon(QIcon("icon.ico"))
33+
except: pass
14134
window.show()
142-
14335
return app.exec()
14436

145-
14637
if __name__ == "__main__":
14738
sys.exit(main())

app_main.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)