flet-cli 0.86.1__tar.gz → 0.86.3__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-0.86.1 → flet_cli-0.86.3}/PKG-INFO +2 -2
- {flet_cli-0.86.1 → flet_cli-0.86.3}/pyproject.toml +2 -2
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/cli.py +86 -24
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/build_base.py +75 -17
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/flutter_base.py +14 -2
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/run.py +12 -1
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/python_versions.py +1 -1
- flet_cli-0.86.3/src/flet_cli/version.py +1 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli.egg-info/PKG-INFO +2 -2
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli.egg-info/SOURCES.txt +3 -1
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli.egg-info/requires.txt +1 -1
- flet_cli-0.86.3/tests/test_find_platform_image.py +67 -0
- flet_cli-0.86.3/tests/test_run_script_args.py +103 -0
- flet_cli-0.86.1/src/flet_cli/version.py +0 -1
- {flet_cli-0.86.1 → flet_cli-0.86.3}/README.md +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/setup.cfg +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/__pyinstaller/__init__.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/__pyinstaller/config.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/__pyinstaller/hook-flet.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/__pyinstaller/macos_utils.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/__pyinstaller/utils.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/__pyinstaller/win_utils.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/base.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/build.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/clean.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/create.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/debug.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/devices.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/doctor.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/emulators.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/mcp.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/options.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/pack.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/publish.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/serve.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/test.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/commands/test_host.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/android.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/android_sdk.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/cli.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/distros.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/flutter.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/hash_stamp.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/jdk.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/linux_deps.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/merge.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/plist.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/processes.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/project_dependencies.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/pyodide.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/pyproject_toml.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/utils/template_cache.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli.egg-info/dependency_links.txt +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli.egg-info/entry_points.txt +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli.egg-info/top_level.txt +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/tests/test_clean.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/tests/test_plist.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/tests/test_project_dependencies.py +0 -0
- {flet_cli-0.86.1 → flet_cli-0.86.3}/tests/test_python_versions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-cli
|
|
3
|
-
Version: 0.86.
|
|
3
|
+
Version: 0.86.3
|
|
4
4
|
Summary: Flet CLI
|
|
5
5
|
Author-email: "Appveyor Systems Inc." <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,7 +9,7 @@ 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==0.86.
|
|
12
|
+
Requires-Dist: flet==0.86.3
|
|
13
13
|
Requires-Dist: watchdog>=4.0.0
|
|
14
14
|
Requires-Dist: packaging>=25.0
|
|
15
15
|
Requires-Dist: qrcode>=7.4.2
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flet-cli"
|
|
3
|
-
version = "0.86.
|
|
3
|
+
version = "0.86.3"
|
|
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==0.86.
|
|
10
|
+
"flet==0.86.3",
|
|
11
11
|
"watchdog >=4.0.0",
|
|
12
12
|
"packaging >=25.0",
|
|
13
13
|
"qrcode >=7.4.2",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import json
|
|
3
3
|
import sys
|
|
4
|
+
from typing import Optional
|
|
4
5
|
|
|
5
6
|
import flet.version
|
|
6
7
|
import flet_cli.commands.build
|
|
@@ -41,23 +42,25 @@ def _render_version(as_json: bool) -> str:
|
|
|
41
42
|
|
|
42
43
|
# Source https://stackoverflow.com/a/26379693
|
|
43
44
|
def set_default_subparser(
|
|
44
|
-
parser: argparse.ArgumentParser, name: str, args: list
|
|
45
|
-
):
|
|
45
|
+
parser: argparse.ArgumentParser, name: str, args: list
|
|
46
|
+
) -> list:
|
|
46
47
|
"""
|
|
47
|
-
|
|
48
|
+
Prepend a default subparser name when the command line doesn't name one.
|
|
48
49
|
This should be called after setting up the argument parser but before
|
|
49
50
|
`parse_args()`.
|
|
50
51
|
|
|
51
52
|
Args:
|
|
53
|
+
parser: The root argument parser.
|
|
52
54
|
name: The name of the default subparser to use.
|
|
53
|
-
args:
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
args: The command-line arguments, without the program name.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
`args`, with the default subparser name prepended when applicable.
|
|
56
59
|
"""
|
|
57
60
|
|
|
58
|
-
# exit if help or version flags are present
|
|
59
|
-
if any(flag in
|
|
60
|
-
return
|
|
61
|
+
# exit if no arguments, or help or version flags are present
|
|
62
|
+
if not args or any(flag in args for flag in {"-h", "--help", "-V", "--version"}):
|
|
63
|
+
return args
|
|
61
64
|
|
|
62
65
|
# all subparser actions
|
|
63
66
|
subparser_actions = [
|
|
@@ -72,19 +75,14 @@ def set_default_subparser(
|
|
|
72
75
|
]
|
|
73
76
|
|
|
74
77
|
# if an existing subparser is provided, skip setting a default
|
|
75
|
-
if any(arg in subparser_names for arg in
|
|
76
|
-
return
|
|
78
|
+
if any(arg in subparser_names for arg in args):
|
|
79
|
+
return args
|
|
77
80
|
|
|
78
81
|
# if the default subparser doesn't exist, register it in the first subparser action
|
|
79
82
|
if (name not in subparser_names) and subparser_actions:
|
|
80
83
|
subparser_actions[0].add_parser(name)
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
if args is None:
|
|
84
|
-
if len(sys.argv) > 1:
|
|
85
|
-
sys.argv.insert(index, name)
|
|
86
|
-
else:
|
|
87
|
-
args.insert(index, name)
|
|
85
|
+
return [name, *args]
|
|
88
86
|
|
|
89
87
|
|
|
90
88
|
def get_parser() -> argparse.ArgumentParser:
|
|
@@ -132,22 +130,86 @@ def get_parser() -> argparse.ArgumentParser:
|
|
|
132
130
|
except ImportError:
|
|
133
131
|
pass
|
|
134
132
|
|
|
135
|
-
# set "run" as the default subparser
|
|
136
|
-
set_default_subparser(parser, name="run", index=1)
|
|
137
|
-
|
|
138
133
|
return parser
|
|
139
134
|
|
|
140
135
|
|
|
141
|
-
def
|
|
136
|
+
def split_script_args(argv: list) -> tuple[list, Optional[list]]:
|
|
137
|
+
"""
|
|
138
|
+
Split a command line at the first bare `--` separator.
|
|
139
|
+
|
|
140
|
+
Everything after the separator is meant for the app script, not for Flet
|
|
141
|
+
itself, so it must be removed before the parser (and `set_default_subparser`)
|
|
142
|
+
sees it - otherwise `flet run app.py -- --web` would be read as Flet's own
|
|
143
|
+
`--web` option, and `flet app.py -- build` would suppress the default `run`
|
|
144
|
+
subcommand.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
argv: Command-line arguments, without the program name.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
A `(argv, script_args)` tuple, where `script_args` is `None` when no
|
|
151
|
+
`--` separator is present.
|
|
152
|
+
"""
|
|
153
|
+
try:
|
|
154
|
+
index = argv.index("--")
|
|
155
|
+
except ValueError:
|
|
156
|
+
return argv, None
|
|
157
|
+
return argv[:index], argv[index + 1 :]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def parse_command_line(argv: list) -> argparse.Namespace:
|
|
161
|
+
"""
|
|
162
|
+
Parse a Flet command line into the namespace passed to a command handler.
|
|
163
|
+
|
|
164
|
+
Exits the process with a usage message when the command line is invalid.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
argv: Command-line arguments, without the program name.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
The parsed arguments. For `flet run`, `script_args` holds the arguments
|
|
171
|
+
to forward to the app script.
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
# pull off the arguments meant for the app script before the parser sees them
|
|
175
|
+
argv, script_args = split_script_args(argv)
|
|
176
|
+
|
|
142
177
|
parser = get_parser()
|
|
143
178
|
|
|
179
|
+
# "run" is the default subcommand
|
|
180
|
+
argv = set_default_subparser(parser, name="run", args=argv)
|
|
181
|
+
|
|
182
|
+
args, unrecognized = parser.parse_known_args(argv)
|
|
183
|
+
|
|
184
|
+
if unrecognized:
|
|
185
|
+
message = f"unrecognized arguments: {' '.join(unrecognized)}"
|
|
186
|
+
if getattr(args, "command", None) == "run":
|
|
187
|
+
message += (
|
|
188
|
+
"\nIf these are arguments for your app script, put them after "
|
|
189
|
+
"a `--` separator, e.g. "
|
|
190
|
+
f"`flet run {args.script} -- {' '.join(unrecognized)}`"
|
|
191
|
+
)
|
|
192
|
+
parser.error(message)
|
|
193
|
+
|
|
194
|
+
# forward the arguments that followed `--` to the app script
|
|
195
|
+
if script_args is not None:
|
|
196
|
+
if getattr(args, "command", None) != "run":
|
|
197
|
+
parser.error(
|
|
198
|
+
"the `--` separator is only supported by `flet run`, to pass "
|
|
199
|
+
"the arguments that follow it to your app script"
|
|
200
|
+
)
|
|
201
|
+
args.script_args = list(args.script_args) + script_args
|
|
202
|
+
|
|
203
|
+
return args
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def main():
|
|
144
207
|
# print usage/help if called without arguments
|
|
145
208
|
if len(sys.argv) == 1:
|
|
146
|
-
|
|
209
|
+
get_parser().print_help(sys.stdout)
|
|
147
210
|
sys.exit(1)
|
|
148
211
|
|
|
149
|
-
|
|
150
|
-
args = parser.parse_args()
|
|
212
|
+
args = parse_command_line(sys.argv[1:])
|
|
151
213
|
|
|
152
214
|
# handle `flet --version [--json]` (no subcommand/handler is set)
|
|
153
215
|
if getattr(args, "version", False):
|
|
@@ -474,6 +474,17 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
474
474
|
default=None,
|
|
475
475
|
help="Split the APKs per ABIs (Android only)",
|
|
476
476
|
)
|
|
477
|
+
parser.add_argument(
|
|
478
|
+
"--android-legacy-packaging",
|
|
479
|
+
dest="android_legacy_packaging",
|
|
480
|
+
action=argparse.BooleanOptionalAction,
|
|
481
|
+
default=None,
|
|
482
|
+
help="Use legacy Android native-library packaging: extract `.so` to disk "
|
|
483
|
+
"at install time instead of memory-mapping them directly from the APK. Off "
|
|
484
|
+
"by default (modern packaging). Enabling it makes the raw `.apk` file "
|
|
485
|
+
"smaller for side-loading, at the cost of a larger on-device install size "
|
|
486
|
+
"and slower native-library loading (Android only)",
|
|
487
|
+
)
|
|
477
488
|
parser.add_argument(
|
|
478
489
|
"--compile-app",
|
|
479
490
|
dest="compile_app",
|
|
@@ -920,6 +931,16 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
920
931
|
)
|
|
921
932
|
)
|
|
922
933
|
|
|
934
|
+
android_legacy_packaging = (
|
|
935
|
+
self.options.android_legacy_packaging
|
|
936
|
+
if self.options.android_legacy_packaging is not None
|
|
937
|
+
else (
|
|
938
|
+
self.get_pyproject("tool.flet.android.legacy_packaging")
|
|
939
|
+
if self.get_pyproject("tool.flet.android.legacy_packaging") is not None
|
|
940
|
+
else False
|
|
941
|
+
)
|
|
942
|
+
)
|
|
943
|
+
|
|
923
944
|
info_plist = {}
|
|
924
945
|
macos_entitlements = {
|
|
925
946
|
"com.apple.security.app-sandbox": False,
|
|
@@ -1375,6 +1396,7 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
1375
1396
|
or self.get_pyproject("tool.flet.android.signing.key_store")
|
|
1376
1397
|
or os.getenv("FLET_ANDROID_SIGNING_KEY_STORE")
|
|
1377
1398
|
),
|
|
1399
|
+
"android_legacy_packaging": bool(android_legacy_packaging),
|
|
1378
1400
|
},
|
|
1379
1401
|
"flutter": {"dependencies": list(self.flutter_dependencies.keys())},
|
|
1380
1402
|
"boot_screen": self._resolve_boot_screen(),
|
|
@@ -2832,11 +2854,14 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2832
2854
|
"""
|
|
2833
2855
|
Find the best matching image file for the current target platform.
|
|
2834
2856
|
|
|
2835
|
-
When multiple files share the same base name (e.g. `icon.
|
|
2836
|
-
`icon.
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2857
|
+
When multiple files share the same base name (e.g. `icon.png` and
|
|
2858
|
+
`icon.svg`), incompatible formats are filtered out and the rest are
|
|
2859
|
+
ranked so a raster image (`.png` first) always wins, making the
|
|
2860
|
+
choice deterministic regardless of filesystem ordering. Formats the
|
|
2861
|
+
icon/splash generators cannot decode are dropped: `.svg` (vector,
|
|
2862
|
+
never supported), `.icns` (macOS-only) and `.ico` (Windows-only). If
|
|
2863
|
+
the only candidate is a vector image, a warning is logged and `None`
|
|
2864
|
+
is returned so the default icon is used.
|
|
2840
2865
|
|
|
2841
2866
|
Args:
|
|
2842
2867
|
src_path: Source assets directory.
|
|
@@ -2849,21 +2874,54 @@ class BaseBuildCommand(BaseFlutterCommand):
|
|
|
2849
2874
|
File name of matched image, or `None` if not found.
|
|
2850
2875
|
"""
|
|
2851
2876
|
|
|
2852
|
-
#
|
|
2853
|
-
#
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2877
|
+
# flutter_launcher_icons / flutter_native_splash decode raster images
|
|
2878
|
+
# only, so drop any candidate they can't read: .svg is vector (never
|
|
2879
|
+
# supported), .icns is macOS-only and .ico is Windows-only.
|
|
2880
|
+
def _incompatible(p: str) -> bool:
|
|
2881
|
+
ext = Path(p).suffix.lower()
|
|
2882
|
+
return (
|
|
2883
|
+
ext == ".svg"
|
|
2884
|
+
or (ext == ".icns" and self.target_platform != "macos")
|
|
2885
|
+
or (ext == ".ico" and self.target_platform != "windows")
|
|
2886
|
+
)
|
|
2887
|
+
|
|
2888
|
+
# glob order is filesystem-dependent — sort so the choice is
|
|
2889
|
+
# deterministic across machines, then rank by format so a raster
|
|
2890
|
+
# icon (.png first) always wins when several candidates share a base
|
|
2891
|
+
# name (e.g. both icon.png and icon.svg present).
|
|
2892
|
+
ext_priority = {
|
|
2893
|
+
".png": 0,
|
|
2894
|
+
".webp": 1,
|
|
2895
|
+
".jpg": 2,
|
|
2896
|
+
".jpeg": 2,
|
|
2897
|
+
".gif": 3,
|
|
2898
|
+
".bmp": 4,
|
|
2899
|
+
".tif": 5,
|
|
2900
|
+
".tiff": 5,
|
|
2901
|
+
".ico": 6,
|
|
2902
|
+
".icns": 6,
|
|
2903
|
+
}
|
|
2904
|
+
candidates = sorted(glob.glob(str(src_path.joinpath(f"{image_name}.*"))))
|
|
2905
|
+
images = sorted(
|
|
2906
|
+
(p for p in candidates if not _incompatible(p)),
|
|
2907
|
+
key=lambda p: (ext_priority.get(Path(p).suffix.lower(), 99), p),
|
|
2864
2908
|
)
|
|
2865
2909
|
|
|
2866
2910
|
if not images:
|
|
2911
|
+
# Nothing usable. If the only candidate was a vector image (e.g.
|
|
2912
|
+
# an icon.svg with no raster sibling), say why it's ignored
|
|
2913
|
+
# instead of silently falling back to the default icon.
|
|
2914
|
+
svg = next(
|
|
2915
|
+
(p for p in candidates if Path(p).suffix.lower() == ".svg"), None
|
|
2916
|
+
)
|
|
2917
|
+
if svg:
|
|
2918
|
+
console.log(
|
|
2919
|
+
f'Warning: "{Path(svg).name}" is a vector (SVG) image and '
|
|
2920
|
+
f'cannot be used for "{image_name}". Provide a raster '
|
|
2921
|
+
f'"{image_name}.png" to customize it — using the default '
|
|
2922
|
+
f"for now.",
|
|
2923
|
+
style=warning_style,
|
|
2924
|
+
)
|
|
2867
2925
|
return None
|
|
2868
2926
|
|
|
2869
2927
|
best = images[0]
|
|
@@ -21,14 +21,26 @@ from flet.utils.platform_utils import get_bool_env_var
|
|
|
21
21
|
from flet_cli.commands.base import BaseCommand
|
|
22
22
|
from flet_cli.utils.flutter import get_flutter_dir, install_flutter
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
# Detect the plain-output request BEFORE building the shared console: the
|
|
25
|
+
# `--no-rich-output` argparse flag is parsed per-command, too late to
|
|
26
|
+
# affect this module-level console, so check sys.argv for it here too
|
|
27
|
+
# (alongside the env var). Without this, the flag only suppressed emojis
|
|
28
|
+
# while the color + Live spinner kept going.
|
|
29
|
+
no_rich_output = (
|
|
30
|
+
get_bool_env_var("FLET_CLI_NO_RICH_OUTPUT") or "--no-rich-output" in sys.argv
|
|
31
|
+
)
|
|
25
32
|
|
|
26
33
|
error_style = Style(color="red", bold=True)
|
|
27
34
|
warning_style = Style(color="yellow", bold=True)
|
|
28
35
|
console = Console(
|
|
29
36
|
log_path=False,
|
|
30
37
|
theme=Theme({"log.message": "green bold"}),
|
|
31
|
-
|
|
38
|
+
# no_rich_output forces fully plain output (no color, no animation).
|
|
39
|
+
# Otherwise auto-detect the terminal (force_terminal=None): a real TTY
|
|
40
|
+
# gets the animated Live spinner, but piped output (CI, cloud build)
|
|
41
|
+
# must NOT be fed one line per animation frame — forcing the terminal
|
|
42
|
+
# on there floods non-TTY logs with thousands of spinner redraws.
|
|
43
|
+
force_terminal=False if no_rich_output else None,
|
|
32
44
|
)
|
|
33
45
|
verbose1_style = Style(dim=True, bold=False)
|
|
34
46
|
verbose2_style = Style(color="bright_black", bold=False)
|
|
@@ -47,6 +47,16 @@ class Command(BaseCommand):
|
|
|
47
47
|
default=".",
|
|
48
48
|
help="Path to the Python script that starts your Flet app",
|
|
49
49
|
)
|
|
50
|
+
parser.add_argument(
|
|
51
|
+
"script_args",
|
|
52
|
+
type=str,
|
|
53
|
+
nargs="*",
|
|
54
|
+
default=[],
|
|
55
|
+
metavar="args",
|
|
56
|
+
help="Arguments to pass to your app script, available there as "
|
|
57
|
+
"`sys.argv[1:]`. Separate them from Flet's own options with `--`, "
|
|
58
|
+
"e.g. `flet run --web app.py -- --verbose`",
|
|
59
|
+
)
|
|
50
60
|
parser.add_argument(
|
|
51
61
|
"-p",
|
|
52
62
|
"--port",
|
|
@@ -287,7 +297,8 @@ class Command(BaseCommand):
|
|
|
287
297
|
my_event_handler = Handler(
|
|
288
298
|
args=[sys.executable, "-u"]
|
|
289
299
|
+ ["-m"] * options.module
|
|
290
|
-
+ [options.script if options.module else script_path]
|
|
300
|
+
+ [options.script if options.module else script_path]
|
|
301
|
+
+ list(options.script_args),
|
|
291
302
|
watch_directory=options.directory or options.recursive,
|
|
292
303
|
script_path=str(script_path),
|
|
293
304
|
port=port,
|
|
@@ -28,7 +28,7 @@ from flet_cli.utils.template_cache import get_cache_root
|
|
|
28
28
|
# python-build release this flet pins. Keep in sync with serious_python's
|
|
29
29
|
# `pythonReleaseDate` (lib/src/python_versions.dart) — both should track the
|
|
30
30
|
# same python-build release.
|
|
31
|
-
PYTHON_BUILD_RELEASE_DATE = "
|
|
31
|
+
PYTHON_BUILD_RELEASE_DATE = "20260726"
|
|
32
32
|
|
|
33
33
|
RELEASE_DATE_ENV = "FLET_PYTHON_BUILD_RELEASE_DATE"
|
|
34
34
|
MANIFEST_PATH_ENV = "FLET_PYTHON_BUILD_MANIFEST"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "0.86.3"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-cli
|
|
3
|
-
Version: 0.86.
|
|
3
|
+
Version: 0.86.3
|
|
4
4
|
Summary: Flet CLI
|
|
5
5
|
Author-email: "Appveyor Systems Inc." <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,7 +9,7 @@ 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==0.86.
|
|
12
|
+
Requires-Dist: flet==0.86.3
|
|
13
13
|
Requires-Dist: watchdog>=4.0.0
|
|
14
14
|
Requires-Dist: packaging>=25.0
|
|
15
15
|
Requires-Dist: qrcode>=7.4.2
|
|
@@ -50,6 +50,8 @@ src/flet_cli/utils/pyproject_toml.py
|
|
|
50
50
|
src/flet_cli/utils/python_versions.py
|
|
51
51
|
src/flet_cli/utils/template_cache.py
|
|
52
52
|
tests/test_clean.py
|
|
53
|
+
tests/test_find_platform_image.py
|
|
53
54
|
tests/test_plist.py
|
|
54
55
|
tests/test_project_dependencies.py
|
|
55
|
-
tests/test_python_versions.py
|
|
56
|
+
tests/test_python_versions.py
|
|
57
|
+
tests/test_run_script_args.py
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Icon/splash image selection in `flet build`.
|
|
2
|
+
|
|
3
|
+
`find_platform_image` must pick a *decodable* image deterministically when
|
|
4
|
+
several files share a base name — otherwise the choice depends on filesystem
|
|
5
|
+
glob order and an `icon.svg` can slip through to `flutter_launcher_icons`,
|
|
6
|
+
which crashes with `NoDecoderForImageFormatException`.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from types import SimpleNamespace
|
|
10
|
+
|
|
11
|
+
from flet_cli.commands.build_base import BaseBuildCommand
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _FakeHash:
|
|
15
|
+
def update(self, *_):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _find(tmp_path, filenames, *, image_name="icon", target_platform="web"):
|
|
20
|
+
assets = tmp_path / "assets"
|
|
21
|
+
assets.mkdir(exist_ok=True)
|
|
22
|
+
for name in filenames:
|
|
23
|
+
(assets / name).write_bytes(b"x")
|
|
24
|
+
dest = tmp_path / "images"
|
|
25
|
+
dest.mkdir(exist_ok=True)
|
|
26
|
+
fake_self = SimpleNamespace(target_platform=target_platform, verbose=0)
|
|
27
|
+
copy_ops: list = []
|
|
28
|
+
result = BaseBuildCommand.find_platform_image(
|
|
29
|
+
fake_self, assets, dest, image_name, copy_ops, _FakeHash()
|
|
30
|
+
)
|
|
31
|
+
return result, copy_ops
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_prefers_raster_over_svg(tmp_path):
|
|
35
|
+
# Both present: the raster png must win regardless of glob order.
|
|
36
|
+
result, copy_ops = _find(tmp_path, ["icon.svg", "icon.png"])
|
|
37
|
+
assert result == "icon.png"
|
|
38
|
+
assert copy_ops and str(copy_ops[0][0]).endswith("icon.png")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_png_preferred_over_other_raster(tmp_path):
|
|
42
|
+
# Ranking, not alphabetical order (jpg < png alphabetically).
|
|
43
|
+
result, _ = _find(tmp_path, ["icon.jpg", "icon.png"])
|
|
44
|
+
assert result == "icon.png"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_svg_only_returns_none_with_warning(tmp_path, capsys):
|
|
48
|
+
result, copy_ops = _find(tmp_path, ["icon.svg"])
|
|
49
|
+
assert result is None
|
|
50
|
+
assert copy_ops == []
|
|
51
|
+
combined = capsys.readouterr()
|
|
52
|
+
assert "icon.svg" in (combined.out + combined.err)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_no_candidates_is_silent_none(tmp_path, capsys):
|
|
56
|
+
result, copy_ops = _find(tmp_path, [])
|
|
57
|
+
assert result is None
|
|
58
|
+
assert copy_ops == []
|
|
59
|
+
combined = capsys.readouterr()
|
|
60
|
+
assert "Warning" not in (combined.out + combined.err)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_ico_is_windows_only(tmp_path):
|
|
64
|
+
# ico is incompatible on web (no raster sibling) -> default icon.
|
|
65
|
+
assert _find(tmp_path, ["icon.ico"], target_platform="web")[0] is None
|
|
66
|
+
# ...but valid on a windows build.
|
|
67
|
+
assert _find(tmp_path, ["icon.ico"], target_platform="windows")[0] == "icon.ico"
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from flet_cli.cli import parse_command_line
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _parse(*argv):
|
|
7
|
+
"""Parse a Flet command line given as separate arguments."""
|
|
8
|
+
return parse_command_line(list(argv))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_no_script_args():
|
|
12
|
+
"""A plain `flet run app.py` passes nothing to the script."""
|
|
13
|
+
args = _parse("run", "app.py")
|
|
14
|
+
|
|
15
|
+
assert args.script == "app.py"
|
|
16
|
+
assert args.script_args == []
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_script_args_after_separator():
|
|
20
|
+
"""Arguments after `--` are forwarded to the script, options and all."""
|
|
21
|
+
args = _parse("run", "app.py", "--", "--manual", "-x", "1")
|
|
22
|
+
|
|
23
|
+
assert args.script == "app.py"
|
|
24
|
+
assert args.script_args == ["--manual", "-x", "1"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_flet_options_are_not_forwarded():
|
|
28
|
+
"""Flet's own options before `--` stay with Flet."""
|
|
29
|
+
args = _parse("run", "-w", "app.py", "--", "--web")
|
|
30
|
+
|
|
31
|
+
assert args.web is True
|
|
32
|
+
assert args.script == "app.py"
|
|
33
|
+
assert args.script_args == ["--web"]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_flet_options_between_script_and_separator():
|
|
37
|
+
"""Flet's options may follow the script path and precede `--`."""
|
|
38
|
+
args = _parse("run", "app.py", "--web", "--port", "8080", "--", "--manual")
|
|
39
|
+
|
|
40
|
+
assert args.web is True
|
|
41
|
+
assert args.port == 8080
|
|
42
|
+
assert args.script_args == ["--manual"]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_positional_script_args_need_no_separator():
|
|
46
|
+
"""Arguments that don't look like options are forwarded without `--`."""
|
|
47
|
+
args = _parse("run", "app.py", "foo", "bar")
|
|
48
|
+
|
|
49
|
+
assert args.script == "app.py"
|
|
50
|
+
assert args.script_args == ["foo", "bar"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_positional_and_separated_script_args_are_combined():
|
|
54
|
+
"""Arguments before and after `--` are forwarded in command-line order."""
|
|
55
|
+
args = _parse("run", "app.py", "foo", "--", "--manual")
|
|
56
|
+
|
|
57
|
+
assert args.script_args == ["foo", "--manual"]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_script_args_with_module():
|
|
61
|
+
"""`-m` module invocations forward script arguments too."""
|
|
62
|
+
args = _parse("run", "-m", "my_app.main", "--", "--manual")
|
|
63
|
+
|
|
64
|
+
assert args.module is True
|
|
65
|
+
assert args.script == "my_app.main"
|
|
66
|
+
assert args.script_args == ["--manual"]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_script_args_with_implicit_run_command():
|
|
70
|
+
"""The default `run` subcommand is applied even with a `--` separator."""
|
|
71
|
+
args = _parse("app.py", "--", "--manual")
|
|
72
|
+
|
|
73
|
+
assert args.command == "run"
|
|
74
|
+
assert args.script == "app.py"
|
|
75
|
+
assert args.script_args == ["--manual"]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_script_args_named_like_a_subcommand():
|
|
79
|
+
"""A script argument matching a subcommand name doesn't select it."""
|
|
80
|
+
args = _parse("app.py", "--", "build", "test")
|
|
81
|
+
|
|
82
|
+
assert args.command == "run"
|
|
83
|
+
assert args.script == "app.py"
|
|
84
|
+
assert args.script_args == ["build", "test"]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_unknown_flet_option_is_rejected(capsys):
|
|
88
|
+
"""A mistyped Flet option still errors instead of reaching the script."""
|
|
89
|
+
with pytest.raises(SystemExit):
|
|
90
|
+
_parse("run", "app.py", "--wev")
|
|
91
|
+
|
|
92
|
+
err = capsys.readouterr().err
|
|
93
|
+
assert "unrecognized arguments: --wev" in err
|
|
94
|
+
# ...and the error suggests the `--` separator
|
|
95
|
+
assert "flet run app.py -- --wev" in err
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_separator_rejected_for_other_commands(capsys):
|
|
99
|
+
"""Only `flet run` accepts a `--` separator."""
|
|
100
|
+
with pytest.raises(SystemExit):
|
|
101
|
+
_parse("build", "apk", "--", "--manual")
|
|
102
|
+
|
|
103
|
+
assert "only supported by `flet run`" in capsys.readouterr().err
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "0.86.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_cli-0.86.1 → flet_cli-0.86.3}/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|