bootstack 0.2.1__py3-none-any.whl → 0.2.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.
@@ -282,7 +282,9 @@ class PublicWidgetBase:
282
282
  Example:
283
283
  .. code-block:: python
284
284
 
285
- widget.emit("change", data=bs.events.ChangeEvent(value=new_value))
285
+ from bootstack.events import ChangeEvent
286
+
287
+ field.emit("change", data=ChangeEvent(value=new_value))
286
288
  """
287
289
  sequence = resolve_event(self, str(event))
288
290
 
@@ -29,7 +29,7 @@ from bootstack.style.style import get_style
29
29
  from bootstack.data.sqlite_source import SqliteDataSource
30
30
  from bootstack.data.query import col, any_of, all_of
31
31
  from bootstack.widgets._impl.primitives.button import Button
32
- from bootstack._runtime.utility import bind_right_click
32
+ from bootstack._runtime.utility import bind_right_click, debug_log_exception
33
33
  from bootstack.widgets._impl.composites.contextmenu import ContextMenu
34
34
  from bootstack.widgets._impl.composites.tooltip import ToolTip
35
35
  from bootstack.widgets._impl.composites.dropdownbutton import DropdownButton
@@ -1148,8 +1148,8 @@ class TableView(Frame):
1148
1148
  self._tree.bind("<Button-1>", self._on_header_click)
1149
1149
  self._tree.bind("<<TreeviewSelect>>", self._on_selection_event)
1150
1150
  # Keep group-header chevrons in sync with their open/closed state.
1151
- self._tree.bind("<<TreeviewOpen>>", self._refresh_group_chevrons, add="+")
1152
- self._tree.bind("<<TreeviewClose>>", self._refresh_group_chevrons, add="+")
1151
+ self._tree.bind("<<TreeviewOpen>>", self._refresh_group_chevrons_deferred, add="+")
1152
+ self._tree.bind("<<TreeviewClose>>", self._refresh_group_chevrons_deferred, add="+")
1153
1153
  self._tree.bind("<ButtonRelease-1>", self._on_row_click_event)
1154
1154
  # Escape clears the selection (also reachable in single-select mode, where
1155
1155
  # clicking can't return to an empty selection). Bound on the tree widget
@@ -1158,8 +1158,10 @@ class TableView(Frame):
1158
1158
  self._tree.bind("<Escape>", lambda _e: self.deselect_all(), add="+")
1159
1159
  if self._context_menus != "none":
1160
1160
  bind_right_click(self._tree, self._on_tree_context)
1161
- if self._editing['updating']:
1162
- self._tree.bind("<Double-1>", self._on_row_double_click)
1161
+ # Bound unconditionally: `on_row_double_click` is public API and does not
1162
+ # depend on editing. The handler itself gates the built-in edit dialog on
1163
+ # `_editing['updating']`, so editing behavior is unchanged.
1164
+ self._tree.bind("<Double-1>", self._on_row_double_click)
1163
1165
  # Track resize events to rebalance grouped layouts
1164
1166
  self._tree.bind("<Configure>", self._on_tree_configure)
1165
1167
 
@@ -1690,9 +1692,12 @@ class TableView(Frame):
1690
1692
  col_idx = 0
1691
1693
  # Right-click does not alter the selection (left-click owns that); it
1692
1694
  # only records which row the menu targets and opens the menu there.
1693
- self._context_iid = iid or None
1694
- if not iid:
1695
+ # A group header is a real tree item but holds no record — it is absent
1696
+ # from `_row_map` — so it targets nothing, exactly like empty space.
1697
+ if not iid or iid not in self._row_map:
1698
+ self._context_iid = None
1695
1699
  return # empty space or a group-header row — no row menu
1700
+ self._context_iid = iid
1696
1701
  rec = self._row_map.get(iid, {})
1697
1702
  self.event_generate("<<RowRightClick>>", data=RowEvent(record=self._public_record(rec), id=self._record_id(rec)))
1698
1703
  self._row_menu_col = col_idx
@@ -1704,8 +1709,8 @@ class TableView(Frame):
1704
1709
  if region == "heading":
1705
1710
  return
1706
1711
  iid = self._tree.identify_row(event.y)
1707
- if not iid:
1708
- return
1712
+ if not iid or iid not in self._row_map:
1713
+ return # empty space or a group-header row (no record)
1709
1714
  rec = self._row_map.get(iid, {})
1710
1715
  self.event_generate("<<RowDoubleClick>>", data=RowEvent(record=self._public_record(rec), id=self._record_id(rec)))
1711
1716
  if self._editing['updating']:
@@ -2343,6 +2348,19 @@ class TableView(Frame):
2343
2348
  except Exception:
2344
2349
  pass
2345
2350
 
2351
+ def _refresh_group_chevrons_deferred(self, _event=None) -> None:
2352
+ """Refresh chevrons once Tk has applied the item's new open state.
2353
+
2354
+ The toolkit reports an expand *before* it records it, so reading the
2355
+ state inside the notification paints the previous chevron. Deferring to
2356
+ the next idle point reads the settled state. Scheduled on the root so
2357
+ the pending callback outlives any widget being torn down.
2358
+ """
2359
+ try:
2360
+ self._root().after_idle(self._refresh_group_chevrons)
2361
+ except Exception:
2362
+ pass
2363
+
2346
2364
  def _refresh_group_chevrons(self, _event=None) -> None:
2347
2365
  """Sync every group header's chevron to its current open/closed state."""
2348
2366
  if not self._group_by_key:
@@ -2845,6 +2863,23 @@ class TableView(Frame):
2845
2863
  """
2846
2864
  return self._selection_markers_active()
2847
2865
 
2866
+ def _take_click_focus(self, iid) -> None:
2867
+ """Give the body keyboard focus, and point it at the clicked row.
2868
+
2869
+ Both branches that call this answer the click themselves and stop it,
2870
+ which also stops the built-in handling that would otherwise have done
2871
+ this. Without it a click leaves the keyboard aimed somewhere else, so
2872
+ the row the user just clicked is not the row the arrow keys move from.
2873
+ """
2874
+ try:
2875
+ self._tree.focus_set()
2876
+ if iid:
2877
+ self._tree.focus(iid)
2878
+ except Exception:
2879
+ # Silence here would restore the very bug this method exists to
2880
+ # fix, with nothing to show for it on any channel.
2881
+ debug_log_exception("could not move keyboard focus to the clicked row")
2882
+
2848
2883
  def _on_header_click(self, event):
2849
2884
  """Handle left-click: header sorting, or toggle-select with checkboxes."""
2850
2885
  # A left-click on the tree dismisses an open context menu. Do it
@@ -2873,20 +2908,25 @@ class TableView(Frame):
2873
2908
  # fall through to normal selection below.
2874
2909
  iid = self._tree.identify_row(event.y)
2875
2910
  if iid and self._tree.get_children(iid):
2911
+ self._take_click_focus(iid)
2876
2912
  self._toggle_group_open(iid)
2877
2913
  return "break"
2878
2914
 
2879
2915
  # Body click with checkboxes showing: treat the list like a checklist —
2880
2916
  # a plain click toggles the row in/out of the selection (no modifier),
2881
2917
  # and "break" suppresses ttk's default replace-the-selection behavior.
2918
+ # Only a click that lands on a row earns that "break" — a click on a
2919
+ # column separator reports no row, and stopping it there would kill the
2920
+ # drag that resizes the column.
2882
2921
  if self._toggle_select_active():
2883
2922
  iid = self._tree.identify_row(event.y)
2884
2923
  if iid:
2924
+ self._take_click_focus(iid)
2885
2925
  if iid in self._tree.selection():
2886
2926
  self._tree.selection_remove(iid)
2887
2927
  else:
2888
2928
  self._tree.selection_add(iid)
2889
- return "break"
2929
+ return "break"
2890
2930
  return None
2891
2931
 
2892
2932
  def _filter_header_column(self) -> None:
@@ -1,302 +1,302 @@
1
- Metadata-Version: 2.4
2
- Name: bootstack
3
- Version: 0.2.1
4
- Summary: Build desktop GUI apps in pure Python and ship them as a standalone executable — built on Tk, no Tkinter boilerplate.
5
- Author-email: Israel Dryer <israel.dryer@gmail.com>
6
- License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/israel-dryer/bootstack
8
- Project-URL: Documentation, https://bootstack.org/
9
- Keywords: tkinter,ttk,gui,desktop,python3,ui,widgets,theming,cross-platform,modern,framework,application-framework,desktop-ui,python-gui
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Environment :: Win32 (MS Windows)
12
- Classifier: Environment :: MacOS X
13
- Classifier: Environment :: X11 Applications
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.12
17
- Classifier: Programming Language :: Python :: 3.13
18
- Classifier: Programming Language :: Python :: 3.14
19
- Classifier: Topic :: Software Development :: User Interfaces
20
- Classifier: Operating System :: OS Independent
21
- Requires-Python: >=3.12
22
- Description-Content-Type: text/markdown
23
- License-File: LICENSE
24
- License-File: NOTICE
25
- Requires-Dist: pillow<=12,>=10
26
- Requires-Dist: pygments>=2.15
27
- Requires-Dist: typing-extensions>=4.10
28
- Requires-Dist: Babel>=2.12
29
- Requires-Dist: python-dateutil>=2.9
30
- Requires-Dist: dateparser>=1.1
31
- Requires-Dist: pywinstyles>=1.8; sys_platform == "win32"
32
- Requires-Dist: screeninfo>=0.8
33
- Provides-Extra: excel
34
- Requires-Dist: XlsxWriter>=3; extra == "excel"
35
- Provides-Extra: parquet
36
- Requires-Dist: pyarrow>=14; extra == "parquet"
37
- Provides-Extra: hdf5
38
- Requires-Dist: pandas>=2; extra == "hdf5"
39
- Requires-Dist: tables>=3.8; extra == "hdf5"
40
- Provides-Extra: viz
41
- Requires-Dist: matplotlib>=3.8; extra == "viz"
42
- Provides-Extra: viz-seaborn
43
- Requires-Dist: matplotlib>=3.8; extra == "viz-seaborn"
44
- Requires-Dist: seaborn>=0.13; extra == "viz-seaborn"
45
- Provides-Extra: docs
46
- Requires-Dist: sphinx>=7.2; extra == "docs"
47
- Requires-Dist: pydata-sphinx-theme; extra == "docs"
48
- Requires-Dist: sphinx-design; extra == "docs"
49
- Requires-Dist: sphinx-copybutton; extra == "docs"
50
- Requires-Dist: sphinx-autobuild; extra == "docs"
51
- Requires-Dist: myst-parser; extra == "docs"
52
- Dynamic: license-file
53
-
54
- ![bootstack](https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/banner-readme.png)
55
-
56
- ![](https://img.shields.io/github/release/israel-dryer/bootstack.svg)
57
- [![Downloads](https://pepy.tech/badge/bootstack)](https://pepy.tech/project/bootstack)
58
- [![Downloads](https://pepy.tech/badge/bootstack/month)](https://pepy.tech/project/bootstack)
59
- ![](https://img.shields.io/github/issues/israel-dryer/bootstack.svg)
60
- ![](https://img.shields.io/github/issues-closed/israel-dryer/bootstack.svg)
61
- ![](https://img.shields.io/github/license/israel-dryer/bootstack.svg)
62
- ![](https://img.shields.io/github/stars/israel-dryer/bootstack.svg)
63
- ![](https://img.shields.io/github/forks/israel-dryer/bootstack.svg)
64
-
65
- > Full documentation is at **[bootstack.org](https://bootstack.org)**.
66
-
67
- ### Desktop apps in pure Python — Tk underneath, none of the boilerplate.
68
-
69
- bootstack is built on Tk, so the install is light and your app ships as a small standalone executable. But you'll never
70
- write a `StringVar` or call `.pack()` — the API is its own. 60+ widgets, reactive state, and a CLI that scaffolds and
71
- packages the whole thing.
72
-
73
- <p align="center">
74
- <picture>
75
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-dark.png">
76
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-light.png">
77
- <img alt="bootstack hero demo" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-light.png">
78
- </picture>
79
- </p>
80
-
81
- ## Why bootstack?
82
-
83
- Most Python desktop frameworks make you fight the framework. bootstack gets out of the way.
84
-
85
- - **30% less code** — the declarative, context-manager layout eliminates geometry calls, explicit parenting, and most of the wiring boilerplate
86
- - **Reads like Python** — nested `with` blocks mirror your UI structure; the code hierarchy *is* the layout
87
- - **Modern layout system** — `Row`, `Column`, and `Grid` containers handle spacing, alignment, and growth automatically; a screen-axis vocabulary (`gap`, `padding`, `margin`, `horizontal`, `vertical`, `grow`) without writing CSS
88
- - **60+ widgets out of the box** — primitives through full composites: tables, trees, calendars, date pickers, gauges, sliders, and more — including a full `CodeEditor` with syntax highlighting, line numbers, bracket matching, smart indent, and search; no external editor dependency required
89
- - **Reactive signals** — observable state that flows between widgets; bind once, update everywhere
90
- - **Event and stream pipelines** — compose, filter, debounce, and throttle UI events with a chainable stream API
91
- - **Built-in icons** — the full Bootstrap Icons catalog, theme-aware and recolorable, bundled with the framework
92
- - **Built-in localization** — 23 language catalogs, locale-aware number/date/time formatting, runtime language switching
93
- - **Semantic styling** — `accent="primary"`, `variant="outline"` — no hard-coded colors; looks right across every theme automatically
94
- - **10 paired light/dark themes** — popular dev color schemes plus Bootstrap, with a runtime switcher and a custom-theme API
95
- - **Forms and validation** — field-level validators, inline error messages, and a `FormDialog` for quick modal forms
96
- - **DataSource abstraction** — one interface over SQLite, in-memory, and file backends with filtering, sorting, pagination, and CRUD
97
- - **Data visualization** — embed `matplotlib` (and `seaborn`) figures with `Chart`; they recolor with the theme and live-update from a `Signal` or `DataSource` (optional `viz` extra)
98
- - **A real CLI** — scaffold, run, add pages/views/dialogs/themes, and package for distribution
99
- - **Hot reload** — `bootstack dev app.py` updates the running app on save and keeps your place; module-level state and the active page survive the reload
100
- - **PyInstaller packaging built in** — `bootstack build` produces a standalone executable; no separate toolchain required
101
-
102
- ## Hot reload
103
-
104
- Edit and save — the running window updates in place. `bootstack dev app.py`
105
- reloads the UI on every save while keeping your window position, module-level
106
- state, and active page, so you never lose your spot.
107
-
108
- <p align="center">
109
- <video src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/docs/_static/examples/live-reload.mp4" controls muted loop playsinline></video>
110
- </p>
111
-
112
- ## Installation
113
-
114
- Requires Python 3.12+ and Tk/Tcl (bundled with most Python distributions).
115
- Install with pip:
116
-
117
- ```bash
118
- python -m pip install bootstack
119
- ```
120
-
121
- See the [installation guide](https://bootstack.org/getting-started/installation/)
122
- for platform-specific Tk setup and the optional data-format extras.
123
-
124
- ## See it
125
-
126
- The widget gallery is a single-window tour of everything bootstack ships — every widget, theme switcher, accent variants, and layout containers. Fastest way to see the framework in action without writing a line of code:
127
-
128
- ```bash
129
- bootstack gallery
130
- ```
131
-
132
- <p align="center">
133
- <picture>
134
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-dark.png">
135
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-light.png">
136
- <img alt="bootstack widget gallery" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-light.png">
137
- </picture>
138
- </p>
139
-
140
- ## Quick Start
141
-
142
- ```python
143
- import bootstack as bs
144
-
145
- with bs.App(title="Hello", padding=16, gap=16) as app:
146
- bs.Label("Hello from bootstack!")
147
- bs.Button("Primary", accent="primary")
148
- bs.Button("Success", accent="success")
149
- bs.Button("Danger Outline", accent="danger", variant="outline")
150
-
151
- app.run()
152
- ```
153
-
154
- <p align="center">
155
- <picture>
156
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-dark.png">
157
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-light.png">
158
- <img alt="bootstack quick start example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-light.png">
159
- </picture>
160
- </p>
161
-
162
- For navigation-based apps, use `AppShell` — it gives you stacked toolbars, a sidebar, and a page stack in one call:
163
-
164
- ```python
165
- import bootstack as bs
166
-
167
- shell = bs.AppShell(title="My App", size=(1000, 650))
168
-
169
- with shell.page_nav() as nav:
170
- with nav.add_page("home", text="Home", icon="house"):
171
- bs.Label("Welcome!")
172
- with nav.add_page("docs", text="Documents", icon="file-earmark-text"):
173
- bs.Label("Your documents.")
174
-
175
- shell.run()
176
- ```
177
-
178
- ## How it works
179
-
180
- ### Layout containers
181
-
182
- `Column`, `Row`, and `Grid` let you describe a layout once instead of repeating geometry calls on each child:
183
-
184
- ```python
185
- with bs.App(title="Sign In") as app:
186
- with bs.Grid(columns=["auto", 1], gap=(12, 6), horizontal_items="stretch", padding=16):
187
- bs.Label("Name:")
188
- bs.TextField(placeholder="Full name")
189
- bs.Label("Email:")
190
- bs.TextField(placeholder="email@example.com")
191
- bs.Label("Role:")
192
- bs.Select(options=["Admin", "User", "Viewer"], value="User")
193
- bs.Button("Submit", accent="primary", columnspan=2)
194
-
195
- app.run()
196
- ```
197
-
198
- <p align="center">
199
- <picture>
200
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-dark.png">
201
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-light.png">
202
- <img alt="bootstack layout containers example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-light.png">
203
- </picture>
204
- </p>
205
-
206
- ### Semantic styling
207
-
208
- Widgets take an `accent` (color intent) and `variant` (visual weight) instead of hard-coded colors, so the same code looks right across themes and light/dark modes:
209
-
210
- ```python
211
- bs.Button("Save", accent="primary")
212
- bs.Button("Cancel", accent="secondary", variant="outline")
213
- bs.Label("Heading", font="heading-lg")
214
- ```
215
-
216
- <p align="center">
217
- <picture>
218
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-dark.png">
219
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-light.png">
220
- <img alt="bootstack semantic styling example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-light.png">
221
- </picture>
222
- </p>
223
-
224
- ### Signals (optional)
225
-
226
- Plain callbacks work fine for most things. When state needs to flow between widgets, signals give you a small reactive primitive with two-way binding:
227
-
228
- ```python
229
- with bs.App(title="Hello") as app:
230
- name = bs.Signal("World")
231
- bs.Label(textsignal=name) # updates automatically when name changes
232
- bs.TextField(textsignal=name) # two-way binding to the same state
233
-
234
- app.run()
235
- ```
236
-
237
- ## Features
238
-
239
- - **Application scaffolding** — `App` for blank windows, `AppShell` for toolbar + sidebar + page-stack apps, `Workbench` for two-tier workspace apps, `Splash` for a startup intro screen, undecorated windows with custom chrome
240
- - **60+ themed widgets** — primitives plus higher-level composites (DataTable, Tree, ListView, Calendar, DateField, Form, Gauge, ToggleGroup, PageStack, Carousel, Tooltip, and more)
241
- - **Dialogs and messages** — `alert()` / `confirm()` / `ask_*()` prompts and `FormDialog` / `FontDialog` / `FilterDialog`, plus non-blocking `toast()`, `Notification`, and `Snackbar` surfaces
242
- - **Layout containers** — `Column`, `Row`, `Grid`, and `Spacer` for declarative layouts; `Card`, `GroupBox`, `ScrollView`, `SplitView`, `Accordion`, `Divider`
243
- - **Design system** — semantic `accent` colors (primary, secondary, success, danger, warning, info) and `variant` tokens (solid, outline, ghost), consistent across widgets
244
- - **Built-in themes** — 10 paired light/dark variants (bootstrap, catppuccin, dracula, everforest, gruvbox, nord, one, pydata, solarized, tokyo-night) with runtime theme switching and a custom-theme API
245
- - **Reactive signals** — observable state with subscribe/set, integrates with widgets via `signal=` / `textsignal=`
246
- - **Forms & validation** — `Form` with built-in field-level validators and inline error messages
247
- - **DataSource** — common interface over in-memory, SQLite, and file backends, with pagination, filtering, sorting, CRUD, and CSV/TSV/Excel export
248
- - **Data visualization** — `Chart` embeds `matplotlib`/`seaborn` figures that theme themselves and live-update from a `Signal` or `DataSource`; managed render, blitting animation, and a themed navigation toolbar (optional `viz` / `viz-seaborn` extras)
249
- - **Localization (i18n)** — 23 bundled message catalogs, locale-aware number/date/time formatting via Babel, runtime language switching
250
- - **Icons & images** — Bootstrap Icons catalog with theme-aware recoloring and caching
251
- - **Platform support** — DPI awareness, multi-monitor centering, mica/acrylic effects on Windows
252
- - **CLI (`bootstack`)** — project scaffolding, run, add components, theme/i18n setup, doctor, build/package
253
-
254
- ## Widget Categories
255
-
256
- | Category | Widgets |
257
- |----------|---------|
258
- | **Actions** | Button, ButtonGroup, MenuButton, ContextMenu, Toolbar, ThemeToggle |
259
- | **Inputs** | TextField, PasswordField, PathField, NumberField, SpinnerField, Slider, RangeSlider, TextArea, CodeEditor, DateField, TimeField |
260
- | **Selection** | Checkbox, Switch, ToggleButton, Radio, RadioGroup, ToggleGroup, Select, SelectButton, Calendar |
261
- | **Data Display** | Label, Badge, ListView, Tree, DataTable, ProgressBar, Gauge |
262
- | **Media** | Avatar, Picture, Gallery, Carousel |
263
- | **Layout** | Column, Row, Grid, Spacer, Card, GroupBox, SplitView, ScrollView, Accordion, Divider |
264
- | **Navigation** | AppShell, Workbench, Window, Splash, StatusBar, Tabs, PageStack |
265
- | **Dialogs** | `alert()`, `confirm()`, `ask_*()` prompts, FormDialog, FontDialog, FilterDialog |
266
- | **Overlays** | `toast()`, Notification, Snackbar, Tooltip |
267
- | **Forms** | Form, with field-level validation |
268
-
269
- ## CLI
270
-
271
- bootstack ships with an optional CLI for scaffolding, running, and packaging applications:
272
-
273
- ```bash
274
- bootstack gallery # Launch the interactive widget gallery
275
- bootstack icons # Browse the built-in icon catalog
276
- bootstack appicon # Design an app icon and export it
277
- bootstack start MyApp # Create a new project (basic template)
278
- bootstack start MyApp --template appshell # ...or with sidebar navigation
279
- bootstack run # Run the app defined in the project config
280
- bootstack dev app.py # Run with hot reload (live edit-and-save)
281
- bootstack add page Dashboard # Add a new page (appshell)
282
- bootstack add view Settings # Add a new view (basic)
283
- bootstack add dialog Preferences # Add a new dialog
284
- bootstack doctor # Diagnose project & environment
285
- bootstack promote # Make the project packaging-ready
286
- bootstack build # Package for distribution
287
- ```
288
-
289
- ## Documentation
290
-
291
- Full documentation — guides, the widget catalog, and the API reference — lives at
292
- **[bootstack.org](https://bootstack.org)**.
293
-
294
- ## Contributing
295
-
296
- Contributions are welcome — code, bug reports, and especially **translations**.
297
- See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, the pull-request
298
- workflow, and how to review the bundled language catalogs.
299
-
300
- ## Links
301
-
302
- - **GitHub**: https://github.com/israel-dryer/bootstack
1
+ Metadata-Version: 2.4
2
+ Name: bootstack
3
+ Version: 0.2.2
4
+ Summary: Build desktop GUI apps in pure Python and ship them as a standalone executable — built on Tk, no Tkinter boilerplate.
5
+ Author-email: Israel Dryer <israel.dryer@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/israel-dryer/bootstack
8
+ Project-URL: Documentation, https://bootstack.org/
9
+ Keywords: tkinter,ttk,gui,desktop,python3,ui,widgets,theming,cross-platform,modern,framework,application-framework,desktop-ui,python-gui
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Win32 (MS Windows)
12
+ Classifier: Environment :: MacOS X
13
+ Classifier: Environment :: X11 Applications
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: User Interfaces
20
+ Classifier: Operating System :: OS Independent
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ License-File: NOTICE
25
+ Requires-Dist: pillow<=12,>=10
26
+ Requires-Dist: pygments>=2.15
27
+ Requires-Dist: typing-extensions>=4.10
28
+ Requires-Dist: Babel>=2.12
29
+ Requires-Dist: python-dateutil>=2.9
30
+ Requires-Dist: dateparser>=1.1
31
+ Requires-Dist: pywinstyles>=1.8; sys_platform == "win32"
32
+ Requires-Dist: screeninfo>=0.8
33
+ Provides-Extra: excel
34
+ Requires-Dist: XlsxWriter>=3; extra == "excel"
35
+ Provides-Extra: parquet
36
+ Requires-Dist: pyarrow>=14; extra == "parquet"
37
+ Provides-Extra: hdf5
38
+ Requires-Dist: pandas>=2; extra == "hdf5"
39
+ Requires-Dist: tables>=3.8; extra == "hdf5"
40
+ Provides-Extra: viz
41
+ Requires-Dist: matplotlib>=3.8; extra == "viz"
42
+ Provides-Extra: viz-seaborn
43
+ Requires-Dist: matplotlib>=3.8; extra == "viz-seaborn"
44
+ Requires-Dist: seaborn>=0.13; extra == "viz-seaborn"
45
+ Provides-Extra: docs
46
+ Requires-Dist: sphinx>=7.2; extra == "docs"
47
+ Requires-Dist: pydata-sphinx-theme; extra == "docs"
48
+ Requires-Dist: sphinx-design; extra == "docs"
49
+ Requires-Dist: sphinx-copybutton; extra == "docs"
50
+ Requires-Dist: sphinx-autobuild; extra == "docs"
51
+ Requires-Dist: myst-parser; extra == "docs"
52
+ Dynamic: license-file
53
+
54
+ ![bootstack](https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/banner-readme.png)
55
+
56
+ ![](https://img.shields.io/github/release/israel-dryer/bootstack.svg)
57
+ [![Downloads](https://pepy.tech/badge/bootstack)](https://pepy.tech/project/bootstack)
58
+ [![Downloads](https://pepy.tech/badge/bootstack/month)](https://pepy.tech/project/bootstack)
59
+ ![](https://img.shields.io/github/issues/israel-dryer/bootstack.svg)
60
+ ![](https://img.shields.io/github/issues-closed/israel-dryer/bootstack.svg)
61
+ ![](https://img.shields.io/github/license/israel-dryer/bootstack.svg)
62
+ ![](https://img.shields.io/github/stars/israel-dryer/bootstack.svg)
63
+ ![](https://img.shields.io/github/forks/israel-dryer/bootstack.svg)
64
+
65
+ > Full documentation is at **[bootstack.org](https://bootstack.org)**.
66
+
67
+ ### Desktop apps in pure Python — Tk underneath, none of the boilerplate.
68
+
69
+ bootstack is built on Tk, so the install is light and your app ships as a small standalone executable. But you'll never
70
+ write a `StringVar` or call `.pack()` — the API is its own. 60+ widgets, reactive state, and a CLI that scaffolds and
71
+ packages the whole thing.
72
+
73
+ <p align="center">
74
+ <picture>
75
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-dark.png">
76
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-light.png">
77
+ <img alt="bootstack hero demo" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-light.png">
78
+ </picture>
79
+ </p>
80
+
81
+ ## Why bootstack?
82
+
83
+ Most Python desktop frameworks make you fight the framework. bootstack gets out of the way.
84
+
85
+ - **30% less code** — the declarative, context-manager layout eliminates geometry calls, explicit parenting, and most of the wiring boilerplate
86
+ - **Reads like Python** — nested `with` blocks mirror your UI structure; the code hierarchy *is* the layout
87
+ - **Modern layout system** — `Row`, `Column`, and `Grid` containers handle spacing, alignment, and growth automatically; a screen-axis vocabulary (`gap`, `padding`, `margin`, `horizontal`, `vertical`, `grow`) without writing CSS
88
+ - **60+ widgets out of the box** — primitives through full composites: tables, trees, calendars, date pickers, gauges, sliders, and more — including a full `CodeEditor` with syntax highlighting, line numbers, bracket matching, smart indent, and search; no external editor dependency required
89
+ - **Reactive signals** — observable state that flows between widgets; bind once, update everywhere
90
+ - **Event and stream pipelines** — compose, filter, debounce, and throttle UI events with a chainable stream API
91
+ - **Built-in icons** — the full Bootstrap Icons catalog, theme-aware and recolorable, bundled with the framework
92
+ - **Built-in localization** — 23 language catalogs, locale-aware number/date/time formatting, runtime language switching
93
+ - **Semantic styling** — `accent="primary"`, `variant="outline"` — no hard-coded colors; looks right across every theme automatically
94
+ - **10 paired light/dark themes** — popular dev color schemes plus Bootstrap, with a runtime switcher and a custom-theme API
95
+ - **Forms and validation** — field-level validators, inline error messages, and a `FormDialog` for quick modal forms
96
+ - **DataSource abstraction** — one interface over SQLite, in-memory, and file backends with filtering, sorting, pagination, and CRUD
97
+ - **Data visualization** — embed `matplotlib` (and `seaborn`) figures with `Chart`; they recolor with the theme and live-update from a `Signal` or `DataSource` (optional `viz` extra)
98
+ - **A real CLI** — scaffold, run, add pages/views/dialogs/themes, and package for distribution
99
+ - **Hot reload** — `bootstack dev app.py` updates the running app on save and keeps your place; module-level state and the active page survive the reload
100
+ - **PyInstaller packaging built in** — `bootstack build` produces a standalone executable; no separate toolchain required
101
+
102
+ ## Hot reload
103
+
104
+ Edit and save — the running window updates in place. `bootstack dev app.py`
105
+ reloads the UI on every save while keeping your window position, module-level
106
+ state, and active page, so you never lose your spot.
107
+
108
+ <p align="center">
109
+ <video src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/docs/_static/examples/live-reload.mp4" controls muted loop playsinline></video>
110
+ </p>
111
+
112
+ ## Installation
113
+
114
+ Requires Python 3.12+ and Tk/Tcl (bundled with most Python distributions).
115
+ Install with pip:
116
+
117
+ ```bash
118
+ python -m pip install bootstack
119
+ ```
120
+
121
+ See the [installation guide](https://bootstack.org/getting-started/installation/)
122
+ for platform-specific Tk setup and the optional data-format extras.
123
+
124
+ ## See it
125
+
126
+ The widget gallery is a single-window tour of everything bootstack ships — every widget, theme switcher, accent variants, and layout containers. Fastest way to see the framework in action without writing a line of code:
127
+
128
+ ```bash
129
+ bootstack gallery
130
+ ```
131
+
132
+ <p align="center">
133
+ <picture>
134
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-dark.png">
135
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-light.png">
136
+ <img alt="bootstack widget gallery" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-light.png">
137
+ </picture>
138
+ </p>
139
+
140
+ ## Quick Start
141
+
142
+ ```python
143
+ import bootstack as bs
144
+
145
+ with bs.App(title="Hello", padding=16, gap=16) as app:
146
+ bs.Label("Hello from bootstack!")
147
+ bs.Button("Primary", accent="primary")
148
+ bs.Button("Success", accent="success")
149
+ bs.Button("Danger Outline", accent="danger", variant="outline")
150
+
151
+ app.run()
152
+ ```
153
+
154
+ <p align="center">
155
+ <picture>
156
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-dark.png">
157
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-light.png">
158
+ <img alt="bootstack quick start example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-light.png">
159
+ </picture>
160
+ </p>
161
+
162
+ For navigation-based apps, use `AppShell` — it gives you stacked toolbars, a sidebar, and a page stack in one call:
163
+
164
+ ```python
165
+ import bootstack as bs
166
+
167
+ shell = bs.AppShell(title="My App", size=(1000, 650))
168
+
169
+ with shell.page_nav() as nav:
170
+ with nav.add_page("home", text="Home", icon="house"):
171
+ bs.Label("Welcome!")
172
+ with nav.add_page("docs", text="Documents", icon="file-earmark-text"):
173
+ bs.Label("Your documents.")
174
+
175
+ shell.run()
176
+ ```
177
+
178
+ ## How it works
179
+
180
+ ### Layout containers
181
+
182
+ `Column`, `Row`, and `Grid` let you describe a layout once instead of repeating geometry calls on each child:
183
+
184
+ ```python
185
+ with bs.App(title="Sign In") as app:
186
+ with bs.Grid(columns=["auto", 1], gap=(12, 6), horizontal_items="stretch", padding=16):
187
+ bs.Label("Name:")
188
+ bs.TextField(placeholder="Full name")
189
+ bs.Label("Email:")
190
+ bs.TextField(placeholder="email@example.com")
191
+ bs.Label("Role:")
192
+ bs.Select(options=["Admin", "User", "Viewer"], value="User")
193
+ bs.Button("Submit", accent="primary", columnspan=2)
194
+
195
+ app.run()
196
+ ```
197
+
198
+ <p align="center">
199
+ <picture>
200
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-dark.png">
201
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-light.png">
202
+ <img alt="bootstack layout containers example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-light.png">
203
+ </picture>
204
+ </p>
205
+
206
+ ### Semantic styling
207
+
208
+ Widgets take an `accent` (color intent) and `variant` (visual weight) instead of hard-coded colors, so the same code looks right across themes and light/dark modes:
209
+
210
+ ```python
211
+ bs.Button("Save", accent="primary")
212
+ bs.Button("Cancel", accent="secondary", variant="outline")
213
+ bs.Label("Heading", font="heading-lg")
214
+ ```
215
+
216
+ <p align="center">
217
+ <picture>
218
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-dark.png">
219
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-light.png">
220
+ <img alt="bootstack semantic styling example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-light.png">
221
+ </picture>
222
+ </p>
223
+
224
+ ### Signals (optional)
225
+
226
+ Plain callbacks work fine for most things. When state needs to flow between widgets, signals give you a small reactive primitive with two-way binding:
227
+
228
+ ```python
229
+ with bs.App(title="Hello") as app:
230
+ name = bs.Signal("World")
231
+ bs.Label(textsignal=name) # updates automatically when name changes
232
+ bs.TextField(textsignal=name) # two-way binding to the same state
233
+
234
+ app.run()
235
+ ```
236
+
237
+ ## Features
238
+
239
+ - **Application scaffolding** — `App` for blank windows, `AppShell` for toolbar + sidebar + page-stack apps, `Workbench` for two-tier workspace apps, `Splash` for a startup intro screen, undecorated windows with custom chrome
240
+ - **60+ themed widgets** — primitives plus higher-level composites (DataTable, Tree, ListView, Calendar, DateField, Form, Gauge, ToggleGroup, PageStack, Carousel, Tooltip, and more)
241
+ - **Dialogs and messages** — `alert()` / `confirm()` / `ask_*()` prompts and `FormDialog` / `FontDialog` / `FilterDialog`, plus non-blocking `toast()`, `Notification`, and `Snackbar` surfaces
242
+ - **Layout containers** — `Column`, `Row`, `Grid`, and `Spacer` for declarative layouts; `Card`, `GroupBox`, `ScrollView`, `SplitView`, `Accordion`, `Divider`
243
+ - **Design system** — semantic `accent` colors (primary, secondary, success, danger, warning, info) and `variant` tokens (solid, outline, ghost), consistent across widgets
244
+ - **Built-in themes** — 10 paired light/dark variants (bootstrap, catppuccin, dracula, everforest, gruvbox, nord, one, pydata, solarized, tokyo-night) with runtime theme switching and a custom-theme API
245
+ - **Reactive signals** — observable state with subscribe/set, integrates with widgets via `signal=` / `textsignal=`
246
+ - **Forms & validation** — `Form` with built-in field-level validators and inline error messages
247
+ - **DataSource** — common interface over in-memory, SQLite, and file backends, with pagination, filtering, sorting, CRUD, and CSV/TSV/Excel export
248
+ - **Data visualization** — `Chart` embeds `matplotlib`/`seaborn` figures that theme themselves and live-update from a `Signal` or `DataSource`; managed render, blitting animation, and a themed navigation toolbar (optional `viz` / `viz-seaborn` extras)
249
+ - **Localization (i18n)** — 23 bundled message catalogs, locale-aware number/date/time formatting via Babel, runtime language switching
250
+ - **Icons & images** — Bootstrap Icons catalog with theme-aware recoloring and caching
251
+ - **Platform support** — DPI awareness, multi-monitor centering, mica/acrylic effects on Windows
252
+ - **CLI (`bootstack`)** — project scaffolding, run, add components, theme/i18n setup, doctor, build/package
253
+
254
+ ## Widget Categories
255
+
256
+ | Category | Widgets |
257
+ |----------|---------|
258
+ | **Actions** | Button, ButtonGroup, MenuButton, ContextMenu, Toolbar, ThemeToggle |
259
+ | **Inputs** | TextField, PasswordField, PathField, NumberField, SpinnerField, Slider, RangeSlider, TextArea, CodeEditor, DateField, TimeField |
260
+ | **Selection** | Checkbox, Switch, ToggleButton, Radio, RadioGroup, ToggleGroup, Select, SelectButton, Calendar |
261
+ | **Data Display** | Label, Badge, ListView, Tree, DataTable, ProgressBar, Gauge |
262
+ | **Media** | Avatar, Picture, Gallery, Carousel |
263
+ | **Layout** | Column, Row, Grid, Spacer, Card, GroupBox, SplitView, ScrollView, Accordion, Divider |
264
+ | **Navigation** | AppShell, Workbench, Window, Splash, StatusBar, Tabs, PageStack |
265
+ | **Dialogs** | `alert()`, `confirm()`, `ask_*()` prompts, FormDialog, FontDialog, FilterDialog |
266
+ | **Overlays** | `toast()`, Notification, Snackbar, Tooltip |
267
+ | **Forms** | Form, with field-level validation |
268
+
269
+ ## CLI
270
+
271
+ bootstack ships with an optional CLI for scaffolding, running, and packaging applications:
272
+
273
+ ```bash
274
+ bootstack gallery # Launch the interactive widget gallery
275
+ bootstack icons # Browse the built-in icon catalog
276
+ bootstack appicon # Design an app icon and export it
277
+ bootstack start MyApp # Create a new project (basic template)
278
+ bootstack start MyApp --template appshell # ...or with sidebar navigation
279
+ bootstack run # Run the app defined in the project config
280
+ bootstack dev app.py # Run with hot reload (live edit-and-save)
281
+ bootstack add page Dashboard # Add a new page (appshell)
282
+ bootstack add view Settings # Add a new view (basic)
283
+ bootstack add dialog Preferences # Add a new dialog
284
+ bootstack doctor # Diagnose project & environment
285
+ bootstack promote # Make the project packaging-ready
286
+ bootstack build # Package for distribution
287
+ ```
288
+
289
+ ## Documentation
290
+
291
+ Full documentation — guides, the widget catalog, and the API reference — lives at
292
+ **[bootstack.org](https://bootstack.org)**.
293
+
294
+ ## Contributing
295
+
296
+ Contributions are welcome — code, bug reports, and especially **translations**.
297
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, the pull-request
298
+ workflow, and how to review the bundled language catalogs.
299
+
300
+ ## Links
301
+
302
+ - **GitHub**: https://github.com/israel-dryer/bootstack
@@ -322,7 +322,7 @@ bootstack/widgets/types.py,sha256=_86PwJ20gim0hGnCdPYSn1YVrrsTfZhyQ1zWDwHqQTY,13
322
322
  bootstack/widgets/window.py,sha256=lwzYO6uAeXM_lSMXES911OsX8aVrJPKQHJu1u30bAIo,12921
323
323
  bootstack/widgets/_core/__init__.py,sha256=rJPvvI3eOV9M5cICBD2XPZFokThf_tQyTeZhLPaqukU,1106
324
324
  bootstack/widgets/_core/app_config.py,sha256=h_OaJ0jSif1eJeHWErpsXNyhtfCcmYQCcq0VriM48uk,9771
325
- bootstack/widgets/_core/base.py,sha256=NWJWqG-rbFRadnacCdnIueQUht6XEtVFoEChU5t7VSw,22691
325
+ bootstack/widgets/_core/base.py,sha256=LOLzA-m3NpcFi05b-W77r5W73efR5mgceq6xIsZJ4Ps,22739
326
326
  bootstack/widgets/_core/choices.py,sha256=IGm4NspPJQgnGOxfuXWsqs4nSk7HSkdH0P60Cd1gnjo,2369
327
327
  bootstack/widgets/_core/container.py,sha256=zrMadhoswXERiY4jjzeot2dnqpus-PKmG_vHESiuoqM,16051
328
328
  bootstack/widgets/_core/context.py,sha256=laL75HYr7kIx3KbZqtT_rO1wWRjV4pehNzWgcZUkw_I,764
@@ -402,7 +402,7 @@ bootstack/widgets/_impl/composites/slider/_shared.py,sha256=xbwghVe-mKno5gDJsQNX
402
402
  bootstack/widgets/_impl/composites/slider/rangeslider.py,sha256=xhzv68hhSx2iImtPdXBzuk9p41tdOJxzdl8APnGAnhY,43770
403
403
  bootstack/widgets/_impl/composites/slider/slider.py,sha256=OWdhzahCDsXP1xNtDoHb82iQMbtYyzR895CePBbEQP0,38996
404
404
  bootstack/widgets/_impl/composites/tableview/__init__.py,sha256=ccQKtGH53tGj7K1ezfsbY2iEyIH1wRgd1qEQ0Glqra4,127
405
- bootstack/widgets/_impl/composites/tableview/tableview.py,sha256=YAhgiLvDMwH_5Qx6_d-StXlI748anf0HpLj0QDzidMI,148479
405
+ bootstack/widgets/_impl/composites/tableview/tableview.py,sha256=Qr7UwHxRB6p9mG6WDD5rZblEi3TvxuYwnk6TJXKgA1Q,150713
406
406
  bootstack/widgets/_impl/composites/tableview/types.py,sha256=oDmJco19M42Zv_lUEpsfeM7kjjuHHsNBMVZoWRe-QDs,4906
407
407
  bootstack/widgets/_impl/composites/tabs/__init__.py,sha256=yRRJCO9egzFCDNN7xDyQcH8KqCQx6AgGE-eVtpn4KSc,427
408
408
  bootstack/widgets/_impl/composites/tabs/tabitem.py,sha256=WGCxBU2ObqFVLVa5p4KfBLp7QvJ-Y8sLfUkJjXP4820,14754
@@ -465,10 +465,10 @@ bootstack/widgets/_impl/primitives/sizegrip.py,sha256=uwQRzOEHjNPXtUURhT6k2TNYdy
465
465
  bootstack/widgets/_impl/primitives/spinbox.py,sha256=5m0tZrqCw745nvIiBrJWnZ0q8fZ7bNEvopjROMbQolc,4526
466
466
  bootstack/widgets/_impl/primitives/switch.py,sha256=7dt43uE2P_WdkxZZsGtCFRAQ20nI2jx5VUqGSrWwEmA,2543
467
467
  bootstack/widgets/_impl/primitives/treeview.py,sha256=vnSowgzmtNEWst_i9ZgcacHjdvuheF9xmeTvTWE1bLg,2709
468
- bootstack-0.2.1.dist-info/licenses/LICENSE,sha256=CUeTPUOM8Qc0yuqneJUwuUmDBooET5UfsHjMrkdBeCg,1097
469
- bootstack-0.2.1.dist-info/licenses/NOTICE,sha256=-wgrIMRWBeNKGVXd48W43hf2xv9zDLzRyemn5tkgZIE,370
470
- bootstack-0.2.1.dist-info/METADATA,sha256=OTjxaH158rVV2viKWpoDXPuUG9NNtaSpQY9qunOZ9Xk,16107
471
- bootstack-0.2.1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
472
- bootstack-0.2.1.dist-info/entry_points.txt,sha256=phOlfRy3Th86IYlNhQiUrTLLLzxie1IG-kMas_5iMdA,49
473
- bootstack-0.2.1.dist-info/top_level.txt,sha256=IsKBAac2vRCegvRFSCzwcBr7TpHp4bLnLFgA75LOkXs,10
474
- bootstack-0.2.1.dist-info/RECORD,,
468
+ bootstack-0.2.2.dist-info/licenses/LICENSE,sha256=CUeTPUOM8Qc0yuqneJUwuUmDBooET5UfsHjMrkdBeCg,1097
469
+ bootstack-0.2.2.dist-info/licenses/NOTICE,sha256=-wgrIMRWBeNKGVXd48W43hf2xv9zDLzRyemn5tkgZIE,370
470
+ bootstack-0.2.2.dist-info/METADATA,sha256=yefZeA7n_PxLWN5n6WhxoVNMD45CZZbSHbG9ecBLkkc,16409
471
+ bootstack-0.2.2.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
472
+ bootstack-0.2.2.dist-info/entry_points.txt,sha256=phOlfRy3Th86IYlNhQiUrTLLLzxie1IG-kMas_5iMdA,49
473
+ bootstack-0.2.2.dist-info/top_level.txt,sha256=IsKBAac2vRCegvRFSCzwcBr7TpHp4bLnLFgA75LOkXs,10
474
+ bootstack-0.2.2.dist-info/RECORD,,