pycforge 0.15.2__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 (221) hide show
  1. pycforge/__init__.py +8 -0
  2. pycforge/__main__.py +2 -0
  3. pycforge/_version.py +1 -0
  4. pycforge/converter/__init__.py +0 -0
  5. pycforge/converter/analysis/__init__.py +5 -0
  6. pycforge/converter/analysis/functions.py +723 -0
  7. pycforge/converter/analysis/model.py +158 -0
  8. pycforge/converter/analysis/planning.py +464 -0
  9. pycforge/converter/analysis/stage.py +1976 -0
  10. pycforge/converter/analysis/symbols.py +237 -0
  11. pycforge/converter/analysis/validation.py +2166 -0
  12. pycforge/converter/c_output/__init__.py +2 -0
  13. pycforge/converter/c_output/conformance.py +297 -0
  14. pycforge/converter/c_output/renderer.py +220 -0
  15. pycforge/converter/conditional_regions/__init__.py +71 -0
  16. pycforge/converter/conditional_regions/analysis.py +481 -0
  17. pycforge/converter/conditional_regions/lowering.py +579 -0
  18. pycforge/converter/conditional_regions/model.py +243 -0
  19. pycforge/converter/conditional_regions/validation.py +690 -0
  20. pycforge/converter/containers/__init__.py +19 -0
  21. pycforge/converter/containers/analysis.py +542 -0
  22. pycforge/converter/containers/lowering.py +290 -0
  23. pycforge/converter/containers/model.py +146 -0
  24. pycforge/converter/contracts/__init__.py +0 -0
  25. pycforge/converter/contracts/configuration.py +178 -0
  26. pycforge/converter/contracts/identifiers.py +68 -0
  27. pycforge/converter/contracts/versions.py +71 -0
  28. pycforge/converter/core/__init__.py +0 -0
  29. pycforge/converter/core/artifact_io.py +87 -0
  30. pycforge/converter/core/cancellation.py +7 -0
  31. pycforge/converter/core/canonicalization.py +254 -0
  32. pycforge/converter/core/context.py +13 -0
  33. pycforge/converter/core/diagnostics.py +95 -0
  34. pycforge/converter/core/enums.py +23 -0
  35. pycforge/converter/core/fingerprint.py +22 -0
  36. pycforge/converter/core/pipeline.py +8 -0
  37. pycforge/converter/core/progress.py +25 -0
  38. pycforge/converter/core/request.py +50 -0
  39. pycforge/converter/core/resource_policy.py +31 -0
  40. pycforge/converter/core/result.py +23 -0
  41. pycforge/converter/core/serialization.py +36 -0
  42. pycforge/converter/core/stage.py +10 -0
  43. pycforge/converter/core/stage_artifact.py +80 -0
  44. pycforge/converter/core/stage_outcome.py +15 -0
  45. pycforge/converter/decision_trace/__init__.py +0 -0
  46. pycforge/converter/decision_trace/recorder.py +52 -0
  47. pycforge/converter/facade.py +459 -0
  48. pycforge/converter/frontend/__init__.py +4 -0
  49. pycforge/converter/frontend/normalizer.py +59 -0
  50. pycforge/converter/frontend/parser.py +20 -0
  51. pycforge/converter/frontend/source_document.py +93 -0
  52. pycforge/converter/frontend/stages.py +518 -0
  53. pycforge/converter/frontend/validation.py +76 -0
  54. pycforge/converter/io/__init__.py +0 -0
  55. pycforge/converter/io/atomic_writer.py +33 -0
  56. pycforge/converter/ir/__init__.py +1 -0
  57. pycforge/converter/ir/c_ir/__init__.py +4 -0
  58. pycforge/converter/ir/c_ir/builder.py +26 -0
  59. pycforge/converter/ir/c_ir/model.py +318 -0
  60. pycforge/converter/ir/c_ir/serialization.py +88 -0
  61. pycforge/converter/ir/c_ir/validation.py +834 -0
  62. pycforge/converter/ir/python_ir/__init__.py +17 -0
  63. pycforge/converter/ir/python_ir/nodes.py +86 -0
  64. pycforge/converter/keyword_calls/__init__.py +68 -0
  65. pycforge/converter/keyword_calls/analysis.py +458 -0
  66. pycforge/converter/keyword_calls/lowering.py +271 -0
  67. pycforge/converter/keyword_calls/model.py +304 -0
  68. pycforge/converter/keyword_calls/validation.py +802 -0
  69. pycforge/converter/keyword_only_calls/__init__.py +68 -0
  70. pycforge/converter/keyword_only_calls/analysis.py +640 -0
  71. pycforge/converter/keyword_only_calls/lowering.py +376 -0
  72. pycforge/converter/keyword_only_calls/model.py +328 -0
  73. pycforge/converter/keyword_only_calls/validation.py +1357 -0
  74. pycforge/converter/lowering.py +1000 -0
  75. pycforge/converter/modules/__init__.py +13 -0
  76. pycforge/converter/modules/analysis.py +1250 -0
  77. pycforge/converter/modules/lowering.py +200 -0
  78. pycforge/converter/modules/model.py +73 -0
  79. pycforge/converter/modules/stage.py +192 -0
  80. pycforge/converter/numeric_semantics/__init__.py +23 -0
  81. pycforge/converter/numeric_semantics/analysis.py +420 -0
  82. pycforge/converter/numeric_semantics/lowering.py +153 -0
  83. pycforge/converter/numeric_semantics/model.py +123 -0
  84. pycforge/converter/records/__init__.py +34 -0
  85. pycforge/converter/records/analysis.py +1394 -0
  86. pycforge/converter/records/lowering.py +393 -0
  87. pycforge/converter/records/model.py +319 -0
  88. pycforge/converter/rules/__init__.py +3 -0
  89. pycforge/converter/support_templates/__init__.py +49 -0
  90. pycforge/converter/support_templates/assembly.py +106 -0
  91. pycforge/converter/support_templates/factories.py +348 -0
  92. pycforge/converter/support_templates/model.py +159 -0
  93. pycforge/converter/support_templates/registry.py +388 -0
  94. pycforge/converter/telemetry/__init__.py +0 -0
  95. pycforge/converter/telemetry/sink.py +39 -0
  96. pycforge/ide/__init__.py +19 -0
  97. pycforge/ide/__main__.py +5 -0
  98. pycforge/ide/_worker_event_codec.py +276 -0
  99. pycforge/ide/_worker_protocol_json.py +197 -0
  100. pycforge/ide/_worker_protocol_types.py +90 -0
  101. pycforge/ide/_worker_request_codec.py +200 -0
  102. pycforge/ide/_worker_request_data.py +260 -0
  103. pycforge/ide/_worker_result_data.py +343 -0
  104. pycforge/ide/action_contract.py +469 -0
  105. pycforge/ide/action_validation.py +229 -0
  106. pycforge/ide/command_palette.py +223 -0
  107. pycforge/ide/controller.py +904 -0
  108. pycforge/ide/controller_conversion.py +546 -0
  109. pycforge/ide/controller_io.py +205 -0
  110. pycforge/ide/editor.py +951 -0
  111. pycforge/ide/editor_commands_qt.py +274 -0
  112. pycforge/ide/editor_lexical.py +43 -0
  113. pycforge/ide/editor_sidebars.py +236 -0
  114. pycforge/ide/editor_syntax.py +243 -0
  115. pycforge/ide/find_replace.py +535 -0
  116. pycforge/ide/icons.py +91 -0
  117. pycforge/ide/io_service.py +196 -0
  118. pycforge/ide/model.py +164 -0
  119. pycforge/ide/panels.py +903 -0
  120. pycforge/ide/positions.py +220 -0
  121. pycforge/ide/process_worker.py +130 -0
  122. pycforge/ide/qt.py +230 -0
  123. pycforge/ide/qt_actions.py +418 -0
  124. pycforge/ide/qt_close.py +169 -0
  125. pycforge/ide/qt_command_palette.py +297 -0
  126. pycforge/ide/qt_contract.py +220 -0
  127. pycforge/ide/qt_documents.py +590 -0
  128. pycforge/ide/qt_editor_buffers.py +113 -0
  129. pycforge/ide/qt_editor_surfaces.py +112 -0
  130. pycforge/ide/qt_menus.py +324 -0
  131. pycforge/ide/qt_projection.py +500 -0
  132. pycforge/ide/qt_shell.py +348 -0
  133. pycforge/ide/qt_shell_interactions.py +320 -0
  134. pycforge/ide/qt_state.py +393 -0
  135. pycforge/ide/qt_workspace_features.py +398 -0
  136. pycforge/ide/qt_workspace_navigation.py +208 -0
  137. pycforge/ide/qt_workspace_observers.py +173 -0
  138. pycforge/ide/qt_workspace_panels.py +545 -0
  139. pycforge/ide/qt_workspace_widgets.py +228 -0
  140. pycforge/ide/resources/icons/about.svg +1 -0
  141. pycforge/ide/resources/icons/add-document.svg +1 -0
  142. pycforge/ide/resources/icons/brand-mark.svg +1 -0
  143. pycforge/ide/resources/icons/bundle-search.svg +1 -0
  144. pycforge/ide/resources/icons/cancel.svg +1 -0
  145. pycforge/ide/resources/icons/check.svg +1 -0
  146. pycforge/ide/resources/icons/chevron-right.svg +1 -0
  147. pycforge/ide/resources/icons/close.svg +1 -0
  148. pycforge/ide/resources/icons/collapse-all.svg +1 -0
  149. pycforge/ide/resources/icons/command-palette.svg +1 -0
  150. pycforge/ide/resources/icons/convert.svg +1 -0
  151. pycforge/ide/resources/icons/copy.svg +1 -0
  152. pycforge/ide/resources/icons/cut.svg +1 -0
  153. pycforge/ide/resources/icons/decision-trace.svg +1 -0
  154. pycforge/ide/resources/icons/details.svg +1 -0
  155. pycforge/ide/resources/icons/diagnostics.svg +1 -0
  156. pycforge/ide/resources/icons/duplicate-line.svg +1 -0
  157. pycforge/ide/resources/icons/exit.svg +1 -0
  158. pycforge/ide/resources/icons/expand-all.svg +1 -0
  159. pycforge/ide/resources/icons/export.svg +1 -0
  160. pycforge/ide/resources/icons/find.svg +1 -0
  161. pycforge/ide/resources/icons/go-to-line.svg +1 -0
  162. pycforge/ide/resources/icons/go-to-output.svg +1 -0
  163. pycforge/ide/resources/icons/go-to-source.svg +1 -0
  164. pycforge/ide/resources/icons/history.svg +1 -0
  165. pycforge/ide/resources/icons/indent.svg +1 -0
  166. pycforge/ide/resources/icons/link-c.svg +1 -0
  167. pycforge/ide/resources/icons/mappings.svg +1 -0
  168. pycforge/ide/resources/icons/module.svg +1 -0
  169. pycforge/ide/resources/icons/move-down.svg +1 -0
  170. pycforge/ide/resources/icons/move-line-down.svg +1 -0
  171. pycforge/ide/resources/icons/move-line-up.svg +1 -0
  172. pycforge/ide/resources/icons/move-up.svg +1 -0
  173. pycforge/ide/resources/icons/next.svg +1 -0
  174. pycforge/ide/resources/icons/open.svg +1 -0
  175. pycforge/ide/resources/icons/outdent.svg +1 -0
  176. pycforge/ide/resources/icons/outline.svg +1 -0
  177. pycforge/ide/resources/icons/paste.svg +1 -0
  178. pycforge/ide/resources/icons/previous.svg +1 -0
  179. pycforge/ide/resources/icons/primary-module.svg +1 -0
  180. pycforge/ide/resources/icons/redo.svg +1 -0
  181. pycforge/ide/resources/icons/remove-document.svg +1 -0
  182. pycforge/ide/resources/icons/replace.svg +1 -0
  183. pycforge/ide/resources/icons/save-as.svg +1 -0
  184. pycforge/ide/resources/icons/save.svg +1 -0
  185. pycforge/ide/resources/icons/select-all.svg +1 -0
  186. pycforge/ide/resources/icons/settings.svg +1 -0
  187. pycforge/ide/resources/icons/show-c.svg +1 -0
  188. pycforge/ide/resources/icons/split-view.svg +1 -0
  189. pycforge/ide/resources/icons/summary.svg +1 -0
  190. pycforge/ide/resources/icons/telemetry.svg +1 -0
  191. pycforge/ide/resources/icons/toggle-comment.svg +1 -0
  192. pycforge/ide/resources/icons/toggle-fold.svg +1 -0
  193. pycforge/ide/resources/icons/undo.svg +1 -0
  194. pycforge/ide/resources/icons/whitespace.svg +1 -0
  195. pycforge/ide/revisions.py +400 -0
  196. pycforge/ide/search_service.py +280 -0
  197. pycforge/ide/session_history.py +150 -0
  198. pycforge/ide/source_editing.py +417 -0
  199. pycforge/ide/source_structure.py +558 -0
  200. pycforge/ide/source_structure_async.py +191 -0
  201. pycforge/ide/supervisor.py +503 -0
  202. pycforge/ide/theme.py +119 -0
  203. pycforge/ide/theme_stylesheet.py +598 -0
  204. pycforge/ide/theme_workspace_stylesheet.py +155 -0
  205. pycforge/ide/visual_tokens.py +142 -0
  206. pycforge/ide/worker_protocol.py +80 -0
  207. pycforge/ide/workspace_search.py +462 -0
  208. pycforge/ide/workspace_session.py +256 -0
  209. pycforge/laboratory/__init__.py +6 -0
  210. pycforge/laboratory/audits.py +2244 -0
  211. pycforge/laboratory/checkpoint_e.py +2685 -0
  212. pycforge/laboratory/cli.py +119 -0
  213. pycforge/laboratory/exit_codes.py +11 -0
  214. pycforge/laboratory/keyword_audit.py +661 -0
  215. pycforge/laboratory/keyword_only_audit.py +481 -0
  216. pycforge-0.15.2.dist-info/METADATA +209 -0
  217. pycforge-0.15.2.dist-info/RECORD +221 -0
  218. pycforge-0.15.2.dist-info/WHEEL +5 -0
  219. pycforge-0.15.2.dist-info/entry_points.txt +5 -0
  220. pycforge-0.15.2.dist-info/licenses/LICENSE +674 -0
  221. pycforge-0.15.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,155 @@
1
+ """Phase 15C editor-workspace additions to the PyCForge visual system."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from string import Template
6
+
7
+ from .visual_tokens import (
8
+ PYCFORGE_COLORS,
9
+ PyCForgeColors,
10
+ color_tokens,
11
+ )
12
+
13
+
14
+ _WORKSPACE_QSS = Template(
15
+ r"""
16
+ QTabBar#SourceDocumentTabs {
17
+ background: qlineargradient(x1:0,y1:0,x2:1,y2:0,
18
+ stop:0 ${void},stop:0.55 ${canvas},stop:1 ${surface_raised});
19
+ border: 1px solid ${border};
20
+ border-bottom: 1px solid ${border_strong};
21
+ border-radius: 7px;
22
+ padding: 3px 4px 0 4px;
23
+ }
24
+ QTabBar#SourceDocumentTabs::tab {
25
+ color: ${text_soft};
26
+ background: ${surface};
27
+ border: 1px solid ${border};
28
+ border-bottom: 2px solid ${border};
29
+ border-top-left-radius: 6px;
30
+ border-top-right-radius: 6px;
31
+ padding: 7px 12px;
32
+ min-width: 110px;
33
+ }
34
+ QTabBar#SourceDocumentTabs::tab:hover {
35
+ color: #FFFFFF;
36
+ background: ${surface_hover};
37
+ border-bottom: 2px solid ${blue};
38
+ }
39
+ QTabBar#SourceDocumentTabs::tab:selected {
40
+ color: #FFFFFF;
41
+ background: qlineargradient(x1:0,y1:0,x2:1,y2:0,
42
+ stop:0 ${selection},stop:0.75 ${violet_dim},stop:1 ${warm_dim});
43
+ border-color: ${blue};
44
+ border-bottom: 2px solid ${violet_bright};
45
+ }
46
+ QTabBar#SourceDocumentTabs:focus {
47
+ border: 1px solid ${focus_ring};
48
+ border-bottom: 2px solid ${violet};
49
+ }
50
+ QWidget#SourceBreadcrumbBar {
51
+ background: qlineargradient(x1:0,y1:0,x2:1,y2:0,
52
+ stop:0 ${canvas},stop:0.72 ${surface},stop:1 ${violet_dim});
53
+ border: 1px solid ${border};
54
+ border-left: 2px solid ${blue};
55
+ border-radius: 6px;
56
+ }
57
+ QToolButton#BreadcrumbButton {
58
+ color: ${text_soft};
59
+ background: transparent;
60
+ border: 1px solid transparent;
61
+ border-radius: 5px;
62
+ padding: 3px 7px;
63
+ }
64
+ QToolButton#BreadcrumbButton:hover {
65
+ color: #FFFFFF;
66
+ background: ${surface_hover};
67
+ border-color: ${blue_dim};
68
+ }
69
+ QToolButton#BreadcrumbButton:focus {
70
+ color: #FFFFFF;
71
+ border: 1px solid ${focus_ring};
72
+ background: ${selection};
73
+ }
74
+ QLabel#BreadcrumbSeparator {
75
+ color: ${violet_bright};
76
+ padding: 0 1px;
77
+ }
78
+ QDialog#CommandPaletteDialog {
79
+ background: qlineargradient(x1:0,y1:0,x2:0,y2:1,
80
+ stop:0 ${surface_raised},stop:0.55 ${canvas},stop:1 ${void});
81
+ border: 1px solid ${blue};
82
+ border-radius: 10px;
83
+ }
84
+ QLineEdit#CommandPaletteQuery {
85
+ color: #FFFFFF;
86
+ background: ${void};
87
+ border: 1px solid ${blue};
88
+ border-bottom: 2px solid ${violet};
89
+ border-radius: 8px;
90
+ padding: 9px 11px;
91
+ }
92
+ QTreeWidget#CommandPaletteResults,
93
+ QTreeWidget#BundleSearchTree,
94
+ QTreeWidget#OutlineTree,
95
+ QTreeWidget#SessionHistoryTree {
96
+ color: ${text_soft};
97
+ background: ${void};
98
+ border: 1px solid ${border_strong};
99
+ border-radius: 7px;
100
+ }
101
+ QTreeWidget#CommandPaletteResults::item,
102
+ QTreeWidget#BundleSearchTree::item,
103
+ QTreeWidget#OutlineTree::item,
104
+ QTreeWidget#SessionHistoryTree::item {
105
+ border-bottom: 1px solid ${surface_raised};
106
+ padding: 6px 5px;
107
+ }
108
+ QTreeWidget#CommandPaletteResults::item:hover,
109
+ QTreeWidget#BundleSearchTree::item:hover,
110
+ QTreeWidget#OutlineTree::item:hover,
111
+ QTreeWidget#SessionHistoryTree::item:hover {
112
+ color: #FFFFFF;
113
+ background: ${surface_hover};
114
+ }
115
+ QTreeWidget#CommandPaletteResults::item:selected,
116
+ QTreeWidget#BundleSearchTree::item:selected,
117
+ QTreeWidget#OutlineTree::item:selected,
118
+ QTreeWidget#SessionHistoryTree::item:selected {
119
+ color: #FFFFFF;
120
+ background: qlineargradient(x1:0,y1:0,x2:1,y2:0,
121
+ stop:0 ${selection},stop:1 ${violet_dim});
122
+ border-left: 3px solid ${blue_bright};
123
+ }
124
+ QWidget#BundleSearchView,
125
+ QWidget#OutlineView,
126
+ QWidget#SessionHistoryView {
127
+ background: qlineargradient(x1:0,y1:0,x2:0,y2:1,
128
+ stop:0 ${surface_raised},stop:1 ${canvas});
129
+ }
130
+ QFrame#SourceSplitSurface {
131
+ background: ${void};
132
+ border: 1px solid ${border};
133
+ border-top: 2px solid ${blue_dim};
134
+ border-radius: 7px;
135
+ }
136
+ QLabel#GeneratedCWindowLabel {
137
+ color: ${warning_bright};
138
+ background: ${warning_dim};
139
+ border: 1px solid ${warm_dim};
140
+ border-radius: 7px;
141
+ padding: 3px 8px;
142
+ }
143
+ """
144
+ )
145
+
146
+
147
+ def build_workspace_stylesheet(
148
+ colors: PyCForgeColors = PYCFORGE_COLORS,
149
+ ) -> str:
150
+ """Return deterministic styling for the Phase 15C workspace surfaces."""
151
+
152
+ return _WORKSPACE_QSS.substitute(dict(color_tokens(colors))).strip() + "\n"
153
+
154
+
155
+ __all__ = ["build_workspace_stylesheet"]
@@ -0,0 +1,142 @@
1
+ """Headless-safe semantic tokens for the PyCForge desktop visual system.
2
+
3
+ The optional Qt workspace and its tests share these values without importing
4
+ PyQt5. Colors are named for their role rather than a particular widget so the
5
+ visual language remains coherent across menus, editors, panels, and future
6
+ presentation surfaces.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from dataclasses import asdict, dataclass
12
+ from types import MappingProxyType
13
+ from typing import Mapping
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class PyCForgeColors:
18
+ """Professional graphite palette with restrained operational accents."""
19
+
20
+ void: str = "#070A10"
21
+ canvas: str = "#0B0F16"
22
+ surface: str = "#111823"
23
+ surface_raised: str = "#172130"
24
+ surface_active: str = "#1D2939"
25
+ surface_hover: str = "#243348"
26
+ border: str = "#29384A"
27
+ border_strong: str = "#3B526A"
28
+ text: str = "#F1F5FA"
29
+ text_soft: str = "#C8D2DE"
30
+ text_muted: str = "#9BAABC"
31
+ text_disabled: str = "#748497"
32
+ blue: str = "#4FB6FF"
33
+ blue_bright: str = "#7BCCFF"
34
+ blue_dim: str = "#1B425D"
35
+ cyan: str = "#4FB6FF"
36
+ cyan_bright: str = "#7BCCFF"
37
+ cyan_dim: str = "#1B425D"
38
+ violet: str = "#A58BFF"
39
+ violet_bright: str = "#C0AEFF"
40
+ violet_dim: str = "#443B70"
41
+ warm: str = "#FF9A52"
42
+ warm_bright: str = "#FFB878"
43
+ warm_dim: str = "#55321F"
44
+ success: str = "#5AD8A6"
45
+ success_bright: str = "#91EDC8"
46
+ success_dim: str = "#173C30"
47
+ warning: str = "#FFC56F"
48
+ warning_bright: str = "#FFDEA3"
49
+ warning_dim: str = "#49371B"
50
+ error: str = "#FF7085"
51
+ error_bright: str = "#FFABB8"
52
+ error_dim: str = "#49212A"
53
+ selection: str = "#244F70"
54
+ selection_active: str = "#2C638B"
55
+ focus_ring: str = "#7BCCFF"
56
+
57
+
58
+ @dataclass(frozen=True, slots=True)
59
+ class PyCForgeMetrics:
60
+ """Logical-pixel metrics; Qt applies the effective display scale."""
61
+
62
+ radius_small: int = 4
63
+ radius_control: int = 6
64
+ radius_panel: int = 8
65
+ radius_menu: int = 9
66
+ icon_menu: int = 18
67
+ icon_toolbar: int = 20
68
+ icon_navigator: int = 18
69
+ focus_width: int = 2
70
+ menu_outer_padding: int = 6
71
+ menu_item_vertical_padding: int = 7
72
+ menu_item_left_padding: int = 38
73
+ menu_item_right_padding: int = 36
74
+
75
+
76
+ PYCFORGE_COLORS = PyCForgeColors()
77
+ PYCFORGE_METRICS = PyCForgeMetrics()
78
+
79
+
80
+ def color_tokens(
81
+ colors: PyCForgeColors = PYCFORGE_COLORS,
82
+ ) -> Mapping[str, str]:
83
+ """Return an immutable token mapping suitable for stylesheet expansion."""
84
+
85
+ return MappingProxyType(asdict(colors))
86
+
87
+
88
+ def relative_luminance(color: str) -> float:
89
+ """Return WCAG relative luminance for an exact ``#RRGGBB`` color."""
90
+
91
+ red, green, blue = _rgb_channels(color)
92
+ linear = tuple(
93
+ channel / 12.92
94
+ if channel <= 0.04045
95
+ else ((channel + 0.055) / 1.055) ** 2.4
96
+ for channel in (red, green, blue)
97
+ )
98
+ return (
99
+ 0.2126 * linear[0]
100
+ + 0.7152 * linear[1]
101
+ + 0.0722 * linear[2]
102
+ )
103
+
104
+
105
+ def contrast_ratio(first: str, second: str) -> float:
106
+ """Return the WCAG contrast ratio between two exact RGB colors."""
107
+
108
+ lighter, darker = sorted(
109
+ (relative_luminance(first), relative_luminance(second)),
110
+ reverse=True,
111
+ )
112
+ return (lighter + 0.05) / (darker + 0.05)
113
+
114
+
115
+ def _rgb_channels(color: str) -> tuple[float, float, float]:
116
+ if (
117
+ not isinstance(color, str)
118
+ or len(color) != 7
119
+ or not color.startswith("#")
120
+ ):
121
+ raise ValueError("color must use exact #RRGGBB notation")
122
+ try:
123
+ values = tuple(
124
+ int(color[index : index + 2], 16) / 255.0
125
+ for index in (1, 3, 5)
126
+ )
127
+ except ValueError as exc:
128
+ raise ValueError(
129
+ "color must use exact #RRGGBB notation"
130
+ ) from exc
131
+ return values # type: ignore[return-value]
132
+
133
+
134
+ __all__ = [
135
+ "PYCFORGE_COLORS",
136
+ "PYCFORGE_METRICS",
137
+ "PyCForgeColors",
138
+ "PyCForgeMetrics",
139
+ "color_tokens",
140
+ "contrast_ratio",
141
+ "relative_luminance",
142
+ ]
@@ -0,0 +1,80 @@
1
+ """Public facade for the bounded isolated-converter worker protocol.
2
+
3
+ Frames are canonical JSON transported through ``send_bytes`` and
4
+ ``recv_bytes`` only. The cohesive private codec modules keep request,
5
+ result/event, and low-level JSON validation responsibilities separate while
6
+ this module preserves the original Phase 15A import surface.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from ._worker_event_codec import (
12
+ decode_event,
13
+ encode_failure,
14
+ encode_progress,
15
+ encode_terminal,
16
+ receive_event,
17
+ send_event,
18
+ )
19
+ from ._worker_protocol_types import (
20
+ FAILURE_CLASSIFICATIONS,
21
+ MAX_CONTROL_BYTES,
22
+ MAX_DIAGNOSTICS,
23
+ MAX_EVENT_BYTES,
24
+ MAX_FAILURE_MESSAGE_CHARS,
25
+ MAX_JSON_DEPTH,
26
+ MAX_REQUEST_BYTES,
27
+ MAX_SOURCE_BYTES,
28
+ MAX_SOURCE_DOCUMENTS,
29
+ PROTOCOL_SCHEMA,
30
+ ByteConnection,
31
+ WorkerControl,
32
+ WorkerEvent,
33
+ WorkerProtocolError,
34
+ WorkerRequest,
35
+ )
36
+ from ._worker_request_codec import (
37
+ decode_control,
38
+ decode_request,
39
+ encode_cancel,
40
+ encode_request,
41
+ receive_control,
42
+ receive_request,
43
+ send_cancel,
44
+ send_request,
45
+ )
46
+ from ._worker_request_data import bundle_fingerprint_for_request
47
+
48
+
49
+ __all__ = [
50
+ "FAILURE_CLASSIFICATIONS",
51
+ "MAX_CONTROL_BYTES",
52
+ "MAX_DIAGNOSTICS",
53
+ "MAX_EVENT_BYTES",
54
+ "MAX_FAILURE_MESSAGE_CHARS",
55
+ "MAX_JSON_DEPTH",
56
+ "MAX_REQUEST_BYTES",
57
+ "MAX_SOURCE_BYTES",
58
+ "MAX_SOURCE_DOCUMENTS",
59
+ "PROTOCOL_SCHEMA",
60
+ "ByteConnection",
61
+ "WorkerControl",
62
+ "WorkerEvent",
63
+ "WorkerProtocolError",
64
+ "WorkerRequest",
65
+ "bundle_fingerprint_for_request",
66
+ "decode_control",
67
+ "decode_event",
68
+ "decode_request",
69
+ "encode_cancel",
70
+ "encode_failure",
71
+ "encode_progress",
72
+ "encode_request",
73
+ "encode_terminal",
74
+ "receive_control",
75
+ "receive_event",
76
+ "receive_request",
77
+ "send_cancel",
78
+ "send_event",
79
+ "send_request",
80
+ ]