The open-source GetX-inspired Python Framework for Building Reactive, Cross-Platform Apps with Flet
FletX brings Flutter's beloved GetX patterns to Python, combining Flet's UI capabilities with:
- β‘ Reactive state management
- π§ Declarative routing
- π Dependency injection
- π§© Modular architecture
- π¨ Widget library
Perfect for building desktop, web, and mobile apps with Python at lightning speed.
NOTE: FletX currently supports Python 3.12 only. Compatibility with newer versions is in progress β we're actively working to expand support soon.
pip install FletXr --pre
fletx new my_project --no-install
my_project/
βββ app/
β βββ controllers/ # Business logic controllers
β βββ services/ # Business services and API calls
β βββ models/ # Data models
β βββ components/ # Reusable widgets
β βββ pages/ # Application pages
β βββ routes.py # App routing modules
βββ assets/ # Static assets (images, fonts, etc.)
βββ tests/ # Test files
βββ .python-version # Python version
βββ pyproject.toml # Python dependencies
βββ README.md # Quick start README
βββ main.py # Application entry point
To run the project, just navigate to the project folder and run this command
fletx run --web # Will open app in a navigator
# --desktop to open app in a desktop window
# --android to open app on Android device
# --ios to open app on a iOs device
# --help for more option
The fletx test
command allows you to run tests for your FletX project using pytest
.
fletx test # Run all tests
fletx test ./tests/test_api.py # Run a specific test file
fletx test -k "MyTestClass" # Run tests matching a keyword
fletx test -v # Verbose output
fletx test --coverage # Run tests with coverage report
fletx test --pdb # Debug on test failure
import flet as ft
from fletx.app import FletXApp
from fletx.core import (
FletXPage, FletXController, RxInt, RxStr
)
from fletx.navigation import router_config
from fletx.decorators import obx
class CounterController(FletXController):
def __init__(self):
count = RxInt(0) # Reactive state
super().__init__()
class CounterPage(FletXPage):
ctrl = CounterController()
@obx
def counter_text(self):
return ft.Text(
value = f'Count: {self.ctrl.count}',
size = 50,
weight = "bold",
color = 'red' if not self.ctrl.count.value % 2 == 0 else 'white'
)
def build(self):
return ft.Column(
controls = [
self.counter_text(),
ft.ElevatedButton(
"Increment",
on_click = lambda e: self.ctrl.count.increment() # Auto UI update
)
]
)
def main():
# Defining route
router_config.add_route(
path = '/',
component = CounterPage
)
app = FletXApp(
title = "My Counter",
initial_route = "/",
debug = True
).with_window_size(400, 600).with_theme(
ft.Theme(color_scheme_seed=ft.Colors.BLUE)
)
# Run sync
app.run()
if __name__ == "__main__":
main()
class SearchController(FletXController):
"""Search controller"""
def __init__(self):
self.query = RxStr("")
self.results = RxList([])
self.is_enabled = RxBool(True)
super().__init__()
# Configure reactives effects
self._setup_reactive_effects()
def _setup_reactive_effects(self):
"""Configure reactive effects"""
# Search with debounce
@reactive_debounce(0.5)
@reactive_when(self.is_enabled)
def search_handler():
if self.query.value.strip():
self.perform_search(self.query.value)
# Listen query changes
self.query.listen(search_handler)
# Cache expensive search results
@reactive_memo(maxsize=50)
def expensive_search(query: str):
# Expensive search simulation
import time
time.sleep(0.1) # Simulate
return [f"Result {i} for '{query}'" for i in range(5)]
self.expensive_search = expensive_search
# Other actions here...
class NewsPage(FletXPage):
def __init__(self):
self.news_ctrl: NewsController = FletX.find(
NewsController, tag = 'news_ctrl'
)
super().__init__()
...
def build(self):
return ft.Text('Hello world!')
# Define routes
from fletx.navigation import router_config, navigate
# 1. simple routing
router_config.add_routes([
{"path": "/", "component": HomePage},
{"path": "/settings", "component": SettingsPage}
])
# 2. Dynamic routes with parameters
router_config.add_routes([
{
"path": "/users/:id",
"component": UserDetailPage
},
{
"path": "/products/*category",
"component": ProductsPage
}
])
# Navigate programmatically
navigate("/users/123")
class NewsService(FletXService):
"""News Service"""
def __init__(self, test_mode: bool = False, *args, **kwargs):
self.base_url = ""
self.max_per_page: int = 20
self.test_mode: bool = test_mode
self.newsapi = NewsApiClient(api_key = os.environ.get('NEWS_APIKEY'))
# Init base class
super().__init__(**kwargs)
# Register services
FletX.put(AuthService(), tag="auth")
# Retrieve anywhere
auth_service = FletX.find(AuthService, tag="auth")
FletX allows you to quickly create reactive widgets from flet Controls by using reactive widget decorators.
from fletx.decorators import (
reactive_control, simple_reactive,
reactive_state_machine, reactive_form,
two_way_reactive, reactive_list, obx
...
)
- Documentation π (draft)
- Discord Community π¬
- Issue Tracker π
- Examples Projects π
- Video Courses π₯
We welcome contributions from the community! Please see the CONTRIBUTING.md guide for more information.
MIT Β© 2025 AllDotPy
# Happy coding!
# Let's build amazing apps with Python π
Made with β€οΈ By AllDotPy