Skip to content

Commit

Permalink
Merge pull request #11 from encode/master
Browse files Browse the repository at this point in the history
Sync Fork from Upstream Repo
  • Loading branch information
sthagen authored Feb 19, 2021
2 parents 4c49905 + 0f280af commit 51aed86
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 11 deletions.
4 changes: 2 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ what gets sent over the wire.*
>>> response = client.send(request)
```

* `def __init__(method, url, [params], [data], [json], [headers], [cookies])`
* `def __init__(method, url, [params], [headers], [cookies], [content], [data], [files], [json], [stream])`
* `.method` - **str**
* `.url` - **URL**
* `.content` - **byte**, **byte iterator**, or **byte async iterator**
Expand All @@ -121,7 +121,7 @@ what gets sent over the wire.*
* `.port` - **int**
* `.path` - **str**
* `.query` - **str**
* `.full_path` - **str**
* `.raw_path` - **str**
* `.fragment` - **str**
* `.is_ssl` - **bool**
* `.is_absolute_url` - **bool**
Expand Down
2 changes: 2 additions & 0 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ When using a `Client` instance, the `trust_env`, `verify`, and `cert` arguments

If you need more than one different SSL configuration, you should use different client instances for each SSL configuration.

Requests supports `REQUESTS_CA_BUNDLE` which points to either a file or a directory. HTTPX supports the `SSL_CERT_FILE` (for a file) and `SSL_CERT_DIR` (for a directory) OpenSSL variables instead.

## Request body on HTTP methods

The HTTP `GET`, `DELETE`, `HEAD`, and `OPTIONS` methods are specified as not supporting a request body. To stay in line with this, the `.get`, `.delete`, `.head` and `.options` functions do not support `files`, `data`, or `json` arguments.
Expand Down
8 changes: 3 additions & 5 deletions docs/environment_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ CLIENT_TRAFFIC_SECRET_0 XXXX

Valid values: a filename

if this environment variable is set then HTTPX will load
If this environment variable is set then HTTPX will load
CA certificate from the specified file instead of the default
location.

Expand All @@ -122,11 +122,9 @@ SSL_CERT_FILE=/path/to/ca-certs/ca-bundle.crt python -c "import httpx; httpx.get

## `SSL_CERT_DIR`

Valid values: a directory
Valid values: a directory following an [OpenSSL specific layout](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_load_verify_locations.html).

if this environment variable is set then HTTPX will load
CA certificates from the specified location instead of the default
location.
If this environment variable is set and the directory follows an [OpenSSL specific layout](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_load_verify_locations.html) (ie. you ran `c_rehash`) then HTTPX will load CA certificates from this directory instead of the default location.

Example:

Expand Down
3 changes: 2 additions & 1 deletion httpx/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1500,7 +1500,8 @@ async def _send_single_request(
async def on_close(response: Response) -> None:
response.elapsed = datetime.timedelta(seconds=await timer.async_elapsed())
if hasattr(stream, "aclose"):
await stream.aclose()
with map_exceptions(HTTPCORE_EXC_MAP, request=request):
await stream.aclose()

response = Response(
status_code,
Expand Down
4 changes: 2 additions & 2 deletions httpx/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class UnsetType:
def create_ssl_context(
cert: CertTypes = None,
verify: VerifyTypes = True,
trust_env: bool = None,
trust_env: bool = True,
http2: bool = False,
) -> ssl.SSLContext:
return SSLConfig(
Expand All @@ -63,7 +63,7 @@ def __init__(
*,
cert: CertTypes = None,
verify: VerifyTypes = True,
trust_env: bool = None,
trust_env: bool = True,
http2: bool = False,
):
self.cert = cert
Expand Down
2 changes: 1 addition & 1 deletion httpx/_status_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __new__(cls, value: int, phrase: str = "") -> "codes":
obj = int.__new__(cls, value) # type: ignore
obj._value_ = value

obj.phrase = phrase
obj.phrase = phrase # type: ignore
return obj

def __str__(self) -> str:
Expand Down
11 changes: 11 additions & 0 deletions httpx/_transports/mock.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
from typing import Callable, List, Optional, Tuple

import httpcore
Expand Down Expand Up @@ -47,7 +48,17 @@ async def arequest(
stream=stream,
)
await request.aread()

response = self.handler(request)

# Allow handler to *optionally* be an `async` function.
# If it is, then the `response` variable need to be awaited to actually
# return the result.

# https://simonwillison.net/2020/Sep/2/await-me-maybe/
if asyncio.iscoroutine(response):
response = await response

return (
response.status_code,
response.headers.raw,
Expand Down
3 changes: 3 additions & 0 deletions httpx/_transports/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ def request(

scheme, host, port, full_path = url
path, _, query = full_path.partition(b"?")
if port is None:
port = {b"http": 80, b"https": 443}[scheme]

environ = {
"wsgi.version": (1, 0),
"wsgi.url_scheme": scheme.decode("ascii"),
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def get_packages(package):
version=get_version("httpx"),
url="https://github.com/encode/httpx",
project_urls={
"Changelog": "https://github.com/encode/httpx/blob/master/CHANGELOG.md",
"Documentation": "https://www.python-httpx.org",
"Source": "https://github.com/encode/httpx",
},
Expand Down
32 changes: 32 additions & 0 deletions tests/client/test_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,35 @@ async def test_mounted_transport():
response = await client.get("custom://www.example.com")
assert response.status_code == 200
assert response.json() == {"app": "mounted"}


@pytest.mark.usefixtures("async_environment")
async def test_response_aclose_map_exceptions():
class BrokenStream:
async def __aiter__(self):
# so we're an AsyncIterator
pass # pragma: nocover

async def aclose(self):
raise httpcore.CloseError(OSError(104, "Connection reset by peer"))

def handle(request: httpx.Request) -> httpx.Response:
return httpx.Response(200, stream=BrokenStream())

async with httpx.AsyncClient(transport=httpx.MockTransport(handle)) as client:
async with client.stream("GET", "http://example.com") as response:
with pytest.raises(httpx.CloseError):
await response.aclose()


@pytest.mark.usefixtures("async_environment")
async def test_async_mock_transport():
async def hello_world(request):
return httpx.Response(200, text="Hello, world!")

transport = httpx.MockTransport(hello_world)

async with httpx.AsyncClient(transport=transport) as client:
response = await client.get("https://www.example.com")
assert response.status_code == 200
assert response.text == "Hello, world!"
27 changes: 27 additions & 0 deletions tests/test_wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,30 @@ def test_wsgi_generator_empty():
response = client.get("http://www.example.org/")
assert response.status_code == 200
assert response.text == ""


@pytest.mark.parametrize(
"url, expected_server_port",
[
pytest.param("http://www.example.org", "80", id="auto-http"),
pytest.param("https://www.example.org", "443", id="auto-https"),
pytest.param("http://www.example.org:8000", "8000", id="explicit-port"),
],
)
def test_wsgi_server_port(url: str, expected_server_port: int):
"""
SERVER_PORT is populated correctly from the requested URL.
"""
hello_world_app = application_factory([b"Hello, World!"])
server_port: str

def app(environ, start_response):
nonlocal server_port
server_port = environ["SERVER_PORT"]
return hello_world_app(environ, start_response)

client = httpx.Client(app=app)
response = client.get(url)
assert response.status_code == 200
assert response.text == "Hello, World!"
assert server_port == expected_server_port

0 comments on commit 51aed86

Please sign in to comment.