pythonnative 0.25.0__py3-none-any.whl → 0.26.0__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.
Files changed (44) hide show
  1. pythonnative/__init__.py +1 -1
  2. pythonnative/cli/pn.py +172 -12
  3. pythonnative/diagnostics.py +27 -0
  4. pythonnative/native_modules/app_state.py +2 -1
  5. pythonnative/native_modules/battery.py +3 -2
  6. pythonnative/native_modules/biometrics.py +2 -1
  7. pythonnative/native_modules/camera.py +16 -7
  8. pythonnative/native_modules/clipboard.py +3 -2
  9. pythonnative/native_modules/file_system.py +3 -2
  10. pythonnative/native_modules/haptics.py +7 -6
  11. pythonnative/native_modules/linking.py +62 -6
  12. pythonnative/native_modules/location.py +11 -8
  13. pythonnative/native_modules/net_info.py +2 -1
  14. pythonnative/native_modules/notifications.py +97 -6
  15. pythonnative/native_modules/permissions.py +3 -2
  16. pythonnative/native_modules/share.py +2 -1
  17. pythonnative/native_views/android.py +142 -122
  18. pythonnative/native_views/desktop.py +50 -49
  19. pythonnative/native_views/ios.py +228 -160
  20. pythonnative/project/android.py +15 -3
  21. pythonnative/project/builder.py +172 -70
  22. pythonnative/project/config.py +28 -6
  23. pythonnative/project/devices.py +291 -0
  24. pythonnative/project/doctor.py +5 -4
  25. pythonnative/project/ios.py +51 -77
  26. pythonnative/project/permissions.py +19 -1
  27. pythonnative/project/runtime_assets.py +78 -166
  28. pythonnative/templates/android_template/app/build.gradle +5 -0
  29. pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +1 -0
  30. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +88 -12
  31. pythonnative/templates/ios_template/ios_template/AppDelegate.swift +41 -17
  32. pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
  33. pythonnative/templates/ios_template/ios_template/Info.plist +0 -2
  34. pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +397 -0
  35. pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +31 -20
  36. pythonnative/templates/ios_template/ios_template/ViewController.swift +77 -198
  37. pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +72 -47
  38. {pythonnative-0.25.0.dist-info → pythonnative-0.26.0.dist-info}/METADATA +1 -1
  39. {pythonnative-0.25.0.dist-info → pythonnative-0.26.0.dist-info}/RECORD +43 -41
  40. pythonnative/templates/ios_template/ios_template/Base.lproj/Main.storyboard +0 -24
  41. {pythonnative-0.25.0.dist-info → pythonnative-0.26.0.dist-info}/WHEEL +0 -0
  42. {pythonnative-0.25.0.dist-info → pythonnative-0.26.0.dist-info}/entry_points.txt +0 -0
  43. {pythonnative-0.25.0.dist-info → pythonnative-0.26.0.dist-info}/licenses/LICENSE +0 -0
  44. {pythonnative-0.25.0.dist-info → pythonnative-0.26.0.dist-info}/top_level.txt +0 -0
@@ -62,6 +62,7 @@ from tkinter import font as tkfont
62
62
  from tkinter import ttk
63
63
  from typing import Any, Dict, List, Optional, Tuple
64
64
 
65
+ from .. import diagnostics
65
66
  from ..events import dispatch_event, event_names
66
67
  from ..gestures import make_arbiter
67
68
  from .base import ViewHandler
@@ -325,7 +326,7 @@ def _place(widget: Any) -> None:
325
326
  widget.place(in_=target, x=x + tx - sx, y=y + ty - sy, width=max(0.0, w), height=max(0.0, h))
326
327
  widget.lift()
327
328
  except Exception:
328
- pass
329
+ diagnostics.swallowed("desktop._place")
329
330
 
330
331
 
331
332
  def _register_child(parent: Any, child: Any, index: int) -> None:
@@ -375,7 +376,7 @@ def _apply_common(widget: Any, props: Dict[str, Any]) -> None:
375
376
  try:
376
377
  widget.configure(background=color)
377
378
  except Exception:
378
- pass
379
+ diagnostics.swallowed("desktop._apply_common")
379
380
  side_width_keys = (
380
381
  "border_left_width",
381
382
  "border_top_width",
@@ -406,7 +407,7 @@ def _apply_common(widget: Any, props: Dict[str, Any]) -> None:
406
407
  else:
407
408
  widget.configure(highlightthickness=0)
408
409
  except Exception:
409
- pass
410
+ diagnostics.swallowed("desktop._apply_common")
410
411
  if "test_id" in props and props["test_id"] is not None:
411
412
  # Stamped for introspection so preview-level tooling and tests
412
413
  # can locate widgets the same way Maestro does on device.
@@ -460,7 +461,7 @@ def _wire_gestures(widget: Any, specs: Any) -> None:
460
461
  try:
461
462
  widget.after(delay_ms, _poll)
462
463
  except Exception:
463
- pass
464
+ diagnostics.swallowed("desktop._wire_gestures._schedule_poll")
464
465
 
465
466
  def _on_down(event: Any) -> None:
466
467
  current = getattr(widget, "_pn_arbiter", None)
@@ -483,7 +484,7 @@ def _wire_gestures(widget: Any, specs: Any) -> None:
483
484
  widget.bind("<B1-Motion>", _on_move, add="+")
484
485
  widget.bind("<ButtonRelease-1>", _on_up, add="+")
485
486
  except Exception:
486
- pass
487
+ diagnostics.swallowed("desktop._wire_gestures")
487
488
 
488
489
 
489
490
  # ======================================================================
@@ -533,7 +534,7 @@ def _install_wheel_bindings(container: Any) -> None:
533
534
  top.bind_all("<Button-5>", _on_wheel, add="+")
534
535
  _WHEEL_BOUND = True
535
536
  except Exception:
536
- pass
537
+ diagnostics.swallowed("desktop._install_wheel_bindings")
537
538
 
538
539
 
539
540
  def _content_extent(widget: Any) -> Tuple[float, float]:
@@ -627,7 +628,7 @@ class DesktopViewHandler(ViewHandler):
627
628
  try:
628
629
  child.place_forget()
629
630
  except Exception:
630
- pass
631
+ diagnostics.swallowed("desktop.DesktopViewHandler.remove_child")
631
632
  child._pn_parent = None
632
633
 
633
634
  def destroy(self, native_view: Any) -> None:
@@ -638,7 +639,7 @@ class DesktopViewHandler(ViewHandler):
638
639
  try:
639
640
  native_view.destroy()
640
641
  except Exception:
641
- pass
642
+ diagnostics.swallowed("desktop.DesktopViewHandler.destroy")
642
643
 
643
644
  def set_frame(self, native_view: Any, x: float, y: float, width: float, height: float) -> None:
644
645
  if native_view is None:
@@ -672,7 +673,7 @@ class DesktopViewHandler(ViewHandler):
672
673
  try:
673
674
  native_view.configure(background=color)
674
675
  except Exception:
675
- pass
676
+ diagnostics.swallowed("desktop.DesktopViewHandler.set_animated_property")
676
677
 
677
678
 
678
679
  # ======================================================================
@@ -775,7 +776,7 @@ class TextHandler(DesktopViewHandler):
775
776
  try:
776
777
  label.configure(**opts)
777
778
  except Exception:
778
- pass
779
+ diagnostics.swallowed("desktop.TextHandler.apply")
779
780
  _apply_common(label, merged)
780
781
 
781
782
  def set_frame(self, native_view: Any, x: float, y: float, width: float, height: float) -> None:
@@ -784,7 +785,7 @@ class TextHandler(DesktopViewHandler):
784
785
  try:
785
786
  native_view.configure(wraplength=max(1, int(_finite(width))))
786
787
  except Exception:
787
- pass
788
+ diagnostics.swallowed("desktop.TextHandler.set_frame")
788
789
  super().set_frame(native_view, x, y, width, height)
789
790
 
790
791
  def measure_intrinsic(self, native_view: Any, max_width: float, max_height: float) -> Tuple[float, float]:
@@ -825,7 +826,7 @@ class ButtonHandler(DesktopViewHandler):
825
826
  try:
826
827
  button.configure(**opts)
827
828
  except Exception:
828
- pass
829
+ diagnostics.swallowed("desktop.ButtonHandler.apply")
829
830
  _apply_common(button, merged)
830
831
 
831
832
  def measure_intrinsic(self, native_view: Any, max_width: float, max_height: float) -> Tuple[float, float]:
@@ -873,7 +874,7 @@ class TextInputHandler(DesktopViewHandler):
873
874
  widget.delete(0, "end")
874
875
  widget.insert(0, value)
875
876
  except Exception:
876
- pass
877
+ diagnostics.swallowed("desktop.TextInputHandler._set_text")
877
878
  finally:
878
879
  widget._pn_suppress = False
879
880
 
@@ -900,7 +901,7 @@ class TextInputHandler(DesktopViewHandler):
900
901
  if not getattr(widget, "_pn_multiline", False):
901
902
  widget.bind("<Return>", _on_return)
902
903
  except Exception:
903
- pass
904
+ diagnostics.swallowed("desktop.TextInputHandler._bind")
904
905
 
905
906
  def apply(self, widget: Any, props: Dict[str, Any]) -> None:
906
907
  merged = getattr(widget, "_pn_props", props)
@@ -918,7 +919,7 @@ class TextInputHandler(DesktopViewHandler):
918
919
  try:
919
920
  widget.configure(**opts)
920
921
  except Exception:
921
- pass
922
+ diagnostics.swallowed("desktop.TextInputHandler.apply")
922
923
  if "value" in props:
923
924
  incoming = "" if props["value"] is None else str(props["value"])
924
925
  if self._current_text(widget) != incoming:
@@ -927,20 +928,20 @@ class TextInputHandler(DesktopViewHandler):
927
928
  try:
928
929
  widget.configure(highlightbackground="#c7c7cc", highlightcolor="#007aff")
929
930
  except Exception:
930
- pass
931
+ diagnostics.swallowed("desktop.TextInputHandler.apply")
931
932
 
932
933
  def command(self, native_view: Any, name: str, args: Dict[str, Any]) -> Any:
933
934
  if name == "focus":
934
935
  try:
935
936
  native_view.focus_set()
936
937
  except Exception:
937
- pass
938
+ diagnostics.swallowed("desktop.TextInputHandler.command")
938
939
  return True
939
940
  if name == "blur":
940
941
  try:
941
942
  native_view.winfo_toplevel().focus_set()
942
943
  except Exception:
943
- pass
944
+ diagnostics.swallowed("desktop.TextInputHandler.command")
944
945
  return True
945
946
  return None
946
947
 
@@ -982,7 +983,7 @@ class ImageHandler(DesktopViewHandler):
982
983
  try:
983
984
  label.configure(background=color)
984
985
  except Exception:
985
- pass
986
+ diagnostics.swallowed("desktop.ImageHandler.apply")
986
987
  if "source" in props:
987
988
  source = props.get("source")
988
989
  label._pn_pending_source = source
@@ -1021,14 +1022,14 @@ class ImageHandler(DesktopViewHandler):
1021
1022
  if path:
1022
1023
  _fire(label, "on_error", "decode failed")
1023
1024
  except Exception:
1024
- pass
1025
+ diagnostics.swallowed("desktop.ImageHandler._show_file")
1025
1026
 
1026
1027
  def _show_fallback(self, label: Any, source: Any) -> None:
1027
1028
  name = str(source).rsplit("/", 1)[-1] if source else "image"
1028
1029
  try:
1029
1030
  label.configure(image="", text=f"\U0001f5bc\n{name}", compound="center")
1030
1031
  except Exception:
1031
- pass
1032
+ diagnostics.swallowed("desktop.ImageHandler._show_fallback")
1032
1033
 
1033
1034
  def measure_intrinsic(self, native_view: Any, max_width: float, max_height: float) -> Tuple[float, float]:
1034
1035
  photo = getattr(native_view, "_pn_photo", None)
@@ -1036,7 +1037,7 @@ class ImageHandler(DesktopViewHandler):
1036
1037
  try:
1037
1038
  return (float(photo.width()), float(photo.height()))
1038
1039
  except Exception:
1039
- pass
1040
+ diagnostics.swallowed("desktop.ImageHandler.measure_intrinsic")
1040
1041
  return (64.0, 64.0)
1041
1042
 
1042
1043
 
@@ -1059,7 +1060,7 @@ class SwitchHandler(DesktopViewHandler):
1059
1060
  try:
1060
1061
  check._pn_var.set(1 if props.get("value") else 0)
1061
1062
  except Exception:
1062
- pass
1063
+ diagnostics.swallowed("desktop.SwitchHandler.apply")
1063
1064
  _apply_common(check, merged)
1064
1065
 
1065
1066
  def measure_intrinsic(self, native_view: Any, max_width: float, max_height: float) -> Tuple[float, float]:
@@ -1088,12 +1089,12 @@ class CheckboxHandler(DesktopViewHandler):
1088
1089
  try:
1089
1090
  check.configure(**opts)
1090
1091
  except Exception:
1091
- pass
1092
+ diagnostics.swallowed("desktop.CheckboxHandler.apply")
1092
1093
  if "value" in props:
1093
1094
  try:
1094
1095
  check._pn_var.set(1 if props.get("value") else 0)
1095
1096
  except Exception:
1096
- pass
1097
+ diagnostics.swallowed("desktop.CheckboxHandler.apply")
1097
1098
  _apply_common(check, merged)
1098
1099
 
1099
1100
 
@@ -1118,7 +1119,7 @@ class SliderHandler(DesktopViewHandler):
1118
1119
  try:
1119
1120
  _fire(scale, "on_change", float(scale.get()))
1120
1121
  except Exception:
1121
- pass
1122
+ diagnostics.swallowed("desktop.SliderHandler.build._command")
1122
1123
 
1123
1124
  scale.configure(command=_command)
1124
1125
  return scale
@@ -1134,13 +1135,13 @@ class SliderHandler(DesktopViewHandler):
1134
1135
  try:
1135
1136
  scale.configure(**opts)
1136
1137
  except Exception:
1137
- pass
1138
+ diagnostics.swallowed("desktop.SliderHandler.apply")
1138
1139
  if "value" in merged:
1139
1140
  scale._pn_suppress = True
1140
1141
  try:
1141
1142
  scale.set(_finite(merged.get("value")))
1142
1143
  except Exception:
1143
- pass
1144
+ diagnostics.swallowed("desktop.SliderHandler.apply")
1144
1145
  finally:
1145
1146
  scale._pn_suppress = False
1146
1147
  _apply_common(scale, merged)
@@ -1161,12 +1162,12 @@ class ProgressBarHandler(DesktopViewHandler):
1161
1162
  bar.configure(mode="indeterminate")
1162
1163
  bar.start(60)
1163
1164
  except Exception:
1164
- pass
1165
+ diagnostics.swallowed("desktop.ProgressBarHandler.apply")
1165
1166
  else:
1166
1167
  try:
1167
1168
  bar.configure(mode="determinate", value=max(0.0, min(1.0, _finite(merged.get("value", 0.0)))))
1168
1169
  except Exception:
1169
- pass
1170
+ diagnostics.swallowed("desktop.ProgressBarHandler.apply")
1170
1171
 
1171
1172
  def measure_intrinsic(self, native_view: Any, max_width: float, max_height: float) -> Tuple[float, float]:
1172
1173
  width = max_width if math.isfinite(max_width) else 200.0
@@ -1185,7 +1186,7 @@ class ActivityIndicatorHandler(DesktopViewHandler):
1185
1186
  else:
1186
1187
  bar.stop()
1187
1188
  except Exception:
1188
- pass
1189
+ diagnostics.swallowed("desktop.ActivityIndicatorHandler.apply")
1189
1190
 
1190
1191
  def measure_intrinsic(self, native_view: Any, max_width: float, max_height: float) -> Tuple[float, float]:
1191
1192
  merged = getattr(native_view, "_pn_props", {}) or {}
@@ -1228,7 +1229,7 @@ class WebViewHandler(DesktopViewHandler):
1228
1229
  try:
1229
1230
  label.configure(text=f"\U0001f310 WebView\n{target}")
1230
1231
  except Exception:
1231
- pass
1232
+ diagnostics.swallowed("desktop.WebViewHandler.apply")
1232
1233
  _apply_common(label, merged)
1233
1234
 
1234
1235
 
@@ -1272,7 +1273,7 @@ class PressableHandler(DesktopViewHandler):
1272
1273
  frame.bind("<ButtonPress-1>", _on_press_down, add="+")
1273
1274
  frame.bind("<Leave>", _on_leave, add="+")
1274
1275
  except Exception:
1275
- pass
1276
+ diagnostics.swallowed("desktop.PressableHandler._bind")
1276
1277
 
1277
1278
  @staticmethod
1278
1279
  def _cancel_long(frame: Any) -> None:
@@ -1281,7 +1282,7 @@ class PressableHandler(DesktopViewHandler):
1281
1282
  try:
1282
1283
  frame.after_cancel(after_id)
1283
1284
  except Exception:
1284
- pass
1285
+ diagnostics.swallowed("desktop.PressableHandler._cancel_long")
1285
1286
  frame._pn_long_after = None
1286
1287
 
1287
1288
 
@@ -1313,7 +1314,7 @@ class ModalHandler(DesktopViewHandler):
1313
1314
  else:
1314
1315
  frame.place_forget()
1315
1316
  except Exception:
1316
- pass
1317
+ diagnostics.swallowed("desktop.ModalHandler.apply")
1317
1318
  if visible != getattr(frame, "_pn_was_visible", None):
1318
1319
  frame._pn_was_visible = visible
1319
1320
  if visible:
@@ -1357,7 +1358,7 @@ class PortalHandler(DesktopViewHandler):
1357
1358
  try:
1358
1359
  child.place_forget()
1359
1360
  except Exception:
1360
- pass
1361
+ diagnostics.swallowed("desktop.PortalHandler.remove_child")
1361
1362
 
1362
1363
  def set_frame(self, native_view: Any, x: float, y: float, width: float, height: float) -> None:
1363
1364
  # The portal frame itself stays unmapped; only children render.
@@ -1377,7 +1378,7 @@ class TabBarHandler(DesktopViewHandler):
1377
1378
  try:
1378
1379
  frame.configure(highlightbackground="#c6c6c8", highlightcolor="#c6c6c8")
1379
1380
  except Exception:
1380
- pass
1381
+ diagnostics.swallowed("desktop.TabBarHandler.build")
1381
1382
  frame._pn_buttons = []
1382
1383
  return frame
1383
1384
 
@@ -1389,7 +1390,7 @@ class TabBarHandler(DesktopViewHandler):
1389
1390
  try:
1390
1391
  button.destroy()
1391
1392
  except Exception:
1392
- pass
1393
+ diagnostics.swallowed("desktop.TabBarHandler.apply")
1393
1394
  buttons: List[Any] = []
1394
1395
  for item in items:
1395
1396
  name = item.get("name")
@@ -1428,7 +1429,7 @@ class TabBarHandler(DesktopViewHandler):
1428
1429
  try:
1429
1430
  button.place(x=i * each, y=0, width=each, height=frame_h)
1430
1431
  except Exception:
1431
- pass
1432
+ diagnostics.swallowed("desktop.TabBarHandler._layout_buttons")
1432
1433
 
1433
1434
  def set_frame(self, native_view: Any, x: float, y: float, width: float, height: float) -> None:
1434
1435
  native_view._pn_size = (max(0.0, _finite(width)), max(0.0, _finite(height)))
@@ -1458,7 +1459,7 @@ class PickerHandler(DesktopViewHandler):
1458
1459
  try:
1459
1460
  combo.bind("<<ComboboxSelected>>", _on_select)
1460
1461
  except Exception:
1461
- pass
1462
+ diagnostics.swallowed("desktop.PickerHandler.build")
1462
1463
  return combo
1463
1464
 
1464
1465
  def apply(self, combo: Any, props: Dict[str, Any]) -> None:
@@ -1469,7 +1470,7 @@ class PickerHandler(DesktopViewHandler):
1469
1470
  try:
1470
1471
  combo.configure(values=labels)
1471
1472
  except Exception:
1472
- pass
1473
+ diagnostics.swallowed("desktop.PickerHandler.apply")
1473
1474
  if "value" in merged:
1474
1475
  target = merged.get("value")
1475
1476
  for i, item in enumerate(items):
@@ -1477,7 +1478,7 @@ class PickerHandler(DesktopViewHandler):
1477
1478
  try:
1478
1479
  combo.current(i)
1479
1480
  except Exception:
1480
- pass
1481
+ diagnostics.swallowed("desktop.PickerHandler.apply")
1481
1482
  break
1482
1483
 
1483
1484
  def measure_intrinsic(self, native_view: Any, max_width: float, max_height: float) -> Tuple[float, float]:
@@ -1499,7 +1500,7 @@ class SegmentedControlHandler(DesktopViewHandler):
1499
1500
  try:
1500
1501
  button.destroy()
1501
1502
  except Exception:
1502
- pass
1503
+ diagnostics.swallowed("desktop.SegmentedControlHandler.apply")
1503
1504
  buttons: List[Any] = []
1504
1505
  for i, label in enumerate(segments):
1505
1506
  is_active = i == selected
@@ -1522,7 +1523,7 @@ class SegmentedControlHandler(DesktopViewHandler):
1522
1523
  state = "normal" if merged.get("enabled", True) else "disabled"
1523
1524
  button.configure({"highlightbackground": tint, "state": state})
1524
1525
  except Exception:
1525
- pass
1526
+ diagnostics.swallowed("desktop.SegmentedControlHandler.apply")
1526
1527
  buttons.append(button)
1527
1528
  frame._pn_buttons = buttons
1528
1529
  self._layout_buttons(frame)
@@ -1540,7 +1541,7 @@ class SegmentedControlHandler(DesktopViewHandler):
1540
1541
  try:
1541
1542
  button.place(x=i * each, y=0, width=each, height=frame_h)
1542
1543
  except Exception:
1543
- pass
1544
+ diagnostics.swallowed("desktop.SegmentedControlHandler._layout_buttons")
1544
1545
 
1545
1546
  def set_frame(self, native_view: Any, x: float, y: float, width: float, height: float) -> None:
1546
1547
  native_view._pn_size = (max(0.0, _finite(width)), max(0.0, _finite(height)))
@@ -1560,7 +1561,7 @@ class DatePickerHandler(DesktopViewHandler):
1560
1561
  try:
1561
1562
  entry.bind("<KeyRelease>", _on_key)
1562
1563
  except Exception:
1563
- pass
1564
+ diagnostics.swallowed("desktop.DatePickerHandler.build")
1564
1565
  return entry
1565
1566
 
1566
1567
  def apply(self, entry: Any, props: Dict[str, Any]) -> None:
@@ -1569,7 +1570,7 @@ class DatePickerHandler(DesktopViewHandler):
1569
1570
  try:
1570
1571
  entry.configure(state="normal" if merged.get("enabled", True) else "disabled")
1571
1572
  except Exception:
1572
- pass
1573
+ diagnostics.swallowed("desktop.DatePickerHandler.apply")
1573
1574
  if "value" in props:
1574
1575
  incoming = "" if props["value"] is None else str(props["value"])
1575
1576
  try:
@@ -1580,11 +1581,11 @@ class DatePickerHandler(DesktopViewHandler):
1580
1581
  entry.insert(0, incoming)
1581
1582
  entry.configure(state=state)
1582
1583
  except Exception:
1583
- pass
1584
+ diagnostics.swallowed("desktop.DatePickerHandler.apply")
1584
1585
  try:
1585
1586
  entry.configure(highlightbackground="#c7c7cc", highlightcolor="#007aff")
1586
1587
  except Exception:
1587
- pass
1588
+ diagnostics.swallowed("desktop.DatePickerHandler.apply")
1588
1589
 
1589
1590
 
1590
1591
  # ======================================================================