Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Use pp.common.downcaseTokens for pyparsing v3 #209

Merged
merged 3 commits into from
Nov 2, 2021

Conversation

busunkim96
Copy link
Contributor

For #207.

Applies the patch @temoto shared in #207 (comment) and adjusts requirements.txt to install a compatible version of pyparsing based on the Python version.

@busunkim96
Copy link
Contributor Author

test_auth.py seems to pass on a local run.

env) busunkim@busunkim:~/github/httplib2$ pytest -sv tests/test_auth.py
================================================================================== test session starts ===================================================================================
platform linux -- Python 3.9.7, pytest-3.2.1, py-1.10.0, pluggy-0.4.0 -- /usr/local/google/home/busunkim/github/httplib2/env/bin/python3
cachedir: .cache
Using --randomly-seed=1635290136
rootdir: /usr/local/google/home/busunkim/github/httplib2, inifile: setup.cfg
plugins: xdist-1.20.0, timeout-1.2.0, randomly-1.2.1, forked-0.2, cov-2.5.1
timeout: 17.0s method: signal
collected 50 items                                                                                                                                                                        

tests/test_auth.py::test_basic debug: auth_parsed {'basic': {'token': 'am9lOk4lJjc7HhgzbSR9DGJ5WRozAjlaASBNVhVnJxoYdHNkLiw/E0xpXhg4N2YmTCJ/fwF5GnVNY2t7Vlxsdj09'}}
debug: first auth scheme='basic'
PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'}] PASSED
tests/test_auth.py::test_digest_next_nonce_nc debug: auth_parsed {'digest': {'username': 'joe', 'realm': 'httplib2 test', 'nonce': 'FrG3typ19gA6PhiqaBhlMq8sqqvSxj4mhLKQ8Ag=', 'uri': '/', 'algorithm': 'MD5', 'response': '0d58f218ebd6fff7042a9a83178fb1a3', 'qop': 'auth', 'nc': '00000001', 'cnonce': '740729028247c47e', 'opaque': 'FrG3typ2WgA6akJXtj+U+XKv37llfGNai2CiuC8='}}
debug: first auth scheme='digest'
debug: response1 authentication-info: qop=auth, rspauth="f8ee112a52d75e096dbcb9fdd1dea7f9", cnonce="740729028247c47e", nc=00000001
parsed: {'qop': 'auth', 'rspauth': 'f8ee112a52d75e096dbcb9fdd1dea7f9', 'cnonce': '740729028247c47e', 'nc': '00000001'}
debug: auth_parsed {'digest': {'username': 'joe', 'realm': 'httplib2 test', 'nonce': 'FrG3typ19gA6PhiqaBhlMq8sqqvSxj4mhLKQ8Ag=', 'uri': '/', 'algorithm': 'MD5', 'response': '72f42a98029cdad45f295e936517de64', 'qop': 'auth', 'nc': '00000002', 'cnonce': 'e85682e9b130b5ec', 'opaque': 'FrG3typ2WgA6akJXtj+U+XKv37llfGNai2CiuC8='}}
debug: first auth scheme='digest'
debug: auth_parsed {'digest': {'username': 'joe', 'realm': 'httplib2 test', 'nonce': 'FrG3typ19gA6PhiqaBhlMq8sqqvSxj4mhLKQ8Ag=', 'uri': '/', 'algorithm': 'MD5', 'response': 'b25e81c3c3688d09cf3cd3249a96bb4f', 'qop': 'auth', 'nc': '00000003', 'cnonce': 'd97b2c5ed08f6e43', 'opaque': 'FrG3typ2WgA6akJXtj+U+XKv37llfGNai2CiuC8='}}
debug: first auth scheme='digest'
debug: auth_parsed {'digest': {'username': 'joe', 'realm': 'httplib2 test', 'nonce': 'FrG3tysCWAA63mc7WdHy0vGoTh3PW71x8GL6dlE=', 'uri': '/', 'algorithm': 'MD5', 'response': '49c8f3bb3a0209272697bf966bc70455', 'qop': 'auth', 'nc': '00000001', 'cnonce': '5119827dfea3bc46', 'opaque': 'FrG3typ2WgA6akJXtj+U+XKv37llfGNai2CiuC8='}}
debug: first auth scheme='digest'
PASSED
tests/test_auth.py::test_digest_object_auth_info PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': ''}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me",other="fred" '}] PASSED
tests/test_auth.py::test_parse_www_authenticate_malformed[{'www-authenticate': 'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me", algorithm="MD5"'}] PASSED
tests/test_auth.py::test_benchmark_parse_www_authenticate[Basic realm="me", algorithm="MD5"] SKIPPED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': "Basic param='single quote'"}] PASSED
tests/test_auth.py::test_digest_object_with_opaque PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic REAlm="me" '}] PASSED
tests/test_auth.py::test_parse_www_authenticate_complexity x50: time=455.0us speed=9.1 us/op
x100: time=624.0us speed=6.2 us/op expected=18.2 us/op error=0.3
PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Test realm="a \\\\"test\\\\" realm"'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'}] PASSED
tests/test_auth.py::test_basic_for_domain debug: auth_parsed {'basic': {'token': 'am9lOk4lJjc7HhgzbSR9DGJ5WRozAjlaASBNVhVnJxoYdHNkLiw/E0xpXhg4N2YmTCJ/fwF5GnVNY2t7Vlxsdj09'}}
debug: first auth scheme='basic'
PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': ''}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': "Basic param='single quote'"}] PASSED
tests/test_auth.py::test_benchmark_parse_www_authenticate[Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"] SKIPPED
tests/test_auth.py::test_wsse_ok debug: auth_parsed {'wsse': {'profile': 'UsernameToken'}}
debug: first auth scheme='wsse'
debug: wsse_params {'username': 'user314', 'passworddigest': 'fTKaWNdTKU/vzNTR6mB0sbnvlis=', 'nonce': '740729028247c47e', 'created': '2021-10-26T23:15:37Z'}
debug: check client=fTKaWNdTKU/vzNTR6mB0sbnvlis= == real=fTKaWNdTKU/vzNTR6mB0sbnvlis=
PASSED
tests/test_auth.py::test_digest debug: auth_parsed {'digest': {'username': 'joe', 'realm': 'httplib2 test', 'nonce': 'FrG3ty6VTAA6siOK9sUYgyCnaeOf7HUn9L4dUow=', 'uri': '/', 'algorithm': 'MD5', 'response': '2a859767761bef586f493a350dd1c193', 'qop': 'auth', 'nc': '00000001', 'cnonce': '740729028247c47e', 'opaque': 'FrG3ty6VhwA6KpBa6903oAOLEQSnAuEIHfKDUnk='}}
debug: first auth scheme='digest'
PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Test realm="a \\\\"test\\\\" realm"'}] PASSED
tests/test_auth.py::test_benchmark_parse_www_authenticate[Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"] SKIPPED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'}] PASSED
tests/test_auth.py::test_digest_object_stale PASSED
tests/test_auth.py::test_credentials PASSED
tests/test_auth.py::test_benchmark_parse_www_authenticate[Bearer 0b79bab50daca910b000d4f1a2b675d604257e42] SKIPPED
tests/test_auth.py::test_digest_object PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me",other="fred" '}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'}] PASSED
tests/test_auth.py::test_basic_two_credentials debug: auth_parsed {'basic': {'token': 'ZnJlZDpMExAgExx1B0R+L1doQXd4ewYOfVFzOkxuXitRXzdvUGkdXhhqPVp7GWtiCAN1Hjogchc8YQ=='}}
debug: first auth scheme='basic'
debug: auth_parsed {'basic': {'token': 'ZnJlZDpMExAgExx1B0R+L1doQXd4ewYOfVFzOkxuXitRXzdvUGkdXhhqPVp7GWtiCAN1Hjogchc8YQ=='}}
debug: first auth scheme='basic'
debug: auth_parsed {'basic': {'token': 'am9lOk4lJjc7HhgzbSR9DGJ5WRozAjlaASBNVhVnJxoYdHNkLiw/E0xpXhg4N2YmTCJ/fwF5GnVNY2t7Vlxsdj09'}}
debug: first auth scheme='basic'
debug: auth_parsed {'basic': {'token': 'am9lOk4lJjc7HhgzbSR9DGJ5WRozAjlaASBNVhVnJxoYdHNkLiw/E0xpXhg4N2YmTCJ/fwF5GnVNY2t7Vlxsdj09'}}
debug: first auth scheme='basic'
debug: auth_parsed {'basic': {'token': 'ZnJlZDpMExAgExx1B0R+L1doQXd4ewYOfVFzOkxuXitRXzdvUGkdXhhqPVp7GWtiCAN1Hjogchc8YQ=='}}
debug: first auth scheme='basic'
PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic REAlm="me" '}] PASSED
tests/test_auth.py::test_wsse_algorithm PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me"'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me"'}] PASSED
tests/test_auth.py::test_digest_auth_stale debug: auth_parsed {'digest': {'username': 'joe', 'realm': 'httplib2 test', 'nonce': 'FrG3tzEBUwA68ZaqTFeAsiQvOqkBsibN2Ul4HB8=', 'uri': '/', 'algorithm': 'MD5', 'response': '8aa1f326b974ab6b32b700f45b197646', 'qop': 'auth', 'nc': '00000001', 'cnonce': '740729028247c47e', 'opaque': 'FrG3tzEBnAA6BjpWtDY6+87W7oOHgq9h879zeV0='}}
debug: first auth scheme='digest'
debug: auth_parsed {'digest': {'username': 'joe', 'realm': 'httplib2 test', 'nonce': 'FrG3tzEBUwA68ZaqTFeAsiQvOqkBsibN2Ul4HB8=', 'uri': '/', 'algorithm': 'MD5', 'response': 'adef6fff2ecb7035f82752a33b857dc4', 'qop': 'auth', 'nc': '00000002', 'cnonce': 'e85682e9b130b5ec', 'opaque': 'FrG3tzEBnAA6BjpWtDY6+87W7oOHgq9h879zeV0='}}
debug: first auth scheme='digest'
debug: auth_parsed {'digest': {'username': 'joe', 'realm': 'httplib2 test', 'nonce': 'FrG3tzFdpgA6owqS12s8MOqE91Xj7bXx38ElSG8=', 'uri': '/', 'algorithm': 'MD5', 'response': '67b3e0d5bbd4f01a226e71094f6eeb82', 'qop': 'auth', 'nc': '00000001', 'cnonce': 'd97b2c5ed08f6e43', 'opaque': 'FrG3tzEBnAA6BjpWtDY6+87W7oOHgq9h879zeV0='}}
debug: first auth scheme='digest'
PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm="MD5"'}] PASSED
tests/test_auth.py::test_wsse_invalid debug: auth_parsed {'wsse': {'profile': 'UsernameToken'}}
debug: first auth scheme='wsse'
debug: wsse_params {'username': 'user294', 'passworddigest': '3Mri76zy1ilTPFonE/TJR5K79J8=', 'nonce': '740729028247c47e', 'created': '2021-10-26T23:15:37Z'}
debug: check client=3Mri76zy1ilTPFonE/TJR5K79J8= == real=fTKaWNdTKU/vzNTR6mB0sbnvlis=
PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'}] PASSED

----------- coverage: platform linux, python 3.9.7-final-0 -----------
Name                           Stmts   Miss  Cover
--------------------------------------------------
python3/httplib2/__init__.py     923    540    41%
python3/httplib2/auth.py          40      3    92%
python3/httplib2/certs.py         29      8    72%
python3/httplib2/error.py         25      3    88%
python3/httplib2/iri2uri.py       41     18    56%
python3/httplib2/socks.py        244    201    18%
--------------------------------------------------
TOTAL                           1302    773    41%

================================================================================ short test summary info =================================================================================
SKIP [4] tests/test_auth.py:249: benchmark disabled by default, set env httplib2_test_bench=1

========================================================================== 46 passed, 4 skipped in 0.34 seconds ==========================================================================

python3/httplib2/auth.py Outdated Show resolved Hide resolved
@temoto
Copy link
Member

temoto commented Oct 27, 2021

Did you check pip freeze |fgrep pypars ?

Sorry IDK how you do that, this patch fails for me on two very different machines. Please wait until I restore CI.

(example)

________________________ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}] ________________________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'algorithm': 'MD5', 'realm': 'me'}}

it looks like lost captures.

Co-authored-by: Sergey Shepelev <temotor@gmail.com>
@busunkim96
Copy link
Contributor Author

It looks like I had an older pyparsing installed in my environment when I ran the tests locally yesterday. A bunch of tests now fail for me when I use pyparsing==3.0.3

(env) busunkim@busunkim:~/github/httplib2$ pytest -sv tests/test_auth.py
================================================ test session starts =================================================
platform linux -- Python 3.9.7, pytest-3.2.1, py-1.10.0, pluggy-0.4.0 -- /usr/local/google/home/busunkim/github/httplib2/env/bin/python3
cachedir: .cache
Using --randomly-seed=1635366827
rootdir: /usr/local/google/home/busunkim/github/httplib2, inifile: setup.cfg
plugins: xdist-1.20.0, timeout-1.2.0, randomly-1.2.1, forked-0.2, cov-2.5.1
timeout: 17.0s method: signal
collected 50 items                                                                                                    

tests/test_auth.py::test_benchmark_parse_www_authenticate[Basic realm="me", algorithm="MD5"] SKIPPED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': "Basic param='single quote'"}] FAILED
tests/test_auth.py::test_digest_object FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me", algorithm="MD5"'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'}] FAILED
tests/test_auth.py::test_benchmark_parse_www_authenticate[Bearer 0b79bab50daca910b000d4f1a2b675d604257e42] SKIPPED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic REAlm="me" '}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'}] FAILED
tests/test_auth.py::test_wsse_invalid debug: auth_parsed {'wsse': {}}
debug: first auth scheme='wsse'
debug: wsse_params {}
PASSED
tests/test_auth.py::test_wsse_ok debug: auth_parsed {'wsse': {}}
debug: first auth scheme='wsse'
debug: wsse_params {}
FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': "Basic param='single quote'"}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': ''}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Test realm="a \\\\"test\\\\" realm"'}] FAILED
tests/test_auth.py::test_credentials PASSED
tests/test_auth.py::test_wsse_algorithm PASSED
tests/test_auth.py::test_digest_object_stale FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'}] FAILED
tests/test_auth.py::test_basic_for_domain debug: auth_parsed {'basic': {'token': 'am9lOktTbnhdMDwZZh03bmFNPCwhKh48CxV6ZQ=='}}
debug: first auth scheme='basic'
PASSED
tests/test_auth.py::test_basic debug: auth_parsed {'basic': {'token': 'am9lOktTbnhdMDwZZh03bmFNPCwhKh48CxV6ZQ=='}}
debug: first auth scheme='basic'
PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_complexity FAILED
tests/test_auth.py::test_parse_www_authenticate_malformed[{'www-authenticate': 'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'}] PASSED
tests/test_auth.py::test_basic_two_credentials debug: auth_parsed {'basic': {'token': 'ZnJlZDoBPHRAfw1CLikWBVUSFhI9JAx3GHxgNW8JGlgzIBAyKQ1DAnt4Yl8jdiAraB4SZVE='}}
debug: first auth scheme='basic'
debug: auth_parsed {'basic': {'token': 'ZnJlZDoBPHRAfw1CLikWBVUSFhI9JAx3GHxgNW8JGlgzIBAyKQ1DAnt4Yl8jdiAraB4SZVE='}}
debug: first auth scheme='basic'
debug: auth_parsed {'basic': {'token': 'am9lOktTbnhdMDwZZh03bmFNPCwhKh48CxV6ZQ=='}}
debug: first auth scheme='basic'
debug: auth_parsed {'basic': {'token': 'am9lOktTbnhdMDwZZh03bmFNPCwhKh48CxV6ZQ=='}}
debug: first auth scheme='basic'
debug: auth_parsed {'basic': {'token': 'ZnJlZDoBPHRAfw1CLikWBVUSFhI9JAx3GHxgNW8JGlgzIBAyKQ1DAnt4Yl8jdiAraB4SZVE='}}
debug: first auth scheme='basic'
PASSED
tests/test_auth.py::test_digest_next_nonce_nc FAILED
tests/test_auth.py::test_digest FAILED
tests/test_auth.py::test_digest_object_auth_info FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Test realm="a \\\\"test\\\\" realm"'}] FAILED
tests/test_auth.py::test_benchmark_parse_www_authenticate[Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"] SKIPPED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'}] FAILED
tests/test_auth.py::test_digest_object_with_opaque FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm="MD5"'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'}] FAILED
tests/test_auth.py::test_digest_auth_stale FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me",other="fred" '}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me"'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': ''}] PASSED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me",other="fred" '}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me"'}] FAILED
tests/test_auth.py::test_benchmark_parse_www_authenticate[Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"] SKIPPED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'}] FAILED
tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic REAlm="me" '}] FAILED

----------- coverage: platform linux, python 3.9.7-final-0 -----------
Name                           Stmts   Miss  Cover
--------------------------------------------------
python3/httplib2/__init__.py     923    559    39%
python3/httplib2/auth.py          40     10    75%
python3/httplib2/certs.py         29      8    72%
python3/httplib2/error.py         25      3    88%
python3/httplib2/iri2uri.py       41     18    56%
python3/httplib2/socks.py        244    201    18%
--------------------------------------------------
TOTAL                           1302    799    39%

============================================== short test summary info ===============================================
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': "Basic param='single quote'"}]
FAIL tests/test_auth.py::test_digest_object
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me", algorithm="MD5"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic REAlm="me" '}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'}]
FAIL tests/test_auth.py::test_wsse_ok
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': "Basic param='single quote'"}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Test realm="a \\\\"test\\\\" realm"'}]
FAIL tests/test_auth.py::test_digest_object_stale
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_complexity
FAIL tests/test_auth.py::test_digest_next_nonce_nc
FAIL tests/test_auth.py::test_digest
FAIL tests/test_auth.py::test_digest_object_auth_info
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Test realm="a \\\\"test\\\\" realm"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'}]
FAIL tests/test_auth.py::test_digest_object_with_opaque
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm="MD5"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'}]
FAIL tests/test_auth.py::test_digest_auth_stale
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me",other="fred" '}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me",other="fred" '}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'}]
FAIL tests/test_auth.py::test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic REAlm="me" '}]
SKIP [4] tests/test_auth.py:249: benchmark disabled by default, set env httplib2_test_bench=1

====================================================== FAILURES ======================================================
_ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'digest': {}} == {'digest': {'algorithm...alm': 'myrealm', ...}}
E     Differing items:
E     {'digest': {}} != {'digest': {'algorithm': 'MD5', 'nonce': 'KBAA=3', 'qop': 'auth', 'realm': 'myrealm', ...}}
E     Full diff:
E     - {'digest': {}}
E     + {'digest': {'algorithm': 'MD5',
E     +             'nonce': 'KBAA=3',
E     +             'qop': 'auth',
E     +             'realm': 'myrealm',
E     +             'stale': 'true'}}
___________ test_parse_www_authenticate_correct[strict-{'www-authenticate': "Basic param='single quote'"}] ___________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   assert {'basic': {}} == {'basic': {'param': "'single"}}
E     Differing items:
E     {'basic': {}} != {'basic': {'param': "'single"}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'param': "'single"}}
_________________________________________________ test_digest_object _________________________________________________
tests/test_auth.py:300: in test_digest_object
    d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
python3/httplib2/__init__.py:555: in __init__
    self.A1 = "".join([self.credentials[0], ":", self.challenge["realm"], ":", self.credentials[1],])
E   KeyError: 'realm'
________ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me", algorithm="MD5"'}] ________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
_ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'t*!%#st': {}} == {'t*!%#st': {'realm':...en': 'quoted string'}}
E     Differing items:
E     {'t*!%#st': {}} != {'t*!%#st': {'realm': 'to*!%#en', 'to*!%#en': 'quoted string'}}
E     Full diff:
E     - {'t*!%#st': {}}
E     + {'t*!%#st': {'realm': 'to*!%#en', 'to*!%#en': 'quoted string'}}
_________ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}] _________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
_ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}, 'digest': {}} == {'basic': {'rea...': '2-comma-d'}}
E     Differing items:
E     {'digest': {}} != {'digest': {'nonce': 'c0c8ff1', 'qop': 'auth-int', 'realm': '2-comma-d'}}
E     {'basic': {}} != {'basic': {'realm': '2-comma-b'}}
E     Full diff:
E     - {'basic': {}, 'digest': {}}
E     + {'basic': {'realm': '2-comma-b'},
E     +  'digest': {'nonce': 'c0c8ff1', 'qop': 'auth-int', 'realm': '2-comma-d'}}
________________ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic REAlm="me" '}] ________________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'realm': 'me'}}
_ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'test': {}} == {'test': {'bar': 'bar',...o', 'qux': 'qux', ...}}
E     Differing items:
E     {'test': {}} != {'test': {'bar': 'bar', 'baz': 'baz', 'foo': 'foo', 'qux': 'qux', ...}}
E     Full diff:
E     - {'test': {}}
E     + {'test': {'bar': 'bar',
E     +           'baz': 'baz',
E     +           'foo': 'foo',
E     +           'qux': 'qux',
E     +           'realm': 'test realm'}}
____________________________________________________ test_wsse_ok ____________________________________________________
tests/test_auth.py:407: in test_wsse_ok
    assert response.status == 200
E   assert 401 == 200
E    +  where 401 = {'www-authenticate': 'wsse realm="httplib2 test", profile="UsernameToken"', 'content-length': '16', 'status': '401'}.status
___________ test_parse_www_authenticate_correct[relax-{'www-authenticate': "Basic param='single quote'"}] ____________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   assert {'basic': {}} == {'basic': {'param': "'single"}}
E     Differing items:
E     {'basic': {}} != {'basic': {'param': "'single"}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'param': "'single"}}
________ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm=MD5'}] _________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
_______ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Test realm="a \\\\"test\\\\" realm"'}] _______
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   assert {'test': {}} == {'test': {'realm': 'a "test" realm'}}
E     Differing items:
E     {'test': {}} != {'test': {'realm': 'a "test" realm'}}
E     Full diff:
E     - {'test': {}}
E     + {'test': {'realm': 'a "test" realm'}}
______________________________________________ test_digest_object_stale ______________________________________________
tests/test_auth.py:342: in test_digest_object_stale
    d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
python3/httplib2/__init__.py:555: in __init__
    self.A1 = "".join([self.credentials[0], ":", self.challenge["realm"], ":", self.credentials[1],])
E   KeyError: 'realm'
_ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'digest': {}} == {'digest': {'nonce': '..., 'realm': 'digest1'}}
E     Differing items:
E     {'digest': {}} != {'digest': {'nonce': '7102dd2', 'opaque': 'e9517f', 'qop': 'auth,auth-int', 'realm': 'digest1'}}
E     Full diff:
E     - {'digest': {}}
E     + {'digest': {'nonce': '7102dd2',
E     +             'opaque': 'e9517f',
E     +             'qop': 'auth,auth-int',
E     +             'realm': 'digest1'}}
_ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'digest': {}} == {'digest': {'nonce': '..., 'realm': 'digest1'}}
E     Differing items:
E     {'digest': {}} != {'digest': {'nonce': '7102dd2', 'opaque': 'e9517f', 'qop': 'auth,auth-int', 'realm': 'digest1'}}
E     Full diff:
E     - {'digest': {}}
E     + {'digest': {'nonce': '7102dd2',
E     +             'opaque': 'e9517f',
E     +             'qop': 'auth,auth-int',
E     +             'realm': 'digest1'}}
_______________________________________ test_parse_www_authenticate_complexity _______________________________________
tests/test_auth.py:238: in test_parse_www_authenticate_complexity
    time1 = min(check(n1) for _ in range(repeat))
tests/test_auth.py:238: in <genexpr>
    time1 = min(check(n1) for _ in range(repeat))
tests/test_auth.py:233: in check
    assert result == {"scheme": {"key": "value", "quoted": "foo=bar"}}
E   AssertionError: assert {'scheme': {}} == {'scheme': {'key': 'va... 'quoted': 'foo=bar'}}
E     Differing items:
E     {'scheme': {}} != {'scheme': {'key': 'value', 'quoted': 'foo=bar'}}
E     Full diff:
E     - {'scheme': {}}
E     + {'scheme': {'key': 'value', 'quoted': 'foo=bar'}}
_____________________________________________ test_digest_next_nonce_nc ______________________________________________
tests/test_auth.py:100: in test_digest_next_nonce_nc
    response1, _ = http.request(uri, "GET")
python3/httplib2/__init__.py:1725: in request
    (response, content) = self._request(
python3/httplib2/__init__.py:1450: in _request
    for authorization in self._auth_from_challenge(host, request_uri, headers, response, content):
python3/httplib2/__init__.py:1338: in _auth_from_challenge
    yield AUTH_SCHEME_CLASSES[scheme](cred, host, request_uri, headers, response, content, self)
python3/httplib2/__init__.py:555: in __init__
    self.A1 = "".join([self.credentials[0], ":", self.challenge["realm"], ":", self.credentials[1],])
E   KeyError: 'realm'
____________________________________________________ test_digest _____________________________________________________
tests/test_auth.py:85: in test_digest
    response, content = http.request(uri, "GET")
python3/httplib2/__init__.py:1725: in request
    (response, content) = self._request(
python3/httplib2/__init__.py:1450: in _request
    for authorization in self._auth_from_challenge(host, request_uri, headers, response, content):
python3/httplib2/__init__.py:1338: in _auth_from_challenge
    yield AUTH_SCHEME_CLASSES[scheme](cred, host, request_uri, headers, response, content, self)
python3/httplib2/__init__.py:555: in __init__
    self.A1 = "".join([self.credentials[0], ":", self.challenge["realm"], ":", self.credentials[1],])
E   KeyError: 'realm'
____________________________________________ test_digest_object_auth_info ____________________________________________
tests/test_auth.py:356: in test_digest_object_auth_info
    d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
python3/httplib2/__init__.py:555: in __init__
    self.A1 = "".join([self.credentials[0], ":", self.challenge["realm"], ":", self.credentials[1],])
E   KeyError: 'realm'
______ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Test realm="a \\\\"test\\\\" realm"'}] _______
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   assert {'test': {}} == {'test': {'realm': 'a "test" realm'}}
E     Differing items:
E     {'test': {}} != {'test': {'realm': 'a "test" realm'}}
E     Full diff:
E     - {'test': {}}
E     + {'test': {'realm': 'a "test" realm'}}
_ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {},...}, 'wsse': {}} == {'basic': {'re...lm': 'com3w'}}
E     Differing items:
E     {'wsse': {}} != {'wsse': {'profile': 'token', 'realm': 'com3w'}}
E     {'digest': {}} != {'digest': {'realm': 'com3d'}}
E     {'basic': {}} != {'basic': {'realm': 'com3b'}}
E     Full diff:
E     - {'basic': {}, 'digest': {}, 'wsse': {}}
E     + {'basic': {'realm': 'com3b'},
E     +  'digest': {'realm': 'com3d'},
E     +  'wsse': {'profile': 'token', 'realm': 'com3w'}}
_ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'test': {}} == {'test': {'bar': 'bar',...o', 'qux': 'qux', ...}}
E     Differing items:
E     {'test': {}} != {'test': {'bar': 'bar', 'baz': 'baz', 'foo': 'foo', 'qux': 'qux', ...}}
E     Full diff:
E     - {'test': {}}
E     + {'test': {'bar': 'bar',
E     +           'baz': 'baz',
E     +           'foo': 'foo',
E     +           'qux': 'qux',
E     +           'realm': 'test realm'}}
___________________________________________ test_digest_object_with_opaque ___________________________________________
tests/test_auth.py:321: in test_digest_object_with_opaque
    d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
python3/httplib2/__init__.py:555: in __init__
    self.A1 = "".join([self.credentials[0], ":", self.challenge["realm"], ":", self.credentials[1],])
E   KeyError: 'realm'
_______ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me", algorithm="MD5"'}] ________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'algorithm': 'MD5', 'realm': 'me'}}
_ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'t*!%#st': {}} == {'t*!%#st': {'realm':...en': 'quoted string'}}
E     Differing items:
E     {'t*!%#st': {}} != {'t*!%#st': {'realm': 'to*!%#en', 'to*!%#en': 'quoted string'}}
E     Full diff:
E     - {'t*!%#st': {}}
E     + {'t*!%#st': {'realm': 'to*!%#en', 'to*!%#en': 'quoted string'}}
_______________________________________________ test_digest_auth_stale _______________________________________________
tests/test_auth.py:130: in test_digest_auth_stale
    response, _ = http.request(uri, "GET")
python3/httplib2/__init__.py:1725: in request
    (response, content) = self._request(
python3/httplib2/__init__.py:1450: in _request
    for authorization in self._auth_from_challenge(host, request_uri, headers, response, content):
python3/httplib2/__init__.py:1338: in _auth_from_challenge
    yield AUTH_SCHEME_CLASSES[scheme](cred, host, request_uri, headers, response, content, self)
python3/httplib2/__init__.py:555: in __init__
    self.A1 = "".join([self.credentials[0], ":", self.challenge["realm"], ":", self.credentials[1],])
E   KeyError: 'realm'
_________ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me",other="fred" '}] _________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'other': 'fred', 'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'other': 'fred', 'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'other': 'fred', 'realm': 'me'}}
________________ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic realm="me"'}] ________________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'realm': 'me'}}
_________ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me",other="fred" '}] __________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'other': 'fred', 'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'other': 'fred', 'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'other': 'fred', 'realm': 'me'}}
________________ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Basic realm="me"'}] _________________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'realm': 'me'}}
_ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'digest': {}} == {'digest': {'algorithm...alm': 'myrealm', ...}}
E     Differing items:
E     {'digest': {}} != {'digest': {'algorithm': 'MD5', 'nonce': 'KBAA=3', 'qop': 'auth', 'realm': 'myrealm', ...}}
E     Full diff:
E     - {'digest': {}}
E     + {'digest': {'algorithm': 'MD5',
E     +             'nonce': 'KBAA=3',
E     +             'qop': 'auth',
E     +             'realm': 'myrealm',
E     +             'stale': 'true'}}
_ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}, 'digest': {}} == {'basic': {'rea...': '2-comma-d'}}
E     Differing items:
E     {'digest': {}} != {'digest': {'nonce': 'c0c8ff1', 'qop': 'auth-int', 'realm': '2-comma-d'}}
E     {'basic': {}} != {'basic': {'realm': '2-comma-b'}}
E     Full diff:
E     - {'basic': {}, 'digest': {}}
E     + {'basic': {'realm': '2-comma-b'},
E     +  'digest': {'nonce': 'c0c8ff1', 'qop': 'auth-int', 'realm': '2-comma-d'}}
_ test_parse_www_authenticate_correct[relax-{'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'}] _
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {},...}, 'wsse': {}} == {'basic': {'re...lm': 'com3w'}}
E     Differing items:
E     {'wsse': {}} != {'wsse': {'profile': 'token', 'realm': 'com3w'}}
E     {'digest': {}} != {'digest': {'realm': 'com3d'}}
E     {'basic': {}} != {'basic': {'realm': 'com3b'}}
E     Full diff:
E     - {'basic': {}, 'digest': {}, 'wsse': {}}
E     + {'basic': {'realm': 'com3b'},
E     +  'digest': {'realm': 'com3d'},
E     +  'wsse': {'profile': 'token', 'realm': 'com3w'}}
_______________ test_parse_www_authenticate_correct[strict-{'www-authenticate': 'Basic REAlm="me" '}] ________________
tests/test_auth.py:202: in test_parse_www_authenticate_correct
    assert httplib2.auth._parse_www_authenticate(headers) == info
E   AssertionError: assert {'basic': {}} == {'basic': {'realm': 'me'}}
E     Differing items:
E     {'basic': {}} != {'basic': {'realm': 'me'}}
E     Full diff:
E     - {'basic': {}}
E     + {'basic': {'realm': 'me'}}
================================== 35 failed, 11 passed, 4 skipped in 1.72 seconds ===================================

@busunkim96
Copy link
Contributor Author

I will circle back to this tomorrow to try to figure out why the parsing behavior has changed.

It looks like there have been a number of patch releases of pyparsing the past few days (https://pypi.org/project/pyparsing/#history) so it might also be an unintentional behavior changes.

@temoto
Copy link
Member

temoto commented Oct 28, 2021

Cool, glad to see consistent result. Problem was greedy challenges.

# test code
header = "basic realm=\"well\", sign n1234"
print([
    c.asDict()
    for c in auth.www_authenticate.parseString(header)
])
# pyparsing<3
[{'scheme': 'basic', 'params': {'realm': 'well'}}, {'scheme': 'sign', 'token': 'n1234'}]

# pyparsing>=3
[{'scheme': 'basic', 'realm': 'well', 'params': [['realm', 'well']]}, {'scheme': 'sign', 'token': 'n1234'}]

@ptmcg would you be so kind to help with updating this seemingly simple parser to pyparsing 3?

@busunkim96
Copy link
Contributor Author

busunkim96 commented Oct 28, 2021

I stepped through each of the 3.0.0 pre-releases and found the unit tests start to fail on 3.0.0b1.

The commit where the httplib2 unit tests begin to fail is pyparsing/pyparsing@3c495db.

It looks like the different output comes from changes on lines 4547 - 4550 in pyparsing/core.py. When I revert back to the older code the unit tests pass again.

image

In pyparsing<3 code seems to enter the if block which wrapped the results in an additional []. Now if the asDict flag is not enabled the additional wrapping doesn't happen, which alters the results.

@ptmcg
Copy link
Contributor

ptmcg commented Oct 28, 2021

Excellent! Thanks so much for chasing this down. I think this addresses at least one other issue as well.

@busunkim96
Copy link
Contributor Author

Opened pyparsing/pyparsing#324.

Thank you @ptmcg for maintaining pyparsing, and @temoto for maintaining httplib2!

@busunkim96
Copy link
Contributor Author

Unit tests all pass for me locally with pyparsing==3.0.4. This PR is ready for review.

Copy link
Member

@temoto temoto left a comment

Choose a reason for hiding this comment

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

LGTM

@temoto
Copy link
Member

temoto commented Nov 2, 2021

For pyparsing v3 support use httplib2>=0.20.2

@busunkim96 thank you very much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support pyparsing v3 (AttributeError downcaseTokens)
4 participants