Compare commits

...

30 Commits
0.7.0 ... 0.8.0

Author SHA1 Message Date
43cc3e7ddb Fixed changelog link. 2014-01-25 15:15:16 +01:00
f1224da526 v0.8.0 2014-01-25 15:11:38 +01:00
e0cc63c7eb Cleanup 2014-01-25 15:09:28 +01:00
52dd6adaa3 Updated README. 2014-01-25 15:04:15 +01:00
1aa77017d5 Catch UnicodeDecodeError when embedding file via =@ or :=@. 2014-01-25 14:57:19 +01:00
748a0a480d Update README.rst 2014-01-17 08:57:05 +01:00
01df344a07 Update README.rst 2014-01-17 08:56:24 +01:00
b1074ccb4f Merge pull request #191 from solidsnack/wip-no-auth-in-host-header
Expunge user:pass@... from Host header.
2014-01-08 02:28:19 -08:00
7a84163d1c Merge pull request #192 from thomasleveil/patch-1
fix typo
2014-01-08 02:27:29 -08:00
a31d552d1c fix typo 2014-01-07 14:04:13 +01:00
5a037b2e13 Expunge user:pass@... from Host header.
In verbose mode, the basic auth user and password would show up in colored
output reporting the Host header, as reported in
https://github.com/jkbr/httpie/issues/169
2014-01-06 19:12:33 +00:00
6af42b1827 Added Bitdeli badge. 2013-12-08 11:38:26 +01:00
0e267d8efa Added a link to the httpie-negotiate auth plugin by @ndzou II. 2013-10-09 23:46:55 +02:00
927acc283e Added a link to the httpie-negotiate auth plugin by @ndzou. 2013-10-09 23:44:55 +02:00
817165f5ff Merge pull request #171 from nlf/master
Allow :port style shorthand for localhost.
2013-10-09 13:22:30 -07:00
4fe3deb9d9 add self to authors, update changelog, and mention shorthand in --help output 2013-10-09 13:21:14 -07:00
9034546b80 tweak readme more 2013-10-09 11:37:05 -07:00
2c12fd99f9 tweak readme more 2013-10-09 11:36:01 -07:00
70eb97dece tweak readme to show http requests 2013-10-09 11:34:22 -07:00
8a52bef559 make shorthand parsing more robust, add unit tests and documentation 2013-10-09 11:32:41 -07:00
711168a899 allow :port style shorthand 2013-10-08 22:41:38 -07:00
81c99886fd Update --proxy examples to include URLs to work with Requests v2.0.0.. 2013-09-25 22:02:29 +02:00
2e535d8345 Fixed password prompt. 2013-09-25 00:17:50 +02:00
0bcd4d2fb0 Fixed a bytes/str issue for Python 3. 2013-09-25 00:00:17 +02:00
d5bc564e4f Allow embeding text (=@) and JSON (:=@) files content into request data fields. 2013-09-24 23:41:18 +02:00
54c5c3d82b 0.7.1 2013-09-24 21:57:29 +02:00
2a6514eb5d Update to requests 2.0.0
Closes #140.
2013-09-24 21:49:43 +02:00
22c2cc6465 Removed unused import. 2013-09-24 20:30:54 +02:00
2265edf05e Cleanup 2013-09-24 20:15:19 +02:00
87774acf5c Changelog 2013-09-24 20:09:23 +02:00
10 changed files with 265 additions and 82 deletions

View File

@ -29,3 +29,4 @@ Patches and ideas
* `Davey Shafik <https://github.com/dshafik>`_
* `cido <https://github.com/cido>`_
* `Justin Bonnar <https://github.com/jargonjustin>`_
* `Nathan LaFreniere <https://github.com/nlf>`_

View File

@ -121,7 +121,6 @@ See also ``http --help``.
Examples
--------
Custom `HTTP method`_, `HTTP headers`_ and `JSON`_ data:
.. code-block:: bash
@ -226,6 +225,42 @@ The only information HTTPie needs to perform a request is a URL.
The default scheme is, somewhat unsurprisingly, ``http://``,
and can be omitted from the argument ``http example.org`` works just fine.
Additionally, curl-like shorthand for localhost is supported.
This means that, for example ``:3000`` would expand to ``http://localhost:3000``
If the port is omitted, then port 80 is assumed.
.. code-block:: bash
$ http :/foo
.. code-block:: http
GET /foo HTTP/1.1
Host: localhost
.. code-block:: bash
$ http :3000/bar
.. code-block:: http
GET /bar HTTP/1.1
Host: localhost:3000
.. code-block:: bash
$ http :
.. code-block:: http
GET / HTTP/1.1
Host: localhost
If find yourself manually constructing URLs with **querystring parameters**
on the terminal, you may appreciate the ``param==value`` syntax for appending
URL parameters so that you don't have to worry about escaping the ``&``
@ -246,14 +281,15 @@ command:
Request Items
=============
There are five different *request item* types that provide a
There are a few different *request item* types that provide a
convenient mechanism for specifying HTTP headers, simple JSON and
form data, files, and URL parameters.
They are key/value pairs specified after the URL. All have in
common that they become part of the actual request that is sent and that
their type is distinguished only by the separator used:
``:``, ``=``, ``:=``, ``@``, and ``==``.
``:``, ``=``, ``:=``, ``==``, ``@``, ``=@``, and ``:=@``. The ones with an
``@`` expect a file path as value.
+-----------------------+-----------------------------------------------------+
| Item Type | Description |
@ -266,16 +302,16 @@ their type is distinguished only by the separator used:
| | The ``==`` separator is used |
+-----------------------+-----------------------------------------------------+
| Data Fields | Request data fields to be serialized as a JSON |
| ``field=value`` | object (default), or to be form encoded |
| | (``--form, -f``). |
| ``field=value``, | object (default), or to be form-encoded |
| ``field=@file.txt`` | (``--form, -f``). |
+-----------------------+-----------------------------------------------------+
| Raw JSON fields | Useful when sending JSON and one or |
| ``field:=json`` | more fields need to be a ``Boolean``, ``Number``, |
| | nested ``Object``, or an ``Array``, e.g., |
| ``field:=json``, | more fields need to be a ``Boolean``, ``Number``, |
| ``field:=@file.json`` | nested ``Object``, or an ``Array``, e.g., |
| | ``meals:='["ham","spam"]'`` or ``pies:=[1,2,3]`` |
| | (note the quotes). |
+-----------------------+-----------------------------------------------------+
| Files | Only available with ``--form, -f``. |
| Form File Fields | Only available with ``--form, -f``. |
| ``field@/dir/file`` | For example ``screenshot@~/Pictures/img.png``. |
| | The presence of a file field results |
| | in a ``multipart/form-data`` request. |
@ -285,6 +321,8 @@ You can use ``\`` to escape characters that shouldn't be used as separators
(or parts thereof). For instance, ``foo\==bar`` will become a data key/value
pair (``foo=`` and ``bar``) instead of a URL parameter.
You can also quote values, e.g. ``foo="bar baz"``.
Note that data fields aren't the only way to specify request data:
`Redirected input`_ allows for passing arbitrary data to be sent with the
request.
@ -332,11 +370,16 @@ Simple example:
Non-string fields use the ``:=`` separator, which allows you to embed raw JSON
into the resulting object:
into the resulting object. Text and raw JSON files can also be embedded into
fields using ``=@`` and ``:=@``:
.. code-block:: bash
$ http PUT api.example.com/person/1 name=John age:=29 married:=false hobbies:='["http", "pies"]'
$ http PUT api.example.com/person/1 \
name=John \
age:=29 married:=false hobbies:='["http", "pies"]' \ # Raw JSON
description=@about-john.txt \ # Embed text file
bookmarks:=@bookmarks.json # Embed JSON file
.. code-block:: http
@ -352,8 +395,12 @@ into the resulting object:
"http",
"pies"
],
"description": "John is a nice guy who likes pies.",
"married": false,
"name": "John"
"name": "John",
"bookmarks": {
"HTTPie": "http://httpie.org",
}
}
@ -383,7 +430,7 @@ Regular Forms
.. code-block:: bash
$ http --form POST api.example.org/person/1 name='John Smith' email=john@example.org
$ http --form POST api.example.org/person/1 name='John Smith' email=john@example.org cv=@~/Documents/cv.txt
.. code-block:: http
@ -391,7 +438,7 @@ Regular Forms
POST /person/1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=utf-8
name=John+Smith&email=john%40example.org
name=John+Smith&email=john%40example.org&cv=John's+CV+...
-----------------
@ -416,6 +463,9 @@ submitted:
<input type="file" name="cv" />
</form>
Note that ``@`` is used to simulate a file upload form field, whereas
``=@`` just embeds the file content as a regular text field value.
============
HTTP Headers
@ -519,8 +569,9 @@ Authorization information from your ``~/.netrc`` file is honored as well:
Auth Plugins
------------
* `httpie-ntlm <https://github.com/jkbr/httpie-ntlm>`_
* `httpie-oauth <https://github.com/jkbr/httpie-oauth>`_
* `httpie-oauth <https://github.com/jkbr/httpie-oauth>`_: OAuth
* `httpie-ntlm <https://github.com/jkbr/httpie-ntlm>`_: NTLM (NT LAN Manager)
* `httpie-negotiate <https://github.com/ndzou/httpie-negotiate>`_: SPNEGO (GSS Negotiate)
=======
@ -532,7 +583,7 @@ protocol (which is included in the value in case of redirects across protocols):
.. code-block:: bash
$ http --proxy=http:10.10.1.10:3128 --proxy=https:10.10.1.10:1080 example.org
$ http --proxy=http:http://10.10.1.10:3128 --proxy=https:https://10.10.1.10:1080 example.org
With Basic authentication:
@ -550,8 +601,8 @@ In your ``~/.bash_profile``:
.. code-block:: bash
export HTTP_PROXY=10.10.1.10:3128
export HTTPS_PROXY=10.10.1.10:1080
export HTTP_PROXY=http://10.10.1.10:3128
export HTTPS_PROXY=https://10.10.1.10:1080
export NO_PROXY=localhost,example.com
@ -1197,7 +1248,7 @@ See `claudiatd/httpie-artwork`_
Authors
=======
`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_
`Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_
have contributed.
=======
@ -1213,11 +1264,19 @@ Changelog
*You can click a version name to see a diff with the previous one.*
* `0.8.0-dev`_
* `0.7.0`_ (2013-09-24)
* `0.9.0-dev`_
* `0.8.0`_ (2014-01-25)
* Added ``field=@file.txt`` and ``field:=@file.json`` for embedding
the contents of text and JSON files into request data.
* Added curl-style shorthand for localhost.
* Fixed request ``Host`` header value output so that it doesn't contain
credentials, if included in the URL.
* `0.7.1`_ (2013-09-24)
* Added ``--ignore-stdin``.
* Added support for auth plugins.
* Improved ``--help`` output.
* Improved ``Content-Disposition`` parsing for ``--download`` mode.
* Update to Requests 2.0.0
* `0.6.0`_ (2013-06-03)
* XML data is now formatted.
* ``--session`` and ``--session-read-only`` now also accept paths to
@ -1309,6 +1368,14 @@ Changelog
* `0.1.6`_ (2012-03-04)
------------
.. image:: https://d2weczhvl823v0.cloudfront.net/jkbr/httpie/trend.png
:target: https://bitdeli.com/free
:alt: Bitdeli Badge
.. _Requests: http://python-requests.org
.. _Pygments: http://pygments.org/
.. _pip: http://www.pip-installer.org/en/latest/index.html
@ -1319,8 +1386,8 @@ Changelog
.. _Debian: http://packages.debian.org/httpie
.. _the repository: https://github.com/jkbr/httpie
.. _these fine people: https://github.com/jkbr/httpie/contributors
.. _Jakub Roztocil: http://roztocil.name
.. _@jakubroztocil: https://twitter.com/jakubroztocil
.. _Jakub Roztocil: http://subtleapps.com
.. _@jkbrzt: https://twitter.com/jkbrzt
.. _existing issues: https://github.com/jkbr/httpie/issues?state=open
.. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork
.. _0.1.6: https://github.com/jkbr/httpie/compare/0.1.4...0.1.6
@ -1336,7 +1403,8 @@ Changelog
.. _0.5.0: https://github.com/jkbr/httpie/compare/0.4.1...0.5.0
.. _0.5.1: https://github.com/jkbr/httpie/compare/0.5.0...0.5.1
.. _0.6.0: https://github.com/jkbr/httpie/compare/0.5.1...0.6.0
.. _0.7.0: https://github.com/jkbr/httpie/compare/0.6.0...0.7.0
.. _0.8.0-dev: https://github.com/jkbr/httpie/compare/0.7.0...master
.. _0.7.1: https://github.com/jkbr/httpie/compare/0.6.0...0.7.1
.. _0.8.0: https://github.com/jkbr/httpie/compare/0.7.1...0.8.0
.. _0.9.0-dev: https://github.com/jkbr/httpie/compare/0.8.0...master
.. _AUTHORS.rst: https://github.com/jkbr/httpie/blob/master/AUTHORS.rst
.. _LICENSE: https://github.com/jkbr/httpie/blob/master/LICENSE

View File

@ -3,7 +3,7 @@ HTTPie - a CLI, cURL-like tool for humans.
"""
__author__ = 'Jakub Roztocil'
__version__ = '0.7.0'
__version__ = '0.8.0'
__licence__ = 'BSD'

View File

@ -15,7 +15,7 @@ from .plugins import plugin_manager
from .sessions import DEFAULT_SESSIONS_DIR
from .output import AVAILABLE_STYLES, DEFAULT_STYLE
from .input import (Parser, AuthCredentialsArgType, KeyValueArgType,
SEP_PROXY, SEP_CREDENTIALS, SEP_GROUP_ITEMS,
SEP_PROXY, SEP_CREDENTIALS, SEP_GROUP_ALL_ITEMS,
OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD,
OUT_RESP_BODY, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT,
PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SessionNameValidator)
@ -88,13 +88,18 @@ positional.add_argument(
help="""
The scheme defaults to 'http://' if the URL does not include one.
You can also use a shorthand for localhost
$ http :3000 # => http://localhost:3000
$ http :/foo # => http://localhost/foo
"""
)
positional.add_argument(
'items',
metavar='REQUEST ITEM',
metavar='REQUEST_ITEM',
nargs=ZERO_OR_MORE,
type=KeyValueArgType(*SEP_GROUP_ITEMS),
type=KeyValueArgType(*SEP_GROUP_ALL_ITEMS),
help=r"""
Optional key-value pairs to be included in the request. The separator used
determines the type:
@ -112,13 +117,21 @@ positional.add_argument(
name=HTTPie language=Python description='CLI HTTP client'
':=' Non-string JSON data fields (only with --json, -j):
awesome:=true amount:=42 colors:='["red", "green", "blue"]'
'@' Form file fields (only with --form, -f):
cs@~/Documents/CV.pdf
':=' Non-string JSON data fields (only with --json, -j):
'=@' A data field like '=', but takes a file path and embeds its content:
awesome:=true amount:=42 colors:='["red", "green", "blue"]'
essay=@Documents/essay.txt
':=@' A raw JSON field like ':=', but takes a file path and embeds its content:
package:=@./package.json
You can use a backslash to escape a colliding separator in the field name:
@ -186,7 +199,7 @@ output_processing.add_argument(
default=DEFAULT_STYLE,
choices=AVAILABLE_STYLES,
help="""
Output coloring style (default is "{default}"). On of:
Output coloring style (default is "{default}"). One of:
{available}
@ -422,11 +435,12 @@ network.add_argument(
'--proxy',
default=[],
action='append',
metavar='PROTOCOL:HOST',
metavar='PROTOCOL:PROXY_URL',
type=KeyValueArgType(SEP_PROXY),
help="""
String mapping protocol to the URL of the proxy (e.g. http:foo.bar:3128).
You can specify multiple proxies with different protocols.
String mapping protocol to the URL of the proxy
(e.g. http:http://foo.bar:3128). You can specify multiple proxies with
different protocols.
"""
)

View File

@ -3,7 +3,6 @@ import sys
from pprint import pformat
import requests
import requests.auth
from . import sessions
from . import __version__
@ -15,12 +14,6 @@ JSON = 'application/json; charset=utf-8'
DEFAULT_UA = 'HTTPie/%s' % __version__
class HTTPie(object):
def __init__(self, env, plugin_manager):
pass
def get_response(args, config_dir):
"""Send the request and return a `request.Response`."""

View File

@ -6,7 +6,7 @@ import sys
import re
import json
import mimetypes
from getpass import getpass
import getpass
from io import BytesIO
#noinspection PyCompatibility
from argparse import ArgumentParser, ArgumentTypeError, ArgumentError
@ -37,22 +37,40 @@ SEP_PROXY = ':'
SEP_DATA = '='
SEP_DATA_RAW_JSON = ':='
SEP_FILES = '@'
SEP_DATA_EMBED_FILE = '=@'
SEP_DATA_EMBED_RAW_JSON_FILE = ':=@'
SEP_QUERY = '=='
# Separators that become request data
SEP_GROUP_DATA_ITEMS = frozenset([
SEP_DATA,
SEP_DATA_RAW_JSON,
SEP_FILES
SEP_FILES,
SEP_DATA_EMBED_FILE,
SEP_DATA_EMBED_RAW_JSON_FILE
])
# Separators for items whose value is a filename to be embedded
SEP_GROUP_DATA_EMBED_ITEMS = frozenset([
SEP_DATA_EMBED_FILE,
SEP_DATA_EMBED_RAW_JSON_FILE,
])
# Separators for raw JSON items
SEP_GROUP_RAW_JSON_ITEMS = frozenset([
SEP_DATA_RAW_JSON,
SEP_DATA_EMBED_RAW_JSON_FILE,
])
# Separators allowed in ITEM arguments
SEP_GROUP_ITEMS = frozenset([
SEP_GROUP_ALL_ITEMS = frozenset([
SEP_HEADERS,
SEP_QUERY,
SEP_DATA,
SEP_DATA_RAW_JSON,
SEP_FILES
SEP_FILES,
SEP_DATA_EMBED_FILE,
SEP_DATA_EMBED_RAW_JSON_FILE,
])
@ -120,7 +138,18 @@ class Parser(ArgumentParser):
if not (self.args.url.startswith((HTTP, HTTPS))):
# Default to 'https://' if invoked as `https args`.
scheme = HTTPS if self.env.progname == 'https' else HTTP
self.args.url = scheme + self.args.url
# See if we're using curl style shorthand for localhost (:3000/foo)
shorthand = re.match(r'^:(?!:)(\d*)(/?.*)$', self.args.url)
if shorthand:
port = shorthand.group(1)
rest = shorthand.group(2)
self.args.url = scheme + 'localhost'
if port:
self.args.url += ':' + port
self.args.url += rest
else:
self.args.url = scheme + self.args.url
self._process_auth()
return self.args
@ -257,7 +286,7 @@ class Parser(ArgumentParser):
# Parse the URL as an ITEM and store it as the first ITEM arg.
self.args.items.insert(
0,
KeyValueArgType(*SEP_GROUP_ITEMS).__call__(self.args.url)
KeyValueArgType(*SEP_GROUP_ALL_ITEMS).__call__(self.args.url)
)
except ArgumentTypeError as e:
@ -558,9 +587,7 @@ def parse_items(items, data=None, headers=None, files=None, params=None):
params = ParamDict()
for item in items:
value = item.value
key = item.key
if item.sep == SEP_HEADERS:
target = headers
@ -572,21 +599,34 @@ def parse_items(items, data=None, headers=None, files=None, params=None):
value = (os.path.basename(value),
BytesIO(f.read()))
except IOError as e:
raise ParseError(
'Invalid argument "%s": %s' % (item.orig, e))
raise ParseError('"%s": %s' % (item.orig, e))
target = files
elif item.sep in [SEP_DATA, SEP_DATA_RAW_JSON]:
if item.sep == SEP_DATA_RAW_JSON:
elif item.sep in SEP_GROUP_DATA_ITEMS:
if item.sep in SEP_GROUP_DATA_EMBED_ITEMS:
try:
value = json.loads(item.value)
except ValueError:
raise ParseError('"%s" is not valid JSON' % item.orig)
with open(os.path.expanduser(value), 'rb') as f:
value = f.read().decode('utf8')
except IOError as e:
raise ParseError('"%s": %s' % (item.orig, e))
except UnicodeDecodeError:
raise ParseError(
'"%s": cannot embed the content of "%s",'
' not a UTF8 or ASCII-encoded text file'
% (item.orig, item.value)
)
if item.sep in SEP_GROUP_RAW_JSON_ITEMS:
try:
value = json.loads(value)
except ValueError as e:
raise ParseError('"%s": %s' % (item.orig, e))
target = data
else:
raise TypeError(item)
target[key] = value
target[item.key] = value
return headers, data, files, params

View File

@ -88,16 +88,7 @@ class HTTPMessage(object):
@property
def content_type(self):
"""Return the message content type."""
ct = self._orig.headers.get(
b'Content-Type',
self._orig.headers.get(
'Content-Type',
''
)
)
if isinstance(ct, bytes):
ct = ct.decode()
return ct
return self._orig.headers.get('Content-Type', '')
class HTTPResponse(HTTPMessage):
@ -164,7 +155,7 @@ class HTTPRequest(HTTPMessage):
headers = dict(self._orig.headers)
if 'Host' not in headers:
headers['Host'] = url.netloc
headers['Host'] = url.netloc.split('@')[-1]
headers = ['%s: %s' % (name, value)
for name, value in headers.items()]

View File

@ -11,7 +11,7 @@ if sys.argv[-1] == 'test':
requirements = [
'requests>=1.2.3',
'requests>=2.0.0',
'Pygments>=1.5'
]
try:

3
tests/fixtures/test.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"hello": "world"
}

View File

@ -64,6 +64,7 @@ sys.path.insert(0, os.path.realpath(os.path.join(TESTS_ROOT, '..')))
from httpie import ExitStatus
from httpie import input
from httpie.cli import parser
from httpie.models import Environment
from httpie.core import main
from httpie.output import BINARY_SUPPRESSED_NOTICE
@ -101,15 +102,22 @@ def patharg(path):
FILE_PATH = os.path.join(TESTS_ROOT, 'fixtures', 'file.txt')
FILE2_PATH = os.path.join(TESTS_ROOT, 'fixtures', 'file2.txt')
BIN_FILE_PATH = os.path.join(TESTS_ROOT, 'fixtures', 'file.bin')
JSON_FILE_PATH = os.path.join(TESTS_ROOT, 'fixtures', 'test.json')
FILE_PATH_ARG = patharg(FILE_PATH)
FILE2_PATH_ARG = patharg(FILE2_PATH)
BIN_FILE_PATH_ARG = patharg(BIN_FILE_PATH)
JSON_FILE_PATH_ARG = patharg(JSON_FILE_PATH)
with open(FILE_PATH) as f:
# Strip because we don't want new lines in the data so that we can
# easily count occurrences also when embedded in JSON (where the new
# line would be escaped).
FILE_CONTENT = f.read().strip()
with open(BIN_FILE_PATH, 'rb') as f:
BIN_FILE_CONTENT = f.read()
with open(JSON_FILE_PATH, 'rb') as f:
JSON_FILE_CONTENT = f.read()
def httpbin(path):
@ -809,8 +817,6 @@ class RequestBodyFromFilePathTest(BaseTestCase):
"""
def test_request_body_from_file_by_path(self):
# FIXME: *sometimes* fails on py33, the content-type is form.
# https://github.com/jkbr/httpie/issues/140
r = http(
'--verbose',
'POST',
@ -822,8 +828,6 @@ class RequestBodyFromFilePathTest(BaseTestCase):
self.assertIn('"Content-Type": "text/plain"', r)
def test_request_body_from_file_by_path_with_explicit_content_type(self):
# FIXME: *sometimes* fails on py33, the content-type is form.
# https://github.com/jkbr/httpie/issues/140
r = http(
'POST',
httpbin('/post'),
@ -1176,11 +1180,7 @@ class ItemParsingTest(BaseTestCase):
def setUp(self):
self.key_value_type = input.KeyValueArgType(
input.SEP_HEADERS,
input.SEP_QUERY,
input.SEP_DATA,
input.SEP_DATA_RAW_JSON,
input.SEP_FILES,
*input.SEP_GROUP_ALL_ITEMS
)
def test_invalid_items(self):
@ -1227,26 +1227,99 @@ class ItemParsingTest(BaseTestCase):
self.key_value_type('eh:'),
self.key_value_type('ed='),
self.key_value_type('bool:=true'),
self.key_value_type('test-file@%s' % FILE_PATH_ARG),
self.key_value_type('file@' + FILE_PATH_ARG),
self.key_value_type('query==value'),
self.key_value_type('string-embed=@' + FILE_PATH_ARG),
self.key_value_type('raw-json-embed:=@' + JSON_FILE_PATH_ARG),
])
# Parsed headers
# `requests.structures.CaseInsensitiveDict` => `dict`
headers = dict(headers._store.values())
self.assertDictEqual(headers, {
'header': 'value',
'eh': ''
})
self.assertDictEqual(data, {
# Parsed data
raw_json_embed = data.pop('raw-json-embed')
self.assertDictEqual(raw_json_embed, json.loads(
JSON_FILE_CONTENT.decode('utf8')))
data['string-embed'] = data['string-embed'].strip()
self.assertDictEqual(dict(data), {
"ed": "",
"string": "value",
"bool": True,
"list": ["a", 1, {}, False],
"obj": {"a": "b"},
"string-embed": FILE_CONTENT,
})
# Parsed query string parameters
self.assertDictEqual(params, {
'query': 'value',
})
self.assertIn('test-file', files)
# Parsed file fields
self.assertIn('file', files)
self.assertEqual(files['file'][1].read().strip().decode('utf8'),
FILE_CONTENT)
class CLIParserTestCase(unittest.TestCase):
def test_expand_localhost_shorthand(self):
args = parser.parse_args(args=[':'], env=TestEnvironment())
self.assertEqual(args.url, 'http://localhost')
def test_expand_localhost_shorthand_with_slash(self):
args = parser.parse_args(args=[':/'], env=TestEnvironment())
self.assertEqual(args.url, 'http://localhost/')
def test_expand_localhost_shorthand_with_port(self):
args = parser.parse_args(args=[':3000'], env=TestEnvironment())
self.assertEqual(args.url, 'http://localhost:3000')
def test_expand_localhost_shorthand_with_path(self):
args = parser.parse_args(args=[':/path'], env=TestEnvironment())
self.assertEqual(args.url, 'http://localhost/path')
def test_expand_localhost_shorthand_with_port_and_slash(self):
args = parser.parse_args(args=[':3000/'], env=TestEnvironment())
self.assertEqual(args.url, 'http://localhost:3000/')
def test_expand_localhost_shorthand_with_port_and_path(self):
args = parser.parse_args(args=[':3000/path'], env=TestEnvironment())
self.assertEqual(args.url, 'http://localhost:3000/path')
def test_dont_expand_shorthand_ipv6_as_shorthand(self):
args = parser.parse_args(args=['::1'], env=TestEnvironment())
self.assertEqual(args.url, 'http://::1')
def test_dont_expand_longer_ipv6_as_shorthand(self):
args = parser.parse_args(
args=['::ffff:c000:0280'],
env=TestEnvironment()
)
self.assertEqual(args.url, 'http://::ffff:c000:0280')
def test_dont_expand_full_ipv6_as_shorthand(self):
args = parser.parse_args(
args=['0000:0000:0000:0000:0000:0000:0000:0001'],
env=TestEnvironment()
)
self.assertEqual(
args.url,
'http://0000:0000:0000:0000:0000:0000:0000:0001'
)
class ArgumentParserTestCase(unittest.TestCase):