Skip to content

Commit 8497692

Browse files
committed
Add shell completion support via argcomplete
1 parent 28d11b2 commit 8497692

File tree

2 files changed

+57
-32
lines changed

2 files changed

+57
-32
lines changed

httpie/cli/definition.py

+53-30
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@
6666
$ http example.org hello=world # => POST
6767
6868
""",
69-
).completer = ChoicesCompleter(
70-
('GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'))
69+
completer=ChoicesCompleter(('GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'))
70+
)
7171
positional_arguments.add_argument(
7272
dest='url',
7373
metavar='URL',
@@ -82,7 +82,8 @@
8282
$ http :/foo # => http://localhost/foo
8383
8484
""",
85-
).completer = ChoicesCompleter(())
85+
completer=ChoicesCompleter(()),
86+
)
8687
positional_arguments.add_argument(
8788
dest='request_items',
8889
metavar='REQUEST_ITEM',
@@ -139,7 +140,8 @@
139140
field-name-with\:colon=value
140141
141142
""",
142-
).completer = ChoicesCompleter(())
143+
completer=ChoicesCompleter(()),
144+
)
143145

144146
#######################################################################
145147
# Content type.
@@ -192,8 +194,9 @@
192194
short_help=(
193195
'Specify a custom boundary string for multipart/form-data requests. '
194196
'Only has effect only together with --form.'
195-
)
196-
).completer = ChoicesCompleter(())
197+
),
198+
completer=ChoicesCompleter(()),
199+
)
197200
content_types.add_argument(
198201
'--raw',
199202
short_help='Pass raw request data without extra processing.',
@@ -354,7 +357,8 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
354357
--response-charset=big5
355358
356359
""",
357-
).completer = ChoicesCompleter(())
360+
completer=ChoicesCompleter(()),
361+
)
358362
output_processing.add_argument(
359363
'--response-mime',
360364
metavar='MIME_TYPE',
@@ -367,7 +371,8 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
367371
--response-mime=text/xml
368372
369373
""",
370-
).completer = ChoicesCompleter(())
374+
completer=ChoicesCompleter(()),
375+
)
371376
output_processing.add_argument(
372377
'--format-options',
373378
action='append',
@@ -392,7 +397,8 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
392397
f' {option}' for option in DEFAULT_FORMAT_OPTIONS
393398
).strip()
394399
),
395-
).completer = ChoicesCompleter(())
400+
completer=ChoicesCompleter(()),
401+
)
396402

397403
#######################################################################
398404
# Output options
@@ -421,7 +427,8 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
421427
response body is printed by default.
422428
423429
""",
424-
).completer = ChoicesCompleter(())
430+
completer=ChoicesCompleter(()),
431+
)
425432
output_options.add_argument(
426433
'--headers',
427434
'-h',
@@ -495,7 +502,8 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
495502
dest='output_options_history',
496503
metavar='WHAT',
497504
help=Qualifiers.SUPPRESS,
498-
).completer = ChoicesCompleter(())
505+
completer=ChoicesCompleter(()),
506+
)
499507
output_options.add_argument(
500508
'--stream',
501509
'-S',
@@ -529,7 +537,8 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
529537
printed to stderr.
530538
531539
""",
532-
).completer = FilesCompleter()
540+
completer=FilesCompleter(),
541+
)
533542

534543
output_options.add_argument(
535544
'--download',
@@ -600,7 +609,8 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
600609
601610
https://httpie.io/docs/cli/config-file-directory
602611
""",
603-
).completer = FilesCompleter(('json',))
612+
completer=FilesCompleter(('json',)),
613+
)
604614
sessions.add_argument(
605615
'--session-read-only',
606616
metavar='SESSION_NAME_OR_PATH',
@@ -611,7 +621,8 @@ def format_style_help(available_styles, *, isolation_mode: bool = False):
611621
exchange.
612622
613623
""",
614-
).completer = FilesCompleter(('json',))
624+
completer=FilesCompleter(('json',)),
625+
)
615626

616627
#######################################################################
617628
# Authentication
@@ -675,7 +686,8 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
675686
(-a username), HTTPie will prompt for the password.
676687
677688
""",
678-
).completer = ChoicesCompleter(())
689+
completer=ChoicesCompleter(()),
690+
)
679691
authentication.add_argument(
680692
'--auth-type',
681693
'-A',
@@ -686,7 +698,7 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
686698
cache=False,
687699
short_help='The authentication mechanism to be used.',
688700
help_formatter=format_auth_help,
689-
).completer = ChoicesCompleter(())
701+
)
690702
authentication.add_argument(
691703
'--ignore-netrc',
692704
default=False,
@@ -720,7 +732,8 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
720732
and $HTTPS_proxy are supported as well.
721733
722734
""",
723-
).completer = ChoicesCompleter(())
735+
completer=ChoicesCompleter(()),
736+
)
724737
network.add_argument(
725738
'--follow',
726739
'-F',
@@ -738,16 +751,18 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
738751
By default, requests have a limit of 30 redirects (works with --follow).
739752
740753
""",
741-
).completer = ChoicesCompleter(())
754+
completer=ChoicesCompleter(()),
755+
)
742756
network.add_argument(
743757
'--max-headers',
744758
type=int,
745759
default=0,
746760
short_help=(
747761
'The maximum number of response headers to be read before '
748762
'giving up (default 0, i.e., no limit).'
749-
)
750-
).completer = ChoicesCompleter(())
763+
),
764+
completer=ChoicesCompleter(()),
765+
)
751766

752767
network.add_argument(
753768
'--timeout',
@@ -764,7 +779,8 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
764779
the underlying socket for timeout seconds).
765780
766781
""",
767-
).completer = ChoicesCompleter(())
782+
completer=ChoicesCompleter(()),
783+
)
768784
network.add_argument(
769785
'--check-status',
770786
default=False,
@@ -814,7 +830,8 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
814830
for private certs. (Or you can set the REQUESTS_CA_BUNDLE environment
815831
variable instead.)
816832
""",
817-
).completer = ChoicesCompleter(('yes', 'no'))
833+
completer=ChoicesCompleter(('yes', 'no')),
834+
)
818835
ssl.add_argument(
819836
'--ssl',
820837
dest='ssl_version',
@@ -828,7 +845,8 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
828845
are shown here).
829846
830847
""",
831-
).completer = ChoicesCompleter(())
848+
completer=ChoicesCompleter(()),
849+
)
832850
ssl.add_argument(
833851
'--ciphers',
834852
short_help='A string in the OpenSSL cipher list format.',
@@ -840,7 +858,8 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
840858
{DEFAULT_SSL_CIPHERS}
841859
842860
""",
843-
).completer = ChoicesCompleter(())
861+
completer=ChoicesCompleter(()),
862+
)
844863
ssl.add_argument(
845864
'--cert',
846865
default=None,
@@ -852,7 +871,8 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
852871
specify --cert-key separately.
853872
854873
""",
855-
).completer = FilesCompleter(('crt', 'cert', 'pem'))
874+
completer=FilesCompleter(('crt', 'cert', 'pem')),
875+
)
856876
ssl.add_argument(
857877
'--cert-key',
858878
default=None,
@@ -863,7 +883,8 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
863883
certificate file does not contain the private key.
864884
865885
""",
866-
).completer = FilesCompleter(('key', 'pem'))
886+
completer=FilesCompleter(('key', 'pem')),
887+
)
867888

868889
ssl.add_argument(
869890
'--cert-key-pass',
@@ -874,8 +895,9 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
874895
The passphrase to be used to with the given private key. Only needed if --cert-key
875896
is given and the key file requires a passphrase.
876897
If not provided, you’ll be prompted interactively.
877-
"""
878-
).completer = ChoicesCompleter(())
898+
""",
899+
completer=ChoicesCompleter(()),
900+
)
879901

880902
#######################################################################
881903
# Troubleshooting
@@ -916,8 +938,9 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False):
916938
troubleshooting.add_argument(
917939
'--default-scheme',
918940
default='http',
919-
short_help='The default scheme to use if not specified in the URL.'
920-
).completer = ChoicesCompleter(('http', 'https'))
941+
short_help='The default scheme to use if not specified in the URL.',
942+
completer=ChoicesCompleter(('http', 'https')),
943+
)
921944
troubleshooting.add_argument(
922945
'--debug',
923946
action='store_true',

httpie/cli/options.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def __getattr__(self, attribute_name):
187187
Qualifiers.ZERO_OR_MORE: argparse.ZERO_OR_MORE,
188188
Qualifiers.ONE_OR_MORE: argparse.ONE_OR_MORE
189189
}
190-
ARGPARSE_IGNORE_KEYS = ('short_help', 'nested_options')
190+
ARGPARSE_IGNORE_KEYS = ('short_help', 'nested_options', 'completer')
191191

192192

193193
def to_argparse(
@@ -211,12 +211,14 @@ def to_argparse(
211211
concrete_group = concrete_group.add_mutually_exclusive_group(required=False)
212212

213213
for abstract_argument in abstract_group.arguments:
214-
concrete_group.add_argument(
214+
argument = concrete_group.add_argument(
215215
*abstract_argument.aliases,
216216
**drop_keys(map_qualifiers(
217217
abstract_argument.configuration, ARGPARSE_QUALIFIER_MAP
218218
), ARGPARSE_IGNORE_KEYS)
219219
)
220+
if 'completer' in abstract_argument.configuration:
221+
argument.completer = abstract_argument.configuration['completer']
220222

221223
return concrete_parser
222224

0 commit comments

Comments
 (0)