)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8ffbcd3cc3592f87c59f33b19ff5871297b64407","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"bda7f794_67aeebdd","updated":"2024-05-14 18:50:54.000000000","message":"thanks for fixing this issue!","commit_id":"65be8f8867dd61250063e682d861994c971de284"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"09b1e30ca34a994c6ecbdd2daeadac6bddaa4886","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"77791a9f_fbc160c3","updated":"2024-05-13 18:25:29.000000000","message":"this seems to fixed the issue with retry on BytesIO objects.","commit_id":"65be8f8867dd61250063e682d861994c971de284"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"c23c8039_69f4ff55","updated":"2024-07-01 22:53:54.000000000","message":"I\u0027d love to put this to bed, but I can\u0027t convince myself this fix should merge as is\n\n1) the lack of the _can_reset initilization is an obvious smell, but I guess we avoid the land-mine by checking hasattr(\u0027reset\u0027) which catches the \"wrong\" AttributeError\n2) we\u0027ve added *new* \"normalization to a resetable\" of our readable content in `swiftclient.Connection._retry` method but then we still craft our *own* `reset_func`\n\nMaybe these are some what non-material issues but I\u0027d be pretty happy with this chnage if we squash in something like:\n\n923189: sq: normalize reset_func | https://review.opendev.org/c/openstack/python-swiftclient/+/923189","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"1bb7b742ae854496ac60c2c2e6ef6ba752a52ba9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"c41adb67_e2486619","updated":"2024-06-27 23:34:08.000000000","message":"LGTM.","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"b367399b3f57775b44e81c50fea1bc9dab46741c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"577142a1_33c288ec","updated":"2024-07-02 13:52:52.000000000","message":"Tim, since I have a co-author already should I go ahead and do the squash or did you want to look at it first?","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"7f111e5c_162683d1","updated":"2024-10-03 23:56:59.000000000","message":"The big struggle for me was to grok that both `SwiftService._upload_obj_job` \u0026 `swiftclient.put_object` want to normalize to either a `LengthWrapper` or `ReadableToIterable` - but `Connection.put_object` does NOT.  I think it might be reasonable to lean into this separation of concerns rather than add a 3rd place that tries to normalize contents.\n\nThe change in `Connection.put_object` to prefer `contents.reset` when available seems very nice and simplifies a lot of reasoning about reset handling when coming from `SwiftService`.\n\nThe existing test`test/unit/test_swiftclient.py::TestConnection::test_reset_stream` really didn\u0027t like `ReadableToIterable` growing reset support in it\u0027s `__init__` even tho that\u0027s exactly what we want for the `SwiftService`\u0027s use of `ReadableToIterable` from the bug report.  My compromise was to sublcass with `ResetableReadableToIterable` and use that in `SwiftService`, since \"reset support\" in `swiftclient.put_object` doesn\u0027t make sense anyway.  The `_can_reset` handling is strongly inspired by `LengthWrapper` - the quentisential \"resetable w/o seek/tell\" - for some reason no tests seem to care that `swiftclient.put_object` uses `LengthWrapper` if you pass in `content_length` which calls tell inside the module function each retry even tho the actual \"reset_func\" being used is defined in `Connection.put_object`.\n\nThere may be room to improve if we break apart a `NonResetableLengthWrapper` and have `LengthWrapper \u003d ResetableLengthWrapper` share a common `ResetableMixIn` with `ResetableReadableToIterable` since `LengthWrapper` was *already* resetable and possibly used by external kit.  However, since no tests seem to currently care about the \"extra\" tell calls when using `Connection.put_object` w/ `content_length` maybe it\u0027s best to leave well enough alone.","commit_id":"c2aba7023a3f6ee02e3d3e4b66c23bc2f8cfe22d"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"1d43af9f49ecab134b9e40f8a24fe6c2378dd6e2","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"2b49e727_d290b6c8","updated":"2024-11-06 20:31:29.000000000","message":"functest failures passing locally have to do with me running `urllib3\u003d\u003d2.2.3` with `urllib3\u003d\u003d1.26.20` tests fail reliably.\n\n\u003e Changed the default request body encoding from ‘ISO-8859-1’ to ‘UTF-8’.\nhttps://urllib3.readthedocs.io/en/latest/v2-migration-guide.html","commit_id":"7a14de6ca04c9a464e21465afdd0bd139b0892cf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"650317ad9eecb73414d51947edfffd54b567f2bb","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"ff8aa98e_57a6ef02","updated":"2024-11-06 18:16:04.000000000","message":"recheck\n\nthe results of the failed func test run have aged out - they pass for me locally.","commit_id":"7a14de6ca04c9a464e21465afdd0bd139b0892cf"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"4e969bb44a0fcadd12751949855f979ebf104f9f","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":6,"id":"cfc9ab91_81e20df5","in_reply_to":"2b49e727_d290b6c8","updated":"2025-05-15 16:47:17.000000000","message":"oic, zuul is running a different version of ``urllib3``, that\u0027s why it\u0027s not happy. should we upgrade it with swiftclient?\n\n```\n    httplib_response \u003d self._make_request(\n                       ^^^^^^^^^^^^^^^^^^^\n\n      File \"/home/zuul/src/opendev.org/openstack/python-swiftclient/.tox/func/lib/python3.12/site-packages/urllib3/connectionpool.py\", line 416, in _make_request\n    conn.request(method, url, **httplib_request_kw)\n\n      File \"/home/zuul/src/opendev.org/openstack/python-swiftclient/.tox/func/lib/python3.12/site-packages/urllib3/connection.py\", line 244, in request\n    super(HTTPConnection, self).request(method, url, body\u003dbody, headers\u003dheaders)\n\n      File \"/usr/lib/python3.12/http/client.py\", line 1336, in request\n    self._send_request(method, url, body, headers, encode_chunked)\n\n      File \"/usr/lib/python3.12/http/client.py\", line 1381, in _send_request\n    body \u003d _encode(body, \u0027body\u0027)\n           ^^^^^^^^^^^^^^^^^^^^^\n\n      File \"/usr/lib/python3.12/http/client.py\", line 166, in _encode\n    raise UnicodeEncodeError(\n\n    UnicodeEncodeError: \u0027latin-1\u0027 codec can\u0027t encode character \u0027\\u2603\u0027 in position 0: Body (\u0027☃\u0027) is not valid Latin-1. Use body.encode(\u0027utf-8\u0027) if you want to send it encoded in UTF-8.\n```","commit_id":"7a14de6ca04c9a464e21465afdd0bd139b0892cf"}],"swiftclient/client.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":1418,"context_line":"        if content_length is None:"},{"line_number":1419,"context_line":"            data \u003d ReadableToIterable(contents, chunk_size, md5\u003dFalse)"},{"line_number":1420,"context_line":"        else:"},{"line_number":1421,"context_line":"            data \u003d LengthWrapper(contents, content_length, md5\u003dFalse)"},{"line_number":1422,"context_line":""},{"line_number":1423,"context_line":"        conn.putrequest(path, headers\u003dheaders, data\u003ddata)"},{"line_number":1424,"context_line":"    else:"}],"source_content_type":"text/x-python","patch_set":4,"id":"cc6eb461_735815ce","line":1421,"updated":"2024-07-01 22:53:54.000000000","message":"jeez; how many times do we wrap these things!?","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"b367399b3f57775b44e81c50fea1bc9dab46741c","unresolved":false,"context_lines":[{"line_number":1418,"context_line":"        if content_length is None:"},{"line_number":1419,"context_line":"            data \u003d ReadableToIterable(contents, chunk_size, md5\u003dFalse)"},{"line_number":1420,"context_line":"        else:"},{"line_number":1421,"context_line":"            data \u003d LengthWrapper(contents, content_length, md5\u003dFalse)"},{"line_number":1422,"context_line":""},{"line_number":1423,"context_line":"        conn.putrequest(path, headers\u003dheaders, data\u003ddata)"},{"line_number":1424,"context_line":"    else:"}],"source_content_type":"text/x-python","patch_set":4,"id":"62c3baa4_1abe4a76","line":1421,"in_reply_to":"3caebf5c_2ce98751","updated":"2024-07-02 13:52:52.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0954df22beec133255cb263e95fee64c0e6b1656","unresolved":true,"context_lines":[{"line_number":1418,"context_line":"        if content_length is None:"},{"line_number":1419,"context_line":"            data \u003d ReadableToIterable(contents, chunk_size, md5\u003dFalse)"},{"line_number":1420,"context_line":"        else:"},{"line_number":1421,"context_line":"            data \u003d LengthWrapper(contents, content_length, md5\u003dFalse)"},{"line_number":1422,"context_line":""},{"line_number":1423,"context_line":"        conn.putrequest(path, headers\u003dheaders, data\u003ddata)"},{"line_number":1424,"context_line":"    else:"}],"source_content_type":"text/x-python","patch_set":4,"id":"3caebf5c_2ce98751","line":1421,"in_reply_to":"cc6eb461_735815ce","updated":"2024-07-01 23:54:19.000000000","message":"All. The. Damn. Time.","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":1957,"context_line":"                                  \u0027ability to reset contents for reupload.\u0027"},{"line_number":1958,"context_line":"                                  % (container, obj))"},{"line_number":1959,"context_line":""},{"line_number":1960,"context_line":"        if isinstance(contents, (bytes, str)) or not contents:"},{"line_number":1961,"context_line":"            # if its a str or None then you can retry as much as you want"},{"line_number":1962,"context_line":"            reset_func \u003d None"},{"line_number":1963,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":4,"id":"dca6687c_4ae7bce2","line":1960,"updated":"2024-07-01 22:53:54.000000000","message":"this seems like a mostly unrelated drive-by bug fix\n\nbut it\u0027s well covered by `test/unit/test_swiftclient.py::TestConnection::test_put_object_retry_bytes`","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"b367399b3f57775b44e81c50fea1bc9dab46741c","unresolved":false,"context_lines":[{"line_number":1957,"context_line":"                                  \u0027ability to reset contents for reupload.\u0027"},{"line_number":1958,"context_line":"                                  % (container, obj))"},{"line_number":1959,"context_line":""},{"line_number":1960,"context_line":"        if isinstance(contents, (bytes, str)) or not contents:"},{"line_number":1961,"context_line":"            # if its a str or None then you can retry as much as you want"},{"line_number":1962,"context_line":"            reset_func \u003d None"},{"line_number":1963,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":4,"id":"c42580af_5aeef2b3","line":1960,"in_reply_to":"dca6687c_4ae7bce2","updated":"2024-07-02 13:52:52.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":1968,"context_line":"                reset \u003d getattr(contents, \u0027reset\u0027, None)"},{"line_number":1969,"context_line":"                if reset:"},{"line_number":1970,"context_line":"                    reset_func \u003d reset"},{"line_number":1971,"context_line":"                elif tell and seek:"},{"line_number":1972,"context_line":"                    orig_pos \u003d tell()"},{"line_number":1973,"context_line":""},{"line_number":1974,"context_line":"                    def reset_func(*a, **kw):"}],"source_content_type":"text/x-python","patch_set":4,"id":"e2299f54_4772e1b9","line":1971,"updated":"2024-07-01 22:53:54.000000000","message":"this change just seems like an order of precedence change:\n\n\u003e if there\u0027s an explicit reset function use that directly/plainly even if *also* has a seek/tell method\n\n^ seems reasonable; and probably mostly functionally immaterial since a `LengthWrapper` doesn\u0027t expose it\u0027s readable\u0027s underlying `seek`/`tell` methods.","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"b367399b3f57775b44e81c50fea1bc9dab46741c","unresolved":false,"context_lines":[{"line_number":1968,"context_line":"                reset \u003d getattr(contents, \u0027reset\u0027, None)"},{"line_number":1969,"context_line":"                if reset:"},{"line_number":1970,"context_line":"                    reset_func \u003d reset"},{"line_number":1971,"context_line":"                elif tell and seek:"},{"line_number":1972,"context_line":"                    orig_pos \u003d tell()"},{"line_number":1973,"context_line":""},{"line_number":1974,"context_line":"                    def reset_func(*a, **kw):"}],"source_content_type":"text/x-python","patch_set":4,"id":"698a4c9d_40ab1386","line":1971,"in_reply_to":"25219bf1_301ee48c","updated":"2024-07-02 13:52:52.000000000","message":"I think reset is fine; i agree we should use it when we can.","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0954df22beec133255cb263e95fee64c0e6b1656","unresolved":true,"context_lines":[{"line_number":1968,"context_line":"                reset \u003d getattr(contents, \u0027reset\u0027, None)"},{"line_number":1969,"context_line":"                if reset:"},{"line_number":1970,"context_line":"                    reset_func \u003d reset"},{"line_number":1971,"context_line":"                elif tell and seek:"},{"line_number":1972,"context_line":"                    orig_pos \u003d tell()"},{"line_number":1973,"context_line":""},{"line_number":1974,"context_line":"                    def reset_func(*a, **kw):"}],"source_content_type":"text/x-python","patch_set":4,"id":"25219bf1_301ee48c","line":1971,"in_reply_to":"e2299f54_4772e1b9","updated":"2024-07-01 23:54:19.000000000","message":"Yeah, mostly it seemed insane to me that we\u0027d add our own `reset` API then *not prioritize it*.\n\n🤔 Maybe the *real* win would be to get rid of our `reset` API entirely...","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"1bb7b742ae854496ac60c2c2e6ef6ba752a52ba9","unresolved":false,"context_lines":[{"line_number":1974,"context_line":"                    def reset_func(*a, **kw):"},{"line_number":1975,"context_line":"                        seek(orig_pos)"},{"line_number":1976,"context_line":""},{"line_number":1977,"context_line":"            if hasattr(contents, \u0027read\u0027) and not isinstance("},{"line_number":1978,"context_line":"                    contents, (ReadableToIterable, LengthWrapper)):"},{"line_number":1979,"context_line":"                if content_length is None:"},{"line_number":1980,"context_line":"                    contents \u003d ReadableToIterable("}],"source_content_type":"text/x-python","patch_set":4,"id":"9818b60e_178511f7","line":1977,"updated":"2024-06-27 23:34:08.000000000","message":"ok, so ByteIO object will be wrapped one level up at here","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":1975,"context_line":"                        seek(orig_pos)"},{"line_number":1976,"context_line":""},{"line_number":1977,"context_line":"            if hasattr(contents, \u0027read\u0027) and not isinstance("},{"line_number":1978,"context_line":"                    contents, (ReadableToIterable, LengthWrapper)):"},{"line_number":1979,"context_line":"                if content_length is None:"},{"line_number":1980,"context_line":"                    contents \u003d ReadableToIterable("},{"line_number":1981,"context_line":"                        contents, chunk_size or 65536, md5\u003dFalse)"}],"source_content_type":"text/x-python","patch_set":4,"id":"6d794916_b05bd3f6","line":1978,"updated":"2024-07-01 22:53:54.000000000","message":"ReadableToIterable doesn\u0027t have a read attribute","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"b367399b3f57775b44e81c50fea1bc9dab46741c","unresolved":false,"context_lines":[{"line_number":1975,"context_line":"                        seek(orig_pos)"},{"line_number":1976,"context_line":""},{"line_number":1977,"context_line":"            if hasattr(contents, \u0027read\u0027) and not isinstance("},{"line_number":1978,"context_line":"                    contents, (ReadableToIterable, LengthWrapper)):"},{"line_number":1979,"context_line":"                if content_length is None:"},{"line_number":1980,"context_line":"                    contents \u003d ReadableToIterable("},{"line_number":1981,"context_line":"                        contents, chunk_size or 65536, md5\u003dFalse)"}],"source_content_type":"text/x-python","patch_set":4,"id":"6a0aa1f9_fc2eb894","line":1978,"in_reply_to":"252bc9f6_34d57041","updated":"2024-07-02 13:52:52.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0954df22beec133255cb263e95fee64c0e6b1656","unresolved":true,"context_lines":[{"line_number":1975,"context_line":"                        seek(orig_pos)"},{"line_number":1976,"context_line":""},{"line_number":1977,"context_line":"            if hasattr(contents, \u0027read\u0027) and not isinstance("},{"line_number":1978,"context_line":"                    contents, (ReadableToIterable, LengthWrapper)):"},{"line_number":1979,"context_line":"                if content_length is None:"},{"line_number":1980,"context_line":"                    contents \u003d ReadableToIterable("},{"line_number":1981,"context_line":"                        contents, chunk_size or 65536, md5\u003dFalse)"}],"source_content_type":"text/x-python","patch_set":4,"id":"252bc9f6_34d57041","line":1978,"in_reply_to":"6d794916_b05bd3f6","updated":"2024-07-01 23:54:19.000000000","message":"...yet?? *shrug*\n\nMostly I was just trying to mimic the check up around L1412","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":1981,"context_line":"                        contents, chunk_size or 65536, md5\u003dFalse)"},{"line_number":1982,"context_line":"                else:"},{"line_number":1983,"context_line":"                    contents \u003d LengthWrapper("},{"line_number":1984,"context_line":"                        contents, content_length, md5\u003dFalse)"},{"line_number":1985,"context_line":""},{"line_number":1986,"context_line":"        return self._retry(reset_func, put_object, container, obj, contents,"},{"line_number":1987,"context_line":"                           content_length\u003dcontent_length, etag\u003detag,"}],"source_content_type":"text/x-python","patch_set":4,"id":"1cc9ddbf_fb218549","line":1984,"updated":"2024-07-01 22:53:54.000000000","message":"I\u0027m not 100% sure I understand the motivation/justification for this change\n\nit\u0027s annoying me that we normalize here to avoid reset redefinition in `swiftclient.put_object` but don\u0027t actually pass in `reset_func\u003dcontents.reset`","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0954df22beec133255cb263e95fee64c0e6b1656","unresolved":true,"context_lines":[{"line_number":1981,"context_line":"                        contents, chunk_size or 65536, md5\u003dFalse)"},{"line_number":1982,"context_line":"                else:"},{"line_number":1983,"context_line":"                    contents \u003d LengthWrapper("},{"line_number":1984,"context_line":"                        contents, content_length, md5\u003dFalse)"},{"line_number":1985,"context_line":""},{"line_number":1986,"context_line":"        return self._retry(reset_func, put_object, container, obj, contents,"},{"line_number":1987,"context_line":"                           content_length\u003dcontent_length, etag\u003detag,"}],"source_content_type":"text/x-python","patch_set":4,"id":"abe1d537_c7b56eaf","line":1984,"in_reply_to":"1cc9ddbf_fb218549","updated":"2024-07-01 23:54:19.000000000","message":"I\u0027m a little confused -- `swiftclient.put_object` has no concept of retries, much less resets.\n\n`reset_func\u003dcontents.reset` sounds like a simplification of the\n```\nreset \u003d getattr(contents, \u0027reset\u0027, None)\nif reset:\n    reset_func \u003d reset\nself._retry(reset_func, ...)\n```\nthat we\u0027ve got here (ignoring the rest of the edge cases).\n\nMotivation was to avoid doing the wrapping (with its attendant `tell()` call) inside the function that\u0027s getting retried.","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":1981,"context_line":"                        contents, chunk_size or 65536, md5\u003dFalse)"},{"line_number":1982,"context_line":"                else:"},{"line_number":1983,"context_line":"                    contents \u003d LengthWrapper("},{"line_number":1984,"context_line":"                        contents, content_length, md5\u003dFalse)"},{"line_number":1985,"context_line":""},{"line_number":1986,"context_line":"        return self._retry(reset_func, put_object, container, obj, contents,"},{"line_number":1987,"context_line":"                           content_length\u003dcontent_length, etag\u003detag,"}],"source_content_type":"text/x-python","patch_set":4,"id":"f12d98f5_5bfe9137","line":1984,"in_reply_to":"ab2451ae_3474cb6c","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"b367399b3f57775b44e81c50fea1bc9dab46741c","unresolved":true,"context_lines":[{"line_number":1981,"context_line":"                        contents, chunk_size or 65536, md5\u003dFalse)"},{"line_number":1982,"context_line":"                else:"},{"line_number":1983,"context_line":"                    contents \u003d LengthWrapper("},{"line_number":1984,"context_line":"                        contents, content_length, md5\u003dFalse)"},{"line_number":1985,"context_line":""},{"line_number":1986,"context_line":"        return self._retry(reset_func, put_object, container, obj, contents,"},{"line_number":1987,"context_line":"                           content_length\u003dcontent_length, etag\u003detag,"}],"source_content_type":"text/x-python","patch_set":4,"id":"ab2451ae_3474cb6c","line":1984,"in_reply_to":"abe1d537_c7b56eaf","updated":"2024-07-02 13:52:52.000000000","message":"well, except we\u0027ve already built a new reset_func from the readable *before* we normalize to ReadableToIterable/LengthWrapper - if it wasn\u0027t for the fact that ReadableToIterable doesn\u0027t have a read and so we never fall into this function we\u0027d end up doing another tell when we normalize the type here.\n\nIf we do the type normalization of readables *first* we never have to create our own reset_func in this method to pass to _retry - which seemed like a simplification:\n\n923189: sq: normalize reset_func | https://review.opendev.org/c/openstack/python-swiftclient/+/923189","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"}],"swiftclient/utils.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"09b1e30ca34a994c6ecbdd2daeadac6bddaa4886","unresolved":true,"context_lines":[{"line_number":382,"context_line":"    def reset(self):"},{"line_number":383,"context_line":"        if self._can_reset:"},{"line_number":384,"context_line":"            return self._reset"},{"line_number":385,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"},{"line_number":386,"context_line":"                             type(self).__name__)"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"    def _reset(self, *args, **kwargs):"}],"source_content_type":"text/x-python","patch_set":2,"id":"86934c2a_a4d3dfc6","line":385,"updated":"2024-05-13 18:25:29.000000000","message":"we want hasattr(reset) to fail - rather than just raising some kind of ... TypeError?","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":382,"context_line":"    def reset(self):"},{"line_number":383,"context_line":"        if self._can_reset:"},{"line_number":384,"context_line":"            return self._reset"},{"line_number":385,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"},{"line_number":386,"context_line":"                             type(self).__name__)"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"    def _reset(self, *args, **kwargs):"}],"source_content_type":"text/x-python","patch_set":2,"id":"3ca678b5_b9a6f1b3","line":385,"in_reply_to":"208531e7_66a83d2f","updated":"2024-07-01 22:53:54.000000000","message":"heh, yeah I think it\u0027s raising AttributeError on `self._can_reset`???\n\nperhaps both LengthWrapper/ReadableToIterable should subclass a ResetableReadable in order to unify their `seek`/`tell` \u003d\u003e `reset` logic since it seems easy enough to get that wrong...","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":382,"context_line":"    def reset(self):"},{"line_number":383,"context_line":"        if self._can_reset:"},{"line_number":384,"context_line":"            return self._reset"},{"line_number":385,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"},{"line_number":386,"context_line":"                             type(self).__name__)"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"    def _reset(self, *args, **kwargs):"}],"source_content_type":"text/x-python","patch_set":2,"id":"5f852fd7_51f4cae3","line":385,"in_reply_to":"3ca678b5_b9a6f1b3","updated":"2024-10-03 23:56:59.000000000","message":"Done","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"086a0fcb66e1ffd8e9e038d0784d0db785e2d495","unresolved":true,"context_lines":[{"line_number":382,"context_line":"    def reset(self):"},{"line_number":383,"context_line":"        if self._can_reset:"},{"line_number":384,"context_line":"            return self._reset"},{"line_number":385,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"},{"line_number":386,"context_line":"                             type(self).__name__)"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"    def _reset(self, *args, **kwargs):"}],"source_content_type":"text/x-python","patch_set":2,"id":"208531e7_66a83d2f","line":385,"in_reply_to":"86934c2a_a4d3dfc6","updated":"2024-05-13 19:02:50.000000000","message":"Largely cribbed from `LengthWrapper` -- and yeah, the expectation is to [raise an `AttributeError`](https://github.com/openstack/python-swiftclient/blob/master/swiftclient/client.py#L1968) (or, I suppose, return None -- but that\u0027s not terribly obvious IMO).","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"09b1e30ca34a994c6ecbdd2daeadac6bddaa4886","unresolved":true,"context_lines":[{"line_number":386,"context_line":"                             type(self).__name__)"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"    def _reset(self, *args, **kwargs):"},{"line_number":389,"context_line":"        if hasattr(self.content, \u0027reset\u0027):"},{"line_number":390,"context_line":"            self.content.reset(*args, **kwargs)"},{"line_number":391,"context_line":"        else:"},{"line_number":392,"context_line":"            self.content.seek(self._orig_pos)"}],"source_content_type":"text/x-python","patch_set":2,"id":"abb849d6_a27651c3","line":389,"updated":"2024-05-13 18:25:29.000000000","message":"should this be self._can_reset?","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":386,"context_line":"                             type(self).__name__)"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"    def _reset(self, *args, **kwargs):"},{"line_number":389,"context_line":"        if hasattr(self.content, \u0027reset\u0027):"},{"line_number":390,"context_line":"            self.content.reset(*args, **kwargs)"},{"line_number":391,"context_line":"        else:"},{"line_number":392,"context_line":"            self.content.seek(self._orig_pos)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3a18aa75_276223b0","line":389,"in_reply_to":"12f150b6_f941efdb","updated":"2024-07-01 22:53:54.000000000","message":"Probably `ReadableToIterable` just doesn\u0027t need to support readables with magic `reset` method.","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":386,"context_line":"                             type(self).__name__)"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"    def _reset(self, *args, **kwargs):"},{"line_number":389,"context_line":"        if hasattr(self.content, \u0027reset\u0027):"},{"line_number":390,"context_line":"            self.content.reset(*args, **kwargs)"},{"line_number":391,"context_line":"        else:"},{"line_number":392,"context_line":"            self.content.seek(self._orig_pos)"}],"source_content_type":"text/x-python","patch_set":2,"id":"5bf94825_c23d5fba","line":389,"in_reply_to":"3a18aa75_276223b0","updated":"2024-10-03 23:56:59.000000000","message":"Done","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"086a0fcb66e1ffd8e9e038d0784d0db785e2d495","unresolved":true,"context_lines":[{"line_number":386,"context_line":"                             type(self).__name__)"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"    def _reset(self, *args, **kwargs):"},{"line_number":389,"context_line":"        if hasattr(self.content, \u0027reset\u0027):"},{"line_number":390,"context_line":"            self.content.reset(*args, **kwargs)"},{"line_number":391,"context_line":"        else:"},{"line_number":392,"context_line":"            self.content.seek(self._orig_pos)"}],"source_content_type":"text/x-python","patch_set":2,"id":"12f150b6_f941efdb","line":389,"in_reply_to":"abb849d6_a27651c3","updated":"2024-05-13 19:02:50.000000000","message":"Nope -- we also set `self._can_reset` if there\u0027s `seek`/`tell`. Maybe it\u0027d be better to get rid of `_can_reset` entirely and always use the attr checks? *\\*shrug\\**","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"09b1e30ca34a994c6ecbdd2daeadac6bddaa4886","unresolved":true,"context_lines":[{"line_number":391,"context_line":"        else:"},{"line_number":392,"context_line":"            self.content.seek(self._orig_pos)"},{"line_number":393,"context_line":"        if not isinstance(self.md5sum, NoopMD5):"},{"line_number":394,"context_line":"            self.md5sum \u003d hashlib.md5()"},{"line_number":395,"context_line":""},{"line_number":396,"context_line":""},{"line_number":397,"context_line":"class LengthWrapper:"}],"source_content_type":"text/x-python","patch_set":2,"id":"a0a07d0f_04364ed5","line":394,"updated":"2024-05-13 18:25:29.000000000","message":"oh good catch!","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8ffbcd3cc3592f87c59f33b19ff5871297b64407","unresolved":false,"context_lines":[{"line_number":391,"context_line":"        else:"},{"line_number":392,"context_line":"            self.content.seek(self._orig_pos)"},{"line_number":393,"context_line":"        if not isinstance(self.md5sum, NoopMD5):"},{"line_number":394,"context_line":"            self.md5sum \u003d hashlib.md5()"},{"line_number":395,"context_line":""},{"line_number":396,"context_line":""},{"line_number":397,"context_line":"class LengthWrapper:"}],"source_content_type":"text/x-python","patch_set":2,"id":"6ac9cb12_28cb7680","line":394,"in_reply_to":"a0a07d0f_04364ed5","updated":"2024-05-14 18:50:54.000000000","message":"Acknowledged","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8ffbcd3cc3592f87c59f33b19ff5871297b64407","unresolved":true,"context_lines":[{"line_number":379,"context_line":"        return self"},{"line_number":380,"context_line":""},{"line_number":381,"context_line":"    @property"},{"line_number":382,"context_line":"    def reset(self):"},{"line_number":383,"context_line":"        if self._can_reset:"},{"line_number":384,"context_line":"            return self._reset"},{"line_number":385,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"}],"source_content_type":"text/x-python","patch_set":3,"id":"b3d3af46_ce4dd909","line":382,"updated":"2024-05-14 18:50:54.000000000","message":"I wonder why you wrote two functions instead of having just one?\n\n```    def reset(self, *args, **kwargs):\n        if self._can_reset:\n            if hasattr(self.content, \u0027reset\u0027):\n                self.content.reset(*args, **kwargs)\n            else:\n                self.content.seek(self._orig_pos)\n            if not isinstance(self.md5sum, NoopMD5):\n                self.md5sum \u003d hashlib.md5()\n        else:\n            raise AttributeError(\"Cannot reset this object\")```","commit_id":"65be8f8867dd61250063e682d861994c971de284"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":379,"context_line":"        return self"},{"line_number":380,"context_line":""},{"line_number":381,"context_line":"    @property"},{"line_number":382,"context_line":"    def reset(self):"},{"line_number":383,"context_line":"        if self._can_reset:"},{"line_number":384,"context_line":"            return self._reset"},{"line_number":385,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"}],"source_content_type":"text/x-python","patch_set":3,"id":"e099c573_ceaa6746","line":382,"in_reply_to":"68739668_86494333","updated":"2024-07-01 22:53:54.000000000","message":"ok, so THIS is the meat of the fix - when service hands a stream to a client it\u0027s normally just an open file wrapped by LengthWrapper, but otherwise it wraps it in one of these ReadableToIterable\n\nhttps://github.com/openstack/python-swiftclient/blob/master/swiftclient/service.py#L2334-L2349\n\n... which didn\u0027t previously support \"reset\"","commit_id":"65be8f8867dd61250063e682d861994c971de284"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"4f9cc57154e2154e5df1166325cee4601acdb09e","unresolved":true,"context_lines":[{"line_number":379,"context_line":"        return self"},{"line_number":380,"context_line":""},{"line_number":381,"context_line":"    @property"},{"line_number":382,"context_line":"    def reset(self):"},{"line_number":383,"context_line":"        if self._can_reset:"},{"line_number":384,"context_line":"            return self._reset"},{"line_number":385,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"}],"source_content_type":"text/x-python","patch_set":3,"id":"68739668_86494333","line":382,"in_reply_to":"b3d3af46_ce4dd909","updated":"2024-05-17 15:28:51.000000000","message":"Like that, `instance.reset` would always find the attribute, and it wouldn\u0027t be until you call it (`instance.reset()`) that the `AttributeError` would be raised. As a result, it would always pass [the `getattr` check in `Connection.put_object`](https://github.com/openstack/python-swiftclient/blob/4.5.0/swiftclient/client.py#L1955), causing the `AttributeError` to get raised instead of the \"no ability to reset contents\" exception.","commit_id":"65be8f8867dd61250063e682d861994c971de284"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":379,"context_line":"        return self"},{"line_number":380,"context_line":""},{"line_number":381,"context_line":"    @property"},{"line_number":382,"context_line":"    def reset(self):"},{"line_number":383,"context_line":"        if self._can_reset:"},{"line_number":384,"context_line":"            return self._reset"},{"line_number":385,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"}],"source_content_type":"text/x-python","patch_set":3,"id":"d6bff578_a19a44c5","line":382,"in_reply_to":"e099c573_ceaa6746","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"65be8f8867dd61250063e682d861994c971de284"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"1bb7b742ae854496ac60c2c2e6ef6ba752a52ba9","unresolved":true,"context_lines":[{"line_number":328,"context_line":"    \"\"\""},{"line_number":329,"context_line":"    Wrap a filelike object and act as an iterator."},{"line_number":330,"context_line":""},{"line_number":331,"context_line":"    It is recommended to use this class only on files opened in binary mode."},{"line_number":332,"context_line":"    Due to the Unicode changes in Python 3, files are now opened using an"},{"line_number":333,"context_line":"    encoding not suitable for use with the md5 class and because of this"},{"line_number":334,"context_line":"    hit the exception on every call to next. This could cause problems,"}],"source_content_type":"text/x-python","patch_set":4,"id":"7235c783_60281748","line":331,"updated":"2024-06-27 23:34:08.000000000","message":"add comment that this class can also support in memory content like ByteIO?","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":false,"context_lines":[{"line_number":328,"context_line":"    \"\"\""},{"line_number":329,"context_line":"    Wrap a filelike object and act as an iterator."},{"line_number":330,"context_line":""},{"line_number":331,"context_line":"    It is recommended to use this class only on files opened in binary mode."},{"line_number":332,"context_line":"    Due to the Unicode changes in Python 3, files are now opened using an"},{"line_number":333,"context_line":"    encoding not suitable for use with the md5 class and because of this"},{"line_number":334,"context_line":"    hit the exception on every call to next. This could cause problems,"}],"source_content_type":"text/x-python","patch_set":4,"id":"5b9e3c5d_ac843787","line":331,"in_reply_to":"7235c783_60281748","updated":"2024-07-01 22:53:54.000000000","message":"I think that\u0027s what it means by \"filelike\"","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"1bb7b742ae854496ac60c2c2e6ef6ba752a52ba9","unresolved":true,"context_lines":[{"line_number":344,"context_line":"        \"\"\""},{"line_number":345,"context_line":"        self.md5sum \u003d hashlib.md5() if md5 else NoopMD5()"},{"line_number":346,"context_line":"        self.content \u003d content"},{"line_number":347,"context_line":"        self.chunk_size \u003d chunk_size"},{"line_number":348,"context_line":"        if getattr(content, \u0027reset\u0027, None):"},{"line_number":349,"context_line":"            self._can_reset \u003d True"},{"line_number":350,"context_line":"        elif getattr(content, \u0027seek\u0027, None) and \\"}],"source_content_type":"text/x-python","patch_set":4,"id":"b22d7a11_ec36f375","line":347,"updated":"2024-06-27 23:34:08.000000000","message":"should we set ``self._can_reset \u003d False`` here?","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":344,"context_line":"        \"\"\""},{"line_number":345,"context_line":"        self.md5sum \u003d hashlib.md5() if md5 else NoopMD5()"},{"line_number":346,"context_line":"        self.content \u003d content"},{"line_number":347,"context_line":"        self.chunk_size \u003d chunk_size"},{"line_number":348,"context_line":"        if getattr(content, \u0027reset\u0027, None):"},{"line_number":349,"context_line":"            self._can_reset \u003d True"},{"line_number":350,"context_line":"        elif getattr(content, \u0027seek\u0027, None) and \\"}],"source_content_type":"text/x-python","patch_set":4,"id":"f7454e68_dae5c8e5","line":347,"in_reply_to":"b22d7a11_ec36f375","updated":"2024-07-01 22:53:54.000000000","message":"yes!","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":344,"context_line":"        \"\"\""},{"line_number":345,"context_line":"        self.md5sum \u003d hashlib.md5() if md5 else NoopMD5()"},{"line_number":346,"context_line":"        self.content \u003d content"},{"line_number":347,"context_line":"        self.chunk_size \u003d chunk_size"},{"line_number":348,"context_line":"        if getattr(content, \u0027reset\u0027, None):"},{"line_number":349,"context_line":"            self._can_reset \u003d True"},{"line_number":350,"context_line":"        elif getattr(content, \u0027seek\u0027, None) and \\"}],"source_content_type":"text/x-python","patch_set":4,"id":"9c14539e_e6e6a436","line":347,"in_reply_to":"f7454e68_dae5c8e5","updated":"2024-10-03 23:56:59.000000000","message":"Done","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":346,"context_line":"        self.content \u003d content"},{"line_number":347,"context_line":"        self.chunk_size \u003d chunk_size"},{"line_number":348,"context_line":"        if getattr(content, \u0027reset\u0027, None):"},{"line_number":349,"context_line":"            self._can_reset \u003d True"},{"line_number":350,"context_line":"        elif getattr(content, \u0027seek\u0027, None) and \\"},{"line_number":351,"context_line":"                getattr(content, \u0027tell\u0027, None):"},{"line_number":352,"context_line":"            self._orig_pos \u003d content.tell()"}],"source_content_type":"text/x-python","patch_set":4,"id":"6ada3b06_3e1b3722","line":349,"updated":"2024-07-01 22:53:54.000000000","message":"AFAICT this is untested","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":346,"context_line":"        self.content \u003d content"},{"line_number":347,"context_line":"        self.chunk_size \u003d chunk_size"},{"line_number":348,"context_line":"        if getattr(content, \u0027reset\u0027, None):"},{"line_number":349,"context_line":"            self._can_reset \u003d True"},{"line_number":350,"context_line":"        elif getattr(content, \u0027seek\u0027, None) and \\"},{"line_number":351,"context_line":"                getattr(content, \u0027tell\u0027, None):"},{"line_number":352,"context_line":"            self._orig_pos \u003d content.tell()"}],"source_content_type":"text/x-python","patch_set":4,"id":"e0f2eabd_6ec77067","line":349,"in_reply_to":"6ada3b06_3e1b3722","updated":"2024-10-03 23:56:59.000000000","message":"Done","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":349,"context_line":"            self._can_reset \u003d True"},{"line_number":350,"context_line":"        elif getattr(content, \u0027seek\u0027, None) and \\"},{"line_number":351,"context_line":"                getattr(content, \u0027tell\u0027, None):"},{"line_number":352,"context_line":"            self._orig_pos \u003d content.tell()"},{"line_number":353,"context_line":"            self._can_reset \u003d True"},{"line_number":354,"context_line":""},{"line_number":355,"context_line":"    def get_md5sum(self):"}],"source_content_type":"text/x-python","patch_set":4,"id":"510f59e3_e4ff3a6d","line":352,"updated":"2024-07-01 22:53:54.000000000","message":"maybe name this `_start` for consistency with LengthWrapper?","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":349,"context_line":"            self._can_reset \u003d True"},{"line_number":350,"context_line":"        elif getattr(content, \u0027seek\u0027, None) and \\"},{"line_number":351,"context_line":"                getattr(content, \u0027tell\u0027, None):"},{"line_number":352,"context_line":"            self._orig_pos \u003d content.tell()"},{"line_number":353,"context_line":"            self._can_reset \u003d True"},{"line_number":354,"context_line":""},{"line_number":355,"context_line":"    def get_md5sum(self):"}],"source_content_type":"text/x-python","patch_set":4,"id":"977f6c97_6ceb8de6","line":352,"in_reply_to":"510f59e3_e4ff3a6d","updated":"2024-10-03 23:56:59.000000000","message":"Done","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":446,"context_line":"    @property"},{"line_number":447,"context_line":"    def reset(self):"},{"line_number":448,"context_line":"        if self._can_reset:"},{"line_number":449,"context_line":"            return self._reset"},{"line_number":450,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"},{"line_number":451,"context_line":"                             type(self).__name__)"},{"line_number":452,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"287145ce_1bfec7ad","line":449,"updated":"2024-07-01 22:53:54.000000000","message":"ok, and this is why `swiftclient.Connection` supports `contents` with a `reset` method - `LengthWrapper` is the quentisential \"resetable\" but doesn\u0027t have `seek`/`tell`","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":446,"context_line":"    @property"},{"line_number":447,"context_line":"    def reset(self):"},{"line_number":448,"context_line":"        if self._can_reset:"},{"line_number":449,"context_line":"            return self._reset"},{"line_number":450,"context_line":"        raise AttributeError(\"%r object has no attribute \u0027reset\u0027\" %"},{"line_number":451,"context_line":"                             type(self).__name__)"},{"line_number":452,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"dfde17d7_e1315344","line":449,"in_reply_to":"287145ce_1bfec7ad","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"}],"test/functional/test_swiftclient.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":29,"context_line":"        if not self.skip_tests:"},{"line_number":30,"context_line":"            self._get_config()"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"        self.test_data \u003d b\u002742\u0027 * 10"},{"line_number":33,"context_line":"        self.etag \u003d \u00272704306ec982238d85d4b235c925d58e\u0027"},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"        self.containername \u003d \"functional-tests-container-%s\" % int(time.time())"}],"source_content_type":"text/x-python","patch_set":4,"id":"73f9a247_c11f8637","line":32,"updated":"2024-07-01 22:53:54.000000000","message":"ok, so the existing comments about \"string\" were wrong","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":29,"context_line":"        if not self.skip_tests:"},{"line_number":30,"context_line":"            self._get_config()"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"        self.test_data \u003d b\u002742\u0027 * 10"},{"line_number":33,"context_line":"        self.etag \u003d \u00272704306ec982238d85d4b235c925d58e\u0027"},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"        self.containername \u003d \"functional-tests-container-%s\" % int(time.time())"}],"source_content_type":"text/x-python","patch_set":4,"id":"735f2303_1faa9839","line":32,"in_reply_to":"73f9a247_c11f8637","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":58,"context_line":"        if self.skip_tests:"},{"line_number":59,"context_line":"            self.skipTest(\u0027SKIPPING FUNCTIONAL TESTS DUE TO NO CONFIG\u0027)"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"        self.conn \u003d self._get_connection()"},{"line_number":62,"context_line":"        self.conn.put_container(self.containername)"},{"line_number":63,"context_line":"        self.conn.put_container(self.containername_2)"},{"line_number":64,"context_line":"        self.conn.put_object("}],"source_content_type":"text/x-python","patch_set":4,"id":"6c161779_f105268c","line":61,"updated":"2024-07-01 22:53:54.000000000","message":"so this was always testing a `swiftclient.Connection` (as opposed to a `service.SwiftService`)","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":58,"context_line":"        if self.skip_tests:"},{"line_number":59,"context_line":"            self.skipTest(\u0027SKIPPING FUNCTIONAL TESTS DUE TO NO CONFIG\u0027)"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"        self.conn \u003d self._get_connection()"},{"line_number":62,"context_line":"        self.conn.put_container(self.containername)"},{"line_number":63,"context_line":"        self.conn.put_container(self.containername_2)"},{"line_number":64,"context_line":"        self.conn.put_object("}],"source_content_type":"text/x-python","patch_set":4,"id":"e1efa1b6_42be4c41","line":61,"in_reply_to":"6c161779_f105268c","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":212,"context_line":"        # Object with content from unicode"},{"line_number":213,"context_line":"        self.conn.put_object("},{"line_number":214,"context_line":"            self.containername, self.objectname,"},{"line_number":215,"context_line":"            contents\u003dself.test_data.decode(\u0027ascii\u0027))"},{"line_number":216,"context_line":"        hdrs \u003d self.conn.head_object(self.containername, self.objectname)"},{"line_number":217,"context_line":"        self.assertEqual(str(len(self.test_data)),"},{"line_number":218,"context_line":"                         hdrs.get(\u0027content-length\u0027))"}],"source_content_type":"text/x-python","patch_set":4,"id":"80fb8d61_ec9909c7","line":215,"updated":"2024-07-01 22:53:54.000000000","message":"as best I can tell this worked on master equally well; I don\u0027t know how interesting/relevant it would be to have a test that uses a string with non-ascii chars","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":212,"context_line":"        # Object with content from unicode"},{"line_number":213,"context_line":"        self.conn.put_object("},{"line_number":214,"context_line":"            self.containername, self.objectname,"},{"line_number":215,"context_line":"            contents\u003dself.test_data.decode(\u0027ascii\u0027))"},{"line_number":216,"context_line":"        hdrs \u003d self.conn.head_object(self.containername, self.objectname)"},{"line_number":217,"context_line":"        self.assertEqual(str(len(self.test_data)),"},{"line_number":218,"context_line":"                         hdrs.get(\u0027content-length\u0027))"}],"source_content_type":"text/x-python","patch_set":4,"id":"6f9858c8_99de7376","line":215,"in_reply_to":"80fb8d61_ec9909c7","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":265,"context_line":"        self.assertEqual(\u0027application/octet-stream\u0027, hdrs.get(\u0027content-type\u0027))"},{"line_number":266,"context_line":""},{"line_number":267,"context_line":"        # Content from File-like object"},{"line_number":268,"context_line":"        fileobj \u003d BytesIO(self.test_data)"},{"line_number":269,"context_line":"        self.conn.put_object("},{"line_number":270,"context_line":"            self.containername, self.objectname, contents\u003dfileobj)"},{"line_number":271,"context_line":"        hdrs \u003d self.conn.head_object(self.containername, self.objectname)"}],"source_content_type":"text/x-python","patch_set":4,"id":"92fe0e9f_85b735ae","line":268,"updated":"2024-07-01 22:53:54.000000000","message":"it seems relevant to note that the the bug report has nothing to do with passing `BytesIO` as content to `swiftclient.Connection` - the issue was only with `service.SwiftService`/`SwiftUploadOjbect` interfaces.","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":265,"context_line":"        self.assertEqual(\u0027application/octet-stream\u0027, hdrs.get(\u0027content-type\u0027))"},{"line_number":266,"context_line":""},{"line_number":267,"context_line":"        # Content from File-like object"},{"line_number":268,"context_line":"        fileobj \u003d BytesIO(self.test_data)"},{"line_number":269,"context_line":"        self.conn.put_object("},{"line_number":270,"context_line":"            self.containername, self.objectname, contents\u003dfileobj)"},{"line_number":271,"context_line":"        hdrs \u003d self.conn.head_object(self.containername, self.objectname)"}],"source_content_type":"text/x-python","patch_set":4,"id":"fc6adb5a_b164deff","line":268,"in_reply_to":"92fe0e9f_85b735ae","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"}],"test/unit/test_service.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"09b1e30ca34a994c6ecbdd2daeadac6bddaa4886","unresolved":true,"context_lines":[{"line_number":1539,"context_line":"            \u0027success\u0027: True,"},{"line_number":1540,"context_line":"        }"},{"line_number":1541,"context_line":"        for k, v in expected.items():"},{"line_number":1542,"context_line":"            self.assertEqual(v, upload_object_resp.get(k), k)"},{"line_number":1543,"context_line":""},{"line_number":1544,"context_line":"    def test_upload_bytes_with_retry(self):"},{"line_number":1545,"context_line":"        content \u003d io.BytesIO(b\u0027some-content\u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"93ec3a54_0cca072f","line":1542,"updated":"2024-05-13 18:25:29.000000000","message":"i was kind of waffling between create_container_resp and upload_object_response which style of assert-sub-dict-keys I preferred.\n\nmaybe I should try:\n\n    assertEqual(b, b | a)","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":1539,"context_line":"            \u0027success\u0027: True,"},{"line_number":1540,"context_line":"        }"},{"line_number":1541,"context_line":"        for k, v in expected.items():"},{"line_number":1542,"context_line":"            self.assertEqual(v, upload_object_resp.get(k), k)"},{"line_number":1543,"context_line":""},{"line_number":1544,"context_line":"    def test_upload_bytes_with_retry(self):"},{"line_number":1545,"context_line":"        content \u003d io.BytesIO(b\u0027some-content\u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"7f223770_4408c75a","line":1542,"in_reply_to":"35183eeb_a4ddaf7a","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"086a0fcb66e1ffd8e9e038d0784d0db785e2d495","unresolved":true,"context_lines":[{"line_number":1539,"context_line":"            \u0027success\u0027: True,"},{"line_number":1540,"context_line":"        }"},{"line_number":1541,"context_line":"        for k, v in expected.items():"},{"line_number":1542,"context_line":"            self.assertEqual(v, upload_object_resp.get(k), k)"},{"line_number":1543,"context_line":""},{"line_number":1544,"context_line":"    def test_upload_bytes_with_retry(self):"},{"line_number":1545,"context_line":"        content \u003d io.BytesIO(b\u0027some-content\u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"35183eeb_a4ddaf7a","line":1542,"in_reply_to":"93ec3a54_0cca072f","updated":"2024-05-13 19:02:50.000000000","message":"We\u0027d need to bump up our minimum python version -- [PEP 584](https://peps.python.org/pep-0584/) came in 3.9. FWIW,\n```\nassertEqual(b, {**b, **a})\n```\nwould work with our current 3.6 minimum; [PEP 0448](https://peps.python.org/pep-0448/) dates back to 3.5. I don\u0027t know that I like *either* though; they\u0027re so terse as to mask what you want to assert, and they can\u0027t spot missing keys. I\u0027d be partial towards something like\n```\nassertEqual(b, {a.get(k) for k in b})\n```\npersonally, assuming the expected dict doesn\u0027t have any `None`s. If it *did*, maybe do something more like\n```\nclass Missing:\n    def __repr__(self):\n        return \u0027MISSING\u0027\nMISSING \u003d Missing()\nassertEqual(b, {a.get(k, MISSING) for k in b})\n```","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"}],"test/unit/test_swiftclient.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"09b1e30ca34a994c6ecbdd2daeadac6bddaa4886","unresolved":true,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":2,"id":"3a606e1b_f1da78d5","line":2716,"updated":"2024-05-13 18:25:29.000000000","message":"two more tells huh?  I saw at least ONE.","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"086a0fcb66e1ffd8e9e038d0784d0db785e2d495","unresolved":true,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":2,"id":"f4001c38_d6120675","line":2716,"in_reply_to":"3a606e1b_f1da78d5","updated":"2024-05-13 19:02:50.000000000","message":"Yeah, and I\u0027m still a little suspicious as to *why*. Haven\u0027t run it down yet.","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"4f9cc57154e2154e5df1166325cee4601acdb09e","unresolved":false,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":2,"id":"c89a3625_88a85333","line":2716,"in_reply_to":"c590e1fa_f39292ef","updated":"2024-05-17 15:28:51.000000000","message":"Thanks for digging into that! I still hadn\u0027t gotten around to it. I think this demonstrates two areas for improvement:\n\n1. a custom reset function should be preferred over `tell`/`seek` in `Connection.put_object`\n2. `Connection.put_object` should wrap `contents` so [the module-level `put_object` won\u0027t have to](https://github.com/openstack/python-swiftclient/blob/4.5.0/swiftclient/client.py#L1400-L1401).","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8ffbcd3cc3592f87c59f33b19ff5871297b64407","unresolved":false,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":2,"id":"c590e1fa_f39292ef","line":2716,"in_reply_to":"f4001c38_d6120675","updated":"2024-05-14 18:50:54.000000000","message":"it was triggered by internal client retries. so retries didn\u0027t triggered before reset function is added in this patch. I think ``[0, 0, 0]`` makes sense now.\n\n```-\u003e method()\n  /vagrant/python-swiftclient/test/unit/test_swiftclient.py(2715)test_reset_stream()\n-\u003e conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)\n  /vagrant/python-swiftclient/swiftclient/client.py(1970)put_object()\n-\u003e orig_pos \u003d tell()\n\u003e /vagrant/python-swiftclient/test/unit/test_swiftclient.py(2644)tell()\n-\u003e self.tells.append(self.data.tell())\n\n\n-\u003e method()\n  /vagrant/python-swiftclient/test/unit/test_swiftclient.py(2715)test_reset_stream()\n-\u003e conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)\n  /vagrant/python-swiftclient/swiftclient/client.py(1976)put_object()\n-\u003e return self._retry(reset_func, put_object, container, obj, contents,\n  /vagrant/python-swiftclient/swiftclient/client.py(1809)_retry()\n-\u003e rv \u003d func(self.url, self.token, *args,\n  /vagrant/python-swiftclient/swiftclient/client.py(1419)put_object()\n-\u003e data \u003d ReadableToIterable(contents, chunk_size, md5\u003dFalse)\n  /vagrant/python-swiftclient/swiftclient/utils.py(352)__init__()\n-\u003e self._orig_pos \u003d content.tell()\n\u003e /vagrant/python-swiftclient/test/unit/test_swiftclient.py(2644)tell()\n-\u003e self.tells.append(self.data.tell())\n\n-\u003e method()\n  /vagrant/python-swiftclient/test/unit/test_swiftclient.py(2715)test_reset_stream()\n-\u003e conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)\n  /vagrant/python-swiftclient/swiftclient/client.py(1976)put_object()\n-\u003e return self._retry(reset_func, put_object, container, obj, contents,\n  /vagrant/python-swiftclient/swiftclient/client.py(1809)_retry()\n-\u003e rv \u003d func(self.url, self.token, *args,\n  /vagrant/python-swiftclient/swiftclient/client.py(1419)put_object()\n-\u003e data \u003d ReadableToIterable(contents, chunk_size, md5\u003dFalse)\n  /vagrant/python-swiftclient/swiftclient/utils.py(352)__init__()\n-\u003e self._orig_pos \u003d content.tell()\n\u003e /vagrant/python-swiftclient/test/unit/test_swiftclient.py(2644)tell()\n-\u003e self.tells.append(self.data.tell())```","commit_id":"38a4b5adc898e77f4098974902da5e34efc13cdb"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":4,"id":"32f98846_e695d7a9","side":"PARENT","line":2716,"updated":"2024-07-01 22:53:54.000000000","message":"so on master `swiftclient.put_object` wraps our `LocalContents` in a `ReadableToIterable` - with a single call to `tell` in `_retry` to build it\u0027s `reset_func`\n\nNow that `ReadableToIterable` calls `tell` to support `reset`, if `_retry` were to continue to pass `swiftclient.put_object` `LocalContents` directly each call to `swiftclient.put_object` would wrap it in a `ReadableToIterable` (although mostly for the purpose of enforcing `chunk_size` since `swiftclient.put_object` won\u0027t ever use a `reset` method directly; retries a property of `swiftclient.Connection`","commit_id":"e7061db7a4ab705ae93e0b0c82c5418a3a8d299d"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":4,"id":"4c569997_55af7a3d","side":"PARENT","line":2716,"in_reply_to":"32f98846_e695d7a9","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"e7061db7a4ab705ae93e0b0c82c5418a3a8d299d"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":2676,"context_line":"                    else:"},{"line_number":2677,"context_line":"                        for datum in data:"},{"line_number":2678,"context_line":"                            pass"},{"line_number":2679,"context_line":"                raise socket.error(\u0027oops\u0027)"},{"line_number":2680,"context_line":""},{"line_number":2681,"context_line":"            def request(self, *args, **kwargs):"},{"line_number":2682,"context_line":"                return"}],"source_content_type":"text/x-python","patch_set":4,"id":"2c7ad556_c908bbe6","line":2679,"updated":"2024-07-01 22:53:54.000000000","message":"FWIW this test is always hitting \"max retries reached \u003d\u003e error\" path not a \"retry once and then succeed\" path","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":2676,"context_line":"                    else:"},{"line_number":2677,"context_line":"                        for datum in data:"},{"line_number":2678,"context_line":"                            pass"},{"line_number":2679,"context_line":"                raise socket.error(\u0027oops\u0027)"},{"line_number":2680,"context_line":""},{"line_number":2681,"context_line":"            def request(self, *args, **kwargs):"},{"line_number":2682,"context_line":"                return"}],"source_content_type":"text/x-python","patch_set":4,"id":"a383b7fc_1569b13b","line":2679,"in_reply_to":"2c7ad556_c908bbe6","updated":"2024-10-03 23:56:59.000000000","message":"Acknowledged","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"1bb7b742ae854496ac60c2c2e6ef6ba752a52ba9","unresolved":false,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":4,"id":"07fa36cd_d3295e7a","line":2716,"updated":"2024-06-27 23:34:08.000000000","message":"okay, no extra `0` now.","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d3dcfb7605b4fdb9522101707ceef29a871604f9","unresolved":true,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":4,"id":"8caf08bd_db866ac7","line":2716,"in_reply_to":"07fa36cd_d3295e7a","updated":"2024-07-01 22:53:54.000000000","message":"the extra call to `tell` is a side effect of forcing the converstion in `swiftclient.Connection._retry` to `ReadableToIterable` - we used to be able to pass our own file-like/`LocalContents` and have it used in `put_object` directly/unmolested; but now `swiftclient.Connection` always inserts a layer between the caller and the contents used by the module level functions.","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"b367399b3f57775b44e81c50fea1bc9dab46741c","unresolved":true,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":4,"id":"ff4b7ef1_04b9f277","line":2716,"in_reply_to":"1ca5fcdf_6250fa1d","updated":"2024-07-02 13:52:52.000000000","message":"agree, I decided to just go ahead and let them have their ResetableReadables!\n\n923189: sq: normalize reset_func | https://review.opendev.org/c/openstack/python-swiftclient/+/923189","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0954df22beec133255cb263e95fee64c0e6b1656","unresolved":true,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ca5fcdf_6250fa1d","line":2716,"in_reply_to":"8caf08bd_db866ac7","updated":"2024-07-01 23:54:19.000000000","message":"\u003e we used to be able to pass our own file-like/`LocalContents` and have it used in `put_object` directly/unmolested\n\nI\u0027m not sure there\u0027s much virtue in that unless `put_object` *also* passes that directly on to `requests`","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"80a89a2f5940e1cf705b306a6078cfd88bbc0b3e","unresolved":false,"context_lines":[{"line_number":2713,"context_line":"                conn.put_object(\u0027c\u0027, \u0027o\u0027, contents)"},{"line_number":2714,"context_line":"            except socket.error as err:"},{"line_number":2715,"context_line":"                exc \u003d err"},{"line_number":2716,"context_line":"            self.assertEqual(contents.tells, [0, 0])"},{"line_number":2717,"context_line":"            self.assertEqual(contents.seeks, [(0, 0)])"},{"line_number":2718,"context_line":"            # four reads: two in the initial pass, two in the retry"},{"line_number":2719,"context_line":"            self.assertEqual(4, len(contents.reads))"}],"source_content_type":"text/x-python","patch_set":4,"id":"925eaaf5_b931ef0c","line":2716,"in_reply_to":"ff4b7ef1_04b9f277","updated":"2024-10-03 23:56:59.000000000","message":"Done","commit_id":"3eb6e615048e7f37fe537770dbf8e1022ea8c2d9"}]}
