@entrypoint¶
The @entrypoint decorator marks a function or class as the application entry point. When the decorated item's file is run directly (module is __main__), it automatically creates a Qt application, runs the entry point, and starts the event loop.
When imported from another module, the decorator simply stores configuration without auto-running, allowing the class/function to be used normally.
Basic Usage¶
Without Parentheses¶
For default settings, use @entrypoint without parentheses:
from qtpie import entrypoint
from qtpy.QtWidgets import QLabel
@entrypoint
def main():
return QLabel("Hello, World!")
Run this file with python main.py and it automatically starts the Qt application.
With Parentheses¶
To customize the application, use @entrypoint() with parameters:
@entrypoint(dark_mode=True, title="My App", size=(800, 600))
def main():
return QLabel("Hello, World!")
Entry Point Styles¶
Function Entry Point¶
The simplest approach - a function that returns a widget:
from qtpie import entrypoint
from qtpy.QtWidgets import QLabel
@entrypoint
def main():
return QLabel("Hello, World!")
When run directly, this creates a QApplication, calls main(), shows the returned widget, and starts the event loop.
Widget Class Entry Point¶
Use with @widget for declarative widgets:
from qtpie import entrypoint, make, widget
from qtpy.QtWidgets import QLabel, QPushButton, QWidget
@entrypoint
@widget
class MyWidget(QWidget):
text: QLabel = make(QLabel, "Hello, World!")
button: QPushButton = make(QPushButton, "Click Me", clicked="on_click")
def on_click(self):
self.text.setText("Button Clicked!")
The decorator automatically instantiates the widget class, shows it, and runs the app.
App Class Entry Point¶
For full control over application lifecycle:
from typing import override
from qtpie import App, entrypoint
from qtpy.QtWidgets import QLabel
@entrypoint
class MyApp(App):
@override
def create_window(self):
return QLabel("Hello from App!")
This gives you access to App lifecycle hooks like setup() and create_window().
Async Entry Point¶
Use async functions with qasync:
import asyncio
from qtpie import entrypoint
from qtpy.QtWidgets import QLabel
@entrypoint
async def main():
# Perform async operations
await asyncio.sleep(1)
data = await fetch_data()
return DataViewer(data)
The decorator automatically sets up qasync.QEventLoop and runs the coroutine.
Parameters¶
dark_mode¶
Type: bool
Default: False
Enables dark mode color scheme for the application.
Example:
light_mode¶
Type: bool
Default: False
Enables light mode color scheme for the application. Typically unnecessary as light mode is the default Qt behavior.
Example:
title¶
Type: str | None
Default: None
Sets the window title. Applied to the widget returned by the entry point function or created from the decorated class.
Example:
@entrypoint(title="My Application v1.0")
def main():
return QLabel("Hello!")
# Window title will be "My Application v1.0"
size¶
Type: tuple[int, int] | None
Default: None
Sets the initial window size as (width, height) in pixels.
Example:
stylesheet¶
Type: str | None
Default: None
Path to a stylesheet. Supports three formats:
- Filesystem path - Regular file path (e.g.,
"styles.qss","styles/main.scss") - QRC path - Qt resource path starting with
:/(e.g.,":/styles/app.qss") - SCSS file - Any
.scssfile is automatically compiled to QSS
Examples:
@entrypoint(stylesheet="styles.qss") # Filesystem
def main():
return QLabel("Styled!")
@entrypoint(stylesheet=":/styles/app.qss") # QRC resource
def main():
return QLabel("Styled from resources!")
watch_stylesheet¶
Type: bool
Default: False
Enables hot-reload for the stylesheet. When True, changes to the stylesheet file are automatically detected and applied without restarting the app. Useful during development.
Note: Not applicable to QRC paths (resources are compiled into the binary).
Example:
@entrypoint(stylesheet="styles.scss", watch_stylesheet=True)
@widget
class MyApp(QWidget):
pass
# Now edit styles.scss and save - changes appear instantly!
scss_search_paths¶
Type: Sequence[str]
Default: ()
Directories to search when resolving SCSS @import statements. If empty, the parent directory of the stylesheet is used automatically.
Example:
@entrypoint(
stylesheet="styles/main.scss",
watch_stylesheet=True,
scss_search_paths=["styles/partials", "styles/themes"]
)
@widget
class MyApp(QWidget):
pass
With this structure:
myapp/
├── styles/
│ ├── main.scss # @import 'variables';
│ ├── partials/
│ │ └── _variables.scss
│ └── themes/
│ └── _dark.scss
└── main.py
window¶
Type: type[QWidget] | None
Default: None
A widget class to instantiate as the main window. Only used when the entry point function returns None or when decorating a non-widget class.
Example:
from qtpie import entrypoint
@entrypoint(window=MyMainWindow)
def main():
# Perform setup, but don't return a widget
initialize_database()
# MyMainWindow will be automatically created and shown
Auto-Run Behavior¶
The @entrypoint decorator automatically runs when both conditions are met:
- Module is
__main__- The file is executed directly (python myapp.py) - No QApplication exists - There's no existing Qt application instance
This means:
# myapp.py
@entrypoint
def main():
return QLabel("Hello!")
# When run directly:
# $ python myapp.py
# → Automatically creates QApplication and starts event loop
# When imported:
# from myapp import main
# → Does nothing, main() can be called manually
Testing Compatibility¶
The auto-run behavior is disabled when a QApplication already exists, making @entrypoint safe to use in tests:
# test_myapp.py
from qtpie.testing import QtDriver
def test_my_app(qt: QtDriver):
# This works fine - @entrypoint won't auto-run
# because qt fixture already created a QApplication
widget = MyAppWidget()
qt.track(widget)
# ... assertions
Complete Examples¶
Simple Counter¶
from qtpie import entrypoint, make, state, widget
from qtpy.QtWidgets import QLabel, QPushButton, QWidget
@entrypoint(title="Counter", size=(300, 150))
@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):
self.count += 1
App with Custom Setup¶
from typing import override
from qtpie import App, entrypoint, make, widget
from qtpy.QtWidgets import QLabel, QMainWindow, QWidget
@widget
class MainWidget(QWidget):
label: QLabel = make(QLabel, "Application Ready!")
@entrypoint(dark_mode=True, size=(800, 600))
class MyApp(App):
@override
def setup(self):
# Called before window creation
self.load_stylesheet("styles.qss")
print("App initialized")
@override
def create_window(self):
# Return the main window widget
return MainWidget()
Multiple Configuration Options¶
@entrypoint(
dark_mode=True,
title="Production Dashboard",
size=(1280, 720),
stylesheet="dashboard.scss",
)
@widget
class Dashboard(QWidget):
# ... widget implementation
Full Stylesheet Configuration¶
@entrypoint(
dark_mode=True,
title="My App",
size=(1024, 768),
stylesheet="styles/main.scss",
watch_stylesheet=True, # Hot-reload during development
scss_search_paths=["styles/partials", "styles/themes"],
)
@widget
class MyApp(QWidget):
label: QLabel = make(QLabel, "Styled with SCSS!")
Function with Window Parameter¶
from qtpie import entrypoint, make, widget
from qtpy.QtWidgets import QLabel, QWidget
@widget
class MainWindow(QWidget):
label: QLabel = make(QLabel, "Main Window")
@entrypoint(window=MainWindow, title="My App")
def main():
# Perform initialization
load_config()
connect_database()
# MainWindow will be automatically created and shown
Order with Other Decorators¶
When using @entrypoint with other decorators, @entrypoint should be the outermost decorator:
# Correct order
@entrypoint(dark_mode=True)
@widget(layout="vertical")
class MyApp(QWidget):
pass
# Also correct
@entrypoint
@window(title="My Window")
class MyApp(QMainWindow):
pass
This ensures @entrypoint decorates the fully-configured widget class.
When to Use¶
Use @entrypoint when:
- Building a standalone application with a single entry point file
- You want automatic app creation and event loop management
- Writing simple scripts or demos that should "just run"
Don't use @entrypoint when:
- Building a library (use regular
@widgetor@window) - The widget should be reusable as a component
- You need manual control over
QApplicationcreation
For library code, prefer explicit app creation:
from qtpie import run_app, widget
from qtpy.QtWidgets import QWidget
@widget # No @entrypoint
class MyLibraryWidget(QWidget):
pass
# Users can then do:
if __name__ == "__main__":
widget = MyLibraryWidget()
widget.show()
run_app()
See Also¶
- App & Entry Points - Complete guide to application structure
- App Class - App class reference
- run_app() - Manual event loop runner
- @widget - Widget decorator reference
- @window - Window decorator reference