0
# Interactive Selection
1
2
User interface for selecting packages to upgrade, presenting upgrade information in formatted tables with interactive prompts and pre-selection options.
3
4
## Capabilities
5
6
### Interactive Package Selection
7
8
Presents available package upgrades in a formatted table and handles user selection through an interactive command-line interface.
9
10
```python { .api }
11
class PackageInteractiveSelector:
12
def __init__(self, packages_map, options):
13
"""
14
Initialize interactive package selector.
15
16
Args:
17
packages_map (dict): Package status map from PackagesStatusDetector
18
options (dict): Command-line options including -p for pre-selection
19
20
Raises:
21
KeyboardInterrupt: If no packages need upgrading
22
"""
23
24
def get_packages(self):
25
"""
26
Return the list of packages selected for upgrade.
27
28
Returns:
29
list: List of package status dictionaries for selected packages
30
"""
31
32
def ask_for_packages(self):
33
"""
34
Display interactive upgrade table and prompt for user selection.
35
36
Displays:
37
- Formatted table with package names, versions, and upload dates
38
- Color-coded output for better readability
39
- Interactive prompt for package selection
40
41
Raises:
42
KeyboardInterrupt: On invalid selection or user cancellation
43
"""
44
```
45
46
### Package Selection Processing
47
48
Processes user selection input and validates package choices.
49
50
```python { .api }
51
def _select_packages(self, indexes):
52
"""
53
Select packages by index numbers from the upgrade table.
54
55
Args:
56
indexes (list): List of integer indexes corresponding to table rows
57
58
Returns:
59
list: List of booleans indicating successful selections
60
61
Side effects:
62
Populates self.selected_packages with selected package dictionaries
63
"""
64
```
65
66
### Cross-Platform Input Handling
67
68
Provides compatible input handling across Python 2 and 3.
69
70
```python { .api }
71
def user_input(prompt=None):
72
"""
73
Cross-Python compatible input function.
74
75
Args:
76
prompt (str, optional): Prompt string to display
77
78
Returns:
79
str: User input string
80
81
Compatibility:
82
Uses raw_input for Python 2, input for Python 3
83
"""
84
```
85
86
## Selection Modes
87
88
### Interactive Mode (Default)
89
90
When no `-p` option is provided, displays an interactive table for package selection.
91
92
**Table Format:**
93
```
94
Available upgrades:
95
┌─────┬─────────────────┬─────────────────┬────────────────┬─────────────────┐
96
│ No. │ Package │ Current version │ Latest version │ Release date │
97
├─────┼─────────────────┼─────────────────┼────────────────┼─────────────────┤
98
│ 1 │ django │ 3.2.0 │ 4.1.0 │ 2022-08-03 │
99
│ 2 │ requests │ 2.25.1 │ 2.28.1 │ 2022-06-29 │
100
│ 3 │ flask │ 2.0.0 │ 2.2.2 │ 2022-08-08 │
101
└─────┴─────────────────┴─────────────────┴────────────────┴─────────────────┘
102
103
Please choose which packages should be upgraded. Choices: "all", "q" (quit), "x" (exit) or "1 2 3"
104
Choice:
105
```
106
107
**Selection Options:**
108
- `all` - Select all available upgrades
109
- `q` or `x` - Quit/exit without upgrading
110
- `1 2 3` - Space-separated list of package numbers
111
- Empty input - Cancel operation
112
113
### Pre-Selection Mode
114
115
When `-p` option is provided, skips interactive prompts.
116
117
**All Packages:**
118
```bash
119
pip-upgrade requirements.txt -p all
120
```
121
122
**Specific Packages:**
123
```bash
124
pip-upgrade requirements.txt -p django -p flask
125
```
126
127
Matches package names case-insensitively.
128
129
## Usage Examples
130
131
### Interactive Selection
132
133
```python
134
from pip_upgrader.packages_interactive_selector import PackageInteractiveSelector
135
136
# Package status map from status detector
137
packages_map = {
138
'django': {
139
'name': 'django',
140
'current_version': Version('3.2.0'),
141
'latest_version': Version('4.1.0'),
142
'upgrade_available': True,
143
'upload_time': '2022-08-03 08:15:30'
144
},
145
'requests': {
146
'name': 'requests',
147
'current_version': Version('2.25.1'),
148
'latest_version': Version('2.28.1'),
149
'upgrade_available': True,
150
'upload_time': '2022-06-29 14:22:18'
151
}
152
}
153
154
# Interactive selection (no -p option)
155
options = {'-p': []}
156
selector = PackageInteractiveSelector(packages_map, options)
157
selected = selector.get_packages()
158
159
# User sees table and chooses "1 2"
160
print(len(selected)) # 2 packages selected
161
```
162
163
### Pre-Selection All
164
165
```python
166
# Select all packages automatically
167
options = {'-p': ['all']}
168
selector = PackageInteractiveSelector(packages_map, options)
169
selected = selector.get_packages()
170
171
print(len(selected)) # All upgradeable packages selected
172
```
173
174
### Pre-Selection Specific
175
176
```python
177
# Pre-select specific packages
178
options = {'-p': ['django', 'flask']}
179
selector = PackageInteractiveSelector(packages_map, options)
180
selected = selector.get_packages()
181
182
# Only django and flask will be selected (if available for upgrade)
183
```
184
185
## Color-Coded Output
186
187
The interface uses `colorclass` for enhanced terminal output:
188
189
### Table Headers
190
- **Blue**: Column headers (No., Package, Current version, etc.)
191
192
### Package Information
193
- **Green**: Package names and row numbers
194
- **Default**: Version numbers and dates
195
196
### User Prompts
197
- **Green**: "Available upgrades:" header
198
- **Red**: Error messages ("No choice selected", "Invalid choice")
199
200
### Status Messages
201
- **Green**: "All packages are up-to-date" when no upgrades available
202
203
## Input Validation
204
205
### Valid Inputs
206
207
```python
208
"all" # Select all packages
209
"1" # Select package #1
210
"1 2 3" # Select packages #1, #2, #3
211
"q" # Quit
212
"x" # Exit
213
```
214
215
### Invalid Inputs
216
217
```python
218
"" # Empty input -> "No choice selected"
219
" " # Whitespace only -> "No choice selected"
220
"5 6 7" # Non-existent indexes -> "No valid choice selected"
221
"abc" # Non-numeric -> "Invalid choice"
222
```
223
224
All invalid inputs raise `KeyboardInterrupt` with appropriate error messages.
225
226
## Edge Cases
227
228
### No Upgrades Available
229
230
When all packages are up-to-date:
231
232
```python
233
# Prints colored message and raises KeyboardInterrupt
234
print(Color('{autogreen}All packages are up-to-date.{/autogreen}'))
235
raise KeyboardInterrupt()
236
```
237
238
### Package Filtering
239
240
Only packages with `upgrade_available: True` are included in the interactive table. Up-to-date packages are filtered out automatically.
241
242
### Case-Insensitive Matching
243
244
Pre-selected package names are matched case-insensitively:
245
246
```python
247
# These are equivalent:
248
-p Django
249
-p django
250
-p DJANGO
251
```
252
253
### Index Mapping
254
255
Interactive selection uses 1-based indexing for user-friendliness, but internally maps to 0-based dictionary keys.
256
257
## Error Handling
258
259
### Selection Errors
260
261
- **Empty selection**: Displays "No choice selected" and cancels
262
- **Invalid numbers**: Displays "Invalid choice" and cancels
263
- **Out-of-range numbers**: Displays "No valid choice selected" and cancels
264
- **No matching pre-selected packages**: Results in empty selection (not an error)
265
266
### User Cancellation
267
268
- **Keyboard interrupts**: Ctrl+C during input gracefully exits
269
- **Quit commands**: 'q' and 'x' commands raise KeyboardInterrupt for clean exit
270
- **Empty selections**: Treated as cancellation
271
272
### Package Mapping Errors
273
274
- **Missing packages**: Pre-selected packages not found in packages_map are silently skipped
275
- **Invalid package data**: Malformed package dictionaries may cause processing errors in later stages
276
277
## Integration Points
278
279
### Input from PackagesStatusDetector
280
281
Requires package status map with specific structure:
282
283
```python
284
{
285
'package_name': {
286
'name': str,
287
'current_version': Version,
288
'latest_version': Version,
289
'upgrade_available': bool,
290
'upload_time': str
291
}
292
}
293
```
294
295
### Output to PackagesUpgrader
296
297
Produces list of package dictionaries for upgrade processing:
298
299
```python
300
[
301
{
302
'name': 'django',
303
'current_version': Version('3.2.0'),
304
'latest_version': Version('4.1.0'),
305
'upgrade_available': True,
306
'upload_time': '2022-08-03 08:15:30'
307
}
308
]
309
```