)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":12620,"name":"Alexander Corwin","email":"ancorwin@gmail.com","username":"acorwin"},"change_message_id":"bfe571f2ac096b4721bf8e6e4b5e22a32ae17170","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":1,"id":"3774f276_558949e2","updated":"2023-11-28 17:16:19.000000000","message":"Looks like a reasonable patch (although i\u0027m not up to date on the lore) but some things here look like bugs","commit_id":"a3f7169129fda0fc6c2e042bd8a128798c6faa04"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"f25de8a338fef29a159664ff80b50d3644a833ed","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"a3970bf1_5ebbbc57","in_reply_to":"3774f276_558949e2","updated":"2023-12-20 19:42:03.000000000","message":"Done","commit_id":"a3f7169129fda0fc6c2e042bd8a128798c6faa04"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"72d90d40768356f68c9d64d99b2f2dd13f1a1bd8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"0157601e_9de701b1","updated":"2024-02-21 19:42:06.000000000","message":"recheck","commit_id":"319f16177349af333c1ee2b4a31c327854486f00"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"83976c9f85f8fd6a812e57c145f3e5e0483e3e50","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"6e674199_47b8a290","updated":"2024-04-03 21:57:48.000000000","message":"recheck\n\nFailure in `tempest.api.volume.test_volumes_actions.VolumesActionsTest.test_volume_upload[id-d8f1ca95-3d5b-44a3-b8ca-909691c9532d,image]` -- don\u0027t think it\u0027s related.","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ee9ef177f9efa8762ce1a067960773e765dd33b0","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"ca7d9f0d_8d8f2d30","updated":"2024-04-17 22:58:25.000000000","message":"this doesn\u0027t work at all\n\n```\nvagrant@saio:~/deleteme$ swift download test5 test.big --part-number 2\n--part-number option only allowed for object downloads\n```\n\nI was able to track down most of the bugs by writing some more tests:\n\nhttps://review.opendev.org/c/openstack/python-swiftclient/+/916145\n\nlet me know if you still can\u0027t get some working code together and I can cough up some diffs.","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"0bc7e1006f4f7d630bd5f1f41a8a2dfb27218981","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":20,"id":"51958479_caacea57","updated":"2024-04-29 17:08:47.000000000","message":"I think the tests in test_shell cover the behaviors in command_helpers and service as well as shell.  cli args to connection - the implementation is mainly adding the new qs option, which I think could be spelled a little differently:\n\n917461: sq? reword query_string params parsing | https://review.opendev.org/c/openstack/python-swiftclient/+/917461\n\nbut this seems to work!\n\nI spotted what looks like a bug with `--skip-identical` - however that might be an existing issue with --version-id.  Maybe you could help me write some tests?  Even if it\u0027s an existing issue for `--version-id` that\u0027s not a great reason to write the same bug w/ `--part-num` and it may be trivial to fix both at the same time?\n\nPlease consider doing a re-base on-top of the fix for `md5sum !\u003d etag`\n\n916135: failing test: slo download raises SwiftError | https://review.opendev.org/c/openstack/python-swiftclient/+/916135\n\nThe error-noise/invalid-return when using this patch based on master is making it really annoying test.","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"b5527e28e7cff2cfce884a03587870fa2d03fa46","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":22,"id":"94c6d97f_9ae5f8e2","updated":"2024-05-01 15:59:20.000000000","message":"recheck.","commit_id":"42ecd1a7258fa608c95498459c89f4bdb93dc5a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":23,"id":"07f7c7d4_a18f35e4","updated":"2024-05-02 23:04:40.000000000","message":"All the behaviors check out for me testing this functionally - kudos!\n\nAnd thanks for raising the error on skip-identical + part-number; the fact that you also error on skip-identical + version-id makes https://bugs.launchpad.net/python-swiftclient/+bug/2064675 slightly better actually, so you can add `Partial-Bug: #2064675` to the commit message if you want!\n\nHowever, I think the new test for skip-identical + part-number is sketch - it doesn\u0027t seem to be asserting anyting about what\u0027s actually returned from the unit under test.  I think the assert-not-called is doing *some* good, but the actual error is just a stub - I left a diff that I think would be better.\n\nAFAICT the implementation you went with (if a \u0026 b; elif a; elif b) is functionally equivilent to https://review.opendev.org/c/openstack/python-swiftclient/+/917461/1/swiftclient/service.py#1235 so it\u0027s not a blocker for me - but the style is not my taste and I think it might get re-written if we add more options in the future.  I\u0027m curious about your preference and reasoning for the implementation you went with?  We have a running joke about there\u0027s only 3 numbers in computer science: 0, 1 and N 😊\n\nDoing assertions on output in test_shell is kind of annoying, but useful I think to validating correctness since the tool we\u0027re testing is primarily consumed by humans reading the text output... I\u0027ve tried to invest over the years at making it easier for test authors to have strong assertions, but certainly it could be improved further, YMMV.","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"aafc1ad8d3bb5cba6192a757406cfdec4e13a558","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":24,"id":"21d51788_68fa2507","updated":"2024-05-06 19:27:11.000000000","message":"the new test in test_shell for --part-number + --skip-identical is fixed; thanks.\n\nI think the new code in shell has a questionable behavior with part_number\u003d0 that was probably introduced when re-writing the query_param handling to be a list comprehension:\n\n918337: wip: failing test | https://review.opendev.org/c/openstack/python-swiftclient/+/918337\n\nFWIW I\u0027m pretty sure the bug only shows up if out-of-tree code tried to use the SwiftService interface directly since from the CLI the options are always strings and \u00270\u0027 evaluates to true.","commit_id":"f18eb808665e2f9f00386e890c5ec17684173005"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":28,"id":"7e3015a1_2c22503f","updated":"2024-05-22 19:50:50.000000000","message":"I wonder if we should adopt a convention for `swift download --part-number` file names that doesn\u0027t clobber the local file?\n\n```\nvagrant@saio:~$ swift upload test test.big --use-slo -S 1000000\ntest.big segment 7\ntest.big segment 8\ntest.big segment 9\ntest.big segment 3\ntest.big segment 2\ntest.big segment 0\ntest.big segment 1\ntest.big segment 5\ntest.big segment 4\ntest.big segment 6\ntest.big\nvagrant@saio:~$ md5sum test.big\n311175294563b07db7ea80dee2e5b3c6  test.big\nvagrant@saio:~$ swift download test test.big\ntest.big [auth 0.005s, headers 0.031s, total 0.197s, 52.265 MB/s]\nvagrant@saio:~$ md5sum test.big\n311175294563b07db7ea80dee2e5b3c6  test.big\nvagrant@saio:~$ swift download test test.big --part-number 4\ntest.big [auth 0.006s, headers 0.029s, total 0.038s, 31.731 MB/s]\nvagrant@saio:~$ md5sum test.big\n879f4bba57ed37c9ec5e5aedf9864698  test.big\nvagrant@saio:~$ swift download test test.big\ntest.big [auth 0.006s, headers 0.061s, total 0.233s, 44.010 MB/s]\nvagrant@saio:~$ md5sum test.big\n311175294563b07db7ea80dee2e5b3c6  test.big\nvagrant@saio:~$ swift download test test.big --part-number 4 --output test.big.4\ntest.big [auth 0.005s, headers 0.030s, total 0.037s, 32.029 MB/s]\nvagrant@saio:~$ md5sum test.big\n311175294563b07db7ea80dee2e5b3c6  test.big\nvagrant@saio:~$ md5sum test.big.4\n879f4bba57ed37c9ec5e5aedf9864698  test.big.4\n```\n\nI\u0027m actually ok with merging this as is (niche use-case \u003d\u003e foot gun!), but I think it also might be reasonable to require users to explicitly specify `--output` when the `--part-number` option is used on the shell with download in order to avoid clobbering your local files on accident.\n\nplease fix:\n\n* I think the test_shell is missing negative tests for invalid part-numbers, and the behavior might not be what we want.\n\n* I think the negative test for part-number\u003d0 in test_service is missing an assert on the query string of the request that was actually made, and the behavior might not be what we want.\n\nnit:\n\nYou could add part_number to the service stat and donwload doc strings and that would be a very nice improvement to round out the new feature.\n\nyou have options:\n\nI\u0027m glad this change will not introduce a new bug with --skip-identical and --part-number, I think handling it with an explicit \"not allowed\" error is fine.\n\n```\nvagrant@saio:~$ swift download test test.big --part-number 4 --output test.big.4 --skip-identical\nError downloading object \u0027test/test.big\u0027: Cannot use --skip-identical with part-number or version-id: ?part-number\u003d4\nFailed Transaction ID: None\n```\n\nI think we should assert --skip-identical + --version-id is an error and uppdate the commit message with partial/related bug tag.  I have a slight preference to \"leave it better than you found it\" - a marginal improvement over the status quo is progress and I\u0027ll take it!  But a silent drive-by that makes the bug report no longer invalid will probably cause more confusion than doing good IMHO - so the other option is leave the existing behavior/bug alone entirely; which would also be acceptable to merge; just not my personal *favorite*.  You can choose which way you want to go - but the current hybrid is confusing/bad (although might not be reason enough on it\u0027s own to block a merge if that was the only issue).","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"}],"swiftclient/command_helpers.py":[{"author":{"_account_id":12620,"name":"Alexander Corwin","email":"ancorwin@gmail.com","username":"acorwin"},"change_message_id":"bfe571f2ac096b4721bf8e6e4b5e22a32ae17170","unresolved":true,"context_lines":[{"line_number":147,"context_line":"    if options.get(\u0027version_id\u0027) is not None:"},{"line_number":148,"context_line":"        query_string \u003d \u0027version-id\u003d%s\u0027 % options[\u0027version_id\u0027]"},{"line_number":149,"context_line":"    if options.get(\u0027part-number\u0027) is not None:"},{"line_number":150,"context_line":"        query_string \u003d \u0027part-number\u003d%s\u0027 % options[\u0027part-number\u0027]"},{"line_number":151,"context_line":"    headers \u003d conn.head_object(container, obj, headers\u003dreq_headers,"},{"line_number":152,"context_line":"                               query_string\u003dquery_string)"},{"line_number":153,"context_line":"    items \u003d []"}],"source_content_type":"text/x-python","patch_set":1,"id":"4c7278ea_53a2022c","line":150,"updated":"2023-11-28 17:16:19.000000000","message":"this looks like it\u0027s going to trample the existing `query_string` if `version_id` and `part-number` are both set. is that on purpose? it kind of looks like a bug","commit_id":"a3f7169129fda0fc6c2e042bd8a128798c6faa04"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"f25de8a338fef29a159664ff80b50d3644a833ed","unresolved":false,"context_lines":[{"line_number":147,"context_line":"    if options.get(\u0027version_id\u0027) is not None:"},{"line_number":148,"context_line":"        query_string \u003d \u0027version-id\u003d%s\u0027 % options[\u0027version_id\u0027]"},{"line_number":149,"context_line":"    if options.get(\u0027part-number\u0027) is not None:"},{"line_number":150,"context_line":"        query_string \u003d \u0027part-number\u003d%s\u0027 % options[\u0027part-number\u0027]"},{"line_number":151,"context_line":"    headers \u003d conn.head_object(container, obj, headers\u003dreq_headers,"},{"line_number":152,"context_line":"                               query_string\u003dquery_string)"},{"line_number":153,"context_line":"    items \u003d []"}],"source_content_type":"text/x-python","patch_set":1,"id":"c36dd3f8_1b07c6c8","line":150,"in_reply_to":"4c7278ea_53a2022c","updated":"2023-12-20 19:42:03.000000000","message":"Done","commit_id":"a3f7169129fda0fc6c2e042bd8a128798c6faa04"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ee9ef177f9efa8762ce1a067960773e765dd33b0","unresolved":true,"context_lines":[{"line_number":161,"context_line":"        query_string \u003d \u0027version-id\u003d%s\u0027 % options[\u0027version_id\u0027]"},{"line_number":162,"context_line":"    if options.get(\u0027part_number\u0027) is not None:"},{"line_number":163,"context_line":"        query_string \u003d \u0027part-number\u003d%s\u0027 % options[\u0027part_number\u0027]"},{"line_number":164,"context_line":"    elif (options.get(\u0027version_id\u0027) is not None and options.get(\u0027part_number\u0027)"},{"line_number":165,"context_line":"          is not None):"},{"line_number":166,"context_line":"        query_string \u003d \u0027version-id\u003d%s\u0026part-number\u003d%s\u0027 % ("},{"line_number":167,"context_line":"            options[\u0027version_id\u0027], options[\u0027part_number\u0027]"}],"source_content_type":"text/x-python","patch_set":16,"id":"862e1ebb_21f093f7","line":164,"updated":"2024-04-17 22:58:25.000000000","message":"how can we ever get to this block `if options.get(\u0027part_number\u0027) is not None`???\n\nprobably since we\u0027re moving from 1 to N it\u0027s better to establish a pattern of gathering all the args components and then building the query string just once.","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cdd8ce5fe66bc79872b8d2d982df6049deb3d0eb","unresolved":false,"context_lines":[{"line_number":161,"context_line":"        query_string \u003d \u0027version-id\u003d%s\u0027 % options[\u0027version_id\u0027]"},{"line_number":162,"context_line":"    if options.get(\u0027part_number\u0027) is not None:"},{"line_number":163,"context_line":"        query_string \u003d \u0027part-number\u003d%s\u0027 % options[\u0027part_number\u0027]"},{"line_number":164,"context_line":"    elif (options.get(\u0027version_id\u0027) is not None and options.get(\u0027part_number\u0027)"},{"line_number":165,"context_line":"          is not None):"},{"line_number":166,"context_line":"        query_string \u003d \u0027version-id\u003d%s\u0026part-number\u003d%s\u0027 % ("},{"line_number":167,"context_line":"            options[\u0027version_id\u0027], options[\u0027part_number\u0027]"}],"source_content_type":"text/x-python","patch_set":16,"id":"64442433_f18d07cd","line":164,"in_reply_to":"862e1ebb_21f093f7","updated":"2024-04-23 18:42:19.000000000","message":"Done","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"0bc7e1006f4f7d630bd5f1f41a8a2dfb27218981","unresolved":true,"context_lines":[{"line_number":164,"context_line":"        query_string \u003d \u0027version-id\u003d%s\u0026part-number\u003d%s\u0027 % ("},{"line_number":165,"context_line":"            options[\u0027version_id\u0027], options[\u0027part_number\u0027]"},{"line_number":166,"context_line":"        )"},{"line_number":167,"context_line":"    elif options.get(\u0027part_number\u0027) is not None:"},{"line_number":168,"context_line":"        query_string \u003d \u0027part-number\u003d%s\u0027 % options[\u0027part_number\u0027]"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    headers \u003d conn.head_object(container, obj, headers\u003dreq_headers,"}],"source_content_type":"text/x-python","patch_set":20,"id":"79bed219_8af03c8e","line":167,"updated":"2024-04-29 17:08:47.000000000","message":"it\u0027s a little un-usual to see both branches of an if/elif start with the same condition.\n\nI wonder if you might try to find a more idiomatic way to express correct code?","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"e21059b2461280fd1b8f681327d8617468402134","unresolved":false,"context_lines":[{"line_number":164,"context_line":"        query_string \u003d \u0027version-id\u003d%s\u0026part-number\u003d%s\u0027 % ("},{"line_number":165,"context_line":"            options[\u0027version_id\u0027], options[\u0027part_number\u0027]"},{"line_number":166,"context_line":"        )"},{"line_number":167,"context_line":"    elif options.get(\u0027part_number\u0027) is not None:"},{"line_number":168,"context_line":"        query_string \u003d \u0027part-number\u003d%s\u0027 % options[\u0027part_number\u0027]"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    headers \u003d conn.head_object(container, obj, headers\u003dreq_headers,"}],"source_content_type":"text/x-python","patch_set":20,"id":"b7828782_9ce2f23f","line":167,"in_reply_to":"79bed219_8af03c8e","updated":"2024-04-30 19:32:10.000000000","message":"Done","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"aafc1ad8d3bb5cba6192a757406cfdec4e13a558","unresolved":true,"context_lines":[{"line_number":160,"context_line":"    version_id \u003d options.get(\u0027version_id\u0027)"},{"line_number":161,"context_line":"    query_params \u003d [(k, v) for k, v in"},{"line_number":162,"context_line":"                    [(\u0027version-id\u0027, version_id), (\u0027part-number\u0027, part_number)]"},{"line_number":163,"context_line":"                    if v]"},{"line_number":164,"context_line":"    query_string \u003d \u0027\u0026\u0027.join("},{"line_number":165,"context_line":"        \u0027%s\u003d%s\u0027 % (k, v) for k, v in query_params) if query_params else None"},{"line_number":166,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"dae6c741_1152b6c8","line":163,"updated":"2024-05-06 19:27:11.000000000","message":"I think there\u0027s very little advantage trying to write this as a list comprehension if we\u0027re still going to have to define each new named option (e.g. L159 \u0026 L160)\n\nIf we want to write it this way probably better as:\n\n```\n    option_to_param \u003d [\n        (\u0027version_id\u0027, \u0027version-id\u0027),\n        (\u0027part_number\u0027, \u0027part-number\u0027),\n    ]\n    query_params \u003d [\n        (p, options[o])\n        for o, p in option_to_param\n        if options.get(o) is not None\n    ]\n```\n\n... so we clearly define the mapping of option key to query_param and only have to update one data structure.\n\nBut I\u0027m not sure I\u0027d want to write the query_params with a list comprehension.  I think the lazy evaluation of the param item only if it exists in the options dict is a little tricky to read when it\u0027s all bundled up like that (I think the list comprehension is just doing to disjoint things: name-translation \u0026 filter)\n\nMaybe clearer as:\n\n```\n    query_params \u003d []\n\n    version_id \u003d options.get(\u0027version_id\u0027)\n    if version_id is not None:\n        query_params.append((\u0027version-id\u0027, version_id))\n    part_number \u003d options.get(\u0027part_number\u0027)\n    if part_number is not None:\n        query_params.append((\u0027part-number\u0027, part_number))\n```\n\nSure each new option adds 3 new lines; but those 3 lines are each super obvious!\n\nBut I think this are both equivilent; I assume options here only/always comes from the CLI and we don\u0027t have to worry about part_number\u003d0\n\n918337: wip: failing test | https://review.opendev.org/c/openstack/python-swiftclient/+/918337","commit_id":"f18eb808665e2f9f00386e890c5ec17684173005"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"799455b2c84ae86b0415804101e3558995288393","unresolved":false,"context_lines":[{"line_number":160,"context_line":"    version_id \u003d options.get(\u0027version_id\u0027)"},{"line_number":161,"context_line":"    query_params \u003d [(k, v) for k, v in"},{"line_number":162,"context_line":"                    [(\u0027version-id\u0027, version_id), (\u0027part-number\u0027, part_number)]"},{"line_number":163,"context_line":"                    if v]"},{"line_number":164,"context_line":"    query_string \u003d \u0027\u0026\u0027.join("},{"line_number":165,"context_line":"        \u0027%s\u003d%s\u0027 % (k, v) for k, v in query_params) if query_params else None"},{"line_number":166,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"398350ea_1213ee2e","line":163,"in_reply_to":"dae6c741_1152b6c8","updated":"2024-05-13 20:23:15.000000000","message":"Acknowledged","commit_id":"f18eb808665e2f9f00386e890c5ec17684173005"}],"swiftclient/exceptions.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3c8217b2d5f91cd7820843485ad1088b97a221d0","unresolved":true,"context_lines":[{"line_number":21,"context_line":"    def __init__(self, msg, http_scheme\u003d\u0027\u0027, http_host\u003d\u0027\u0027, http_port\u003d\u0027\u0027,"},{"line_number":22,"context_line":"                 http_path\u003d\u0027\u0027, http_query\u003d\u0027\u0027, http_status\u003dNone, http_reason\u003d\u0027\u0027,"},{"line_number":23,"context_line":"                 http_device\u003d\u0027\u0027, http_response_content\u003d\u0027\u0027,"},{"line_number":24,"context_line":"                 http_response_headers\u003dNone, query_string\u003dNone):"},{"line_number":25,"context_line":"        super(ClientException, self).__init__(msg)"},{"line_number":26,"context_line":"        self.msg \u003d msg"},{"line_number":27,"context_line":"        self.http_scheme \u003d http_scheme"}],"source_content_type":"text/x-python","patch_set":27,"id":"073e3b5e_be7468cf","line":24,"updated":"2024-05-14 18:33:34.000000000","message":"How is this different from `http_query`?","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"634483f4cdac1c09d220ed15808458cb6846e2b3","unresolved":false,"context_lines":[{"line_number":21,"context_line":"    def __init__(self, msg, http_scheme\u003d\u0027\u0027, http_host\u003d\u0027\u0027, http_port\u003d\u0027\u0027,"},{"line_number":22,"context_line":"                 http_path\u003d\u0027\u0027, http_query\u003d\u0027\u0027, http_status\u003dNone, http_reason\u003d\u0027\u0027,"},{"line_number":23,"context_line":"                 http_device\u003d\u0027\u0027, http_response_content\u003d\u0027\u0027,"},{"line_number":24,"context_line":"                 http_response_headers\u003dNone, query_string\u003dNone):"},{"line_number":25,"context_line":"        super(ClientException, self).__init__(msg)"},{"line_number":26,"context_line":"        self.msg \u003d msg"},{"line_number":27,"context_line":"        self.http_scheme \u003d http_scheme"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a0e9a50_87d98c7d","line":24,"in_reply_to":"073e3b5e_be7468cf","updated":"2024-05-15 01:36:20.000000000","message":"ahh shoot, i didn\u0027t see that, my bad.","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"}],"swiftclient/service.py":[{"author":{"_account_id":12620,"name":"Alexander Corwin","email":"ancorwin@gmail.com","username":"acorwin"},"change_message_id":"bfe571f2ac096b4721bf8e6e4b5e22a32ae17170","unresolved":true,"context_lines":[{"line_number":1220,"context_line":"                get_args[\u0027query_string\u0027] \u003d ("},{"line_number":1221,"context_line":"                    \u0027version-id\u003d%s\u0027 % options[\u0027version_id\u0027])"},{"line_number":1222,"context_line":"            if options.get(\u0027part-number\u0027) is not None:"},{"line_number":1223,"context_line":"                get_args[\u0027query_string\u0027] \u003d ("},{"line_number":1224,"context_line":"                    \u0027part-number\u003d%s\u0027 % options[\u0027part-number\u0027])"},{"line_number":1225,"context_line":"            if options[\u0027skip_identical\u0027]:"},{"line_number":1226,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"}],"source_content_type":"text/x-python","patch_set":1,"id":"281ba477_0e624092","line":1223,"updated":"2023-11-28 17:16:19.000000000","message":"same as above - this looks like it\u0027s trampling the query string again","commit_id":"a3f7169129fda0fc6c2e042bd8a128798c6faa04"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"f25de8a338fef29a159664ff80b50d3644a833ed","unresolved":false,"context_lines":[{"line_number":1220,"context_line":"                get_args[\u0027query_string\u0027] \u003d ("},{"line_number":1221,"context_line":"                    \u0027version-id\u003d%s\u0027 % options[\u0027version_id\u0027])"},{"line_number":1222,"context_line":"            if options.get(\u0027part-number\u0027) is not None:"},{"line_number":1223,"context_line":"                get_args[\u0027query_string\u0027] \u003d ("},{"line_number":1224,"context_line":"                    \u0027part-number\u003d%s\u0027 % options[\u0027part-number\u0027])"},{"line_number":1225,"context_line":"            if options[\u0027skip_identical\u0027]:"},{"line_number":1226,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"}],"source_content_type":"text/x-python","patch_set":1,"id":"3d773774_88ea2e3d","line":1223,"in_reply_to":"281ba477_0e624092","updated":"2023-12-20 19:42:03.000000000","message":"Done","commit_id":"a3f7169129fda0fc6c2e042bd8a128798c6faa04"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"0bc7e1006f4f7d630bd5f1f41a8a2dfb27218981","unresolved":true,"context_lines":[{"line_number":1235,"context_line":"                    \u0027version-id\u003d%s\u0027 % options[\u0027version_id\u0027])"},{"line_number":1236,"context_line":"            elif options.get(\u0027part_number\u0027) is not None:"},{"line_number":1237,"context_line":"                get_args[\u0027query_string\u0027] \u003d ("},{"line_number":1238,"context_line":"                    \u0027part-number\u003d%s\u0027 % options[\u0027part_number\u0027])"},{"line_number":1239,"context_line":""},{"line_number":1240,"context_line":"            if options[\u0027skip_identical\u0027]:"},{"line_number":1241,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"}],"source_content_type":"text/x-python","patch_set":20,"id":"c8c749ae_e59ec304","line":1238,"updated":"2024-04-29 17:08:47.000000000","message":"this is slightly better than the implementation used for stat in command helpers, but I imagine this pattern would get quite unruly once we have 3 or more query args.\n\nMaybe a stdlib urllib utility could provide inspiration\n\nhttps://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode\nhttps://docs.python.org/3/library/urllib.request.html#urllib-examples\nhttps://github.com/python/cpython/blob/main/Lib/urllib/parse.py#L1035","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"e21059b2461280fd1b8f681327d8617468402134","unresolved":false,"context_lines":[{"line_number":1235,"context_line":"                    \u0027version-id\u003d%s\u0027 % options[\u0027version_id\u0027])"},{"line_number":1236,"context_line":"            elif options.get(\u0027part_number\u0027) is not None:"},{"line_number":1237,"context_line":"                get_args[\u0027query_string\u0027] \u003d ("},{"line_number":1238,"context_line":"                    \u0027part-number\u003d%s\u0027 % options[\u0027part_number\u0027])"},{"line_number":1239,"context_line":""},{"line_number":1240,"context_line":"            if options[\u0027skip_identical\u0027]:"},{"line_number":1241,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"}],"source_content_type":"text/x-python","patch_set":20,"id":"551a9ffb_591a7ed4","line":1238,"in_reply_to":"c8c749ae_e59ec304","updated":"2024-04-30 19:32:10.000000000","message":"Done","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"0bc7e1006f4f7d630bd5f1f41a8a2dfb27218981","unresolved":true,"context_lines":[{"line_number":1241,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"},{"line_number":1242,"context_line":"                # string is ignored and the If-None-Match header will trigger"},{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                get_args[\u0027query_string\u0027] \u003d \u0027multipart-manifest\u003dget\u0027"},{"line_number":1245,"context_line":""},{"line_number":1246,"context_line":"            try:"},{"line_number":1247,"context_line":"                headers, body \u003d conn.get_object(container, obj, **get_args)"}],"source_content_type":"text/x-python","patch_set":20,"id":"148540a3_450579cf","line":1244,"updated":"2024-04-29 17:08:47.000000000","message":"I how/if part-number of version-id should interact with skip_identical\n\n```\nvagrant@saio:~$ swift download test test.big -o delete.me 2\u003e /dev/null\nvagrant@saio:~$ ls -alhF delete.me \n-rw-rw-r-- 1 vagrant vagrant 9.6M Apr 15 18:33 delete.me\nvagrant@saio:~$ swift download test test.big -o delete.me --skip-identical\nSkipped identical file \u0027test.big\u0027\nvagrant@saio:~$ ls -alhF delete.me \n-rw-rw-r-- 1 vagrant vagrant 9.6M Apr 15 18:33 delete.me\nvagrant@saio:~$ swift download test test.big -o delete.me --part-num 2 2\u003e /dev/null\nvagrant@saio:~$ ls -alhF delete.me \n-rw-rw-r-- 1 vagrant vagrant 977K Apr 15 18:33 delete.me\nvagrant@saio:~$ swift download test test.big -o delete.me --part-num 2 --skip-identical 2\u003e /dev/null\nvagrant@saio:~$ ls -alhF delete.me \n-rw-rw-r-- 1 vagrant vagrant 9.6M Apr 15 18:33 delete.me\n```\n\nprobably --skip-identical w/ part-number should NOT result in the whole SLO being downloaded.","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"e21059b2461280fd1b8f681327d8617468402134","unresolved":false,"context_lines":[{"line_number":1241,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"},{"line_number":1242,"context_line":"                # string is ignored and the If-None-Match header will trigger"},{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                get_args[\u0027query_string\u0027] \u003d \u0027multipart-manifest\u003dget\u0027"},{"line_number":1245,"context_line":""},{"line_number":1246,"context_line":"            try:"},{"line_number":1247,"context_line":"                headers, body \u003d conn.get_object(container, obj, **get_args)"}],"source_content_type":"text/x-python","patch_set":20,"id":"34a93d5e_5bd46148","line":1244,"in_reply_to":"148540a3_450579cf","updated":"2024-04-30 19:32:10.000000000","message":"Done","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":1234,"context_line":"                query_dict \u003d {"},{"line_number":1235,"context_line":"                    \u0027version-id\u0027: version_id,"},{"line_number":1236,"context_line":"                    \u0027part-number\u0027: part_number"},{"line_number":1237,"context_line":"                }"},{"line_number":1238,"context_line":"            elif version_id:"},{"line_number":1239,"context_line":"                query_dict \u003d {"},{"line_number":1240,"context_line":"                    \u0027version-id\u0027: version_id"}],"source_content_type":"text/x-python","patch_set":23,"id":"62ebafa8_34d64c88","line":1237,"updated":"2024-05-02 23:04:40.000000000","message":"I do NOT understand the advantage of this over just making this accumlation of query params addative ...","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"40b5c0cce098c2c79f2c4d1684bb20937c051372","unresolved":false,"context_lines":[{"line_number":1234,"context_line":"                query_dict \u003d {"},{"line_number":1235,"context_line":"                    \u0027version-id\u0027: version_id,"},{"line_number":1236,"context_line":"                    \u0027part-number\u0027: part_number"},{"line_number":1237,"context_line":"                }"},{"line_number":1238,"context_line":"            elif version_id:"},{"line_number":1239,"context_line":"                query_dict \u003d {"},{"line_number":1240,"context_line":"                    \u0027version-id\u0027: version_id"}],"source_content_type":"text/x-python","patch_set":23,"id":"4cd49fed_401d5975","line":1237,"in_reply_to":"62ebafa8_34d64c88","updated":"2024-05-06 17:56:48.000000000","message":"Done","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":1252,"context_line":"                    raise ClientException("},{"line_number":1253,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1254,"context_line":"                        \u0027version-id\u0027)"},{"line_number":1255,"context_line":"                query_dict[\u0027multipart-manifest\u0027] \u003d \u0027get\u0027"},{"line_number":1256,"context_line":""},{"line_number":1257,"context_line":"            get_args[\u0027query_string\u0027] \u003d urlencode(query_dict) if query_dict \\"},{"line_number":1258,"context_line":"                else None"}],"source_content_type":"text/x-python","patch_set":23,"id":"63543973_52db7666","line":1255,"updated":"2024-05-02 23:04:40.000000000","message":"FWIW I\u0027m pretty sure we could \"fix\" the version-id limitation simply by extending the query_dict to have version-id \u0026 multipart-manifest\n\nIt\u0027s less obvious to me that skip-identical will transparently work with part-number w/o some kind of part-number awareness on the local side.\n\nregardless the version-id+skip-identical bug is separate from this patch:\n\nhttps://bugs.launchpad.net/python-swiftclient/+bug/2064675","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":false,"context_lines":[{"line_number":1252,"context_line":"                    raise ClientException("},{"line_number":1253,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1254,"context_line":"                        \u0027version-id\u0027)"},{"line_number":1255,"context_line":"                query_dict[\u0027multipart-manifest\u0027] \u003d \u0027get\u0027"},{"line_number":1256,"context_line":""},{"line_number":1257,"context_line":"            get_args[\u0027query_string\u0027] \u003d urlencode(query_dict) if query_dict \\"},{"line_number":1258,"context_line":"                else None"}],"source_content_type":"text/x-python","patch_set":23,"id":"bbc14629_5c42d3af","line":1255,"in_reply_to":"63543973_52db7666","updated":"2024-05-22 19:50:50.000000000","message":"Done","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":1255,"context_line":"                query_dict[\u0027multipart-manifest\u0027] \u003d \u0027get\u0027"},{"line_number":1256,"context_line":""},{"line_number":1257,"context_line":"            get_args[\u0027query_string\u0027] \u003d urlencode(query_dict) if query_dict \\"},{"line_number":1258,"context_line":"                else None"},{"line_number":1259,"context_line":""},{"line_number":1260,"context_line":"            try:"},{"line_number":1261,"context_line":"                headers, body \u003d conn.get_object(container, obj, **get_args)"}],"source_content_type":"text/x-python","patch_set":23,"id":"5aca681c_a6f1fff3","line":1258,"updated":"2024-05-02 23:04:40.000000000","message":"I sort of assume the existing code was just not setting this kwarg at all if there was no query_dict - if you wanted to maintain existing behavior it\u0027d be more like:\n\n```\nif query_dict:\n    get_args[\u0027query_string\u0027] \u003d urlencode(query_dict)\n```\n\nbut I guess then you don\u0027t get to use the fancy ternary broken across two lines","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"f366f42e15ecf7ac1f83be3afc9f1ad93fad1386","unresolved":false,"context_lines":[{"line_number":1255,"context_line":"                query_dict[\u0027multipart-manifest\u0027] \u003d \u0027get\u0027"},{"line_number":1256,"context_line":""},{"line_number":1257,"context_line":"            get_args[\u0027query_string\u0027] \u003d urlencode(query_dict) if query_dict \\"},{"line_number":1258,"context_line":"                else None"},{"line_number":1259,"context_line":""},{"line_number":1260,"context_line":"            try:"},{"line_number":1261,"context_line":"                headers, body \u003d conn.get_object(container, obj, **get_args)"}],"source_content_type":"text/x-python","patch_set":23,"id":"58fc0d9b_0d8baf6e","line":1258,"in_reply_to":"2bcfe07d_d58eef1f","updated":"2024-05-13 20:22:46.000000000","message":"Acknowledged","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"8c7914220d12aff54d62fb2460eb78f3c75b46fd","unresolved":true,"context_lines":[{"line_number":1255,"context_line":"                query_dict[\u0027multipart-manifest\u0027] \u003d \u0027get\u0027"},{"line_number":1256,"context_line":""},{"line_number":1257,"context_line":"            get_args[\u0027query_string\u0027] \u003d urlencode(query_dict) if query_dict \\"},{"line_number":1258,"context_line":"                else None"},{"line_number":1259,"context_line":""},{"line_number":1260,"context_line":"            try:"},{"line_number":1261,"context_line":"                headers, body \u003d conn.get_object(container, obj, **get_args)"}],"source_content_type":"text/x-python","patch_set":23,"id":"a7393a29_2279689b","line":1258,"in_reply_to":"5aca681c_a6f1fff3","updated":"2024-05-03 20:48:10.000000000","message":"Right, but maybe i should revert it back so i do not have to update the tests","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"aafc1ad8d3bb5cba6192a757406cfdec4e13a558","unresolved":true,"context_lines":[{"line_number":1255,"context_line":"                query_dict[\u0027multipart-manifest\u0027] \u003d \u0027get\u0027"},{"line_number":1256,"context_line":""},{"line_number":1257,"context_line":"            get_args[\u0027query_string\u0027] \u003d urlencode(query_dict) if query_dict \\"},{"line_number":1258,"context_line":"                else None"},{"line_number":1259,"context_line":""},{"line_number":1260,"context_line":"            try:"},{"line_number":1261,"context_line":"                headers, body \u003d conn.get_object(container, obj, **get_args)"}],"source_content_type":"text/x-python","patch_set":23,"id":"2bcfe07d_d58eef1f","line":1258,"in_reply_to":"a7393a29_2279689b","updated":"2024-05-06 19:27:11.000000000","message":"I probably would have done that to *avoid* updating the existing tests - but I\u0027m super lazy.  Now that it\u0027s done - I guess I guess leave it?","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"aafc1ad8d3bb5cba6192a757406cfdec4e13a558","unresolved":true,"context_lines":[{"line_number":1231,"context_line":""},{"line_number":1232,"context_line":"            query_dict \u003d {"},{"line_number":1233,"context_line":"                k: v for k, v in"},{"line_number":1234,"context_line":"                [(\u0027version-id\u0027, version_id), (\u0027part-number\u0027, part_number)] if v"},{"line_number":1235,"context_line":"            }"},{"line_number":1236,"context_line":""},{"line_number":1237,"context_line":"            if skip_identical:"}],"source_content_type":"text/x-python","patch_set":24,"id":"464b43ee_e541434e","line":1234,"updated":"2024-05-06 19:27:11.000000000","message":"oh i almost missed the \"if v\" - key!\n\nI think the service can be used programatically; so I don\u0027t love the surprising behavior of zero if you pass in part_number as an integer:\n\n918337: wip: failing test | https://review.opendev.org/c/openstack/python-swiftclient/+/918337","commit_id":"f18eb808665e2f9f00386e890c5ec17684173005"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"799455b2c84ae86b0415804101e3558995288393","unresolved":false,"context_lines":[{"line_number":1231,"context_line":""},{"line_number":1232,"context_line":"            query_dict \u003d {"},{"line_number":1233,"context_line":"                k: v for k, v in"},{"line_number":1234,"context_line":"                [(\u0027version-id\u0027, version_id), (\u0027part-number\u0027, part_number)] if v"},{"line_number":1235,"context_line":"            }"},{"line_number":1236,"context_line":""},{"line_number":1237,"context_line":"            if skip_identical:"}],"source_content_type":"text/x-python","patch_set":24,"id":"c57f739c_0d9634fe","line":1234,"in_reply_to":"464b43ee_e541434e","updated":"2024-05-13 20:23:15.000000000","message":"Acknowledged","commit_id":"f18eb808665e2f9f00386e890c5ec17684173005"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3c8217b2d5f91cd7820843485ad1088b97a221d0","unresolved":true,"context_lines":[{"line_number":1241,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"},{"line_number":1242,"context_line":"                # string is ignored and the If-None-Match header will trigger"},{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                if part_number is not None or version_id is not None:"},{"line_number":1245,"context_line":"                    raise ClientException("},{"line_number":1246,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1247,"context_line":"                        \u0027version-id\u0027,"}],"source_content_type":"text/x-python","patch_set":27,"id":"46fe9617_b310f407","line":1244,"range":{"start_line":1244,"start_character":46,"end_line":1244,"end_character":68},"updated":"2024-05-14 18:33:34.000000000","message":"This seems like an incomplete fix for a separate problem. Would it be better to fix the `--skip-identical`/`--version-id` interaction in a separate change?","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":1241,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"},{"line_number":1242,"context_line":"                # string is ignored and the If-None-Match header will trigger"},{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                if part_number is not None or version_id is not None:"},{"line_number":1245,"context_line":"                    raise ClientException("},{"line_number":1246,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1247,"context_line":"                        \u0027version-id\u0027,"}],"source_content_type":"text/x-python","patch_set":27,"id":"144f7db1_af2f74cc","line":1244,"range":{"start_line":1244,"start_character":46,"end_line":1244,"end_character":68},"in_reply_to":"0f1db41b_075bc99e","updated":"2024-05-29 20:27:28.000000000","message":"Done","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"634483f4cdac1c09d220ed15808458cb6846e2b3","unresolved":true,"context_lines":[{"line_number":1241,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"},{"line_number":1242,"context_line":"                # string is ignored and the If-None-Match header will trigger"},{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                if part_number is not None or version_id is not None:"},{"line_number":1245,"context_line":"                    raise ClientException("},{"line_number":1246,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1247,"context_line":"                        \u0027version-id\u0027,"}],"source_content_type":"text/x-python","patch_set":27,"id":"cf24df5e_105c810a","line":1244,"range":{"start_line":1244,"start_character":46,"end_line":1244,"end_character":68},"in_reply_to":"46fe9617_b310f407","updated":"2024-05-15 01:36:20.000000000","message":"yes, we have a launchpad bug https://bugs.launchpad.net/python-swiftclient/+bug/2064675, and this could be addressed in a follow-on patch.","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":true,"context_lines":[{"line_number":1241,"context_line":"                # Assume the file is a large object; if we\u0027re wrong, the query"},{"line_number":1242,"context_line":"                # string is ignored and the If-None-Match header will trigger"},{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                if part_number is not None or version_id is not None:"},{"line_number":1245,"context_line":"                    raise ClientException("},{"line_number":1246,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1247,"context_line":"                        \u0027version-id\u0027,"}],"source_content_type":"text/x-python","patch_set":27,"id":"0f1db41b_075bc99e","line":1244,"range":{"start_line":1244,"start_character":46,"end_line":1244,"end_character":68},"in_reply_to":"cf24df5e_105c810a","updated":"2024-05-22 19:50:50.000000000","message":"if this change is going to change the behavior reported in the bug it should include the relevant\n\n    Partial-Bug: #2064675\n\ncommit message tag","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3c8217b2d5f91cd7820843485ad1088b97a221d0","unresolved":true,"context_lines":[{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                if part_number is not None or version_id is not None:"},{"line_number":1245,"context_line":"                    raise ClientException("},{"line_number":1246,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1247,"context_line":"                        \u0027version-id\u0027,"},{"line_number":1248,"context_line":"                        query_string\u003dquery_string)"},{"line_number":1249,"context_line":"                get_args[\u0027query_string\u0027] \u003d \u0027multipart-manifest\u003dget\u0027"}],"source_content_type":"text/x-python","patch_set":27,"id":"372b28f6_a61f77b1","line":1246,"range":{"start_line":1246,"start_character":25,"end_line":1246,"end_character":69},"updated":"2024-05-14 18:33:34.000000000","message":"Why not? It seems like there should be a reasonable semantic for it...","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"8ca2308282e12efbbfbeb9530cfda1b932b26a5d","unresolved":false,"context_lines":[{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                if part_number is not None or version_id is not None:"},{"line_number":1245,"context_line":"                    raise ClientException("},{"line_number":1246,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1247,"context_line":"                        \u0027version-id\u0027,"},{"line_number":1248,"context_line":"                        query_string\u003dquery_string)"},{"line_number":1249,"context_line":"                get_args[\u0027query_string\u0027] \u003d \u0027multipart-manifest\u003dget\u0027"}],"source_content_type":"text/x-python","patch_set":27,"id":"12f87015_cc74d2f4","line":1246,"range":{"start_line":1246,"start_character":25,"end_line":1246,"end_character":69},"in_reply_to":"0eb1c5f1_5701a220","updated":"2024-05-20 21:46:28.000000000","message":"Done","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"634483f4cdac1c09d220ed15808458cb6846e2b3","unresolved":true,"context_lines":[{"line_number":1243,"context_line":"                # the behavior we want"},{"line_number":1244,"context_line":"                if part_number is not None or version_id is not None:"},{"line_number":1245,"context_line":"                    raise ClientException("},{"line_number":1246,"context_line":"                        \u0027Cannot use --skip-identical with part-number or \u0027"},{"line_number":1247,"context_line":"                        \u0027version-id\u0027,"},{"line_number":1248,"context_line":"                        query_string\u003dquery_string)"},{"line_number":1249,"context_line":"                get_args[\u0027query_string\u0027] \u003d \u0027multipart-manifest\u003dget\u0027"}],"source_content_type":"text/x-python","patch_set":27,"id":"0eb1c5f1_5701a220","line":1246,"range":{"start_line":1246,"start_character":25,"end_line":1246,"end_character":69},"in_reply_to":"372b28f6_a61f77b1","updated":"2024-05-15 01:36:20.000000000","message":"answered it here, ref: https://review.opendev.org/c/openstack/python-swiftclient/+/902020/comment/46fe9617_b310f407/","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3c8217b2d5f91cd7820843485ad1088b97a221d0","unresolved":true,"context_lines":[{"line_number":1250,"context_line":""},{"line_number":1251,"context_line":"            if part_number is not None and int(part_number) \u003c 1:"},{"line_number":1252,"context_line":"                raise ClientException(\u0027Object GET failed\u0027,"},{"line_number":1253,"context_line":"                                      http_status\u003d400,"},{"line_number":1254,"context_line":"                                      http_reason\u003d\u0027Bad Request\u0027,"},{"line_number":1255,"context_line":"                                      http_response_content\u003d\u0027Part number \u0027"},{"line_number":1256,"context_line":"                                                            \u0027must be \u0027"}],"source_content_type":"text/x-python","patch_set":27,"id":"2ed64a5d_41304a78","line":1253,"updated":"2024-05-14 18:33:34.000000000","message":"Feels a little sneaky, saying there was a 400 despite not making any requests. Maybe better to just\n```\nraise ClientException(\u0027Part number must be an integer greater than 0\u0027)\n```\n? Speaking of, would it be better to raise `ClientException`, or `SwiftError`? Feels rather like some existing precedent:\n```\nraise SwiftError(\u0027Segment size should be an integer value\u0027)\n```","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"634483f4cdac1c09d220ed15808458cb6846e2b3","unresolved":true,"context_lines":[{"line_number":1250,"context_line":""},{"line_number":1251,"context_line":"            if part_number is not None and int(part_number) \u003c 1:"},{"line_number":1252,"context_line":"                raise ClientException(\u0027Object GET failed\u0027,"},{"line_number":1253,"context_line":"                                      http_status\u003d400,"},{"line_number":1254,"context_line":"                                      http_reason\u003d\u0027Bad Request\u0027,"},{"line_number":1255,"context_line":"                                      http_response_content\u003d\u0027Part number \u0027"},{"line_number":1256,"context_line":"                                                            \u0027must be \u0027"}],"source_content_type":"text/x-python","patch_set":27,"id":"efc233c4_4b2ed41f","line":1253,"in_reply_to":"2ed64a5d_41304a78","updated":"2024-05-15 01:36:20.000000000","message":"We get a 400 Bad Request(InvalidArgument) for when part-number\u003d0 in aws s3api as illustrated in this cross-compat test here(ref: https://review.opendev.org/c/openstack/swift/+/894580/100/test/s3api/test_mpu.py#256), so i figured i could adapt it the same way in our client. but if there\u0027s precedent for SwiftError, i could choose that alternative as well.","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":1250,"context_line":""},{"line_number":1251,"context_line":"            if part_number is not None and int(part_number) \u003c 1:"},{"line_number":1252,"context_line":"                raise ClientException(\u0027Object GET failed\u0027,"},{"line_number":1253,"context_line":"                                      http_status\u003d400,"},{"line_number":1254,"context_line":"                                      http_reason\u003d\u0027Bad Request\u0027,"},{"line_number":1255,"context_line":"                                      http_response_content\u003d\u0027Part number \u0027"},{"line_number":1256,"context_line":"                                                            \u0027must be \u0027"}],"source_content_type":"text/x-python","patch_set":27,"id":"939d1ef5_f6eaaeda","line":1253,"in_reply_to":"efc233c4_4b2ed41f","updated":"2024-05-29 20:27:28.000000000","message":"This is no longer valid.","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":true,"context_lines":[{"line_number":1115,"context_line":"                                \u0027no_download\u0027: False,"},{"line_number":1116,"context_line":"                                \u0027header\u0027: [],"},{"line_number":1117,"context_line":"                                \u0027skip_identical\u0027: False,"},{"line_number":1118,"context_line":"                                \u0027version_id\u0027: None,"},{"line_number":1119,"context_line":"                                \u0027out_directory\u0027: None,"},{"line_number":1120,"context_line":"                                \u0027checksum\u0027: True,"},{"line_number":1121,"context_line":"                                \u0027out_file\u0027: None,"}],"source_content_type":"text/x-python","patch_set":28,"id":"eab78b18_1cf320d6","line":1118,"updated":"2024-05-22 19:50:50.000000000","message":"the `part_number` option should probably be documented here and in the stat doc string as well.","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":1115,"context_line":"                                \u0027no_download\u0027: False,"},{"line_number":1116,"context_line":"                                \u0027header\u0027: [],"},{"line_number":1117,"context_line":"                                \u0027skip_identical\u0027: False,"},{"line_number":1118,"context_line":"                                \u0027version_id\u0027: None,"},{"line_number":1119,"context_line":"                                \u0027out_directory\u0027: None,"},{"line_number":1120,"context_line":"                                \u0027checksum\u0027: True,"},{"line_number":1121,"context_line":"                                \u0027out_file\u0027: None,"}],"source_content_type":"text/x-python","patch_set":28,"id":"f7dba5e3_b2a7bcec","line":1118,"in_reply_to":"eab78b18_1cf320d6","updated":"2024-05-29 20:27:28.000000000","message":"Acknowledged","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":true,"context_lines":[{"line_number":1227,"context_line":"                        \u0027response_dict\u0027: results_dict}"},{"line_number":1228,"context_line":"            query_params \u003d []"},{"line_number":1229,"context_line":"            part_number \u003d options.get(\u0027part_number\u0027)"},{"line_number":1230,"context_line":"            version_id \u003d options.get(\u0027version_id\u0027)"},{"line_number":1231,"context_line":"            if version_id is not None:"},{"line_number":1232,"context_line":"                query_params.append((\u0027version-id\u0027, options[\u0027version_id\u0027]))"},{"line_number":1233,"context_line":"            if part_number is not None and int(part_number) \u003e 0:"}],"source_content_type":"text/x-python","patch_set":28,"id":"7b012d9d_58e47e9b","line":1230,"updated":"2024-05-22 19:50:50.000000000","message":"i\u0027m not sure what to make of the difference between `options.get(\u0027version_id\u0027)` and `options[\u0027skip_identical\u0027]`\n\n`version_id` exists in the `_default_local_options` global - but changing `options.get(\u0027version_id\u0027)` to `options[\u0027version_id\u0027]` still blows up a number of tests:\n\n```\ndiff --git a/swiftclient/service.py b/swiftclient/service.py\nindex 32e0ac8..a3e8337 100644\n--- a/swiftclient/service.py\n+++ b/swiftclient/service.py\n@@ -221,6 +221,7 @@ _default_local_options \u003d {\n     \u0027skip_identical\u0027: False,\n     \u0027skip_container_put\u0027: False,\n     \u0027version_id\u0027: None,\n+    \u0027part_number\u0027: None,\n     \u0027yes_all\u0027: False,\n     \u0027read_acl\u0027: None,\n     \u0027write_acl\u0027: None,\n@@ -1227,7 +1228,7 @@ class SwiftService:\n                         \u0027response_dict\u0027: results_dict}\n             query_params \u003d []\n             part_number \u003d options.get(\u0027part_number\u0027)\n-            version_id \u003d options.get(\u0027version_id\u0027)\n+            version_id \u003d options[\u0027version_id\u0027]\n             if version_id is not None:\n                 query_params.append((\u0027version-id\u0027, options[\u0027version_id\u0027]))\n             if part_number is not None and int(part_number) \u003e 0:\n```\n\n\n```\nFAILED python-swiftclient/test/unit/test_service.py::TestServiceDownload::test_download_object_job_skip_identical - AssertionError: {\u0027act[90 chars]or\u0027: KeyError(\u0027version_id\u0027), \u0027traceback\u0027: \u0027Tra[312 chars]\u0027: 2} !\u003d {\u0027act[90 chars]or\u0027: ClientException(\u0027Object GET failed\u0027), \u0027re[124 chars]ANY\u003e}\nFAILED python-swiftclient/test/unit/test_service.py::TestServiceDownload::test_download_object_job_skip_identical_dlo - AttributeError: \u0027KeyError\u0027 object has no attribute \u0027msg\u0027\nFAILED python-swiftclient/test/unit/test_service.py::TestServiceDownload::test_download_object_job_skip_identical_nested_slo - AttributeError: \u0027KeyError\u0027 object has no attribute \u0027msg\u0027\nFAILED python-swiftclient/test/unit/test_service.py::TestServiceDownload::test_download_skip_identical_with_part_num_or_version_id - AssertionError: False is not true\n```\n\nSince our tests are already inconsistent about applying `options \u003d dict(s._options, **options)`, e.g.\n\n\n```\n            with mock.patch(\u0027swiftclient.service.get_conn\u0027,\n                            return_value\u003dmock_conn):\n                r \u003d s._download_object_job(conn\u003dmock_conn,\n                                           container\u003d\u0027test_c\u0027,\n                                           obj\u003d\u0027test_o\u0027,\n                                           options\u003d{\u0027out_file\u0027: f.name,\n                                                    \u0027out_directory\u0027: None,\n                                                    \u0027prefix\u0027: None,\n                                                    \u0027remove_prefix\u0027: False,\n                                                    \u0027header\u0027: {},\n                                                    \u0027yes_all\u0027: False,\n                                                    \u0027skip_identical\u0027: True})\n    \n            err \u003d r.pop(\u0027error\u0027)\n\u003e           self.assertEqual(\"Large object is identical\", err.msg)\nE           AttributeError: \u0027KeyError\u0027 object has no attribute \u0027msg\u0027\n\npython-swiftclient/test/unit/test_service.py:3001: AttributeError\n```\n\nI would suggest there\u0027s no good reason to add `part_number` to the `_default_local_options` structure?  It wouldn\u0027t make sense to me as global service level option and probably neither does version_id?","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":1227,"context_line":"                        \u0027response_dict\u0027: results_dict}"},{"line_number":1228,"context_line":"            query_params \u003d []"},{"line_number":1229,"context_line":"            part_number \u003d options.get(\u0027part_number\u0027)"},{"line_number":1230,"context_line":"            version_id \u003d options.get(\u0027version_id\u0027)"},{"line_number":1231,"context_line":"            if version_id is not None:"},{"line_number":1232,"context_line":"                query_params.append((\u0027version-id\u0027, options[\u0027version_id\u0027]))"},{"line_number":1233,"context_line":"            if part_number is not None and int(part_number) \u003e 0:"}],"source_content_type":"text/x-python","patch_set":28,"id":"5238393f_14315b17","line":1230,"in_reply_to":"7b012d9d_58e47e9b","updated":"2024-05-29 20:27:28.000000000","message":"I actually missed the spot where i should have included part_number in the _default_local_options. It has been included in this revision.","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"}],"swiftclient/shell.py":[{"author":{"_account_id":12620,"name":"Alexander Corwin","email":"ancorwin@gmail.com","username":"acorwin"},"change_message_id":"bfe571f2ac096b4721bf8e6e4b5e22a32ae17170","unresolved":true,"context_lines":[{"line_number":731,"context_line":"    if options[\u0027version_id\u0027] and len(args) \u003c 2:"},{"line_number":732,"context_line":"        exit(\u0027--version-id option only allowed for object stats\u0027)"},{"line_number":733,"context_line":"    if options[\u0027version_id\u0027] and len(args) \u003c 2:"},{"line_number":734,"context_line":"        exit(\u0027--version-id option only allowed for object stats\u0027)"},{"line_number":735,"context_line":""},{"line_number":736,"context_line":"    with SwiftService(options\u003doptions) as swift:"},{"line_number":737,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":1,"id":"0db9e57c_57c6bcca","line":734,"updated":"2023-11-28 17:16:19.000000000","message":"this is a copy paste, i think you meant to change this to `--part-number`","commit_id":"a3f7169129fda0fc6c2e042bd8a128798c6faa04"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"f25de8a338fef29a159664ff80b50d3644a833ed","unresolved":false,"context_lines":[{"line_number":731,"context_line":"    if options[\u0027version_id\u0027] and len(args) \u003c 2:"},{"line_number":732,"context_line":"        exit(\u0027--version-id option only allowed for object stats\u0027)"},{"line_number":733,"context_line":"    if options[\u0027version_id\u0027] and len(args) \u003c 2:"},{"line_number":734,"context_line":"        exit(\u0027--version-id option only allowed for object stats\u0027)"},{"line_number":735,"context_line":""},{"line_number":736,"context_line":"    with SwiftService(options\u003doptions) as swift:"},{"line_number":737,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":1,"id":"26f0acf5_41e9f714","line":734,"in_reply_to":"0db9e57c_57c6bcca","updated":"2023-12-20 19:42:03.000000000","message":"Done","commit_id":"a3f7169129fda0fc6c2e042bd8a128798c6faa04"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ee9ef177f9efa8762ce1a067960773e765dd33b0","unresolved":true,"context_lines":[{"line_number":382,"context_line":"    if options[\u0027out_file\u0027] and len(args) !\u003d 2:"},{"line_number":383,"context_line":"        exit(\u0027-o option only allowed for single file downloads\u0027)"},{"line_number":384,"context_line":"    elif options[\u0027out_file\u0027] and options[\u0027part_number\u0027] and len(args) !\u003d 4:"},{"line_number":385,"context_line":"        exit(\u0027--part-number only allowed for single file downloads\u0027)"},{"line_number":386,"context_line":""},{"line_number":387,"context_line":"    if not options[\u0027prefix\u0027]:"},{"line_number":388,"context_line":"        options[\u0027remove_prefix\u0027] \u003d False"}],"source_content_type":"text/x-python","patch_set":16,"id":"75ae2929_f810e501","line":385,"updated":"2024-04-17 22:58:25.000000000","message":"is this tested?","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cdd8ce5fe66bc79872b8d2d982df6049deb3d0eb","unresolved":false,"context_lines":[{"line_number":382,"context_line":"    if options[\u0027out_file\u0027] and len(args) !\u003d 2:"},{"line_number":383,"context_line":"        exit(\u0027-o option only allowed for single file downloads\u0027)"},{"line_number":384,"context_line":"    elif options[\u0027out_file\u0027] and options[\u0027part_number\u0027] and len(args) !\u003d 4:"},{"line_number":385,"context_line":"        exit(\u0027--part-number only allowed for single file downloads\u0027)"},{"line_number":386,"context_line":""},{"line_number":387,"context_line":"    if not options[\u0027prefix\u0027]:"},{"line_number":388,"context_line":"        options[\u0027remove_prefix\u0027] \u003d False"}],"source_content_type":"text/x-python","patch_set":16,"id":"58dec7e7_c2c2c7db","line":385,"in_reply_to":"75ae2929_f810e501","updated":"2024-04-23 18:42:19.000000000","message":"It wasn\u0027t and the logic was wrong, I went ahead and removed it.","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ee9ef177f9efa8762ce1a067960773e765dd33b0","unresolved":true,"context_lines":[{"line_number":392,"context_line":"    if options[\u0027out_directory\u0027] and len(args) \u003d\u003d 4 and options[\u0027part_number\u0027]:"},{"line_number":393,"context_line":"        exit(\u0027Please use -o option for single file downloads and renames\u0027)"},{"line_number":394,"context_line":""},{"line_number":395,"context_line":"    if options[\u0027part_number\u0027] and len(args) \u003c 4:"},{"line_number":396,"context_line":"        exit(\u0027--part-number option only allowed for object downloads\u0027)"},{"line_number":397,"context_line":""},{"line_number":398,"context_line":"    if (not args and not options[\u0027yes_all\u0027]) or (args and options[\u0027yes_all\u0027]):"}],"source_content_type":"text/x-python","patch_set":16,"id":"c8ca568d_d469a39f","line":395,"updated":"2024-04-17 22:58:25.000000000","message":"where did you come up with args \u003c 4?","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cdd8ce5fe66bc79872b8d2d982df6049deb3d0eb","unresolved":false,"context_lines":[{"line_number":392,"context_line":"    if options[\u0027out_directory\u0027] and len(args) \u003d\u003d 4 and options[\u0027part_number\u0027]:"},{"line_number":393,"context_line":"        exit(\u0027Please use -o option for single file downloads and renames\u0027)"},{"line_number":394,"context_line":""},{"line_number":395,"context_line":"    if options[\u0027part_number\u0027] and len(args) \u003c 4:"},{"line_number":396,"context_line":"        exit(\u0027--part-number option only allowed for object downloads\u0027)"},{"line_number":397,"context_line":""},{"line_number":398,"context_line":"    if (not args and not options[\u0027yes_all\u0027]) or (args and options[\u0027yes_all\u0027]):"}],"source_content_type":"text/x-python","patch_set":16,"id":"83b14736_534d95ea","line":395,"in_reply_to":"c8ca568d_d469a39f","updated":"2024-04-23 18:42:19.000000000","message":"Since the tests were wrong i came up with a different exit strategy","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ee9ef177f9efa8762ce1a067960773e765dd33b0","unresolved":true,"context_lines":[{"line_number":736,"context_line":"    args \u003d args[1:]"},{"line_number":737,"context_line":"    if options[\u0027version_id\u0027] and len(args) \u003c 2:"},{"line_number":738,"context_line":"        exit(\u0027--version-id option only allowed for object stats\u0027)"},{"line_number":739,"context_line":"    if options[\u0027part_number\u0027] and len(args) \u003c 2:"},{"line_number":740,"context_line":"        exit(\u0027--part-number option only allowed for object stats\u0027)"},{"line_number":741,"context_line":""},{"line_number":742,"context_line":"    with SwiftService(options\u003doptions) as swift:"}],"source_content_type":"text/x-python","patch_set":16,"id":"88e14975_c055dff0","line":739,"updated":"2024-04-17 22:58:25.000000000","message":"len(args) \u003c 2 makes sense in stat - why not in download?","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cdd8ce5fe66bc79872b8d2d982df6049deb3d0eb","unresolved":false,"context_lines":[{"line_number":736,"context_line":"    args \u003d args[1:]"},{"line_number":737,"context_line":"    if options[\u0027version_id\u0027] and len(args) \u003c 2:"},{"line_number":738,"context_line":"        exit(\u0027--version-id option only allowed for object stats\u0027)"},{"line_number":739,"context_line":"    if options[\u0027part_number\u0027] and len(args) \u003c 2:"},{"line_number":740,"context_line":"        exit(\u0027--part-number option only allowed for object stats\u0027)"},{"line_number":741,"context_line":""},{"line_number":742,"context_line":"    with SwiftService(options\u003doptions) as swift:"}],"source_content_type":"text/x-python","patch_set":16,"id":"0eac1e1f_98bf1b37","line":739,"in_reply_to":"88e14975_c055dff0","updated":"2024-04-23 18:42:19.000000000","message":"I have applied the same in the download operation, i didn\u0027t have the unit tests setup correctly","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":12620,"name":"Alexander Corwin","email":"ancorwin@gmail.com","username":"acorwin"},"change_message_id":"7e0f45e4bb730e58e8fa32c6e07ab7ab4b1e8e11","unresolved":true,"context_lines":[{"line_number":351,"context_line":"        help\u003d\u0027Download a specific version of a versioned object\u0027)"},{"line_number":352,"context_line":"    parser.add_argument("},{"line_number":353,"context_line":"        \u0027--part-number\u0027, action\u003d\u0027store\u0027, default\u003dNone,"},{"line_number":354,"context_line":"        help\u003d\u0027Download a specific version of a versioned object\u0027)"},{"line_number":355,"context_line":"    parser.add_argument("},{"line_number":356,"context_line":"        \u0027--ignore-checksum\u0027, action\u003d\u0027store_false\u0027, dest\u003d\u0027checksum\u0027,"},{"line_number":357,"context_line":"        default\u003dTrue, help\u003d\u0027Turn off checksum validation for downloads.\u0027)"}],"source_content_type":"text/x-python","patch_set":23,"id":"637b0b08_19242ade","line":354,"updated":"2024-05-03 00:13:17.000000000","message":"copypaste error","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"8c7914220d12aff54d62fb2460eb78f3c75b46fd","unresolved":false,"context_lines":[{"line_number":351,"context_line":"        help\u003d\u0027Download a specific version of a versioned object\u0027)"},{"line_number":352,"context_line":"    parser.add_argument("},{"line_number":353,"context_line":"        \u0027--part-number\u0027, action\u003d\u0027store\u0027, default\u003dNone,"},{"line_number":354,"context_line":"        help\u003d\u0027Download a specific version of a versioned object\u0027)"},{"line_number":355,"context_line":"    parser.add_argument("},{"line_number":356,"context_line":"        \u0027--ignore-checksum\u0027, action\u003d\u0027store_false\u0027, dest\u003d\u0027checksum\u0027,"},{"line_number":357,"context_line":"        default\u003dTrue, help\u003d\u0027Turn off checksum validation for downloads.\u0027)"}],"source_content_type":"text/x-python","patch_set":23,"id":"f9686c87_b3eeeb15","line":354,"in_reply_to":"637b0b08_19242ade","updated":"2024-05-03 20:48:10.000000000","message":"Done","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3c8217b2d5f91cd7820843485ad1088b97a221d0","unresolved":true,"context_lines":[{"line_number":351,"context_line":"        help\u003d\u0027Download a specific version of a versioned object\u0027)"},{"line_number":352,"context_line":"    parser.add_argument("},{"line_number":353,"context_line":"        \u0027--part-number\u0027, action\u003d\u0027store\u0027, default\u003dNone,"},{"line_number":354,"context_line":"        help\u003d\u0027Download a specific part of a static large object\u0027)"},{"line_number":355,"context_line":"    parser.add_argument("},{"line_number":356,"context_line":"        \u0027--ignore-checksum\u0027, action\u003d\u0027store_false\u0027, dest\u003d\u0027checksum\u0027,"},{"line_number":357,"context_line":"        default\u003dTrue, help\u003d\u0027Turn off checksum validation for downloads.\u0027)"}],"source_content_type":"text/x-python","patch_set":27,"id":"050bb92c_7cbf777b","line":354,"updated":"2024-05-14 18:33:34.000000000","message":"Should this include a `type\u003dint`, so the argparser will bomb out if you do `--part-number foo`? If we really want to get fancy, we could even define a `positive_int` function, but FWIW other places (`object_threads`, for example) would just handle it like `if options[\u0027part_number\u0027] \u003c\u003d 0: output_manager.error(...)`","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"634483f4cdac1c09d220ed15808458cb6846e2b3","unresolved":false,"context_lines":[{"line_number":351,"context_line":"        help\u003d\u0027Download a specific version of a versioned object\u0027)"},{"line_number":352,"context_line":"    parser.add_argument("},{"line_number":353,"context_line":"        \u0027--part-number\u0027, action\u003d\u0027store\u0027, default\u003dNone,"},{"line_number":354,"context_line":"        help\u003d\u0027Download a specific part of a static large object\u0027)"},{"line_number":355,"context_line":"    parser.add_argument("},{"line_number":356,"context_line":"        \u0027--ignore-checksum\u0027, action\u003d\u0027store_false\u0027, dest\u003d\u0027checksum\u0027,"},{"line_number":357,"context_line":"        default\u003dTrue, help\u003d\u0027Turn off checksum validation for downloads.\u0027)"}],"source_content_type":"text/x-python","patch_set":27,"id":"0839cac8_469b294a","line":354,"in_reply_to":"050bb92c_7cbf777b","updated":"2024-05-15 01:36:20.000000000","message":"Done","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3c8217b2d5f91cd7820843485ad1088b97a221d0","unresolved":true,"context_lines":[{"line_number":718,"context_line":"        help\u003d\u0027Report stat of a specific version of a versioned object\u0027)"},{"line_number":719,"context_line":"    parser.add_argument("},{"line_number":720,"context_line":"        \u0027--part-number\u0027, action\u003d\u0027store\u0027, default\u003dNone,"},{"line_number":721,"context_line":"        help\u003d\u0027Report a specific part of a static large object\u0027)"},{"line_number":722,"context_line":"    parser.add_argument("},{"line_number":723,"context_line":"        \u0027-H\u0027, \u0027--header\u0027, action\u003d\u0027append\u0027, dest\u003d\u0027header\u0027,"},{"line_number":724,"context_line":"        default\u003d[],"}],"source_content_type":"text/x-python","patch_set":27,"id":"84ae704d_0cb86d16","line":721,"updated":"2024-05-14 18:33:34.000000000","message":"Here, too -- a `type` might be good.","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"634483f4cdac1c09d220ed15808458cb6846e2b3","unresolved":false,"context_lines":[{"line_number":718,"context_line":"        help\u003d\u0027Report stat of a specific version of a versioned object\u0027)"},{"line_number":719,"context_line":"    parser.add_argument("},{"line_number":720,"context_line":"        \u0027--part-number\u0027, action\u003d\u0027store\u0027, default\u003dNone,"},{"line_number":721,"context_line":"        help\u003d\u0027Report a specific part of a static large object\u0027)"},{"line_number":722,"context_line":"    parser.add_argument("},{"line_number":723,"context_line":"        \u0027-H\u0027, \u0027--header\u0027, action\u003d\u0027append\u0027, dest\u003d\u0027header\u0027,"},{"line_number":724,"context_line":"        default\u003d[],"}],"source_content_type":"text/x-python","patch_set":27,"id":"d7cdc364_c146017b","line":721,"in_reply_to":"84ae704d_0cb86d16","updated":"2024-05-15 01:36:20.000000000","message":"Done","commit_id":"a9dcc68a0a973aab0ba49b4421811974f0ff1267"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":true,"context_lines":[{"line_number":412,"context_line":"            st_download_options, st_download_help)"},{"line_number":413,"context_line":"        return"},{"line_number":414,"context_line":""},{"line_number":415,"context_line":"    if options[\u0027part_number\u0027] and options[\u0027part_number\u0027] \u003c\u003d 0:"},{"line_number":416,"context_line":"        output_manager.error("},{"line_number":417,"context_line":"            \u0027ERROR: option --part-number should be a positive integer.\u0027"},{"line_number":418,"context_line":"            \u0027\\n\\nUsage: %s download %s\\n%s\u0027, BASENAME,"}],"source_content_type":"text/x-python","patch_set":28,"id":"52235758_c9942ce7","line":415,"updated":"2024-05-22 19:50:50.000000000","message":"what is your expection for this boolean AND logic when part_number is the integer 0 and evalues false?\n\n```\nvagrant@saio:~$ swift upload test test.big --use-slo -S 1000000\ntest.big segment 1\ntest.big segment 5\ntest.big segment 3\ntest.big segment 4\ntest.big segment 2\ntest.big segment 7\ntest.big segment 8\ntest.big segment 6\ntest.big segment 0\ntest.big\nvagrant@saio:~$ swift stat test test.big --part-number 1\n               Account: AUTH_test\n             Container: test\n                Object: test.big\n          Content Type: application/octet-stream\n        Content Length: 1000000\n         Last Modified: Wed, 22 May 2024 18:45:09 GMT\n                  ETag: \"cac0f63d4c7cfc6a4abdcb06b382e465\"\n            Meta Mtime: 1713206008.541586\n X-Static-Large-Object: True\n           X-Timestamp: 1716403508.35154\n         Accept-Ranges: bytes\n       X-Manifest-Etag: 3238eb2edf56735b63034575032ac54c\n         Content-Range: bytes 0-999999/10000000\n         X-Parts-Count: 10\n            X-Trans-Id: txa9fdb97a581d4aaf96d3b-00664e3d3a\nX-Openstack-Request-Id: txa9fdb97a581d4aaf96d3b-00664e3d3a\nvagrant@saio:~$ swift stat test test.big --part-number 30\nObject HEAD failed: http://saio:8080/v1/AUTH_test/test/test.big?part-number\u003d30 416 Requested Range Not Satisfiable\nFailed Transaction ID: txdf74e7a0a4ac43f89ee2b-00664e3d45\nvagrant@saio:~$ echo $?\n1\nvagrant@saio:~$ swift stat test test.big --part-number 0\n               Account: AUTH_test\n             Container: test\n                Object: test.big\n          Content Type: application/octet-stream\n        Content Length: 10000000\n         Last Modified: Wed, 22 May 2024 18:45:09 GMT\n                  ETag: \"cac0f63d4c7cfc6a4abdcb06b382e465\"\n            Meta Mtime: 1713206008.541586\n X-Static-Large-Object: True\n           X-Timestamp: 1716403508.35154\n         Accept-Ranges: bytes\n       X-Manifest-Etag: 3238eb2edf56735b63034575032ac54c\n            X-Trans-Id: tx53b36aafe29e40ff98152-00664e3e32\nX-Openstack-Request-Id: tx53b36aafe29e40ff98152-00664e3e32\nvagrant@saio:~$ echo $?\n0\n```","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":412,"context_line":"            st_download_options, st_download_help)"},{"line_number":413,"context_line":"        return"},{"line_number":414,"context_line":""},{"line_number":415,"context_line":"    if options[\u0027part_number\u0027] and options[\u0027part_number\u0027] \u003c\u003d 0:"},{"line_number":416,"context_line":"        output_manager.error("},{"line_number":417,"context_line":"            \u0027ERROR: option --part-number should be a positive integer.\u0027"},{"line_number":418,"context_line":"            \u0027\\n\\nUsage: %s download %s\\n%s\u0027, BASENAME,"}],"source_content_type":"text/x-python","patch_set":28,"id":"8b8e9997_5ed93886","line":415,"in_reply_to":"52235758_c9942ce7","updated":"2024-05-29 20:27:28.000000000","message":"Done","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"}],"test/unit/test_service.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":2634,"context_line":""},{"line_number":2635,"context_line":"        mock_conn.get_object.assert_called_once_with("},{"line_number":2636,"context_line":"            \u0027test_c\u0027, \u0027test_o\u0027, resp_chunk_size\u003d65536, headers\u003d{},"},{"line_number":2637,"context_line":"            response_dict\u003d{}, query_string\u003dNone"},{"line_number":2638,"context_line":"        )"},{"line_number":2639,"context_line":"        self.assertEqual(expected_r, actual_r)"},{"line_number":2640,"context_line":""}],"source_content_type":"text/x-python","patch_set":23,"id":"0583f394_fd9a0932","line":2637,"updated":"2024-05-02 23:04:40.000000000","message":"right, and this is because previously the code wasn\u0027t setting this arg unless there was query params\n\ni guess it\u0027s only like what 5 tests to udpate?","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"8c7914220d12aff54d62fb2460eb78f3c75b46fd","unresolved":false,"context_lines":[{"line_number":2634,"context_line":""},{"line_number":2635,"context_line":"        mock_conn.get_object.assert_called_once_with("},{"line_number":2636,"context_line":"            \u0027test_c\u0027, \u0027test_o\u0027, resp_chunk_size\u003d65536, headers\u003d{},"},{"line_number":2637,"context_line":"            response_dict\u003d{}, query_string\u003dNone"},{"line_number":2638,"context_line":"        )"},{"line_number":2639,"context_line":"        self.assertEqual(expected_r, actual_r)"},{"line_number":2640,"context_line":""}],"source_content_type":"text/x-python","patch_set":23,"id":"71fbb69d_16b81810","line":2637,"in_reply_to":"0583f394_fd9a0932","updated":"2024-05-03 20:48:10.000000000","message":"True.","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":2831,"context_line":"            f.flush()"},{"line_number":2832,"context_line":""},{"line_number":2833,"context_line":"            err \u003d ClientException(\u0027Cannot use --skip-identical with \u0027"},{"line_number":2834,"context_line":"                                  \u0027part-number or version-id\u0027)"},{"line_number":2835,"context_line":"            mock_conn \u003d mock.Mock()"},{"line_number":2836,"context_line":"            type(mock_conn).attempts \u003d mock.PropertyMock(return_value\u003d0)"},{"line_number":2837,"context_line":""}],"source_content_type":"text/x-python","patch_set":23,"id":"18b4df25_9411798f","line":2834,"updated":"2024-05-02 23:04:40.000000000","message":"I don\u0027t think you need this - _download_object_job should return this error on it\u0027s own.","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"8c7914220d12aff54d62fb2460eb78f3c75b46fd","unresolved":false,"context_lines":[{"line_number":2831,"context_line":"            f.flush()"},{"line_number":2832,"context_line":""},{"line_number":2833,"context_line":"            err \u003d ClientException(\u0027Cannot use --skip-identical with \u0027"},{"line_number":2834,"context_line":"                                  \u0027part-number or version-id\u0027)"},{"line_number":2835,"context_line":"            mock_conn \u003d mock.Mock()"},{"line_number":2836,"context_line":"            type(mock_conn).attempts \u003d mock.PropertyMock(return_value\u003d0)"},{"line_number":2837,"context_line":""}],"source_content_type":"text/x-python","patch_set":23,"id":"948de1e3_855ef73f","line":2834,"in_reply_to":"18b4df25_9411798f","updated":"2024-05-03 20:48:10.000000000","message":"Done","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":2849,"context_line":"                                                \u0027skip_identical\u0027: True,"},{"line_number":2850,"context_line":"                                                options: \u00271\u0027})"},{"line_number":2851,"context_line":"                self.assertTrue(\u0027Cannot use --skip-identical with part-number \u0027"},{"line_number":2852,"context_line":"                                \u0027or version-id\u0027 in str(err))"},{"line_number":2853,"context_line":"                self.assertEqual(mock_conn.get_object.call_count, 0)"},{"line_number":2854,"context_line":""},{"line_number":2855,"context_line":"    def test_download_object_job_skip_identical_dlo(self):"}],"source_content_type":"text/x-python","patch_set":23,"id":"2b954709_801a0aaa","line":2852,"updated":"2024-05-02 23:04:40.000000000","message":"wait a minute... what is this even asserting?\n\nif you capture `r \u003d s._download_object_job` I think you can use:\n\n    assertFalse(r[\u0027success\u0027])\n    assertIn(\u0027expected error\u0027, r[\u0027error\u0027])\n    \nthis is what I came up with:\n    \n    diff --git a/test/unit/test_service.py b/test/unit/test_service.py\n    index aee1b5b..481684e 100644\n    --- a/test/unit/test_service.py\n    +++ b/test/unit/test_service.py\n    @@ -2833,23 +2833,30 @@ class TestServiceDownload(_TestServiceBase):\n                 err \u003d ClientException(\u0027Cannot use --skip-identical with \u0027\n                                       \u0027part-number or version-id\u0027)\n                 mock_conn \u003d mock.Mock()\n    -            type(mock_conn).attempts \u003d mock.PropertyMock(return_value\u003d0)\n    +            mock_conn.attempts \u003d 0\n     \n                 s \u003d SwiftService()\n    -            for options in [\u0027part_number\u0027, \u0027version_id\u0027]:\n    -                s._download_object_job(conn\u003dmock_conn,\n    -                                       container\u003d\u0027test_c\u0027,\n    -                                       obj\u003d\u0027test_o\u0027,\n    -                                       options\u003d{\u0027out_file\u0027: f.name,\n    -                                                \u0027out_directory\u0027: None,\n    -                                                \u0027prefix\u0027: None,\n    -                                                \u0027remove_prefix\u0027: False,\n    -                                                \u0027header\u0027: {},\n    -                                                \u0027yes_all\u0027: False,\n    -                                                \u0027skip_identical\u0027: True,\n    -                                                options: \u00271\u0027})\n    -                self.assertTrue(\u0027Cannot use --skip-identical with part-number \u0027\n    -                                \u0027or version-id\u0027 in str(err))\n    +            base_options \u003d {\n    +                \u0027out_file\u0027: f.name,\n    +                \u0027out_directory\u0027: None,\n    +                \u0027prefix\u0027: None,\n    +                \u0027remove_prefix\u0027: False,\n    +                \u0027header\u0027: {},\n    +                \u0027yes_all\u0027: False,\n    +                # skip_identical isn\u0027t allowed with some options\n    +                \u0027skip_identical\u0027: True,\n    +            }\n    +            for option_name in [\u0027part_number\u0027, \u0027version_id\u0027]:\n    +                options \u003d dict(base_options)\n    +                options[option_name] \u003d \u00271\u0027\n    +                r \u003d s._download_object_job(\n    +                    conn\u003dmock_conn,\n    +                    container\u003d\u0027test_c\u0027,\n    +                    obj\u003d\u0027test_o\u0027,\n    +                    options\u003doptions)\n    +                self.assertFalse(r[\u0027success\u0027])\n    +                self.assertIn(\u0027Cannot use --skip-identical with part-number \u0027\n    +                              \u0027or version-id\u0027, str(r[\u0027error\u0027]))\n                     self.assertEqual(mock_conn.get_object.call_count, 0)\n     \n         def test_download_object_job_skip_identical_dlo(self):","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"40b5c0cce098c2c79f2c4d1684bb20937c051372","unresolved":false,"context_lines":[{"line_number":2849,"context_line":"                                                \u0027skip_identical\u0027: True,"},{"line_number":2850,"context_line":"                                                options: \u00271\u0027})"},{"line_number":2851,"context_line":"                self.assertTrue(\u0027Cannot use --skip-identical with part-number \u0027"},{"line_number":2852,"context_line":"                                \u0027or version-id\u0027 in str(err))"},{"line_number":2853,"context_line":"                self.assertEqual(mock_conn.get_object.call_count, 0)"},{"line_number":2854,"context_line":""},{"line_number":2855,"context_line":"    def test_download_object_job_skip_identical_dlo(self):"}],"source_content_type":"text/x-python","patch_set":23,"id":"68315f2a_138baeec","line":2852,"in_reply_to":"2b954709_801a0aaa","updated":"2024-05-06 17:56:48.000000000","message":"Done","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":2850,"context_line":"                                                options: \u00271\u0027})"},{"line_number":2851,"context_line":"                self.assertTrue(\u0027Cannot use --skip-identical with part-number \u0027"},{"line_number":2852,"context_line":"                                \u0027or version-id\u0027 in str(err))"},{"line_number":2853,"context_line":"                self.assertEqual(mock_conn.get_object.call_count, 0)"},{"line_number":2854,"context_line":""},{"line_number":2855,"context_line":"    def test_download_object_job_skip_identical_dlo(self):"},{"line_number":2856,"context_line":"        with tempfile.NamedTemporaryFile() as f:"}],"source_content_type":"text/x-python","patch_set":23,"id":"c792076d_57aa0bb9","line":2853,"updated":"2024-05-02 23:04:40.000000000","message":"ok, and eventually if we fix https://bugs.launchpad.net/python-swiftclient/+bug/2064675 this test can just be \"skip_identical_with_part_num\" - thanks for adding this!","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"8c7914220d12aff54d62fb2460eb78f3c75b46fd","unresolved":false,"context_lines":[{"line_number":2850,"context_line":"                                                options: \u00271\u0027})"},{"line_number":2851,"context_line":"                self.assertTrue(\u0027Cannot use --skip-identical with part-number \u0027"},{"line_number":2852,"context_line":"                                \u0027or version-id\u0027 in str(err))"},{"line_number":2853,"context_line":"                self.assertEqual(mock_conn.get_object.call_count, 0)"},{"line_number":2854,"context_line":""},{"line_number":2855,"context_line":"    def test_download_object_job_skip_identical_dlo(self):"},{"line_number":2856,"context_line":"        with tempfile.NamedTemporaryFile() as f:"}],"source_content_type":"text/x-python","patch_set":23,"id":"6846e56e_bba4e257","line":2853,"in_reply_to":"c792076d_57aa0bb9","updated":"2024-05-03 20:48:10.000000000","message":"Done","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":true,"context_lines":[{"line_number":2916,"context_line":"        self.assertEqual(actual_r[\u0027error\u0027].http_reason, err.http_reason)"},{"line_number":2917,"context_line":"        self.assertEqual(actual_r[\u0027error\u0027].http_response_content,"},{"line_number":2918,"context_line":"                         err.http_response_content)"},{"line_number":2919,"context_line":"        self.assertEqual(actual_r[\u0027error\u0027].http_query, err.http_query)"},{"line_number":2920,"context_line":""},{"line_number":2921,"context_line":"    def test_download_skip_identical_with_part_num_or_version_id(self):"},{"line_number":2922,"context_line":"        with tempfile.NamedTemporaryFile() as f:"}],"source_content_type":"text/x-python","patch_set":28,"id":"4e1aaf48_4b4345db","line":2919,"updated":"2024-05-22 19:50:50.000000000","message":"writing negative tests that use mocks are a bit of an art... the point is to prevent bugs.\n\nLike this test *seems* to be suggestion this code should get a `resp` that has `resp[\u0027success\u0027] \u003d False`:\n\n```\nimport sys\nfrom swiftclient.service import SwiftService\n\ncontainer, obj \u003d sys.argv[-2:]\nwith SwiftService() as swift:\n    resp_iter \u003d swift.download(container, [obj], options\u003d{\u0027part_number\u0027: 0})\n    for resp in resp_iter:\n        print(resp)\n```\n\nDo I understand the behavior this test is asserting correctly?  Is that how the code behaves for you?\n\nThe goal of this tests should be to prevent a bug like \"if a user explicitly passes part_number\u003d0 we don\u0027t ignore it and instead omit the query param and accidently download the whole object\"\n\nOne way we could prevent such a bug would be to check that the UUT actually MADE a request that would have generated an error like we stubbed above:\n\n```\ndiff --git a/test/unit/test_service.py b/test/unit/test_service.py\nindex 99c1794..9a35acf 100644\n--- a/test/unit/test_service.py\n+++ b/test/unit/test_service.py\n@@ -2917,6 +2917,10 @@ class TestServiceDownload(_TestServiceBase):\n         self.assertEqual(actual_r[\u0027error\u0027].http_response_content,\n                          err.http_response_content)\n         self.assertEqual(actual_r[\u0027error\u0027].http_query, err.http_query)\n+        mock_conn.get_object.assert_called_once_with(\n+            \u0027test_c\u0027, \u0027test_o\u0027, resp_chunk_size\u003d65536, headers\u003d{},\n+            response_dict\u003d{}, query_string\u003d\u0027part-number\u003d0\u0027,\n+        )\n \n     def test_download_skip_identical_with_part_num_or_version_id(self):\n         with tempfile.NamedTemporaryFile() as f:\n```\n\nIf we were to MAKE such an assertion, and see an assertion error like:\n\n```\nE           AssertionError: expected call not found.\nE           Expected: get_object(\u0027test_c\u0027, \u0027test_o\u0027, resp_chunk_size\u003d65536, headers\u003d{}, response_dict\u003d{}, query_string\u003d\u0027part-number\u003d0\u0027)\nE           Actual: get_object(\u0027test_c\u0027, \u0027test_o\u0027, resp_chunk_size\u003d65536, headers\u003d{}, response_dict\u003d{})\n```\n\nthat would be telling us that SwiftService never sent a ?part-number\u003d0 request, so our stub response that returned a 400 isn\u0027t a good stub for the behavior we\u0027re trying to maintain.\n\nDoes that make sense?  Can you add this assertion and make sure the code is doing what we want?","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":2916,"context_line":"        self.assertEqual(actual_r[\u0027error\u0027].http_reason, err.http_reason)"},{"line_number":2917,"context_line":"        self.assertEqual(actual_r[\u0027error\u0027].http_response_content,"},{"line_number":2918,"context_line":"                         err.http_response_content)"},{"line_number":2919,"context_line":"        self.assertEqual(actual_r[\u0027error\u0027].http_query, err.http_query)"},{"line_number":2920,"context_line":""},{"line_number":2921,"context_line":"    def test_download_skip_identical_with_part_num_or_version_id(self):"},{"line_number":2922,"context_line":"        with tempfile.NamedTemporaryFile() as f:"}],"source_content_type":"text/x-python","patch_set":28,"id":"fddea60f_161022b7","line":2919,"in_reply_to":"4e1aaf48_4b4345db","updated":"2024-05-29 20:27:28.000000000","message":"This test no longer applies to this error-case since its being handled in `/swiftclient/shell.py`","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":true,"context_lines":[{"line_number":2948,"context_line":"                self.assertFalse(r[\u0027success\u0027])"},{"line_number":2949,"context_line":"                self.assertTrue(\u0027Cannot use --skip-identical with part-number \u0027"},{"line_number":2950,"context_line":"                                \u0027or version-id\u0027 in str(r[\u0027error\u0027]))"},{"line_number":2951,"context_line":"                self.assertEqual(mock_conn.get_object.call_count, 0)"},{"line_number":2952,"context_line":""},{"line_number":2953,"context_line":"    def test_download_object_job_skip_identical_dlo(self):"},{"line_number":2954,"context_line":"        with tempfile.NamedTemporaryFile() as f:"}],"source_content_type":"text/x-python","patch_set":28,"id":"5bae6062_9f4945bf","line":2951,"updated":"2024-05-22 19:50:50.000000000","message":"if we\u0027re not going to write a test for turning --skip-identical and --version-id into an error maybe it\u0027d just be better to leave the bug where skip-identical over-writes your version-id query param in place...\n\nat least we\u0027re not adding a new bug for part-number!","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":2948,"context_line":"                self.assertFalse(r[\u0027success\u0027])"},{"line_number":2949,"context_line":"                self.assertTrue(\u0027Cannot use --skip-identical with part-number \u0027"},{"line_number":2950,"context_line":"                                \u0027or version-id\u0027 in str(r[\u0027error\u0027]))"},{"line_number":2951,"context_line":"                self.assertEqual(mock_conn.get_object.call_count, 0)"},{"line_number":2952,"context_line":""},{"line_number":2953,"context_line":"    def test_download_object_job_skip_identical_dlo(self):"},{"line_number":2954,"context_line":"        with tempfile.NamedTemporaryFile() as f:"}],"source_content_type":"text/x-python","patch_set":28,"id":"c17f68d5_5a1c0a86","line":2951,"in_reply_to":"5bae6062_9f4945bf","updated":"2024-05-29 20:27:28.000000000","message":"Acknowledged","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"}],"test/unit/test_shell.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ee9ef177f9efa8762ce1a067960773e765dd33b0","unresolved":true,"context_lines":[{"line_number":335,"context_line":"            swiftclient.shell.main(argv)"},{"line_number":336,"context_line":"        self.assertEqual([mock.call(\u0027container\u0027, \u0027object\u0027, headers\u003d{},"},{"line_number":337,"context_line":"                                    query_string\u003d\u0027part-number\u003d20\u0027)],"},{"line_number":338,"context_line":"                         connection.return_value.head_object.mock_calls)"},{"line_number":339,"context_line":""},{"line_number":340,"context_line":"    @mock.patch(\u0027swiftclient.service.Connection\u0027)"},{"line_number":341,"context_line":"    def test_stat_object(self, connection):"}],"source_content_type":"text/x-python","patch_set":16,"id":"8ec3fda8_19437486","line":338,"updated":"2024-04-17 22:58:25.000000000","message":"why not also a test for part_number \u0026 version_id?","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cdd8ce5fe66bc79872b8d2d982df6049deb3d0eb","unresolved":false,"context_lines":[{"line_number":335,"context_line":"            swiftclient.shell.main(argv)"},{"line_number":336,"context_line":"        self.assertEqual([mock.call(\u0027container\u0027, \u0027object\u0027, headers\u003d{},"},{"line_number":337,"context_line":"                                    query_string\u003d\u0027part-number\u003d20\u0027)],"},{"line_number":338,"context_line":"                         connection.return_value.head_object.mock_calls)"},{"line_number":339,"context_line":""},{"line_number":340,"context_line":"    @mock.patch(\u0027swiftclient.service.Connection\u0027)"},{"line_number":341,"context_line":"    def test_stat_object(self, connection):"}],"source_content_type":"text/x-python","patch_set":16,"id":"0008ef89_f3267b4e","line":338,"in_reply_to":"8ec3fda8_19437486","updated":"2024-04-23 18:42:19.000000000","message":"Added, i squashed some tests from https://review.opendev.org/c/openstack/python-swiftclient/+/916145/1","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ee9ef177f9efa8762ce1a067960773e765dd33b0","unresolved":true,"context_lines":[{"line_number":739,"context_line":"                         \"--part-number option only allowed for \""},{"line_number":740,"context_line":"                         \"object downloads\")"},{"line_number":741,"context_line":""},{"line_number":742,"context_line":"        argv \u003d [\"\", \"download\", \" --part-number\", \"7\", \"container\", \"object\"]"},{"line_number":743,"context_line":"        connection.return_value.head_object.return_value \u003d {}"},{"line_number":744,"context_line":"        connection.return_value.get_object.return_value \u003d {}, \u0027\u0027"},{"line_number":745,"context_line":"        connection.return_value.attempts \u003d 0"}],"source_content_type":"text/x-python","patch_set":16,"id":"f656dab4_77ff9ff4","line":742,"updated":"2024-04-17 22:58:25.000000000","message":"FWIW the leading space in `\" --part-number\"` causes the options parser to fail to pick it up as an option so it shows up as another argument.","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cdd8ce5fe66bc79872b8d2d982df6049deb3d0eb","unresolved":false,"context_lines":[{"line_number":739,"context_line":"                         \"--part-number option only allowed for \""},{"line_number":740,"context_line":"                         \"object downloads\")"},{"line_number":741,"context_line":""},{"line_number":742,"context_line":"        argv \u003d [\"\", \"download\", \" --part-number\", \"7\", \"container\", \"object\"]"},{"line_number":743,"context_line":"        connection.return_value.head_object.return_value \u003d {}"},{"line_number":744,"context_line":"        connection.return_value.get_object.return_value \u003d {}, \u0027\u0027"},{"line_number":745,"context_line":"        connection.return_value.attempts \u003d 0"}],"source_content_type":"text/x-python","patch_set":16,"id":"332ad003_c42943c9","line":742,"in_reply_to":"f656dab4_77ff9ff4","updated":"2024-04-23 18:42:19.000000000","message":"Acknowledged","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ee9ef177f9efa8762ce1a067960773e765dd33b0","unresolved":true,"context_lines":[{"line_number":753,"context_line":"                              resp_chunk_size\u003d65536),"},{"line_number":754,"context_line":"                              mock.call(\u0027 --part-number\u0027, \u0027object\u0027,"},{"line_number":755,"context_line":"                              headers\u003d{}, response_dict\u003d{},"},{"line_number":756,"context_line":"                              resp_chunk_size\u003d65536)],"},{"line_number":757,"context_line":"                             connection.return_value.get_object.mock_calls)"},{"line_number":758,"context_line":""},{"line_number":759,"context_line":"    @mock.patch(\u0027swiftclient.service.makedirs\u0027)"}],"source_content_type":"text/x-python","patch_set":16,"id":"381adbdf_2d390878","line":756,"updated":"2024-04-17 22:58:25.000000000","message":"this looks like like we tried to download the objects 7, container and object from the \" --part-number\" container - is that what you WANT to assert?","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cdd8ce5fe66bc79872b8d2d982df6049deb3d0eb","unresolved":false,"context_lines":[{"line_number":753,"context_line":"                              resp_chunk_size\u003d65536),"},{"line_number":754,"context_line":"                              mock.call(\u0027 --part-number\u0027, \u0027object\u0027,"},{"line_number":755,"context_line":"                              headers\u003d{}, response_dict\u003d{},"},{"line_number":756,"context_line":"                              resp_chunk_size\u003d65536)],"},{"line_number":757,"context_line":"                             connection.return_value.get_object.mock_calls)"},{"line_number":758,"context_line":""},{"line_number":759,"context_line":"    @mock.patch(\u0027swiftclient.service.makedirs\u0027)"}],"source_content_type":"text/x-python","patch_set":16,"id":"6f7f778d_dfc56146","line":756,"in_reply_to":"381adbdf_2d390878","updated":"2024-04-23 18:42:19.000000000","message":"Nope. I missed the nit.","commit_id":"356f8ca57db60b32228eb83977a61ecf3dc4388f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"0bc7e1006f4f7d630bd5f1f41a8a2dfb27218981","unresolved":true,"context_lines":[{"line_number":770,"context_line":""},{"line_number":771,"context_line":"    @mock.patch(\u0027swiftclient.service.Connection\u0027)"},{"line_number":772,"context_line":"    def test_download_part_number(self, connection):"},{"line_number":773,"context_line":"        argv \u003d [\"\", \"download\", \"--yes-all\", \"--part-number\", \"3\"]"},{"line_number":774,"context_line":"        with self.assertRaises(SystemExit) as caught:"},{"line_number":775,"context_line":"            swiftclient.shell.main(argv)"},{"line_number":776,"context_line":"        self.assertEqual(str(caught.exception),"}],"source_content_type":"text/x-python","patch_set":20,"id":"3ae0765b_6deb9b10","line":773,"updated":"2024-04-29 17:08:47.000000000","message":"I\u0027m a little surprised to see `--yes-all` here - oic this test is doing more than one thing.\n\n\nIt\u0027s like we have `test_download_part_number_not_allowed_for_non_object`, and `test_download_part_number` all in one test.","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"e21059b2461280fd1b8f681327d8617468402134","unresolved":false,"context_lines":[{"line_number":770,"context_line":""},{"line_number":771,"context_line":"    @mock.patch(\u0027swiftclient.service.Connection\u0027)"},{"line_number":772,"context_line":"    def test_download_part_number(self, connection):"},{"line_number":773,"context_line":"        argv \u003d [\"\", \"download\", \"--yes-all\", \"--part-number\", \"3\"]"},{"line_number":774,"context_line":"        with self.assertRaises(SystemExit) as caught:"},{"line_number":775,"context_line":"            swiftclient.shell.main(argv)"},{"line_number":776,"context_line":"        self.assertEqual(str(caught.exception),"}],"source_content_type":"text/x-python","patch_set":20,"id":"0f9cf8df_217b2b7b","line":773,"in_reply_to":"3ae0765b_6deb9b10","updated":"2024-04-30 19:32:10.000000000","message":"Done","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"0bc7e1006f4f7d630bd5f1f41a8a2dfb27218981","unresolved":true,"context_lines":[{"line_number":828,"context_line":"            mock.call(\u0027container\u0027, \u0027obj\u0027, headers\u003d{}, response_dict\u003d{},"},{"line_number":829,"context_line":"                      resp_chunk_size\u003d65536,"},{"line_number":830,"context_line":"                      query_string\u003d\u0027version-id\u003d1713378563.05537\u0026part-number\u003d2\u0027)"},{"line_number":831,"context_line":"        ], mock_conn.get_object.mock_calls)"},{"line_number":832,"context_line":"        self.assertEqual("},{"line_number":833,"context_line":"            \u0027obj [auth 0.010s, headers 0.020s, total 0.030s, 5.000 MB/s]\\n\u0027,"},{"line_number":834,"context_line":"            ctx.out)"}],"source_content_type":"text/x-python","patch_set":20,"id":"65e7581d_9dfd715f","line":831,"updated":"2024-04-29 17:08:47.000000000","message":"I like how these tests cut through the shell AND service testing","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"e21059b2461280fd1b8f681327d8617468402134","unresolved":false,"context_lines":[{"line_number":828,"context_line":"            mock.call(\u0027container\u0027, \u0027obj\u0027, headers\u003d{}, response_dict\u003d{},"},{"line_number":829,"context_line":"                      resp_chunk_size\u003d65536,"},{"line_number":830,"context_line":"                      query_string\u003d\u0027version-id\u003d1713378563.05537\u0026part-number\u003d2\u0027)"},{"line_number":831,"context_line":"        ], mock_conn.get_object.mock_calls)"},{"line_number":832,"context_line":"        self.assertEqual("},{"line_number":833,"context_line":"            \u0027obj [auth 0.010s, headers 0.020s, total 0.030s, 5.000 MB/s]\\n\u0027,"},{"line_number":834,"context_line":"            ctx.out)"}],"source_content_type":"text/x-python","patch_set":20,"id":"a4297376_4cc89cb1","line":831,"in_reply_to":"65e7581d_9dfd715f","updated":"2024-04-30 19:32:10.000000000","message":"Acknowledged","commit_id":"adda3e8b5b217903a7b01a694b830fd779e8ee83"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":380,"context_line":"        \"\"\""},{"line_number":381,"context_line":"        for line in expected_lines.splitlines():"},{"line_number":382,"context_line":"            expected \u003d line.strip()"},{"line_number":383,"context_line":"            self.assertIn(expected, ctx.out, \u0027\\n\u0027 + ctx.out)"},{"line_number":384,"context_line":""},{"line_number":385,"context_line":"    @mock.patch(\u0027swiftclient.service.Connection\u0027)"},{"line_number":386,"context_line":"    def test_stat_object(self, connection):"}],"source_content_type":"text/x-python","patch_set":23,"id":"01e27894_489934c0","line":383,"updated":"2024-05-02 23:04:40.000000000","message":"this is an annoyingly weak assertion, but given the current state of master [1] with duplicated etags it\u0027d be hard to to write a test that uses CaseInsenstiveDict and didn\u0027t look super stupid.\n\n1. 916135: Fix swiftclient output regression | https://review.opendev.org/c/openstack/python-swiftclient/+/916135\n\nin the meantime this is what I came up with:\n\n    diff --git a/test/unit/test_shell.py b/test/unit/test_shell.py\n    index 0841ca7..b3f6b70 100644\n    --- a/test/unit/test_shell.py\n    +++ b/test/unit/test_shell.py\n    @@ -319,6 +319,35 @@ class TestShell(unittest.TestCase):\n                                         query_string\u003d\u0027version-id\u003d1\u0027)],\n                              connection.return_value.head_object.mock_calls)\n     \n    +    def assertFormlessLines(self, expected, found):\n    +        \"\"\"\n    +        assert the lines are more or less the same, ignoring leading and\n    +        trailing whitespace and empty lines\n    +        \"\"\"\n    +        def normalize(text):\n    +            return [line.strip() for line in text.strip().splitlines()]\n    +        expected \u003d normalize(expected)\n    +        found \u003d normalize(found)\n    +        enumerated_errors \u003d []\n    +        for i, (e, f) in enumerate(zip(expected, found)):\n    +            if e.strip() !\u003d f.strip():\n    +                enumerated_errors.append((i, \u0027%r !\u003d %r\u0027 % (e, f)))\n    +\n    +        def with_numbers(enumerated_lines):\n    +            return \u0027\\n\u0027.join(\u0027%3d: %s\u0027 % (i, line)\n    +                             for i, line in enumerated_lines)\n    +        if enumerated_errors:\n    +            self.fail(\u0027\\nexpected:\\n\u0027\n    +                      \u0027%s\\n\u0027\n    +                      \u0027does not equal found:\\n\u0027\n    +                      \u0027%s\\n\u0027\n    +                      \u0027check the following lines:\\n\u0027\n    +                      \u0027%s\\n\u0027 % (\n    +                          with_numbers(enumerate(expected)),\n    +                          with_numbers(enumerate(found)),\n    +                          with_numbers(enumerated_errors),\n    +                      ))\n    +\n         @mock.patch(\u0027swiftclient.service.Connection\u0027)\n         def test_stat_part_number(self, connection):\n             argv \u003d [\"\", \"stat\", \"--part-number\", \"3\"]\n    @@ -337,27 +366,34 @@ class TestShell(unittest.TestCase):\n     \n             argv \u003d [\"\", \"stat\", \"--part-number\", \"20\", \"container\", \"object\"]\n             connection.return_value.head_object.return_value \u003d {}\n    -        with CaptureOutput():\n    +        connection.return_value.url \u003d \u0027http://127.0.0.1/v1/AUTH_account\u0027\n    +        with CaptureOutput() as ctx:\n                 swiftclient.shell.main(argv)\n             self.assertEqual([mock.call(\u0027container\u0027, \u0027object\u0027,\n                                         headers\u003d{},\n                                         query_string\u003d\u0027part-number\u003d20\u0027)],\n                              connection.return_value.head_object.mock_calls)\n     \n    +        self.assertFormlessLines(\"\"\"\n    +               Account: AUTH_account\n    +             Container: container\n    +                Object: object\n    +        Content Length: 0\n    +                                 \"\"\", ctx.out)\n    +\n         @mock.patch(\u0027swiftclient.service.Connection\u0027)\n         def test_stat_version_id_and_part_number(self, connection_cls):\n             mock_conn \u003d connection_cls.return_value\n             mock_conn.url \u003d \u0027http://127.0.0.1/v1/AUTH_account\u0027\n    -        mock_conn.head_object.return_value \u003d CaseInsensitiveDict({\n    -            \u0027X-Static-Large-Object\u0027: \u0027True\u0027,\n    -            \u0027Content-Length\u0027: \u00271000000\u0027,\n    -            \"ETag\": \u0027\"cac0f63d4c7cfc6a4abdcb06b382e465\"\u0027,\n    -            \u0027X-Manifest-Etag\u0027: \u0027b4f746e58ea5ecfa2bc6383982d6570b\u0027,\n    -            \u0027Content-Range\u0027: \u0027bytes 1000000-1999999/10000000\u0027,\n    -            \u0027X-Parts-Count\u0027: \u002710\u0027,\n    -            \u0027X-Object-Version-Id\u0027: \u00271713378563.05537\u0027,\n    -        })\n    -\n    +        mock_conn.head_object.return_value \u003d dict([\n    +            (\u0027x-static-large-object\u0027, \u0027True\u0027),\n    +            (\u0027content-length\u0027, \u00271000000\u0027),\n    +            (\u0027etag\u0027, \u0027\"cac0f63d4c7cfc6a4abdcb06b382e465\"\u0027),\n    +            (\u0027x-object-version-id\u0027, \u00271713378563.05537\u0027),\n    +            (\u0027x-manifest-etag\u0027, \u0027b4f746e58ea5ecfa2bc6383982d6570b\u0027),\n    +            (\u0027content-range\u0027, \u0027bytes 1000000-1999999/10000000\u0027),\n    +            (\u0027x-parts-count\u0027, \u002710\u0027),\n    +        ])\n             argv \u003d [\"\", \"stat\", \"container\", \"object\",\n                     \"--part-number\", \"2\", \"--version-id\", \"1713378563.05537\"]\n             with CaptureOutput() as ctx:\n    @@ -378,9 +414,7 @@ class TestShell(unittest.TestCase):\n             Content-Range: bytes 1000000-1999999/10000000\n             X-Parts-Count: 10\n             \"\"\"\n    -        for line in expected_lines.splitlines():\n    -            expected \u003d line.strip()\n    -            self.assertIn(expected, ctx.out, \u0027\\n\u0027 + ctx.out)\n    +        self.assertFormlessLines(expected_lines, ctx.out)\n     \n         @mock.patch(\u0027swiftclient.service.Connection\u0027)\n         def test_stat_object(self, connection):","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"40b5c0cce098c2c79f2c4d1684bb20937c051372","unresolved":false,"context_lines":[{"line_number":380,"context_line":"        \"\"\""},{"line_number":381,"context_line":"        for line in expected_lines.splitlines():"},{"line_number":382,"context_line":"            expected \u003d line.strip()"},{"line_number":383,"context_line":"            self.assertIn(expected, ctx.out, \u0027\\n\u0027 + ctx.out)"},{"line_number":384,"context_line":""},{"line_number":385,"context_line":"    @mock.patch(\u0027swiftclient.service.Connection\u0027)"},{"line_number":386,"context_line":"    def test_stat_object(self, connection):"}],"source_content_type":"text/x-python","patch_set":23,"id":"0a8724db_c98c3b4a","line":383,"in_reply_to":"01e27894_489934c0","updated":"2024-05-06 17:56:48.000000000","message":"Done","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"6999e5b1bba77687100c29eedb0adb41afca1484","unresolved":true,"context_lines":[{"line_number":1111,"context_line":"                           response_dict\u003d{}, query_string\u003dNone),"},{"line_number":1112,"context_line":"                 mock.call(\u0027container\u0027, \u0027pseudo/\u0027,"},{"line_number":1113,"context_line":"                           headers\u003d{}, resp_chunk_size\u003d65536,"},{"line_number":1114,"context_line":"                           response_dict\u003d{}, query_string\u003dNone)]"},{"line_number":1115,"context_line":"        connection.return_value.get_object.assert_has_calls("},{"line_number":1116,"context_line":"            calls, any_order\u003dTrue)"},{"line_number":1117,"context_line":"        mock_open.assert_called_once_with(\u0027object\u0027, \u0027wb\u0027, 65536)"}],"source_content_type":"text/x-python","patch_set":23,"id":"2696b563_4cceff0e","line":1114,"updated":"2024-05-02 23:04:40.000000000","message":"oh it was slightly more than just 5 tests; that seems like it probably would have been annoying; but I guess not sufficiently so to just make the uut behavior consistent with master?  it wasn\u0027t *wrong* to not send the query_string kwarg - it has a default of None...","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"8c7914220d12aff54d62fb2460eb78f3c75b46fd","unresolved":true,"context_lines":[{"line_number":1111,"context_line":"                           response_dict\u003d{}, query_string\u003dNone),"},{"line_number":1112,"context_line":"                 mock.call(\u0027container\u0027, \u0027pseudo/\u0027,"},{"line_number":1113,"context_line":"                           headers\u003d{}, resp_chunk_size\u003d65536,"},{"line_number":1114,"context_line":"                           response_dict\u003d{}, query_string\u003dNone)]"},{"line_number":1115,"context_line":"        connection.return_value.get_object.assert_has_calls("},{"line_number":1116,"context_line":"            calls, any_order\u003dTrue)"},{"line_number":1117,"context_line":"        mock_open.assert_called_once_with(\u0027object\u0027, \u0027wb\u0027, 65536)"}],"source_content_type":"text/x-python","patch_set":23,"id":"cc5c861f_b3086c1a","line":1114,"in_reply_to":"2696b563_4cceff0e","updated":"2024-05-03 20:48:10.000000000","message":"Should i be reverting this change ? Well as you said it isn\u0027t wrong.","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"aafc1ad8d3bb5cba6192a757406cfdec4e13a558","unresolved":false,"context_lines":[{"line_number":1111,"context_line":"                           response_dict\u003d{}, query_string\u003dNone),"},{"line_number":1112,"context_line":"                 mock.call(\u0027container\u0027, \u0027pseudo/\u0027,"},{"line_number":1113,"context_line":"                           headers\u003d{}, resp_chunk_size\u003d65536,"},{"line_number":1114,"context_line":"                           response_dict\u003d{}, query_string\u003dNone)]"},{"line_number":1115,"context_line":"        connection.return_value.get_object.assert_has_calls("},{"line_number":1116,"context_line":"            calls, any_order\u003dTrue)"},{"line_number":1117,"context_line":"        mock_open.assert_called_once_with(\u0027object\u0027, \u0027wb\u0027, 65536)"}],"source_content_type":"text/x-python","patch_set":23,"id":"3dc68e42_2938f5cd","line":1114,"in_reply_to":"cc5c861f_b3086c1a","updated":"2024-05-06 19:27:11.000000000","message":"Acknowledged","commit_id":"60220277f8e8426688e25ea910aee1a837311b99"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"aafc1ad8d3bb5cba6192a757406cfdec4e13a558","unresolved":true,"context_lines":[{"line_number":362,"context_line":"            (\u0027x-manifest-etag\u0027, \u0027b4f746e58ea5ecfa2bc6383982d6570b\u0027),"},{"line_number":363,"context_line":"            (\u0027content-range\u0027, \u0027bytes 1000000-1999999/10000000\u0027),"},{"line_number":364,"context_line":"            (\u0027x-parts-count\u0027, \u002710\u0027),"},{"line_number":365,"context_line":"        ])"},{"line_number":366,"context_line":""},{"line_number":367,"context_line":"        argv \u003d [\"\", \"stat\", \"container\", \"object\","},{"line_number":368,"context_line":"                \"--part-number\", \"2\", \"--version-id\", \"1713378563.05537\"]"}],"source_content_type":"text/x-python","patch_set":24,"id":"9dac3314_ef1b9770","line":365,"updated":"2024-05-06 19:27:11.000000000","message":"this test seemes dependent on the order of these dict keys, but I don\u0027t actually understand how the order is preserved with a stdlib dict\n\nhttps://docs.python.org/3.6/whatsnew/3.6.html#new-dict-implementation\n\nNow that 916135: Fix swiftclient output regression | https://review.opendev.org/c/openstack/python-swiftclient/+/916135 is merged we should probably use a LowerKeyCaseInsensitiveDict which is insertion ordered reliably:\n\nhttps://docs.python-requests.org/en/v3.0.0/_modules/requests/structures/","commit_id":"f18eb808665e2f9f00386e890c5ec17684173005"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"799455b2c84ae86b0415804101e3558995288393","unresolved":false,"context_lines":[{"line_number":362,"context_line":"            (\u0027x-manifest-etag\u0027, \u0027b4f746e58ea5ecfa2bc6383982d6570b\u0027),"},{"line_number":363,"context_line":"            (\u0027content-range\u0027, \u0027bytes 1000000-1999999/10000000\u0027),"},{"line_number":364,"context_line":"            (\u0027x-parts-count\u0027, \u002710\u0027),"},{"line_number":365,"context_line":"        ])"},{"line_number":366,"context_line":""},{"line_number":367,"context_line":"        argv \u003d [\"\", \"stat\", \"container\", \"object\","},{"line_number":368,"context_line":"                \"--part-number\", \"2\", \"--version-id\", \"1713378563.05537\"]"}],"source_content_type":"text/x-python","patch_set":24,"id":"10ebb7df_d094a70d","line":365,"in_reply_to":"1d58e509_96b31977","updated":"2024-05-13 20:23:15.000000000","message":"Done","commit_id":"f18eb808665e2f9f00386e890c5ec17684173005"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"f366f42e15ecf7ac1f83be3afc9f1ad93fad1386","unresolved":true,"context_lines":[{"line_number":362,"context_line":"            (\u0027x-manifest-etag\u0027, \u0027b4f746e58ea5ecfa2bc6383982d6570b\u0027),"},{"line_number":363,"context_line":"            (\u0027content-range\u0027, \u0027bytes 1000000-1999999/10000000\u0027),"},{"line_number":364,"context_line":"            (\u0027x-parts-count\u0027, \u002710\u0027),"},{"line_number":365,"context_line":"        ])"},{"line_number":366,"context_line":""},{"line_number":367,"context_line":"        argv \u003d [\"\", \"stat\", \"container\", \"object\","},{"line_number":368,"context_line":"                \"--part-number\", \"2\", \"--version-id\", \"1713378563.05537\"]"}],"source_content_type":"text/x-python","patch_set":24,"id":"1d58e509_96b31977","line":365,"in_reply_to":"9dac3314_ef1b9770","updated":"2024-05-13 20:22:46.000000000","message":"Ahh this makes sense infact when i have done the rebase it did prompt me to opt-in to use `LowerKeyCaseInsensitiveDict` but I was unsure if this MR could/should incorporate these changes. I should have abided by this (ref: https://docs.openstack.org/swift/latest/development_guidelines.html#testing-guidelines)","commit_id":"f18eb808665e2f9f00386e890c5ec17684173005"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":true,"context_lines":[{"line_number":370,"context_line":"            swiftclient.shell.main(argv)"},{"line_number":371,"context_line":"        self.assertEqual(["},{"line_number":372,"context_line":"            mock.call(\u0027container\u0027, \u0027object\u0027, headers\u003d{},"},{"line_number":373,"context_line":"                      query_string\u003d\u0027version-id\u003d1713378563.05537\u0026part-number\u003d2\u0027)"},{"line_number":374,"context_line":"        ], mock_conn.head_object.call_args_list)"},{"line_number":375,"context_line":"        expected_lines \u003d \"\"\""},{"line_number":376,"context_line":"            Account: AUTH_account"}],"source_content_type":"text/x-python","patch_set":28,"id":"e2885619_dfe3aebe","line":373,"updated":"2024-05-22 19:50:50.000000000","message":"it\u0027s very good to see the assertion on the request query string!","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":370,"context_line":"            swiftclient.shell.main(argv)"},{"line_number":371,"context_line":"        self.assertEqual(["},{"line_number":372,"context_line":"            mock.call(\u0027container\u0027, \u0027object\u0027, headers\u003d{},"},{"line_number":373,"context_line":"                      query_string\u003d\u0027version-id\u003d1713378563.05537\u0026part-number\u003d2\u0027)"},{"line_number":374,"context_line":"        ], mock_conn.head_object.call_args_list)"},{"line_number":375,"context_line":"        expected_lines \u003d \"\"\""},{"line_number":376,"context_line":"            Account: AUTH_account"}],"source_content_type":"text/x-python","patch_set":28,"id":"2822969d_872fd2be","line":373,"in_reply_to":"e2885619_dfe3aebe","updated":"2024-05-29 20:27:28.000000000","message":"Acknowledged","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"81d042fac108fa4c567d45a124dff08c37fbf694","unresolved":true,"context_lines":[{"line_number":786,"context_line":"            swiftclient.shell.main(argv)"},{"line_number":787,"context_line":"        self.assertEqual(str(caught.exception),"},{"line_number":788,"context_line":"                         \"--part-number option only allowed for \""},{"line_number":789,"context_line":"                         \"object downloads\")"},{"line_number":790,"context_line":""},{"line_number":791,"context_line":"        argv \u003d [\"\", \"download\", \"--part-number\", \"7\", \"container\", \"object\"]"},{"line_number":792,"context_line":"        connection.return_value.head_object.return_value \u003d {}"}],"source_content_type":"text/x-python","patch_set":28,"id":"950f0e84_eddd475b","line":789,"updated":"2024-05-22 19:50:50.000000000","message":"I don\u0027t see negative tests for the error handling of part-number \u003d 0 or part-number \u003d -1 \n\nat least one of those I can functionally confirm is disallowed; I assume that behavior would be desirable to maintain.","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"cb41fe7186a44a33350196c9f0029fa296e47826","unresolved":false,"context_lines":[{"line_number":786,"context_line":"            swiftclient.shell.main(argv)"},{"line_number":787,"context_line":"        self.assertEqual(str(caught.exception),"},{"line_number":788,"context_line":"                         \"--part-number option only allowed for \""},{"line_number":789,"context_line":"                         \"object downloads\")"},{"line_number":790,"context_line":""},{"line_number":791,"context_line":"        argv \u003d [\"\", \"download\", \"--part-number\", \"7\", \"container\", \"object\"]"},{"line_number":792,"context_line":"        connection.return_value.head_object.return_value \u003d {}"}],"source_content_type":"text/x-python","patch_set":28,"id":"905563a1_21872240","line":789,"in_reply_to":"950f0e84_eddd475b","updated":"2024-05-29 20:27:28.000000000","message":"I actually missed the spot where i should have included part_number in the _default_local_options","commit_id":"5dd7ae80ffd36ae00604228bf73da117b00c1eff"}]}
