Skip to main content

· 6 min read
Feodor Fitsner

Flet makes writing dynamic, real-time web apps a real fun!

Flet 0.21.0 further improves web apps development experience as well as using asyncio APIs in your Flet apps.

Here's what's new in Flet 0.21.0:

FastAPI with Uvicorn replaces built-in web server

From very beginning of Flet life to serve web apps there was a built-in web server written in Go and called "Fletd". It's being started on the background when you run your app with flet run --web. Fletd was part of Flet Python wheel contributing a few megabytes to its size. Additionally, Python app was using WebSockets to talk to Fletd web server which was adding sometimes noticable overhead.

Then, in Flet 0.10.0 we have added FastAPI support to build "serious" web apps using AsyncIO API.

Now, in Flet 0.21.0 built-in web server has been completely removed and replaced with FastAPI and Uvicorn. Fletd is not a part of Flet distribution anymore.

Using FastAPI means there is no more communication overhead as web server is a part of Flet app. Also, you don't need to do any additional steps to host your app in production with FastAPI - you just use the same ft.app(main) command to run your app.

Breaking change

flet_fastapi package has been deprecated and its contents moved to flet package as flet.fastapi module. If you were using FastAPI in your Flet app replace:

import flet_fastapi

with

import flet.fastapi as flet_fastapi

Use any ASGI web server for hosting

You can host your Flet web app with any ASGI-compatible server such as Uvicorn (used by default), Hypercorn or Daphne.

Just tell Flet to export ASGI app:

main.py
import flet as ft

def main(page: ft.Page):
page.add(ft.Text("Hello ASGI!"))

app = ft.app(main, export_asgi_app=True)

and then run with Hypercorn as:

hypercorn main:app --bind 0.0.0.0:8000

Web app environment variables

Every aspect of web app hosting can be controlled with environment variables:

  • FLET_FORCE_WEB_SERVER - true to force running app as a web app. Automatically set on headless Linux hosts.
  • FLET_SERVER_PORT - TCP port to run app on. 8000 if the program is running on a Linux server or FLET_FORCE_WEB_SERVER is set; otherwise random port.
  • FLET_SERVER_IP - IP address to listen web app on, e.g. 127.0.0.1. Default is 0.0.0.0 - bound to all server IPs.
  • FLET_ASSETS_DIR - absolute path to app "assets" directory.
  • FLET_UPLOAD_DIR - absolute path to app "upload" directory.
  • FLET_MAX_UPLOAD_SIZE - max allowed size of uploaded file, in bytes. Unlimited if not specified.
  • FLET_SECRET_KEY - a secret key to sign temporary upload URLs.
  • FLET_WEB_APP_PATH - a URL path after domain name to host web app under, e.g. /apps/myapp. Default is / - host app in the root.
  • FLET_SESSION_TIMEOUT - session lifetime, in seconds. Default is 3600.
  • FLET_OAUTH_STATE_TIMEOUT - max allowed time to complete OAuth web flow, in seconds. Default is 600.
  • FLET_WEB_RENDERER - Flutter rendering mode: canvaskit (default), html or auto.
  • FLET_WEB_USE_COLOR_EMOJI - true, or True or 1 to load web font with colorful emojis.
  • FLET_WEB_ROUTE_URL_STRATEGY - path (default) or hash.
  • FLET_WEBSOCKET_HANDLER_ENDPOINT - custom path for WebSocket handler. Default is /ws.
  • FLET_UPLOAD_HANDLER_ENDPOINT - custom path for upload handler. Default is /upload.
  • FLET_OAUTH_CALLBACK_HANDLER_ENDPOINT - custom path for OAuth handler. Default is /oauth_callback.

Async-first framework

Flet is now async-first framework which means you don't have to decide whether your app is entirely sync or async, but you can mix both sync and async methods in the same app.

For example, in Flet 0.21.0 you can write an app like this:

import flet as ft
import time
import asyncio

def main(page: ft.Page):

def handler(e):
time.sleep(3)
page.add(ft.Text("Handler clicked"))

async def handler_async(e):
await asyncio.sleep(3)
page.add(ft.Text("Async handler clicked"))

page.add(
ft.ElevatedButton("Call handler", on_click=handler),
ft.ElevatedButton("Call async handler", on_click=handler_async)
)

ft.app(main)

In the example above a click on one button is handled by a "blocking" handler while a click on second button calls asynchronous handler. The first handler is run in a threading.Thread while second handler is run in asyncio.Task.

Also, notice in async def handler you are not required to use await page.add_async() anymore, but a regular page.add() works just fine.

API changes

Most of Page.<method>_async() and Control.<method>_async() methods have been deprecated and their Page.<method>() and Control.<method>() counterparts should be used instead.

The only exception here is methods returning results, like those ones in Audio control: you still have to use async methods in async event handlers.

Custom controls API normalized

In this Flet release we also re-visited API for writing custom controls in Python.

As a result UserControl class has been deprecated. You just inherit from a specific control with layout that works for your needs.

For example, Countdown custom control is just a Text and could be implemented as following:

import asyncio

import flet as ft

class Countdown(ft.Text):
def __init__(self, seconds):
super().__init__()
self.seconds = seconds

def did_mount(self):
self.running = True
self.page.run_task(self.update_timer)

def will_unmount(self):
self.running = False

async def update_timer(self):
while self.seconds and self.running:
mins, secs = divmod(self.seconds, 60)
self.value = "{:02d}:{:02d}".format(mins, secs)
self.update()
await asyncio.sleep(1)
self.seconds -= 1

def main(page: ft.Page):
page.add(Countdown(120), Countdown(60))

ft.app(main)

Notice the usage of self.page.run_task(self.update_timer) to start a new task. There is also self.page.run_thread() method that must be used by control developer to start a new background job in a thread.

If you want to spawn your own tasks or threads Flet provides the current event loop and thread executor via Page.loop and Page.executor properties respectively.

API changes

Control._before_build_command() replaced with Control.before_update()

Control.build() should not return any control now, but must update inherited control properties, for example:

def build():
self.controls.append(ft.Text("Something"))

Control.did_mount_async() and Control.will_unmount_async() are deprecated. Use Control.did_mount() and Control.will_unmount() instead.

New Cupertino controls

This Flet release adds more Cupertino controls to make your apps shine on iOS:

  • CupertinoActivityIndicator
  • CupertinoActionSheet
  • CupertinoSlidingSegmentedButton
  • CupertinoSegmentedButton
  • CupertinoTimerPicker
  • CupertinoPicker
  • CupertinoDatePicker
  • CupertinoContextMenu

Accessibility improvements

Now Flet has complete implementation of Semantics control and new SemanticsService control.

App lifecycle change event

There is a new Page.on_app_lifecycle_state_change event that allows listening for changes in the application lifecycle.

For example, you can now update UI with the latest information when the app becomes active (brought to the front). This event works on iOS, Android, all desktop platforms and web!

The following app lifecycle transitions are recognized:

  • SHOW
  • RESUME
  • HIDE
  • INACTIVE
  • PAUSE
  • DETACH
  • RESTART
note

Read more about each lifecycle state.

Here's a small example of how this event can be used:

import flet as ft

def main(page: ft.Page):

def app_lifecycle_change(e: ft.AppLifecycleStateChangeEvent):
if e.state == ft.AppLifecycleState.RESUME:
print("Update UI with fresh data!")

page.on_app_lifecycle_state_change = app_lifecycle_change
page.add(ft.Text("Hello World"))

ft.app(target=main)

Flet 0.21.0 release has some breaking changes. Upgrade to it, test your apps and let us know how it worked for you. Join Flet Discord server or create a new thread on Flet GitHub discussions.

Enjoy!

· 3 min read
Feodor Fitsner

🥰 Happy Valentine's Day lovely people! 🥰

We just released Flet 0.20.0 with the focus on:

  1. Adaptive UI.
  2. Extending Flet apps with 3rd-party Flutter packages.
  3. New controls: Video (yay!), AudioRecorder and a bunch of Cupertino-like controls. Flet now includes 97 built-in controls!
warning

Flet 0.20.0 includes a new Video control. While macOS and Windows already include all required media libraries to test Flet apps on Linux, the libmpv package must be installed. On Ubuntu/Debian in can be installed with:

sudo apt install libmpv-dev mpv

Adaptive UI

Adaptive controls allow writing apps with a single code base which look and behave differently depending on the platform they are running on.

To the date Flet provides 11 adaptive controls. To make control adaptive you should set its adaptive property to True.

In Flet 0.20.0 we introduce adaptive property to all container-alike controls. Setting adaptive=True on a container propagates this property to all child adaptive controls.

Page adds design property which enables granular control over controls design language and can have the following values: ft.PageDesign.ADAPTIVE, ft.PageDesign.MATERIAL or ft.PageDesign.CUPERTINO.

By setting just page.design = ft.PageDesign.ADAPTIVE you can make you app looking awesome on both iOS and Android devices:

iPhone

Android

Integrating existing Flutter packages

Today Flet offers almost 100 controls, but, as you can imagine, not every Flutter library/widget could be added to the core Flet library and Flet team couldn't do that alone in the acceptable timeframe.

At the same time we do not want to put early adopters, who chose Flet to build their next commercial or corporate app, into a situation where their progress depends on Flet team availability and desire to implement a Flutter control they need.

In Flet 0.20.0 we re-factored Flutter core packages and identified the API that can be used by 3rd-party developers to add their own Flet controls written in Dart.

We are currently working on API docs, but you can learn now how custom Flutter packages are implemented by looking at Dart sources for Video, and Audio controls.

In short, you have to create a new Flutter package which implements and exports two methods:

void ensureInitialized();
Widget createControl(CreateControlArgs args);

See ensureInitialized() and createControl() implementations for Video control.

On Python side you create a new class inherited from Control (non-visual or overlay controls) or ConstrainedControl.

See Video class implementation in Python.

To integrate a custom Flutter package while building your Flet app with flet build command you can list extra packages with either --include-packages option or in pubspec.yaml file put into root of your Flet app.

Video control

Video control is implemented in a separate Flutter package.

To build your Flet app with Video control add --include-packages flet_video to your flet build command, for example:

flet build apk --include-packages flet_video

Flet 0.20.0 is a relatively "large" release and could break some things.

Upgrade to Flet 0.20.0, test your apps and let us know what you think by joining Flet Discord server or creating a new thread on Flet GitHub discussions.

Enjoy!

· 3 min read
Feodor Fitsner

Dear friends! In the final post of this year I would like to thank you all for your contributions to Flet project whether it's spreading a word, submitting pull request, joining Discord discussion or a even sending an annoying bug report!

With your fantastic support we achieved a lot in year 2023:

  • 70+ controls (special thanks to @ndonkoHenri for his tremendous contibution).
  • 7,700 stars on GitHub.
  • 2,150 users with community moderators (thank you guys!) on Discord.
  • Flet integration with Pyodide for pure client-side Python apps - no other frameworks provide a better UI for Pyodide!
  • Flet app in AppStore and Google Play - great way to test on mobile devices and real proof of Flet apps being accepted in stores.
  • ...and finally... drum roll...🥁🥁🥁 flet build command is here! 🎉🎉🎉

🎄 "New Year" 🎄 edition of Flet 0.18.0 has been just released which allows packaging your Flet apps for distribution on all platforms: iOS, Android, Web, macOS, Windows and Linux!

The one command to rule them all!

The full circle is now closed: you can create (flet create), run (flet run) and build (flet build) your Flet apps with Flet CLI.

Flet CLI provides flet build command that allows packaging Flet app into a standalone executable or install package for distribution.

flet build command supersedes both flet pack (packaging into desktop app) and flet publish (packaging into a static website) commands and allows converting your Flet app into Android or iOS bundle, desktop app and a static website.

For building desktop apps flet build does not longer rely on PyInstaller like flet pack does, but uses Flutter SDK to produce a fast, offline, fully customizable (your own icons, about dialog and metadata) executable for Windows, Linux and macOS with Python runtime embedded into executable and running in-process.

Static websites built with flet build, compared to flet publish, have faster load time as all Python dependencies are now packaged into a single archive instead of being pulled in runtime with micropip. flet build web also detects native Python packages built into Pyodide, such as bcrypt, html5lib, numpy and many others, and installs them from Pyodide package registry.

Check Packaging app for distribution guide for complete information about flet build command.

Let us know what you think by joining Flet Discord server or creating a new thread on Flet GitHub discussions.

We wish you Happy New Year! Enjoy your holidays!

· 2 min read
Feodor Fitsner

We've just released Flet 0.10.0 with FastAPI support!

FastAPI coupled with Uvicorn, Hypercorn, Gunicorn or other web server replaces built-in Flet web server (Fletd) to reliably run production Flet workloads.

On the other hand, seasoned FastAPI developers can use Flet to easily add interactive, real-time dashboards and admin UI to their existing or new FastAPI services.

A minimal app example

import flet as ft
import flet_fastapi

async def main(page: ft.Page):
await page.add_async(
ft.Text("Hello, Flet!")
)

app = flet_fastapi.app(main)

It's a simple app that just outputs "Hello, Flet!" on a web page.

To run the app install Flet for FastAPI and Uvicorn:

pip install flet-fastapi
pip install uvicorn

Save the code above to hello.py and then start uvicorn as:

uvicorn hello:app

Open the browser and navigate to http://127.0.0.1:8000 to see the app running.

note

Flet app must be async in order to work with FastAPI WebSocket handler.

Features and benefits

Check the guide for complete information about Flet with FastAPI.

Let us know what you think by joining Flet Discord server or creating a new thread on Flet GitHub discussions.

· 2 min read
Feodor Fitsner

🤖 Android support is here!

With Flet Android app you can see how your Flet Python app looks and behaves on Android devices while the app itself is running on your computer.

Similar to iOS, Flet for Android is a Flutter app written entirely in Python with the help of two open-source packages: serious_python and flet. Resulting app package is technically compliant with Google Play requirements, so you can publish awesome Android apps in pure Python.

Follow this guide to get started with testing your Flet apps on Android. Explore the app, browse gallery, play with sample projects and app settings.

FAQ

How to package my Flet app for Google Play?

We are going to provide a project template for bootstrap Flutter app and a guide how to combine Flutter, serious_python package and your Python app together to create a standalone Android app and publish it to Google Play.

Check serious_python's readme for instructions on how create a Flutter bootstrap and package your Python app to run within it. Use flet_example project as a starting point.

Will you provide packaging for Windows, macOS and Linux?

Yes! At the moment Flet desktop apps are packaged with flet pack command and PyInstaller. Produced app bundle adds performance and size overhead and is hard to customize, so we are going to replace it with native Flutter packaging.

Flet v0.9.0 release notes

For testing on Android you need to upgrade your Flet installation to v0.9.0.

There were a few changes mainly to support Android in Flet CLI. Let us know if you notice something unusual.

Enjoy!