Include mypy in noxfile and add ssl_match_hostname stubs
MODIFY
noxfile.py
noxfile.py
import os
import shutil
+import subprocess
import nox
+# Whenever type-hints are completed on a file it should be added here so that
+# this file will continue to be checked by mypy. Errors from other files are
+# ignored.
+STUB_FILES = {
+ "src/urllib3/packages/ssl_match_hostname/__init__.pyi",
+ "src/urllib3/packages/ssl_match_hostname/_implementation.pyi",
+}
+
+
def tests_impl(session, extras="socks,secure,brotli"):
# Install deps and the package itself.
session.install("-r", "dev-requirements.txt")
@@ -33,7 +43,7 @@ def tests_impl(session, extras="socks,secure,brotli"):
"--tb=native",
"--no-success-flaky-report",
*(session.posargs or ("test/",)),
- env={"PYTHONWARNINGS": "always::DeprecationWarning"}
+ env={"PYTHONWARNINGS": "always::DeprecationWarning"},
)
session.run("coverage", "combine")
session.run("coverage", "report", "-m")
@@ -67,7 +77,7 @@ def app_engine(session):
"-r",
"sx",
"test/appengine",
- *session.posargs
+ *session.posargs,
)
session.run("coverage", "combine")
session.run("coverage", "report", "-m")
@@ -93,6 +103,27 @@ def lint(session):
)
session.run("flake8", "setup.py", "docs", "dummyserver", "src", "test")
+ errors = []
+ popen = subprocess.Popen(
+ "mypy --strict src/urllib3",
+ env=session.env,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ )
+
+ mypy_output = ""
+ while popen.poll() is None:
+ mypy_output += popen.stdout.read(8192).decode()
+ mypy_output += popen.stdout.read().decode()
+
+ for line in mypy_output.split("\n"):
+ filepath = line.partition(":")[0]
+ if filepath in STUB_FILES:
+ errors.append(line)
+ if errors:
+ session.error("\n" + "\n".join(sorted(set(errors))))
+
@nox.session
def docs(session):

MODIFY
src/urllib3/packages/ssl_match_hostname/__init__.py
src/urllib3/packages/ssl_match_hostname/__init__.py
@@ -10,10 +10,10 @@ try:
except ImportError:
try:
# Backport of the function from a pypi module
- from backports.ssl_match_hostname import CertificateError, match_hostname
+ from backports.ssl_match_hostname import CertificateError, match_hostname # type: ignore
except ImportError:
# Our vendored copy
- from ._implementation import CertificateError, match_hostname
+ from ._implementation import CertificateError, match_hostname # type: ignore
# Not needed, but documenting what we provide.
__all__ = ("CertificateError", "match_hostname")

ADD
src/urllib3/packages/ssl_match_hostname/__init__.pyi
+import ssl
+
+CertificateError = ssl.CertificateError
+match_hostname = ssl.match_hostname

ADD
src/urllib3/packages/ssl_match_hostname/_implementation.pyi
+from typing import Dict, Tuple, Union
+
+# https://github.com/python/typeshed/blob/master/stdlib/2and3/ssl.pyi
+_PCTRTT = Tuple[Tuple[str, str], ...]
+_PCTRTTT = Tuple[_PCTRTT, ...]
+_PeerCertRetDictType = Dict[str, Union[str, _PCTRTTT, _PCTRTT]]
+_PeerCertRetType = Union[_PeerCertRetDictType, bytes, None]
+
+class CertificateError(ValueError): ...
+
+def match_hostname(cert: _PeerCertRetType, hostname: str) -> None: ...

Include mypy in noxfile and add ssl_match_hostname stubs