Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate docs to Sphinx + MyST #285

Merged
merged 14 commits into from Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
92 changes: 59 additions & 33 deletions docs/api.md
Expand Up @@ -2,55 +2,81 @@

## Async API Overview

The `AsyncHTTPTransport` and `AsyncByteStream` classes provide the base
interface which transport classes need to implement.
### Base async interfaces

::: httpcore.AsyncHTTPTransport
:docstring:
:members: arequest aclose
These classes provide the base interface which transport classes need to implement.

::: httpcore.AsyncByteStream
:docstring:
:members: __aiter__ aclose
:::{eval-rst}
.. autoclass:: httpcore.AsyncHTTPTransport
:members: arequest, aclose

The `AsyncConnectionPool` class is a concrete implementation of `AsyncHTTPTransport`.
.. autoclass:: httpcore.AsyncByteStream
:members: __aiter__, aclose
:::

::: httpcore.AsyncConnectionPool
:docstring:
### Async connection pool

:::{eval-rst}
.. autoclass:: httpcore.AsyncConnectionPool
:show-inheritance:
:::

The `PlainByteStream` and `AsyncIteratorByteStream` classes are concrete implementations of `AsyncByteStream`.
### Async proxy

::: httpcore.PlainByteStream
:docstring:
:::{eval-rst}
.. autoclass:: httpcore.AsyncHTTPProxy
:show-inheritance:
:::

::: httpcore.AsyncIteratorByteStream
:docstring:
### Async byte streams

---
These classes are concrete implementations of [`AsyncByteStream`](httpcore.AsyncByteStream).

:::{eval-rst}
.. autoclass:: httpcore.PlainByteStream
:show-inheritance:

.. autoclass:: httpcore.AsyncIteratorByteStream
:show-inheritance:
:::

## Sync API Overview

The `SyncHTTPTransport` and `SyncByteStream` classes provide the base
interface which transport classes need to implement.
### Base sync interfaces

These classes provide the base interface which transport classes need to implement.

:::{eval-rst}
.. autoclass:: httpcore.SyncHTTPTransport
:members: request, close

.. autoclass:: httpcore.SyncByteStream
:members: __iter__, close
:::

### Sync connection pool

::: httpcore.SyncHTTPTransport
:docstring:
:members: request close
:::{eval-rst}
.. autoclass:: httpcore.SyncConnectionPool
:show-inheritance:
:::

::: httpcore.SyncByteStream
:docstring:
:members: __iter__ close
### Sync proxy

The `SyncConnectionPool` class is a concrete implementation of `SyncHTTPTransport`.
:::{eval-rst}
.. autoclass:: httpcore.SyncHTTPProxy
:show-inheritance:
:::

::: httpcore.SyncConnectionPool
:docstring:
### Sync byte streams

The `PlainByteStream` and `IteratorByteStream` classes are concrete implementations of `SyncByteStream`.
These classes are concrete implementations of [`SyncByteStream`](httpcore.SyncByteStream).

::: httpcore.PlainByteStream
:docstring:
:::{eval-rst}
.. autoclass:: httpcore.PlainByteStream
:show-inheritance:
:noindex:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious - what is :noindex: here, and why on this class in particular?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We show this class two times, once for the sync API, once for the async API. I figured it's fine, except showing them twice would make Sphinx index them twice, which raised a warning hinting to add :noindex:.


::: httpcore.IteratorByteStream
:docstring:
.. autoclass:: httpcore.IteratorByteStream
:show-inheritance:
:::
60 changes: 60 additions & 0 deletions docs/conf.py
@@ -0,0 +1,60 @@
# See: https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --

import os
import sys

# Allow sphinx-autodoc to access `httpcore` contents.
sys.path.insert(0, os.path.abspath("."))

# -- Project information --

project = "HTTPCore"
copyright = "2021, Encode"
author = "Encode"

# -- General configuration --

extensions = [
"myst_parser",
"sphinx.ext.autodoc",
"sphinx.ext.viewcode",
"sphinx.ext.napoleon",
]

myst_enable_extensions = [
"colon_fence",
]

# Preserve :members: order.
autodoc_member_order = "bysource"

# Show type hints in descriptions, rather than signatures.
autodoc_typehints = "description"

# -- HTML configuration --

html_theme = "furo"

# -- App setup --


def _viewcode_follow_imported(app, modname, attribute):
# We set `__module__ = "httpcore"` on all public attributes for prettier
# repr(), so viewcode needs a little help to find the original source modules.

if modname != "httpcore":
return None

import httpcore

try:
# Set in httpcore/__init__.py
return getattr(httpcore, attribute).__source_module__
except AttributeError:
return None


def setup(app):
app.connect("viewcode-follow-imported", _viewcode_follow_imported)
7 changes: 4 additions & 3 deletions docs/contributing.md
Expand Up @@ -97,9 +97,10 @@ To run the tests, use:
$ scripts/test
```

!!! warning
The test suite spawns testing servers on ports **8000** and **8001**.
Make sure these are not in use, so the tests can run properly.
:::{warning}
The test suite spawns testing servers on ports **8000** and **8001**.
Make sure these are not in use, so the tests can run properly.
:::

You can run a single test script like this:

Expand Down
10 changes: 0 additions & 10 deletions docs/css/custom.css

This file was deleted.

100 changes: 16 additions & 84 deletions docs/index.md
@@ -1,89 +1,21 @@
# HTTP Core
:::{include} ../README.md
:::

[![Test Suite](https://github.com/encode/httpcore/workflows/Test%20Suite/badge.svg)](https://github.com/encode/httpcore/actions)
[![Package version](https://badge.fury.io/py/httpcore.svg)](https://pypi.org/project/httpcore/)
<!-- Table of Content entries, shown in left sidebar. -->

> *Do one thing, and do it well.*
:::{toctree}
:hidden:
:caption: Usage

The HTTP Core package provides a minimal low-level HTTP client, which does
one thing only. Sending HTTP requests.
api
:::

It does not provide any high level model abstractions over the API,
does not handle redirects, multipart uploads, building authentication headers,
transparent HTTP caching, URL parsing, session cookie handling,
content or charset decoding, handling JSON, environment based configuration
defaults, or any of that Jazz.
:::{toctree}
:hidden:
:caption: Development

Some things HTTP Core does do:

* Sending HTTP requests.
* Provides both sync and async interfaces.
* Supports HTTP/1.1 and HTTP/2.
* Async backend support for `asyncio`, `trio` and `curio`.
* Automatic connection pooling.
* HTTP(S) proxy support.

## Installation

For HTTP/1.1 only support, install with...

```shell
$ pip install httpcore
```

For HTTP/1.1 and HTTP/2 support, install with...

```shell
$ pip install httpcore[http2]
```

## Quickstart

Here's an example of making an HTTP GET request using `httpcore`...

```python
with httpcore.SyncConnectionPool() as http:
status_code, headers, stream, ext = http.request(
method=b'GET',
url=(b'https', b'example.org', 443, b'/'),
headers=[(b'host', b'example.org'), (b'user-agent', 'httpcore')]
)

try:
body = b''.join([chunk for chunk in stream])
finally:
stream.close()

print(status_code, body)
```

Or, using async...

```python
async with httpcore.AsyncConnectionPool() as http:
status_code, headers, stream, ext = await http.arequest(
method=b'GET',
url=(b'https', b'example.org', 443, b'/'),
headers=[(b'host', b'example.org'), (b'user-agent', 'httpcore')]
)

try:
body = b''.join([chunk async for chunk in stream])
finally:
await stream.aclose()

print(status_code, body)
```

## Motivation

You probably don't want to be using HTTP Core directly. It might make sense if
you're writing something like a proxy service in Python, and you just want
something at the lowest possible level, but more typically you'll want to use
a higher level client library, such as `httpx`.

The motivation for `httpcore` is:

* To provide a reusable low-level client library, that other packages can then build on top of.
* To provide a *really clear interface split* between the networking code and client logic,
so that each is easier to understand and reason about in isolation.
contributing
Changelog <https://github.com/encode/httpcore/blob/master/CHANGELOG.md>
License <https://github.com/encode/httpcore/blob/master/LICENSE.md>
Source Code <https://github.com/encode/httpcore>
:::
3 changes: 3 additions & 0 deletions httpcore/__init__.py
Expand Up @@ -57,4 +57,7 @@

for _name in __all__:
if not _name.startswith("__"):
# Save original source module, used by Sphinx.
__locals[_name].__source_module__ = __locals[_name].__module__
# Override module for prettier repr().
setattr(__locals[_name], "__module__", "httpcore") # noqa
48 changes: 26 additions & 22 deletions httpcore/_async/base.py
Expand Up @@ -37,7 +37,7 @@ class AsyncByteStream:
The base interface for request and response bodies.

Concrete implementations should subclass this class, and implement
the `\\__aiter__` method, and optionally the `aclose` method.
the :meth:`__aiter__` method, and optionally the :meth:`aclose` method.
"""

async def __aiter__(self) -> AsyncIterator[bytes]:
Expand All @@ -57,8 +57,8 @@ class AsyncHTTPTransport:
"""
The base interface for sending HTTP requests.

Concete implementations should subclass this class, and implement
the `request` method, and optionally the `close` method.
Concrete implementations should subclass this class, and implement
the :meth:`arequest` method, and optionally the :meth:`aclose` method.
"""

async def arequest(
Expand All @@ -72,25 +72,29 @@ async def arequest(
"""
The interface for sending a single HTTP request, and returning a response.

**Parameters:**

* **method** - `bytes` - The HTTP method, such as `b'GET'`.
* **url** - `Tuple[bytes, bytes, Optional[int], bytes]` - The URL as a 4-tuple
of (scheme, host, port, path).
* **headers** - `Optional[List[Tuple[bytes, bytes]]]` - Any HTTP headers
to send with the request.
* **stream** - `Optional[AsyncByteStream]` - The body of the HTTP request.
* **ext** - `Optional[dict]` - A dictionary of optional extensions.

** Returns:**

A four-tuple of:

* **status_code** - `int` - The HTTP status code, such as `200`.
* **headers** - `List[Tuple[bytes, bytes]]` - Any HTTP headers included
on the response.
* **stream** - `AsyncByteStream` - The body of the HTTP response.
* **ext** - `dict` - A dictionary of optional extensions.
Parameters
----------
method:
The HTTP method, such as ``b'GET'``.
url:
The URL as a 4-tuple of (scheme, host, port, path).
headers:
Any HTTP headers to send with the request.
stream:
The body of the HTTP request.
ext:
A dictionary of optional extensions.

Returns
-------
status_code:
The HTTP status code, such as ``200``.
headers:
Any HTTP headers included on the response.
stream:
The body of the HTTP response.
ext:
A dictionary of optional extensions.
"""
raise NotImplementedError() # pragma: nocover

Expand Down