@@ -156,8 +156,12 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens)
156
156
2 Another item False
157
157
3 Yet another item False
158
158
159
- To use CompletionItems, just return them from your choices or completer
160
- functions.
159
+ To use CompletionItems, just return them from your choices_provider or
160
+ completer functions. They can also be used as argparse choices. When a
161
+ CompletionItem is created, it stores the original value (e.g. ID number) and
162
+ makes it accessible through a property called orig_value. cmd2 has patched
163
+ argparse so that when evaluating choices, input is compared to
164
+ CompletionItem.orig_value instead of the CompletionItem instance.
161
165
162
166
To avoid printing a ton of information to the screen at once when a user
163
167
presses tab, there is a maximum threshold for the number of CompletionItems
@@ -173,6 +177,12 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens)
173
177
completion and enables nargs range parsing. See _add_argument_wrapper for
174
178
more details on these arguments.
175
179
180
+ ``argparse.ArgumentParser._check_value`` - adds support for using
181
+ ``CompletionItems`` as argparse choices. When evaluating choices, input is
182
+ compared to ``CompletionItem.orig_value`` instead of the ``CompletionItem``
183
+ instance.
184
+ See _ArgumentParser_check_value for more details.
185
+
176
186
``argparse.ArgumentParser._get_nargs_pattern`` - adds support for nargs ranges.
177
187
See _get_nargs_pattern_wrapper for more details.
178
188
@@ -308,17 +318,26 @@ def __new__(cls, value: object, *args: Any, **kwargs: Any) -> 'CompletionItem':
308
318
return super (CompletionItem , cls ).__new__ (cls , value )
309
319
310
320
# noinspection PyUnusedLocal
311
- def __init__ (self , value : object , desc : str = '' , * args : Any ) -> None :
321
+ def __init__ (self , value : object , description : str = '' , * args : Any ) -> None :
312
322
"""
313
323
CompletionItem Initializer
314
324
315
325
:param value: the value being tab completed
316
- :param desc : description text to display
326
+ :param description : description text to display
317
327
:param args: args for str __init__
318
328
:param kwargs: kwargs for str __init__
319
329
"""
320
330
super ().__init__ (* args )
321
- self .description = desc
331
+ self .description = description
332
+
333
+ # Save the original value to support CompletionItems as argparse choices.
334
+ # cmd2 has patched argparse so input is compared to this value instead of the CompletionItem instance.
335
+ self .__orig_value = value
336
+
337
+ @property
338
+ def orig_value (self ) -> Any :
339
+ """Read-only property for __orig_value"""
340
+ return self .__orig_value
322
341
323
342
324
343
############################################################################################################
@@ -870,7 +889,7 @@ def _add_argument_wrapper(
870
889
setattr (argparse ._ActionsContainer , 'add_argument' , _add_argument_wrapper )
871
890
872
891
############################################################################################################
873
- # Patch ArgumentParser._get_nargs_pattern with our wrapper to nargs ranges
892
+ # Patch ArgumentParser._get_nargs_pattern with our wrapper to support nargs ranges
874
893
############################################################################################################
875
894
876
895
# Save original ArgumentParser._get_nargs_pattern so we can call it in our wrapper
@@ -905,7 +924,7 @@ def _get_nargs_pattern_wrapper(self: argparse.ArgumentParser, action: argparse.A
905
924
906
925
907
926
############################################################################################################
908
- # Patch ArgumentParser._match_argument with our wrapper to nargs ranges
927
+ # Patch ArgumentParser._match_argument with our wrapper to support nargs ranges
909
928
############################################################################################################
910
929
# noinspection PyProtectedMember
911
930
orig_argument_parser_match_argument = argparse .ArgumentParser ._match_argument
@@ -977,6 +996,38 @@ def _ArgumentParser_set_ap_completer_type(self: argparse.ArgumentParser, ap_comp
977
996
setattr (argparse .ArgumentParser , 'set_ap_completer_type' , _ArgumentParser_set_ap_completer_type )
978
997
979
998
999
+ ############################################################################################################
1000
+ # Patch ArgumentParser._check_value to support CompletionItems as choices
1001
+ ############################################################################################################
1002
+ # noinspection PyPep8Naming
1003
+ def _ArgumentParser_check_value (self : argparse .ArgumentParser , action : argparse .Action , value : Any ) -> None :
1004
+ """
1005
+ Custom override of ArgumentParser._check_value that supports CompletionItems as choices.
1006
+ When evaluating choices, input is compared to CompletionItem.orig_value instead of the
1007
+ CompletionItem instance.
1008
+
1009
+ :param self: ArgumentParser instance
1010
+ :param action: the action being populated
1011
+ :param value: value from command line already run through conversion function by argparse
1012
+ """
1013
+ # Import gettext like argparse does
1014
+ from gettext import (
1015
+ gettext as _ ,
1016
+ )
1017
+
1018
+ # converted value must be one of the choices (if specified)
1019
+ if action .choices is not None :
1020
+ # If any choice is a CompletionItem, then use its orig_value property.
1021
+ choices = [c .orig_value if isinstance (c , CompletionItem ) else c for c in action .choices ]
1022
+ if value not in choices :
1023
+ args = {'value' : value , 'choices' : ', ' .join (map (repr , choices ))}
1024
+ msg = _ ('invalid choice: %(value)r (choose from %(choices)s)' )
1025
+ raise ArgumentError (action , msg % args )
1026
+
1027
+
1028
+ setattr (argparse .ArgumentParser , '_check_value' , _ArgumentParser_check_value )
1029
+
1030
+
980
1031
############################################################################################################
981
1032
# Patch argparse._SubParsersAction to add remove_parser function
982
1033
############################################################################################################
0 commit comments