From: Seth Michael Larson Date: Tue, 13 Aug 2019 13:39:35 +0000 (-0500) Subject: Use nox for automation and CI (#128) X-Git-Tag: 0.7.0~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80dc3e274e8a797b305baa5005128c6d47cf8f3f;p=thirdparty%2Fhttpx.git Use nox for automation and CI (#128) --- diff --git a/.gitignore b/.gitignore index 938e2d15..90690006 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ __pycache__/ htmlcov/ *.egg-info/ venv/ +.nox diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 00000000..83cfd951 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +known_first_party = httpx +known_third_party = brotli,certifi,chardet,cryptography,h11,h2,hstspreload,nox,pytest,rfc3986,setuptools,trustme,uvicorn diff --git a/.travis.yml b/.travis.yml index 55549909..d702022c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,16 +4,35 @@ language: python cache: pip -python: - - "3.6" - - "3.7" +branches: + only: + - master + +matrix: + include: + - python: 3.7 + env: NOX_SESSION=check + - python: 3.7 + env: NOX_SESSION=docs + + - python: 3.6 + env: NOX_SESSION=test-3.6 + - python: 3.7 + env: NOX_SESSION=test-3.7 + - python: 3.8-dev + env: NOX_SESSION=test-3.8 + + allow_failures: + - python: 3.8-dev install: - - pip install -U -r requirements.txt + - pip install --upgrade nox script: - - scripts/test + - nox -s ${NOX_SESSION} after_script: - - pip install codecov - - codecov + - if [ -f .coverage ]; then + python -m pip install codecov; + codecov; + fi diff --git a/httpx/__init__.py b/httpx/__init__.py index 39b44aae..dec5cff1 100644 --- a/httpx/__init__.py +++ b/httpx/__init__.py @@ -86,6 +86,8 @@ __all__ = [ "TimeoutConfig", "VerifyTypes", "HTTPConnection", + "BasePoolSemaphore", + "BaseBackgroundManager", "ConnectionPool", "ConnectTimeout", "CookieConflict", diff --git a/httpx/exceptions.py b/httpx/exceptions.py index ddccbf8c..7ca9055b 100644 --- a/httpx/exceptions.py +++ b/httpx/exceptions.py @@ -1,6 +1,6 @@ -from typing import TYPE_CHECKING +import typing -if TYPE_CHECKING: +if typing.TYPE_CHECKING: from .models import BaseRequest, BaseResponse # pragma: nocover @@ -10,7 +10,10 @@ class HTTPError(Exception): """ def __init__( - self, request: "BaseRequest" = None, response: "BaseResponse" = None, *args + self, + *args: typing.Any, + request: "BaseRequest" = None, + response: "BaseResponse" = None, ) -> None: self.response = response self.request = request or getattr(self.response, "request", None) diff --git a/httpx/interfaces.py b/httpx/interfaces.py index 0a17f99c..6c79c9e2 100644 --- a/httpx/interfaces.py +++ b/httpx/interfaces.py @@ -41,7 +41,7 @@ class AsyncDispatcher: headers: HeaderTypes = None, verify: VerifyTypes = None, cert: CertTypes = None, - timeout: TimeoutTypes = None + timeout: TimeoutTypes = None, ) -> AsyncResponse: request = AsyncRequest(method, url, data=data, params=params, headers=headers) return await self.send(request, verify=verify, cert=cert, timeout=timeout) @@ -89,7 +89,7 @@ class Dispatcher: headers: HeaderTypes = None, verify: VerifyTypes = None, cert: CertTypes = None, - timeout: TimeoutTypes = None + timeout: TimeoutTypes = None, ) -> Response: request = Request(method, url, data=data, params=params, headers=headers) return self.send(request, verify=verify, cert=cert, timeout=timeout) diff --git a/httpx/models.py b/httpx/models.py index f397e780..4437bcc3 100644 --- a/httpx/models.py +++ b/httpx/models.py @@ -36,7 +36,7 @@ from .utils import ( str_query_param, ) -PrimitiveData = typing.Union[str, int, float, bool, type(None)] +PrimitiveData = typing.Optional[typing.Union[str, int, float, bool]] URLTypes = typing.Union["URL", str] @@ -92,6 +92,16 @@ class URL: else: self._uri_reference = url._uri_reference + # Handle IDNA domain names. + if self._uri_reference.authority: + idna_authority = self._uri_reference.authority.encode("idna").decode( + "ascii" + ) + if idna_authority != self._uri_reference.authority: + self._uri_reference = self._uri_reference.copy_with( + authority=idna_authority + ) + # Normalize scheme and domain name. if self.is_absolute_url: self._uri_reference = self._uri_reference.normalize() @@ -170,7 +180,7 @@ class URL: # URLs with a fragment portion as not absolute. # What we actually care about is if the URL provides # a scheme and hostname to which connections should be made. - return self.scheme and self.host + return bool(self.scheme and self.host) @property def is_relative_url(self) -> bool: @@ -252,7 +262,7 @@ class QueryParams(typing.Mapping[str, str]): elif isinstance(value, QueryParams): items = value.multi_items() elif isinstance(value, list): - items = value + items = value # type: ignore else: items = value.items() # type: ignore diff --git a/httpx/utils.py b/httpx/utils.py index e3acfd77..ff399356 100644 --- a/httpx/utils.py +++ b/httpx/utils.py @@ -23,7 +23,7 @@ def normalize_header_value(value: typing.AnyStr, encoding: str = None) -> bytes: return value.encode(encoding or "ascii") -def str_query_param(value: typing.Union[str, int, float, bool, type(None)]) -> str: +def str_query_param(value: typing.Optional[typing.Union[str, int, float, bool]]) -> str: """ Coerce a primitive data type into a string value for query params. @@ -100,5 +100,5 @@ def get_netrc_login(host: str) -> typing.Optional[typing.Tuple[str, str, str]]: if netrc_path is None: return None - netrc_info = netrc.netrc(netrc_path) + netrc_info = netrc.netrc(str(netrc_path)) return netrc_info.authenticators(host) # type: ignore diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000..a63d620c --- /dev/null +++ b/noxfile.py @@ -0,0 +1,60 @@ +import nox + +source_files = ("httpx", "tests", "setup.py", "noxfile.py") + + +@nox.session(reuse_venv=True) +def lint(session): + session.install("autoflake", "black", "flake8", "isort", "seed-isort-config") + + session.run("autoflake", "--in-place", "--recursive", *source_files) + session.run("seed-isort-config", "--application-directories=httpx") + session.run( + "isort", + "--project=httpx", + "--multi-line=3", + "--trailing-comma", + "--force-grid-wrap=0", + "--combine-as", + "--line-width=88", + "--recursive", + "--apply", + *source_files, + ) + session.run("black", "--target-version=py36", *source_files) + + check(session) + + +@nox.session(reuse_venv=True) +def check(session): + session.install("black", "flake8", "flake8-bugbear", "mypy") + + session.run("black", "--check", "--target-version=py36", *source_files) + session.run( + "flake8", "--max-line-length=88", "--ignore=W503,E203,B305", *source_files + ) + session.run("mypy", "httpx", "--ignore-missing-imports", "--disallow-untyped-defs") + + +@nox.session(reuse_venv=True) +def docs(session): + session.install("mkdocs", "mkdocs-material") + + session.run("mkdocs", "build") + + +@nox.session(python=["3.6", "3.7", "3.8"]) +def test(session): + session.install("-r", "test-requirements.txt") + + session.run( + "coverage", + "run", + "--omit='*'", + "-m", + "pytest", + "--cov=httpx", + "--cov=tests", + "--cov-report=term-missing", + ) diff --git a/scripts/install b/scripts/install deleted file mode 100755 index d263b44f..00000000 --- a/scripts/install +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -e - -# Use the Python executable provided from the `-p` option, or a default. -[[ $1 = "-p" ]] && PYTHON=$2 || PYTHON="python3" - -MIN_VERSION="(3, 6)" -VERSION_OK=`"$PYTHON" -c "import sys; print(sys.version_info[0:2] >= $MIN_VERSION and '1' or '');"` - -if [[ -z "$VERSION_OK" ]] ; then - PYTHON_VERSION=`"$PYTHON" -c "import sys; print('%s.%s' % sys.version_info[0:2]);"` - DISP_MIN_VERSION=`"$PYTHON" -c "print('%s.%s' % $MIN_VERSION)"` - echo "ERROR: Python $PYTHON_VERSION detected, but $DISP_MIN_VERSION+ is required." - echo "Please upgrade your Python distribution to install Databases." - exit 1 -fi - -REQUIREMENTS="requirements.txt" -VENV="venv" -PIP="$VENV/bin/pip" - -set -x -"$PYTHON" -m venv "$VENV" -"$PIP" install -r "$REQUIREMENTS" -"$PIP" install -e . diff --git a/scripts/lint b/scripts/lint deleted file mode 100755 index a1b85cce..00000000 --- a/scripts/lint +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -e - -export PREFIX="" -if [ -d 'venv' ] ; then - export PREFIX="venv/bin/" -fi - -set -x - -${PREFIX}autoflake --in-place --recursive httpx tests setup.py -${PREFIX}isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --apply httpx tests setup.py -${PREFIX}black httpx tests setup.py -${PREFIX}flake8 --max-line-length=88 --ignore=W503,E203,B305 httpx tests setup.py -${PREFIX}mypy httpx --ignore-missing-imports --disallow-untyped-defs - -scripts/clean diff --git a/scripts/test b/scripts/test deleted file mode 100755 index 626d43e9..00000000 --- a/scripts/test +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -e - -export PACKAGE="httpx" -export PREFIX="" -if [ -d 'venv' ] ; then - export PREFIX="venv/bin/" -fi - -set -x - -PYTHONPATH=. ${PREFIX}pytest --ignore venv --cov tests --cov ${PACKAGE} --cov-report= ${@} -${PREFIX}coverage report --show-missing --fail-under=100 diff --git a/requirements.txt b/test-requirements.txt similarity index 77% rename from requirements.txt rename to test-requirements.txt index e7400b09..089189b3 100644 --- a/requirements.txt +++ b/test-requirements.txt @@ -9,13 +9,6 @@ rfc3986==1.* # Optional brotlipy==0.7.* -# Documentation -mkdocs -mkdocs-material - -# Testing -autoflake -black cryptography flake8 flake8-bugbear diff --git a/tests/models/test_url.py b/tests/models/test_url.py index 7cbfc1c9..80542db9 100644 --- a/tests/models/test_url.py +++ b/tests/models/test_url.py @@ -1,5 +1,4 @@ import pytest -import rfc3986 from httpx import URL from httpx.exceptions import InvalidURL diff --git a/tests/test_utils.py b/tests/test_utils.py index 96d186b5..a6085fc7 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -37,7 +37,7 @@ def test_bad_utf_like_encoding(): ), ) def test_guess_by_bom(encoding, expected): - data = u"\ufeff{}".encode(encoding) + data = "\ufeff{}".encode(encoding) assert guess_json_utf(data) == expected