listpick 0.1.16.8__py3-none-any.whl → 0.1.16.17__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.
@@ -37,39 +37,57 @@ def generate_columns_worker(
37
37
  getting_data: threading.Event,
38
38
  task_queue: PriorityQueue,
39
39
  completed_cells: set,
40
+ state: dict,
40
41
  ) -> None:
41
42
  """ Get a task from the priorty queue and fill the data for that cell."""
42
- while task_queue.qsize() > 0:
43
+ while task_queue.qsize() > 0 and not state["thread_stop_event"].is_set():
43
44
  _, (i, j) = task_queue.get()
44
45
 
45
46
  if (i, j) in completed_cells:
46
47
  task_queue.task_done()
47
48
  continue
48
49
 
50
+ if state["thread_stop_event"].is_set():
51
+ with task_queue.mutex:
52
+ task_queue.queue.clear()
53
+
49
54
  generate_cell(
50
55
  func=funcs[j],
51
56
  file=files[i],
52
57
  items=items,
53
58
  row=i,
54
59
  col=j+1,
60
+ state=state,
55
61
  )
56
62
  completed_cells.add((i, j))
57
63
  task_queue.task_done()
58
64
  getting_data.set()
59
65
 
60
- def generate_cell(func: Callable, file: str, items: list[list[str]], row: int, col: int) -> None:
66
+ def generate_cell(func: Callable, file: str, items: list[list[str]], row: int, col: int, state: dict) -> None:
61
67
  """
62
68
  Takes a function, file and a file and then sets items[row][col] to the result.
63
69
  """
64
-
65
- items[row][col] = func(file).strip()
66
-
67
- def update_queue(task_queue: PriorityQueue, visible_rows_indices: list[int], rows: int, cols: int):
70
+ if not state["thread_stop_event"].is_set():
71
+ try:
72
+ result = func(file).strip()
73
+ if not state["thread_stop_event"].is_set():
74
+ items[row][col] = result
75
+ except Exception as e:
76
+ pass
77
+ # import pyperclip
78
+ # pyperclip.copy(f"({row}, {col}): len(items)={len(items)}, len(items[0])={len(items[0])} {e}")
79
+
80
+ def update_queue(task_queue: PriorityQueue, visible_rows_indices: list[int], rows: int, cols: int, state: dict):
68
81
  """ Increase the priority of getting the data for the cells that are currently visible. """
69
82
  while task_queue.qsize() > 0:
70
83
  time.sleep(0.1)
84
+ if state["thread_stop_event"].is_set():
85
+ with task_queue.mutex:
86
+ task_queue.queue.clear()
87
+ break
71
88
  for row in visible_rows_indices:
72
89
  for col in range(cols):
90
+ if state["generate_data_for_hidden_columns"] == False and col+1 in state["hidden_columns"]: continue
73
91
  if 0 <= row < rows:
74
92
  task_queue.put((1, (row, col)))
75
93
 
@@ -124,7 +142,9 @@ def generate_picker_data_from_file(
124
142
  items,
125
143
  header,
126
144
  visible_rows_indices,
127
- getting_data
145
+ getting_data,
146
+ state,
147
+
128
148
  ) -> None:
129
149
  """
130
150
  Generate data for Picker based upon the toml file commands.
@@ -155,6 +175,7 @@ def generate_picker_data_from_file(
155
175
  picker_header = header,
156
176
  visible_rows_indices = visible_rows_indices,
157
177
  getting_data = getting_data,
178
+ state=state,
158
179
  )
159
180
 
160
181
  def generate_picker_data(
@@ -164,7 +185,8 @@ def generate_picker_data(
164
185
  items,
165
186
  picker_header,
166
187
  visible_rows_indices,
167
- getting_data
188
+ getting_data,
189
+ state,
168
190
  ) -> None:
169
191
  """
170
192
  Generate data from a list of files and a list of column functions which will be used to
@@ -180,13 +202,13 @@ def generate_picker_data(
180
202
 
181
203
  items.clear()
182
204
  items.extend([[file] + ["..." for _ in column_functions] for file in files])
183
- # items[:] = [[file] + ["..." for _ in column_functions] for file in files]
184
205
  picker_header[:] = data_header
185
206
 
186
207
 
187
- task_queue = PriorityQueue()
208
+ task_queue = state["data_generation_queue"]
188
209
  for i in range(len(files)):
189
210
  for j in range(len(column_functions)):
211
+ if state["generate_data_for_hidden_columns"] == False and j+1 in state["hidden_columns"]: continue
190
212
  task_queue.put((10, (i, j)))
191
213
 
192
214
  num_workers = os.cpu_count()
@@ -197,14 +219,16 @@ def generate_picker_data(
197
219
  for _ in range(num_workers):
198
220
  gen_items_thread = threading.Thread(
199
221
  target=generate_columns_worker,
200
- args=(column_functions, files, items, getting_data, task_queue, completed_cells),
222
+ args=(column_functions, files, items, getting_data, task_queue, completed_cells, state),
201
223
  )
224
+ state["threads"].append(gen_items_thread)
202
225
  gen_items_thread.daemon = True
203
226
  gen_items_thread.start()
204
227
 
205
228
  update_queue_thread = threading.Thread(
206
229
  target=update_queue,
207
- args=(task_queue, visible_rows_indices, len(files), len(column_functions)),
230
+ args=(task_queue, visible_rows_indices, len(files), len(column_functions), state),
208
231
  )
232
+ state["threads"].append(update_queue_thread)
209
233
  update_queue_thread.daemon = True
210
234
  update_queue_thread.start()
@@ -0,0 +1,43 @@
1
+ #!/bin/python
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ generate_data_utils.py
5
+
6
+ Author: GrimAndGreedy
7
+ License: MIT
8
+ """
9
+
10
+ def sort_priority_first(element):
11
+ return element[0]
12
+
13
+ class ProcessSafePriorityQueue:
14
+ def __init__(self, manager):
15
+ self.data = manager.list()
16
+ self.lock = manager.Lock()
17
+
18
+ def put(self, item):
19
+ with self.lock:
20
+ self.data.append(item)
21
+ self.data.sort(key=sort_priority_first)
22
+
23
+ def get(self, timeout=None):
24
+ start = time.time()
25
+ while True:
26
+ with self.lock:
27
+ if self.data:
28
+ return self.data.pop(0)
29
+ if timeout is not None and (time.time() - start) > timeout:
30
+ raise IndexError("get timeout")
31
+ time.sleep(0.01)
32
+
33
+ def qsize(self):
34
+ with self.lock:
35
+ return len(self.data)
36
+
37
+ def empty(self):
38
+ with self.lock:
39
+ return len(self.data) == 0
40
+
41
+ def clear(self):
42
+ with self.lock:
43
+ self.data[:] = []
listpick/utils/utils.py CHANGED
@@ -15,9 +15,13 @@ import os
15
15
  from typing import Tuple, Dict
16
16
  import logging
17
17
  import shlex
18
+ from collections import defaultdict
19
+ import time
18
20
 
19
21
  logger = logging.getLogger('picker_log')
20
22
 
23
+
24
+
21
25
  def clip_left(text, n):
22
26
  """
23
27
  Clips the first `n` display-width characters from the left of the input string.
@@ -99,7 +103,12 @@ def format_row(row: list[str], hidden_columns: list, column_widths: list[int], s
99
103
 
100
104
  def get_column_widths(items: list[list[str]], header: list[str]=[], max_column_width:int=70, number_columns:bool=True, max_total_width=-1, separator = " ", unicode_char_width: bool = True) -> list[int]:
101
105
  """ Calculate maximum width of each column with clipping. """
102
- if len(items) == 0: return [0]
106
+ if len(items) == 0 and len(header) == 0: return [0]
107
+ elif len(items) == 0:
108
+ header_widths = [wcswidth(f"{i}. {str(h)}") if number_columns else wcswidth(str(h)) for i, h in enumerate(header)]
109
+ col_widths = [min(max_column_width, header_widths[i]) for i in range(len(header))]
110
+ return col_widths
111
+
103
112
  assert len(items) > 0
104
113
  widths = [max(wcswidth(str(row[i])) for row in items) for i in range(len(items[0]))]
105
114
  # widths = [max(len(str(row[i])) for row in items) for i in range(len(items[0]))]
@@ -205,17 +214,11 @@ def get_selected_cells(cell_selections: Dict[Tuple[int, int], bool]) -> list[Tup
205
214
  def get_selected_cells_by_row(cell_selections: dict[tuple[int, int], bool]) -> dict[int, list[int]]:
206
215
  """ {0: [1,2], 9: [1] }"""
207
216
 
208
- d = {}
209
- try:
210
- for tup in cell_selections.keys():
211
- if cell_selections[tup]:
212
- if tup[0] in d:
213
- d[tup[0]].append(tup[1])
214
- else:
215
- d[tup[0]] = [tup[1]]
216
- except:
217
- pass
218
- return d
217
+ d = defaultdict(list)
218
+ for (row, col), selected in cell_selections.items():
219
+ if selected:
220
+ d[row].append(col)
221
+ return dict(d)
219
222
 
220
223
  def get_selected_values(items: list[list[str]], selections: dict[int, bool]) -> list[list[str]]:
221
224
  """ Return a list of rows based on wich are True in the selections dictionary. """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: listpick
3
- Version: 0.1.16.8
3
+ Version: 0.1.16.17
4
4
  Summary: Listpick is a powerful TUI data tool for creating TUI apps or viewing/comparing tabulated data.
5
5
  Home-page: https://github.com/grimandgreedy/listpick
6
6
  Author: Grim
@@ -43,11 +43,7 @@ Dynamic: summary
43
43
 
44
44
  # listpick
45
45
 
46
- listpick is a TUI tool which displays a tabulated list of rows and allows the user to operate upon these rows--select, copy, pipe. A very simple concept but also, I hope, a powerful tool that will make it easier for people to develop TUI apps.
47
-
48
- Rows of data can be viewed, selected, generated, saved, loaded, refreshed, modified or copied to the clipboard. Easy to integrate into your project by creating a `menu = Picker(stdscr: curses.window, items: list[list[str]])` and then the menu will be displayed by running `menu.run()`.
49
-
50
- It works great as the backend for a TUI application and can also be used as a standalone data viewer.
46
+ listpick is a powerful TUI data tool for viewing, editing and operating upon tabulated data; can be used to build TUI applications, generate data columns, or function as a command-line utility.
51
47
 
52
48
  **NOTE**: listpick is still in development.
53
49
 
@@ -72,18 +68,13 @@ x = Picker(
72
68
  ["row zero column zero", "row zero column one"],
73
69
  ["row one column zero", "row one column one"]
74
70
  ],
75
- header=["H0", "H1"]
71
+ header=["H0", "H1"],
72
+ cell_cursor=True,
76
73
  )
77
74
  x.run()
78
75
 
79
76
  close_curses(stdscr)
80
77
 
81
- ```
82
- Or use the listpick binary to generate and display rows based on a list of commands:
83
-
84
- ```
85
- wget https://raw.githubusercontent.com/grimandgreedy/listpick/refs/heads/master/examples/data_generation/list_files.toml
86
- listpick -g list_files.py
87
78
  ```
88
79
 
89
80
  ## Overview
@@ -102,31 +93,42 @@ The application allows you to:
102
93
  ## Examples
103
94
 
104
95
 
105
- ### Identify video duplicates (./examples/data_generation//video_duplicates.toml):
106
- ```python
107
- listpick -g ./examples/data_generation/video_duplicates.toml
96
+ ### listpick as a command-line tool
97
+
98
+ listpick can be used as a command-line tool for tabulating command outputs:
99
+ ```bash
100
+ df -h | listpick --stdin
108
101
  ```
109
- - From the list of commands in the toml file we generate the properties we will use to identify the duplicates.
110
102
 
111
- - In the example file we set the directory and get the files with a simle `eza` (`ls`) command. We could also use `find` or `cat` from a list of files.
103
+ <div align="center"> <img src="assets/listpick_df_example.png" alt="lpfman" width="90%"> </div>
112
104
 
105
+ ### Applications
113
106
 
114
- - We get the SHA1 hash to identify identical files; we also get the size, duration, resolution, and bitrate so that we can identify a video duplicate that may have the same duration but a lower resolution.
107
+ #### Aria2TUI
108
+
109
+ [Aria2TUI](https://github.com/grimandgreedy/Aria2TUI): TUI client for the aria2c download utility.
110
+
111
+ <div align="center"> <img src="assets/aria2tui_graph_screenshot.png" alt="Aria2TUI" width="90%"> </div>
112
+
113
+ #### lpfman
114
+ [lpfman](https://github.com/grimandgreedy/lpfman): Terminal file manager with extensive column support.
115
115
 
116
- <div align="center"> <img src="assets/file_compare.png" alt="Video Compare" width="70%"> </div>
116
+ <div align="center"> <img src="https://github.com/grimandgreedy/lpfman/blob/master/assets/lpfman_02.png?raw=true" alt="lpfman" width="90%"> </div>
117
117
 
118
118
 
119
- ### Aria2TUI
119
+ ### Data generation from toml file
120
120
 
121
- [Aria2TUI](https://github.com/grimandgreedy/Aria2TUI) is implemented using listpick. This is a good example of how listpick can be used for menus, data viewing, and active data retrieval.
121
+ ```python
122
+ listpick -g ./listpick/examples/data_generation/video_duplicates.toml
123
+ ```
124
+ - From the list of commands in the toml file we generate the properties we will use to identify the duplicates.
122
125
 
123
- <div align="center"> <img src="assets/aria2tui_screenshot.png" alt="Aria2TUI" width="70%"> </div>
126
+ - In the example file we set the directory and get the files with a simle `eza` (`ls`) command. We could also use `find` or `cat` from a list of files.
124
127
 
125
- ### lpfman
126
- [lpfman](https://github.com/grimandgreedy/lpfman) is a basic file manager created for the purposes of illustrating how easy TUI apps can be developed with the use of listpick. In 20 minutes and <100 lines of code we made a very basic file manager.
127
128
 
128
- <div align="center"> <img src="assets/lpfman.png" alt="lpfman" width="70%"> </div>
129
+ - We get the SHA1 hash to identify identical files; we also get the size, duration, resolution, and bitrate so that we can identify a video duplicate that may have the same duration but a lower resolution.
129
130
 
131
+ <div align="center"> <img src="assets/file_compare.png" alt="Video Compare" width="90%"> </div>
130
132
 
131
133
 
132
134
  ## Description
@@ -134,7 +136,7 @@ listpick -g ./examples/data_generation/video_duplicates.toml
134
136
  ### Key Features:
135
137
  1. **File Input Support:**
136
138
  ```python
137
- listpick -i ~/dn.pkl -t pkl
139
+ listpick -i ~/items.csv
138
140
  ```
139
141
  - Text files (TSV, CSV)
140
142
  - JSON
@@ -206,19 +208,6 @@ listpick -g ./examples/data_generation/video_duplicates.toml
206
208
  - Opening files with a specific application `xargs -d \n -I{} mpv {}` will open the files in mpv
207
209
  - Dumping data. `xargs -d \n -I{} echo {} > ~/stuff.txt`
208
210
 
209
- ## Overview
210
-
211
- The application allows you to:
212
- - Select multiple items from different file types and input streams
213
- - Navigate between selected items with arrow keys
214
- - Delete individual items
215
- - Highlight specific items for quick selection
216
- - Perform complex filtering operations
217
- - Sort data based on specified columns
218
- - Persistent save/load of selections
219
- - Copy/paste selections to clipboard
220
-
221
-
222
211
  ## Support and Feedback
223
212
 
224
213
  Feel free to request features. Please report any errors you encounter with appropriate context.
@@ -1,25 +1,29 @@
1
1
  listpick/__init__.py,sha256=ExXc97-bibodH--wlwpQivl0zCNR5D1hvpvrf7OBofU,154
2
2
  listpick/__main__.py,sha256=wkCjDdqw093W27yWwnlC3nG_sMRKaIad7hHHWy0RBgY,193
3
- listpick/listpick_app.py,sha256=oFkMaWdoqd6fId1hBSavY2Nsoql6EcVppd4d7mgVVGo,201956
3
+ listpick/listpick_app.py,sha256=MHe0-HWbby5SNotbozL_7hcR0lrMYy5jujFoRoPiSuo,222741
4
4
  listpick/pane/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  listpick/pane/get_data.py,sha256=l12mHIb6qoZWIfW5zZZY8K8EqNcyIcRiHgtRaM2CVGs,2735
6
+ listpick/pane/left_pane_functions.py,sha256=SVIW4Ef8uNPBQRk4hL67mEFL3pfgChSFZSMRz06CVzw,5543
6
7
  listpick/pane/pane_functions.py,sha256=_dL9jHpd3sT0enL9H_bMcUsBlMELXdtP9dtKFSC2KPQ,5117
8
+ listpick/pane/pane_functions_1.py,sha256=_dL9jHpd3sT0enL9H_bMcUsBlMELXdtP9dtKFSC2KPQ,5117
7
9
  listpick/pane/pane_utils.py,sha256=cnuzBH52wdWoKrHR6iMBF4N-uhwpXYpHDnrglk21pqg,2539
8
10
  listpick/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- listpick/ui/build_help.py,sha256=FNKshZpYJfgF-17ad5Mq0IGeBEo7y52u3CcpQ8ajlOs,10774
11
+ listpick/ui/build_help.py,sha256=wSGeE3tUVWP7D709mb1cDyRU2M0QKVg0mRyTFmcR3fo,11720
10
12
  listpick/ui/draw_screen.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
13
  listpick/ui/footer.py,sha256=NcdH1uO_ma91m0qCczyQZ3zGrexfkiEnwDf5E4tHSMk,15089
12
14
  listpick/ui/help_screen.py,sha256=zbfGIgb-IXtATpl4_Sx7nPbsnRXZ7eiMYlCKGS9EFmw,5608
13
- listpick/ui/input_field.py,sha256=scJjvmSS0QqeDbCky7_0Zgt35Aki7gezRJkrQROlLg4,30034
14
- listpick/ui/keys.py,sha256=rOOhvxfrQ1LRuLJYf_6pAQcuugxHo-M9TQn7Qow5uIg,13716
15
- listpick/ui/picker_colours.py,sha256=FFsyny_q0mGO6u7B1n7anuReBtP7Jw6LrgX5ycN-MRM,13413
15
+ listpick/ui/input_field.py,sha256=1GUuzMl7P-uw5ijYUOQONMhAzAKoYXRax0-332OroLE,29971
16
+ listpick/ui/keys.py,sha256=7QpG8xEp7kBH9tObTzL-Cmw7i5HTvN6amA3Dd4FmMpE,14077
17
+ listpick/ui/picker_colours.py,sha256=PYWtJEbBCsiM-Gbm83vJiFoIwfKuJuP4SGKxpozszKY,15159
16
18
  listpick/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
19
  listpick/utils/clipboard_operations.py,sha256=ORdNm2kgGbfs51xJSvgJPERgoSmBgT11axuMkvSoP9A,3133
18
20
  listpick/utils/config.py,sha256=MEnAZg2Rhfl38XofEIN0uoVAOY7I0ftc79Evk3fOiVw,1654
19
21
  listpick/utils/dump.py,sha256=60YVIMNtBoYvWhmzfTJOsNGcetOvcCB3_T7yv-bYTPQ,3838
20
22
  listpick/utils/filtering.py,sha256=59_YIEYRV0ovnjF4iyuShq276FMAx5gBD9m3mE9IqJg,1237
21
23
  listpick/utils/generate_data.py,sha256=TCGwDrN49Xx33AdURpQRGi6Xi2uwjt96rEeWWYS8mFE,4649
22
- listpick/utils/generate_data_multithreaded.py,sha256=9TF-Z1qF3GDNFbe5K9Gf6EUj0UpruZTdKWHxz6jgGHY,6590
24
+ listpick/utils/generate_data_multiprocessing.py,sha256=B797wFm7bSpoe0wb5C_q1J96ffVp3JCB5Lu4Rly8K8M,178
25
+ listpick/utils/generate_data_multithreaded.py,sha256=jI9kWgWegnumegQOnKxrJg854lGw59cOXm-IyzdpjQ8,7631
26
+ listpick/utils/generate_data_utils.py,sha256=Aw1uL4Feqm6-23K-PhQg232N5dQZ16RGNIF_dvTPbtQ,1009
23
27
  listpick/utils/graphing.py,sha256=ugjAH8js_iH7hulg4SySxb_W_f8B6GhTaceN5i7DID4,6954
24
28
  listpick/utils/keycodes.py,sha256=ZGkw1-4szxPnP81wj80r92L6_neIOlBBjQltEieCwnk,2696
25
29
  listpick/utils/options_selectors.py,sha256=fQqTCAqRsrMhZwXUtsPBm47svkaUaeJqWsMW7Q4JTYY,3083
@@ -30,10 +34,10 @@ listpick/utils/searching.py,sha256=Xk5UIqamNHL2L90z3ACB_Giqdpi9iRKoAJ6pKaqaD7Q,3
30
34
  listpick/utils/sorting.py,sha256=WZZiVlVA3Zkcpwji3U5SNFlQ14zVEk3cZJtQirBkecQ,5329
31
35
  listpick/utils/table_to_list_of_lists.py,sha256=XBj7eGBDF15BRME-swnoXyOfZWxXCxrXp0pzsBfcJ5g,12224
32
36
  listpick/utils/user_input.py,sha256=L3ylI7nnuFM_TP1XKwpiKpxUSkNb2W5cr7mJjTmv_6E,4582
33
- listpick/utils/utils.py,sha256=nsR6orCBQy3rTXrCweq8cV-RzRVU15v3J9NclPeAOJk,13741
34
- listpick-0.1.16.8.dist-info/licenses/LICENSE.txt,sha256=2mP-MRHJptADDNE9VInMNg1tE-C6Qv93Z4CCQKrpg9w,1061
35
- listpick-0.1.16.8.dist-info/METADATA,sha256=ywGEK-Ljulg5NRWTW-AKhbZSCDOcASjOK5UdOSmWeo4,8128
36
- listpick-0.1.16.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
- listpick-0.1.16.8.dist-info/entry_points.txt,sha256=-QCf_BKIkUz35Y9nkYpjZWs2Qg0KfRna2PAs5DnF6BE,43
38
- listpick-0.1.16.8.dist-info/top_level.txt,sha256=5mtsGEz86rz3qQDe0D463gGjAfSp6A3EWg4J4AGYr-Q,9
39
- listpick-0.1.16.8.dist-info/RECORD,,
37
+ listpick/utils/utils.py,sha256=gwonigqPd8nSQBvN6lLDB68kwUzXqWALesZBja-cehU,13956
38
+ listpick-0.1.16.17.dist-info/licenses/LICENSE.txt,sha256=2mP-MRHJptADDNE9VInMNg1tE-C6Qv93Z4CCQKrpg9w,1061
39
+ listpick-0.1.16.17.dist-info/METADATA,sha256=_NIFHFBvzMzRwNXlPJG7CZa_PG0DmiL9D__ylQ_wJYQ,7144
40
+ listpick-0.1.16.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
41
+ listpick-0.1.16.17.dist-info/entry_points.txt,sha256=-QCf_BKIkUz35Y9nkYpjZWs2Qg0KfRna2PAs5DnF6BE,43
42
+ listpick-0.1.16.17.dist-info/top_level.txt,sha256=5mtsGEz86rz3qQDe0D463gGjAfSp6A3EWg4J4AGYr-Q,9
43
+ listpick-0.1.16.17.dist-info/RECORD,,