mirror of
https://github.com/httpie/cli.git
synced 2025-02-08 05:39:22 +01:00
WIP
This commit is contained in:
parent
c431ed7728
commit
d12af4a569
@ -15,12 +15,10 @@ from httpie.cli.argtypes import (
|
|||||||
parse_format_options,
|
parse_format_options,
|
||||||
)
|
)
|
||||||
from httpie.cli.constants import (
|
from httpie.cli.constants import (
|
||||||
DEFAULT_FORMAT_OPTIONS, HTTP_GET, HTTP_POST, OUTPUT_OPTIONS,
|
HTTP_GET, HTTP_POST, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT,
|
||||||
OUTPUT_OPTIONS_DEFAULT,
|
OUTPUT_OPTIONS_DEFAULT_OFFLINE, OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED,
|
||||||
OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED, OUT_RESP_BODY, PRETTY_MAP,
|
OUT_RESP_BODY, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SEPARATOR_CREDENTIALS,
|
||||||
PRETTY_STDOUT_TTY_ONLY, SEPARATOR_CREDENTIALS, SEPARATOR_GROUP_ALL_ITEMS,
|
SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_GROUP_DATA_ITEMS, URL_SCHEME_RE,
|
||||||
SEPARATOR_GROUP_DATA_ITEMS, URL_SCHEME_RE,
|
|
||||||
OUTPUT_OPTIONS_DEFAULT_OFFLINE,
|
|
||||||
)
|
)
|
||||||
from httpie.cli.exceptions import ParseError
|
from httpie.cli.exceptions import ParseError
|
||||||
from httpie.cli.requestitems import RequestItems
|
from httpie.cli.requestitems import RequestItems
|
||||||
@ -165,7 +163,8 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
|
|
||||||
if self.args.quiet:
|
if self.args.quiet:
|
||||||
self.env.stderr = self.env.devnull
|
self.env.stderr = self.env.devnull
|
||||||
if not (self.args.output_file_specified and not self.args.download):
|
if not (
|
||||||
|
self.args.output_file_specified and not self.args.download):
|
||||||
self.env.stdout = self.env.devnull
|
self.env.stdout = self.env.devnull
|
||||||
|
|
||||||
def _process_auth(self):
|
def _process_auth(self):
|
||||||
@ -193,8 +192,8 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
plugin = plugin_manager.get_auth_plugin(self.args.auth_type)()
|
plugin = plugin_manager.get_auth_plugin(self.args.auth_type)()
|
||||||
|
|
||||||
if (not self.args.ignore_netrc
|
if (not self.args.ignore_netrc
|
||||||
and self.args.auth is None
|
and self.args.auth is None
|
||||||
and plugin.netrc_parse):
|
and plugin.netrc_parse):
|
||||||
# Only host needed, so it’s OK URL not finalized.
|
# Only host needed, so it’s OK URL not finalized.
|
||||||
netrc_credentials = get_netrc_auth(self.args.url)
|
netrc_credentials = get_netrc_auth(self.args.url)
|
||||||
if netrc_credentials:
|
if netrc_credentials:
|
||||||
@ -222,7 +221,7 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
credentials = parse_auth(self.args.auth)
|
credentials = parse_auth(self.args.auth)
|
||||||
|
|
||||||
if (not credentials.has_password()
|
if (not credentials.has_password()
|
||||||
and plugin.prompt_password):
|
and plugin.prompt_password):
|
||||||
if self.args.ignore_stdin:
|
if self.args.ignore_stdin:
|
||||||
# Non-tty stdin read by now
|
# Non-tty stdin read by now
|
||||||
self.error(
|
self.error(
|
||||||
@ -276,7 +275,13 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
'data (key=value) cannot be mixed. Pass '
|
'data (key=value) cannot be mixed. Pass '
|
||||||
'--ignore-stdin to let key/value take priority. '
|
'--ignore-stdin to let key/value take priority. '
|
||||||
'See https://httpie.org/doc#scripting for details.')
|
'See https://httpie.org/doc#scripting for details.')
|
||||||
self.args.data = getattr(fd, 'buffer', fd).read()
|
buffer = getattr(fd, 'buffer', fd)
|
||||||
|
# if fd is self.env.stdin and not self.args.chunked:
|
||||||
|
# self.args.data = buffer.read()
|
||||||
|
# else:
|
||||||
|
# self.args.data = buffer
|
||||||
|
# print(type(fd))
|
||||||
|
self.args.data = buffer
|
||||||
|
|
||||||
def _guess_method(self):
|
def _guess_method(self):
|
||||||
"""Set `args.method` if not specified to either POST or GET
|
"""Set `args.method` if not specified to either POST or GET
|
||||||
@ -312,8 +317,8 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
has_data = (
|
has_data = (
|
||||||
self.has_stdin_data
|
self.has_stdin_data
|
||||||
or any(
|
or any(
|
||||||
item.sep in SEPARATOR_GROUP_DATA_ITEMS
|
item.sep in SEPARATOR_GROUP_DATA_ITEMS
|
||||||
for item in self.args.request_items)
|
for item in self.args.request_items)
|
||||||
)
|
)
|
||||||
self.args.method = HTTP_POST if has_data else HTTP_GET
|
self.args.method = HTTP_POST if has_data else HTTP_GET
|
||||||
|
|
||||||
@ -416,11 +421,12 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
|||||||
if self.args.download_resume:
|
if self.args.download_resume:
|
||||||
self.error('--continue only works with --download')
|
self.error('--continue only works with --download')
|
||||||
if self.args.download_resume and not (
|
if self.args.download_resume and not (
|
||||||
self.args.download and self.args.output_file):
|
self.args.download and self.args.output_file):
|
||||||
self.error('--continue requires --output to be specified')
|
self.error('--continue requires --output to be specified')
|
||||||
|
|
||||||
def _process_format_options(self):
|
def _process_format_options(self):
|
||||||
parsed_options = PARSED_DEFAULT_FORMAT_OPTIONS
|
parsed_options = PARSED_DEFAULT_FORMAT_OPTIONS
|
||||||
for options_group in self.args.format_options or []:
|
for options_group in self.args.format_options or []:
|
||||||
parsed_options = parse_format_options(options_group, defaults=parsed_options)
|
parsed_options = parse_format_options(options_group,
|
||||||
|
defaults=parsed_options)
|
||||||
self.args.format_options = parsed_options
|
self.args.format_options = parsed_options
|
||||||
|
@ -657,6 +657,15 @@ network.add_argument(
|
|||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
|
|
||||||
|
network.add_argument(
|
||||||
|
'--chunked',
|
||||||
|
default=False,
|
||||||
|
action='store_true',
|
||||||
|
help="""
|
||||||
|
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# SSL
|
# SSL
|
||||||
#######################################################################
|
#######################################################################
|
||||||
|
@ -5,7 +5,7 @@ import sys
|
|||||||
import zlib
|
import zlib
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterable, Union
|
from typing import Callable, Iterable, Union
|
||||||
from urllib.parse import urlparse, urlunparse
|
from urllib.parse import urlparse, urlunparse
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
@ -16,7 +16,10 @@ from httpie.cli.dicts import RequestHeadersDict
|
|||||||
from httpie.plugins.registry import plugin_manager
|
from httpie.plugins.registry import plugin_manager
|
||||||
from httpie.sessions import get_httpie_session
|
from httpie.sessions import get_httpie_session
|
||||||
from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter
|
from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter
|
||||||
from httpie.uploads import get_multipart_data_and_content_type
|
from httpie.uploads import (
|
||||||
|
wrap_request_data,
|
||||||
|
get_multipart_data_and_content_type,
|
||||||
|
)
|
||||||
from httpie.utils import get_expired_cookies, repr_dict
|
from httpie.utils import get_expired_cookies, repr_dict
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +34,7 @@ DEFAULT_UA = f'HTTPie/{__version__}'
|
|||||||
def collect_messages(
|
def collect_messages(
|
||||||
args: argparse.Namespace,
|
args: argparse.Namespace,
|
||||||
config_dir: Path,
|
config_dir: Path,
|
||||||
|
body_chunk_sent_callback: Callable[[bytes], None]=None,
|
||||||
) -> Iterable[Union[requests.PreparedRequest, requests.Response]]:
|
) -> Iterable[Union[requests.PreparedRequest, requests.Response]]:
|
||||||
httpie_session = None
|
httpie_session = None
|
||||||
httpie_session_headers = None
|
httpie_session_headers = None
|
||||||
@ -46,6 +50,7 @@ def collect_messages(
|
|||||||
request_kwargs = make_request_kwargs(
|
request_kwargs = make_request_kwargs(
|
||||||
args=args,
|
args=args,
|
||||||
base_headers=httpie_session_headers,
|
base_headers=httpie_session_headers,
|
||||||
|
callback=body_chunk_sent_callback
|
||||||
)
|
)
|
||||||
send_kwargs = make_send_kwargs(args)
|
send_kwargs = make_send_kwargs(args)
|
||||||
send_kwargs_mergeable_from_env = make_send_kwargs_mergeable_from_env(args)
|
send_kwargs_mergeable_from_env = make_send_kwargs_mergeable_from_env(args)
|
||||||
@ -251,7 +256,8 @@ def make_send_kwargs_mergeable_from_env(args: argparse.Namespace) -> dict:
|
|||||||
|
|
||||||
def make_request_kwargs(
|
def make_request_kwargs(
|
||||||
args: argparse.Namespace,
|
args: argparse.Namespace,
|
||||||
base_headers: RequestHeadersDict = None
|
base_headers: RequestHeadersDict = None,
|
||||||
|
callback=lambda chunk: chunk
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""
|
"""
|
||||||
Translate our `args` into `requests.Request` keyword arguments.
|
Translate our `args` into `requests.Request` keyword arguments.
|
||||||
@ -289,7 +295,7 @@ def make_request_kwargs(
|
|||||||
'method': args.method.lower(),
|
'method': args.method.lower(),
|
||||||
'url': args.url,
|
'url': args.url,
|
||||||
'headers': headers,
|
'headers': headers,
|
||||||
'data': data,
|
'data': wrap_request_data(data, callback=callback),
|
||||||
'auth': args.auth,
|
'auth': args.auth,
|
||||||
'params': args.params,
|
'params': args.params,
|
||||||
'files': files,
|
'files': files,
|
||||||
|
@ -9,6 +9,10 @@ from pygments import __version__ as pygments_version
|
|||||||
from requests import __version__ as requests_version
|
from requests import __version__ as requests_version
|
||||||
|
|
||||||
from httpie import __version__ as httpie_version
|
from httpie import __version__ as httpie_version
|
||||||
|
from httpie.cli.constants import (
|
||||||
|
OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY,
|
||||||
|
OUT_RESP_HEAD,
|
||||||
|
)
|
||||||
from httpie.client import collect_messages
|
from httpie.client import collect_messages
|
||||||
from httpie.context import Environment
|
from httpie.context import Environment
|
||||||
from httpie.downloads import Downloader
|
from httpie.downloads import Downloader
|
||||||
@ -111,6 +115,22 @@ def main(
|
|||||||
return exit_status
|
return exit_status
|
||||||
|
|
||||||
|
|
||||||
|
def get_output_options(
|
||||||
|
args: argparse.Namespace,
|
||||||
|
message: Union[requests.PreparedRequest, requests.Response]
|
||||||
|
) -> dict:
|
||||||
|
return {
|
||||||
|
requests.PreparedRequest: {
|
||||||
|
'with_headers': OUT_REQ_HEAD in args.output_options,
|
||||||
|
'with_body': OUT_REQ_BODY in args.output_options,
|
||||||
|
},
|
||||||
|
requests.Response: {
|
||||||
|
'with_headers': OUT_RESP_HEAD in args.output_options,
|
||||||
|
'with_body': OUT_RESP_BODY in args.output_options,
|
||||||
|
},
|
||||||
|
}[type(message)]
|
||||||
|
|
||||||
|
|
||||||
def program(
|
def program(
|
||||||
args: argparse.Namespace,
|
args: argparse.Namespace,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -135,15 +155,36 @@ def program(
|
|||||||
initial_request = None
|
initial_request = None
|
||||||
final_response = None
|
final_response = None
|
||||||
|
|
||||||
for message in collect_messages(args, env.config.directory):
|
def upload_callback(chunk):
|
||||||
write_message(
|
print('GOT', chunk)
|
||||||
requests_message=message,
|
|
||||||
env=env,
|
messages = collect_messages(
|
||||||
args=args,
|
args=args,
|
||||||
)
|
config_dir=env.config.directory,
|
||||||
if isinstance(message, requests.PreparedRequest):
|
body_chunk_sent_callback=upload_callback
|
||||||
|
)
|
||||||
|
for message in messages:
|
||||||
|
is_request = isinstance(message, requests.PreparedRequest)
|
||||||
|
output_options = get_output_options(args=args, message=message)
|
||||||
|
if not is_request or not output_options['with_body']:
|
||||||
|
write_message(
|
||||||
|
requests_message=message,
|
||||||
|
env=env,
|
||||||
|
args=args,
|
||||||
|
**output_options,
|
||||||
|
)
|
||||||
|
if is_request:
|
||||||
if not initial_request:
|
if not initial_request:
|
||||||
initial_request = message
|
initial_request = message
|
||||||
|
if 0and not args.offline:
|
||||||
|
output_options['with_body'] = False
|
||||||
|
write_message(
|
||||||
|
requests_message=message,
|
||||||
|
env=env,
|
||||||
|
args=args,
|
||||||
|
**output_options,
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
final_response = message
|
final_response = message
|
||||||
if args.check_status or downloader:
|
if args.check_status or downloader:
|
||||||
|
@ -23,6 +23,13 @@ LARGE_UPLOAD_SUPPRESSED_NOTICE = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def might_suppress(chunk):
|
||||||
|
if isinstance(chunk, MultipartEncoder):
|
||||||
|
raise LargeUploadSuppressedError()
|
||||||
|
# if isinstance(io.IOBase):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
|
||||||
class DataSuppressedError(Exception):
|
class DataSuppressedError(Exception):
|
||||||
message = None
|
message = None
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import errno
|
import errno
|
||||||
from typing import Union, IO, TextIO, Tuple, Type
|
from typing import IO, TextIO, Tuple, Type, Union
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@ -8,12 +8,7 @@ from httpie.context import Environment
|
|||||||
from httpie.models import HTTPRequest, HTTPResponse
|
from httpie.models import HTTPRequest, HTTPResponse
|
||||||
from httpie.output.processing import Conversion, Formatting
|
from httpie.output.processing import Conversion, Formatting
|
||||||
from httpie.output.streams import (
|
from httpie.output.streams import (
|
||||||
RawStream, PrettyStream,
|
BaseStream, BufferedPrettyStream, EncodedStream, PrettyStream, RawStream,
|
||||||
BufferedPrettyStream, EncodedStream,
|
|
||||||
BaseStream,
|
|
||||||
)
|
|
||||||
from httpie.cli.constants import (
|
|
||||||
OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -21,26 +16,18 @@ def write_message(
|
|||||||
requests_message: Union[requests.PreparedRequest, requests.Response],
|
requests_message: Union[requests.PreparedRequest, requests.Response],
|
||||||
env: Environment,
|
env: Environment,
|
||||||
args: argparse.Namespace,
|
args: argparse.Namespace,
|
||||||
|
with_headers=False,
|
||||||
|
with_body=False,
|
||||||
):
|
):
|
||||||
output_options_by_message_type = {
|
if not (with_body or with_headers):
|
||||||
requests.PreparedRequest: {
|
|
||||||
'with_headers': OUT_REQ_HEAD in args.output_options,
|
|
||||||
'with_body': OUT_REQ_BODY in args.output_options,
|
|
||||||
},
|
|
||||||
requests.Response: {
|
|
||||||
'with_headers': OUT_RESP_HEAD in args.output_options,
|
|
||||||
'with_body': OUT_RESP_BODY in args.output_options,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
output_options = output_options_by_message_type[type(requests_message)]
|
|
||||||
if not any(output_options.values()):
|
|
||||||
return
|
return
|
||||||
write_stream_kwargs = {
|
write_stream_kwargs = {
|
||||||
'stream': build_output_stream_for_message(
|
'stream': build_output_stream_for_message(
|
||||||
args=args,
|
args=args,
|
||||||
env=env,
|
env=env,
|
||||||
requests_message=requests_message,
|
requests_message=requests_message,
|
||||||
**output_options,
|
with_body=with_body,
|
||||||
|
with_headers=with_headers,
|
||||||
),
|
),
|
||||||
# NOTE: `env.stdout` will in fact be `stderr` with `--download`
|
# NOTE: `env.stdout` will in fact be `stderr` with `--download`
|
||||||
'outfile': env.stdout,
|
'outfile': env.stdout,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from typing import Tuple, Union
|
from typing import Tuple, Union
|
||||||
|
|
||||||
|
from requests.utils import super_len
|
||||||
from requests_toolbelt import MultipartEncoder
|
from requests_toolbelt import MultipartEncoder
|
||||||
|
|
||||||
from httpie.cli.dicts import RequestDataDict, RequestFilesDict
|
from httpie.cli.dicts import RequestDataDict, RequestFilesDict
|
||||||
@ -28,5 +29,40 @@ def get_multipart_data_and_content_type(
|
|||||||
else:
|
else:
|
||||||
content_type = encoder.content_type
|
content_type = encoder.content_type
|
||||||
|
|
||||||
data = encoder.to_string() if encoder.len < UPLOAD_BUFFER else encoder
|
data = encoder.to_string() if 0 and encoder.len < UPLOAD_BUFFER else encoder
|
||||||
return data, content_type
|
return data, content_type
|
||||||
|
|
||||||
|
|
||||||
|
class Stdin:
|
||||||
|
|
||||||
|
def __init__(self, stdin, callback):
|
||||||
|
self.callback = callback
|
||||||
|
self.stdin = stdin
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for chunk in self.stdin:
|
||||||
|
print("__iter__() =>", chunk)
|
||||||
|
self.callback(chunk)
|
||||||
|
yield chunk
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_stdin(cls, obj):
|
||||||
|
return super_len(obj) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_request_data(data, callback=lambda chunk: print('chunk', chunk)):
|
||||||
|
if hasattr(data, 'read'):
|
||||||
|
if Stdin.is_stdin(data):
|
||||||
|
data = Stdin(data, callback=callback)
|
||||||
|
else:
|
||||||
|
orig_read = data.read
|
||||||
|
|
||||||
|
def new_read(*args):
|
||||||
|
val = orig_read(*args)
|
||||||
|
print('read() =>', val)
|
||||||
|
callback(callback)
|
||||||
|
return val
|
||||||
|
|
||||||
|
data.read = new_read
|
||||||
|
|
||||||
|
return data
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"""High-level tests."""
|
"""High-level tests."""
|
||||||
import io
|
import io
|
||||||
|
import sys
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
Loading…
Reference in New Issue
Block a user