httpie / cli

🥧 HTTPie CLI — modern, user-friendly command-line HTTP client for the API era. JSON support, colors, sessions, downloads, plugins & more.
https://httpie.io
BSD 3-Clause "New" or "Revised" License
33.56k stars 3.67k forks source link

Python 3.11 test failures: Different enum reprs and different cookie order #1410

Closed hroncok closed 1 year ago

hroncok commented 2 years ago

Checklist


Minimal reproduction code and steps

The tests are failing with Python 3.11.0b3.

  1. git clone httpie and cd into it, this is on the master branch @ 418b12bbd6072585118c06c5c4e17996d7f0b085
  2. python3.11 -m venv __venv__ and . __venv__/bin/activate
  3. pip install '.[test]'
  4. pytest tests/

Current result

============================= test session starts ==============================
platform linux -- Python 3.11.0b3, pytest-7.1.2, pluggy-1.0.0
rootdir: .../httpie, configfile: pytest.ini
plugins: mock-3.7.0, lazy-fixture-0.6.3, httpbin-1.0.2, forked-1.4.0, xdist-2.5.0
collected 1026 items

tests/test_auth.py ..........                                            [  0%]
tests/test_compress.py .......                                           [  1%]
tests/test_downloads.py ......                                           [  2%]
tests/test_errors.py ....                                                [  2%]
tests/test_httpie.py ...........s...............                         [  5%]
tests/test_json.py .                                                     [  5%]
tests/test_auth.py ..........                                            [  6%]
tests/test_compress.py .......                                           [  7%]
tests/test_downloads.py ......                                           [  7%]
tests/test_errors.py ....                                                [  7%]
tests/test_httpie.py ...........s...............                         [ 10%]
tests/test_json.py .                                                     [ 10%]
tests/test_auth.py .........                                             [ 11%]
tests/test_auth_plugins.py ....                                          [ 11%]
tests/test_binary.py ......                                              [ 12%]
tests/test_cli.py ..............F.......................                 [ 16%]
tests/test_cli_ui.py ....                                                [ 16%]
tests/test_cli_utils.py ..                                               [ 16%]
tests/test_compress.py ..                                                [ 17%]
tests/test_config.py ........s                                           [ 17%]
tests/test_cookie.py .                                                   [ 18%]
tests/test_cookie_on_redirects.py .....................                  [ 20%]
tests/test_defaults.py .................                                 [ 21%]
tests/test_downloads.py ....................                             [ 23%]
tests/test_encoding.py ................................................. [ 28%]
....                                                                     [ 28%]
tests/test_errors.py ....                                                [ 29%]
tests/test_exit_status.py .........                                      [ 30%]
tests/test_httpie.py ......................                              [ 32%]
tests/test_httpie_cli.py .....................................           [ 35%]
tests/test_json.py ..................................................... [ 41%]
........................................................................ [ 48%]
........................................................................ [ 55%]
........................................................................ [ 62%]
.......................                                                  [ 64%]
tests/test_meta.py ......                                                [ 64%]
tests/test_offline.py .........                                          [ 65%]
tests/test_output.py ......FF.FxXX...................................... [ 70%]
........................................................................ [ 77%]
.                                                                        [ 77%]
tests/test_parser_schema.py .                                            [ 77%]
tests/test_plugins_cli.py ......FFFF..F.F                                [ 79%]
tests/test_redirects.py ...x......                                       [ 80%]
tests/test_regressions.py ...                                            [ 80%]
tests/test_sessions.py .........................FF.F.................... [ 85%]
............                                                             [ 86%]
tests/test_ssl.py .ss.....pytest-httpbin server hit an exception serving request: EOF occurred in violation of protocol (_ssl.c:992)
attempting to ignore so the rest of the tests can run
............pytest-httpbin server hit an exception serving request: EOF occurred in violation of protocol (_ssl.c:992)
attempting to ignore so the rest of the tests can run
...                                [ 88%]
tests/test_stream.py ................                                    [ 90%]
tests/test_tokens.py ...................                                 [ 92%]
tests/test_transport_plugin.py .                                         [ 92%]
tests/test_update_warnings.py ............                               [ 93%]
tests/test_uploads.py ...........................                        [ 96%]
tests/test_windows.py s.                                                 [ 96%]
tests/test_xml.py .................                                      [ 98%]
tests/utils/matching/test_matching.py ....................               [100%]

=================================== FAILURES ===================================
_______________________ test_url_colon_slash_slash_only ________________________

    def test_url_colon_slash_slash_only():
        r = http('://', tolerate_error_exit_status=True)
>       assert r.stderr.strip() == "http: error: InvalidURL: Invalid URL 'http://': No host supplied"
E       AssertionError: assert 'http: LogLev...host supplied' == 'http: error:...host supplied'
E         - http: error: InvalidURL: Invalid URL 'http://': No host supplied
E         ?        ^^^^
E         + http: LogLevel.ERROR: InvalidURL: Invalid URL 'http://': No host supplied
E         ?       ++++ ^^^^^^^^^

tests/test_cli.py:192: AssertionError
----------------------------- Captured stderr call -----------------------------

http: LogLevel.ERROR: InvalidURL: Invalid URL 'http://': No host supplied

_____________ TestQuietFlag.test_quiet_with_check_status_non_zero ______________

self = <tests.test_output.TestQuietFlag object at 0x7ff4dcbdfe90>
httpbin = <pytest_httpbin.serve.Server object at 0x7ff4dcb5a4d0>

    def test_quiet_with_check_status_non_zero(self, httpbin):
        r = http(
            '--quiet', '--check-status', httpbin + '/status/500',
            tolerate_error_exit_status=True,
        )
>       assert 'http: warning: HTTP 500' in r.stderr
E       AssertionError: assert 'http: warning: HTTP 500' in '\nhttp: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR\n\n\n'
E        +  where '\nhttp: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR\n\n\n' = ''.stderr

tests/test_output.py:69: AssertionError
----------------------------- Captured stderr call -----------------------------
127.0.0.1 - - [07/Jun/2022 16:23:54] "GET /status/500 HTTP/1.1" 500 0

http: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR

___________ TestQuietFlag.test_quiet_with_check_status_non_zero_pipe ___________

self = <tests.test_output.TestQuietFlag object at 0x7ff4dcbe4650>
httpbin = <pytest_httpbin.serve.Server object at 0x7ff4dcb5a4d0>

    def test_quiet_with_check_status_non_zero_pipe(self, httpbin):
        r = http(
            '--quiet', '--check-status', httpbin + '/status/500',
            tolerate_error_exit_status=True,
            env=MockEnvironment(stdout_isatty=False)
        )
>       assert 'http: warning: HTTP 500' in r.stderr
E       AssertionError: assert 'http: warning: HTTP 500' in '\nhttp: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR\n\n\n'
E        +  where '\nhttp: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR\n\n\n' = ''.stderr

tests/test_output.py:77: AssertionError
----------------------------- Captured stderr call -----------------------------
127.0.0.1 - - [07/Jun/2022 16:23:54] "GET /status/500 HTTP/1.1" 500 0

http: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR

________ TestQuietFlag.test_quiet_quiet_with_check_status_non_zero_pipe ________

self = <tests.test_output.TestQuietFlag object at 0x7ff4dcbe5550>
httpbin = <pytest_httpbin.serve.Server object at 0x7ff4dcb5a4d0>

    def test_quiet_quiet_with_check_status_non_zero_pipe(self, httpbin):
        r = http(
            '--quiet', '--quiet', '--check-status', httpbin + '/status/500',
            tolerate_error_exit_status=True,
            env=MockEnvironment(stdout_isatty=False)
        )
>       assert 'http: warning: HTTP 500' in r.stderr
E       AssertionError: assert 'http: warning: HTTP 500' in '\nhttp: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR\n\n\n'
E        +  where '\nhttp: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR\n\n\n' = ''.stderr

tests/test_output.py:92: AssertionError
----------------------------- Captured stderr call -----------------------------
127.0.0.1 - - [07/Jun/2022 16:23:54] "GET /status/500 HTTP/1.1" 500 0

http: LogLevel.WARNING: HTTP 500 INTERNAL SERVER ERROR

_________________________ test_plugins_uninstall[True] _________________________

interface = Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_True_0/interface'), environment=<...out': <tempfile._TemporaryFileWrapper object at 0x7ff4d5c78410>,
 'stdout_encoding': 'utf-8',
 'stdout_isatty': True}>)
httpie_plugins_success = <function httpie_plugins_success.<locals>.runner at 0x7ff4d5cbe0c0>
dummy_plugin = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_True_0/interface...ue}>), name='httpie-4bef7587', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')])
cli_mode = True

    @pytest.mark.requires_installation
    @pytest.mark.parametrize('cli_mode', [True, False])
    def test_plugins_uninstall(interface, httpie_plugins_success, dummy_plugin, cli_mode):
        httpie_plugins_success('install', dummy_plugin.path, cli_mode=cli_mode)
        httpie_plugins_success('uninstall', dummy_plugin.name, cli_mode=cli_mode)
>       assert not interface.is_installed(dummy_plugin.name)
E       AssertionError: assert not True
E        +  where True = <bound method Interface.is_installed of Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uni...ut': <tempfile._TemporaryFileWrapper object at 0x7ff4d5c78410>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>)>('httpie-4bef7587')
E        +    where <bound method Interface.is_installed of Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uni...ut': <tempfile._TemporaryFileWrapper object at 0x7ff4d5c78410>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>)> = Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_True_0/interface'), environment=<...out': <tempfile._TemporaryFileWrapper object at 0x7ff4d5c78410>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>).is_installed
E        +    and   'httpie-4bef7587' = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_True_0/interface...ue}>), name='httpie-4bef7587', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')]).name

tests/test_plugins_cli.py:59: AssertionError
________________________ test_plugins_uninstall[False] _________________________

interface = Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_False_0/interface'), environment=...out': <tempfile._TemporaryFileWrapper object at 0x7ff4d5c811d0>,
 'stdout_encoding': 'utf-8',
 'stdout_isatty': True}>)
httpie_plugins_success = <function httpie_plugins_success.<locals>.runner at 0x7ff4d5cac220>
dummy_plugin = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_False_0/interfac...ue}>), name='httpie-300cc8fa', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')])
cli_mode = False

    @pytest.mark.requires_installation
    @pytest.mark.parametrize('cli_mode', [True, False])
    def test_plugins_uninstall(interface, httpie_plugins_success, dummy_plugin, cli_mode):
        httpie_plugins_success('install', dummy_plugin.path, cli_mode=cli_mode)
        httpie_plugins_success('uninstall', dummy_plugin.name, cli_mode=cli_mode)
>       assert not interface.is_installed(dummy_plugin.name)
E       AssertionError: assert not True
E        +  where True = <bound method Interface.is_installed of Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uni...ut': <tempfile._TemporaryFileWrapper object at 0x7ff4d5c811d0>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>)>('httpie-300cc8fa')
E        +    where <bound method Interface.is_installed of Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uni...ut': <tempfile._TemporaryFileWrapper object at 0x7ff4d5c811d0>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>)> = Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_False_0/interface'), environment=...out': <tempfile._TemporaryFileWrapper object at 0x7ff4d5c811d0>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>).is_installed
E        +    and   'httpie-300cc8fa' = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_False_0/interfac...ue}>), name='httpie-300cc8fa', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')]).name

tests/test_plugins_cli.py:59: AssertionError
_____________________ test_plugins_listing_after_uninstall _____________________

interface = Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_listing_after_uni0/interface'), environment...out': <tempfile._TemporaryFileWrapper object at 0x7ff4d5dbc410>,
 'stdout_encoding': 'utf-8',
 'stdout_isatty': True}>)
httpie_plugins_success = <function httpie_plugins_success.<locals>.runner at 0x7ff4d5cd2200>
dummy_plugin = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_listing_after_uni0/interfa...ue}>), name='httpie-99a195f1', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')])

    @pytest.mark.requires_installation
    def test_plugins_listing_after_uninstall(interface, httpie_plugins_success, dummy_plugin):
        httpie_plugins_success('install', dummy_plugin.path)
        httpie_plugins_success('uninstall', dummy_plugin.name)

        data = parse_listing(httpie_plugins_success('list'))
>       assert len(data) == 0
E       AssertionError: assert 1 == 0
E        +  where 1 = len({'httpie-99a195f1': {'entry_points': [{'group': 'httpie.plugins.auth.v1', 'name': 'test'}], 'version': '1.0.0'}})

tests/test_plugins_cli.py:68: AssertionError
_______________________ test_plugins_uninstall_specific ________________________

interface = Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_specifi0/interface'), environment...out': <tempfile._TemporaryFileWrapper object at 0x7ff4d5cc8950>,
 'stdout_encoding': 'utf-8',
 'stdout_isatty': True}>)
httpie_plugins_success = <function httpie_plugins_success.<locals>.runner at 0x7ff4d5cd3560>

    @pytest.mark.requires_installation
    def test_plugins_uninstall_specific(interface, httpie_plugins_success):
        new_plugin_1 = interface.make_dummy_plugin()
        new_plugin_2 = interface.make_dummy_plugin()
        target_plugin = interface.make_dummy_plugin()

        httpie_plugins_success('install', new_plugin_1.path, new_plugin_2.path, target_plugin.path)
        httpie_plugins_success('uninstall', target_plugin.name)

        assert interface.is_installed(new_plugin_1.name)
        assert interface.is_installed(new_plugin_2.name)
>       assert not interface.is_installed(target_plugin.name)
E       AssertionError: assert not True
E        +  where True = <bound method Interface.is_installed of Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uni...ut': <tempfile._TemporaryFileWrapper object at 0x7ff4d5cc8950>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>)>('httpie-79b6b9b0')
E        +    where <bound method Interface.is_installed of Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uni...ut': <tempfile._TemporaryFileWrapper object at 0x7ff4d5cc8950>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>)> = Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_specifi0/interface'), environment...out': <tempfile._TemporaryFileWrapper object at 0x7ff4d5cc8950>,\n 'stdout_encoding': 'utf-8',\n 'stdout_isatty': True}>).is_installed
E        +    and   'httpie-79b6b9b0' = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_uninstall_specifi0/interfa...ue}>), name='httpie-79b6b9b0', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')]).name

tests/test_plugins_cli.py:82: AssertionError
________________________ test_plugins_double_uninstall _________________________

httpie_plugins = <function httpie_plugins.<locals>.runner at 0x7ff4d5cfa160>
httpie_plugins_success = <function httpie_plugins_success.<locals>.runner at 0x7ff4d5cfa3e0>
dummy_plugin = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_plugins_double_uninstall0/interfac...ue}>), name='httpie-6d157572', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')])

    @pytest.mark.requires_installation
    def test_plugins_double_uninstall(httpie_plugins, httpie_plugins_success, dummy_plugin):
        httpie_plugins_success("install", dummy_plugin.path)
        httpie_plugins_success("uninstall", dummy_plugin.name)

        result = httpie_plugins("uninstall", dummy_plugin.name)

>       assert result.exit_status == ExitStatus.ERROR
E       AssertionError: assert <ExitStatus.SUCCESS: 0> == <ExitStatus.ERROR: 1>
E        +  where <ExitStatus.SUCCESS: 0> = 'Successfully uninstalled httpie-6d157572\n'.exit_status
E        +  and   <ExitStatus.ERROR: 1> = ExitStatus.ERROR

tests/test_plugins_cli.py:113: AssertionError
_____________________________ test_broken_plugins ______________________________

httpie_plugins = <function httpie_plugins.<locals>.runner at 0x7ff4d6d29300>
httpie_plugins_success = <function httpie_plugins_success.<locals>.runner at 0x7ff4d76eb920>
dummy_plugin = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_broken_plugins0/interface'), envir...ue}>), name='httpie-8972797e', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')])
broken_plugin = Plugin(interface=Interface(path=PosixPath('/tmp/pytest-of-.../pytest-31/test_broken_plugins0/interface'), envir...ue}>), name='httpie-4cd7d933', version='1.0.0', entry_points=[EntryPoint(name='test', group='httpie.plugins.auth.v1')])

    @pytest.mark.requires_installation
    def test_broken_plugins(httpie_plugins, httpie_plugins_success, dummy_plugin, broken_plugin):
        httpie_plugins_success("install", dummy_plugin.path, broken_plugin.path)

        with pytest.warns(
            UserWarning,
            match=(
                f'While loading "{broken_plugin.name}", an error'
                ' occurred: broken plugin'
            )
        ):
            data = parse_listing(httpie_plugins_success('list'))
            assert len(data) == 2

        # We load before the uninstallation, so it will warn again.
        with pytest.warns(UserWarning):
            httpie_plugins_success("uninstall", broken_plugin.name)

        # No warning now, since it is uninstalled.
        data = parse_listing(httpie_plugins_success('list'))
>       assert len(data) == 1
E       AssertionError: assert 2 == 1
E        +  where 2 = len({'httpie-4cd7d933': {'entry_points': [{'group': 'httpie.plugins.auth.v1', 'name': 'test'}], 'version': '1.0.0'}, 'httpie-8972797e': {'entry_points': [{'group': 'httpie.plugins.auth.v1', 'name': 'test'}], 'version': '1.0.0'}})

tests/test_plugins_cli.py:153: AssertionError
_ TestCookieStorage.test_existing_and_new_cookies_sent_in_request[new=bar;chocolate=milk-new_cookies_dict1-chocolate=milk; cookie1=foo; cookie2=foo; new=bar] _

self = <tests.test_sessions.TestCookieStorage object at 0x7ff4dca91c10>
new_cookies = 'new=bar;chocolate=milk'
new_cookies_dict = {'chocolate': 'milk', 'new': 'bar'}
expected = 'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
httpbin = <pytest_httpbin.serve.Server object at 0x7ff4dcb5a4d0>

    @pytest.mark.parametrize(
        'new_cookies, new_cookies_dict, expected',
        [(
            'new=bar',
            {'new': 'bar'},
            'cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar;chocolate=milk',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar; chocolate=milk',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar;; chocolate=milk;;;',
            {'new': 'bar', 'chocolate': 'milk'},
            'cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar; chocolate=milk;;;',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        )
        ]
    )
    def test_existing_and_new_cookies_sent_in_request(self, new_cookies, new_cookies_dict, expected, httpbin):
        r = http(
            '--session', str(self.session_path),
            '--print=H',
            httpbin.url,
            'Cookie:' + new_cookies,
        )
        # Note: cookies in response are in alphabetical order
>       assert f'Cookie: {expected}' in r
E       AssertionError: assert 'Cookie: chocolate=milk; cookie1=foo; cookie2=foo; new=bar' in 'GET / HTTP/1.1\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nConnection: keep-alive\r\nCookie: cookie1=foo; cookie2=foo; new=bar; chocolate=milk\r\nHost: 127.0.0.1:38085\r\nUser-Agent: HTTPie/3.2.1\r\n\r\n'

tests/test_sessions.py:485: AssertionError
----------------------------- Captured stderr call -----------------------------
127.0.0.1 - - [07/Jun/2022 16:24:20] "GET / HTTP/1.1" 200 12144
_ TestCookieStorage.test_existing_and_new_cookies_sent_in_request[new=bar; chocolate=milk-new_cookies_dict2-chocolate=milk; cookie1=foo; cookie2=foo; new=bar] _

self = <tests.test_sessions.TestCookieStorage object at 0x7ff4dca91e90>
new_cookies = 'new=bar; chocolate=milk'
new_cookies_dict = {'chocolate': 'milk', 'new': 'bar'}
expected = 'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
httpbin = <pytest_httpbin.serve.Server object at 0x7ff4dcb5a4d0>

    @pytest.mark.parametrize(
        'new_cookies, new_cookies_dict, expected',
        [(
            'new=bar',
            {'new': 'bar'},
            'cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar;chocolate=milk',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar; chocolate=milk',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar;; chocolate=milk;;;',
            {'new': 'bar', 'chocolate': 'milk'},
            'cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar; chocolate=milk;;;',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        )
        ]
    )
    def test_existing_and_new_cookies_sent_in_request(self, new_cookies, new_cookies_dict, expected, httpbin):
        r = http(
            '--session', str(self.session_path),
            '--print=H',
            httpbin.url,
            'Cookie:' + new_cookies,
        )
        # Note: cookies in response are in alphabetical order
>       assert f'Cookie: {expected}' in r
E       AssertionError: assert 'Cookie: chocolate=milk; cookie1=foo; cookie2=foo; new=bar' in 'GET / HTTP/1.1\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nConnection: keep-alive\r\nCookie: cookie1=foo; cookie2=foo; new=bar; chocolate=milk\r\nHost: 127.0.0.1:38085\r\nUser-Agent: HTTPie/3.2.1\r\n\r\n'

tests/test_sessions.py:485: AssertionError
----------------------------- Captured stderr call -----------------------------
127.0.0.1 - - [07/Jun/2022 16:24:20] "GET / HTTP/1.1" 200 12144
_ TestCookieStorage.test_existing_and_new_cookies_sent_in_request[new=bar; chocolate=milk;;;-new_cookies_dict4-chocolate=milk; cookie1=foo; cookie2=foo; new=bar] _

self = <tests.test_sessions.TestCookieStorage object at 0x7ff4dca925d0>
new_cookies = 'new=bar; chocolate=milk;;;'
new_cookies_dict = {'chocolate': 'milk', 'new': 'bar'}
expected = 'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
httpbin = <pytest_httpbin.serve.Server object at 0x7ff4dcb5a4d0>

    @pytest.mark.parametrize(
        'new_cookies, new_cookies_dict, expected',
        [(
            'new=bar',
            {'new': 'bar'},
            'cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar;chocolate=milk',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar; chocolate=milk',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar;; chocolate=milk;;;',
            {'new': 'bar', 'chocolate': 'milk'},
            'cookie1=foo; cookie2=foo; new=bar'
        ),
            (
            'new=bar; chocolate=milk;;;',
            {'new': 'bar', 'chocolate': 'milk'},
            'chocolate=milk; cookie1=foo; cookie2=foo; new=bar'
        )
        ]
    )
    def test_existing_and_new_cookies_sent_in_request(self, new_cookies, new_cookies_dict, expected, httpbin):
        r = http(
            '--session', str(self.session_path),
            '--print=H',
            httpbin.url,
            'Cookie:' + new_cookies,
        )
        # Note: cookies in response are in alphabetical order
>       assert f'Cookie: {expected}' in r
E       AssertionError: assert 'Cookie: chocolate=milk; cookie1=foo; cookie2=foo; new=bar' in 'GET / HTTP/1.1\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nConnection: keep-alive\r\nCookie: cookie1=foo; cookie2=foo; new=bar; chocolate=milk\r\nHost: 127.0.0.1:38085\r\nUser-Agent: HTTPie/3.2.1\r\n\r\n'

tests/test_sessions.py:485: AssertionError
----------------------------- Captured stderr call -----------------------------
127.0.0.1 - - [07/Jun/2022 16:24:20] "GET / HTTP/1.1" 200 12144
=============================== warnings summary ===============================
...
=========================== short test summary info ============================
FAILED tests/test_cli.py::test_url_colon_slash_slash_only - AssertionError: a...
FAILED tests/test_output.py::TestQuietFlag::test_quiet_with_check_status_non_zero
FAILED tests/test_output.py::TestQuietFlag::test_quiet_with_check_status_non_zero_pipe
FAILED tests/test_output.py::TestQuietFlag::test_quiet_quiet_with_check_status_non_zero_pipe
FAILED tests/test_plugins_cli.py::test_plugins_uninstall[True] - AssertionErr...
FAILED tests/test_plugins_cli.py::test_plugins_uninstall[False] - AssertionEr...
FAILED tests/test_plugins_cli.py::test_plugins_listing_after_uninstall - Asse...
FAILED tests/test_plugins_cli.py::test_plugins_uninstall_specific - Assertion...
FAILED tests/test_plugins_cli.py::test_plugins_double_uninstall - AssertionEr...
FAILED tests/test_plugins_cli.py::test_broken_plugins - AssertionError: asser...
FAILED tests/test_sessions.py::TestCookieStorage::test_existing_and_new_cookies_sent_in_request[new=bar;chocolate=milk-new_cookies_dict1-chocolate=milk; cookie1=foo; cookie2=foo; new=bar]
FAILED tests/test_sessions.py::TestCookieStorage::test_existing_and_new_cookies_sent_in_request[new=bar; chocolate=milk-new_cookies_dict2-chocolate=milk; cookie1=foo; cookie2=foo; new=bar]
FAILED tests/test_sessions.py::TestCookieStorage::test_existing_and_new_cookies_sent_in_request[new=bar; chocolate=milk;;;-new_cookies_dict4-chocolate=milk; cookie1=foo; cookie2=foo; new=bar]
= 13 failed, 1003 passed, 6 skipped, 2 xfailed, 2 xpassed, 351 warnings in 56.38s =

Expected result

Tests pass.

Debug output

Please re-run the command with --debug, then copy the entire command & output and paste both below:

Not relevant.

Additional information, screenshots, or code examples

We are about to update to Python 3.11 in Fedora 37 (the development version of Fedora). This is not yet blocking our users, but getting it sorted out will be eventually required. Fedora 37 Beta is to be released in September 2022.

I believe that most of the test failures observed, if not all, are bad test expectations rather than actual problems in httpie.

jkbrzt commented 2 years ago

Thanks, @hroncok. We’ll look into the compatibility with Python 3.11.