Skip to content

Commit

Permalink
Added --unsorted
Browse files Browse the repository at this point in the history
It acts as a shortcut for --format-options=json.sort_keys:false,headers.sort:false

#128
  • Loading branch information
jkbrzt committed Jun 16, 2020
1 parent b865988 commit 8264899
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.

* Fixed built-in plugins-related circular imports (`#925`_).
* Added ``--format-options`` to allow disabling sorting, etc. (`#128`_)
* Added ``--unsorted`` shortcut to set all sorting-related ``--format-options`` to ``false``. (`#128`_)
* Added ``--ciphers`` to allow configuring OpenSSL ciphers (`#870`_).
* Added support for ``$XDG_CONFIG_HOME`` (`#920`_).
* Added support for custom content types for uploaded files (`#668`_).
Expand Down
18 changes: 16 additions & 2 deletions httpie/cli/argparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@

from requests.utils import get_netrc_auth

from httpie.cli.argtypes import AuthCredentials, KeyValueArgType, parse_auth
from httpie.cli.argtypes import (
AuthCredentials, KeyValueArgType, PARSED_DEFAULT_FORMAT_OPTIONS,
parse_auth,
parse_format_options,
)
from httpie.cli.constants import (
HTTP_GET, HTTP_POST, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT,
DEFAULT_FORMAT_OPTIONS, HTTP_GET, HTTP_POST, OUTPUT_OPTIONS,
OUTPUT_OPTIONS_DEFAULT,
OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED, OUT_RESP_BODY, PRETTY_MAP,
PRETTY_STDOUT_TTY_ONLY, SEPARATOR_CREDENTIALS, SEPARATOR_GROUP_ALL_ITEMS,
SEPARATOR_GROUP_DATA_ITEMS, URL_SCHEME_RE,
Expand Down Expand Up @@ -44,6 +49,8 @@ def _split_lines(self, text, width):
return text.splitlines()


# TODO: refactor and design type-annotated data structures
# for raw args + parsed args and keep things immutable.
class HTTPieArgumentParser(argparse.ArgumentParser):
"""Adds additional logic to `argparse.ArgumentParser`.
Expand Down Expand Up @@ -84,6 +91,7 @@ def parse_args(
self._setup_standard_streams()
self._process_output_options()
self._process_pretty_options()
self._process_format_options()
self._guess_method()
self._parse_items()

Expand Down Expand Up @@ -405,3 +413,9 @@ def _process_download_options(self):
if self.args.download_resume and not (
self.args.download and self.args.output_file):
self.error('--continue requires --output to be specified')

def _process_format_options(self):
parsed_options = PARSED_DEFAULT_FORMAT_OPTIONS
for options_group in self.args.format_options:
parsed_options = parse_format_options(options_group, defaults=parsed_options)
self.args.format_options = parsed_options
6 changes: 6 additions & 0 deletions httpie/cli/argtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,9 @@ def parse_format_options(s: str, defaults: Optional[dict]) -> dict:
s=','.join(DEFAULT_FORMAT_OPTIONS),
defaults=None,
)


class UnsortedAction(argparse.Action):

def __call__(self, *args, **kwargs):
return 1
5 changes: 4 additions & 1 deletion httpie/cli/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@
'json.indent:4',
'json.sort_keys:true',
]

UNSORTED_FORMAT_OPTIONS = [
'headers.sort:false',
'json.sort_keys:false',
]

# Defaults
OUTPUT_OPTIONS_DEFAULT = OUT_RESP_HEAD + OUT_RESP_BODY
Expand Down
28 changes: 18 additions & 10 deletions httpie/cli/definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
from httpie.cli.argparser import HTTPieArgumentParser
from httpie.cli.argtypes import (
KeyValueArgType, PARSED_DEFAULT_FORMAT_OPTIONS, SessionNameValidator,
parse_format_options,
readable_file_arg,
)
from httpie.cli.constants import (
DEFAULT_FORMAT_OPTIONS, OUTPUT_OPTIONS,
OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD,
OUT_RESP_BODY, OUT_RESP_HEAD, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY,
SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY,
SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, UNSORTED_FORMAT_OPTIONS,
)
from httpie.output.formatters.colors import (
AUTO_STYLE, AVAILABLE_STYLES, DEFAULT_STYLE,
Expand Down Expand Up @@ -229,25 +228,34 @@
auto_style=AUTO_STYLE,
)
)
output_processing.add_argument(
'--unsorted',
action='append_const',
const=','.join(UNSORTED_FORMAT_OPTIONS),
dest='format_options',
help="""
Disables all sorting while formatting output. It is a shortcut for:
--format-options=json.sort_keys:false,headers.sort:false
"""
)
output_processing.add_argument(
'--format-options',
type=lambda s: parse_format_options(
s=s,
defaults=PARSED_DEFAULT_FORMAT_OPTIONS
),
default=PARSED_DEFAULT_FORMAT_OPTIONS,
default=[],
action='append',
help="""
Controls output formatting. Only relevant when formatting is enabled
through (explicit or implied) --pretty=all or --pretty=format.
The following are the default options:
{option_list}
You can specify multiple comma-separated options. For example, this modifies
the settings to disable the sorting of JSON keys and headers:
You may use this option multiple times, as well as specify multiple
comma-separated options at the same time. For example, this modifies the
settings to disable the sorting of JSON keys, and sets the indent size to 2:
--format-options json.sort_keys:false,headers.sort:false
--format-options json.sort_keys:false,json.indent:2
This is something you will typically put into your config file.
Expand Down
59 changes: 58 additions & 1 deletion tests/test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

import pytest

from httpie.cli.argtypes import parse_format_options
from httpie.cli.constants import DEFAULT_FORMAT_OPTIONS
from httpie.cli.definition import parser
from httpie.cli.argtypes import (
PARSED_DEFAULT_FORMAT_OPTIONS,
parse_format_options,
)
from httpie.output.formatters.colors import get_lexer
from httpie.status import ExitStatus
from utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http
Expand Down Expand Up @@ -249,3 +254,55 @@ def test_parse_format_options_errors(self, options_string, expected_error):
}
with pytest.raises(argparse.ArgumentTypeError, match=expected_error):
parse_format_options(s=options_string, defaults=defaults)

@pytest.mark.parametrize(
argnames=['args', 'expected_format_options'],
argvalues=[
(
[
'--format-options',
'headers.sort:false,json.sort_keys:false',
'--format-options=json.indent:10'
],
{
'headers': {'sort': False},
'json': {'sort_keys': False, 'indent': 10, 'format': True},
}
),
(
[
'--unsorted'
],
{
'headers': {'sort': False},
'json': {'sort_keys': False, 'indent': 4, 'format': True},
}
),
(
[
'--format-options=headers.sort:true',
'--unsorted',
'--format-options=headers.sort:true',
],
{
'headers': {'sort': True},
'json': {'sort_keys': False, 'indent': 4, 'format': True},
}
),
(
[
'--no-format-options', # --no-<option> anywhere resets
'--format-options=headers.sort:true',
'--unsorted',
'--format-options=headers.sort:true',
],
PARSED_DEFAULT_FORMAT_OPTIONS,
),
],
)
def test_format_options_accumulation(self, args, expected_format_options):
parsed_args = parser.parse_args(
args=[*args, 'example.org'],
env=MockEnvironment(),
)
assert parsed_args.format_options == expected_format_options

0 comments on commit 8264899

Please sign in to comment.