CTkDataTable 0.1.0__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.
@@ -0,0 +1,681 @@
1
+ Metadata-Version: 2.4
2
+ Name: CTkDataTable
3
+ Version: 0.1.0
4
+ Summary: A virtualized data table widget for CustomTkinter applications.
5
+ Author: Harry Gomm
6
+ License-Expression: MIT
7
+ Project-URL: Documentation, https://github.com/Harry-g25/CTkTableData/blob/main/docs/Docs.md
8
+ Project-URL: Homepage, https://github.com/Harry-g25/CTkTableData
9
+ Project-URL: Issues, https://github.com/Harry-g25/CTkTableData/issues
10
+ Project-URL: Source, https://github.com/Harry-g25/CTkTableData
11
+ Keywords: customtkinter,tkinter,table,datagrid,widgets
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Typing :: Typed
21
+ Classifier: Topic :: Software Development :: User Interfaces
22
+ Requires-Python: >=3.11
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: customtkinter>=5.2
26
+ Provides-Extra: dev
27
+ Requires-Dist: build>=1.2; extra == "dev"
28
+ Requires-Dist: mypy>=1.10; extra == "dev"
29
+ Requires-Dist: ruff>=0.11; extra == "dev"
30
+ Requires-Dist: twine>=5.1; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # CTkDataTable
34
+
35
+ The `CTkDataTable` package provides a virtualized data table widget for CustomTkinter apps.
36
+
37
+ Use it when you want to show records from Python data, PostgreSQL queries, SQLite queries, or SQLAlchemy results without building a grid of labels by hand.
38
+
39
+ ## Install
40
+
41
+ From PyPI:
42
+
43
+ ```powershell
44
+ pip install CTkDataTable
45
+ ```
46
+
47
+ For local development:
48
+
49
+ ```powershell
50
+ pip install -e ".[dev]"
51
+ ```
52
+
53
+ ## Run a Demo
54
+
55
+ ```powershell
56
+ python -m CTkDataTable.examples.basic_table
57
+ python -m CTkDataTable.examples.ncr_records
58
+ ```
59
+
60
+ ## Development Checks
61
+
62
+ ```powershell
63
+ python -m unittest discover -v
64
+ python -m ruff check .
65
+ python -m mypy CTkDataTable
66
+ python -m build
67
+ python -m twine check dist/*
68
+ ```
69
+
70
+ ## Release Build
71
+
72
+ ```powershell
73
+ Remove-Item -Recurse -Force dist, build -ErrorAction SilentlyContinue
74
+ python -m build
75
+ python -m twine check dist/*
76
+ ```
77
+
78
+ ## License
79
+
80
+ MIT License. See [LICENSE](https://github.com/Harry-g25/CTkTableData/blob/main/LICENSE).
81
+
82
+ ## Quick Start
83
+
84
+ Using the table has three steps:
85
+
86
+ 1. Define the columns.
87
+ 2. Pass rows.
88
+ 3. Place the table in your CustomTkinter layout.
89
+
90
+ ```python
91
+ import customtkinter as ctk
92
+
93
+ from CTkDataTable import CTkDataTable
94
+
95
+
96
+ app = ctk.CTk()
97
+ app.geometry("700x400")
98
+ app.grid_rowconfigure(0, weight=1)
99
+ app.grid_columnconfigure(0, weight=1)
100
+
101
+ columns = [
102
+ {"key": "id", "title": "ID", "width": 80},
103
+ {"key": "name", "title": "Name", "width": 180},
104
+ {"key": "status", "title": "Status", "width": 140},
105
+ ]
106
+
107
+ rows = [
108
+ {"id": 1, "name": "Alice", "status": "Open"},
109
+ {"id": 2, "name": "Bob", "status": "Closed"},
110
+ {"id": 3, "name": "Charlie", "status": "In Review"},
111
+ ]
112
+
113
+ table = CTkDataTable(app, columns=columns, data=rows)
114
+ table.grid(row=0, column=0, sticky="nsew", padx=16, pady=16)
115
+
116
+ app.mainloop()
117
+ ```
118
+
119
+ The important rule is simple:
120
+
121
+ ```python
122
+ column["key"] == row dictionary key
123
+ ```
124
+
125
+ For example:
126
+
127
+ ```python
128
+ {"key": "name", "title": "Name", "width": 180}
129
+ {"name": "Alice"}
130
+ ```
131
+
132
+ ## Loading Data
133
+
134
+ Most users can pass a list of dictionaries:
135
+
136
+ ```python
137
+ table.set_data([
138
+ {"id": 1, "name": "Alice", "status": "Open"},
139
+ {"id": 2, "name": "Bob", "status": "Closed"},
140
+ ])
141
+ ```
142
+
143
+ The table also accepts common database row objects, including:
144
+
145
+ - PostgreSQL rows returned as dictionaries
146
+ - SQLAlchemy mapping rows
147
+ - `sqlite3.Row` objects
148
+ - plain DB-API tuple cursors converted with `rows_from_cursor()`
149
+
150
+ ### PostgreSQL with psycopg 3
151
+
152
+ Use `dict_row`, then pass the query result directly to the table.
153
+
154
+ ```python
155
+ import psycopg
156
+ from psycopg.rows import dict_row
157
+
158
+
159
+ with psycopg.connect(DB_URL, row_factory=dict_row) as connection:
160
+ rows = connection.execute("""
161
+ SELECT id, name, status
162
+ FROM customers
163
+ """).fetchall()
164
+
165
+ table.set_data(rows)
166
+ ```
167
+
168
+ ### PostgreSQL with psycopg2
169
+
170
+ Use `RealDictCursor`.
171
+
172
+ ```python
173
+ import psycopg2
174
+ from psycopg2.extras import RealDictCursor
175
+
176
+
177
+ connection = psycopg2.connect(DB_URL)
178
+ cursor = connection.cursor(cursor_factory=RealDictCursor)
179
+
180
+ cursor.execute("""
181
+ SELECT id, name, status
182
+ FROM customers
183
+ """)
184
+
185
+ table.set_data(cursor.fetchall())
186
+ ```
187
+
188
+ ### Plain DB-API Cursors
189
+
190
+ If your cursor returns tuples, convert them with `rows_from_cursor()`.
191
+
192
+ ```python
193
+ from CTkDataTable import rows_from_cursor
194
+
195
+
196
+ cursor.execute("""
197
+ SELECT id, name, status
198
+ FROM customers
199
+ """)
200
+
201
+ table.set_data(rows_from_cursor(cursor))
202
+ ```
203
+
204
+ If database column names do not match your table column keys, use SQL aliases:
205
+
206
+ ```sql
207
+ SELECT created_at AS created FROM customers;
208
+ ```
209
+
210
+ ## Column Types
211
+
212
+ Every column needs at least a `key`, `title`, and `width`.
213
+
214
+ ```python
215
+ {"key": "name", "title": "Name", "width": 180}
216
+ ```
217
+
218
+ You can also set a `type`.
219
+
220
+ ### Text
221
+
222
+ ```python
223
+ {"key": "name", "title": "Name", "width": 180, "type": "text"}
224
+ ```
225
+
226
+ ### Number
227
+
228
+ ```python
229
+ {"key": "amount", "title": "Amount", "width": 120, "type": "number"}
230
+ ```
231
+
232
+ Format numbers with `number_format`:
233
+
234
+ ```python
235
+ {"key": "amount", "title": "Amount", "width": 120, "type": "number", "number_format": "${:,.2f}"}
236
+ ```
237
+
238
+ ### Percentage
239
+
240
+ Use `percentage` for percent values. It right-aligns by default, sorts numerically, and appends `%`.
241
+
242
+ ```python
243
+ {"key": "margin", "title": "Margin", "width": 120, "type": "percentage"}
244
+ ```
245
+
246
+ Customize output with `percentage_format`. If your row values are stored as ratios, multiply them before display:
247
+
248
+ ```python
249
+ {
250
+ "key": "margin",
251
+ "title": "Margin",
252
+ "width": 120,
253
+ "type": "percentage",
254
+ "percentage_format": "{value:.1f}%",
255
+ "percentage_multiplier": 100,
256
+ }
257
+ ```
258
+
259
+ ### Currency
260
+
261
+ Use `currency` for money values. It right-aligns by default, sorts numerically, and formats numeric row values.
262
+
263
+ ```python
264
+ {
265
+ "key": "amount",
266
+ "title": "Amount",
267
+ "width": 120,
268
+ "type": "currency",
269
+ "currency_symbol": "$",
270
+ }
271
+ ```
272
+
273
+ Customize output with `currency_format` and `currency_negative_format`:
274
+
275
+ ```python
276
+ {
277
+ "key": "amount",
278
+ "title": "Amount",
279
+ "width": 120,
280
+ "type": "currency",
281
+ "currency_symbol": "GBP ",
282
+ "currency_format": "{symbol}{value:,.2f}",
283
+ "currency_negative_format": "({symbol}{value:,.2f})",
284
+ }
285
+ ```
286
+
287
+ ### Date
288
+
289
+ ```python
290
+ {"key": "created", "title": "Created", "width": 130, "type": "date"}
291
+ ```
292
+
293
+ Date columns accept `datetime.date`, `datetime.datetime`, and ISO date strings.
294
+
295
+ ### Badge
296
+
297
+ Use badges for status-like values.
298
+
299
+ ```python
300
+ {
301
+ "key": "status",
302
+ "title": "Status",
303
+ "width": 130,
304
+ "type": "badge",
305
+ "badge_colors": {
306
+ "Open": "#2ecc71",
307
+ "Closed": "#e74c3c",
308
+ "Overdue": "#e67e22",
309
+ },
310
+ "badge_fallback_color": "#64748b",
311
+ }
312
+ ```
313
+
314
+ ### Pill List
315
+
316
+ Use `pill_list` for compact tag lists. Row values can be a list, tuple, set, or a comma-separated string.
317
+
318
+ ```python
319
+ {
320
+ "key": "tags",
321
+ "title": "Tags",
322
+ "width": 180,
323
+ "type": "pill_list",
324
+ "pill_colors": {"Urgent": "#ef4444", "Finance": "#0ea5e9"},
325
+ "pill_fallback_color": "#64748b",
326
+ "pill_text_color": "#ffffff",
327
+ }
328
+ ```
329
+
330
+ ### Checkbox
331
+
332
+ Checkbox columns display boolean row values and toggle them when clicked. Toggle callbacks receive a
333
+ `TableRowEvent` with the updated row, `column_key` set to the checkbox column, and `action_key` set to
334
+ `"checkbox"`.
335
+
336
+ ```python
337
+ from CTkDataTable import TableRowEvent
338
+
339
+
340
+ def handle_checkbox(event: TableRowEvent) -> None:
341
+ approved = event.row[event.column_key]
342
+
343
+
344
+ columns = [
345
+ {"key": "approved", "title": "Approved", "width": 100, "type": "checkbox"},
346
+ ]
347
+
348
+ table = CTkDataTable(app, columns=columns, data=rows, on_checkbox_toggle=handle_checkbox)
349
+ ```
350
+
351
+ ### Progress
352
+
353
+ Use `progress` for numeric completion values. Values are clamped between `progress_min` and `progress_max`.
354
+
355
+ ```python
356
+ {
357
+ "key": "completion",
358
+ "title": "Complete",
359
+ "width": 140,
360
+ "type": "progress",
361
+ "progress_min": 0,
362
+ "progress_max": 100,
363
+ "progress_text_format": "{percent:.0f}%",
364
+ }
365
+ ```
366
+
367
+ ### Link
368
+
369
+ Use `link` for clickable text cells. Link clicks fire `on_link_click` with a `TableRowEvent`.
370
+
371
+ ```python
372
+ from CTkDataTable import TableRowEvent
373
+
374
+
375
+ def handle_link(event: TableRowEvent) -> None:
376
+ selected_profile = event.row
377
+
378
+
379
+ columns = [
380
+ {"key": "profile", "title": "Profile", "width": 130, "type": "link"},
381
+ ]
382
+
383
+ table = CTkDataTable(app, columns=columns, data=rows, on_link_click=handle_link)
384
+ ```
385
+
386
+ ### Actions
387
+
388
+ Action columns draw buttons inside each row.
389
+
390
+ ```python
391
+ from CTkDataTable import CTkDataTable, TableRowEvent
392
+
393
+
394
+ def handle_action(event: TableRowEvent) -> None:
395
+ selected_action = event.action_key
396
+
397
+
398
+ columns = [
399
+ {"key": "id", "title": "ID", "width": 80},
400
+ {
401
+ "key": "actions",
402
+ "title": "Actions",
403
+ "width": 160,
404
+ "type": "action",
405
+ "sortable": False,
406
+ "actions": [
407
+ {"key": "view", "label": "View"},
408
+ {"key": "delete", "label": "Delete"},
409
+ ],
410
+ },
411
+ ]
412
+
413
+ table = CTkDataTable(
414
+ app,
415
+ columns=columns,
416
+ data=rows,
417
+ on_action_click=handle_action,
418
+ )
419
+ ```
420
+
421
+ ## Common Tasks
422
+
423
+ ### Replace All Rows
424
+
425
+ ```python
426
+ table.set_data(rows)
427
+ ```
428
+
429
+ ### Add One Row
430
+
431
+ ```python
432
+ table.add_row({"id": 4, "name": "Diana", "status": "Open"})
433
+ ```
434
+
435
+ ### Search from a Search Box
436
+
437
+ ```python
438
+ search = ctk.CTkEntry(app, placeholder_text="Search")
439
+ search.grid(row=0, column=0, sticky="ew")
440
+
441
+ table.grid(row=1, column=0, sticky="nsew")
442
+
443
+ search.bind("<KeyRelease>", lambda _event: table.search(search.get()))
444
+ ```
445
+
446
+ ### Sort by a Column
447
+
448
+ ```python
449
+ table.sort_by("name", ascending=True)
450
+ ```
451
+
452
+ Users can also click sortable column headers.
453
+
454
+ ### Resize Columns
455
+
456
+ ```python
457
+ table = CTkDataTable(app, columns=columns, data=rows, resizable_columns=True)
458
+ ```
459
+
460
+ Users can drag header dividers to resize columns. The table keeps the resize in memory for the current widget instance.
461
+
462
+ You can also change columns from code:
463
+
464
+ ```python
465
+ table.set_column_width("name", 220)
466
+ table.set_columns([
467
+ {"key": "id", "title": "ID", "width": 80},
468
+ {"key": "name", "title": "Customer", "width": 220},
469
+ ])
470
+ ```
471
+
472
+ ### Style the Table
473
+
474
+ Use `style` to control the table surface, header, rows, selection, dividers, feature cells, padding, and corner radii.
475
+ Pass either a dictionary or a `TableStyle` object.
476
+
477
+ ```python
478
+ table = CTkDataTable(
479
+ app,
480
+ columns=columns,
481
+ data=rows,
482
+ style={
483
+ "corner_radius": 12,
484
+ "border_width": 1,
485
+ "border_color": "#d1d5db",
486
+ "header_bg": "#f3f4f6",
487
+ "row_bg": "#ffffff",
488
+ "row_alt_bg": "#f9fafb",
489
+ "hover_bg": "#eef6ff",
490
+ "selected_bg": "#2563eb",
491
+ "selected_text_color": "#ffffff",
492
+ "divider_color": "#e5e7eb",
493
+ "badge_radius": 8,
494
+ "action_radius": 6,
495
+ "cell_padding_x": 14,
496
+ },
497
+ )
498
+
499
+ table.configure_style(header_bg="#111827", header_text_color="#ffffff")
500
+ table.set_style(row_bg="#ffffff", row_alt_bg="#f8fafc")
501
+ ```
502
+
503
+ ### Style Rows and Cells
504
+
505
+ Style hooks are opt-in. Passing `row_style` or `cell_style` without `enable_style_hooks=True` raises a clear error.
506
+
507
+ ```python
508
+ def row_style(row):
509
+ if row["status"] == "Overdue":
510
+ return {"fg_color": "#fff7ed", "text_color": "#9a3412"}
511
+ return None
512
+
513
+
514
+ def cell_style(row, column_key, value):
515
+ if column_key == "amount" and value < 0:
516
+ return {"text_color": "#dc2626"}
517
+ return None
518
+
519
+
520
+ table = CTkDataTable(
521
+ app,
522
+ columns=columns,
523
+ data=rows,
524
+ enable_style_hooks=True,
525
+ row_style=row_style,
526
+ cell_style=cell_style,
527
+ )
528
+ ```
529
+
530
+ ### Filter by Column
531
+
532
+ Column filters combine with global search.
533
+
534
+ ```python
535
+ table.set_column_filter("status", {"type": "equals", "value": "Open"})
536
+ table.set_column_filter("amount", {"type": "range", "min": 100, "max": 500})
537
+ table.clear_column_filter("status")
538
+ table.clear_column_filters()
539
+ ```
540
+
541
+ Supported filter types are `contains`, `equals`, `not_equals`, `in`, `bool`, `range`, and `date_range`.
542
+
543
+ ### Add a Context Menu
544
+
545
+ ```python
546
+ def handle_context(event: TableRowEvent) -> None:
547
+ selected_action = event.action_key
548
+
549
+
550
+ table = CTkDataTable(
551
+ app,
552
+ columns=columns,
553
+ data=rows,
554
+ context_menu=[
555
+ {"key": "copy_id", "label": "Copy ID"},
556
+ {"key": "delete", "label": "Delete"},
557
+ ],
558
+ on_context_action=handle_context,
559
+ )
560
+ ```
561
+
562
+ ### Show a Footer Summary
563
+
564
+ Footer summaries use the current visible rows after search and column filters.
565
+
566
+ ```python
567
+ table = CTkDataTable(
568
+ app,
569
+ columns=columns,
570
+ data=rows,
571
+ footer=True,
572
+ summaries={
573
+ "id": "count",
574
+ "amount": "sum",
575
+ "status": lambda rows: f"{len(rows)} visible",
576
+ },
577
+ )
578
+ ```
579
+
580
+ Built-in summaries are `count`, `sum`, `avg`, `min`, and `max`.
581
+
582
+ ### Load Rows in the Background
583
+
584
+ ```python
585
+ def fetch_rows():
586
+ return database.load_customers()
587
+
588
+
589
+ table.load_async(
590
+ fetch_rows,
591
+ on_success=lambda rows: None,
592
+ on_error=lambda error: None,
593
+ )
594
+ ```
595
+
596
+ `load_async()` shows the loading state, runs your fetch function in a background thread, and updates the table safely on the Tkinter thread.
597
+
598
+ ### Get the Selected Row
599
+
600
+ ```python
601
+ selected = table.get_selected_row()
602
+ if selected is not None:
603
+ selected_id = selected.get("id")
604
+ ```
605
+
606
+ For row identity, use source-data indices or current view indices:
607
+
608
+ ```python
609
+ source_indices = table.get_selected_indices()
610
+ view_indices = table.get_selected_view_indices()
611
+ ```
612
+
613
+ ### Delete Rows
614
+
615
+ ```python
616
+ table.delete_row(0)
617
+ table.delete_view_row(0)
618
+ table.delete_row_by_key("id", 4)
619
+ table.delete_selected_rows()
620
+ ```
621
+
622
+ `delete_row(index)` uses the original source-data index. `delete_row_by_key()` is usually easier after sorting or filtering.
623
+ Use `delete_view_row(view_index)` when you intentionally want to target the current visible row order.
624
+
625
+ ### Detailed Event Payloads
626
+
627
+ Interaction callbacks receive `TableRowEvent` objects when you need the row, source index, visible index, clicked column, or clicked action.
628
+
629
+ ```python
630
+ def handle_action(event):
631
+ row_identity = (event.source_index, event.view_index, event.action_key)
632
+
633
+
634
+ table = CTkDataTable(
635
+ app,
636
+ columns=columns,
637
+ data=rows,
638
+ on_action_click=handle_action,
639
+ )
640
+ ```
641
+
642
+ For link cells, `event.column_key` is the link column and `event.action_key` is `"link"`.
643
+ For checkbox cells, `event.column_key` is the checkbox column, `event.action_key` is `"checkbox"`, and
644
+ `event.row[event.column_key]` is the new boolean value.
645
+
646
+ ### Show a Loading State
647
+
648
+ ```python
649
+ table.set_loading(True)
650
+ table.set_data(rows)
651
+ table.set_loading(False)
652
+ ```
653
+
654
+ ### Enable Horizontal Scrolling
655
+
656
+ Use this when the total column width is wider than the window.
657
+
658
+ ```python
659
+ table = CTkDataTable(app, columns=columns, data=rows, horizontal_scroll=True)
660
+ ```
661
+
662
+ ### Keyboard Navigation
663
+
664
+ When the table has focus, use Up, Down, Page Up, Page Down, Home, and End to move selection. Press Enter to trigger the double-click row callback. In multi-select mode, Shift extends the selection range.
665
+
666
+ ## Notes
667
+
668
+ - The table does not edit text, number, date, or badge cells inline. Checkbox columns can toggle boolean values.
669
+ - The table does not run database queries. Query your database yourself, then call `set_data()`.
670
+ - The table only draws visible rows, so large lists scroll smoothly.
671
+ - `delete_row(index)` deletes from the original data list, not the currently visible filtered or sorted row number.
672
+ - Searching clears selected rows that are no longer visible.
673
+ - Sorting and searching reset the vertical scroll position to the top.
674
+
675
+ ## More Detail
676
+
677
+ - Full API reference: [docs/Docs.md](https://github.com/Harry-g25/CTkTableData/blob/main/docs/Docs.md)
678
+ - Publishing guide: [docs/Publishing.md](https://github.com/Harry-g25/CTkTableData/blob/main/docs/Publishing.md)
679
+ - Standalone HTML guide: [docs/Docs.html](https://github.com/Harry-g25/CTkTableData/blob/main/docs/Docs.html)
680
+ - Basic example: [CTkDataTable/examples/basic_table.py](https://github.com/Harry-g25/CTkTableData/blob/main/CTkDataTable/examples/basic_table.py)
681
+ - NCR records example: [CTkDataTable/examples/ncr_records.py](https://github.com/Harry-g25/CTkTableData/blob/main/CTkDataTable/examples/ncr_records.py)
@@ -0,0 +1,16 @@
1
+ CTkDataTable/__init__.py,sha256=P11xSuOMlhMsqQIy52wqUM10B1f5xXOKL9EdMexnWgc,394
2
+ CTkDataTable/_utils.py,sha256=8VXDLPN73_087FgPqrm1eZdjysEdu7Q9dvZUhT-VuuM,1813
3
+ CTkDataTable/ctk_data_table.py,sha256=JIf_bEIYjpsZuG_t3Miy-hTAxYEMNJttv4JHuU8n2MY,67887
4
+ CTkDataTable/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
5
+ CTkDataTable/table_column.py,sha256=Dy9PjRKTxT59hG56_v8OWVbzwigjq4mPFaVq2IwL0i0,16737
6
+ CTkDataTable/table_events.py,sha256=A2TacxpGLYRelbXWPvmVLWdd-9msN3AHt87xcOYHddI,400
7
+ CTkDataTable/table_model.py,sha256=OC3GXljescOxs9oF9V8rr5co1UbDXKvqP039wiFRSAU,23863
8
+ CTkDataTable/table_renderer.py,sha256=04IRmK_boUBR02wQXK-ksozlAhW2ZZjNwtmmEGLfF9Y,43551
9
+ CTkDataTable/table_style.py,sha256=50o0lqOsjttuKeogj9LqH_ZIPkTYKmP4adUpCDA_eJI,7638
10
+ CTkDataTable/examples/__init__.py,sha256=2mDoEpUzwuLeNzf2GMEwa6lQSVux4eWT7KERXirnoU0,45
11
+ CTkDataTable/examples/basic_table.py,sha256=S4NnIwBNc0gHcnwDttJr3lngfQIgldkG2ZZfIADzlYs,7453
12
+ ctkdatatable-0.1.0.dist-info/licenses/LICENSE,sha256=P6rR8xoQJKDIOADNG6W0oI-axVRS5SWOSC0XlzI7tkA,1067
13
+ ctkdatatable-0.1.0.dist-info/METADATA,sha256=XUrDMDDdbTkKd0IWDiypXhb6DvrnzivU-z9OxyECaZQ,16133
14
+ ctkdatatable-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
15
+ ctkdatatable-0.1.0.dist-info/top_level.txt,sha256=qMa16zN3yNS8gjqIWs8KIpo9iSXXFtdAN854irTDUFI,13
16
+ ctkdatatable-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+