From b851862a4f2afb64459a1aede8f980d10ae5c193 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Sun, 21 Mar 2021 13:15:54 +0100 Subject: [PATCH 01/11] Migrate docs to Sphinx + MyST --- docs/api.md | 75 ++++++++++++++---------- docs/conf.py | 53 +++++++++++++++++ docs/css/custom.css | 10 ---- docs/index.md | 94 +++++------------------------- httpcore/_async/base.py | 48 ++++++++------- httpcore/_async/connection_pool.py | 44 +++++++------- httpcore/_bytestreams.py | 57 +++++++++++++----- httpcore/_sync/base.py | 48 ++++++++------- httpcore/_sync/connection_pool.py | 44 +++++++------- requirements.txt | 8 ++- scripts/docs | 14 ++++- 11 files changed, 269 insertions(+), 226 deletions(-) create mode 100644 docs/conf.py delete mode 100644 docs/css/custom.css diff --git a/docs/api.md b/docs/api.md index 3bbde423c..05ce757a1 100644 --- a/docs/api.md +++ b/docs/api.md @@ -2,55 +2,68 @@ ## Async API Overview +### Base interfaces + The `AsyncHTTPTransport` and `AsyncByteStream` classes provide the base interface which transport classes need to implement. -::: httpcore.AsyncHTTPTransport - :docstring: - :members: arequest aclose + + +```{eval-rst} +.. autoclass:: httpcore.AsyncHTTPTransport + :members: arequest, aclose -::: httpcore.AsyncByteStream - :docstring: - :members: __aiter__ aclose +.. autoclass:: httpcore.AsyncByteStream + :members: __aiter__, aclose +``` -The `AsyncConnectionPool` class is a concrete implementation of `AsyncHTTPTransport`. +### Connection pool -::: httpcore.AsyncConnectionPool - :docstring: +The {class}`AsyncConnectionPool ` class is a concrete implementation of {class}`AsyncHTTPTransport `. +```{eval-rst} +.. autoclass:: httpcore.AsyncConnectionPool +``` -The `PlainByteStream` and `AsyncIteratorByteStream` classes are concrete implementations of `AsyncByteStream`. +### Byte streams -::: httpcore.PlainByteStream - :docstring: +The {class}`PlainByteStream ` and {class}`AsyncIteratorByteStream ` classes are concrete implementations of `AsyncByteStream`. -::: httpcore.AsyncIteratorByteStream - :docstring: +```{eval-rst} +.. autoclass:: httpcore.PlainByteStream ---- +.. autoclass:: httpcore.AsyncIteratorByteStream +``` ## Sync API Overview -The `SyncHTTPTransport` and `SyncByteStream` classes provide the base -interface which transport classes need to implement. +### Base interfaces + +The {class}`SyncHTTPTransport ` and {class}`SyncByteStream ` 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 +``` -::: httpcore.SyncHTTPTransport - :docstring: - :members: request close +### Connection pool -::: httpcore.SyncByteStream - :docstring: - :members: __iter__ close +The {class}`SyncConnectionPool ` class is a concrete implementation of {class}`SyncHTTPTransport `. -The `SyncConnectionPool` class is a concrete implementation of `SyncHTTPTransport`. +```{eval-rst} +.. autoclass:: httpcore.SyncConnectionPool +``` -::: httpcore.SyncConnectionPool - :docstring: +### Byte streams -The `PlainByteStream` and `IteratorByteStream` classes are concrete implementations of `SyncByteStream`. +The {class}`PlainByteStream ` and {class}`IteratorByteStream ` classes are concrete implementations of `SyncByteStream`. -::: httpcore.PlainByteStream - :docstring: +```{eval-rst} +.. autoclass:: httpcore.PlainByteStream + :noindex: -::: httpcore.IteratorByteStream - :docstring: +.. autoclass:: httpcore.IteratorByteStream +``` diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 000000000..7b36c2b90 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,53 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('.')) + +# -- Project information ----------------------------------------------------- + +project = "HTTPCore" +copyright = "2021, Encode" +author = "Encode" + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ["myst_parser", "sphinx.ext.autodoc", "sphinx.ext.napoleon"] + +# Prevent sphinx-autodoc from ordering autodoc members alphabetically. +# Instead use whichever order is defined by :members:. +# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_member_order +autodoc_member_order = "bysource" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "furo" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] diff --git a/docs/css/custom.css b/docs/css/custom.css deleted file mode 100644 index 6e5d91919..000000000 --- a/docs/css/custom.css +++ /dev/null @@ -1,10 +0,0 @@ -div.autodoc-docstring { - padding-left: 20px; - margin-bottom: 30px; - border-left: 5px solid rgba(230, 230, 230); -} - -div.autodoc-members { - padding-left: 20px; - margin-bottom: 15px; -} diff --git a/docs/index.md b/docs/index.md index 5178ada6b..bea6d712f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,89 +1,21 @@ -# HTTP Core - -[![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/) - -> *Do one thing, and do it well.* - -The HTTP Core package provides a minimal low-level HTTP client, which does -one thing only. Sending HTTP requests. - -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. - -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] +```{include} ../README.md ``` -## 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')] - ) +```{toctree} +:hidden: +:caption: Usage - try: - body = b''.join([chunk for chunk in stream]) - finally: - stream.close() - - print(status_code, body) +api ``` -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')] - ) +```{toctree} +:hidden: +:caption: Development - try: - body = b''.join([chunk async for chunk in stream]) - finally: - await stream.aclose() - - print(status_code, body) +contributing +Changelog +License +Source Code ``` - -## 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. diff --git a/httpcore/_async/base.py b/httpcore/_async/base.py index cf449f428..c908b4bdc 100644 --- a/httpcore/_async/base.py +++ b/httpcore/_async/base.py @@ -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]: @@ -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( @@ -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: 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: List[Tuple[bytes, bytes]] + Any HTTP headers to send with the request. + stream: :class:`AsyncByteStream` + The body of the HTTP request. + ext: dict + A dictionary of optional extensions. + + Returns + ------- + status_code: int + The HTTP status code, such as `200`. + headers: List[Tuple[bytes, bytes]] + Any HTTP headers included on the response. + stream: :class:`AsyncByteStream` + The body of the HTTP response. + ext: dict + A dictionary of optional extensions. """ raise NotImplementedError() # pragma: nocover diff --git a/httpcore/_async/connection_pool.py b/httpcore/_async/connection_pool.py index 46ede0ba4..90c1818d8 100644 --- a/httpcore/_async/connection_pool.py +++ b/httpcore/_async/connection_pool.py @@ -77,26 +77,30 @@ class AsyncConnectionPool(AsyncHTTPTransport): """ A connection pool for making HTTP requests. - **Parameters:** - - * **ssl_context** - `Optional[SSLContext]` - An SSL context to use for - verifying connections. - * **max_connections** - `Optional[int]` - The maximum number of concurrent - connections to allow. - * **max_keepalive_connections** - `Optional[int]` - The maximum number of - connections to allow before closing keep-alive connections. - * **keepalive_expiry** - `Optional[float]` - The maximum time to allow - before closing a keep-alive connection. - * **http2** - `bool` - Enable HTTP/2 support. - * **uds** - `str` - Path to a Unix Domain Socket to use instead of TCP sockets. - * **local_address** - `Optional[str]` - Local address to connect from. Can - also be used to connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address (IPv4), - while using `local_address="::"` will connect using an `AF_INET6` address - (IPv6). - * **retries** - `int` - The maximum number of retries when trying to establish a - connection. - * **backend** - `str` - A name indicating which concurrency backend to use. + Parameters + ---------- + ssl_context: Optional[SSLContext] + An SSL context to use for verifying connections. + max_connections: Optional[int] + The maximum number of concurrent connections to allow. + max_keepalive_connections: Optional[int] + The maximum number of connections to allow before closing keep-alive + connections. + keepalive_expiry: Optional[float] + The maximum time to allow before closing a keep-alive connection. + http2: bool + Enable HTTP/2 support. + uds: str + Path to a Unix Domain Socket to use instead of TCP sockets. + local_address: Optional[str] + Local address to connect from. Can also be used to connect using a particular + address family. Using `local_address="0.0.0.0"` will connect using an `AF_INET` + address (IPv4), while using `local_address="::"` will connect using an + `AF_INET6` address (IPv6). + retries: int + The maximum number of retries when trying to establish a connection. + backend: str + A name indicating which concurrency backend to use. """ def __init__( diff --git a/httpcore/_bytestreams.py b/httpcore/_bytestreams.py index e938aaf90..ee1d183f0 100644 --- a/httpcore/_bytestreams.py +++ b/httpcore/_bytestreams.py @@ -7,11 +7,17 @@ class PlainByteStream(AsyncByteStream, SyncByteStream): """ A concrete implementation for either sync or async byte streams. - Just handles a plain byte string as the content of the stream. - ``` - stream = httpcore.PlainByteStream(b"123") - ``` + Parameters + ---------- + content: bytes + A plain byte string used as the content of the stream. + + Example + ------- + :: + + stream = httpcore.PlainByteStream(b"123") """ def __init__(self, content: bytes) -> None: @@ -27,14 +33,23 @@ async def __aiter__(self) -> AsyncIterator[bytes]: class IteratorByteStream(SyncByteStream): """ A concrete implementation for sync byte streams. - Handles a byte iterator as the content of the stream. - ``` - def generate_content(): - ... + Parameters + ---------- + aiterator: + A sync byte iterator, used as the content of the stream. + aclose_func: + An optional function called when closing the stream. + + Example + ------- + :: + + def generate_content(): + yield b"Hello, world!" + ... - stream = httpcore.IteratorByteStream(generate_content()) - ``` + stream = httpcore.IteratorByteStream(generate_content()) """ def __init__(self, iterator: Iterator[bytes], close_func: Callable = None) -> None: @@ -53,14 +68,24 @@ def close(self) -> None: class AsyncIteratorByteStream(AsyncByteStream): """ A concrete implementation for async byte streams. - Handles an async byte iterator as the content of the stream. - ``` - async def generate_content(): - ... + Parameters + ---------- + aiterator: + An async byte iterator, used as the content of the stream. + aclose_func: + An optional async function called when closing the stream. + + Example + ------- + + :: + + async def generate_content(): + yield b"Hello, world!" + ... - stream = httpcore.AsyncIteratorByteStream(generate_content()) - ``` + stream = httpcore.AsyncIteratorByteStream(generate_content()) """ def __init__( diff --git a/httpcore/_sync/base.py b/httpcore/_sync/base.py index 95a434eb0..b96054b74 100644 --- a/httpcore/_sync/base.py +++ b/httpcore/_sync/base.py @@ -37,7 +37,7 @@ class SyncByteStream: The base interface for request and response bodies. Concrete implementations should subclass this class, and implement - the `\\__iter__` method, and optionally the `close` method. + the :meth:`__iter__` method, and optionally the :meth:`close` method. """ def __iter__(self) -> Iterator[bytes]: @@ -57,8 +57,8 @@ class SyncHTTPTransport: """ 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:`request` method, and optionally the :meth:`close` method. """ def request( @@ -72,25 +72,29 @@ def request( """ 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[SyncByteStream]` - 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** - `SyncByteStream` - The body of the HTTP response. - * **ext** - `dict` - A dictionary of optional extensions. + 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: List[Tuple[bytes, bytes]] + Any HTTP headers to send with the request. + stream: :class:`SyncByteStream` + The body of the HTTP request. + ext: dict + A dictionary of optional extensions. + + Returns + ------- + status_code: int + The HTTP status code, such as `200`. + headers: List[Tuple[bytes, bytes]] + Any HTTP headers included on the response. + stream: :class:`SyncByteStream` + The body of the HTTP response. + ext: dict + A dictionary of optional extensions. """ raise NotImplementedError() # pragma: nocover diff --git a/httpcore/_sync/connection_pool.py b/httpcore/_sync/connection_pool.py index 4702184b8..6eebb7d2d 100644 --- a/httpcore/_sync/connection_pool.py +++ b/httpcore/_sync/connection_pool.py @@ -77,26 +77,30 @@ class SyncConnectionPool(SyncHTTPTransport): """ A connection pool for making HTTP requests. - **Parameters:** - - * **ssl_context** - `Optional[SSLContext]` - An SSL context to use for - verifying connections. - * **max_connections** - `Optional[int]` - The maximum number of concurrent - connections to allow. - * **max_keepalive_connections** - `Optional[int]` - The maximum number of - connections to allow before closing keep-alive connections. - * **keepalive_expiry** - `Optional[float]` - The maximum time to allow - before closing a keep-alive connection. - * **http2** - `bool` - Enable HTTP/2 support. - * **uds** - `str` - Path to a Unix Domain Socket to use instead of TCP sockets. - * **local_address** - `Optional[str]` - Local address to connect from. Can - also be used to connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address (IPv4), - while using `local_address="::"` will connect using an `AF_INET6` address - (IPv6). - * **retries** - `int` - The maximum number of retries when trying to establish a - connection. - * **backend** - `str` - A name indicating which concurrency backend to use. + Parameters + ---------- + ssl_context: Optional[SSLContext] + An SSL context to use for verifying connections. + max_connections: Optional[int] + The maximum number of concurrent connections to allow. + max_keepalive_connections: Optional[int] + The maximum number of connections to allow before closing keep-alive + connections. + keepalive_expiry: Optional[float] + The maximum time to allow before closing a keep-alive connection. + http2: bool + Enable HTTP/2 support. + uds: str + Path to a Unix Domain Socket to use instead of TCP sockets. + local_address: Optional[str] + Local address to connect from. Can also be used to connect using a particular + address family. Using `local_address="0.0.0.0"` will connect using an `AF_INET` + address (IPv4), while using `local_address="::"` will connect using an + `AF_INET6` address (IPv6). + retries: int + The maximum number of retries when trying to establish a connection. + backend: str + A name indicating which concurrency backend to use. """ def __init__( diff --git a/requirements.txt b/requirements.txt index ea3f8414c..fc691c081 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,9 +6,11 @@ trio-typing==0.5.0 curio==1.4 # Docs -mkautodoc==0.1.0 -mkdocs==1.1.2 -mkdocs-material==6.1.6 +sphinx==3.5.3 +sphinx-autobuild==2021.3.14 +myst-parser==0.13.5 +furo==2021.3.20b30 +ghp-import==1.1.0 # Packaging twine==3.2.0 diff --git a/scripts/docs b/scripts/docs index 4ac3beb7a..5f261d3f1 100755 --- a/scripts/docs +++ b/scripts/docs @@ -5,6 +5,18 @@ if [ -d 'venv' ] ; then export PREFIX="venv/bin/" fi +SOURCE_DIR="docs" +OUT_DIR="build/html" + +COMMAND="$1" + set -x -${PREFIX}mkdocs serve +if [ "$COMMAND" = "build" ]; then + ${PREFIX}sphinx-build $SOURCE_DIR $OUT_DIR +elif [ "$COMMAND" = "gh-deploy" ]; then + scripts/docs build + ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" +else + ${PREFIX}sphinx-autobuild $SOURCE_DIR $OUT_DIR --watch httpcore/ +fi From 74e43d4edc576645ba18c254a8124b452f8f0e9b Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Sun, 21 Mar 2021 15:25:58 +0100 Subject: [PATCH 02/11] Improvements * Add [source] links Fix broken admonition in contributing.md Use ::: for reST items Document proxies Update build and publish scripts Simplify conf.py --- docs/api.md | 71 ++++++++++++++++++------------ docs/conf.py | 60 +++++++++---------------- docs/contributing.md | 7 +-- docs/index.md | 12 ++--- httpcore/_async/base.py | 22 ++++----- httpcore/_async/connection_pool.py | 24 +++++----- httpcore/_async/http_proxy.py | 31 ++++++------- httpcore/_bytestreams.py | 49 +++++++++------------ httpcore/_sync/base.py | 22 ++++----- httpcore/_sync/connection_pool.py | 24 +++++----- httpcore/_sync/http_proxy.py | 31 ++++++------- mkdocs.yml | 23 ---------- requirements.txt | 1 + scripts/build | 2 +- scripts/docs | 3 +- scripts/publish | 2 +- 16 files changed, 177 insertions(+), 207 deletions(-) delete mode 100644 mkdocs.yml diff --git a/docs/api.md b/docs/api.md index 05ce757a1..908eb8a54 100644 --- a/docs/api.md +++ b/docs/api.md @@ -2,68 +2,81 @@ ## Async API Overview -### Base interfaces +### Base async interfaces -The `AsyncHTTPTransport` and `AsyncByteStream` classes provide the base -interface which transport classes need to implement. +These classes provide the base interface which transport classes need to implement. - - -```{eval-rst} +:::{eval-rst} .. autoclass:: httpcore.AsyncHTTPTransport :members: arequest, aclose .. autoclass:: httpcore.AsyncByteStream :members: __aiter__, aclose -``` - -### Connection pool +::: -The {class}`AsyncConnectionPool ` class is a concrete implementation of {class}`AsyncHTTPTransport `. +### Async connection pool -```{eval-rst} +:::{eval-rst} .. autoclass:: httpcore.AsyncConnectionPool -``` + :show-inheritance: +::: + +### Async proxy + +:::{eval-rst} +.. autoclass:: httpcore.AsyncHTTPProxy + :show-inheritance: +::: -### Byte streams +### Async byte streams -The {class}`PlainByteStream ` and {class}`AsyncIteratorByteStream ` classes are concrete implementations of `AsyncByteStream`. +These classes are concrete implementations of [`AsyncByteStream`](httpcore.AsyncByteStream). -```{eval-rst} +:::{eval-rst} .. autoclass:: httpcore.PlainByteStream + :show-inheritance: .. autoclass:: httpcore.AsyncIteratorByteStream -``` + :show-inheritance: +::: ## Sync API Overview -### Base interfaces +### Base sync interfaces -The {class}`SyncHTTPTransport ` and {class}`SyncByteStream ` classes provide the base interface which transport classes need to implement. +These classes provide the base interface which transport classes need to implement. -```{eval-rst} +:::{eval-rst} .. autoclass:: httpcore.SyncHTTPTransport :members: request, close .. autoclass:: httpcore.SyncByteStream :members: __iter__, close -``` +::: -### Connection pool +### Sync connection pool -The {class}`SyncConnectionPool ` class is a concrete implementation of {class}`SyncHTTPTransport `. - -```{eval-rst} +:::{eval-rst} .. autoclass:: httpcore.SyncConnectionPool -``` + :show-inheritance: +::: + +### Sync proxy + +:::{eval-rst} +.. autoclass:: httpcore.SyncHTTPProxy + :show-inheritance: +::: -### Byte streams +### Sync byte streams -The {class}`PlainByteStream ` and {class}`IteratorByteStream ` classes are concrete implementations of `SyncByteStream`. +These classes are concrete implementations of [`SyncByteStream`](httpcore.SyncByteStream). -```{eval-rst} +:::{eval-rst} .. autoclass:: httpcore.PlainByteStream + :show-inheritance: :noindex: .. autoclass:: httpcore.IteratorByteStream -``` + :show-inheritance: +::: diff --git a/docs/conf.py b/docs/conf.py index 7b36c2b90..6d09a17ef 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,53 +1,35 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# +# See: https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -- + import os import sys -sys.path.insert(0, os.path.abspath('.')) -# -- Project information ----------------------------------------------------- +# 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 --------------------------------------------------- +# -- General configuration -- -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ["myst_parser", "sphinx.ext.autodoc", "sphinx.ext.napoleon"] +extensions = [ + "myst_parser", + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", + "sphinx_autodoc_typehints", +] -# Prevent sphinx-autodoc from ordering autodoc members alphabetically. -# Instead use whichever order is defined by :members:. -# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_member_order -autodoc_member_order = "bysource" +myst_enable_extensions = [ + "colon_fence", +] -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] +autodoc_member_order = "bysource" # Preserve :members: order. -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] +# -- HTML configuration -- -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# html_theme = "furo" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [] diff --git a/docs/contributing.md b/docs/contributing.md index 0b42944fe..f87d48e33 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -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: diff --git a/docs/index.md b/docs/index.md index bea6d712f..29f3c54cf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,16 +1,16 @@ -```{include} ../README.md -``` +:::{include} ../README.md +::: -```{toctree} +:::{toctree} :hidden: :caption: Usage api -``` +::: -```{toctree} +:::{toctree} :hidden: :caption: Development @@ -18,4 +18,4 @@ contributing Changelog License Source Code -``` +::: diff --git a/httpcore/_async/base.py b/httpcore/_async/base.py index c908b4bdc..ca62e044c 100644 --- a/httpcore/_async/base.py +++ b/httpcore/_async/base.py @@ -74,26 +74,26 @@ async def arequest( Parameters ---------- - method: bytes - The HTTP method, such as `b'GET'`. - url: Tuple[bytes, bytes, Optional[int], bytes] + method: + The HTTP method, such as ``b'GET'``. + url: The URL as a 4-tuple of (scheme, host, port, path). - headers: List[Tuple[bytes, bytes]] + headers: Any HTTP headers to send with the request. - stream: :class:`AsyncByteStream` + stream: The body of the HTTP request. - ext: dict + ext: A dictionary of optional extensions. Returns ------- - status_code: int - The HTTP status code, such as `200`. - headers: List[Tuple[bytes, bytes]] + status_code: + The HTTP status code, such as ``200``. + headers: Any HTTP headers included on the response. - stream: :class:`AsyncByteStream` + stream: The body of the HTTP response. - ext: dict + ext: A dictionary of optional extensions. """ raise NotImplementedError() # pragma: nocover diff --git a/httpcore/_async/connection_pool.py b/httpcore/_async/connection_pool.py index 90c1818d8..ce50f87ed 100644 --- a/httpcore/_async/connection_pool.py +++ b/httpcore/_async/connection_pool.py @@ -79,27 +79,27 @@ class AsyncConnectionPool(AsyncHTTPTransport): Parameters ---------- - ssl_context: Optional[SSLContext] + ssl_context: An SSL context to use for verifying connections. - max_connections: Optional[int] + max_connections: The maximum number of concurrent connections to allow. - max_keepalive_connections: Optional[int] + max_keepalive_connections: The maximum number of connections to allow before closing keep-alive connections. - keepalive_expiry: Optional[float] + keepalive_expiry: The maximum time to allow before closing a keep-alive connection. - http2: bool + http2: Enable HTTP/2 support. - uds: str + uds: Path to a Unix Domain Socket to use instead of TCP sockets. - local_address: Optional[str] + local_address: Local address to connect from. Can also be used to connect using a particular - address family. Using `local_address="0.0.0.0"` will connect using an `AF_INET` - address (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - retries: int + address family. Using ``local_address="0.0.0.0"`` will connect using an + ``AF_INET`` address (IPv4), while using ``local_address="::"`` will connect + using an ``AF_INET6`` address (IPv6). + retries: The maximum number of retries when trying to establish a connection. - backend: str + backend: A name indicating which concurrency backend to use. """ diff --git a/httpcore/_async/http_proxy.py b/httpcore/_async/http_proxy.py index d9df762b0..a888d2674 100644 --- a/httpcore/_async/http_proxy.py +++ b/httpcore/_async/http_proxy.py @@ -41,21 +41,22 @@ class AsyncHTTPProxy(AsyncConnectionPool): """ A connection pool for making HTTP requests via an HTTP proxy. - **Parameters:** - - * **proxy_url** - `Tuple[bytes, bytes, Optional[int], bytes]` - The URL of - the proxy service as a 4-tuple of (scheme, host, port, path). - * **proxy_headers** - `Optional[List[Tuple[bytes, bytes]]]` - A list of - proxy headers to include. - * **proxy_mode** - `str` - A proxy mode to operate in. May be "DEFAULT", - "FORWARD_ONLY", or "TUNNEL_ONLY". - * **ssl_context** - `Optional[SSLContext]` - An SSL context to use for - verifying connections. - * **max_connections** - `Optional[int]` - The maximum number of concurrent - connections to allow. - * **max_keepalive_connections** - `Optional[int]` - The maximum number of - connections to allow before closing keep-alive connections. - * **http2** - `bool` - Enable HTTP/2 support. + Parameters + ---------- + proxy_url: + The URL of the proxy service as a 4-tuple of (scheme, host, port, path). + proxy_headers: + A list of proxy headers to include. + proxy_mode: + A proxy mode to operate in. May be "DEFAULT", "FORWARD_ONLY", or "TUNNEL_ONLY". + ssl_context: + An SSL context to use for verifying connections. + max_connections: + The maximum number of concurrent connections to allow. + max_keepalive_connections: + The maximum number of connections to allow before closing keep-alive connections. + http2: + Enable HTTP/2 support. """ def __init__( diff --git a/httpcore/_bytestreams.py b/httpcore/_bytestreams.py index ee1d183f0..2fffe5fb3 100644 --- a/httpcore/_bytestreams.py +++ b/httpcore/_bytestreams.py @@ -8,16 +8,14 @@ class PlainByteStream(AsyncByteStream, SyncByteStream): """ A concrete implementation for either sync or async byte streams. + Example:: + + stream = httpcore.PlainByteStream(b"123") + Parameters ---------- - content: bytes + content: A plain byte string used as the content of the stream. - - Example - ------- - :: - - stream = httpcore.PlainByteStream(b"123") """ def __init__(self, content: bytes) -> None: @@ -34,22 +32,20 @@ class IteratorByteStream(SyncByteStream): """ A concrete implementation for sync byte streams. - Parameters - ---------- - aiterator: - A sync byte iterator, used as the content of the stream. - aclose_func: - An optional function called when closing the stream. - - Example - ------- - :: + Example:: def generate_content(): yield b"Hello, world!" ... stream = httpcore.IteratorByteStream(generate_content()) + + Parameters + ---------- + iterator: + A sync byte iterator, used as the content of the stream. + close_func: + An optional function called when closing the stream. """ def __init__(self, iterator: Iterator[bytes], close_func: Callable = None) -> None: @@ -69,23 +65,20 @@ class AsyncIteratorByteStream(AsyncByteStream): """ A concrete implementation for async byte streams. - Parameters - ---------- - aiterator: - An async byte iterator, used as the content of the stream. - aclose_func: - An optional async function called when closing the stream. - - Example - ------- - - :: + Example:: async def generate_content(): yield b"Hello, world!" ... stream = httpcore.AsyncIteratorByteStream(generate_content()) + + Parameters + ---------- + aiterator: + An async byte iterator, used as the content of the stream. + aclose_func: + An optional async function called when closing the stream. """ def __init__( diff --git a/httpcore/_sync/base.py b/httpcore/_sync/base.py index b96054b74..5c4d16b8e 100644 --- a/httpcore/_sync/base.py +++ b/httpcore/_sync/base.py @@ -74,26 +74,26 @@ def request( Parameters ---------- - method: bytes - The HTTP method, such as `b'GET'`. - url: Tuple[bytes, bytes, Optional[int], bytes] + method: + The HTTP method, such as ``b'GET'``. + url: The URL as a 4-tuple of (scheme, host, port, path). - headers: List[Tuple[bytes, bytes]] + headers: Any HTTP headers to send with the request. - stream: :class:`SyncByteStream` + stream: The body of the HTTP request. - ext: dict + ext: A dictionary of optional extensions. Returns ------- - status_code: int - The HTTP status code, such as `200`. - headers: List[Tuple[bytes, bytes]] + status_code: + The HTTP status code, such as ``200``. + headers: Any HTTP headers included on the response. - stream: :class:`SyncByteStream` + stream: The body of the HTTP response. - ext: dict + ext: A dictionary of optional extensions. """ raise NotImplementedError() # pragma: nocover diff --git a/httpcore/_sync/connection_pool.py b/httpcore/_sync/connection_pool.py index 6eebb7d2d..ce63f03fe 100644 --- a/httpcore/_sync/connection_pool.py +++ b/httpcore/_sync/connection_pool.py @@ -79,27 +79,27 @@ class SyncConnectionPool(SyncHTTPTransport): Parameters ---------- - ssl_context: Optional[SSLContext] + ssl_context: An SSL context to use for verifying connections. - max_connections: Optional[int] + max_connections: The maximum number of concurrent connections to allow. - max_keepalive_connections: Optional[int] + max_keepalive_connections: The maximum number of connections to allow before closing keep-alive connections. - keepalive_expiry: Optional[float] + keepalive_expiry: The maximum time to allow before closing a keep-alive connection. - http2: bool + http2: Enable HTTP/2 support. - uds: str + uds: Path to a Unix Domain Socket to use instead of TCP sockets. - local_address: Optional[str] + local_address: Local address to connect from. Can also be used to connect using a particular - address family. Using `local_address="0.0.0.0"` will connect using an `AF_INET` - address (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - retries: int + address family. Using ``local_address="0.0.0.0"`` will connect using an + ``AF_INET`` address (IPv4), while using ``local_address="::"`` will connect + using an ``AF_INET6`` address (IPv6). + retries: The maximum number of retries when trying to establish a connection. - backend: str + backend: A name indicating which concurrency backend to use. """ diff --git a/httpcore/_sync/http_proxy.py b/httpcore/_sync/http_proxy.py index f5576c010..255037d0f 100644 --- a/httpcore/_sync/http_proxy.py +++ b/httpcore/_sync/http_proxy.py @@ -41,21 +41,22 @@ class SyncHTTPProxy(SyncConnectionPool): """ A connection pool for making HTTP requests via an HTTP proxy. - **Parameters:** - - * **proxy_url** - `Tuple[bytes, bytes, Optional[int], bytes]` - The URL of - the proxy service as a 4-tuple of (scheme, host, port, path). - * **proxy_headers** - `Optional[List[Tuple[bytes, bytes]]]` - A list of - proxy headers to include. - * **proxy_mode** - `str` - A proxy mode to operate in. May be "DEFAULT", - "FORWARD_ONLY", or "TUNNEL_ONLY". - * **ssl_context** - `Optional[SSLContext]` - An SSL context to use for - verifying connections. - * **max_connections** - `Optional[int]` - The maximum number of concurrent - connections to allow. - * **max_keepalive_connections** - `Optional[int]` - The maximum number of - connections to allow before closing keep-alive connections. - * **http2** - `bool` - Enable HTTP/2 support. + Parameters + ---------- + proxy_url: + The URL of the proxy service as a 4-tuple of (scheme, host, port, path). + proxy_headers: + A list of proxy headers to include. + proxy_mode: + A proxy mode to operate in. May be "DEFAULT", "FORWARD_ONLY", or "TUNNEL_ONLY". + ssl_context: + An SSL context to use for verifying connections. + max_connections: + The maximum number of concurrent connections to allow. + max_keepalive_connections: + The maximum number of connections to allow before closing keep-alive connections. + http2: + Enable HTTP/2 support. """ def __init__( diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index 02dfed4b5..000000000 --- a/mkdocs.yml +++ /dev/null @@ -1,23 +0,0 @@ -site_name: HTTP Core -site_description: Do one thing, and do it well. -site_url: https://www.encode.io/httpcore - -theme: - name: 'material' - -repo_name: encode/httpcore -repo_url: https://github.com/encode/httpcore/ -edit_uri: "" - -nav: - - Introduction: 'index.md' - - Developer Interface: 'api.md' - - Contributing: 'contributing.md' - -markdown_extensions: - - admonition - - codehilite - - mkautodoc - -extra_css: - - css/custom.css diff --git a/requirements.txt b/requirements.txt index fc691c081..5477fb27f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,7 @@ curio==1.4 # Docs sphinx==3.5.3 sphinx-autobuild==2021.3.14 +sphinx-autodoc-typehints==1.11.1 myst-parser==0.13.5 furo==2021.3.20b30 ghp-import==1.1.0 diff --git a/scripts/build b/scripts/build index 602eab0a4..2192b90b8 100755 --- a/scripts/build +++ b/scripts/build @@ -12,4 +12,4 @@ set -x ${PREFIX}python setup.py sdist bdist_wheel ${PREFIX}twine check dist/* -${PREFIX}mkdocs build +scripts/docs build diff --git a/scripts/docs b/scripts/docs index 5f261d3f1..b79f8f25d 100755 --- a/scripts/docs +++ b/scripts/docs @@ -9,6 +9,7 @@ SOURCE_DIR="docs" OUT_DIR="build/html" COMMAND="$1" +ARGS="${@:2}" set -x @@ -16,7 +17,7 @@ if [ "$COMMAND" = "build" ]; then ${PREFIX}sphinx-build $SOURCE_DIR $OUT_DIR elif [ "$COMMAND" = "gh-deploy" ]; then scripts/docs build - ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" + ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" "$ARGS" else ${PREFIX}sphinx-autobuild $SOURCE_DIR $OUT_DIR --watch httpcore/ fi diff --git a/scripts/publish b/scripts/publish index 1c4a32282..a16006d73 100755 --- a/scripts/publish +++ b/scripts/publish @@ -24,4 +24,4 @@ fi set -x ${PREFIX}twine upload dist/* -${PREFIX}mkdocs gh-deploy --force +scripts/docs gh-deploy --push From dc8dda84622a65bfb2503b27f265507ef6c25527 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Sun, 21 Mar 2021 15:30:13 +0100 Subject: [PATCH 03/11] Lint --- httpcore/_async/http_proxy.py | 3 ++- httpcore/_sync/http_proxy.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/httpcore/_async/http_proxy.py b/httpcore/_async/http_proxy.py index a888d2674..f62179a69 100644 --- a/httpcore/_async/http_proxy.py +++ b/httpcore/_async/http_proxy.py @@ -54,7 +54,8 @@ class AsyncHTTPProxy(AsyncConnectionPool): max_connections: The maximum number of concurrent connections to allow. max_keepalive_connections: - The maximum number of connections to allow before closing keep-alive connections. + The maximum number of connections to allow before closing keep-alive + connections. http2: Enable HTTP/2 support. """ diff --git a/httpcore/_sync/http_proxy.py b/httpcore/_sync/http_proxy.py index 255037d0f..2bc66ac0a 100644 --- a/httpcore/_sync/http_proxy.py +++ b/httpcore/_sync/http_proxy.py @@ -54,7 +54,8 @@ class SyncHTTPProxy(SyncConnectionPool): max_connections: The maximum number of concurrent connections to allow. max_keepalive_connections: - The maximum number of connections to allow before closing keep-alive connections. + The maximum number of connections to allow before closing keep-alive + connections. http2: Enable HTTP/2 support. """ From a852e18538387829f8c2213eb4a927091faf21fc Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Sun, 21 Mar 2021 15:34:02 +0100 Subject: [PATCH 04/11] Tweak scripts/docs gh-deploy --- scripts/docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/docs b/scripts/docs index b79f8f25d..a36b82126 100755 --- a/scripts/docs +++ b/scripts/docs @@ -17,7 +17,7 @@ if [ "$COMMAND" = "build" ]; then ${PREFIX}sphinx-build $SOURCE_DIR $OUT_DIR elif [ "$COMMAND" = "gh-deploy" ]; then scripts/docs build - ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" "$ARGS" + ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" $ARGS else ${PREFIX}sphinx-autobuild $SOURCE_DIR $OUT_DIR --watch httpcore/ fi From 3980a9adfb815ab6e6ec0d90abaf9eb0c82fbaa9 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Sun, 21 Mar 2021 15:40:30 +0100 Subject: [PATCH 05/11] Fix scripts/docs cross platform support --- scripts/docs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/docs b/scripts/docs index a36b82126..3533067ef 100755 --- a/scripts/docs +++ b/scripts/docs @@ -9,7 +9,7 @@ SOURCE_DIR="docs" OUT_DIR="build/html" COMMAND="$1" -ARGS="${@:2}" +shift set -x @@ -17,7 +17,7 @@ if [ "$COMMAND" = "build" ]; then ${PREFIX}sphinx-build $SOURCE_DIR $OUT_DIR elif [ "$COMMAND" = "gh-deploy" ]; then scripts/docs build - ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" $ARGS + ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" $@ else ${PREFIX}sphinx-autobuild $SOURCE_DIR $OUT_DIR --watch httpcore/ fi From 721fa36c381e6eca235debefac4548e92ec93db8 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Sun, 21 Mar 2021 16:01:09 +0100 Subject: [PATCH 06/11] Drop sphinx-autodoc-typehints, description mode is okay --- docs/conf.py | 7 +++++-- requirements.txt | 1 - scripts/docs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 6d09a17ef..13e7da528 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -21,14 +21,17 @@ "sphinx.ext.autodoc", "sphinx.ext.viewcode", "sphinx.ext.napoleon", - "sphinx_autodoc_typehints", ] myst_enable_extensions = [ "colon_fence", ] -autodoc_member_order = "bysource" # Preserve :members: order. +# Preserve :members: order. +autodoc_member_order = "bysource" + +# Show type hints in descriptions, rather than signatures. +autodoc_typehints = "description" # -- HTML configuration -- diff --git a/requirements.txt b/requirements.txt index 5477fb27f..fc691c081 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,6 @@ curio==1.4 # Docs sphinx==3.5.3 sphinx-autobuild==2021.3.14 -sphinx-autodoc-typehints==1.11.1 myst-parser==0.13.5 furo==2021.3.20b30 ghp-import==1.1.0 diff --git a/scripts/docs b/scripts/docs index 3533067ef..3bbc09f5f 100755 --- a/scripts/docs +++ b/scripts/docs @@ -9,7 +9,6 @@ SOURCE_DIR="docs" OUT_DIR="build/html" COMMAND="$1" -shift set -x @@ -17,6 +16,7 @@ if [ "$COMMAND" = "build" ]; then ${PREFIX}sphinx-build $SOURCE_DIR $OUT_DIR elif [ "$COMMAND" = "gh-deploy" ]; then scripts/docs build + shift ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" $@ else ${PREFIX}sphinx-autobuild $SOURCE_DIR $OUT_DIR --watch httpcore/ From d2dac48ab6b32d0d87b1f38ebd6bed68d8909a8a Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Mon, 22 Mar 2021 11:07:58 +0100 Subject: [PATCH 07/11] Use standard bash --- scripts/docs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/docs b/scripts/docs index 3bbc09f5f..b4c9f9717 100755 --- a/scripts/docs +++ b/scripts/docs @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/bash -e export PREFIX="" if [ -d 'venv' ] ; then @@ -9,6 +9,7 @@ SOURCE_DIR="docs" OUT_DIR="build/html" COMMAND="$1" +ARGS="${@:2}" set -x @@ -16,8 +17,7 @@ if [ "$COMMAND" = "build" ]; then ${PREFIX}sphinx-build $SOURCE_DIR $OUT_DIR elif [ "$COMMAND" = "gh-deploy" ]; then scripts/docs build - shift - ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" $@ + ${PREFIX}ghp-import $OUT_DIR -np -m "Deployed $(git rev-parse --short HEAD)" $ARGS else - ${PREFIX}sphinx-autobuild $SOURCE_DIR $OUT_DIR --watch httpcore/ + ${PREFIX}sphinx-autobuild $SOURCE_DIR $OUT_DIR --watch httpcore/ $ARGS fi From 902680a59bd182c51aff3cd89d08f06db55c042f Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Mon, 22 Mar 2021 11:52:01 +0100 Subject: [PATCH 08/11] Resolve public API source code locations --- docs/conf.py | 25 +++++++++++++++++++++++++ httpcore/__init__.py | 1 + 2 files changed, 26 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 13e7da528..54c31682b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,6 +33,31 @@ # Show type hints in descriptions, rather than signatures. autodoc_typehints = "description" +# Enable 'viewcode-follow-imported' event. +viewcode_follow_imported_members = True + # -- 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).__full_module__ + except AttributeError: + return None + + +def setup(app): + app.connect("viewcode-follow-imported", _viewcode_follow_imported) diff --git a/httpcore/__init__.py b/httpcore/__init__.py index 84e0ae4d7..cd5b16061 100644 --- a/httpcore/__init__.py +++ b/httpcore/__init__.py @@ -57,4 +57,5 @@ for _name in __all__: if not _name.startswith("__"): + __locals[_name].__full_module__ = __locals[_name].__module__ # Used by Shpinx. setattr(__locals[_name], "__module__", "httpcore") # noqa From 115fc1db842a2227545343ec96d7319d2e695e44 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Mon, 22 Mar 2021 12:36:32 +0100 Subject: [PATCH 09/11] Rename full_module -> source_module --- docs/conf.py | 2 +- httpcore/__init__.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 54c31682b..098ea52af 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -54,7 +54,7 @@ def _viewcode_follow_imported(app, modname, attribute): try: # Set in httpcore/__init__.py - return getattr(httpcore, attribute).__full_module__ + return getattr(httpcore, attribute).__source_module__ except AttributeError: return None diff --git a/httpcore/__init__.py b/httpcore/__init__.py index cd5b16061..18cd929f9 100644 --- a/httpcore/__init__.py +++ b/httpcore/__init__.py @@ -57,5 +57,7 @@ for _name in __all__: if not _name.startswith("__"): - __locals[_name].__full_module__ = __locals[_name].__module__ # Used by Shpinx. + # 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 From c87f1d76b8ec029d03689781a0b7fc85f8d1e9d6 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Wed, 24 Mar 2021 12:11:34 +0100 Subject: [PATCH 10/11] Drop unnecessary viewcode_follow_imported_members option --- docs/conf.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 098ea52af..e5f646c6c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,9 +33,6 @@ # Show type hints in descriptions, rather than signatures. autodoc_typehints = "description" -# Enable 'viewcode-follow-imported' event. -viewcode_follow_imported_members = True - # -- HTML configuration -- html_theme = "furo" From 7f9637ddef33edf957162b09bc2c85cb0bdd77d3 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Fri, 9 Apr 2021 15:44:20 +0200 Subject: [PATCH 11/11] Pin docutils==0.17 --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index e29de98a5..ddb56746e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,8 @@ sphinx-autobuild==2021.3.14 myst-parser==0.13.5 furo==2021.3.20b30 ghp-import==1.1.0 +# myst-parser + docutils==0.17 has a bug: https://github.com/executablebooks/MyST-Parser/issues/343 +docutils==0.16 # Packaging twine==3.4.1