listpick 0.1.13.59__py3-none-any.whl → 0.1.13.61__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.

Potentially problematic release.


This version of listpick might be problematic. Click here for more details.

listpick/listpick_app.py CHANGED
@@ -449,8 +449,6 @@ class Picker:
449
449
  # self.stdscr.refresh()
450
450
  # self.draw_screen(self.indexed_items, self.highlights)
451
451
 
452
-
453
-
454
452
  def initialise_variables(self, get_data: bool = False) -> None:
455
453
  """ Initialise the variables that keep track of the data. """
456
454
 
@@ -473,6 +471,7 @@ class Picker:
473
471
 
474
472
  self.items, self.header = self.refresh_function()
475
473
 
474
+ self.items = pad_lists_to_same_length(self.items)
476
475
 
477
476
  if self.items == []: self.items = [[]]
478
477
  ## Ensure that items is a List[List[Str]] object
@@ -1959,6 +1958,8 @@ class Picker:
1959
1958
 
1960
1959
  while True:
1961
1960
  key = self.stdscr.getch()
1961
+ if key:
1962
+ self.logger.info(f"key={key}")
1962
1963
  h, w = self.stdscr.getmaxyx()
1963
1964
  if key in self.disabled_keys: continue
1964
1965
  clear_screen=True
listpick/utils/utils.py CHANGED
@@ -344,3 +344,20 @@ def guess_file_type(filename: str) -> str:
344
344
  """ Guess filetype. Currently just uses the extension of the file. """
345
345
  logger.info("function: guess_file_type (utils.py)")
346
346
  return filename.split(".")[-1]
347
+
348
+
349
+ def pad_lists_to_same_length(list_of_lists: list[list[str]]) -> list[list[str]]:
350
+ """ Ensure that all lists in a list of lists are of the same length. Pad any shorter sublists with empty strings. """
351
+ if not list_of_lists or list_of_lists in [[], [[]]]:
352
+ return []
353
+
354
+ # Find the maximum length of the sublists
355
+ lengths = [len(sublist) for sublist in list_of_lists]
356
+ max_length = max(lengths)
357
+ min_length = min(lengths)
358
+ if min_length == max_length: return list_of_lists
359
+
360
+ # Pad each sublist with empty strings to match the maximum length
361
+ padded_list = [sublist + [''] * (max_length - len(sublist)) for sublist in list_of_lists]
362
+
363
+ return padded_list
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: listpick
3
- Version: 0.1.13.59
3
+ Version: 0.1.13.61
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
@@ -1,10 +1,9 @@
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=cAZXi69fk_1dcmWF36FfTgEptLyzLQRSdBYG8qCY9bA,165151
3
+ listpick/listpick_app.py,sha256=xCtAMJTeWwos2XTCN7PwZgEgo3lAKmsp74M0cNgyvUI,165274
4
4
  listpick/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  listpick/ui/build_help.py,sha256=_rVKKrX3HfFJtw-pyeNb2lQWbml4-AAw8sZIUYGn97Y,8731
6
6
  listpick/ui/footer.py,sha256=s1L68MNmhWwbWRy0mn0ChmnE_dMQBAzNlTv917pyHE0,10673
7
- listpick/ui/footer_1.py,sha256=Mpn0gFAnX_Ely-Jl5KPP6sdZRnk8makt8EVBh9wdr4Y,10710
8
7
  listpick/ui/help_screen.py,sha256=zbfGIgb-IXtATpl4_Sx7nPbsnRXZ7eiMYlCKGS9EFmw,5608
9
8
  listpick/ui/input_field.py,sha256=eyoWHoApdZybjfXcp7Eth7xwb-C-856ZVnq5j_Q3Ojs,30412
10
9
  listpick/ui/keys.py,sha256=TzaadgBP_rC7jbp--RFJZDOkHd0EB4K1wToDTiVs6CI,13029
@@ -23,10 +22,10 @@ listpick/utils/search_and_filter_utils.py,sha256=XxGfkyDVXO9OAKcftPat8IReMTFIuTH
23
22
  listpick/utils/searching.py,sha256=Xk5UIqamNHL2L90z3ACB_Giqdpi9iRKoAJ6pKaqaD7Q,3093
24
23
  listpick/utils/sorting.py,sha256=WZZiVlVA3Zkcpwji3U5SNFlQ14zVEk3cZJtQirBkecQ,5329
25
24
  listpick/utils/table_to_list_of_lists.py,sha256=T-i-nV1p6g8UagdgUPKrhIGpKY_YXZDxf4xZzcPepNA,7635
26
- listpick/utils/utils.py,sha256=_4HW0p1gnundsTJcKsSsIKCZxy3DtolbxjBpuYQyFBw,12948
27
- listpick-0.1.13.59.dist-info/licenses/LICENSE.txt,sha256=2mP-MRHJptADDNE9VInMNg1tE-C6Qv93Z4CCQKrpg9w,1061
28
- listpick-0.1.13.59.dist-info/METADATA,sha256=bD3N7PxFIQnVXf080zULv-TjMr9ia7RL8pLSZO2smYY,7988
29
- listpick-0.1.13.59.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
- listpick-0.1.13.59.dist-info/entry_points.txt,sha256=-QCf_BKIkUz35Y9nkYpjZWs2Qg0KfRna2PAs5DnF6BE,43
31
- listpick-0.1.13.59.dist-info/top_level.txt,sha256=5mtsGEz86rz3qQDe0D463gGjAfSp6A3EWg4J4AGYr-Q,9
32
- listpick-0.1.13.59.dist-info/RECORD,,
25
+ listpick/utils/utils.py,sha256=m4uzL2ZPVpFuboIola0_ZIfLzlbGqirdz0_oo61tIlU,13636
26
+ listpick-0.1.13.61.dist-info/licenses/LICENSE.txt,sha256=2mP-MRHJptADDNE9VInMNg1tE-C6Qv93Z4CCQKrpg9w,1061
27
+ listpick-0.1.13.61.dist-info/METADATA,sha256=VPjp9FR1XNwseaF4k0z4jyEHp3J7qXqXe3vFVlMXZrQ,7988
28
+ listpick-0.1.13.61.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
+ listpick-0.1.13.61.dist-info/entry_points.txt,sha256=-QCf_BKIkUz35Y9nkYpjZWs2Qg0KfRna2PAs5DnF6BE,43
30
+ listpick-0.1.13.61.dist-info/top_level.txt,sha256=5mtsGEz86rz3qQDe0D463gGjAfSp6A3EWg4J4AGYr-Q,9
31
+ listpick-0.1.13.61.dist-info/RECORD,,
listpick/ui/footer_1.py DELETED
@@ -1,202 +0,0 @@
1
- """
2
- footer.py
3
- Lines to be displayed on the help screen.
4
-
5
- Author: GrimAndGreedy
6
- License: MIT
7
- """
8
-
9
- import curses
10
- import logging
11
-
12
- logger = logging.getLogger('picker_log')
13
-
14
- class Footer:
15
- def __init__(self, stdscr, colours_start, get_state_function):
16
- """
17
- stdscr: curses screen object
18
- colours_start: base colour pair index
19
- get_state_callback: function that returns a dict with all required data for rendering
20
- """
21
- self.stdscr = stdscr
22
- self.colours_start = colours_start
23
- self.get_state = get_state_function
24
- self.height = 0
25
-
26
- def draw(self, h, w):
27
- """
28
- Draw the footer. Must be implemented by subclasses.
29
- """
30
- raise NotImplementedError
31
-
32
- class StandardFooter(Footer):
33
- def __init__(self, stdscr, colours_start, get_state_function):
34
- """
35
- stdscr: curses screen object
36
- colours_start: base colour pair index
37
- get_state_callback: function that returns a dict with all required data for rendering
38
- """
39
- self.stdscr = stdscr
40
- self.colours_start = colours_start
41
- self.get_state = get_state_function
42
- self.height = 3
43
- def draw(self, h, w):
44
- state = self.get_state()
45
-
46
- # Fill background
47
- for i in range(3):
48
- self.stdscr.addstr(h-3+i, 0, ' '*(w-1), curses.color_pair(self.colours_start+20))
49
-
50
- if state["filter_query"]:
51
- self.stdscr.addstr(h - 2, 2, f" Filter: {state['filter_query']} "[:w-40], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
52
- if state["search_query"]:
53
- self.stdscr.addstr(h - 3, 2, f" Search: {state['search_query']} [{state['search_index']}/{state['search_count']}] "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
54
- if state["user_opts"]:
55
- self.stdscr.addstr(h - 1, 2, f" Opts: {state['user_opts']} "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
56
-
57
- # Sort info
58
- sort_column_info = f"{state['sort_column'] if state['sort_column'] is not None else 'None'}"
59
- sort_method_info = f"{state['SORT_METHODS'][state['columns_sort_method'][state['sort_column']]]}" if state['sort_column'] is not None else "NA"
60
- sort_order_info = "Desc." if state["sort_reverse"] else "Asc."
61
- sort_order_info = "▼" if state["sort_reverse"][state['sort_column']] else "▲"
62
- sort_disp_str = f" Sort: ({sort_column_info}, {sort_method_info}, {sort_order_info}) "
63
- self.stdscr.addstr(h - 2, w-35, f"{sort_disp_str:>34}", curses.color_pair(self.colours_start+20))
64
-
65
- if state["footer_string"]:
66
- # footer_string_width = min(w-1, max(len(state["footer_string"]), 50))
67
- # disp_string = f"{state['footer_string'][:footer_string_width]:>{footer_string_width-1}} "
68
- # self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
69
- # self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
70
-
71
- # disp_string = f"{footer_string:>{footer_string_width-1}} "
72
- # self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
73
- # self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
74
-
75
- footer_string_width = min(w-1, len(state["footer_string"])+2)
76
-
77
- disp_string = f"{state["footer_string"][:footer_string_width]}"
78
- disp_string = f" {disp_string:>{footer_string_width-2}} "
79
- self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
80
- self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
81
-
82
-
83
- else:
84
- select_mode = "Cursor"
85
- if state["is_selecting"]: select_mode = "Visual Selection"
86
- elif state["is_deselecting"]: select_mode = "Visual deselection"
87
- self.stdscr.addstr(h - 1, w-35, f"{select_mode:>33} ", curses.color_pair(self.colours_start+20))
88
-
89
- # Cursor & selection info
90
- selected_count = sum(state["selections"].values())
91
- if state["paginate"]:
92
- cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])} Page {state['cursor_pos']//state['items_per_page']}/{len(state['indexed_items'])} Selected {selected_count}"
93
- else:
94
- cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])} | Selected {selected_count}"
95
- self.stdscr.addstr(h - 3, w-35, f"{cursor_disp_str:>33} ", curses.color_pair(self.colours_start+20))
96
-
97
- self.stdscr.refresh()
98
-
99
-
100
-
101
- class CompactFooter(Footer):
102
- def __init__(self, stdscr, colours_start, get_state_function):
103
- """
104
- stdscr: curses screen object
105
- colours_start: base colour pair index
106
- get_state_callback: function that returns a dict with all required data for rendering
107
- """
108
- self.stdscr = stdscr
109
- self.colours_start = colours_start
110
- self.get_state = get_state_function
111
- self.height = 1
112
-
113
- def draw(self, h, w):
114
- state = self.get_state()
115
-
116
- # Fill background
117
- if state["search_query"]: self.height = 3
118
- elif state["filter_query"]: self.height = 2
119
- elif state["user_opts"]: self.height = 1
120
- elif state["footer_string"]: self.height = 2
121
- else: self.height = 1
122
- for i in range(self.height):
123
- self.stdscr.addstr(h-(i+1), 0, ' '*(w-1), curses.color_pair(self.colours_start+20))
124
-
125
- if state["user_opts"]:
126
- self.stdscr.addstr(h - 1, 2, f" Opts: {state['user_opts']} "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
127
- if state["filter_query"]:
128
- self.stdscr.addstr(h - 2, 2, f" Filter: {state['filter_query']} "[:w-40], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
129
- if state["search_query"]:
130
- self.stdscr.addstr(h - 3, 2, f" Search: {state['search_query']} [{state['search_index']}/{state['search_count']}] "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
131
-
132
- right_width = 40
133
- # Sort info
134
- sort_column_info = f"{state['sort_column'] if state['sort_column'] is not None else 'None'}"
135
- sort_method_info = f"{state['SORT_METHODS'][state['columns_sort_method'][state['sort_column']]]}" if state['sort_column'] is not None else "NA"
136
- sort_order_info = "Desc." if state["sort_reverse"][state['sort_column']] else "Asc."
137
- sort_order_info = "▼" if state["sort_reverse"][state['sort_column']] else "▲"
138
- sort_disp_str = f" ({sort_column_info}, {sort_method_info}, {sort_order_info}) "
139
- # self.stdscr.addstr(h - 2, w-right_width, f"{sort_disp_str:>{right_width-1}}", curses.color_pair(self.colours_start+20))
140
-
141
- if state["footer_string"]:
142
- footer_string_width = min(w-1, len(state["footer_string"])+2)
143
-
144
- disp_string = f"{state["footer_string"][:footer_string_width]}"
145
- disp_string = f" {disp_string:>{footer_string_width-2}} "
146
- self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
147
- self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
148
- selected_count = sum(state["selections"].values())
149
- if state["paginate"]:
150
- cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])} Page {state['cursor_pos']//state['items_per_page']}/{len(state['indexed_items'])} Selected {selected_count}"
151
- else:
152
- cursor_disp_str = f"{sort_disp_str} [{selected_count}] {state['cursor_pos']+1}/{len(state['indexed_items'])}"
153
- self.stdscr.addstr(h-2, w-right_width, f"{cursor_disp_str:>{right_width-2}}"[:right_width-1], curses.color_pair(self.colours_start+20))
154
- else:
155
- # Cursor & selection info
156
- selected_count = sum(state["selections"].values())
157
- if state["paginate"]:
158
- cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])} Page {state['cursor_pos']//state['items_per_page']}/{len(state['indexed_items'])} Selected {selected_count}"
159
- else:
160
- cursor_disp_str = f"{sort_disp_str} [{selected_count}] {state['cursor_pos']+1}/{len(state['indexed_items'])}"
161
- self.stdscr.addstr(h - 1, w-right_width, f"{cursor_disp_str:>{right_width-2}}"[:right_width-1], curses.color_pair(self.colours_start+20))
162
-
163
- self.stdscr.refresh()
164
-
165
- class NoFooter(Footer):
166
- def __init__(self, stdscr, colours_start, get_state_function):
167
- """
168
- stdscr: curses screen object
169
- colours_start: base colour pair index
170
- get_state_callback: function that returns a dict with all required data for rendering
171
- """
172
- self.stdscr = stdscr
173
- self.colours_start = colours_start
174
- self.get_state = get_state_function
175
- self.height = 0
176
- def draw(self, h, w):
177
- state = self.get_state()
178
-
179
- if state["search_query"]: self.height = 3
180
- elif state["filter_query"]: self.height = 2
181
- elif state["user_opts"]: self.height = 1
182
- elif state["footer_string"]: self.height = 1
183
- else: self.height = 0
184
-
185
- for i in range(self.height):
186
- self.stdscr.addstr(h-(i+1), 0, ' '*(w-1), curses.color_pair(self.colours_start+20))
187
-
188
- if state["user_opts"]:
189
- self.stdscr.addstr(h - 1, 2, f" Opts: {state['user_opts']} "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
190
- if state["filter_query"]:
191
- self.stdscr.addstr(h - 2, 2, f" Filter: {state['filter_query']} "[:w-40], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
192
- if state["search_query"]:
193
- self.stdscr.addstr(h - 3, 2, f" Search: {state['search_query']} [{state['search_index']}/{state['search_count']}] "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
194
- self.height = 3
195
-
196
-
197
- if state["footer_string"]:
198
- footer_string_width = min(w-1, len(state["footer_string"])+2)
199
- disp_string = f"{state["footer_string"][:footer_string_width]}"
200
- disp_string = f" {disp_string:>{footer_string_width-2}} "
201
- self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
202
- self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))