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
@@ -0,0 +1,607 @@
1
+ # bootstack DataSource Module
2
+
3
+ A flexible, extensible data management system providing unified interfaces for working with data from various sources (memory, databases, files) with built-in support for pagination, filtering, sorting, and CRUD operations.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Architecture Overview](#architecture-overview)
8
+ - [Built-in Implementations](#built-in-implementations)
9
+ - [Creating Custom DataSources](#creating-custom-datasources)
10
+ - [API Reference](#api-reference)
11
+ - [Examples](#examples)
12
+
13
+ ## Architecture Overview
14
+
15
+ The datasource module is built on three key components:
16
+
17
+ ### 1. DataSourceProtocol (types.py)
18
+
19
+ A Protocol (duck-typing interface) that defines the contract all datasources must follow. This enables type checking and IDE support without requiring inheritance.
20
+
21
+ ```python
22
+ from typing import Protocol
23
+
24
+ class DataSourceProtocol(Protocol):
25
+ page_size: int
26
+ def set_data(self, records): ...
27
+ def get_page(self, page=None): ...
28
+ # ... other methods
29
+ ```
30
+
31
+ ### 2. BaseDataSource (base.py)
32
+
33
+ An abstract base class that provides:
34
+ - **Abstract method definitions** - Enforces implementation of required methods
35
+ - **Shared utility methods** - Common functionality like type inference and literal parsing
36
+ - **Hook methods** - Extension points for customization (e.g., `_before_create`, `_after_update`)
37
+
38
+ This is the **recommended base class** for creating custom datasources.
39
+
40
+ ### 3. Concrete Implementations
41
+
42
+ Built-in datasources that inherit from `BaseDataSource`:
43
+ - **MemoryDataSource** - Fast in-memory storage
44
+ - **SqliteDataSource** - Persistent SQLite storage
45
+ - **FileDataSource** - File-based storage (CSV, JSON, JSONL, TSV)
46
+
47
+ ## Built-in Implementations
48
+
49
+ ### MemoryDataSource
50
+
51
+ Best for small to medium datasets that fit comfortably in memory.
52
+
53
+ ```python
54
+ from bootstack.datasource import MemoryDataSource
55
+
56
+ ds = MemoryDataSource(page_size=20)
57
+ ds.set_data([
58
+ {"name": "Alice", "age": 30, "city": "NYC"},
59
+ {"name": "Bob", "age": 25, "city": "LA"},
60
+ ])
61
+
62
+ ds.set_filter("age >= 25")
63
+ ds.set_sort("name ASC")
64
+ page = ds.get_page(0)
65
+ ```
66
+
67
+ **Features:**
68
+ - SQL-like filtering (WHERE syntax)
69
+ - Multi-column sorting (ORDER BY syntax)
70
+ - O(1) ID lookups via internal index
71
+ - Automatic ID generation
72
+
73
+ ### SqliteDataSource
74
+
75
+ Best for large datasets requiring persistence or SQL capabilities.
76
+
77
+ ```python
78
+ from bootstack.datasource import SqliteDataSource
79
+
80
+ # Persistent database
81
+ ds = SqliteDataSource("mydata.db", page_size=50)
82
+ ds.set_data([...])
83
+
84
+ # In-memory database
85
+ ds = SqliteDataSource(":memory:", page_size=50)
86
+ ```
87
+
88
+ **Features:**
89
+ - SQL-native filtering and sorting
90
+ - Persistent storage across sessions
91
+ - Efficient for large datasets
92
+ - Automatic schema inference
93
+
94
+ ### FileDataSource
95
+
96
+ Best for loading data from files with preprocessing needs.
97
+
98
+ ```python
99
+ from bootstack.datasource import FileDataSource, FileSourceConfig
100
+
101
+ # Simple CSV loading
102
+ ds = FileDataSource("data.csv")
103
+ ds.load()
104
+
105
+ # With transformations
106
+ config = FileSourceConfig(
107
+ column_renames={'old_name': 'new_name'},
108
+ column_types={'age': int, 'salary': float},
109
+ row_filter=lambda r: r['status'] == 'active'
110
+ )
111
+ ds = FileDataSource("data.json", config=config)
112
+ ds.load()
113
+ ```
114
+
115
+ **Features:**
116
+ - Supports CSV, TSV, JSON, JSONL
117
+ - Multiple loading strategies (eager, lazy, chunked, hybrid)
118
+ - Transformation pipeline
119
+ - Progress callbacks for large files
120
+
121
+ ## Creating Custom DataSources
122
+
123
+ ### Method 1: Inherit from BaseDataSource (Recommended)
124
+
125
+ This is the easiest and most common approach. You get utility methods for free and only need to implement storage-specific logic.
126
+
127
+ ```python
128
+ from bootstack.datasource import BaseDataSource
129
+ from typing import Any, Dict, List, Optional
130
+
131
+ class RedisDataSource(BaseDataSource):
132
+ """Custom datasource backed by Redis."""
133
+
134
+ def __init__(self, redis_client, page_size=10):
135
+ super().__init__(page_size)
136
+ self.redis = redis_client
137
+ self._key_prefix = "myapp:records:"
138
+
139
+ def set_data(self, records):
140
+ """Store records in Redis."""
141
+ for record in records:
142
+ record_id = record.get('id', self._generate_id())
143
+ key = f"{self._key_prefix}{record_id}"
144
+ self.redis.set(key, json.dumps(record))
145
+ return self
146
+
147
+ def get_page(self, page=None):
148
+ """Retrieve a page of records."""
149
+ if page is not None:
150
+ self._page = page
151
+
152
+ # Get all keys and paginate
153
+ keys = self.redis.keys(f"{self._key_prefix}*")
154
+ start = self._page * self.page_size
155
+ end = start + self.page_size
156
+
157
+ records = []
158
+ for key in keys[start:end]:
159
+ data = self.redis.get(key)
160
+ records.append(json.loads(data))
161
+
162
+ return records
163
+
164
+ def create_record(self, record):
165
+ """Create new record in Redis."""
166
+ record_id = record.get('id', self._generate_id())
167
+ record['id'] = record_id
168
+
169
+ # Use hook for logging/validation
170
+ record = self._before_create(record)
171
+
172
+ key = f"{self._key_prefix}{record_id}"
173
+ self.redis.set(key, json.dumps(record))
174
+
175
+ # Use hook for post-creation tasks
176
+ self._after_create(record_id, record)
177
+
178
+ return record_id
179
+
180
+ def read_record(self, record_id):
181
+ """Read single record from Redis."""
182
+ key = f"{self._key_prefix}{record_id}"
183
+ data = self.redis.get(key)
184
+ return json.loads(data) if data else None
185
+
186
+ def update_record(self, record_id, updates):
187
+ """Update record in Redis."""
188
+ record = self.read_record(record_id)
189
+ if not record:
190
+ return False
191
+
192
+ updates = self._before_update(record_id, updates)
193
+ record.update(updates)
194
+
195
+ key = f"{self._key_prefix}{record_id}"
196
+ self.redis.set(key, json.dumps(record))
197
+
198
+ self._after_update(record_id, updates, True)
199
+ return True
200
+
201
+ def delete_record(self, record_id):
202
+ """Delete record from Redis."""
203
+ self._before_delete(record_id)
204
+ key = f"{self._key_prefix}{record_id}"
205
+ result = self.redis.delete(key) > 0
206
+ self._after_delete(record_id, result)
207
+ return result
208
+
209
+ # Implement remaining abstract methods...
210
+ # (set_filter, set_sort, next_page, prev_page, has_next_page,
211
+ # total_count, selection methods, export_to_csv, etc.)
212
+ ```
213
+
214
+ ### Method 2: Implement the Protocol (Advanced)
215
+
216
+ For maximum flexibility, implement the `DataSourceProtocol` without inheritance. This is useful when you need to integrate with existing classes or have complex inheritance requirements.
217
+
218
+ ```python
219
+ from bootstack.datasource import DataSourceProtocol
220
+ from typing import List, Dict, Any, Optional
221
+
222
+ class APIDataSource:
223
+ """Datasource that fetches data from a REST API."""
224
+
225
+ def __init__(self, api_url: str, page_size: int = 10):
226
+ self.api_url = api_url
227
+ self.page_size = page_size
228
+ self._page = 0
229
+ self._cache = []
230
+
231
+ def set_data(self, records):
232
+ """Cache data locally."""
233
+ self._cache = list(records)
234
+ return self
235
+
236
+ def get_page(self, page: Optional[int] = None) -> List[Dict[str, Any]]:
237
+ """Fetch page from API or cache."""
238
+ if page is not None:
239
+ self._page = page
240
+
241
+ # Make API request with pagination
242
+ response = requests.get(
243
+ self.api_url,
244
+ params={'page': self._page, 'per_page': self.page_size}
245
+ )
246
+ return response.json()['data']
247
+
248
+ # Implement all other protocol methods...
249
+ ```
250
+
251
+ ### Using Utility Methods
252
+
253
+ The `BaseDataSource` provides several utility methods you can use:
254
+
255
+ ```python
256
+ class MyDataSource(BaseDataSource):
257
+ def process_record(self, raw_data: str):
258
+ # Parse literals
259
+ age = self._coerce_literal("25") # Returns int 25
260
+ active = self._coerce_literal("true") # Returns bool True
261
+ name = self._coerce_literal("'Alice'") # Returns str "Alice"
262
+
263
+ # Infer SQL types
264
+ age_type = self._infer_type(25) # Returns "INTEGER"
265
+ name_type = self._infer_type("Alice") # Returns "TEXT"
266
+
267
+ # Validate records
268
+ record = {"name": name, "age": age}
269
+ self._validate_record(record) # Raises ValueError if not dict
270
+
271
+ return record
272
+ ```
273
+
274
+ ### Using Hook Methods
275
+
276
+ Hook methods let you add custom behavior without overriding core logic:
277
+
278
+ ```python
279
+ class AuditedDataSource(BaseDataSource):
280
+ def __init__(self):
281
+ super().__init__()
282
+ self.audit_log = []
283
+
284
+ def _before_create(self, record):
285
+ """Add timestamp before creating."""
286
+ record['created_at'] = datetime.now().isoformat()
287
+ return record
288
+
289
+ def _after_create(self, record_id, record):
290
+ """Log creation to audit trail."""
291
+ self.audit_log.append({
292
+ 'action': 'CREATE',
293
+ 'record_id': record_id,
294
+ 'timestamp': datetime.now()
295
+ })
296
+
297
+ def _before_update(self, record_id, updates):
298
+ """Add modified timestamp."""
299
+ updates['modified_at'] = datetime.now().isoformat()
300
+ return updates
301
+
302
+ def _after_update(self, record_id, updates, success):
303
+ """Log update to audit trail."""
304
+ if success:
305
+ self.audit_log.append({
306
+ 'action': 'UPDATE',
307
+ 'record_id': record_id,
308
+ 'changes': updates,
309
+ 'timestamp': datetime.now()
310
+ })
311
+ ```
312
+
313
+ ## API Reference
314
+
315
+ ### Required Methods (All Implementations)
316
+
317
+ #### Data & View Configuration
318
+ - `set_data(records)` - Load data into the datasource
319
+ - `set_filter(where_sql)` - Apply SQL-like WHERE filter
320
+ - `set_sort(order_by_sql)` - Apply SQL-like ORDER BY sorting
321
+
322
+ #### Pagination
323
+ - `get_page(page=None)` - Get records for specified page
324
+ - `next_page()` - Move to next page
325
+ - `prev_page()` - Move to previous page
326
+ - `has_next_page()` - Check if next page exists
327
+ - `total_count()` - Get total record count
328
+
329
+ #### CRUD Operations
330
+ - `create_record(record)` - Create new record, returns ID
331
+ - `read_record(record_id)` - Read single record by ID
332
+ - `update_record(record_id, updates)` - Update record fields
333
+ - `delete_record(record_id)` - Delete record by ID
334
+
335
+ #### Selection Management
336
+ - `select_record(record_id)` - Mark record as selected
337
+ - `unselect_record(record_id)` - Unmark record
338
+ - `select_all(current_page_only=False)` - Select all/page records
339
+ - `unselect_all(current_page_only=False)` - Unselect all/page records
340
+ - `get_selected(page=None)` - Get selected records
341
+ - `selected_count()` - Count selected records
342
+
343
+ #### Export
344
+ - `export_to_csv(filepath, include_all=True)` - Export to CSV
345
+
346
+ #### Index-based Access
347
+ - `get_page_from_index(start_index, count)` - Get records by index range
348
+
349
+ ### Utility Methods (Inherited from BaseDataSource)
350
+
351
+ - `_infer_type(value)` - Infer SQL type from Python value
352
+ - `_is_mapping(x)` - Check if value is dict-like
353
+ - `_coerce_literal(s)` - Parse string literal to Python value
354
+ - `_validate_record(record)` - Validate record is a dictionary
355
+
356
+ ### Hook Methods (Inherited from BaseDataSource)
357
+
358
+ Override these to add custom behavior:
359
+
360
+ - `_before_create(record)` - Called before creating record
361
+ - `_after_create(record_id, record)` - Called after creating record
362
+ - `_before_update(record_id, updates)` - Called before updating
363
+ - `_after_update(record_id, updates, success)` - Called after updating
364
+ - `_before_delete(record_id)` - Called before deleting
365
+ - `_after_delete(record_id, success)` - Called after deleting
366
+
367
+ ## Examples
368
+
369
+ ### Example 1: MongoDB DataSource
370
+
371
+ ```python
372
+ from bootstack.datasource import BaseDataSource
373
+ from pymongo import MongoClient
374
+
375
+ class MongoDataSource(BaseDataSource):
376
+ def __init__(self, connection_string, database, collection, page_size=10):
377
+ super().__init__(page_size)
378
+ self.client = MongoClient(connection_string)
379
+ self.db = self.client[database]
380
+ self.collection = self.db[collection]
381
+ self._filter = {}
382
+ self._sort = []
383
+
384
+ def set_data(self, records):
385
+ """Insert records into MongoDB."""
386
+ if records:
387
+ self.collection.insert_many(list(records))
388
+ return self
389
+
390
+ def set_filter(self, where_sql=""):
391
+ """Convert SQL-like filter to MongoDB query."""
392
+ # Simple implementation - in production, use a proper parser
393
+ if "age >= 30" in where_sql:
394
+ self._filter = {"age": {"$gte": 30}}
395
+ else:
396
+ self._filter = {}
397
+
398
+ def set_sort(self, order_by_sql=""):
399
+ """Convert SQL ORDER BY to MongoDB sort."""
400
+ if "name ASC" in order_by_sql:
401
+ self._sort = [("name", 1)]
402
+ elif "age DESC" in order_by_sql:
403
+ self._sort = [("age", -1)]
404
+ else:
405
+ self._sort = []
406
+
407
+ def get_page(self, page=None):
408
+ if page is not None:
409
+ self._page = page
410
+
411
+ skip = self._page * self.page_size
412
+ cursor = self.collection.find(self._filter).sort(self._sort).skip(skip).limit(self.page_size)
413
+ return list(cursor)
414
+
415
+ def create_record(self, record):
416
+ result = self.collection.insert_one(record)
417
+ return result.inserted_id
418
+
419
+ def read_record(self, record_id):
420
+ return self.collection.find_one({"_id": record_id})
421
+
422
+ def update_record(self, record_id, updates):
423
+ result = self.collection.update_one({"_id": record_id}, {"$set": updates})
424
+ return result.modified_count > 0
425
+
426
+ def delete_record(self, record_id):
427
+ result = self.collection.delete_one({"_id": record_id})
428
+ return result.deleted_count > 0
429
+
430
+ # ... implement remaining methods
431
+ ```
432
+
433
+ ### Example 2: Cached API DataSource
434
+
435
+ ```python
436
+ from bootstack.datasource import BaseDataSource
437
+ import requests
438
+ from functools import lru_cache
439
+ from datetime import datetime, timedelta
440
+
441
+ class CachedAPIDataSource(BaseDataSource):
442
+ def __init__(self, api_url, cache_ttl=300, page_size=10):
443
+ super().__init__(page_size)
444
+ self.api_url = api_url
445
+ self.cache_ttl = cache_ttl
446
+ self._cache = {}
447
+ self._cache_time = {}
448
+
449
+ def _is_cache_valid(self, key):
450
+ """Check if cached data is still valid."""
451
+ if key not in self._cache_time:
452
+ return False
453
+ age = datetime.now() - self._cache_time[key]
454
+ return age < timedelta(seconds=self.cache_ttl)
455
+
456
+ def get_page(self, page=None):
457
+ if page is not None:
458
+ self._page = page
459
+
460
+ cache_key = f"page_{self._page}"
461
+
462
+ # Return cached data if valid
463
+ if self._is_cache_valid(cache_key):
464
+ return self._cache[cache_key]
465
+
466
+ # Fetch from API
467
+ response = requests.get(
468
+ f"{self.api_url}/records",
469
+ params={'page': self._page, 'per_page': self.page_size}
470
+ )
471
+ data = response.json()
472
+
473
+ # Cache the result
474
+ self._cache[cache_key] = data
475
+ self._cache_time[cache_key] = datetime.now()
476
+
477
+ return data
478
+
479
+ def create_record(self, record):
480
+ # Invalidate cache on write
481
+ self._cache.clear()
482
+ self._cache_time.clear()
483
+
484
+ response = requests.post(f"{self.api_url}/records", json=record)
485
+ return response.json()['id']
486
+
487
+ # ... implement remaining methods
488
+ ```
489
+
490
+ ### Example 3: Multi-Source DataSource
491
+
492
+ ```python
493
+ from bootstack.datasource import BaseDataSource
494
+
495
+ class MultiSourceDataSource(BaseDataSource):
496
+ """Aggregates data from multiple datasources."""
497
+
498
+ def __init__(self, sources, page_size=10):
499
+ super().__init__(page_size)
500
+ self.sources = sources # List of datasources
501
+ self._aggregated_data = []
502
+
503
+ def set_data(self, records):
504
+ """Not applicable for multi-source."""
505
+ raise NotImplementedError("Use add_source() instead")
506
+
507
+ def add_source(self, datasource):
508
+ """Add a datasource to aggregate."""
509
+ self.sources.append(datasource)
510
+
511
+ def _aggregate_data(self):
512
+ """Combine data from all sources."""
513
+ all_records = []
514
+ for source in self.sources:
515
+ source_records = source.get_page_from_index(0, source.total_count())
516
+ all_records.extend(source_records)
517
+ return all_records
518
+
519
+ def get_page(self, page=None):
520
+ if page is not None:
521
+ self._page = page
522
+
523
+ all_data = self._aggregate_data()
524
+ start = self._page * self.page_size
525
+ end = start + self.page_size
526
+ return all_data[start:end]
527
+
528
+ # ... implement remaining methods
529
+ ```
530
+
531
+ ## Best Practices
532
+
533
+ 1. **Always call `super().__init__(page_size)`** in your `__init__` method
534
+ 2. **Use hook methods** for cross-cutting concerns (logging, validation, caching)
535
+ 3. **Inherit utility methods** instead of reimplementing them
536
+ 4. **Handle errors gracefully** - return False/None for failures rather than raising
537
+ 5. **Document your datasource** - explain what backend it uses and any special requirements
538
+ 6. **Test thoroughly** - ensure all protocol methods work correctly
539
+ 7. **Consider performance** - implement efficient filtering and pagination for large datasets
540
+
541
+ ## Testing Your DataSource
542
+
543
+ ```python
544
+ def test_custom_datasource():
545
+ ds = MyCustomDataSource()
546
+
547
+ # Test basic operations
548
+ ds.set_data([{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}])
549
+ assert ds.total_count() == 2
550
+
551
+ # Test CRUD
552
+ new_id = ds.create_record({"name": "Charlie"})
553
+ assert ds.read_record(new_id) is not None
554
+
555
+ # Test pagination
556
+ page = ds.get_page(0)
557
+ assert isinstance(page, list)
558
+
559
+ # Test filtering
560
+ ds.set_filter("name = 'Alice'")
561
+ filtered = ds.get_page(0)
562
+ assert len(filtered) == 1
563
+
564
+ # Test it's an instance of BaseDataSource
565
+ assert isinstance(ds, BaseDataSource)
566
+ ```
567
+
568
+ ## Migration Guide
569
+
570
+ If you have an existing datasource implementation, here's how to migrate to use `BaseDataSource`:
571
+
572
+ ### Before (Standalone Class)
573
+
574
+ ```python
575
+ class MyDataSource:
576
+ def __init__(self, page_size=10):
577
+ self.page_size = page_size
578
+ self._page = 0
579
+
580
+ @staticmethod
581
+ def _infer_type(value):
582
+ # Your implementation
583
+ pass
584
+ ```
585
+
586
+ ### After (Inheriting BaseDataSource)
587
+
588
+ ```python
589
+ from bootstack.datasource import BaseDataSource
590
+
591
+ class MyDataSource(BaseDataSource):
592
+ def __init__(self, page_size=10):
593
+ super().__init__(page_size) # Initialize base class
594
+ # BaseDataSource now provides _page and utility methods
595
+
596
+ # Remove _infer_type - inherited from BaseDataSource
597
+ ```
598
+
599
+ ## Support
600
+
601
+ For questions, issues, or feature requests, please visit:
602
+ - GitHub Issues: https://github.com/israel-dryer/bootstack/issues
603
+ - Documentation: https://bootstack.org/
604
+
605
+ ## License
606
+
607
+ This module is part of bootstack and follows the same license terms.
@@ -0,0 +1,51 @@
1
+ """Data source abstraction for bootstack widgets.
2
+
3
+ Provides unified interface for data management with multiple backend implementations:
4
+ - MemoryDataSource: Fast in-memory storage for small to medium datasets
5
+ - SqliteDataSource: Persistent SQLite storage for large datasets
6
+ - FileDataSource: File-based storage with support for CSV, JSON, and various formats
7
+
8
+ All datasources support:
9
+ - Pagination with configurable page size
10
+ - SQL-like filtering and sorting
11
+ - Full CRUD operations (create, read, update, delete)
12
+ - Record selection tracking
13
+ - CSV export
14
+
15
+ Usage:
16
+ from bootstack.datasource import MemoryDataSource, SqliteDataSource, FileDataSource
17
+
18
+ # In-memory datasource
19
+ ds = MemoryDataSource(page_size=20)
20
+ ds.set_data([{"name": "Alice", "age": 30}, ...])
21
+
22
+ # SQLite datasource (persistent)
23
+ db = SqliteDataSource("mydata.db", page_size=50)
24
+ db.set_data([{"name": "Bob", "age": 25}, ...])
25
+
26
+ # File datasource (CSV, JSON, etc.)
27
+ file_ds = FileDataSource("data.csv", page_size=25)
28
+ file_ds.load()
29
+
30
+ # Common operations (work with all)
31
+ ds.set_filter("age >= 25")
32
+ ds.set_sort("name ASC")
33
+ page1 = ds.get_page(0)
34
+ """
35
+
36
+ from bootstack.datasource.base import BaseDataSource
37
+ from bootstack.datasource.memory_source import MemoryDataSource
38
+ from bootstack.datasource.sqlite_source import SqliteDataSource
39
+ from bootstack.datasource.file_source import FileDataSource, FileSourceConfig
40
+ from bootstack.datasource.types import DataSourceProtocol, Record, Primitive
41
+
42
+ __all__ = [
43
+ 'BaseDataSource',
44
+ 'MemoryDataSource',
45
+ 'SqliteDataSource',
46
+ 'FileDataSource',
47
+ 'FileSourceConfig',
48
+ 'DataSourceProtocol',
49
+ 'Record',
50
+ 'Primitive',
51
+ ]