flet-cli 1.0.0.dev2__tar.gz → 1.0.2__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.
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/PKG-INFO +7 -3
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/README.md +4 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/pyproject.toml +3 -3
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/cli.py +66 -12
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/build.py +3 -5
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/build_base.py +145 -74
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/debug.py +2 -0
- flet_cli-1.0.2/src/flet_cli/commands/options.py +78 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/pack.py +8 -2
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/publish.py +1 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/run.py +18 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/test.py +5 -3
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/android_sdk.py +26 -37
- flet_cli-1.0.2/src/flet_cli/utils/app_excludes.py +117 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/processes.py +19 -1
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/python_versions.py +1 -1
- flet_cli-1.0.2/src/flet_cli/version.py +1 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli.egg-info/PKG-INFO +7 -3
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli.egg-info/SOURCES.txt +7 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli.egg-info/requires.txt +2 -2
- flet_cli-1.0.2/tests/test_app_excludes.py +197 -0
- flet_cli-1.0.2/tests/test_build_app_path.py +119 -0
- flet_cli-1.0.2/tests/test_build_list_options.py +45 -0
- flet_cli-1.0.2/tests/test_build_platform_settings.py +77 -0
- flet_cli-1.0.2/tests/test_cli_pass_through_args.py +235 -0
- flet_cli-1.0.2/tests/test_cli_positionals.py +141 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_run_script_args.py +3 -3
- flet_cli-1.0.0.dev2/src/flet_cli/commands/options.py +0 -42
- flet_cli-1.0.0.dev2/src/flet_cli/version.py +0 -1
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/setup.cfg +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/__pyinstaller/__init__.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/__pyinstaller/config.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/__pyinstaller/hook-flet.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/__pyinstaller/macos_utils.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/__pyinstaller/rthooks.dat +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/__pyinstaller/utils.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/__pyinstaller/win_utils.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/base.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/clean.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/create.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/devices.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/doctor.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/emulators.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/flutter_base.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/mcp.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/serve.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/commands/test_host.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/android.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/cli.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/distros.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/flutter.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/hash_stamp.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/ios_sign.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/jdk.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/linux_deps.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/macos_sign.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/merge.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/plist.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/project_dependencies.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/pyodide.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/pyproject_toml.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli/utils/template_cache.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli.egg-info/dependency_links.txt +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli.egg-info/entry_points.txt +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/src/flet_cli.egg-info/top_level.txt +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_build_icons.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_build_ios.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_build_linux.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_build_macos_signing.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_build_splash.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_build_template.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_clean.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_create.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_find_platform_image.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_flutter.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_macos_sign.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_plist.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_project_dependencies.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_python_versions.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_run_assets_dir.py +0 -0
- {flet_cli-1.0.0.dev2 → flet_cli-1.0.2}/tests/test_run_desktop_dependency.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Flet CLI
|
|
5
5
|
Author-email: "Appveyor Systems Inc." <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,8 +9,8 @@ Project-URL: Repository, https://github.com/flet-dev/flet
|
|
|
9
9
|
Project-URL: Documentation, https://flet.dev/docs
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
-
Requires-Dist: flet==1.0.
|
|
13
|
-
Requires-Dist: flet-platform-assets==1.0.
|
|
12
|
+
Requires-Dist: flet==1.0.2
|
|
13
|
+
Requires-Dist: flet-platform-assets==1.0.2
|
|
14
14
|
Requires-Dist: watchdog>=4.0.0
|
|
15
15
|
Requires-Dist: packaging>=25.0
|
|
16
16
|
Requires-Dist: qrcode>=7.4.2
|
|
@@ -29,6 +29,10 @@ Requires-Dist: flet-mcp; extra == "mcp"
|
|
|
29
29
|
|
|
30
30
|
Flet CLI is a command-line interface tool for Flet, a framework for building interactive multi-platform applications using Python.
|
|
31
31
|
|
|
32
|
+
> **[Try Flet online in Flet Studio](https://studio.flet.dev)**
|
|
33
|
+
>
|
|
34
|
+
> Try an idea in your browser with no installation, then use the Flet CLI locally to develop and package your app. Write your own Python code or get help from the AI agent.
|
|
35
|
+
|
|
32
36
|
## Features
|
|
33
37
|
|
|
34
38
|
- Create new Flet projects
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
Flet CLI is a command-line interface tool for Flet, a framework for building interactive multi-platform applications using Python.
|
|
7
7
|
|
|
8
|
+
> **[Try Flet online in Flet Studio](https://studio.flet.dev)**
|
|
9
|
+
>
|
|
10
|
+
> Try an idea in your browser with no installation, then use the Flet CLI locally to develop and package your app. Write your own Python code or get help from the AI agent.
|
|
11
|
+
|
|
8
12
|
## Features
|
|
9
13
|
|
|
10
14
|
- Create new Flet projects
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flet-cli"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.2"
|
|
4
4
|
description = "Flet CLI"
|
|
5
5
|
authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }]
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
|
-
"flet==1.0.
|
|
11
|
-
"flet-platform-assets==1.0.
|
|
10
|
+
"flet==1.0.2",
|
|
11
|
+
"flet-platform-assets==1.0.2",
|
|
12
12
|
"watchdog >=4.0.0",
|
|
13
13
|
"packaging >=25.0",
|
|
14
14
|
"qrcode >=7.4.2",
|
|
@@ -41,6 +41,34 @@ def _render_version(as_json: bool) -> str:
|
|
|
41
41
|
return f"Flet: {flet.version.flet_version}\nFlutter: {flet.version.flutter_version}"
|
|
42
42
|
|
|
43
43
|
|
|
44
|
+
class _PositionalsFixArgumentParser(argparse.ArgumentParser):
|
|
45
|
+
"""
|
|
46
|
+
An `argparse.ArgumentParser` with the fix for CPython gh-59317 backported.
|
|
47
|
+
|
|
48
|
+
Before Python 3.12.7 and 3.13.1, `argparse` gives an optional positional its
|
|
49
|
+
default as soon as the positionals typed before an option run out, so one
|
|
50
|
+
typed after the option is rejected. `get_parser()` uses this class only on
|
|
51
|
+
those interpreters, and subparsers inherit it through `add_subparsers()`.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def _match_arguments_partial(self, actions, arg_strings_pattern):
|
|
55
|
+
"""
|
|
56
|
+
Match positionals as Python 3.12.7+ and 3.13.1+ do: when the typed
|
|
57
|
+
positionals end at an option, the trailing positionals that matched
|
|
58
|
+
nothing are left unfilled, so positionals after the option can fill them.
|
|
59
|
+
|
|
60
|
+
The matched counts add up to the length of the matched pattern, so the
|
|
61
|
+
result is unchanged on interpreters whose `argparse` already does this.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
result = super()._match_arguments_partial(actions, arg_strings_pattern)
|
|
65
|
+
matched = sum(result)
|
|
66
|
+
if matched < len(arg_strings_pattern) and arg_strings_pattern[matched] == "O":
|
|
67
|
+
while result and not result[-1]:
|
|
68
|
+
result.pop()
|
|
69
|
+
return result
|
|
70
|
+
|
|
71
|
+
|
|
44
72
|
# Source https://stackoverflow.com/a/26379693
|
|
45
73
|
def set_default_subparser(
|
|
46
74
|
parser: argparse.ArgumentParser, name: str, args: list
|
|
@@ -88,9 +116,11 @@ def set_default_subparser(
|
|
|
88
116
|
|
|
89
117
|
def get_parser() -> argparse.ArgumentParser:
|
|
90
118
|
"""Construct and return the CLI argument parser."""
|
|
91
|
-
parser =
|
|
92
|
-
|
|
93
|
-
|
|
119
|
+
parser = (
|
|
120
|
+
_PositionalsFixArgumentParser
|
|
121
|
+
if sys.version_info < (3, 12, 7) or sys.version_info[:3] == (3, 13, 0)
|
|
122
|
+
else argparse.ArgumentParser
|
|
123
|
+
)(formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
94
124
|
|
|
95
125
|
# add version flags
|
|
96
126
|
parser.add_argument(
|
|
@@ -138,9 +168,11 @@ def split_script_args(argv: list) -> tuple[list, Optional[list]]:
|
|
|
138
168
|
"""
|
|
139
169
|
Split a command line at the first bare `--` separator.
|
|
140
170
|
|
|
141
|
-
Everything after the separator is meant for the
|
|
171
|
+
Everything after the separator is meant for the program the command runs -
|
|
172
|
+
the app script of `flet run`, pytest for `flet test`, Flutter for
|
|
173
|
+
`flet build` and `flet debug`, or PyInstaller for `flet pack` - not for Flet
|
|
142
174
|
itself, so it must be removed before the parser (and `set_default_subparser`)
|
|
143
|
-
sees it
|
|
175
|
+
sees it. Otherwise `flet run app.py -- --web` would be read as Flet's own
|
|
144
176
|
`--web` option, and `flet app.py -- build` would suppress the default `run`
|
|
145
177
|
subcommand.
|
|
146
178
|
|
|
@@ -169,10 +201,14 @@ def parse_command_line(argv: list) -> argparse.Namespace:
|
|
|
169
201
|
|
|
170
202
|
Returns:
|
|
171
203
|
The parsed arguments. For `flet run`, `script_args` holds the arguments
|
|
172
|
-
to forward to the app script
|
|
204
|
+
to forward to the app script, for `flet test`, `pytest_args` holds the
|
|
205
|
+
arguments to pass to pytest, for `flet build` and `flet debug`,
|
|
206
|
+
`flutter_build_args` holds the arguments to pass to Flutter, and for
|
|
207
|
+
`flet pack`, `pyinstaller_build_args` holds the arguments to pass to
|
|
208
|
+
PyInstaller.
|
|
173
209
|
"""
|
|
174
210
|
|
|
175
|
-
# pull off
|
|
211
|
+
# pull off arguments meant for the program the command runs before parser sees them
|
|
176
212
|
argv, script_args = split_script_args(argv)
|
|
177
213
|
|
|
178
214
|
parser = get_parser()
|
|
@@ -195,14 +231,32 @@ def parse_command_line(argv: list) -> argparse.Namespace:
|
|
|
195
231
|
)
|
|
196
232
|
parser.error(message)
|
|
197
233
|
|
|
198
|
-
# forward the arguments that followed `--` to the
|
|
234
|
+
# forward the arguments that followed `--` to the program the command runs
|
|
199
235
|
if script_args is not None:
|
|
200
|
-
|
|
236
|
+
command = getattr(args, "command", None)
|
|
237
|
+
if command == "run":
|
|
238
|
+
args.script_args = list(args.script_args) + script_args
|
|
239
|
+
elif command == "test":
|
|
240
|
+
args.pytest_args = script_args
|
|
241
|
+
elif command in ("build", "debug"):
|
|
242
|
+
if script_args:
|
|
243
|
+
args.flutter_build_args = [
|
|
244
|
+
*(args.flutter_build_args or []),
|
|
245
|
+
script_args,
|
|
246
|
+
]
|
|
247
|
+
elif command == "pack":
|
|
248
|
+
if script_args:
|
|
249
|
+
args.pyinstaller_build_args = [
|
|
250
|
+
*(args.pyinstaller_build_args or []),
|
|
251
|
+
script_args,
|
|
252
|
+
]
|
|
253
|
+
else:
|
|
201
254
|
parser.error(
|
|
202
|
-
"the `--` separator is only supported by
|
|
203
|
-
"the arguments that follow it
|
|
255
|
+
"the `--` separator is only supported by commands that run "
|
|
256
|
+
"another program, which receives the arguments that follow it: "
|
|
257
|
+
"`flet run` (the app script), `flet test` (pytest), `flet build` "
|
|
258
|
+
"and `flet debug` (Flutter), and `flet pack` (PyInstaller)"
|
|
204
259
|
)
|
|
205
|
-
args.script_args = list(args.script_args) + script_args
|
|
206
260
|
|
|
207
261
|
return args
|
|
208
262
|
|
|
@@ -43,6 +43,8 @@ class Command(BaseBuildCommand):
|
|
|
43
43
|
Android (APK/AAB), and iOS (IPA and simulator .app), with a wide range of
|
|
44
44
|
customization options for metadata, assets, splash screens, and signing.
|
|
45
45
|
|
|
46
|
+
Arguments after `--` are passed down to the underlying `flutter build`.
|
|
47
|
+
|
|
46
48
|
Detailed usage guide: https://flet.dev/docs/publish
|
|
47
49
|
"""
|
|
48
50
|
|
|
@@ -206,11 +208,7 @@ class Command(BaseBuildCommand):
|
|
|
206
208
|
if build_version:
|
|
207
209
|
args.extend(["--build-name", build_version])
|
|
208
210
|
|
|
209
|
-
for arg in (
|
|
210
|
-
self.get_pyproject(f"tool.flet.{self.config_platform}.flutter.build_args")
|
|
211
|
-
or self.get_pyproject("tool.flet.flutter.build_args")
|
|
212
|
-
or []
|
|
213
|
-
):
|
|
211
|
+
for arg in self.get_platform_setting("flutter.build_args", []):
|
|
214
212
|
args.append(arg)
|
|
215
213
|
|
|
216
214
|
def run_flutter(self):
|
|
@@ -28,6 +28,7 @@ from flet_platform_assets import (
|
|
|
28
28
|
write,
|
|
29
29
|
)
|
|
30
30
|
from packaging.requirements import Requirement
|
|
31
|
+
from rich.markup import escape
|
|
31
32
|
from rich.panel import Panel
|
|
32
33
|
from rich.table import Column, Table
|
|
33
34
|
|
|
@@ -42,10 +43,12 @@ from flet_cli.commands.flutter_base import (
|
|
|
42
43
|
verbose2_style,
|
|
43
44
|
warning_style,
|
|
44
45
|
)
|
|
46
|
+
from flet_cli.commands.options import PassThroughArgsAction
|
|
45
47
|
from flet_cli.utils.android import (
|
|
46
48
|
ANDROID_ARCH_TO_FLUTTER_TARGET_PLATFORM,
|
|
47
49
|
excluded_android_abis,
|
|
48
50
|
)
|
|
51
|
+
from flet_cli.utils.app_excludes import find_default_excludes
|
|
49
52
|
from flet_cli.utils.cli import parse_cli_bool_value
|
|
50
53
|
from flet_cli.utils.hash_stamp import HashStamp
|
|
51
54
|
from flet_cli.utils.merge import merge_dict
|
|
@@ -358,6 +361,23 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
358
361
|
help="Files and/or directories to exclude from the package"
|
|
359
362
|
"; can be used multiple times",
|
|
360
363
|
)
|
|
364
|
+
parser.add_argument(
|
|
365
|
+
"--include",
|
|
366
|
+
dest="include",
|
|
367
|
+
action="extend",
|
|
368
|
+
nargs="+",
|
|
369
|
+
default=[],
|
|
370
|
+
help="Files and/or directories excluded by default to package anyway "
|
|
371
|
+
"(e.g. `.env`); can be used multiple times",
|
|
372
|
+
)
|
|
373
|
+
parser.add_argument(
|
|
374
|
+
"--no-default-excludes",
|
|
375
|
+
dest="default_excludes",
|
|
376
|
+
action="store_false",
|
|
377
|
+
default=None,
|
|
378
|
+
help="Package hidden top-level files and directories, virtual "
|
|
379
|
+
"environments and `__pycache__` directories instead of excluding them",
|
|
380
|
+
)
|
|
361
381
|
parser.add_argument(
|
|
362
382
|
"--project",
|
|
363
383
|
dest="project_name",
|
|
@@ -619,9 +639,12 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
619
639
|
parser.add_argument(
|
|
620
640
|
"--flutter-build-args",
|
|
621
641
|
dest="flutter_build_args",
|
|
622
|
-
action=
|
|
642
|
+
action=PassThroughArgsAction,
|
|
643
|
+
example="--obfuscate",
|
|
623
644
|
nargs="*",
|
|
624
|
-
help="Additional arguments for flutter build command"
|
|
645
|
+
help="Additional arguments for flutter build command. Attach an "
|
|
646
|
+
"argument that starts with `-` using `=`, e.g. "
|
|
647
|
+
"`--flutter-build-args=--obfuscate`, or pass the arguments after `--`",
|
|
625
648
|
)
|
|
626
649
|
parser.add_argument(
|
|
627
650
|
"--source-packages",
|
|
@@ -634,6 +657,7 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
634
657
|
parser.add_argument(
|
|
635
658
|
"--android-extract-packages",
|
|
636
659
|
dest="android_extract_packages",
|
|
660
|
+
action="extend",
|
|
637
661
|
nargs="+",
|
|
638
662
|
default=[],
|
|
639
663
|
help="Android only: Python packages (relative paths) to ship extracted "
|
|
@@ -860,19 +884,25 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
860
884
|
self.config_platform = self.platforms[self.target_platform]["config_platform"]
|
|
861
885
|
self.require_android_sdk = self.package_platform == "Android"
|
|
862
886
|
|
|
863
|
-
super().initialize_command()
|
|
864
|
-
|
|
865
887
|
self.python_app_path = Path(self.options.python_app_path).resolve()
|
|
866
888
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
889
|
+
# validate that the app path exists and is a directory, not a file
|
|
890
|
+
if not os.path.isdir(self.python_app_path):
|
|
891
|
+
self.skip_flutter_doctor = True
|
|
892
|
+
if os.path.isfile(self.python_app_path):
|
|
893
|
+
self.cleanup(
|
|
894
|
+
1,
|
|
895
|
+
f"Path to Flet app must be a directory, not a file: "
|
|
896
|
+
f"{escape(str(self.python_app_path))}",
|
|
897
|
+
)
|
|
870
898
|
self.cleanup(
|
|
871
899
|
1,
|
|
872
900
|
f"Path to Flet app does not exist or is not a directory: "
|
|
873
|
-
f"{self.python_app_path}",
|
|
901
|
+
f"{escape(str(self.python_app_path))}",
|
|
874
902
|
)
|
|
875
903
|
|
|
904
|
+
super().initialize_command()
|
|
905
|
+
|
|
876
906
|
self.rel_out_dir = self.options.output_dir or os.path.join(
|
|
877
907
|
"build", self.platforms[self.target_platform]["dist"]
|
|
878
908
|
)
|
|
@@ -1366,10 +1396,8 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
1366
1396
|
deep_linking_scheme = self.options.deep_linking_scheme
|
|
1367
1397
|
deep_linking_host = self.options.deep_linking_host
|
|
1368
1398
|
|
|
1369
|
-
target_arch = (
|
|
1370
|
-
|
|
1371
|
-
or self.get_pyproject(f"tool.flet.{self.config_platform}.target_arch")
|
|
1372
|
-
or self.get_pyproject("tool.flet.target_arch")
|
|
1399
|
+
target_arch = self.options.target_arch or self.get_platform_setting(
|
|
1400
|
+
"target_arch"
|
|
1373
1401
|
)
|
|
1374
1402
|
target_arch = (
|
|
1375
1403
|
target_arch
|
|
@@ -2532,11 +2560,7 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2532
2560
|
|
|
2533
2561
|
dev_packages_configured = False
|
|
2534
2562
|
if len(toml_dependencies) > 0:
|
|
2535
|
-
dev_packages = (
|
|
2536
|
-
self.get_pyproject(f"tool.flet.{self.config_platform}.dev_packages")
|
|
2537
|
-
or self.get_pyproject("tool.flet.dev_packages")
|
|
2538
|
-
or []
|
|
2539
|
-
)
|
|
2563
|
+
dev_packages = self.get_platform_setting("dev_packages", {})
|
|
2540
2564
|
if len(dev_packages) > 0:
|
|
2541
2565
|
for i in range(0, len(toml_dependencies)):
|
|
2542
2566
|
package_name = Requirement(toml_dependencies[i]).name
|
|
@@ -2616,25 +2640,63 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2616
2640
|
)
|
|
2617
2641
|
|
|
2618
2642
|
# exclude
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
app_exclude = (
|
|
2622
|
-
self.options.exclude
|
|
2623
|
-
or self.get_pyproject(f"tool.flet.{self.config_platform}.app.exclude")
|
|
2624
|
-
or self.get_pyproject("tool.flet.app.exclude")
|
|
2643
|
+
app_exclude = self.options.exclude or self.get_platform_setting(
|
|
2644
|
+
"app.exclude", []
|
|
2625
2645
|
)
|
|
2626
|
-
|
|
2627
|
-
|
|
2646
|
+
explicit_excludes = [
|
|
2647
|
+
"build",
|
|
2648
|
+
*app_exclude,
|
|
2649
|
+
*(["assets"] if self.target_platform == "web" else []),
|
|
2650
|
+
]
|
|
2628
2651
|
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2652
|
+
default_excludes: list[str] = []
|
|
2653
|
+
if self.get_bool_setting(
|
|
2654
|
+
self.options.default_excludes, "app.default_excludes", True
|
|
2655
|
+
):
|
|
2656
|
+
app_include = self.options.include or self.get_platform_setting(
|
|
2657
|
+
"app.include", []
|
|
2658
|
+
)
|
|
2659
|
+
default_excludes = find_default_excludes(
|
|
2660
|
+
self.package_app_path, app_include, explicit_excludes
|
|
2661
|
+
)
|
|
2662
|
+
|
|
2663
|
+
exclude_list = list(dict.fromkeys(explicit_excludes + default_excludes))
|
|
2664
|
+
# one flag per path: serious_python (>= 5.0.0) doesn't split values on
|
|
2665
|
+
# commas, so paths containing `,` survive
|
|
2666
|
+
for path in exclude_list:
|
|
2667
|
+
package_args.extend(["--exclude", path])
|
|
2668
|
+
|
|
2669
|
+
if default_excludes:
|
|
2670
|
+
console.log(
|
|
2671
|
+
"Excluded from app package by default: "
|
|
2672
|
+
f"{', '.join(default_excludes)} "
|
|
2673
|
+
"(use --include <path> or --no-default-excludes to package them)",
|
|
2674
|
+
markup=False,
|
|
2675
|
+
)
|
|
2676
|
+
env_files = [
|
|
2677
|
+
p for p in default_excludes if p == ".env" or p.startswith(".env.")
|
|
2678
|
+
]
|
|
2679
|
+
if env_files:
|
|
2680
|
+
it = "it" if len(env_files) == 1 else "them"
|
|
2681
|
+
console.log(
|
|
2682
|
+
f"Warning: {', '.join(env_files)} not packaged. If the app "
|
|
2683
|
+
f"loads {it} at runtime (e.g. with python-dotenv), package "
|
|
2684
|
+
f"{it} with `--include {' '.join(env_files)}` or "
|
|
2685
|
+
f"`include = {json.dumps(env_files)}` under [tool.flet.app] "
|
|
2686
|
+
"in pyproject.toml.",
|
|
2687
|
+
style=warning_style,
|
|
2688
|
+
markup=False,
|
|
2689
|
+
)
|
|
2690
|
+
if self.verbose > 0:
|
|
2691
|
+
console.log(
|
|
2692
|
+
f"App package exclude list: {exclude_list}",
|
|
2693
|
+
style=verbose1_style,
|
|
2694
|
+
markup=False,
|
|
2695
|
+
)
|
|
2632
2696
|
|
|
2633
2697
|
# source-packages
|
|
2634
|
-
source_packages = (
|
|
2635
|
-
|
|
2636
|
-
or self.get_pyproject(f"tool.flet.{self.config_platform}.source_packages")
|
|
2637
|
-
or self.get_pyproject("tool.flet.source_packages")
|
|
2698
|
+
source_packages = self.options.source_packages or self.get_platform_setting(
|
|
2699
|
+
"source_packages"
|
|
2638
2700
|
)
|
|
2639
2701
|
if source_packages:
|
|
2640
2702
|
package_env["SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS"] = ",".join(
|
|
@@ -2651,11 +2713,7 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2651
2713
|
if self.package_platform == "Android":
|
|
2652
2714
|
user_extract_packages = (
|
|
2653
2715
|
self.options.android_extract_packages
|
|
2654
|
-
or self.
|
|
2655
|
-
f"tool.flet.{self.config_platform}.extract_packages"
|
|
2656
|
-
)
|
|
2657
|
-
or self.get_pyproject("tool.flet.extract_packages")
|
|
2658
|
-
or []
|
|
2716
|
+
or self.get_platform_setting("extract_packages", [])
|
|
2659
2717
|
)
|
|
2660
2718
|
self.android_extract_packages = list(
|
|
2661
2719
|
dict.fromkeys(ANDROID_DEFAULT_EXTRACT_PACKAGES + user_extract_packages)
|
|
@@ -2678,42 +2736,34 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2678
2736
|
|
|
2679
2737
|
if cleanup_app_files := (
|
|
2680
2738
|
self.options.cleanup_app_files
|
|
2681
|
-
or self.
|
|
2682
|
-
or self.get_pyproject("tool.flet.cleanup.app_files")
|
|
2739
|
+
or self.get_platform_setting("cleanup.app_files")
|
|
2683
2740
|
):
|
|
2684
2741
|
if isinstance(cleanup_app_files, str):
|
|
2685
2742
|
cleanup_app_files = [
|
|
2686
2743
|
value.strip() for value in cleanup_app_files.split(",")
|
|
2687
2744
|
]
|
|
2688
2745
|
if isinstance(cleanup_app_files, list):
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
)
|
|
2746
|
+
for glob_pattern in cleanup_app_files:
|
|
2747
|
+
if glob_pattern.strip():
|
|
2748
|
+
package_args.extend(
|
|
2749
|
+
["--cleanup-app-files", glob_pattern.strip()]
|
|
2750
|
+
)
|
|
2695
2751
|
cleanup_app = True
|
|
2696
2752
|
|
|
2697
2753
|
if cleanup_package_files := (
|
|
2698
2754
|
self.options.cleanup_package_files
|
|
2699
|
-
or self.
|
|
2700
|
-
f"tool.flet.{self.config_platform}.cleanup.package_files"
|
|
2701
|
-
)
|
|
2702
|
-
or self.get_pyproject("tool.flet.cleanup.package_files")
|
|
2755
|
+
or self.get_platform_setting("cleanup.package_files")
|
|
2703
2756
|
):
|
|
2704
2757
|
if isinstance(cleanup_package_files, str):
|
|
2705
2758
|
cleanup_package_files = [
|
|
2706
2759
|
value for value in cleanup_package_files.split(",")
|
|
2707
2760
|
]
|
|
2708
2761
|
if isinstance(cleanup_package_files, list):
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
),
|
|
2715
|
-
]
|
|
2716
|
-
)
|
|
2762
|
+
for glob_pattern in cleanup_package_files:
|
|
2763
|
+
if glob_pattern.strip():
|
|
2764
|
+
package_args.extend(
|
|
2765
|
+
["--cleanup-package-files", glob_pattern.strip()]
|
|
2766
|
+
)
|
|
2717
2767
|
cleanup_packages = True
|
|
2718
2768
|
|
|
2719
2769
|
if cleanup_app:
|
|
@@ -2722,6 +2772,15 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2722
2772
|
if cleanup_packages:
|
|
2723
2773
|
package_args.append("--cleanup-packages")
|
|
2724
2774
|
|
|
2775
|
+
if self.verbose > 0:
|
|
2776
|
+
console.log(
|
|
2777
|
+
f"Compile app: {'--compile-app' in package_args}, "
|
|
2778
|
+
f"cleanup app: {cleanup_app}, cleanup packages: {cleanup_packages} "
|
|
2779
|
+
"(cleanup removes serious_python's default junk globs plus any "
|
|
2780
|
+
"--cleanup-app-files/--cleanup-package-files)",
|
|
2781
|
+
style=verbose1_style,
|
|
2782
|
+
)
|
|
2783
|
+
|
|
2725
2784
|
if self.verbose > 1:
|
|
2726
2785
|
package_args.append("--verbose")
|
|
2727
2786
|
|
|
@@ -2840,24 +2899,39 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2840
2899
|
Resolved boolean-like setting value.
|
|
2841
2900
|
"""
|
|
2842
2901
|
|
|
2843
|
-
assert self.get_pyproject
|
|
2844
2902
|
return (
|
|
2845
2903
|
cli_option
|
|
2846
2904
|
if cli_option is not None
|
|
2847
|
-
else (
|
|
2848
|
-
self.get_pyproject(f"tool.flet.{self.config_platform}.{pyproj_setting}")
|
|
2849
|
-
if self.get_pyproject(
|
|
2850
|
-
f"tool.flet.{self.config_platform}.{pyproj_setting}"
|
|
2851
|
-
)
|
|
2852
|
-
is not None
|
|
2853
|
-
else (
|
|
2854
|
-
self.get_pyproject(f"tool.flet.{pyproj_setting}")
|
|
2855
|
-
if self.get_pyproject(f"tool.flet.{pyproj_setting}") is not None
|
|
2856
|
-
else default_value
|
|
2857
|
-
)
|
|
2858
|
-
)
|
|
2905
|
+
else self.get_platform_setting(pyproj_setting, default_value)
|
|
2859
2906
|
)
|
|
2860
2907
|
|
|
2908
|
+
def get_platform_setting(self, pyproj_setting, default_value=None):
|
|
2909
|
+
"""
|
|
2910
|
+
Resolve a pyproject setting with precedence: platform, global, default.
|
|
2911
|
+
|
|
2912
|
+
The platform value wins whenever it is set, even when it is empty, so
|
|
2913
|
+
`[]` or `{}` under `tool.flet.<platform>.` clears a global list or table
|
|
2914
|
+
for that platform.
|
|
2915
|
+
|
|
2916
|
+
Args:
|
|
2917
|
+
pyproj_setting: Relative key under `tool.flet.<platform>.` and
|
|
2918
|
+
`tool.flet.`.
|
|
2919
|
+
default_value: Fallback value when neither key is defined.
|
|
2920
|
+
|
|
2921
|
+
Returns:
|
|
2922
|
+
Resolved setting value.
|
|
2923
|
+
"""
|
|
2924
|
+
|
|
2925
|
+
assert self.get_pyproject
|
|
2926
|
+
for key in (
|
|
2927
|
+
f"tool.flet.{self.config_platform}.{pyproj_setting}",
|
|
2928
|
+
f"tool.flet.{pyproj_setting}",
|
|
2929
|
+
):
|
|
2930
|
+
value = self.get_pyproject(key)
|
|
2931
|
+
if value is not None:
|
|
2932
|
+
return value
|
|
2933
|
+
return default_value
|
|
2934
|
+
|
|
2861
2935
|
def add_flutter_command_args(self, args: list[str]):
|
|
2862
2936
|
"""
|
|
2863
2937
|
Hook for subclasses to append command-specific Flutter arguments.
|
|
@@ -3001,10 +3075,7 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
3001
3075
|
|
|
3002
3076
|
flutter_build_args = (
|
|
3003
3077
|
self.options.flutter_build_args
|
|
3004
|
-
or self.
|
|
3005
|
-
f"tool.flet.{self.config_platform}.flutter.build_args"
|
|
3006
|
-
)
|
|
3007
|
-
or self.get_pyproject("tool.flet.flutter.build_args")
|
|
3078
|
+
or self.get_platform_setting("flutter.build_args")
|
|
3008
3079
|
)
|
|
3009
3080
|
if flutter_build_args:
|
|
3010
3081
|
if isinstance(flutter_build_args, (list, tuple)):
|
|
@@ -13,6 +13,8 @@ class Command(BaseBuildCommand):
|
|
|
13
13
|
"""
|
|
14
14
|
Run a Flet Python app in debug mode on a specified platform (desktop, web, mobile).
|
|
15
15
|
|
|
16
|
+
Arguments after `--` are passed down to the underlying `flutter run`.
|
|
17
|
+
|
|
16
18
|
Detailed usage guide: https://flet.dev/blog/flet-debug-the-new-cli-for-testing-flet-apps-on-mobile-devices
|
|
17
19
|
"""
|
|
18
20
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Option:
|
|
6
|
+
"""A reusable option object which delegates all arguments
|
|
7
|
+
to parser.add_argument().
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
11
|
+
self.args = args
|
|
12
|
+
self.kwargs = kwargs
|
|
13
|
+
|
|
14
|
+
def add_to_parser(self, parser: argparse._ActionsContainer) -> None:
|
|
15
|
+
"""
|
|
16
|
+
Add this option definition to an argument parser or compatible container.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
parser: Parser-like object exposing `add_argument()`.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
parser.add_argument(*self.args, **self.kwargs)
|
|
23
|
+
|
|
24
|
+
def add_to_group(self, group: argparse._ArgumentGroup) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Add this option definition to an argument group.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
group: Argument group that receives the option.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
group.add_argument(*self.args, **self.kwargs)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PassThroughArgsAction(argparse.Action):
|
|
36
|
+
"""
|
|
37
|
+
Collect the values of each occurrence of an option that passes arguments on
|
|
38
|
+
to another program, as one list per occurrence.
|
|
39
|
+
|
|
40
|
+
A value that starts with `-` is read as an option of its own unless it is
|
|
41
|
+
attached with `=`, which leaves the occurrence without values and hands the
|
|
42
|
+
value to whichever Flet option it names. An occurrence without values is
|
|
43
|
+
therefore rejected, with a hint to attach the value or to pass it after
|
|
44
|
+
`--`.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, option_strings, dest, example: str, **kwargs):
|
|
48
|
+
"""
|
|
49
|
+
Args:
|
|
50
|
+
option_strings: The option strings of the option.
|
|
51
|
+
dest: The attribute that receives the collected values.
|
|
52
|
+
example: A value that starts with `-`, shown in the hint.
|
|
53
|
+
**kwargs: The other `add_argument()` arguments.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
super().__init__(option_strings, dest, **kwargs)
|
|
57
|
+
self.example = example
|
|
58
|
+
|
|
59
|
+
def __call__(self, parser, namespace, values, option_string=None):
|
|
60
|
+
if not values:
|
|
61
|
+
raise argparse.ArgumentError(
|
|
62
|
+
self,
|
|
63
|
+
"expected at least one argument - attach one that starts with "
|
|
64
|
+
f"`-` using `=`, e.g. `{self.option_strings[0]}={self.example}`, "
|
|
65
|
+
"or pass it after `--`",
|
|
66
|
+
)
|
|
67
|
+
collected = getattr(namespace, self.dest, None) or []
|
|
68
|
+
setattr(namespace, self.dest, [*collected, values])
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
verbose_option = Option(
|
|
72
|
+
"-v",
|
|
73
|
+
"--verbose",
|
|
74
|
+
action="count",
|
|
75
|
+
default=0,
|
|
76
|
+
help="Enable verbose output. "
|
|
77
|
+
"Use -v for standard verbose logging and -vv for more detailed output",
|
|
78
|
+
)
|
|
@@ -13,6 +13,7 @@ from pathlib import Path
|
|
|
13
13
|
import flet_cli.__pyinstaller.config as hook_config
|
|
14
14
|
from flet.utils import is_linux, is_macos, is_windows
|
|
15
15
|
from flet_cli.commands.base import BaseCommand
|
|
16
|
+
from flet_cli.commands.options import PassThroughArgsAction
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class Command(BaseCommand):
|
|
@@ -20,6 +21,8 @@ class Command(BaseCommand):
|
|
|
20
21
|
Package a Flet application into a standalone desktop executable or app bundle
|
|
21
22
|
using PyInstaller.
|
|
22
23
|
|
|
24
|
+
Arguments after `--` are passed down to PyInstaller.
|
|
25
|
+
|
|
23
26
|
Detailed usage guide: https://flet.dev/docs/publish/using-pyinstaller
|
|
24
27
|
"""
|
|
25
28
|
|
|
@@ -152,9 +155,12 @@ class Command(BaseCommand):
|
|
|
152
155
|
parser.add_argument(
|
|
153
156
|
"--pyinstaller-build-args",
|
|
154
157
|
dest="pyinstaller_build_args",
|
|
155
|
-
action=
|
|
158
|
+
action=PassThroughArgsAction,
|
|
159
|
+
example="--clean",
|
|
156
160
|
nargs="*",
|
|
157
|
-
help="Additional raw arguments to the underlying pyinstaller build
|
|
161
|
+
help="Additional raw arguments to the underlying pyinstaller build "
|
|
162
|
+
"command. Attach an argument that starts with `-` using `=`, e.g. "
|
|
163
|
+
"`--pyinstaller-build-args=--clean`, or pass the arguments after `--`",
|
|
158
164
|
)
|
|
159
165
|
parser.add_argument(
|
|
160
166
|
"-y",
|