diff --git a/_travis/deploy.sh b/_travis/deploy.sh index 08f377ef..503f0723 100755 --- a/_travis/deploy.sh +++ b/_travis/deploy.sh @@ -2,6 +2,6 @@ set -exo pipefail -python3 -m pip install --upgrade twine +python3 -m pip install --upgrade twine wheel python3 setup.py sdist bdist_wheel python3 -m twine upload dist/* -u $PYPI_USERNAME -p $PYPI_PASSWORD --skip-existing diff --git a/dev-requirements.txt b/dev-requirements.txt index b9c867a8..9d391618 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,18 +1,16 @@ -mock==2.0.0 +mock==3.0.5 coverage~=4.5 -wheel==0.30.0 tornado==5.1.1 -PySocks==1.6.8 -pkginfo==1.4.2 +PySocks==1.7.1 +# https://github.com/Anorov/PySocks/issues/131 +win-inet-pton==1.1.0 +pytest==4.6.6 pytest-random-order==1.0.4;python_version>="3.5" pytest-timeout==1.3.3 -pytest==4.6.4 pytest-cov==2.7.1 h11==0.8.0 cryptography==2.6.1 - -# https://github.com/ionelmc/python-lazy-object-proxy/issues/30 -lazy-object-proxy==1.4.0 +flaky==3.6.1 # https://github.com/GoogleCloudPlatform/python-repo-tools/issues/23 pylint<2.0;python_version<="2.7" @@ -20,5 +18,7 @@ gcp-devrel-py-tools # optional dependencies, only intended for use with Python 3.5+ trio==0.3.0; python_version >= "3.5" +# https://github.com/mhammond/pywin32/issues/1439 +pywin32!=226; python_version >= "3.5" and os_name == 'nt' twisted[tls]==19.2.0; python_version >= "3.5" and os_name != 'nt' twisted[tls,windows_platform]==19.2.0; python_version >= "3.5" and os_name == 'nt' diff --git a/docs/index.rst b/docs/index.rst index 533b5822..42d306f8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -43,7 +43,7 @@ urllib3 can be installed with `pip `_:: Alternatively, you can grab the latest source code from `GitHub `_:: - $ git clone git://github.com/shazow/urllib3.git + $ git clone git://github.com/urllib3/urllib3.git $ python setup.py install Usage diff --git a/dummyserver/certs/client.csr b/dummyserver/certs/client.csr deleted file mode 100644 index 703d3510..00000000 --- a/dummyserver/certs/client.csr +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID1TCCAz6gAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UEBhMCRkkx -DjAMBgNVBAgTBWR1bW15MQ4wDAYDVQQHEwVkdW1teTEOMAwGA1UEChMFZHVtbXkx -DjAMBgNVBAsTBWR1bW15MREwDwYDVQQDEwhTbmFrZU9pbDEfMB0GCSqGSIb3DQEJ -ARYQZHVtbXlAdGVzdC5sb2NhbDAeFw0xMTEyMjIwNzU5NTlaFw0yMTEyMTgwNzU5 -NTlaMH8xCzAJBgNVBAYTAkZJMQ4wDAYDVQQIEwVkdW1teTEOMAwGA1UEBxMFZHVt -bXkxDjAMBgNVBAoTBWR1bW15MQ4wDAYDVQQLEwVkdW1teTEPMA0GA1UEAxMGY2xp -ZW50MR8wHQYJKoZIhvcNAQkBFhBjbGllbnRAbG9jYWxob3N0MIGfMA0GCSqGSIb3 -DQEBAQUAA4GNADCBiQKBgQDaITA/XCzviqjex+lJJP+pgmQQ+ncUf+PDaFw86kWh -cWuI2eSBVaIaP6SsxYgIODQTjqYGjRogsd1Nvx3gRdIMEagTfVQyVwfDfNp8aT8v -SY/wDYFjsD07asmjGvwiu0sLp4t/tMz+x5ELlU4+hGnmPInH6hLK150DqgbNmJus -3wIDAQABo4IBXDCCAVgwCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBLAwKwYJ -YIZIAYb4QgENBB4WHFRpbnlDQSBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O -BBYEFG71FCU2yisH1GyrcqYaPKVeTWxBMIG2BgNVHSMEga4wgauAFBl3fyNiYkJZ -Rft1ncdzcgS7MwotoYGHpIGEMIGBMQswCQYDVQQGEwJGSTEOMAwGA1UECBMFZHVt -bXkxDjAMBgNVBAcTBWR1bW15MQ4wDAYDVQQKEwVkdW1teTEOMAwGA1UECxMFZHVt -bXkxETAPBgNVBAMTCFNuYWtlT2lsMR8wHQYJKoZIhvcNAQkBFhBkdW1teUB0ZXN0 -LmxvY2FsggkAs+uxyi/hv+MwCQYDVR0SBAIwADAbBgNVHREEFDASgRBjbGllbnRA -bG9jYWxob3N0MAsGA1UdDwQEAwIFoDANBgkqhkiG9w0BAQUFAAOBgQDEwZmp3yE8 -R4U9Ob/IeEo6O3p0T4o7GNvufGksM/mELmzyC+Qh/Ul6fNn+IhdKWpo61sMZou+n -eOufXVouc8dGhQ1Qi5s0i51d/ouhfYNs+AGRcpwEieVjZhgE1XfrNwvvjIx3yPtK -m9LSmCtVKcTWqOHQywKn+G83a+7bsh835Q== ------END CERTIFICATE----- diff --git a/dummyserver/certs/client.key b/dummyserver/certs/client.key deleted file mode 100644 index 0d1c3434..00000000 --- a/dummyserver/certs/client.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDaITA/XCzviqjex+lJJP+pgmQQ+ncUf+PDaFw86kWhcWuI2eSB -VaIaP6SsxYgIODQTjqYGjRogsd1Nvx3gRdIMEagTfVQyVwfDfNp8aT8vSY/wDYFj -sD07asmjGvwiu0sLp4t/tMz+x5ELlU4+hGnmPInH6hLK150DqgbNmJus3wIDAQAB -AoGAKMMg+AYqo4z+57rl/nQ6jpu+RWn4zMzlbEPZUMzavEOsu8M0L3MoOs1/4YV8 -WUTffnQe1ISTyF5Uo82+MIX7rUtfJITFSQrIWe7AGdm6Nir8TQQ7fD97modXyAUx -69I9SQjQlseg5PCRCp/DfcBncvHeYuf8gAJK5FfC1VW1cQECQQDvzFNoGrwnsrtm -4gj1Kt0c20jkIYFN6iQ6Sjs/1fk1cXDeWzjPaa92zF+i+02Ma/eWJ0ZVrhisw6sv -zxGp+ByBAkEA6N4SpuGWytJqCRfwenQZ4Oa8mNcVo5ulGf/eUHVXvHewWxQ7xWRi -iWUj/z1byR9+yno8Yfd04kaNCPYN/ICZXwJAAf5//xCh2e6pkkx06J0Ho7LLI2KH -8b7tuDJf1cMQxHoCB0dY7JijZeiDLxbJ6U4IjA4djp7ZA67I4KfnLLOsgQJARLZS -dp+WKR7RXwGLWfasNCqhd8/veKlSnEtdxAv76Ya/qQBdaq9mS/hmGMh4Lu52MTTE -YHvuJ159+yjvk5Q2rQJABjlU1+GZqwv/7QM7GxfJO+GPI4PHv5Yji5s7LLu2c6dL -XY2XiTHQL9PnPrKp3+qDDzxjyej30lfz4he6E5pI+g== ------END RSA PRIVATE KEY----- diff --git a/dummyserver/certs/client.pem b/dummyserver/certs/client.pem deleted file mode 100644 index c8302bf2..00000000 --- a/dummyserver/certs/client.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDczCCAtygAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UEBhMCRkkx -DjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQHDAVkdW1teTEOMAwGA1UECgwFZHVtbXkx -DjAMBgNVBAsMBWR1bW15MREwDwYDVQQDDAhTbmFrZU9pbDEfMB0GCSqGSIb3DQEJ -ARYQZHVtbXlAdGVzdC5sb2NhbDAeFw0xMTEyMjIwNzU4NDBaFw0yMTEyMTgwNzU4 -NDBaMGExCzAJBgNVBAYTAkZJMQ4wDAYDVQQIDAVkdW1teTEOMAwGA1UEBwwFZHVt -bXkxDjAMBgNVBAoMBWR1bW15MQ4wDAYDVQQLDAVkdW1teTESMBAGA1UEAwwJbG9j -YWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXe3FqmCWvP8XPxqtT -+0bfL1Tvzvebi46k0WIcUV8bP3vyYiSRXG9ALmyzZH4GHY9UVs4OEDkCMDOBSezB -0y9ai/9doTNcaictdEBu8nfdXKoTtzrn+VX4UPrkH5hm7NQ1fTQuj1MR7yBCmYqN -3Q2Q+Efuujyx0FwBzAuy1aKYuwIDAQABo4IBGDCCARQwCQYDVR0TBAIwADAdBgNV -HQ4EFgQUG+dK5Uos08QUwAWofDb3a8YcYlIwgbYGA1UdIwSBrjCBq4AUGXd/I2Ji -QllF+3Wdx3NyBLszCi2hgYekgYQwgYExCzAJBgNVBAYTAkZJMQ4wDAYDVQQIDAVk -dW1teTEOMAwGA1UEBwwFZHVtbXkxDjAMBgNVBAoMBWR1bW15MQ4wDAYDVQQLDAVk -dW1teTERMA8GA1UEAwwIU25ha2VPaWwxHzAdBgkqhkiG9w0BCQEWEGR1bW15QHRl -c3QubG9jYWyCCQCz67HKL+G/4zAJBgNVHRIEAjAAMCQGA1UdEQQdMBuBDnJvb3RA -bG9jYWxob3N0gglsb2NhbGhvc3QwDQYJKoZIhvcNAQEFBQADgYEAgcW6X1ZUyufm -TFEqEAdpKXdL0rxDwcsM/qqqsXbkz17otH6ujPhBEagzdKtgeNKfy0aXz6rWZugk -lF0IqyC4mcI+vvfgGR5Iy4KdXMrIX98MbrvGJBfbdKhGW2b84wDV42DIDiD2ZGGe -6YZQQIo9LxjuOTf9jsvf+PIkbI4H0To= ------END CERTIFICATE----- diff --git a/dummyserver/certs/intermediate.key b/dummyserver/certs/intermediate.key deleted file mode 100644 index 0b6cd739..00000000 --- a/dummyserver/certs/intermediate.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDEBOFnQ7PU5TqKefxH0VQZ0gxf1s8MrtvCHw2DouX+dAmgebcx -IBo3I4WlR2IOqw0x5Nr9/zfNoO8UEVioVvhsZXXaTCYzm4jjs4bx912pve8RH/q5 -Z8pdHLoUW8HDR9xiJuoROX/0KmD7LWAbj+kmZVCdA0EGoNp//bgC6Ol/uwIDAQAB -AoGAO76dEQNioWYItMI/cYhM0N3jpaZsTxpQotciIFgbL7YgZQgUHOYC94FdL6YV -LhFWoTl2wenzETqXBA/RbOWtK5wmpmu4Qy9Bq+r7FW296lyYOYyjuwz8AJD2kOTe -A9VjTJ9YBGxcbyI3/sSfF3tyNSyQZoh2AEIhsbKEmJPByzkCQQDhLbpvjkMAK5hq -P6TB4IwgK/dAF6fHdlDFCNfwhBvb1LiRe2OJMuPuAGlx+sMgiEiMntKoJrlE09NB -SnWnlaeHAkEA3tlmR+6GsEt6Quv4KgBMlJdVH/AYCba5eX/Ru5kz4WJwLCqJ5sik -V5wPt+lmgAsOLbivKXwuhb4p9WrBtOXLLQJANYOflhlyFN1HeKCtcCIESzUHqqS0 -i/OzWFA0uYU79a+FOZXgXt/ISWyxopPcwaOB0mGAYNPrHc9VmmOuuGgZiwJALFnR -/FDhZ2auH3F9A0bp9syjeWa8Mfq2sRKaOB7Gb326219f8JlP88uwaSa/ao5ItRrD -aZs4Ww+8pAYqJQlyxQJBANtJ14x0aOeFPY4MD7JdqRKxiQF4g9lL149yRGd+mRQC -OEonvmOrib8hGE6ivElMR3azEWCC3BcoKUxdplkY+Xw= ------END RSA PRIVATE KEY----- diff --git a/dummyserver/certs/intermediate.pem b/dummyserver/certs/intermediate.pem deleted file mode 100644 index 1e789cd7..00000000 --- a/dummyserver/certs/intermediate.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC3jCCAkegAwIBAgImMUFZJlNYl5MjhGJkM4MnlQKIQZcWk5k3UQWCCXSURZIw -eBZAYoYwDQYJKoZIhvcNAQELBQAwgYExCzAJBgNVBAYTAkZJMQ4wDAYDVQQIDAVk -dW1teTEOMAwGA1UEBwwFZHVtbXkxDjAMBgNVBAoMBWR1bW15MQ4wDAYDVQQLDAVk -dW1teTERMA8GA1UEAwwIU25ha2VPaWwxHzAdBgkqhkiG9w0BCQEWEGR1bW15QHRl -c3QubG9jYWwwHhcNMTcwNTEyMTgyMDUyWhcNMjExMjE5MTgyMDUyWjBxMQswCQYD -VQQGEwJGSTEOMAwGA1UECAwFZHVtbXkxDjAMBgNVBAoMBWR1bW15MQ4wDAYDVQQL -DAVkdW1teTERMA8GA1UEAwwIU25ha2VPaWwxHzAdBgkqhkiG9w0BCQEWEGR1bW15 -QHRlc3QubG9jYWwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQE4WdDs9Tl -Oop5/EfRVBnSDF/Wzwyu28IfDYOi5f50CaB5tzEgGjcjhaVHYg6rDTHk2v3/N82g -7xQRWKhW+GxlddpMJjObiOOzhvH3Xam97xEf+rlnyl0cuhRbwcNH3GIm6hE5f/Qq -YPstYBuP6SZlUJ0DQQag2n/9uALo6X+7AgMBAAGjUDBOMB0GA1UdDgQWBBSeW2ye -6HaaO2qoNaTZE1LALueMeTAfBgNVHSMEGDAWgBQZd38jYmJCWUX7dZ3Hc3IEuzMK -LTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAGnXyMzPPe5o4tYasY0K -A9sgxg42rH1gAeDJXeG4QqLoVi9JKbOBXdJGN9ZWD9K4EASknwWsa0TWSv291jHN -4+Uz8bHZ+4mH5HMpXZPsHorHR2te2XCZGMNE1V/1N0Q8qQk8CoxDSl5l5n67W9DY -iTQB1g/ymK3/hnTohqkFj9xd ------END CERTIFICATE----- diff --git a/dummyserver/server.py b/dummyserver/server.py index 1f899269..fdf95ec9 100755 --- a/dummyserver/server.py +++ b/dummyserver/server.py @@ -37,14 +37,6 @@ DEFAULT_CLIENT_CERTS = { "certfile": os.path.join(CERTS_PATH, "client_intermediate.pem"), "keyfile": os.path.join(CERTS_PATH, "client_intermediate.key"), - "subject": dict( - countryName=u"FI", - stateOrProvinceName=u"dummy", - organizationName=u"dummy", - organizationalUnitName=u"dummy", - commonName=u"SnakeOilClient", - emailAddress=u"dummy@test.local", - ), } DEFAULT_CLIENT_NO_INTERMEDIATE_CERTS = { "certfile": os.path.join(CERTS_PATH, "client_no_intermediate.pem"), @@ -86,7 +78,7 @@ def _has_ipv6(host): # has_ipv6 returns true if cPython was compiled with IPv6 support. # It does not tell us if the system has IPv6 support enabled. To # determine that we must bind to an IPv6 address. - # https://github.com/shazow/urllib3/pull/611 + # https://github.com/urllib3/urllib3/pull/611 # https://bugs.python.org/issue658327 try: sock = socket.socket(socket.AF_INET6) @@ -102,7 +94,7 @@ def _has_ipv6(host): # Some systems may have IPv6 support but DNS may not be configured # properly. We can not count that localhost will resolve to ::1 on all -# systems. See https://github.com/shazow/urllib3/pull/611 and +# systems. See https://github.com/urllib3/urllib3/pull/611 and # https://bugs.python.org/issue18792 HAS_IPV6_AND_DNS = _has_ipv6("localhost") HAS_IPV6 = _has_ipv6("::1") diff --git a/dummyserver/testcase.py b/dummyserver/testcase.py index afa8ac4c..8901ef52 100644 --- a/dummyserver/testcase.py +++ b/dummyserver/testcase.py @@ -15,8 +15,13 @@ def consume_socket(sock, chunks=65536): - while not sock.recv(chunks).endswith(b"\r\n\r\n"): - pass + consumed = bytearray() + while True: + b = sock.recv(chunks) + consumed += b + if b.endswith(b"\r\n\r\n"): + break + return consumed class SocketDummyServerTestCase(object): diff --git a/noxfile.py b/noxfile.py index 464b0e20..e0239b44 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,93 +1,95 @@ -import os -import shutil - -import nox - - -def tests_impl(session, extras="socks,secure,brotli"): - # Install deps and the package itself. - session.install("-r", "dev-requirements.txt") - session.install(".[{extras}]".format(extras=extras)) - - # Show the pip version. - session.run("pip", "--version") - # Print the Python version and bytesize. - session.run("python", "--version") - session.run("python", "-c", "import struct; print(struct.calcsize('P') * 8)") - # Print OpenSSL information. - session.run("python", "-m", "OpenSSL.debug") - - session.run( - "pytest", - "-r", - "a", - "--cov=urllib3", - *(session.posargs or ("test/",)), - env={"PYTHONWARNINGS": "always::DeprecationWarning"} - ) - session.run("coverage", "xml") - session.run("python", "cleancov.py", "coverage.xml") - - -@nox.session(python=["2.7", "3.4", "3.5", "3.6", "3.7", "3.8", "pypy"]) -def test(session): - tests_impl(session) - - -@nox.session(python=["2", "3"]) -def google_brotli(session): - # https://pypi.org/project/Brotli/ is the Google version of brotli, so - # install it separately and don't install our brotli extra (which installs - # brotlipy). - session.install("brotli") - tests_impl(session, extras="socks,secure") - - -@nox.session(python="2.7") -def app_engine(session): - session.install("-r", "dev-requirements.txt") - session.install(".") - session.run( - "coverage", - "run", - "--parallel-mode", - "-m", - "pytest", - "-r", - "sx", - "test/appengine", - *session.posargs - ) - session.run("coverage", "combine") - session.run("coverage", "report", "-m") - - -@nox.session() -def blacken(session): - """Run black code formater.""" - session.install("black") - session.run("black", "src", "dummyserver", "test", "noxfile.py", "setup.py") - - lint(session) - - -@nox.session -def lint(session): - session.install("flake8", "black") - session.run("flake8", "--version") - session.run("black", "--version") - session.run( - "black", "--check", "src", "dummyserver", "test", "noxfile.py", "setup.py" - ) - session.run("flake8", "setup.py", "docs", "dummyserver", "src", "test") - - -@nox.session -def docs(session): - session.install("-r", "docs/requirements.txt") - session.install(".[socks,secure,brotli]") - - session.chdir("docs") - if os.path.exists("_build"): - shutil.rmtree("_build") - session.run("sphinx-build", "-W", ".", "_build/html") +import os +import shutil + +import nox + + +def tests_impl(session, extras="socks,secure,brotli"): + # Install deps and the package itself. + session.install("-r", "dev-requirements.txt") + session.install(".[{extras}]".format(extras=extras)) + + # Show the pip version. + session.run("pip", "--version") + # Print the Python version and bytesize. + session.run("python", "--version") + session.run("python", "-c", "import struct; print(struct.calcsize('P') * 8)") + # Print OpenSSL information. + session.run("python", "-m", "OpenSSL.debug") + + session.run( + "pytest", + "-r", + "a", + "--tb=native", + "--cov=urllib3", + "--no-success-flaky-report", + *(session.posargs or ("test/",)), + env={"PYTHONWARNINGS": "always::DeprecationWarning"} + ) + session.run("coverage", "xml") + session.run("python", "cleancov.py", "coverage.xml") + + +@nox.session(python=["2.7", "3.4", "3.5", "3.6", "3.7", "3.8", "pypy"]) +def test(session): + tests_impl(session) + + +@nox.session(python=["2", "3"]) +def google_brotli(session): + # https://pypi.org/project/Brotli/ is the Google version of brotli, so + # install it separately and don't install our brotli extra (which installs + # brotlipy). + session.install("brotli") + tests_impl(session, extras="socks,secure") + + +@nox.session(python="2.7") +def app_engine(session): + session.install("-r", "dev-requirements.txt") + session.install(".") + session.run( + "coverage", + "run", + "--parallel-mode", + "-m", + "pytest", + "-r", + "sx", + "test/appengine", + *session.posargs + ) + session.run("coverage", "combine") + session.run("coverage", "report", "-m") + + +@nox.session() +def blacken(session): + """Run black code formater.""" + session.install("black") + session.run("black", "src", "dummyserver", "test", "noxfile.py", "setup.py") + + lint(session) + + +@nox.session +def lint(session): + session.install("flake8", "black") + session.run("flake8", "--version") + session.run("black", "--version") + session.run( + "black", "--check", "src", "dummyserver", "test", "noxfile.py", "setup.py" + ) + session.run("flake8", "setup.py", "docs", "dummyserver", "src", "test") + + +@nox.session +def docs(session): + session.install("-r", "docs/requirements.txt") + session.install(".[socks,secure,brotli]") + + session.chdir("docs") + if os.path.exists("_build"): + shutil.rmtree("_build") + session.run("sphinx-build", "-W", ".", "_build/html") diff --git a/src/urllib3/_async/connection.py b/src/urllib3/_async/connection.py index acfb3d02..5e2aeb9b 100644 --- a/src/urllib3/_async/connection.py +++ b/src/urllib3/_async/connection.py @@ -402,7 +402,7 @@ async def _wrap_socket(self, sock, ssl_context, fingerprint, assert_hostname): "back to check for a `commonName` for now. This " "feature is being removed by major browsers and " "deprecated by RFC 2818. (See " - "https://github.com/shazow/urllib3/issues/497 for " + "https://github.com/urllib3/urllib3/issues/497 for " "details.)".format(self._host) ), SubjectAltNameWarning, diff --git a/src/urllib3/util/connection.py b/src/urllib3/util/connection.py index 43fdbb82..01d4eba1 100644 --- a/src/urllib3/util/connection.py +++ b/src/urllib3/util/connection.py @@ -115,7 +115,7 @@ def _has_ipv6(host): # has_ipv6 returns true if cPython was compiled with IPv6 support. # It does not tell us if the system has IPv6 support enabled. To # determine that we must bind to an IPv6 address. - # https://github.com/shazow/urllib3/pull/611 + # https://github.com/urllib3/urllib3/pull/611 # https://bugs.python.org/issue658327 try: sock = socket.socket(socket.AF_INET6) diff --git a/test/__init__.py b/test/__init__.py index c89d0126..c9a9806a 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -127,8 +127,8 @@ def requires_network(test): def _is_unreachable_err(err): return getattr(err, "errno", None) in ( errno.ENETUNREACH, - errno.EHOSTUNREACH, - ) # For OSX + errno.EHOSTUNREACH, # For OSX + ) def _has_route(): try: diff --git a/test/contrib/test_socks.py b/test/contrib/test_socks.py index 259baac7..7e76ef62 100644 --- a/test/contrib/test_socks.py +++ b/test/contrib/test_socks.py @@ -442,12 +442,9 @@ def request_handler(listener): with socks.SOCKSProxyManager( proxy_url, username="user", password="badpass" ) as pm: - try: + with pytest.raises(NewConnectionError) as e: pm.request("GET", "http://example.com", retries=False) - except NewConnectionError as e: - assert "SOCKS5 authentication failed" in str(e) - else: - self.fail("Did not raise") + assert "SOCKS5 authentication failed" in str(e.value) def test_source_address_works(self): expected_port = _get_free_port(self.host) @@ -657,12 +654,9 @@ def request_handler(listener): self._start_server(request_handler) proxy_url = "socks4a://%s:%s" % (self.host, self.port) with socks.SOCKSProxyManager(proxy_url, username="baduser") as pm: - try: + with pytest.raises(NewConnectionError) as e: pm.request("GET", "http://example.com", retries=False) - except NewConnectionError as e: - assert "different user-ids" in str(e) - else: - self.fail("Did not raise") + assert "different user-ids" in str(e.value) class TestSOCKSWithTLS(IPV4SocketDummyServerTestCase): diff --git a/test/test_connectionpool.py b/test/test_connectionpool.py index d0e9ffe2..75cf3bc5 100644 --- a/test/test_connectionpool.py +++ b/test/test_connectionpool.py @@ -285,7 +285,7 @@ def _test(exception, expect, reason=None): # The pool should never be empty, and with these two exceptions # being raised, a retry will be triggered, but that retry will # fail, eventually raising MaxRetryError, not EmptyPoolError - # See: https://github.com/shazow/urllib3/issues/76 + # See: https://github.com/urllib3/urllib3/issues/76 pool._make_request = lambda *args, **kwargs: _raise( h11.RemoteProtocolError, "" ) @@ -421,7 +421,7 @@ def test_release_after_http_error_retry(self): would be released if the initial request failed, even if a retry succeeded. - [1] + [1] """ class _raise_once_make_request_function(object): diff --git a/test/test_queue_monkeypatch.py b/test/test_queue_monkeypatch.py index b37af394..4ebad62b 100644 --- a/test/test_queue_monkeypatch.py +++ b/test/test_queue_monkeypatch.py @@ -20,12 +20,12 @@ class BadError(Exception): class TestMonkeypatchResistance(object): """ Test that connection pool works even with a monkey patched Queue module, - see obspy/obspy#1599, kennethreitz/requests#3742, shazow/urllib3#1061. + see obspy/obspy#1599, psf/requests#3742, urllib3/urllib3#1061. """ def test_queue_monkeypatching(self): with mock.patch.object(queue, "Empty", BadError): with HTTPConnectionPool(host="localhost", block=True) as http: - http._get_conn(timeout=1) + http._get_conn() with pytest.raises(EmptyPoolError): - http._get_conn(timeout=1) + http._get_conn(timeout=0) diff --git a/test/test_sync_connection.py b/test/test_sync_connection.py index 1ff15064..3c6be18a 100644 --- a/test/test_sync_connection.py +++ b/test/test_sync_connection.py @@ -136,7 +136,7 @@ def send(self, data): if event is not EVENT_SEND: raise ScenarioError("Expected EVENT_SEND, got %s" % event) - amount, = args + (amount,) = args self._raise_errors(amount) if amount is SEND_ALL: amount = len(data) @@ -152,7 +152,7 @@ def recv(self, amt): if event is not EVENT_RECV: raise ScenarioError("Expected EVENT_RECV, got %s" % event) - amount, = args + (amount,) = args self._raise_errors(amount) if amount is RECV_ALL: amount = min(len(RESPONSE), amt) diff --git a/test/with_dummyserver/test_chunked_transfer.py b/test/with_dummyserver/test_chunked_transfer.py index 63fe89de..48176f78 100644 --- a/test/with_dummyserver/test_chunked_transfer.py +++ b/test/with_dummyserver/test_chunked_transfer.py @@ -1,9 +1,14 @@ # -*- coding: utf-8 -*- +import pytest + from urllib3 import HTTPConnectionPool from urllib3.exceptions import InvalidBodyError -from dummyserver.testcase import SocketDummyServerTestCase -import pytest +from urllib3.util.retry import Retry +from dummyserver.testcase import SocketDummyServerTestCase, consume_socket + +# Retry failed tests +pytestmark = pytest.mark.flaky class TestChunkedTransfer(SocketDummyServerTestCase): @@ -97,3 +102,28 @@ def test_provides_default_host_header(self): host_headers = [x for x in header_lines if x.startswith(b"host")] assert len(host_headers) == 1 + + def test_preserve_chunked_on_retry(self): + self.chunked_requests = 0 + + def socket_handler(listener): + for _ in range(2): + sock = listener.accept()[0] + request = consume_socket(sock) + if b"transfer-encoding: chunked" in request.split(b"\r\n"): + self.chunked_requests += 1 + + sock.send(b"HTTP/1.1 404 Not Found\r\n\r\n") + sock.close() + + self._start_server(socket_handler) + with HTTPConnectionPool(self.host, self.port) as pool: + retries = Retry(total=1, raise_on_status=False, status_forcelist=[404]) + pool.urlopen( + "GET", + "/", + body=iter([b"chunk1", b"chunk2"]), + preload_content=False, + retries=retries, + ) + assert self.chunked_requests == 2 diff --git a/test/with_dummyserver/test_connectionpool.py b/test/with_dummyserver/test_connectionpool.py index 071eab61..29678b10 100644 --- a/test/with_dummyserver/test_connectionpool.py +++ b/test/with_dummyserver/test_connectionpool.py @@ -26,6 +26,8 @@ from threading import Event +pytestmark = pytest.mark.flaky + log = logging.getLogger("urllib3.connectionpool") log.setLevel(logging.NOTSET) log.addHandler(logging.StreamHandler(sys.stdout)) @@ -69,9 +71,8 @@ def test_conn_closed(self): conn = pool._get_conn() pool._put_conn(conn) try: - pool.urlopen("GET", "/") - self.fail("The request should fail with a timeout error.") - except ReadTimeoutError: + with pytest.raises(ReadTimeoutError): + pool.urlopen("GET", "/") if conn._sock: with pytest.raises(socket.error): conn.sock.recv(1024) @@ -373,11 +374,9 @@ def test_connection_error_retries(self): """ ECONNREFUSED error should raise a connection error, with retries """ port = find_unused_port() with HTTPConnectionPool(self.host, port) as pool: - try: + with pytest.raises(MaxRetryError) as e: pool.request("GET", "/", retries=Retry(connect=3)) - self.fail("Should have failed with a connection error.") - except MaxRetryError as e: - assert type(e.reason) == NewConnectionError + assert type(e.value.reason) == NewConnectionError def test_timeout_success(self): timeout = Timeout(connect=3, read=5, total=None) @@ -396,11 +395,9 @@ def test_timeout_success(self): def test_bad_connect(self): with HTTPConnectionPool("badhost.invalid", self.port) as pool: - try: + with pytest.raises(MaxRetryError) as e: pool.request("GET", "/", retries=5) - self.fail("should raise timeout exception here") - except MaxRetryError as e: - assert type(e.reason) == NewConnectionError + assert type(e.value.reason) == NewConnectionError def test_keepalive(self): with HTTPConnectionPool(self.host, self.port, block=True, maxsize=1) as pool: diff --git a/test/with_dummyserver/test_https.py b/test/with_dummyserver/test_https.py index 0b4b4525..ad6cd8cb 100644 --- a/test/with_dummyserver/test_https.py +++ b/test/with_dummyserver/test_https.py @@ -55,6 +55,8 @@ from urllib3.util.timeout import Timeout import urllib3.util as util +# Retry failed tests +pytestmark = pytest.mark.flaky ResourceWarning = getattr( six.moves.builtins, "ResourceWarning", type("ResourceWarning", (), {}) @@ -277,54 +279,45 @@ def test_invalid_common_name(self): with HTTPSConnectionPool( "127.0.0.1", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA ) as https_pool: - try: + with pytest.raises(MaxRetryError) as e: https_pool.request("GET", "/") - self.fail("Didn't raise SSL invalid common name") - except MaxRetryError as e: - assert isinstance(e.reason, SSLError) - assert "doesn't match" in str( - e.reason - ) or "certificate verify failed" in str(e.reason) + assert isinstance(e.value.reason, SSLError) + assert "doesn't match" in str( + e.value.reason + ) or "certificate verify failed" in str(e.value.reason) def test_verified_with_bad_ca_certs(self): with HTTPSConnectionPool( self.host, self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA_BAD ) as https_pool: - try: + with pytest.raises(MaxRetryError) as e: https_pool.request("GET", "/") - self.fail("Didn't raise SSL error with bad CA certs") - except MaxRetryError as e: - assert isinstance(e.reason, SSLError) - assert "certificate verify failed" in str(e.reason), ( - "Expected 'certificate verify failed', instead got: %r" % e.reason - ) + assert isinstance(e.value.reason, SSLError) + assert "certificate verify failed" in str(e.value.reason), ( + "Expected 'certificate verify failed', instead got: %r" % e.value.reason + ) def test_verified_without_ca_certs(self): # default is cert_reqs=None which is ssl.CERT_NONE with HTTPSConnectionPool( self.host, self.port, cert_reqs="CERT_REQUIRED" ) as https_pool: - try: + with pytest.raises(MaxRetryError) as e: https_pool.request("GET", "/") - self.fail( - "Didn't raise SSL error with no CA certs when" - "CERT_REQUIRED is set" - ) - except MaxRetryError as e: - assert isinstance(e.reason, SSLError) - # there is a different error message depending on whether or - # not pyopenssl is injected - assert ( - "No root certificates specified" in str(e.reason) - # PyPy sometimes uses all-caps here - or "certificate verify failed" in str(e.reason).lower() - or "invalid certificate chain" in str(e.reason) - ), ( - "Expected 'No root certificates specified', " - "'certificate verify failed', or " - "'invalid certificate chain', " - "instead got: %r" % e.reason - ) + assert isinstance(e.value.reason, SSLError) + # there is a different error message depending on whether or + # not pyopenssl is injected + assert ( + "No root certificates specified" in str(e.value.reason) + # PyPy sometimes uses all-caps here + or "certificate verify failed" in str(e.value.reason).lower() + or "invalid certificate chain" in str(e.value.reason) + ), ( + "Expected 'No root certificates specified', " + "'certificate verify failed', or " + "'invalid certificate chain', " + "instead got: %r" % e.value.reason + ) def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ diff --git a/test/with_dummyserver/test_no_ssl.py b/test/with_dummyserver/test_no_ssl.py index ce60adca..59d0bd50 100644 --- a/test/with_dummyserver/test_no_ssl.py +++ b/test/with_dummyserver/test_no_ssl.py @@ -3,13 +3,16 @@ Note: Import urllib3 inside the test functions to get the importblocker to work """ +import pytest from ..test_no_ssl import TestWithoutSSL from dummyserver.testcase import HTTPDummyServerTestCase, HTTPSDummyServerTestCase -import pytest import urllib3 +# Retry failed tests +pytestmark = pytest.mark.flaky + class TestHTTPWithoutSSL(HTTPDummyServerTestCase, TestWithoutSSL): @pytest.mark.skip( diff --git a/test/with_dummyserver/test_poolmanager.py b/test/with_dummyserver/test_poolmanager.py index 78af6fa1..f84db069 100644 --- a/test/with_dummyserver/test_poolmanager.py +++ b/test/with_dummyserver/test_poolmanager.py @@ -11,6 +11,9 @@ from urllib3.exceptions import MaxRetryError, NewConnectionError, UnrewindableBodyError from urllib3.util.retry import Retry, RequestHistory +# Retry failed tests +pytestmark = pytest.mark.flaky + class TestPoolManager(HTTPDummyServerTestCase): @classmethod @@ -82,7 +85,7 @@ def test_redirect_to_relative_url(self): def test_cross_host_redirect(self): with PoolManager() as http: cross_host_location = "%s/echo?a=b" % self.base_url_alt - try: + with pytest.raises(MaxRetryError): http.request( "GET", "%s/redirect" % self.base_url, @@ -90,12 +93,6 @@ def test_cross_host_redirect(self): timeout=1, retries=0, ) - self.fail( - "Request succeeded instead of raising an exception like it should." - ) - - except MaxRetryError: - pass r = http.request( "GET", @@ -109,8 +106,8 @@ def test_cross_host_redirect(self): def test_too_many_redirects(self): with PoolManager() as http: - try: - r = http.request( + with pytest.raises(MaxRetryError): + http.request( "GET", "%s/redirect" % self.base_url, fields={ @@ -119,14 +116,9 @@ def test_too_many_redirects(self): }, retries=1, ) - self.fail( - "Failed to raise MaxRetryError exception, returned %r" % r.status - ) - except MaxRetryError: - pass - try: - r = http.request( + with pytest.raises(MaxRetryError): + http.request( "GET", "%s/redirect" % self.base_url, fields={ @@ -135,11 +127,6 @@ def test_too_many_redirects(self): }, retries=Retry(total=None, redirect=1), ) - self.fail( - "Failed to raise MaxRetryError exception, returned %r" % r.status - ) - except MaxRetryError: - pass def test_redirect_cross_host_remove_headers(self): with PoolManager() as http: @@ -234,7 +221,7 @@ def test_raise_on_redirect(self): def test_raise_on_status(self): with PoolManager() as http: - try: + with pytest.raises(MaxRetryError): # the default is to raise r = http.request( "GET", @@ -242,13 +229,8 @@ def test_raise_on_status(self): fields={"status": "500 Internal Server Error"}, retries=Retry(total=1, status_forcelist=range(500, 600)), ) - self.fail( - "Failed to raise MaxRetryError exception, returned %r" % r.status - ) - except MaxRetryError: - pass - try: + with pytest.raises(MaxRetryError): # raise explicitly r = http.request( "GET", @@ -258,11 +240,6 @@ def test_raise_on_status(self): total=1, status_forcelist=range(500, 600), raise_on_status=True ), ) - self.fail( - "Failed to raise MaxRetryError exception, returned %r" % r.status - ) - except MaxRetryError: - pass # don't raise r = http.request( @@ -369,18 +346,13 @@ def setup_class(self): def test_max_retry(self): with PoolManager() as http: - try: - r = http.request( + with pytest.raises(MaxRetryError): + http.request( "GET", "%s/redirect" % self.base_url, fields={"target": "/"}, retries=0, ) - self.fail( - "Failed to raise MaxRetryError exception, returned %r" % r.status - ) - except MaxRetryError: - pass def test_disabled_retry(self): """ Disabled retries should disable redirect handling. """ @@ -708,11 +680,9 @@ def tell(self): headers = {"Content-Length": "8"} with PoolManager() as http: - try: + with pytest.raises(UnrewindableBodyError) as e: http.urlopen("PUT", url, headers=headers, body=body) - self.fail("PUT successful despite failed rewind.") - except UnrewindableBodyError as e: - assert "Unable to record file position for" in str(e) + assert "Unable to record file position for" in str(e.value) @pytest.mark.skipif(not HAS_IPV6, reason="IPv6 is not supported on this system") diff --git a/test/with_dummyserver/test_proxy_poolmanager.py b/test/with_dummyserver/test_proxy_poolmanager.py index cfefade2..9167110f 100644 --- a/test/with_dummyserver/test_proxy_poolmanager.py +++ b/test/with_dummyserver/test_proxy_poolmanager.py @@ -11,6 +11,9 @@ from urllib3.exceptions import MaxRetryError, SSLError, ProxyError, ConnectTimeoutError from urllib3.connectionpool import connection_from_url +# Retry failed tests +pytestmark = pytest.mark.flaky + class TestHTTPProxyManager(HTTPDummyProxyTestCase): @classmethod @@ -55,11 +58,9 @@ def test_proxy_conn_fail(self): with pytest.raises(MaxRetryError): http.request("GET", "%s/" % self.http_url) - try: + with pytest.raises(MaxRetryError) as e: http.request("GET", "%s/" % self.http_url) - self.fail("Failed to raise retry error.") - except MaxRetryError as e: - assert type(e.reason) == ProxyError + assert type(e.value.reason) == ProxyError def test_oldapi(self): with ProxyManager( @@ -76,14 +77,12 @@ def test_proxy_verified(self): self.proxy_url, cert_reqs="REQUIRED", ca_certs=DEFAULT_CA_BAD ) as http: https_pool = http._new_pool("https", self.https_host, self.https_port) - try: + with pytest.raises(MaxRetryError) as e: https_pool.request("GET", "/", retries=0) - self.fail("Didn't raise SSL error with wrong CA") - except MaxRetryError as e: - assert isinstance(e.reason, SSLError) - assert "certificate verify failed" in str(e.reason), ( - "Expected 'certificate verify failed', instead got: %r" % e.reason - ) + assert isinstance(e.value.reason, SSLError) + assert "certificate verify failed" in str(e.value.reason), ( + "Expected 'certificate verify failed', instead got: %r" % e.value.reason + ) with proxy_from_url( self.proxy_url, cert_reqs="REQUIRED", ca_certs=DEFAULT_CA @@ -97,12 +96,10 @@ def test_proxy_verified(self): ) as http: https_fail_pool = http._new_pool("https", "127.0.0.1", self.https_port) - try: + with pytest.raises(MaxRetryError) as e: https_fail_pool.request("GET", "/", retries=0) - self.fail("Didn't raise SSL invalid common name") - except MaxRetryError as e: - assert isinstance(e.reason, SSLError) - assert "doesn't match" in str(e.reason) + assert isinstance(e.value.reason, SSLError) + assert "doesn't match" in str(e.value.reason) def test_redirect(self): with proxy_from_url(self.proxy_url) as http: @@ -127,7 +124,7 @@ def test_redirect(self): def test_cross_host_redirect(self): with proxy_from_url(self.proxy_url) as http: cross_host_location = "%s/echo?a=b" % self.http_url_alt - try: + with pytest.raises(MaxRetryError): http.request( "GET", "%s/redirect" % self.http_url, @@ -135,10 +132,6 @@ def test_cross_host_redirect(self): timeout=1, retries=0, ) - self.fail("We don't want to follow redirects here.") - - except MaxRetryError: - pass r = http.request( "GET", @@ -152,7 +145,7 @@ def test_cross_host_redirect(self): def test_cross_protocol_redirect(self): with proxy_from_url(self.proxy_url, ca_certs=DEFAULT_CA) as http: cross_protocol_location = "%s/echo?a=b" % self.https_url - try: + with pytest.raises(MaxRetryError): http.request( "GET", "%s/redirect" % self.http_url, @@ -160,10 +153,6 @@ def test_cross_protocol_redirect(self): timeout=1, retries=0, ) - self.fail("We don't want to follow redirects here.") - - except MaxRetryError: - pass r = http.request( "GET", @@ -325,11 +314,9 @@ def test_proxy_pooling_ext(self): @requires_network def test_https_proxy_timeout(self): with proxy_from_url("https://{host}".format(host=TARPIT_HOST)) as https: - try: + with pytest.raises(MaxRetryError) as e: https.request("GET", self.http_url, timeout=0.001) - self.fail("Failed to raise retry error.") - except MaxRetryError as e: - assert type(e.reason) == ConnectTimeoutError + assert type(e.value.reason) == ConnectTimeoutError @pytest.mark.timeout(0.5) @requires_network @@ -337,11 +324,9 @@ def test_https_proxy_pool_timeout(self): with proxy_from_url( "https://{host}".format(host=TARPIT_HOST), timeout=0.001 ) as https: - try: + with pytest.raises(MaxRetryError) as e: https.request("GET", self.http_url) - self.fail("Failed to raise retry error.") - except MaxRetryError as e: - assert type(e.reason) == ConnectTimeoutError + assert type(e.value.reason) == ConnectTimeoutError def test_scheme_host_case_insensitive(self): """Assert that upper-case schemes and hosts are normalized.""" diff --git a/test/with_dummyserver/test_socketlevel.py b/test/with_dummyserver/test_socketlevel.py index 25ed1045..af87f98c 100644 --- a/test/with_dummyserver/test_socketlevel.py +++ b/test/with_dummyserver/test_socketlevel.py @@ -50,6 +50,9 @@ class MimeToolMessage(object): from test import fails_on_travis_gce, requires_ssl_context_keyfile_password +# Retry failed tests +pytestmark = pytest.mark.flaky + class TestCookies(SocketDummyServerTestCase): def test_multi_setcookie(self): @@ -227,16 +230,10 @@ def socket_handler(listener): with HTTPSConnectionPool( self.host, self.port, cert_reqs="REQUIRED", ca_certs=DEFAULT_CA ) as pool: - try: + with pytest.raises(MaxRetryError): pool.request("GET", "/", retries=0) - except MaxRetryError: done_receiving.set() - else: - done_receiving.set() - self.fail( - "Expected server to reject connection due to missing client " - "certificates" - ) + done_receiving.set() @requires_ssl_context_keyfile_password def test_client_cert_with_string_password(self): @@ -842,8 +839,7 @@ def socket_handler(listener): done_closing.set() # wait until the socket in our pool gets closed successful = complete.wait(timeout=1) - if not successful: - self.fail("Timed out waiting for connection close") + assert successful, "Timed out waiting for connection close" def test_release_conn_param_is_respected_after_timeout_retry(self): """For successful ```urlopen()```, the connection isn't released, even @@ -855,7 +851,7 @@ def test_release_conn_param_is_respected_after_timeout_retry(self): would be released if the initial request failed, even if a retry succeeded. - [1] + [1] """ def socket_handler(listener): @@ -1344,7 +1340,7 @@ def request(): with pytest.raises(MaxRetryError) as cm: request() assert isinstance(cm.value.reason, SSLError) - # Should not hang, see https://github.com/shazow/urllib3/issues/529 + # Should not hang, see https://github.com/urllib3/urllib3/issues/529 with pytest.raises(MaxRetryError): request()