QtPie
Tasty way to build Qt apps
from qtpie import entrypoint, make, state, widget
from qtpy.QtWidgets import QLabel, QPushButton, QWidget
@entrypoint
@widget
class Counter(QWidget):
count: int = state(0)
label: QLabel = make(QLabel, bind="Count: {count}")
button: QPushButton = make(QPushButton, "+1", clicked="increment")
def increment(self) -> None:
self.count += 1
Click the button. State changes. Label updates. That's it.
Declarative. Reactive. Delightful.
Install
pip install qtpie
Features
state()- reactive variables that update the UIbind="{x}"- format expressions with auto-refreshclicked="method"- signal connections by name@widget- dataclass-style components with automatic layoutsWidget[T]- type-safe model binding- SCSS hot reload - style with CSS classes
- Async support -
async defjust works - pyright strict - full type safety, no compromises
Why QtPie?
Qt is powerful but verbose:
# Plain Qt - 35 lines of boilerplate
class Counter(QWidget):
def __init__(self):
super().__init__()
self.setObjectName("Counter")
self.count = 0
layout = QVBoxLayout(self)
self.label = QLabel("Count: 0")
self.label.setObjectName("label")
layout.addWidget(self.label)
self.button = QPushButton("Add")
self.button.setObjectName("button")
self.button.clicked.connect(self.increment)
layout.addWidget(self.button)
def increment(self):
self.count += 1
self.label.setText(f"Count: {self.count}")
if __name__ == "__main__":
app = QApplication([])
window = Counter()
window.show()
app.exec()
vs QtPie - 12 lines, fully reactive:
@entrypoint
@widget
class Counter(QWidget):
count: int = state(0)
label: QLabel = make(QLabel, bind="Count: {count}")
button: QPushButton = make(QPushButton, "+1", clicked="increment")
def increment(self) -> None:
self.count += 1
Quick Examples
Reactive State
count: int = state(0)
label: QLabel = make(QLabel, bind="Count: {count}")
self.count += 1 # Label updates instantly
Two-Way Binding
@widget
class Greeter(QWidget):
name: str = state("")
name_input: QLineEdit = make(QLineEdit, bind="name")
greeting: QLabel = make(QLabel, bind="Hello, {name}!")
Type in the input, greeting updates. Change self.name, input updates.
Format Expressions
bind="Count: {count}"
bind="{first} {last}"
bind="{name.upper()}"
bind="Total: ${price * 1.1:.2f}"
Automatic Layouts
@widget
class MyWidget(QWidget):
top: QLabel = make(QLabel, "Top")
middle: QLabel = make(QLabel, "Middle")
bottom: QLabel = make(QLabel, "Bottom")
@widget(layout="form")
class MyForm(QWidget):
name: QLineEdit = make(QLineEdit, form_label="Name:")
email: QLineEdit = make(QLineEdit, form_label="Email:")
Model Binding
@dataclass
class Person:
name: str = ""
age: int = 0
@widget
class PersonEditor(QWidget, Widget[Person]):
name: QLineEdit = make(QLineEdit) # auto-binds to model.name
age: QSpinBox = make(QSpinBox) # auto-binds to model.age
Full Qt Access
QtPie is a layer, not a cage. All of Qt is still there:
@widget
class MyWidget(QWidget):
label: QLabel = make(QLabel, "Hello")
def setup(self) -> None:
self.setWindowTitle("My App")
self.label.setStyleSheet("color: red;")
Documentation
https://mrowrlib.github.io/qtpie
License
0BSD
Metadata
Release files for qtpie 0.1.10
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| qtpie-0.1.10.tar.gz | 52.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qtpie-0.1.10-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 125.9 kB
Release files / qtpie-0.1.10.tar.gz
| Download URL | qtpie-0.1.10.tar.gz |
|---|---|
| Size | 52.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
be0c37ea668e829af4df9faf9cbe9c59ea51909f860d9e07d6fbeab6041b2d1e
|
|
BLAKE2b-256 checksum How to use checksums |
d46acbcfb62f4d90d916dd147880524683245a44fc1c7d100832aecc9c4e0792
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.2
|
Release files / qtpie-0.1.10-py3-none-any.whl
| Download URL | qtpie-0.1.10-py3-none-any.whl |
|---|---|
| Size | 73.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0b02c54931a8f10d811c22967eb0ea890dcc6d993f2c7ad04092e5dbf6aa2e22
|
|
BLAKE2b-256 checksum How to use checksums |
e84add261cea9d7d92a45672980609ab772efee9d135e2b6a2c856cfa53045d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.2
|