synodic-client 0.0.1.dev75__tar.gz → 0.0.1.dev76__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.
Files changed (102) hide show
  1. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/PKG-INFO +1 -1
  2. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/pyproject.toml +1 -1
  3. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/action_card.py +19 -0
  4. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/install.py +13 -8
  5. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/operations/schema.py +19 -8
  6. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/LICENSE.md +0 -0
  7. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/README.md +0 -0
  8. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/__init__.py +0 -0
  9. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/__main__.py +0 -0
  10. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/__init__.py +0 -0
  11. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/bootstrap.py +0 -0
  12. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/config_store.py +0 -0
  13. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/data.py +0 -0
  14. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/debug.py +0 -0
  15. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/icon.py +0 -0
  16. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/init.py +0 -0
  17. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/instance.py +0 -0
  18. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/package_state.py +0 -0
  19. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/qt.py +0 -0
  20. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/schema.py +0 -0
  21. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/__init__.py +0 -0
  22. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/card.py +0 -0
  23. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/install_workers.py +0 -0
  24. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/log_panel.py +0 -0
  25. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/plugin_row.py +0 -0
  26. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/projects.py +0 -0
  27. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/schema.py +0 -0
  28. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/screen.py +0 -0
  29. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/settings.py +0 -0
  30. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/sidebar.py +0 -0
  31. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/spinner.py +0 -0
  32. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/tool_update_controller.py +0 -0
  33. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/tray.py +0 -0
  34. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/screen/update_banner.py +0 -0
  35. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/theme.py +0 -0
  36. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/update_controller.py +0 -0
  37. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/update_model.py +0 -0
  38. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/uri.py +0 -0
  39. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/application/workers.py +0 -0
  40. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/cli/__init__.py +0 -0
  41. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/cli/config.py +0 -0
  42. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/cli/context.py +0 -0
  43. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/cli/debug.py +0 -0
  44. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/cli/output.py +0 -0
  45. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/cli/project.py +0 -0
  46. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/cli/tool.py +0 -0
  47. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/cli/update.py +0 -0
  48. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/client.py +0 -0
  49. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/config.py +0 -0
  50. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/logging.py +0 -0
  51. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/operations/__init__.py +0 -0
  52. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/operations/bootstrap.py +0 -0
  53. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/operations/config.py +0 -0
  54. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/operations/install.py +0 -0
  55. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/operations/project.py +0 -0
  56. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/operations/tool.py +0 -0
  57. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/operations/update.py +0 -0
  58. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/protocol.py +0 -0
  59. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/py.typed +0 -0
  60. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/resolution.py +0 -0
  61. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/schema.py +0 -0
  62. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/startup.py +0 -0
  63. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/subprocess_patch.py +0 -0
  64. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/synodic_client/updater.py +0 -0
  65. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/__init__.py +0 -0
  66. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/conftest.py +0 -0
  67. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/__init__.py +0 -0
  68. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/operations/__init__.py +0 -0
  69. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/operations/test_config.py +0 -0
  70. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/operations/test_install.py +0 -0
  71. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/operations/test_project.py +0 -0
  72. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/operations/test_tool.py +0 -0
  73. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/operations/test_update.py +0 -0
  74. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/__init__.py +0 -0
  75. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/conftest.py +0 -0
  76. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_action_card.py +0 -0
  77. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_gather_packages.py +0 -0
  78. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_install_preview.py +0 -0
  79. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_log_panel.py +0 -0
  80. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_logging.py +0 -0
  81. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_preview_model.py +0 -0
  82. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_settings.py +0 -0
  83. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_sidebar.py +0 -0
  84. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_tray_window_show.py +0 -0
  85. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_update_banner.py +0 -0
  86. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_update_controller.py +0 -0
  87. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/qt/test_update_feedback.py +0 -0
  88. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_cli.py +0 -0
  89. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_client_updater.py +0 -0
  90. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_client_version.py +0 -0
  91. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_config.py +0 -0
  92. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_examples.py +0 -0
  93. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_init.py +0 -0
  94. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_install.py +0 -0
  95. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_resolution.py +0 -0
  96. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_updater.py +0 -0
  97. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_uri.py +0 -0
  98. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/test_workers.py +0 -0
  99. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/windows/__init__.py +0 -0
  100. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/windows/conftest.py +0 -0
  101. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/windows/test_protocol.py +0 -0
  102. {synodic_client-0.0.1.dev75 → synodic_client-0.0.1.dev76}/tests/unit/windows/test_startup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: synodic_client
3
- Version: 0.0.1.dev75
3
+ Version: 0.0.1.dev76
4
4
  Author-Email: Synodic Software <contact@synodic.software>
5
5
  License: LGPL-3.0-or-later
6
6
  Project-URL: homepage, https://github.com/synodic/synodic-client
@@ -15,7 +15,7 @@ dependencies = [
15
15
  "velopack>=0.0.1444.dev49733",
16
16
  "typer>=0.24.1",
17
17
  ]
18
- version = "0.0.1.dev75"
18
+ version = "0.0.1.dev76"
19
19
 
20
20
  [project.license]
21
21
  text = "LGPL-3.0-or-later"
@@ -632,6 +632,7 @@ class ActionCardList(QWidget):
632
632
 
633
633
  self._cards: list[ActionCard] = []
634
634
  self._action_map: dict[SetupAction, ActionCard] = {}
635
+ self._index_map: dict[int, ActionCard] = {}
635
636
 
636
637
  # ------------------------------------------------------------------
637
638
  # Skeleton loading
@@ -683,6 +684,14 @@ class ActionCardList(QWidget):
683
684
  self._cards.append(card)
684
685
  self._action_map[act] = card
685
686
 
687
+ # Build original-index → card mapping so callers can look up by
688
+ # the action index porringer emits, which is independent of the
689
+ # display sort order.
690
+ for original_index, act in enumerate(actions):
691
+ card = self._action_map.get(act)
692
+ if card is not None:
693
+ self._index_map[original_index] = card
694
+
686
695
  # ------------------------------------------------------------------
687
696
  # Card lookup
688
697
  # ------------------------------------------------------------------
@@ -697,6 +706,15 @@ class ActionCardList(QWidget):
697
706
  """Return the number of cards (including skeletons)."""
698
707
  return len(self._cards)
699
708
 
709
+ def card_for_action_index(self, action_index: int) -> ActionCard | None:
710
+ """Return the card for the given original action index.
711
+
712
+ The index corresponds to the action's position in the unsorted
713
+ list passed to :meth:`populate`, matching the indices emitted
714
+ by porringer's ``ActionCompletedEvent``.
715
+ """
716
+ return self._index_map.get(action_index)
717
+
700
718
  def get_card(self, action: SetupAction) -> ActionCard | None:
701
719
  """Look up the card for a given action.
702
720
 
@@ -727,3 +745,4 @@ class ActionCardList(QWidget):
727
745
  card.deleteLater()
728
746
  self._cards.clear()
729
747
  self._action_map.clear()
748
+ self._index_map.clear()
@@ -638,7 +638,7 @@ class SetupPreviewWidget(QWidget):
638
638
  # Update the card widget
639
639
  if m.preview and 0 <= row < len(m.preview.actions):
640
640
  action = m.preview.actions[row]
641
- card = self._card_list.get_card(action)
641
+ card = self._card_list.card_for_action_index(row)
642
642
  if card is not None:
643
643
  card.set_check_result(result, status)
644
644
 
@@ -679,15 +679,20 @@ class SetupPreviewWidget(QWidget):
679
679
  finalized,
680
680
  )
681
681
 
682
- # Compute summary
682
+ # Compute summary using the shared operations-layer classifier
683
+ from collections import Counter
684
+
685
+ from synodic_client.operations.schema import classify_status
686
+
683
687
  total = len(m.action_states)
684
- needed = sum(1 for s in m.action_states if s.status == 'Needed')
688
+ counts = Counter(classify_status(s.status) for s in m.action_states)
689
+ needed = counts.get('needed', 0)
690
+ satisfied = counts.get('satisfied', 0)
691
+ pending = counts.get('pending', 0)
692
+ ready = counts.get('ready', 0)
693
+ unavailable = counts.get('unavailable', 0)
694
+ failed = counts.get('failed', 0)
685
695
  upgradable = len(m.upgradable_keys)
686
- unavailable = sum(1 for s in m.action_states if s.status == 'Not installed')
687
- failed = sum(1 for s in m.action_states if s.status == 'Failed')
688
- pending = sum(1 for s in m.action_states if s.status == 'Pending')
689
- ready = sum(1 for s in m.action_states if s.status == 'Ready')
690
- satisfied = total - needed - upgradable - unavailable - failed - pending - ready
691
696
 
692
697
  parts: list[str] = []
693
698
  _counts: list[tuple[int, str]] = [
@@ -50,19 +50,30 @@ def resolve_action_status(result: SetupActionResult, action: SetupAction) -> str
50
50
  return 'Needed'
51
51
 
52
52
 
53
+ _STATUS_BUCKETS: dict[str, str] = {
54
+ 'Needed': 'needed',
55
+ 'Pending': 'pending',
56
+ 'Ready': 'ready',
57
+ 'Not installed': 'unavailable',
58
+ 'Failed': 'failed',
59
+ 'Already installed': 'satisfied',
60
+ 'Already latest': 'satisfied',
61
+ }
62
+
63
+
53
64
  def classify_status(status: str) -> str:
54
65
  """Classify a resolved status string into a summary bucket.
55
66
 
56
- Returns one of ``'needed'``, ``'satisfied'``, ``'pending'``, or
57
- ``'unknown'``. Upgradability is determined separately from skip
58
- reason, so it is not included here.
67
+ Returns one of ``'needed'``, ``'satisfied'``, ``'pending'``,
68
+ ``'ready'``, ``'unavailable'``, ``'failed'``, or ``'unknown'``.
69
+ Upgradability is determined separately from skip reason, so it
70
+ is not included here.
59
71
  """
60
- if status == 'Needed':
61
- return 'needed'
62
- if '\u2713' in status or status in {'Already installed', 'Already latest'}:
72
+ bucket = _STATUS_BUCKETS.get(status)
73
+ if bucket is not None:
74
+ return bucket
75
+ if '\u2713' in status:
63
76
  return 'satisfied'
64
- if status == 'Pending':
65
- return 'pending'
66
77
  return 'unknown'
67
78
 
68
79