flet-cli 0.85.3.dev0__py3-none-any.whl → 0.85.3.dev1__py3-none-any.whl

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.
@@ -826,6 +826,7 @@ class BaseBuildCommand(BaseFlutterCommand):
826
826
  "android.hardware.touchscreen": False,
827
827
  }
828
828
  android_meta_data = {}
829
+ android_providers = {}
829
830
 
830
831
  # merge values from "--permissions" arg:
831
832
  for p in (
@@ -974,6 +975,88 @@ class BaseBuildCommand(BaseFlutterCommand):
974
975
  else:
975
976
  self.cleanup(1, f"Invalid Android meta-data option: {p}")
976
977
 
978
+ android_providers = merge_dict(
979
+ android_providers,
980
+ self.get_pyproject("tool.flet.android.provider") or {},
981
+ )
982
+
983
+ def _xml_attr_value(v):
984
+ # Android XML expects lowercase booleans.
985
+ if isinstance(v, bool):
986
+ return "true" if v else "false"
987
+ return v
988
+
989
+ normalized_providers = {}
990
+ for key, value in android_providers.items():
991
+ if value is False or value == {}:
992
+ continue
993
+ if value is True:
994
+ self.cleanup(
995
+ 1,
996
+ f"Invalid Android provider value for {key}: 'true' is not "
997
+ "supported. Use an inline table of attributes, or 'false' "
998
+ "to skip.",
999
+ )
1000
+ if not isinstance(value, dict):
1001
+ self.cleanup(
1002
+ 1,
1003
+ f"Invalid Android provider value for {key}: "
1004
+ f"{type(value).__name__}. Expected boolean or inline table.",
1005
+ )
1006
+ normalized = {}
1007
+ for ak, av in value.items():
1008
+ if ak == "name":
1009
+ self.cleanup(
1010
+ 1,
1011
+ f"Invalid Android provider attribute for {key}: "
1012
+ "'name' is reserved and is taken from the table key.",
1013
+ )
1014
+ if ak == "meta_data":
1015
+ if not isinstance(av, dict):
1016
+ self.cleanup(
1017
+ 1,
1018
+ f"Invalid Android provider meta_data for {key}: "
1019
+ f"{type(av).__name__}. Expected inline table.",
1020
+ )
1021
+ normalized_meta = {}
1022
+ for mk, mv in av.items():
1023
+ if isinstance(mv, (str, bool, int, float)):
1024
+ normalized_meta[mk] = _xml_attr_value(mv)
1025
+ continue
1026
+ if isinstance(mv, dict):
1027
+ normalized_attrs = {}
1028
+ for attr_key, attr_value in mv.items():
1029
+ if not isinstance(attr_value, (str, bool, int, float)):
1030
+ self.cleanup(
1031
+ 1,
1032
+ f"Invalid Android provider meta-data "
1033
+ f"attribute value for "
1034
+ f"{key}.meta_data.{mk}.{attr_key}: "
1035
+ f"{type(attr_value).__name__}. "
1036
+ "Expected string, boolean, or number.",
1037
+ )
1038
+ normalized_attrs[attr_key] = _xml_attr_value(attr_value)
1039
+ normalized_meta[mk] = normalized_attrs
1040
+ continue
1041
+ self.cleanup(
1042
+ 1,
1043
+ f"Invalid Android provider meta-data value for "
1044
+ f"{key}.meta_data.{mk}: {type(mv).__name__}. "
1045
+ "Expected string, boolean, number, or inline table.",
1046
+ )
1047
+ normalized["meta_data"] = normalized_meta
1048
+ continue
1049
+ if not isinstance(av, (str, bool, int, float)):
1050
+ self.cleanup(
1051
+ 1,
1052
+ f"Invalid Android provider attribute value for "
1053
+ f"{key}.{ak}: {type(av).__name__}. "
1054
+ "Expected string, boolean, or number.",
1055
+ )
1056
+ normalized[ak] = _xml_attr_value(av)
1057
+ normalized_providers[key] = normalized
1058
+ android_providers = normalized_providers
1059
+
977
1060
  deep_linking_scheme = (
978
1061
  self.get_pyproject("tool.flet.ios.deep_linking.scheme")
979
1062
  if self.package_platform == "iOS"
@@ -1126,6 +1209,7 @@ class BaseBuildCommand(BaseFlutterCommand):
1126
1209
  "android_permissions": android_permissions,
1127
1210
  "android_features": android_features,
1128
1211
  "android_meta_data": android_meta_data,
1212
+ "android_providers": android_providers,
1129
1213
  "deep_linking": {
1130
1214
  "scheme": deep_linking_scheme,
1131
1215
  "host": deep_linking_host,
@@ -1174,6 +1258,9 @@ class BaseBuildCommand(BaseFlutterCommand):
1174
1258
  template_ref = flet.version.flet_version
1175
1259
 
1176
1260
  is_local_dev = False
1261
+ # Identity printed in status / hashed for invalidation; may differ from
1262
+ # the path cookiecutter actually reads when caching kicks in below.
1263
+ template_source = template_url
1177
1264
  if template_url:
1178
1265
  # User-provided template (git repo or local path) — use checkout
1179
1266
  checkout = template_ref
@@ -1182,13 +1269,19 @@ class BaseBuildCommand(BaseFlutterCommand):
1182
1269
  local_tpl = Path(__file__).resolve().parents[5] / "templates" / "build"
1183
1270
  if local_tpl.is_dir():
1184
1271
  template_url = str(local_tpl)
1272
+ template_source = template_url
1185
1273
  checkout = None
1186
1274
  is_local_dev = True
1187
1275
  else:
1188
- template_url = DEFAULT_TEMPLATE_URL.format(version=template_ref)
1276
+ from flet_cli.utils.template_cache import get_cached_template_zip
1277
+
1278
+ template_source = DEFAULT_TEMPLATE_URL.format(version=template_ref)
1279
+ template_url = str(
1280
+ get_cached_template_zip(template_source, template_ref)
1281
+ )
1189
1282
  checkout = None
1190
1283
 
1191
- hash.update(template_url)
1284
+ hash.update(template_source)
1192
1285
  hash.update(template_ref)
1193
1286
 
1194
1287
  template_dir = self.options.template_dir or self.get_pyproject(
@@ -1214,7 +1307,7 @@ class BaseBuildCommand(BaseFlutterCommand):
1214
1307
  # create a new Flutter bootstrap project directory, if non-existent
1215
1308
  if not second_pass:
1216
1309
  self.flutter_dir.mkdir(parents=True, exist_ok=True)
1217
- status = f"[bold blue]Creating app shell from {template_url}"
1310
+ status = f"[bold blue]Creating app shell from {template_source}"
1218
1311
  if checkout:
1219
1312
  status += f' with ref "{template_ref}"'
1220
1313
  status += "..."
@@ -0,0 +1,48 @@
1
+ import os
2
+ import shutil
3
+ import urllib.request
4
+ from pathlib import Path
5
+
6
+
7
+ def get_cache_root() -> Path:
8
+ """Resolve the Flet on-disk cache root.
9
+
10
+ Uses `$FLET_CACHE_DIR` if set, otherwise `~/.flet/cache`. The resolved
11
+ path is exported back into the process environment so child processes
12
+ (notably the Gradle build of `serious_python_android`) share the same
13
+ cache root by default.
14
+ """
15
+ root = os.environ.get("FLET_CACHE_DIR")
16
+ cache_root = Path(root).expanduser() if root else Path.home() / ".flet" / "cache"
17
+ os.environ["FLET_CACHE_DIR"] = str(cache_root)
18
+ return cache_root
19
+
20
+
21
+ def get_cached_template_zip(url: str, version: str) -> Path:
22
+ """Return a local path to `flet-build-template.zip` for `version`.
23
+
24
+ The build template at a versioned release URL is immutable, so caching
25
+ is a simple "use if present, else download once" — no revalidation.
26
+ """
27
+ cache_path = (
28
+ get_cache_root() / "build-template" / f"v{version}" / "flet-build-template.zip"
29
+ )
30
+
31
+ if cache_path.exists() and cache_path.stat().st_size > 0:
32
+ return cache_path
33
+
34
+ cache_path.parent.mkdir(parents=True, exist_ok=True)
35
+ tmp_path = cache_path.with_suffix(cache_path.suffix + ".tmp")
36
+
37
+ try:
38
+ with urllib.request.urlopen(url) as resp, open(tmp_path, "wb") as out:
39
+ shutil.copyfileobj(resp, out)
40
+ out.flush()
41
+ os.fsync(out.fileno())
42
+ os.replace(tmp_path, cache_path)
43
+ except BaseException:
44
+ if tmp_path.exists():
45
+ tmp_path.unlink(missing_ok=True)
46
+ raise
47
+
48
+ return cache_path
flet_cli/version.py CHANGED
@@ -1 +1 @@
1
- version = "0.85.3.dev0"
1
+ version = "0.85.3.dev1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flet-cli
3
- Version: 0.85.3.dev0
3
+ Version: 0.85.3.dev1
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.85.3.dev0
12
+ Requires-Dist: flet==0.85.3.dev1
13
13
  Requires-Dist: watchdog>=4.0.0
14
14
  Requires-Dist: packaging>=25.0
15
15
  Requires-Dist: qrcode>=7.4.2
@@ -1,5 +1,5 @@
1
1
  flet_cli/cli.py,sha256=iDtpgVnrdrHapnE42bkTe7Sf_bNK724bqXISozNWTRQ,3586
2
- flet_cli/version.py,sha256=7BBA-GWz4ScqgKKnxJllt4nSJKMRObfm82476HDLtL0,24
2
+ flet_cli/version.py,sha256=-o61B0KU42lFqadW17eZ3cIRTnIUvlnypsTdUtrP9Yc,24
3
3
  flet_cli/__pyinstaller/__init__.py,sha256=KJsKpQ6uSVslADmFaOKaxCu-GOZZtcVKnti-ripD-ug,164
4
4
  flet_cli/__pyinstaller/config.py,sha256=MN2IPu53K1RDyh_KE4wIcQH8El_n4Z3fD6NO2iq8y74,20
5
5
  flet_cli/__pyinstaller/hook-flet.py,sha256=RbiFE8-7VBsY4Dwt7a9-9gW0gUFQGjOLY1-OBsZm_mI,506
@@ -9,7 +9,7 @@ flet_cli/__pyinstaller/win_utils.py,sha256=wu0G98CUMkGfloZa2LTqJE7axAZPB2-TLBOHJ
9
9
  flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py,sha256=Q5r19b95nWjDdF-D6civD6_M8jzSDIi26WBHlVJOhdY,584
10
10
  flet_cli/commands/base.py,sha256=6MTAuA7kKdaKIZI4AyWPM1TJfFCxmRj7kc7z2h6E_4k,3496
11
11
  flet_cli/commands/build.py,sha256=lDqO-O9ug9Cy5gU2oGUYDhj9_m8E4mkaytzNHEwJwcA,5741
12
- flet_cli/commands/build_base.py,sha256=p6fbdGRyKI-PW6DxuvS__HfMMaCa7CI_cOtQSMGlMtg,89329
12
+ flet_cli/commands/build_base.py,sha256=9xl3ibvLfOh5Q_ksODhKauT6IBk_v0XqjkAPoOUYkEA,93742
13
13
  flet_cli/commands/create.py,sha256=LLgxC7Sbxhy9es21YS9nmR5oGOCJjsYDCdXWztIV44A,5305
14
14
  flet_cli/commands/debug.py,sha256=7RhwJCKLVSf9_hunWGKd9vBnR9EgujCWmgs6aOzQVr4,6656
15
15
  flet_cli/commands/devices.py,sha256=7kn56lrZLN5LuG_X3IyMdSfdFa421yE4R1otTJr5Yrc,7953
@@ -32,8 +32,9 @@ flet_cli/utils/plist.py,sha256=oqBCkeUjUqPIf5y7XaE2seSx64FEs7yc2cukvbjFoSU,1135
32
32
  flet_cli/utils/processes.py,sha256=S0ErmI5x9S6RNMe89cf5M4ROIofMtjNZRQ29foUllJ4,2885
33
33
  flet_cli/utils/project_dependencies.py,sha256=kC8gZZyaGk-coNXrh6cyPM6i9RhUaXcBIvZmQ50PufY,4064
34
34
  flet_cli/utils/pyproject_toml.py,sha256=o4fAWKXMyK8vdnAO41BLI7Lt3ohMlVdlwrpaifq30Cs,1408
35
- flet_cli-0.85.3.dev0.dist-info/METADATA,sha256=fdZXwPQpRT55hGUP77yEgYe4315MjPYh1YwvigOtPII,1214
36
- flet_cli-0.85.3.dev0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
37
- flet_cli-0.85.3.dev0.dist-info/entry_points.txt,sha256=UZFR426y3mfr0wgikEFPbZ6wtGwfgykif9Obw6R7Wnc,65
38
- flet_cli-0.85.3.dev0.dist-info/top_level.txt,sha256=4_BPVAJpcNofDe3XMxajlZLBNWzWqKhRynNSBCYTKVQ,9
39
- flet_cli-0.85.3.dev0.dist-info/RECORD,,
35
+ flet_cli/utils/template_cache.py,sha256=Lf_iuk30zTfaNFbRmrc8s07w1yE-PYjdovZztoiuPzc,1596
36
+ flet_cli-0.85.3.dev1.dist-info/METADATA,sha256=5Jem3_UzRIbLp4YRt7qrHCTyxr8qshGvO4QU4EnTAw0,1214
37
+ flet_cli-0.85.3.dev1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
38
+ flet_cli-0.85.3.dev1.dist-info/entry_points.txt,sha256=UZFR426y3mfr0wgikEFPbZ6wtGwfgykif9Obw6R7Wnc,65
39
+ flet_cli-0.85.3.dev1.dist-info/top_level.txt,sha256=4_BPVAJpcNofDe3XMxajlZLBNWzWqKhRynNSBCYTKVQ,9
40
+ flet_cli-0.85.3.dev1.dist-info/RECORD,,