bootstack 0.1.0a1__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 (419) hide show
  1. bootstack/__init__.py +249 -0
  2. bootstack/__main__.py +5 -0
  3. bootstack/api/__init__.py +127 -0
  4. bootstack/api/app.py +30 -0
  5. bootstack/api/constants.py +3 -0
  6. bootstack/api/data.py +23 -0
  7. bootstack/api/dialogs.py +44 -0
  8. bootstack/api/i18n.py +17 -0
  9. bootstack/api/localization.py +16 -0
  10. bootstack/api/menu.py +7 -0
  11. bootstack/api/style.py +23 -0
  12. bootstack/api/utils.py +24 -0
  13. bootstack/api/widgets.py +137 -0
  14. bootstack/assets/__init__.py +24 -0
  15. bootstack/assets/bootstack-transparent.png +0 -0
  16. bootstack/assets/bootstack.ico +0 -0
  17. bootstack/assets/bootstack.png +0 -0
  18. bootstack/assets/elements/__init__.py +0 -0
  19. bootstack/assets/elements/badge-pill.png +0 -0
  20. bootstack/assets/elements/badge-square.png +0 -0
  21. bootstack/assets/elements/border.png +0 -0
  22. bootstack/assets/elements/button-compact.png +0 -0
  23. bootstack/assets/elements/button-default.png +0 -0
  24. bootstack/assets/elements/button-group-horizontal-after-compact.png +0 -0
  25. bootstack/assets/elements/button-group-horizontal-after-default.png +0 -0
  26. bootstack/assets/elements/button-group-horizontal-before-compact.png +0 -0
  27. bootstack/assets/elements/button-group-horizontal-before-default.png +0 -0
  28. bootstack/assets/elements/button-group-horizontal-center-compact.png +0 -0
  29. bootstack/assets/elements/button-group-horizontal-center-default.png +0 -0
  30. bootstack/assets/elements/button-group-vertical-after-compact.png +0 -0
  31. bootstack/assets/elements/button-group-vertical-after-default.png +0 -0
  32. bootstack/assets/elements/button-group-vertical-before-compact.png +0 -0
  33. bootstack/assets/elements/button-group-vertical-before-default.png +0 -0
  34. bootstack/assets/elements/button-group-vertical-center-compact.png +0 -0
  35. bootstack/assets/elements/button-group-vertical-center-default.png +0 -0
  36. bootstack/assets/elements/checkbox-checked.png +0 -0
  37. bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  38. bootstack/assets/elements/checkbox-unchecked.png +0 -0
  39. bootstack/assets/elements/field.png +0 -0
  40. bootstack/assets/elements/input-after-compact.png +0 -0
  41. bootstack/assets/elements/input-after-default.png +0 -0
  42. bootstack/assets/elements/input-before-compact.png +0 -0
  43. bootstack/assets/elements/input-before-default.png +0 -0
  44. bootstack/assets/elements/input-compact.png +0 -0
  45. bootstack/assets/elements/input-default.png +0 -0
  46. bootstack/assets/elements/list-item-separated.png +0 -0
  47. bootstack/assets/elements/list-item.png +0 -0
  48. bootstack/assets/elements/manifest.toml +480 -0
  49. bootstack/assets/elements/menu-item.png +0 -0
  50. bootstack/assets/elements/nav-button-compact.png +0 -0
  51. bootstack/assets/elements/nav-button-default.png +0 -0
  52. bootstack/assets/elements/nav-icon-button-compact.png +0 -0
  53. bootstack/assets/elements/nav-icon-button-default.png +0 -0
  54. bootstack/assets/elements/notebook-client-border.png +0 -0
  55. bootstack/assets/elements/notebook-tab-active.png +0 -0
  56. bootstack/assets/elements/notebook-tab-bar.png +0 -0
  57. bootstack/assets/elements/notebook-tab-normal.png +0 -0
  58. bootstack/assets/elements/notebook-tab-pill.png +0 -0
  59. bootstack/assets/elements/progress-bar-horizontal-striped.png +0 -0
  60. bootstack/assets/elements/progress-bar-solid.png +0 -0
  61. bootstack/assets/elements/progress-bar-thin.png +0 -0
  62. bootstack/assets/elements/progress-bar-vertical-striped.png +0 -0
  63. bootstack/assets/elements/radio-selected.png +0 -0
  64. bootstack/assets/elements/radio-unselected.png +0 -0
  65. bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  66. bootstack/assets/elements/scrollbar-vertical.png +0 -0
  67. bootstack/assets/elements/slider-handle-focus.png +0 -0
  68. bootstack/assets/elements/slider-handle.png +0 -0
  69. bootstack/assets/elements/slider-track-horizontal.png +0 -0
  70. bootstack/assets/elements/slider-track-vertical.png +0 -0
  71. bootstack/assets/elements/switch-off.png +0 -0
  72. bootstack/assets/elements/switch-on.png +0 -0
  73. bootstack/assets/elements/tabs-bar-horizontal.png +0 -0
  74. bootstack/assets/elements/tabs-bar-vertical.png +0 -0
  75. bootstack/assets/elements/tabs-pill.png +0 -0
  76. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  77. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +853 -0
  78. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +875 -0
  79. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  80. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +853 -0
  81. bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  82. bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +853 -0
  83. bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  84. bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +853 -0
  85. bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  86. bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +875 -0
  87. bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  88. bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +853 -0
  89. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  90. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +853 -0
  91. bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  92. bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +851 -0
  93. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  94. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +842 -0
  95. bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  96. bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +841 -0
  97. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  98. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +914 -0
  99. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  100. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +842 -0
  101. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  102. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +841 -0
  103. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  104. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +841 -0
  105. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  106. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +842 -0
  107. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  108. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +842 -0
  109. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  110. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +842 -0
  111. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  112. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +842 -0
  113. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  114. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +842 -0
  115. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  116. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +842 -0
  117. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  118. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +842 -0
  119. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  120. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +842 -0
  121. bootstack/assets/themes/__init__.py +0 -0
  122. bootstack/assets/themes/amber-dark.json +32 -0
  123. bootstack/assets/themes/amber-light.json +32 -0
  124. bootstack/assets/themes/aurora-dark.json +32 -0
  125. bootstack/assets/themes/aurora-light.json +32 -0
  126. bootstack/assets/themes/bootstrap-dark.json +32 -0
  127. bootstack/assets/themes/bootstrap-light.json +32 -0
  128. bootstack/assets/themes/classic-dark.json +32 -0
  129. bootstack/assets/themes/classic-light.json +32 -0
  130. bootstack/assets/themes/docs-dark.json +32 -0
  131. bootstack/assets/themes/docs-light.json +32 -0
  132. bootstack/assets/themes/forest-dark.json +32 -0
  133. bootstack/assets/themes/forest-light.json +32 -0
  134. bootstack/assets/themes/ocean-dark.json +32 -0
  135. bootstack/assets/themes/ocean-light.json +32 -0
  136. bootstack/assets/themes/rose-dark.json +32 -0
  137. bootstack/assets/themes/rose-light.json +32 -0
  138. bootstack/assets/widgets/__init__.py +0 -0
  139. bootstack/assets/widgets/badge-default.png +0 -0
  140. bootstack/assets/widgets/badge-pill.png +0 -0
  141. bootstack/assets/widgets/border.png +0 -0
  142. bootstack/assets/widgets/button-group-horizontal-after.png +0 -0
  143. bootstack/assets/widgets/button-group-horizontal-before.png +0 -0
  144. bootstack/assets/widgets/button-group-horizontal-center.png +0 -0
  145. bootstack/assets/widgets/button-group-vertical-after.png +0 -0
  146. bootstack/assets/widgets/button-group-vertical-before.png +0 -0
  147. bootstack/assets/widgets/button-group-vertical-center.png +0 -0
  148. bootstack/assets/widgets/button.png +0 -0
  149. bootstack/assets/widgets/checkbox-checked.png +0 -0
  150. bootstack/assets/widgets/checkbox-indeterminate.png +0 -0
  151. bootstack/assets/widgets/checkbox-unchecked.png +0 -0
  152. bootstack/assets/widgets/field.png +0 -0
  153. bootstack/assets/widgets/icon-button.png +0 -0
  154. bootstack/assets/widgets/input-inner.png +0 -0
  155. bootstack/assets/widgets/input-prefix.png +0 -0
  156. bootstack/assets/widgets/input-suffix.png +0 -0
  157. bootstack/assets/widgets/input.png +0 -0
  158. bootstack/assets/widgets/list-item-focus.png +0 -0
  159. bootstack/assets/widgets/list-item-separated.png +0 -0
  160. bootstack/assets/widgets/menu-item-separated.png +0 -0
  161. bootstack/assets/widgets/notebook-client-border.png +0 -0
  162. bootstack/assets/widgets/notebook-pill-active.png +0 -0
  163. bootstack/assets/widgets/notebook-pill-inactive.png +0 -0
  164. bootstack/assets/widgets/notebook-tab-active.png +0 -0
  165. bootstack/assets/widgets/notebook-tab-border.png +0 -0
  166. bootstack/assets/widgets/notebook-tab-normal.png +0 -0
  167. bootstack/assets/widgets/notebook-underline.png +0 -0
  168. bootstack/assets/widgets/progress-bar-horizontal-default.png +0 -0
  169. bootstack/assets/widgets/progress-bar-horizontal-striped.png +0 -0
  170. bootstack/assets/widgets/progress-bar-vertical-default.png +0 -0
  171. bootstack/assets/widgets/progress-bar-vertical-striped.png +0 -0
  172. bootstack/assets/widgets/progress-trough-horizontal.png +0 -0
  173. bootstack/assets/widgets/progress-trough-vertical.png +0 -0
  174. bootstack/assets/widgets/radio-selected.png +0 -0
  175. bootstack/assets/widgets/radio-unselected.png +0 -0
  176. bootstack/assets/widgets/scrollbar-horizontal-rounded.png +0 -0
  177. bootstack/assets/widgets/scrollbar-vertical-rounded.png +0 -0
  178. bootstack/assets/widgets/separator-horizontal.png +0 -0
  179. bootstack/assets/widgets/separator-vertical.png +0 -0
  180. bootstack/assets/widgets/slider-handle-focus.png +0 -0
  181. bootstack/assets/widgets/slider-handle.png +0 -0
  182. bootstack/assets/widgets/slider-track-horizontal.png +0 -0
  183. bootstack/assets/widgets/slider-track-vertical.png +0 -0
  184. bootstack/assets/widgets/switch-off.png +0 -0
  185. bootstack/assets/widgets/switch-on.png +0 -0
  186. bootstack/assets/widgets/tabs-bar-horizontal.png +0 -0
  187. bootstack/assets/widgets/tabs-bar-vertical.png +0 -0
  188. bootstack/assets/widgets/tabs-pill.png +0 -0
  189. bootstack/cli/__init__.py +124 -0
  190. bootstack/cli/__main__.py +6 -0
  191. bootstack/cli/add.py +439 -0
  192. bootstack/cli/build.py +115 -0
  193. bootstack/cli/config.py +287 -0
  194. bootstack/cli/demo.py +1267 -0
  195. bootstack/cli/doctor.py +195 -0
  196. bootstack/cli/list_cmd.py +71 -0
  197. bootstack/cli/promote.py +120 -0
  198. bootstack/cli/pyinstaller.py +246 -0
  199. bootstack/cli/run.py +99 -0
  200. bootstack/cli/start.py +105 -0
  201. bootstack/cli/templates/__init__.py +861 -0
  202. bootstack/constants.py +325 -0
  203. bootstack/core/__init__.py +34 -0
  204. bootstack/core/capabilities/__init__.py +45 -0
  205. bootstack/core/capabilities/after.py +103 -0
  206. bootstack/core/capabilities/bind.py +154 -0
  207. bootstack/core/capabilities/bindtags.py +112 -0
  208. bootstack/core/capabilities/busy.py +61 -0
  209. bootstack/core/capabilities/clipboard.py +88 -0
  210. bootstack/core/capabilities/focus.py +118 -0
  211. bootstack/core/capabilities/grab.py +65 -0
  212. bootstack/core/capabilities/grid.py +188 -0
  213. bootstack/core/capabilities/localization.py +231 -0
  214. bootstack/core/capabilities/pack.py +119 -0
  215. bootstack/core/capabilities/place.py +92 -0
  216. bootstack/core/capabilities/selection.py +136 -0
  217. bootstack/core/capabilities/signals.py +242 -0
  218. bootstack/core/capabilities/winfo.py +315 -0
  219. bootstack/core/colorutils.py +234 -0
  220. bootstack/core/exceptions.py +95 -0
  221. bootstack/core/images.py +283 -0
  222. bootstack/core/localization/README.md +90 -0
  223. bootstack/core/localization/__init__.py +13 -0
  224. bootstack/core/localization/intl_format.py +580 -0
  225. bootstack/core/localization/msgcat.py +425 -0
  226. bootstack/core/localization/specs.py +143 -0
  227. bootstack/core/mixins/__init__.py +1 -0
  228. bootstack/core/mixins/ttk_state.py +35 -0
  229. bootstack/core/mixins/widget.py +132 -0
  230. bootstack/core/publisher.py +147 -0
  231. bootstack/core/signals/README.md +112 -0
  232. bootstack/core/signals/__init__.py +8 -0
  233. bootstack/core/signals/integration.py +100 -0
  234. bootstack/core/signals/signal.py +317 -0
  235. bootstack/core/signals/types.py +4 -0
  236. bootstack/core/validation/__init__.py +5 -0
  237. bootstack/core/validation/types.py +13 -0
  238. bootstack/core/validation/validation_result.py +17 -0
  239. bootstack/core/validation/validation_rules.py +112 -0
  240. bootstack/core/variables.py +62 -0
  241. bootstack/datasource/README.md +607 -0
  242. bootstack/datasource/__init__.py +51 -0
  243. bootstack/datasource/base.py +474 -0
  244. bootstack/datasource/file_source.py +541 -0
  245. bootstack/datasource/memory_source.py +482 -0
  246. bootstack/datasource/sqlite_source.py +453 -0
  247. bootstack/datasource/types.py +259 -0
  248. bootstack/dialogs/__init__.py +56 -0
  249. bootstack/dialogs/colorchooser.py +674 -0
  250. bootstack/dialogs/colordropper.py +257 -0
  251. bootstack/dialogs/datedialog.py +404 -0
  252. bootstack/dialogs/dialog.py +514 -0
  253. bootstack/dialogs/filterdialog.py +358 -0
  254. bootstack/dialogs/fontdialog.py +339 -0
  255. bootstack/dialogs/formdialog.py +541 -0
  256. bootstack/dialogs/message.py +489 -0
  257. bootstack/dialogs/query.py +561 -0
  258. bootstack/py.typed +1 -0
  259. bootstack/runtime/__init__.py +3 -0
  260. bootstack/runtime/app.py +879 -0
  261. bootstack/runtime/base_window.py +786 -0
  262. bootstack/runtime/events.py +399 -0
  263. bootstack/runtime/menu.py +510 -0
  264. bootstack/runtime/shortcuts.py +423 -0
  265. bootstack/runtime/tk_patch.py +31 -0
  266. bootstack/runtime/toplevel.py +131 -0
  267. bootstack/runtime/utility.py +371 -0
  268. bootstack/runtime/visual_focus.py +228 -0
  269. bootstack/runtime/window_utilities.py +1043 -0
  270. bootstack/style/__init__.py +5498 -0
  271. bootstack/style/bootstyle.py +507 -0
  272. bootstack/style/bootstyle_builder_base.py +752 -0
  273. bootstack/style/bootstyle_builder_mixed.py +93 -0
  274. bootstack/style/bootstyle_builder_tk.py +109 -0
  275. bootstack/style/bootstyle_builder_ttk.py +354 -0
  276. bootstack/style/builders/__init__.py +51 -0
  277. bootstack/style/builders/badge.py +44 -0
  278. bootstack/style/builders/button.py +453 -0
  279. bootstack/style/builders/buttongroup.py +344 -0
  280. bootstack/style/builders/calendar.py +271 -0
  281. bootstack/style/builders/checkbutton.py +95 -0
  282. bootstack/style/builders/combobox.py +112 -0
  283. bootstack/style/builders/contextmenu.py +268 -0
  284. bootstack/style/builders/entry.py +83 -0
  285. bootstack/style/builders/expander.py +171 -0
  286. bootstack/style/builders/field.py +312 -0
  287. bootstack/style/builders/frame.py +27 -0
  288. bootstack/style/builders/label.py +28 -0
  289. bootstack/style/builders/labelframe.py +41 -0
  290. bootstack/style/builders/listview.py +267 -0
  291. bootstack/style/builders/menubar.py +74 -0
  292. bootstack/style/builders/menubutton.py +408 -0
  293. bootstack/style/builders/notebook.py +316 -0
  294. bootstack/style/builders/panedwindow.py +25 -0
  295. bootstack/style/builders/progressbar.py +71 -0
  296. bootstack/style/builders/radiobutton.py +68 -0
  297. bootstack/style/builders/scale.py +66 -0
  298. bootstack/style/builders/scrollbar.py +360 -0
  299. bootstack/style/builders/separator.py +45 -0
  300. bootstack/style/builders/sidenav.py +313 -0
  301. bootstack/style/builders/sizegrip.py +15 -0
  302. bootstack/style/builders/spinbox.py +119 -0
  303. bootstack/style/builders/switch.py +67 -0
  304. bootstack/style/builders/tabitem.py +205 -0
  305. bootstack/style/builders/toolbutton.py +260 -0
  306. bootstack/style/builders/tooltip.py +26 -0
  307. bootstack/style/builders/treeview.py +269 -0
  308. bootstack/style/builders/utils.py +404 -0
  309. bootstack/style/builders_tk/__init__.py +16 -0
  310. bootstack/style/builders_tk/defaults.py +229 -0
  311. bootstack/style/element.py +173 -0
  312. bootstack/style/style.py +499 -0
  313. bootstack/style/theme_provider.py +449 -0
  314. bootstack/style/tk_patch.py +5 -0
  315. bootstack/style/token_maps.py +42 -0
  316. bootstack/style/types.py +32 -0
  317. bootstack/style/typography.py +527 -0
  318. bootstack/style/utility.py +696 -0
  319. bootstack/themes/__init__.py +12 -0
  320. bootstack/themes/standard.py +415 -0
  321. bootstack/themes/user.py +45 -0
  322. bootstack/widgets/__init__.py +53 -0
  323. bootstack/widgets/composites/__init__.py +38 -0
  324. bootstack/widgets/composites/accordion.py +385 -0
  325. bootstack/widgets/composites/appshell.py +445 -0
  326. bootstack/widgets/composites/buttongroup.py +391 -0
  327. bootstack/widgets/composites/calendar.py +914 -0
  328. bootstack/widgets/composites/compositeframe.py +282 -0
  329. bootstack/widgets/composites/contextmenu.py +1754 -0
  330. bootstack/widgets/composites/dateentry.py +261 -0
  331. bootstack/widgets/composites/dropdownbutton.py +190 -0
  332. bootstack/widgets/composites/expander.py +508 -0
  333. bootstack/widgets/composites/field.py +448 -0
  334. bootstack/widgets/composites/floodgauge.py +434 -0
  335. bootstack/widgets/composites/form.py +983 -0
  336. bootstack/widgets/composites/labeledscale.py +209 -0
  337. bootstack/widgets/composites/list/__init__.py +15 -0
  338. bootstack/widgets/composites/list/listitem.py +733 -0
  339. bootstack/widgets/composites/list/listview.py +1507 -0
  340. bootstack/widgets/composites/menubar.py +303 -0
  341. bootstack/widgets/composites/meter.py +882 -0
  342. bootstack/widgets/composites/numericentry.py +183 -0
  343. bootstack/widgets/composites/pagestack.py +330 -0
  344. bootstack/widgets/composites/passwordentry.py +149 -0
  345. bootstack/widgets/composites/pathentry.py +223 -0
  346. bootstack/widgets/composites/radiogroup.py +466 -0
  347. bootstack/widgets/composites/scrolledtext.py +388 -0
  348. bootstack/widgets/composites/scrolledtext.pyi +186 -0
  349. bootstack/widgets/composites/scrollview.py +675 -0
  350. bootstack/widgets/composites/selectbox.py +544 -0
  351. bootstack/widgets/composites/sidenav/__init__.py +24 -0
  352. bootstack/widgets/composites/sidenav/group.py +485 -0
  353. bootstack/widgets/composites/sidenav/header.py +83 -0
  354. bootstack/widgets/composites/sidenav/item.py +413 -0
  355. bootstack/widgets/composites/sidenav/separator.py +51 -0
  356. bootstack/widgets/composites/sidenav/view.py +919 -0
  357. bootstack/widgets/composites/spinnerentry.py +232 -0
  358. bootstack/widgets/composites/tableview/__init__.py +5 -0
  359. bootstack/widgets/composites/tableview/tableview.py +2254 -0
  360. bootstack/widgets/composites/tableview/types.py +169 -0
  361. bootstack/widgets/composites/tabs/__init__.py +6 -0
  362. bootstack/widgets/composites/tabs/tabitem.py +372 -0
  363. bootstack/widgets/composites/tabs/tabs.py +478 -0
  364. bootstack/widgets/composites/tabs/tabview.py +352 -0
  365. bootstack/widgets/composites/textentry.py +90 -0
  366. bootstack/widgets/composites/timeentry.py +189 -0
  367. bootstack/widgets/composites/toast.py +364 -0
  368. bootstack/widgets/composites/togglegroup.py +382 -0
  369. bootstack/widgets/composites/toolbar.py +393 -0
  370. bootstack/widgets/composites/tooltip.py +404 -0
  371. bootstack/widgets/internal/__init__.py +0 -0
  372. bootstack/widgets/internal/wrapper_base.py +304 -0
  373. bootstack/widgets/mixins/__init__.py +25 -0
  374. bootstack/widgets/mixins/configure_mixin.py +186 -0
  375. bootstack/widgets/mixins/entry_mixin.py +70 -0
  376. bootstack/widgets/mixins/font_mixin.py +346 -0
  377. bootstack/widgets/mixins/icon_mixin.py +38 -0
  378. bootstack/widgets/mixins/localization_mixin.py +255 -0
  379. bootstack/widgets/mixins/signal_mixin.py +272 -0
  380. bootstack/widgets/mixins/validation_mixin.py +204 -0
  381. bootstack/widgets/parts/__init__.py +11 -0
  382. bootstack/widgets/parts/numberentry_part.py +345 -0
  383. bootstack/widgets/parts/spinnerentry_part.py +394 -0
  384. bootstack/widgets/parts/textentry_part.py +344 -0
  385. bootstack/widgets/primitives/__init__.py +55 -0
  386. bootstack/widgets/primitives/badge.py +44 -0
  387. bootstack/widgets/primitives/button.py +89 -0
  388. bootstack/widgets/primitives/card.py +66 -0
  389. bootstack/widgets/primitives/checkbutton.py +124 -0
  390. bootstack/widgets/primitives/checktoggle.py +53 -0
  391. bootstack/widgets/primitives/combobox.py +165 -0
  392. bootstack/widgets/primitives/entry.py +98 -0
  393. bootstack/widgets/primitives/frame.py +206 -0
  394. bootstack/widgets/primitives/gridframe.py +479 -0
  395. bootstack/widgets/primitives/label.py +95 -0
  396. bootstack/widgets/primitives/labelframe.py +63 -0
  397. bootstack/widgets/primitives/menubutton.py +118 -0
  398. bootstack/widgets/primitives/notebook.py +551 -0
  399. bootstack/widgets/primitives/optionmenu.py +248 -0
  400. bootstack/widgets/primitives/packframe.py +228 -0
  401. bootstack/widgets/primitives/panedwindow.py +58 -0
  402. bootstack/widgets/primitives/progressbar.py +95 -0
  403. bootstack/widgets/primitives/radiobutton.py +115 -0
  404. bootstack/widgets/primitives/radiotoggle.py +50 -0
  405. bootstack/widgets/primitives/scale.py +85 -0
  406. bootstack/widgets/primitives/scrollbar.py +56 -0
  407. bootstack/widgets/primitives/separator.py +56 -0
  408. bootstack/widgets/primitives/sizegrip.py +47 -0
  409. bootstack/widgets/primitives/spinbox.py +91 -0
  410. bootstack/widgets/primitives/switch.py +41 -0
  411. bootstack/widgets/primitives/treeview.py +77 -0
  412. bootstack/widgets/types.py +20 -0
  413. bootstack-0.1.0a1.dist-info/METADATA +196 -0
  414. bootstack-0.1.0a1.dist-info/RECORD +419 -0
  415. bootstack-0.1.0a1.dist-info/WHEEL +5 -0
  416. bootstack-0.1.0a1.dist-info/entry_points.txt +2 -0
  417. bootstack-0.1.0a1.dist-info/licenses/LICENSE +22 -0
  418. bootstack-0.1.0a1.dist-info/licenses/NOTICE +10 -0
  419. bootstack-0.1.0a1.dist-info/top_level.txt +1 -0
Binary file
@@ -0,0 +1,124 @@
1
+ """CLI entry point for bootstack.
2
+
3
+ The bootstack CLI provides commands for:
4
+ - Creating new projects (start)
5
+ - Running applications (run)
6
+ - Building for distribution (build)
7
+ - Adding components (add)
8
+ - Listing resources (list)
9
+
10
+ Usage:
11
+ bootstack start <appname> Create a new project
12
+ bootstack run [path] Run the application
13
+ bootstack promote --pyinstaller Enable PyInstaller support
14
+ bootstack build Build for distribution
15
+ bootstack add page <ClassName> Add a new page (AppShell)
16
+ bootstack add view <ClassName> Add a new view
17
+ bootstack add dialog <ClassName> Add a new dialog
18
+ bootstack add theme <name> Add a custom theme
19
+ bootstack add i18n Add i18n support
20
+ bootstack list themes List available themes
21
+ bootstack doctor Diagnose project and environment health
22
+ bootstack demo Launch the widget demo
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import sys
29
+ from typing import Sequence
30
+
31
+ from bootstack.cli import add, build, doctor, list_cmd, promote, run, start
32
+ from bootstack.cli.demo import run_demo
33
+
34
+
35
+ def main(argv: Sequence[str] | None = None) -> None:
36
+ """Dispatch CLI commands registered in bootstack."""
37
+ parser = argparse.ArgumentParser(
38
+ prog="bootstack",
39
+ description="bootstack command line interface",
40
+ formatter_class=argparse.RawDescriptionHelpFormatter,
41
+ epilog="""\
42
+ Examples:
43
+ bootstack start MyApp Create a new project
44
+ bootstack start MyApp --template appshell Create an AppShell project
45
+ bootstack start MyApp --theme superhero Use a specific theme
46
+ bootstack run Run the application
47
+ bootstack promote --pyinstaller Enable PyInstaller support
48
+ bootstack build Build for distribution
49
+ bootstack add view SettingsView Add a new view
50
+ bootstack list themes List available themes
51
+ bootstack doctor Diagnose project and environment health
52
+ bootstack demo Launch the widget demo
53
+
54
+ For more information on a command:
55
+ bootstack <command> --help
56
+ """,
57
+ )
58
+
59
+ parser.add_argument(
60
+ "--version",
61
+ action="version",
62
+ version=_get_version(),
63
+ )
64
+ parser.add_argument(
65
+ "-v",
66
+ "--verbose",
67
+ action="store_true",
68
+ help="Print full tracebacks on error",
69
+ )
70
+
71
+ subparsers = parser.add_subparsers(
72
+ dest="command",
73
+ title="commands",
74
+ metavar="<command>",
75
+ )
76
+
77
+ # Register commands
78
+ start.add_parser(subparsers)
79
+ run.add_parser(subparsers)
80
+ promote.add_parser(subparsers)
81
+ build.add_parser(subparsers)
82
+ add.add_parser(subparsers)
83
+ list_cmd.add_parser(subparsers)
84
+ doctor.add_parser(subparsers)
85
+
86
+ # Demo command (kept for backwards compatibility)
87
+ demo_parser = subparsers.add_parser(
88
+ "demo",
89
+ help="Launch the widget demo",
90
+ )
91
+ demo_parser.set_defaults(func=lambda args: run_demo())
92
+
93
+ # Parse arguments
94
+ args = parser.parse_args(argv)
95
+ func = getattr(args, "func", None)
96
+
97
+ if func is None:
98
+ parser.print_help()
99
+ sys.exit(0)
100
+
101
+ # Execute command
102
+ try:
103
+ func(args)
104
+ except KeyboardInterrupt:
105
+ print("\nInterrupted.")
106
+ sys.exit(1)
107
+ except Exception as e:
108
+ if getattr(args, "verbose", False):
109
+ import traceback
110
+ traceback.print_exc()
111
+ else:
112
+ print(f"Error: {e}")
113
+ print("(Run with --verbose for the full traceback.)")
114
+ sys.exit(1)
115
+
116
+
117
+ def _get_version() -> str:
118
+ """Get the bootstack version string."""
119
+ try:
120
+ import bootstack
121
+
122
+ return f"bootstack {bootstack.__version__}"
123
+ except Exception:
124
+ return "bootstack (unknown version)"
@@ -0,0 +1,6 @@
1
+ """Allow running bootstack CLI as python -m bootstack.cli."""
2
+
3
+ from bootstack.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
bootstack/cli/add.py ADDED
@@ -0,0 +1,439 @@
1
+ """bootstack add command - Add views, dialogs, themes, and i18n to a project."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ from pathlib import Path
7
+
8
+ from bootstack.cli.config import TtkbConfig, find_config
9
+ from bootstack.cli.templates import create_dialog, create_page, create_view
10
+
11
+
12
+ def add_parser(subparsers: argparse._SubParsersAction) -> None:
13
+ """Add the 'add' subcommand parser."""
14
+ parser = subparsers.add_parser(
15
+ "add",
16
+ help="Add components to the project",
17
+ description="Add views, pages, dialogs, themes, or i18n support to the project.",
18
+ )
19
+ add_subparsers = parser.add_subparsers(dest="component")
20
+
21
+ # bootstack add page <ClassName>
22
+ page_parser = add_subparsers.add_parser(
23
+ "page",
24
+ help="Add a new page (for AppShell projects)",
25
+ )
26
+ page_parser.add_argument(
27
+ "class_name",
28
+ help="Page class name (CamelCase, e.g., 'DashboardPage')",
29
+ )
30
+ page_parser.add_argument(
31
+ "--dir",
32
+ type=Path,
33
+ default=None,
34
+ help="Target directory (default: src/<app>/pages/)",
35
+ )
36
+ page_parser.add_argument(
37
+ "--scrollable",
38
+ action="store_true",
39
+ help="Make the page scrollable (wraps content in a ScrollView)",
40
+ )
41
+ page_parser.set_defaults(func=run_add_page)
42
+
43
+ # bootstack add view <ClassName>
44
+ view_parser = add_subparsers.add_parser(
45
+ "view",
46
+ help="Add a new view",
47
+ )
48
+ view_parser.add_argument(
49
+ "class_name",
50
+ help="View class name (CamelCase, e.g., 'SettingsView')",
51
+ )
52
+ view_parser.add_argument(
53
+ "--container",
54
+ choices=["grid", "pack"],
55
+ default=None,
56
+ help="Container type (default: from bootstack.toml or 'grid')",
57
+ )
58
+ view_parser.add_argument(
59
+ "--dir",
60
+ type=Path,
61
+ default=None,
62
+ help="Target directory (default: src/<app>/views/)",
63
+ )
64
+ view_parser.set_defaults(func=run_add_view)
65
+
66
+ # bootstack add dialog <ClassName>
67
+ dialog_parser = add_subparsers.add_parser(
68
+ "dialog",
69
+ help="Add a new dialog",
70
+ )
71
+ dialog_parser.add_argument(
72
+ "class_name",
73
+ help="Dialog class name (CamelCase, e.g., 'ConfirmDialog')",
74
+ )
75
+ dialog_parser.add_argument(
76
+ "--dir",
77
+ type=Path,
78
+ default=None,
79
+ help="Target directory (default: src/<app>/dialogs/)",
80
+ )
81
+ dialog_parser.set_defaults(func=run_add_dialog)
82
+
83
+ # bootstack add theme <name>
84
+ theme_parser = add_subparsers.add_parser(
85
+ "theme",
86
+ help="Add a custom theme",
87
+ )
88
+ theme_parser.add_argument(
89
+ "name",
90
+ help="Theme name (e.g., 'mytheme')",
91
+ )
92
+ theme_parser.add_argument(
93
+ "--mode",
94
+ choices=["light", "dark"],
95
+ default="light",
96
+ help="Theme mode (default: light)",
97
+ )
98
+ theme_parser.set_defaults(func=run_add_theme)
99
+
100
+ # bootstack add i18n
101
+ i18n_parser = add_subparsers.add_parser(
102
+ "i18n",
103
+ help="Add internationalization support",
104
+ )
105
+ i18n_parser.add_argument(
106
+ "--languages",
107
+ nargs="+",
108
+ default=["en"],
109
+ help="Languages to support (default: en)",
110
+ )
111
+ i18n_parser.set_defaults(func=run_add_i18n)
112
+
113
+ parser.set_defaults(func=lambda args: parser.print_help())
114
+
115
+
116
+ def run_add_view(args: argparse.Namespace) -> None:
117
+ """Add a new view to the project."""
118
+ class_name = args.class_name
119
+
120
+ # Validate class name
121
+ if not class_name[0].isupper():
122
+ print("Error: Class name should be CamelCase (e.g., 'SettingsView')")
123
+ return
124
+
125
+ # Find project configuration
126
+ config_path = find_config()
127
+ if config_path is None:
128
+ print("Error: No bootstack.toml found. Are you in a bootstack project?")
129
+ return
130
+
131
+ project_root = config_path.parent
132
+ config = TtkbConfig.load(config_path)
133
+
134
+ # Reject in AppShell projects — views belong to the basic template
135
+ if config.app.template == "appshell":
136
+ print("Error: 'bootstack add view' is for basic-template projects.")
137
+ print("This project uses the 'appshell' template. Use 'bootstack add page' instead.")
138
+ return
139
+
140
+ # Determine container type
141
+ container = args.container
142
+ if container is None:
143
+ container = config.layout.default_container
144
+
145
+ # Determine target directory
146
+ if args.dir:
147
+ target_dir = args.dir
148
+ else:
149
+ # Parse entry point to find source directory
150
+ entry_path = Path(config.app.entry)
151
+ if entry_path.parts[0] == "src" and len(entry_path.parts) >= 2:
152
+ module_name = entry_path.parts[1]
153
+ target_dir = project_root / "src" / module_name / "views"
154
+ else:
155
+ target_dir = project_root / "views"
156
+
157
+ target_dir.mkdir(parents=True, exist_ok=True)
158
+
159
+ # Ensure __init__.py exists
160
+ init_file = target_dir / "__init__.py"
161
+ if not init_file.exists():
162
+ init_file.write_text('"""Views package."""\n', encoding="utf-8")
163
+
164
+ # Create view
165
+ file_path = create_view(class_name, target_dir, container)
166
+
167
+ print(f"Created view: {file_path.relative_to(project_root)}")
168
+
169
+
170
+ def run_add_page(args: argparse.Namespace) -> None:
171
+ """Add a new page to an AppShell project."""
172
+ class_name = args.class_name
173
+
174
+ # Validate class name
175
+ if not class_name[0].isupper():
176
+ print("Error: Class name should be CamelCase (e.g., 'DashboardPage')")
177
+ return
178
+
179
+ # Find project configuration
180
+ config_path = find_config()
181
+ if config_path is None:
182
+ print("Error: No bootstack.toml found. Are you in a bootstack project?")
183
+ return
184
+
185
+ project_root = config_path.parent
186
+ config = TtkbConfig.load(config_path)
187
+
188
+ # Check that this is an AppShell project
189
+ if config.app.template != "appshell":
190
+ print("Error: 'bootstack add page' is for AppShell projects.")
191
+ print("This project uses the 'basic' template. Use 'bootstack add view' instead.")
192
+ return
193
+
194
+ # Determine target directory and module name for the import hint
195
+ entry_path = Path(config.app.entry)
196
+ if entry_path.parts[0] == "src" and len(entry_path.parts) >= 2:
197
+ module_name = entry_path.parts[1]
198
+ default_target = project_root / "src" / module_name / "pages"
199
+ else:
200
+ module_name = None
201
+ default_target = project_root / "pages"
202
+
203
+ target_dir = args.dir if args.dir else default_target
204
+
205
+ target_dir.mkdir(parents=True, exist_ok=True)
206
+
207
+ # Ensure __init__.py exists
208
+ init_file = target_dir / "__init__.py"
209
+ if not init_file.exists():
210
+ init_file.write_text('"""Pages package."""\n', encoding="utf-8")
211
+
212
+ # Create page
213
+ scrollable = args.scrollable
214
+ file_path = create_page(class_name, target_dir, scrollable=scrollable)
215
+
216
+ print(f"Created page: {file_path.relative_to(project_root)}")
217
+ print()
218
+ print("This created the file only — it is NOT yet shown in the sidebar.")
219
+ print("To register it with the AppShell, paste these lines into main.py:")
220
+ print()
221
+ import_module = f"{module_name}.pages" if module_name else "<module>.pages"
222
+ print(f" from {import_module}.{file_path.stem} import {class_name}")
223
+ scrollable_arg = ", scrollable=True" if scrollable else ""
224
+ print(f' page = shell.add_page("<id>", text="<Label>", icon="<icon>"{scrollable_arg})')
225
+ print(f" {class_name}(page)")
226
+
227
+
228
+ def run_add_dialog(args: argparse.Namespace) -> None:
229
+ """Add a new dialog to the project."""
230
+ class_name = args.class_name
231
+
232
+ # Validate class name
233
+ if not class_name[0].isupper():
234
+ print("Error: Class name should be CamelCase (e.g., 'ConfirmDialog')")
235
+ return
236
+
237
+ # Find project configuration
238
+ config_path = find_config()
239
+ if config_path is None:
240
+ print("Error: No bootstack.toml found. Are you in a bootstack project?")
241
+ return
242
+
243
+ project_root = config_path.parent
244
+ config = TtkbConfig.load(config_path)
245
+
246
+ # Determine target directory
247
+ if args.dir:
248
+ target_dir = args.dir
249
+ else:
250
+ # Parse entry point to find source directory
251
+ entry_path = Path(config.app.entry)
252
+ if entry_path.parts[0] == "src" and len(entry_path.parts) >= 2:
253
+ module_name = entry_path.parts[1]
254
+ target_dir = project_root / "src" / module_name / "dialogs"
255
+ else:
256
+ target_dir = project_root / "dialogs"
257
+
258
+ target_dir.mkdir(parents=True, exist_ok=True)
259
+
260
+ # Ensure __init__.py exists
261
+ init_file = target_dir / "__init__.py"
262
+ if not init_file.exists():
263
+ init_file.write_text('"""Dialogs package."""\n', encoding="utf-8")
264
+
265
+ # Create dialog
266
+ file_path = create_dialog(class_name, target_dir)
267
+
268
+ print(f"Created dialog: {file_path.relative_to(project_root)}")
269
+
270
+
271
+ def run_add_theme(args: argparse.Namespace) -> None:
272
+ """Add a custom theme to the project."""
273
+ theme_name = args.name.lower()
274
+ mode = args.mode
275
+
276
+ # Find project configuration
277
+ config_path = find_config()
278
+ if config_path is None:
279
+ print("Error: No bootstack.toml found. Are you in a bootstack project?")
280
+ return
281
+
282
+ project_root = config_path.parent
283
+
284
+ # Create themes directory
285
+ themes_dir = project_root / "themes"
286
+ themes_dir.mkdir(exist_ok=True)
287
+
288
+ # Create theme file
289
+ theme_file = themes_dir / f"{theme_name}.json"
290
+ if theme_file.exists():
291
+ print(f"Error: Theme '{theme_name}' already exists.")
292
+ return
293
+
294
+ # Theme template based on mode
295
+ if mode == "light":
296
+ theme_content = _get_light_theme_template(theme_name)
297
+ else:
298
+ theme_content = _get_dark_theme_template(theme_name)
299
+
300
+ theme_file.write_text(theme_content, encoding="utf-8")
301
+
302
+ print(f"Created theme: {theme_file.relative_to(project_root)}")
303
+ print()
304
+ print("To use this theme, register the JSON file before creating your App:")
305
+ print()
306
+ print(" from bootstack.style.theme_provider import register_user_theme")
307
+ print(f' register_user_theme("{theme_name}", "themes/{theme_name}.json")')
308
+ print(f' app = ttk.App(theme="{theme_name}")')
309
+
310
+
311
+ def run_add_i18n(args: argparse.Namespace) -> None:
312
+ """Add internationalization support to the project."""
313
+ languages = args.languages
314
+
315
+ # Find project configuration
316
+ config_path = find_config()
317
+ if config_path is None:
318
+ print("Error: No bootstack.toml found. Are you in a bootstack project?")
319
+ return
320
+
321
+ project_root = config_path.parent
322
+
323
+ # Create locales directory structure
324
+ locales_dir = project_root / "locales"
325
+
326
+ for lang in languages:
327
+ lang_dir = locales_dir / lang / "LC_MESSAGES"
328
+ lang_dir.mkdir(parents=True, exist_ok=True)
329
+
330
+ # Create .po file template
331
+ po_file = lang_dir / "messages.po"
332
+ if not po_file.exists():
333
+ po_content = _get_po_template(lang)
334
+ po_file.write_text(po_content, encoding="utf-8")
335
+ print(f"Created: {po_file.relative_to(project_root)}")
336
+
337
+ print()
338
+ print("Internationalization support added!")
339
+ print()
340
+ print("Next steps:")
341
+ print(" 1. Add translatable strings to your .po files")
342
+ print(" 2. Compile with: msgfmt locales/<lang>/LC_MESSAGES/messages.po -o locales/<lang>/LC_MESSAGES/messages.mo")
343
+ print(" 3. Use translations in code: ttk.mc('Hello')")
344
+
345
+
346
+ _BASE_SHADES = {
347
+ "blue": "#0d6efd",
348
+ "indigo": "#6610f2",
349
+ "purple": "#6f42c1",
350
+ "red": "#dc3545",
351
+ "orange": "#fd7e14",
352
+ "yellow": "#ffc107",
353
+ "green": "#198754",
354
+ "teal": "#20c997",
355
+ "cyan": "#0dcaf0",
356
+ "gray": "#adb5bd",
357
+ "pink": "#d63384",
358
+ }
359
+
360
+
361
+ def _theme_display_name(name: str) -> str:
362
+ return " ".join(part.capitalize() for part in name.replace("_", "-").split("-") if part)
363
+
364
+
365
+ def _render_theme(name: str, mode: str) -> str:
366
+ """Render a v2 theme JSON template.
367
+
368
+ Light themes use the [600] step for semantic accents (so text on white
369
+ has good contrast); dark themes use [400] (lighter accents on a dark
370
+ background). Both schemas match the format consumed by
371
+ `bootstack.style.theme_provider`.
372
+ """
373
+ if mode == "light":
374
+ foreground, background, step = "#212529", "#ffffff", "600"
375
+ else:
376
+ foreground, background, step = "#f8f9fa", "#212529", "400"
377
+
378
+ payload = {
379
+ "name": name,
380
+ "display_name": _theme_display_name(name),
381
+ "mode": mode,
382
+ "foreground": foreground,
383
+ "background": background,
384
+ "white": "#ffffff",
385
+ "black": "#000000",
386
+ "shades": _BASE_SHADES,
387
+ "semantic": {
388
+ "primary": f"blue[{step}]",
389
+ "secondary": f"gray[{step}]",
390
+ "success": f"green[{step}]",
391
+ "info": f"cyan[{step}]",
392
+ "warning": f"yellow[{step}]",
393
+ "danger": f"red[{step}]",
394
+ "light": "gray[100]",
395
+ "dark": "gray[900]",
396
+ },
397
+ }
398
+ import json as _json
399
+ return _json.dumps(payload, indent=2) + "\n"
400
+
401
+
402
+ def _get_light_theme_template(name: str) -> str:
403
+ """Get a v2 light-mode theme template."""
404
+ return _render_theme(name, "light")
405
+
406
+
407
+ def _get_dark_theme_template(name: str) -> str:
408
+ """Get a v2 dark-mode theme template."""
409
+ return _render_theme(name, "dark")
410
+
411
+
412
+ def _get_po_template(lang: str) -> str:
413
+ """Get a .po file template."""
414
+ from datetime import datetime, timezone
415
+
416
+ now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M%z")
417
+
418
+ return f'''\
419
+ # {lang.upper()} translations for the application.
420
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
421
+ # This file is distributed under the same license as the PACKAGE package.
422
+ #
423
+ msgid ""
424
+ msgstr ""
425
+ "Project-Id-Version: 1.0\\n"
426
+ "Report-Msgid-Bugs-To: \\n"
427
+ "POT-Creation-Date: {now}\\n"
428
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
429
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
430
+ "Language-Team: {lang.upper()} <LL@li.org>\\n"
431
+ "Language: {lang}\\n"
432
+ "MIME-Version: 1.0\\n"
433
+ "Content-Type: text/plain; charset=UTF-8\\n"
434
+ "Content-Transfer-Encoding: 8bit\\n"
435
+
436
+ # Example translation
437
+ # msgid "Hello"
438
+ # msgstr "Hello"
439
+ '''
bootstack/cli/build.py ADDED
@@ -0,0 +1,115 @@
1
+ """bootstack build command - Build the application for distribution."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ from bootstack.cli.config import TtkbConfig, find_config
12
+
13
+
14
+ def add_parser(subparsers: argparse._SubParsersAction) -> None:
15
+ """Add the 'build' subcommand parser."""
16
+ parser = subparsers.add_parser(
17
+ "build",
18
+ help="Build the application for distribution",
19
+ description="Build the application using the configured build backend.",
20
+ )
21
+ parser.add_argument(
22
+ "--clean",
23
+ action="store_true",
24
+ help="Clean build artifacts before building",
25
+ )
26
+ parser.set_defaults(func=run_build)
27
+
28
+
29
+ def run_build(args: argparse.Namespace) -> None:
30
+ """Execute the build command."""
31
+ # Find project root
32
+ config_path = find_config()
33
+ if config_path is None:
34
+ print("Error: No bootstack.toml found in current directory or parents.")
35
+ print("Run 'bootstack start <appname>' to create a new project first.")
36
+ return
37
+
38
+ project_root = config_path.parent
39
+ config = TtkbConfig.load(config_path)
40
+
41
+ # Check if project has been promoted
42
+ if config.build is None:
43
+ print("Error: Project has not been promoted for building.")
44
+ print("Run 'bootstack promote --pyinstaller' first.")
45
+ return
46
+
47
+ backend = config.build.backend
48
+
49
+ if backend == "pyinstaller":
50
+ _build_pyinstaller(config, project_root, clean=args.clean)
51
+ else:
52
+ print(f"Error: Unknown build backend '{backend}'")
53
+ return
54
+
55
+
56
+ def _build_pyinstaller(
57
+ config: TtkbConfig,
58
+ project_root: Path,
59
+ clean: bool = False,
60
+ ) -> None:
61
+ """Build using PyInstaller."""
62
+ # Check if PyInstaller is installed
63
+ try:
64
+ import PyInstaller # noqa: F401
65
+ except ImportError:
66
+ print("Error: PyInstaller is not installed.")
67
+ print("Install it with: pip install pyinstaller")
68
+ return
69
+
70
+ spec_path = project_root / "build" / "pyinstaller" / "app.spec"
71
+ if not spec_path.exists():
72
+ print("Error: PyInstaller spec file not found.")
73
+ print("Run 'bootstack promote --pyinstaller' to generate it.")
74
+ return
75
+
76
+ # Clean if requested
77
+ if clean:
78
+ print("Cleaning build artifacts...")
79
+ dist_dir = project_root / "dist"
80
+ build_dir = project_root / "build" / "pyinstaller" / "build"
81
+ if dist_dir.exists():
82
+ shutil.rmtree(dist_dir)
83
+ if build_dir.exists():
84
+ shutil.rmtree(build_dir)
85
+
86
+ print(f"Building '{config.app.name}' with PyInstaller...")
87
+ print()
88
+
89
+ # Run PyInstaller
90
+ cmd = [
91
+ sys.executable,
92
+ "-m",
93
+ "PyInstaller",
94
+ str(spec_path),
95
+ "--distpath",
96
+ str(project_root / "dist"),
97
+ "--workpath",
98
+ str(project_root / "build" / "pyinstaller" / "build"),
99
+ "--noconfirm",
100
+ ]
101
+
102
+ try:
103
+ result = subprocess.run(cmd, cwd=str(project_root))
104
+ if result.returncode == 0:
105
+ print()
106
+ print("Build completed successfully!")
107
+ print()
108
+ print(f"Output: {project_root / 'dist' / config.app.name}")
109
+ else:
110
+ print()
111
+ print("Build failed.")
112
+ sys.exit(result.returncode)
113
+ except KeyboardInterrupt:
114
+ print("\nBuild interrupted.")
115
+ sys.exit(1)