)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d6ebb733966e5f0db52278ffd5f77298f3e747c6","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"b5b112cf_ef46cb49","updated":"2025-11-27 18:38:58.000000000","message":"There\u0027s a lot of Timestamp\u0027s in test_backend.py that ought to become SimpleTimestamps","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"b1194a9c5f9754053d0941738e4f54ce3add924c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"8078bdfd_7db052c7","updated":"2025-12-22 04:01:31.000000000","message":"The patch is great! ``-1`` because of pep8. Will finish reviewing test cases later.","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"cd9a4f95_dc512de9","updated":"2025-12-23 05:53:53.000000000","message":"SimpleTimestamp looks great now! still ``-1`` because I found a place (probably more) we would need the comparison of Timestamp and SimpleTimestamp, see:\nhttps://review.opendev.org/c/openstack/swift/+/968740/4/swift/container/sharder.py#1041","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ef6c325c66b7edbba9076e1795edfb2d4969cd39","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"920b807e_a755c5da","updated":"2025-12-23 18:27:48.000000000","message":"plugging this patch so that it doesn\u0027t merge until we\u0027re happy with the timestamp+jitter","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"2de8f5af1493ab3f5a4d3a76d8972ebc38393635","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"37255658_d5a968bf","updated":"2025-12-24 12:51:08.000000000","message":"recheck","commit_id":"894b05ed2a9597f2fa27dba0f0d34904f52a824e"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":27,"id":"9c02b433_3e0dbe5d","updated":"2026-02-19 06:22:12.000000000","message":"I\u0027m liking the NormalTimestamp and am looking towards putting a +2, just a few little things then I think it\u0027s ready to go from my POV.","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"83ba7f3d242a9e8612aab1c2549ada7eb5149402","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":41,"id":"7c778d35_08c5ad43","updated":"2026-03-11 22:46:42.000000000","message":"it\u0027s good probably that this patch is bigger than the jitter patch - shows that we doing the pre-work!","commit_id":"26432faab511caaa3a7b4ad12c13ea69e17d7b0a"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"4ab308355ac576df7584ce8123580de091df9dd3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":41,"id":"62c5b9b5_434b9931","updated":"2026-03-11 04:33:42.000000000","message":"recheck\n\nzuul failed to download some package files so not released to code.","commit_id":"26432faab511caaa3a7b4ad12c13ea69e17d7b0a"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"64fba0d90b3e7f669a54fcaa4c6e5e2628b0aa90","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":50,"id":"4817a57e_58a4ef14","updated":"2026-04-15 05:39:11.000000000","message":"Cool, so as always there are some polishes we could do. Jian has some good nits, I have some nits too but I don\u0027t think we need to block anymore. So everything left can be a follow up.\n\nUnless someone wants to reroll yet again. But this is awesome! so..","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"26342b50f5cb0d1ecb2e88d3ff2963a9fd6a7ff2","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":52,"id":"4fc77bfb_5b27fd8e","updated":"2026-04-15 22:58:05.000000000","message":"Nice, looks great to me!","commit_id":"0253a6bb44f68d8a9cf50763db7bb9baddfd8f97"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"077616cb97e83fd33ce8b169199d7e898253580c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":53,"id":"583b607e_6c30b87a","updated":"2026-04-16 15:56:44.000000000","message":"I have squashed in https://review.opendev.org/c/openstack/swift/+/984919/2?usp\u003drelated-change, much of which is reverting changes from using .internal to .normal back to .internal\n\nMakes this patch diff ~200 lines smallert","commit_id":"7b5c965238ddf7a43f69684074ea3a98e53e7efe"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8df668cb5b03540c0799557488ef406925c17b4f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":54,"id":"e2741cca_c3a93ca1","updated":"2026-04-21 07:06:19.000000000","message":"Merge!!!","commit_id":"cf5df8fac80ff354ee8e6369dbf18a5e1fd75343"}],"swift/account/backend.py":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"64fba0d90b3e7f669a54fcaa4c6e5e2628b0aa90","unresolved":true,"context_lines":[{"line_number":19,"context_line":""},{"line_number":20,"context_line":"import sqlite3"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"from swift.common.utils import Timestamp, NormalTimestamp, RESERVED_BYTE"},{"line_number":23,"context_line":"from swift.common.db import DatabaseBroker, zero_like"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"DATADIR \u003d \u0027accounts\u0027"}],"source_content_type":"text/x-python","patch_set":50,"id":"ca6eeb62_fbef62b8","line":22,"updated":"2026-04-15 05:39:11.000000000","message":"would prefer this to start using the new form:\n\n```\nfrom.swift.common.utils.timestamp import Timestamp, NormalTimestamp\n```\n\nBut not a blocker.","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":false,"context_lines":[{"line_number":19,"context_line":""},{"line_number":20,"context_line":"import sqlite3"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"from swift.common.utils import Timestamp, NormalTimestamp, RESERVED_BYTE"},{"line_number":23,"context_line":"from swift.common.db import DatabaseBroker, zero_like"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"DATADIR \u003d \u0027accounts\u0027"}],"source_content_type":"text/x-python","patch_set":50,"id":"c894bbe1_321ce1bf","line":22,"in_reply_to":"ca6eeb62_fbef62b8","updated":"2026-04-15 14:23:58.000000000","message":"Done","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"}],"swift/cli/manage_shard_ranges.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":530,"context_line":"    if own_shard_range.state \u003d\u003d ShardRange.ACTIVE:"},{"line_number":531,"context_line":"        own_shard_range \u003d _enable_sharding(broker, own_shard_range, args)"},{"line_number":532,"context_line":"        print(\u0027Container moved to state %r with epoch %s.\u0027 %"},{"line_number":533,"context_line":"              (own_shard_range.state_text, own_shard_range.epoch.normal))"},{"line_number":534,"context_line":"    elif own_shard_range.state \u003d\u003d ShardRange.SHARDING:"},{"line_number":535,"context_line":"        if own_shard_range.epoch:"},{"line_number":536,"context_line":"            print(\u0027Container already in state %r with epoch %s.\u0027 %"}],"source_content_type":"text/x-python","patch_set":50,"id":"a8687381_cb95887c","line":533,"range":{"start_line":533,"start_character":65,"end_line":533,"end_character":71},"updated":"2026-04-15 14:23:58.000000000","message":"having changed ts_now to a NormalTimestamp, I\u0027m wondering if we could/should leave all the string formats as ``internal`` rather than ``normal``. ``internal`` IS the canonical representation after all.","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"077616cb97e83fd33ce8b169199d7e898253580c","unresolved":false,"context_lines":[{"line_number":530,"context_line":"    if own_shard_range.state \u003d\u003d ShardRange.ACTIVE:"},{"line_number":531,"context_line":"        own_shard_range \u003d _enable_sharding(broker, own_shard_range, args)"},{"line_number":532,"context_line":"        print(\u0027Container moved to state %r with epoch %s.\u0027 %"},{"line_number":533,"context_line":"              (own_shard_range.state_text, own_shard_range.epoch.normal))"},{"line_number":534,"context_line":"    elif own_shard_range.state \u003d\u003d ShardRange.SHARDING:"},{"line_number":535,"context_line":"        if own_shard_range.epoch:"},{"line_number":536,"context_line":"            print(\u0027Container already in state %r with epoch %s.\u0027 %"}],"source_content_type":"text/x-python","patch_set":50,"id":"7c4fb8f5_bf1367ec","line":533,"range":{"start_line":533,"start_character":65,"end_line":533,"end_character":71},"in_reply_to":"a8687381_cb95887c","updated":"2026-04-16 15:56:44.000000000","message":"Done","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"}],"swift/common/db.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"dc5ebe62a063e1d63c59a93c3e3903f710c76811","unresolved":true,"context_lines":[{"line_number":1127,"context_line":"                md \u003d json.loads(md)"},{"line_number":1128,"context_line":"                keys_to_delete \u003d []"},{"line_number":1129,"context_line":"                for key, (value, value_timestamp) in md.items():"},{"line_number":1130,"context_line":"                    if value \u003d\u003d \u0027\u0027 and value_timestamp \u003c str(timestamp):"},{"line_number":1131,"context_line":"                        keys_to_delete.append(key)"},{"line_number":1132,"context_line":"                if keys_to_delete:"},{"line_number":1133,"context_line":"                    for key in keys_to_delete:"}],"source_content_type":"text/x-python","patch_set":44,"id":"2c699f71_79e59973","line":1130,"updated":"2026-03-20 02:51:19.000000000","message":"``value_timestamp`` is normal format of timestamp, while ``timestamp`` is a float. I thought this comparison between them at here might have a issue when decimal is 0, see below.\n```\nvagrant@saio:~$ python3\nPython 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\u003e\u003e\u003e str(float(\"1773849197.00000\"))\n\u00271773849197.0\u0027\n\u003e\u003e\u003e \"1773849197.00000\" \u003c \"1773849197.0\"\nFalse  (correct)\n\u003e\u003e\u003e \"1773849197.00000\" \u003e \"1773849197.0\"\nTrue   (incorrect)\n\u003e\u003e\u003e \"1773849197.00000\" \u003d\u003d \"1773849197.0\"\nFalse  (incorrect)\n```\n\nbut the ``\u003c`` comparison we use here is okay, since\n```\n\u003e\u003e\u003e Timestamp(\"1773849197.00000\") \u003c 1773849197.0\nFalse\n```\n\nEven though the change doesn\u0027t have issue, I am not sure why this change is needed, I think the previous line would work fine?\n```\nif value \u003d\u003d \u0027\u0027 and Timestamp(value_timestamp) \u003c timestamp:\n```","commit_id":"297da3cb38579e724d2fde5f165ad23b25615bf6"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":1127,"context_line":"                md \u003d json.loads(md)"},{"line_number":1128,"context_line":"                keys_to_delete \u003d []"},{"line_number":1129,"context_line":"                for key, (value, value_timestamp) in md.items():"},{"line_number":1130,"context_line":"                    if value \u003d\u003d \u0027\u0027 and value_timestamp \u003c str(timestamp):"},{"line_number":1131,"context_line":"                        keys_to_delete.append(key)"},{"line_number":1132,"context_line":"                if keys_to_delete:"},{"line_number":1133,"context_line":"                    for key in keys_to_delete:"}],"source_content_type":"text/x-python","patch_set":44,"id":"c5fbc1b5_309262b8","line":1130,"in_reply_to":"0dc95bba_3b074024","updated":"2026-04-15 14:23:58.000000000","message":"I don\u0027t remember what motivated this change. Perhaps when jitter was added by default then line 1119 was no longer appropriate i.e. ``Timestamp(timestamp)``.\n\nI agree that is is better practice to compare BaseTimestamp instances.\n\nWill fix.","commit_id":"297da3cb38579e724d2fde5f165ad23b25615bf6"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"f48936d48919e0c678b9a5fee1ad804dcaf72e68","unresolved":true,"context_lines":[{"line_number":1127,"context_line":"                md \u003d json.loads(md)"},{"line_number":1128,"context_line":"                keys_to_delete \u003d []"},{"line_number":1129,"context_line":"                for key, (value, value_timestamp) in md.items():"},{"line_number":1130,"context_line":"                    if value \u003d\u003d \u0027\u0027 and value_timestamp \u003c str(timestamp):"},{"line_number":1131,"context_line":"                        keys_to_delete.append(key)"},{"line_number":1132,"context_line":"                if keys_to_delete:"},{"line_number":1133,"context_line":"                    for key in keys_to_delete:"}],"source_content_type":"text/x-python","patch_set":44,"id":"ad105cac_6b6b2793","line":1130,"in_reply_to":"2c699f71_79e59973","updated":"2026-04-13 02:59:41.000000000","message":"I feel this is awkward that it compares the raw string of two timestamps, while we have introduced several forms of timestamp classes. And another fun fact of this: \n```\nvagrant@saio:~$ python3\nPython 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\u003e\u003e\u003e \"0000000002.00000\" \u003c str(1.5)\nTrue\n```\nwe won\u0027t run into this issue though, since the current epoch timestamps all have the same digit counts to align.\n\nIMHO, we should just use ``Timestamp(value_timestamp) \u003c timestamp`` (the latter timestamp is just the input parameter)","commit_id":"297da3cb38579e724d2fde5f165ad23b25615bf6"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"64fba0d90b3e7f669a54fcaa4c6e5e2628b0aa90","unresolved":true,"context_lines":[{"line_number":1127,"context_line":"                md \u003d json.loads(md)"},{"line_number":1128,"context_line":"                keys_to_delete \u003d []"},{"line_number":1129,"context_line":"                for key, (value, value_timestamp) in md.items():"},{"line_number":1130,"context_line":"                    if value \u003d\u003d \u0027\u0027 and value_timestamp \u003c str(timestamp):"},{"line_number":1131,"context_line":"                        keys_to_delete.append(key)"},{"line_number":1132,"context_line":"                if keys_to_delete:"},{"line_number":1133,"context_line":"                    for key in keys_to_delete:"}],"source_content_type":"text/x-python","patch_set":44,"id":"0dc95bba_3b074024","line":1130,"in_reply_to":"ad105cac_6b6b2793","updated":"2026-04-15 05:39:11.000000000","message":"| IMHO, we should just use Timestamp(value_timestamp) \u003c timestamp (the latter timestamp is just the input parameter)\n\nWhich is how it originally was. Was there a reason for this change, surely we str() it for a reason, ansert undoubtably is jitter. I guess value_timestamp is probably coming back as a string.\n\nMaybe going back to:\n\n```\nTimestamp(value_timestamp) \u003c timestamp\n```\n\nOr make sure they strings are properly padded with something like:\n\n```\nvalue_timestamp \u003c NormalTimestamp(timestamp).normal\n```\nto make sure it\u0027s been normalised/padded.\n\nAgain happy for this to be done in a follow up, because of what we\u0027re running already","commit_id":"297da3cb38579e724d2fde5f165ad23b25615bf6"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"37bc60e79489953e9ba47e2267406af4798cb835","unresolved":false,"context_lines":[{"line_number":1127,"context_line":"                md \u003d json.loads(md)"},{"line_number":1128,"context_line":"                keys_to_delete \u003d []"},{"line_number":1129,"context_line":"                for key, (value, value_timestamp) in md.items():"},{"line_number":1130,"context_line":"                    if value \u003d\u003d \u0027\u0027 and value_timestamp \u003c str(timestamp):"},{"line_number":1131,"context_line":"                        keys_to_delete.append(key)"},{"line_number":1132,"context_line":"                if keys_to_delete:"},{"line_number":1133,"context_line":"                    for key in keys_to_delete:"}],"source_content_type":"text/x-python","patch_set":44,"id":"7eb9b1c7_6bf74764","line":1130,"in_reply_to":"c5fbc1b5_309262b8","updated":"2026-04-17 00:27:26.000000000","message":"Done","commit_id":"297da3cb38579e724d2fde5f165ad23b25615bf6"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"64fba0d90b3e7f669a54fcaa4c6e5e2628b0aa90","unresolved":true,"context_lines":[{"line_number":30,"context_line":"import sqlite3"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"from swift.common.constraints import MAX_META_COUNT, MAX_META_OVERALL_SIZE, \\"},{"line_number":33,"context_line":"    check_utf8"},{"line_number":34,"context_line":"from swift.common.utils import Timestamp, NormalTimestamp, \\"},{"line_number":35,"context_line":"    renamer, mkdirs, lock_parent_directory, fallocate, md5"},{"line_number":36,"context_line":"from swift.common.exceptions import LockTimeout"}],"source_content_type":"text/x-python","patch_set":50,"id":"fa7607e1_940e476a","line":33,"updated":"2026-04-15 05:39:11.000000000","message":"```\nfrom swift.common.utils.timestamp import Timestamp NormalTimestamp\n```","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":false,"context_lines":[{"line_number":30,"context_line":"import sqlite3"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"from swift.common.constraints import MAX_META_COUNT, MAX_META_OVERALL_SIZE, \\"},{"line_number":33,"context_line":"    check_utf8"},{"line_number":34,"context_line":"from swift.common.utils import Timestamp, NormalTimestamp, \\"},{"line_number":35,"context_line":"    renamer, mkdirs, lock_parent_directory, fallocate, md5"},{"line_number":36,"context_line":"from swift.common.exceptions import LockTimeout"}],"source_content_type":"text/x-python","patch_set":50,"id":"243cd672_cbd94bdb","line":33,"in_reply_to":"fa7607e1_940e476a","updated":"2026-04-15 14:23:58.000000000","message":"Done","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":1103,"context_line":"            if \u0027no such column: updated_at\u0027 not in str(err):"},{"line_number":1104,"context_line":"                raise"},{"line_number":1105,"context_line":""},{"line_number":1106,"context_line":"    def _reclaim_metadata(self, conn, timestamp):"},{"line_number":1107,"context_line":"        \"\"\""},{"line_number":1108,"context_line":"        Removes any empty metadata values older than the timestamp using the"},{"line_number":1109,"context_line":"        given database connection. This function will not call commit on the"}],"source_content_type":"text/x-python","patch_set":50,"id":"93cc63c2_64ea6ce4","line":1106,"updated":"2026-04-15 14:23:58.000000000","message":"the reclaim execution path passes consistently names ``sync_timestamp`` and/or ``age_timestamp`` until here... I\u0027d like to continue the consistent naming by changing this arg to ``age_timestamp``.\n\nIt\u0027s hard enough keeping track of which timestamp is which, and which is a float or a str or a Timestamp. Anything that removes brain-burden justifies a small drive-by IMHO.","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"37bc60e79489953e9ba47e2267406af4798cb835","unresolved":false,"context_lines":[{"line_number":1103,"context_line":"            if \u0027no such column: updated_at\u0027 not in str(err):"},{"line_number":1104,"context_line":"                raise"},{"line_number":1105,"context_line":""},{"line_number":1106,"context_line":"    def _reclaim_metadata(self, conn, timestamp):"},{"line_number":1107,"context_line":"        \"\"\""},{"line_number":1108,"context_line":"        Removes any empty metadata values older than the timestamp using the"},{"line_number":1109,"context_line":"        given database connection. This function will not call commit on the"}],"source_content_type":"text/x-python","patch_set":50,"id":"d9ec83a9_84b5c898","line":1106,"in_reply_to":"93cc63c2_64ea6ce4","updated":"2026-04-17 00:27:26.000000000","message":"Acknowledged","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"}],"swift/common/middleware/s3api/controllers/multi_upload.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"37bc60e79489953e9ba47e2267406af4798cb835","unresolved":true,"context_lines":[{"line_number":659,"context_line":"        resp, is_marker \u003d _get_upload_info(req, self.app, upload_id)"},{"line_number":660,"context_line":"        marker_delta \u003d ("},{"line_number":661,"context_line":"            float(Timestamp(resp.sw_headers.get(\u0027X-Backend-Timestamp\u0027, \u00270\u0027)))"},{"line_number":662,"context_line":"            - float(NormalTimestamp.now()))"},{"line_number":663,"context_line":"        if is_marker and marker_delta \u003e\u003d 0:"},{"line_number":664,"context_line":"            # Somehow the marker was created in the future w.r.t. this thread\u0027s"},{"line_number":665,"context_line":"            # clock. The manifest PUT may succeed but the subsequent marker"}],"source_content_type":"text/x-python","patch_set":54,"id":"327e35f0_a4155c46","line":662,"updated":"2026-04-17 00:27:26.000000000","message":"note that, the comparison between Timestamp and NormalTimestamp will be based on internal string ordering, ``self.internal \u003c other_ts.internal``, so we can directly use class comparison at here https://review.opendev.org/c/openstack/swift/+/968740/54/swift/common/db.py#1133, but not at this place which needs to calculate float number difference.","commit_id":"cf5df8fac80ff354ee8e6369dbf18a5e1fd75343"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"9c8423858953192777b7b9e1269ff8c67798b2ec","unresolved":true,"context_lines":[{"line_number":659,"context_line":"        resp, is_marker \u003d _get_upload_info(req, self.app, upload_id)"},{"line_number":660,"context_line":"        marker_delta \u003d ("},{"line_number":661,"context_line":"            float(Timestamp(resp.sw_headers.get(\u0027X-Backend-Timestamp\u0027, \u00270\u0027)))"},{"line_number":662,"context_line":"            - float(NormalTimestamp.now()))"},{"line_number":663,"context_line":"        if is_marker and marker_delta \u003e\u003d 0:"},{"line_number":664,"context_line":"            # Somehow the marker was created in the future w.r.t. this thread\u0027s"},{"line_number":665,"context_line":"            # clock. The manifest PUT may succeed but the subsequent marker"}],"source_content_type":"text/x-python","patch_set":54,"id":"4bd406a7_8123d644","line":662,"in_reply_to":"327e35f0_a4155c46","updated":"2026-04-20 11:40:10.000000000","message":"This was until very recently a direct comparison of Timestamps, but changed so that the marker_delta was available to use in the error message:\nhttps://review.opendev.org/c/openstack/swift/+/984467\n\n@Jianjian do you have a concern here?","commit_id":"cf5df8fac80ff354ee8e6369dbf18a5e1fd75343"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"4334f948ce7bdcd0585eeac6703c79de7464dd53","unresolved":false,"context_lines":[{"line_number":659,"context_line":"        resp, is_marker \u003d _get_upload_info(req, self.app, upload_id)"},{"line_number":660,"context_line":"        marker_delta \u003d ("},{"line_number":661,"context_line":"            float(Timestamp(resp.sw_headers.get(\u0027X-Backend-Timestamp\u0027, \u00270\u0027)))"},{"line_number":662,"context_line":"            - float(NormalTimestamp.now()))"},{"line_number":663,"context_line":"        if is_marker and marker_delta \u003e\u003d 0:"},{"line_number":664,"context_line":"            # Somehow the marker was created in the future w.r.t. this thread\u0027s"},{"line_number":665,"context_line":"            # clock. The manifest PUT may succeed but the subsequent marker"}],"source_content_type":"text/x-python","patch_set":54,"id":"60b39434_68b3b941","line":662,"in_reply_to":"4bd406a7_8123d644","updated":"2026-04-20 18:43:30.000000000","message":"No, I don\u0027t. there are total two cases of comparison between Timestamp and NormalTimestamp found so far, and they are for different purposes (string comparison \u0026 float comparision). the current implementation of ``self.internal \u003c other_ts.internal`` is good for string comparison, we can add more logic later on if there are other cases arising.","commit_id":"cf5df8fac80ff354ee8e6369dbf18a5e1fd75343"}],"swift/common/utils/__init__.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"2f9ad91ae23fa4eb0b7fce9e2db1841e698c52bf","unresolved":true,"context_lines":[{"line_number":4011,"context_line":"        self.root_container \u003d self._validate(root_container)"},{"line_number":4012,"context_line":"        self.parent_container_hash \u003d self._validate(parent_container_hash)"},{"line_number":4013,"context_line":"        # XXX flush out callers using Timestamp..."},{"line_number":4014,"context_line":"        assert not isinstance(timestamp, Timestamp), timestamp"},{"line_number":4015,"context_line":"        self.timestamp \u003d SimpleTimestamp(timestamp)"},{"line_number":4016,"context_line":"        self.index \u003d int(index)"},{"line_number":4017,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9d5c3b27_be7d27c3","line":4014,"updated":"2025-12-19 18:20:39.000000000","message":"pep8 doesn\u0027t like this so it\u0027ll need to be removed","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":false,"context_lines":[{"line_number":4011,"context_line":"        self.root_container \u003d self._validate(root_container)"},{"line_number":4012,"context_line":"        self.parent_container_hash \u003d self._validate(parent_container_hash)"},{"line_number":4013,"context_line":"        # XXX flush out callers using Timestamp..."},{"line_number":4014,"context_line":"        assert not isinstance(timestamp, Timestamp), timestamp"},{"line_number":4015,"context_line":"        self.timestamp \u003d SimpleTimestamp(timestamp)"},{"line_number":4016,"context_line":"        self.index \u003d int(index)"},{"line_number":4017,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"4d1e7067_f8e8ef72","line":4014,"in_reply_to":"9d5c3b27_be7d27c3","updated":"2025-12-23 05:53:53.000000000","message":"Done","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"2f9ad91ae23fa4eb0b7fce9e2db1841e698c52bf","unresolved":true,"context_lines":[{"line_number":4342,"context_line":"    @classmethod"},{"line_number":4343,"context_line":"    def _to_timestamp(cls, timestamp):"},{"line_number":4344,"context_line":"        # XXX flush out callers using Timestamp..."},{"line_number":4345,"context_line":"        assert not isinstance(timestamp, Timestamp), timestamp"},{"line_number":4346,"context_line":"        if timestamp is None or isinstance(timestamp, SimpleTimestamp):"},{"line_number":4347,"context_line":"            return timestamp"},{"line_number":4348,"context_line":"        return SimpleTimestamp(timestamp)"}],"source_content_type":"text/x-python","patch_set":4,"id":"03853c75_1317ddeb","line":4345,"updated":"2025-12-19 18:20:39.000000000","message":"pep8 doesn\u0027t like this so it\u0027ll need to be removed","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"b1194a9c5f9754053d0941738e4f54ce3add924c","unresolved":true,"context_lines":[{"line_number":4342,"context_line":"    @classmethod"},{"line_number":4343,"context_line":"    def _to_timestamp(cls, timestamp):"},{"line_number":4344,"context_line":"        # XXX flush out callers using Timestamp..."},{"line_number":4345,"context_line":"        assert not isinstance(timestamp, Timestamp), timestamp"},{"line_number":4346,"context_line":"        if timestamp is None or isinstance(timestamp, SimpleTimestamp):"},{"line_number":4347,"context_line":"            return timestamp"},{"line_number":4348,"context_line":"        return SimpleTimestamp(timestamp)"}],"source_content_type":"text/x-python","patch_set":4,"id":"5129f520_59ebc238","line":4345,"in_reply_to":"03853c75_1317ddeb","updated":"2025-12-22 04:01:31.000000000","message":"change this to below?\n```\n    if isinstance(timestamp, Timestamp):\n        raise TypeError(\n            \u0027ShardRange timestamps must not have offsets; \u0027\n            \u0027use SimpleTimestamp or timestamp.simplify()\u0027)\n```","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":false,"context_lines":[{"line_number":4342,"context_line":"    @classmethod"},{"line_number":4343,"context_line":"    def _to_timestamp(cls, timestamp):"},{"line_number":4344,"context_line":"        # XXX flush out callers using Timestamp..."},{"line_number":4345,"context_line":"        assert not isinstance(timestamp, Timestamp), timestamp"},{"line_number":4346,"context_line":"        if timestamp is None or isinstance(timestamp, SimpleTimestamp):"},{"line_number":4347,"context_line":"            return timestamp"},{"line_number":4348,"context_line":"        return SimpleTimestamp(timestamp)"}],"source_content_type":"text/x-python","patch_set":4,"id":"afa8dcec_08d4a76d","line":4345,"in_reply_to":"5129f520_59ebc238","updated":"2025-12-23 05:53:53.000000000","message":"Done","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":false,"context_lines":[{"line_number":4342,"context_line":"    @classmethod"},{"line_number":4343,"context_line":"    def _to_timestamp(cls, timestamp):"},{"line_number":4344,"context_line":"        # XXX flush out callers using Timestamp..."},{"line_number":4345,"context_line":"        assert not isinstance(timestamp, Timestamp), timestamp"},{"line_number":4346,"context_line":"        if timestamp is None or isinstance(timestamp, SimpleTimestamp):"},{"line_number":4347,"context_line":"            return timestamp"},{"line_number":4348,"context_line":"        return SimpleTimestamp(timestamp)"}],"source_content_type":"text/x-python","patch_set":4,"id":"b5e878ea_cdcc1c5d","line":4345,"in_reply_to":"5129f520_59ebc238","updated":"2025-12-23 12:37:13.000000000","message":"nice idea\n\nexcept we should not encourage use of ``simplify()`` because that can lead to loss of precision - callers should be encouraged to understand and use SimpleTimestamp","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":true,"context_lines":[{"line_number":4016,"context_line":"    Note: some instances of :class:`~swift.common.utils.ShardRange` have names"},{"line_number":4017,"context_line":"    that will NOT parse as a :class:`~swift.common.utils.ShardName`; e.g. a"},{"line_number":4018,"context_line":"    root container\u0027s own shard range will have a name format of"},{"line_number":4019,"context_line":"    \u003caccount\u003e/\u003croot_container\u003e which will raise ValueError if passed to parse."},{"line_number":4020,"context_line":"    \"\"\""},{"line_number":4021,"context_line":""},{"line_number":4022,"context_line":"    def __init__(self, account, root_container,"}],"source_content_type":"text/x-python","patch_set":5,"id":"ae433b9d_926068ca","line":4019,"updated":"2025-12-23 05:53:53.000000000","message":"add a note that the accepted format of ``timestamp`` will be `` str, number, or SimpleTimestamp instance``","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":false,"context_lines":[{"line_number":4016,"context_line":"    Note: some instances of :class:`~swift.common.utils.ShardRange` have names"},{"line_number":4017,"context_line":"    that will NOT parse as a :class:`~swift.common.utils.ShardName`; e.g. a"},{"line_number":4018,"context_line":"    root container\u0027s own shard range will have a name format of"},{"line_number":4019,"context_line":"    \u003caccount\u003e/\u003croot_container\u003e which will raise ValueError if passed to parse."},{"line_number":4020,"context_line":"    \"\"\""},{"line_number":4021,"context_line":""},{"line_number":4022,"context_line":"    def __init__(self, account, root_container,"}],"source_content_type":"text/x-python","patch_set":5,"id":"2858f61b_9e719bbc","line":4019,"in_reply_to":"ae433b9d_926068ca","updated":"2025-12-23 12:37:13.000000000","message":"I think I prefer to specify that timestamp should be a SimpleTimestamp - that is what it is in the current call site. It\u0027s a hidden bonus that other types would be accepted?","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":true,"context_lines":[{"line_number":4120,"context_line":"    associated with subsets of the shard range attributes are used to resolve"},{"line_number":4121,"context_line":"    conflicts when a shard range needs to be merged with an existing shard"},{"line_number":4122,"context_line":"    range record and the most recent version of an attribute should be"},{"line_number":4123,"context_line":"    persisted."},{"line_number":4124,"context_line":""},{"line_number":4125,"context_line":"    :param name: the name of the shard range; this MUST take the form of a"},{"line_number":4126,"context_line":"        path to a container i.e. \u003caccount_name\u003e/\u003ccontainer_name\u003e."}],"source_content_type":"text/x-python","patch_set":5,"id":"ebd2d7f1_d74ca2d1","line":4123,"updated":"2025-12-23 05:53:53.000000000","message":"add a comment line that all timestamps used within ``ShardRange`` are ``SimpleTimestamp``","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":false,"context_lines":[{"line_number":4120,"context_line":"    associated with subsets of the shard range attributes are used to resolve"},{"line_number":4121,"context_line":"    conflicts when a shard range needs to be merged with an existing shard"},{"line_number":4122,"context_line":"    range record and the most recent version of an attribute should be"},{"line_number":4123,"context_line":"    persisted."},{"line_number":4124,"context_line":""},{"line_number":4125,"context_line":"    :param name: the name of the shard range; this MUST take the form of a"},{"line_number":4126,"context_line":"        path to a container i.e. \u003caccount_name\u003e/\u003ccontainer_name\u003e."}],"source_content_type":"text/x-python","patch_set":5,"id":"5de4a0fd_c2b20186","line":4123,"in_reply_to":"ebd2d7f1_d74ca2d1","updated":"2025-12-23 12:37:13.000000000","message":"Done","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"a5472c6890c1c279417ce2e40bdc04e9286335cc","unresolved":true,"context_lines":[{"line_number":3986,"context_line":"        return namespaces"},{"line_number":3987,"context_line":""},{"line_number":3988,"context_line":""},{"line_number":3989,"context_line":"def _make_shard_timestamp(value):"},{"line_number":3990,"context_line":"    \"\"\""},{"line_number":3991,"context_line":"    Cast value to a SimpleTimestamp."},{"line_number":3992,"context_line":""}],"source_content_type":"text/x-python","patch_set":21,"id":"3ff4baec_e40143cc","line":3989,"updated":"2026-02-02 05:51:04.000000000","message":"complete off-topic, I wonder if sharding functions have gotten big enough to move to something like `swift.common.utils.sharding.*` or something?","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"b1f6423916fc6c6b1e98409ba3263f36e32e56fe","unresolved":true,"context_lines":[{"line_number":3986,"context_line":"        return namespaces"},{"line_number":3987,"context_line":""},{"line_number":3988,"context_line":""},{"line_number":3989,"context_line":"def _make_shard_timestamp(value):"},{"line_number":3990,"context_line":"    \"\"\""},{"line_number":3991,"context_line":"    Cast value to a SimpleTimestamp."},{"line_number":3992,"context_line":""}],"source_content_type":"text/x-python","patch_set":21,"id":"be027cb7_80d8ef17","line":3989,"in_reply_to":"3ff4baec_e40143cc","updated":"2026-02-03 15:28:48.000000000","message":"Absolutely! Get everything Shard* out of utils","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"8c52914928ded2e95cfa5d02408405cd92995b04","unresolved":false,"context_lines":[{"line_number":3986,"context_line":"        return namespaces"},{"line_number":3987,"context_line":""},{"line_number":3988,"context_line":""},{"line_number":3989,"context_line":"def _make_shard_timestamp(value):"},{"line_number":3990,"context_line":"    \"\"\""},{"line_number":3991,"context_line":"    Cast value to a SimpleTimestamp."},{"line_number":3992,"context_line":""}],"source_content_type":"text/x-python","patch_set":21,"id":"60c10471_55e458c9","line":3989,"in_reply_to":"be027cb7_80d8ef17","updated":"2026-02-13 15:48:34.000000000","message":"Acknowledged","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"a5472c6890c1c279417ce2e40bdc04e9286335cc","unresolved":true,"context_lines":[{"line_number":4001,"context_line":"        # Timestamp object with an offset part that would be lost if silently"},{"line_number":4002,"context_line":"        # cast to a SimpleTimestamp"},{"line_number":4003,"context_line":"        raise TypeError("},{"line_number":4004,"context_line":"            \u0027ShardRange timestamps must not be an instance of Timestamp\u0027)"},{"line_number":4005,"context_line":"    return SimpleTimestamp(value)"},{"line_number":4006,"context_line":""},{"line_number":4007,"context_line":""}],"source_content_type":"text/x-python","patch_set":21,"id":"fd69e0ca_c4d50d7b","line":4004,"updated":"2026-02-02 05:51:04.000000000","message":"Couldn\u0027t we just use a timestamp.simplify() here? Or I guess we want to be more belts and braces.","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"572d340c845c40e8642037d5f840dce46721d3a2","unresolved":false,"context_lines":[{"line_number":4001,"context_line":"        # Timestamp object with an offset part that would be lost if silently"},{"line_number":4002,"context_line":"        # cast to a SimpleTimestamp"},{"line_number":4003,"context_line":"        raise TypeError("},{"line_number":4004,"context_line":"            \u0027ShardRange timestamps must not be an instance of Timestamp\u0027)"},{"line_number":4005,"context_line":"    return SimpleTimestamp(value)"},{"line_number":4006,"context_line":""},{"line_number":4007,"context_line":""}],"source_content_type":"text/x-python","patch_set":21,"id":"ef884ba6_d958785e","line":4004,"in_reply_to":"a382ac95_b22b91c6","updated":"2026-02-13 06:56:37.000000000","message":"Fair call, silently dropping jitter does sound bad 😊","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"b1f6423916fc6c6b1e98409ba3263f36e32e56fe","unresolved":true,"context_lines":[{"line_number":4001,"context_line":"        # Timestamp object with an offset part that would be lost if silently"},{"line_number":4002,"context_line":"        # cast to a SimpleTimestamp"},{"line_number":4003,"context_line":"        raise TypeError("},{"line_number":4004,"context_line":"            \u0027ShardRange timestamps must not be an instance of Timestamp\u0027)"},{"line_number":4005,"context_line":"    return SimpleTimestamp(value)"},{"line_number":4006,"context_line":""},{"line_number":4007,"context_line":""}],"source_content_type":"text/x-python","patch_set":21,"id":"a382ac95_b22b91c6","line":4004,"in_reply_to":"fd69e0ca_c4d50d7b","updated":"2026-02-03 15:28:48.000000000","message":"I\u0027m deliberately preventing a caller writing:\n```\nshard_range.epoch \u003d Timestamp.now()\n```\nand thinking that the epoch has jitter, rather then silently dropping the jitter.","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"572d340c845c40e8642037d5f840dce46721d3a2","unresolved":true,"context_lines":[{"line_number":137,"context_line":"    MAX_OFFSET,"},{"line_number":138,"context_line":"    PRECISION,"},{"line_number":139,"context_line":"    Timestamp,"},{"line_number":140,"context_line":"    SimpleTimestamp,"},{"line_number":141,"context_line":"    encode_timestamps,"},{"line_number":142,"context_line":"    decode_timestamps,"},{"line_number":143,"context_line":"    normalize_timestamp,"}],"source_content_type":"text/x-python","patch_set":24,"id":"2a929d80_574abda7","line":140,"updated":"2026-02-13 06:56:37.000000000","message":"I wonder if we should stop expanding this \"linking\" and force codebases to start using `swift.common.utils.timestamp.{Timestamp,SimpleTimestamp}` so they\u0027re forced to start making the move.","commit_id":"68014f782523fc463f314435c730fba2c2ac0b76"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"2b502d8617e24424a4ac2bb164dce3e4cc7f1625","unresolved":true,"context_lines":[{"line_number":137,"context_line":"    MAX_OFFSET,"},{"line_number":138,"context_line":"    PRECISION,"},{"line_number":139,"context_line":"    Timestamp,"},{"line_number":140,"context_line":"    SimpleTimestamp,"},{"line_number":141,"context_line":"    encode_timestamps,"},{"line_number":142,"context_line":"    decode_timestamps,"},{"line_number":143,"context_line":"    normalize_timestamp,"}],"source_content_type":"text/x-python","patch_set":24,"id":"bd919de4_cc93bef3","line":140,"in_reply_to":"2a929d80_574abda7","updated":"2026-02-13 10:40:39.000000000","message":"Agree","commit_id":"68014f782523fc463f314435c730fba2c2ac0b76"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"8c52914928ded2e95cfa5d02408405cd92995b04","unresolved":false,"context_lines":[{"line_number":137,"context_line":"    MAX_OFFSET,"},{"line_number":138,"context_line":"    PRECISION,"},{"line_number":139,"context_line":"    Timestamp,"},{"line_number":140,"context_line":"    SimpleTimestamp,"},{"line_number":141,"context_line":"    encode_timestamps,"},{"line_number":142,"context_line":"    decode_timestamps,"},{"line_number":143,"context_line":"    normalize_timestamp,"}],"source_content_type":"text/x-python","patch_set":24,"id":"f3c50508_7931cbb6","line":140,"in_reply_to":"bd919de4_cc93bef3","updated":"2026-02-13 15:48:34.000000000","message":"Update: it needs to be imported because it is used in this module (somewhere in Shard* classes)","commit_id":"68014f782523fc463f314435c730fba2c2ac0b76"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"2b502d8617e24424a4ac2bb164dce3e4cc7f1625","unresolved":true,"context_lines":[{"line_number":143,"context_line":"    normalize_timestamp,"},{"line_number":144,"context_line":"    EPOCH,"},{"line_number":145,"context_line":"    last_modified_date_to_timestamp,"},{"line_number":146,"context_line":"    normalize_delete_at_timestamp,"},{"line_number":147,"context_line":")"},{"line_number":148,"context_line":"from swift.common.utils.ipaddrs import (  # noqa"},{"line_number":149,"context_line":"    is_valid_ip,"}],"source_content_type":"text/x-python","patch_set":24,"id":"0247d868_aa633010","line":146,"updated":"2026-02-13 10:40:39.000000000","message":"tut tut, unnecessary change! take your own medicine acoles!","commit_id":"68014f782523fc463f314435c730fba2c2ac0b76"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"8c52914928ded2e95cfa5d02408405cd92995b04","unresolved":false,"context_lines":[{"line_number":143,"context_line":"    normalize_timestamp,"},{"line_number":144,"context_line":"    EPOCH,"},{"line_number":145,"context_line":"    last_modified_date_to_timestamp,"},{"line_number":146,"context_line":"    normalize_delete_at_timestamp,"},{"line_number":147,"context_line":")"},{"line_number":148,"context_line":"from swift.common.utils.ipaddrs import (  # noqa"},{"line_number":149,"context_line":"    is_valid_ip,"}],"source_content_type":"text/x-python","patch_set":24,"id":"a53b9fba_f6759c66","line":146,"in_reply_to":"0247d868_aa633010","updated":"2026-02-13 15:48:34.000000000","message":"Done","commit_id":"68014f782523fc463f314435c730fba2c2ac0b76"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":true,"context_lines":[{"line_number":4047,"context_line":"        self.account \u003d self._validate(account)"},{"line_number":4048,"context_line":"        self.root_container \u003d self._validate(root_container)"},{"line_number":4049,"context_line":"        self.parent_container_hash \u003d self._validate(parent_container_hash)"},{"line_number":4050,"context_line":"        self.timestamp \u003d _make_shard_timestamp(timestamp)"},{"line_number":4051,"context_line":"        self.index \u003d int(index)"},{"line_number":4052,"context_line":""},{"line_number":4053,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":27,"id":"ab5ac5b1_1465a9f6","line":4050,"updated":"2026-02-19 06:22:12.000000000","message":"Nice, so it\u0027ll let us know if the worng timestamp class is passed in, love it.","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":4047,"context_line":"        self.account \u003d self._validate(account)"},{"line_number":4048,"context_line":"        self.root_container \u003d self._validate(root_container)"},{"line_number":4049,"context_line":"        self.parent_container_hash \u003d self._validate(parent_container_hash)"},{"line_number":4050,"context_line":"        self.timestamp \u003d _make_shard_timestamp(timestamp)"},{"line_number":4051,"context_line":"        self.index \u003d int(index)"},{"line_number":4052,"context_line":""},{"line_number":4053,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":27,"id":"6bcecc16_27ff3422","line":4050,"in_reply_to":"ab5ac5b1_1465a9f6","updated":"2026-02-19 14:46:16.000000000","message":"Acknowledged","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":true,"context_lines":[{"line_number":4366,"context_line":"            shard; for initial first generation shards this should be the same"},{"line_number":4367,"context_line":"            as ``root_container``; for shards of shards this should be the name"},{"line_number":4368,"context_line":"            of the sharding shard container."},{"line_number":4369,"context_line":"        :param timestamp: an instance of :class:`~swift.common.utils.Timestamp`"},{"line_number":4370,"context_line":"        :param index: a unique index that will distinguish the path from any"},{"line_number":4371,"context_line":"            other path generated using the same combination of"},{"line_number":4372,"context_line":"            ``shards_account``, ``root_container``, ``parent_container`` and"}],"source_content_type":"text/x-python","patch_set":27,"id":"c17175a7_827240f8","line":4369,"range":{"start_line":4369,"start_character":69,"end_line":4369,"end_character":78},"updated":"2026-02-19 06:22:12.000000000","message":"This needs to be NormalTimestamp right?","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":4366,"context_line":"            shard; for initial first generation shards this should be the same"},{"line_number":4367,"context_line":"            as ``root_container``; for shards of shards this should be the name"},{"line_number":4368,"context_line":"            of the sharding shard container."},{"line_number":4369,"context_line":"        :param timestamp: an instance of :class:`~swift.common.utils.Timestamp`"},{"line_number":4370,"context_line":"        :param index: a unique index that will distinguish the path from any"},{"line_number":4371,"context_line":"            other path generated using the same combination of"},{"line_number":4372,"context_line":"            ``shards_account``, ``root_container``, ``parent_container`` and"}],"source_content_type":"text/x-python","patch_set":27,"id":"2cd1a2c5_476f7b7a","line":4369,"range":{"start_line":4369,"start_character":69,"end_line":4369,"end_character":78},"in_reply_to":"c17175a7_827240f8","updated":"2026-02-19 14:46:16.000000000","message":"Done","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":true,"context_lines":[{"line_number":4373,"context_line":"            ``timestamp``."},{"line_number":4374,"context_line":"        :return: a string of the form \u003caccount_name\u003e/\u003ccontainer_name\u003e"},{"line_number":4375,"context_line":"        \"\"\""},{"line_number":4376,"context_line":"        timestamp \u003d _make_shard_timestamp(timestamp)"},{"line_number":4377,"context_line":"        return str(ShardName.create(shards_account,"},{"line_number":4378,"context_line":"                                    root_container,"},{"line_number":4379,"context_line":"                                    parent_container,"}],"source_content_type":"text/x-python","patch_set":27,"id":"81671e87_d9431ed7","line":4376,"updated":"2026-02-19 06:22:12.000000000","message":"The ShardName.create below will call ShardName.__init__ which also does the timestamp check, so this strictly isn\u0027t required.. but belt and braces and to fail eariler (and for dev tracebacks) I like that this is explicit.","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":4373,"context_line":"            ``timestamp``."},{"line_number":4374,"context_line":"        :return: a string of the form \u003caccount_name\u003e/\u003ccontainer_name\u003e"},{"line_number":4375,"context_line":"        \"\"\""},{"line_number":4376,"context_line":"        timestamp \u003d _make_shard_timestamp(timestamp)"},{"line_number":4377,"context_line":"        return str(ShardName.create(shards_account,"},{"line_number":4378,"context_line":"                                    root_container,"},{"line_number":4379,"context_line":"                                    parent_container,"}],"source_content_type":"text/x-python","patch_set":27,"id":"4eccebe7_b9e40d3a","line":4376,"in_reply_to":"81671e87_d9431ed7","updated":"2026-02-19 14:46:16.000000000","message":"Acknowledged","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":true,"context_lines":[{"line_number":3997,"context_line":"    if value is None or isinstance(value, NormalTimestamp):"},{"line_number":3998,"context_line":"        return value"},{"line_number":3999,"context_line":"    if isinstance(value, Timestamp):"},{"line_number":4000,"context_line":"        # this is very specific but intended to avoid callers passing in a"},{"line_number":4001,"context_line":"        # Timestamp object with an offset part that would be lost if silently"},{"line_number":4002,"context_line":"        # cast to a NormalTimestamp"},{"line_number":4003,"context_line":"        raise TypeError("}],"source_content_type":"text/x-python","patch_set":28,"id":"58dc7431_e3d45588","line":4000,"updated":"2026-02-19 14:46:16.000000000","message":"should we allow a Timestamp if it has no hex part? IDK, I don\u0027t really want this to be a runtime error, more to catch bad code in unit test","commit_id":"4494e43b26e8a374b66ecaa80897ce9c630514d9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":false,"context_lines":[{"line_number":3997,"context_line":"    if value is None or isinstance(value, NormalTimestamp):"},{"line_number":3998,"context_line":"        return value"},{"line_number":3999,"context_line":"    if isinstance(value, Timestamp):"},{"line_number":4000,"context_line":"        # this is very specific but intended to avoid callers passing in a"},{"line_number":4001,"context_line":"        # Timestamp object with an offset part that would be lost if silently"},{"line_number":4002,"context_line":"        # cast to a NormalTimestamp"},{"line_number":4003,"context_line":"        raise TypeError("}],"source_content_type":"text/x-python","patch_set":28,"id":"b0ae7b5e_a8c42c6c","line":4000,"in_reply_to":"58dc7431_e3d45588","updated":"2026-04-15 14:23:58.000000000","message":"Done","commit_id":"4494e43b26e8a374b66ecaa80897ce9c630514d9"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"64fba0d90b3e7f669a54fcaa4c6e5e2628b0aa90","unresolved":true,"context_lines":[{"line_number":137,"context_line":"    MAX_OFFSET,"},{"line_number":138,"context_line":"    PRECISION,"},{"line_number":139,"context_line":"    Timestamp,"},{"line_number":140,"context_line":"    NormalTimestamp,"},{"line_number":141,"context_line":"    encode_timestamps,"},{"line_number":142,"context_line":"    decode_timestamps,"},{"line_number":143,"context_line":"    normalize_timestamp,"}],"source_content_type":"text/x-python","patch_set":50,"id":"cabc6fef_dd12a95a","line":140,"updated":"2026-04-15 05:39:11.000000000","message":"Arguably this is new and should always been used in the new style, and the Timestamp here was for backward compat. But I guess this is still helpful. So not a blocker for me.","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"9c8423858953192777b7b9e1269ff8c67798b2ec","unresolved":false,"context_lines":[{"line_number":137,"context_line":"    MAX_OFFSET,"},{"line_number":138,"context_line":"    PRECISION,"},{"line_number":139,"context_line":"    Timestamp,"},{"line_number":140,"context_line":"    NormalTimestamp,"},{"line_number":141,"context_line":"    encode_timestamps,"},{"line_number":142,"context_line":"    decode_timestamps,"},{"line_number":143,"context_line":"    normalize_timestamp,"}],"source_content_type":"text/x-python","patch_set":50,"id":"80023fd1_93b9ec2f","line":140,"in_reply_to":"0ff67430_9a4f869f","updated":"2026-04-20 11:40:10.000000000","message":"Done","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":137,"context_line":"    MAX_OFFSET,"},{"line_number":138,"context_line":"    PRECISION,"},{"line_number":139,"context_line":"    Timestamp,"},{"line_number":140,"context_line":"    NormalTimestamp,"},{"line_number":141,"context_line":"    encode_timestamps,"},{"line_number":142,"context_line":"    decode_timestamps,"},{"line_number":143,"context_line":"    normalize_timestamp,"}],"source_content_type":"text/x-python","patch_set":50,"id":"0ff67430_9a4f869f","line":140,"in_reply_to":"cabc6fef_dd12a95a","updated":"2026-04-15 14:23:58.000000000","message":"This here because NormalTimestamp is used in this module.\n\nWe should move all the shard related stuff out of utils and then we can drop this import.\n\nI\u0027ll add a comment to clarify why this is here.","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":4642,"context_line":"    def __repr__(self):"},{"line_number":4643,"context_line":"        return \u0027%s\u003c%r to %r as of %s, (%d, %d) as of %s, %s as of %s\u003e\u0027 % ("},{"line_number":4644,"context_line":"            self.__class__.__name__, self.lower, self.upper,"},{"line_number":4645,"context_line":"            self.timestamp.normal, self.object_count, self.bytes_used,"},{"line_number":4646,"context_line":"            self.meta_timestamp.normal, self.state_text,"},{"line_number":4647,"context_line":"            self.state_timestamp.normal)"},{"line_number":4648,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"4fffb7d0_a40390fb","line":4645,"range":{"start_line":4645,"start_character":27,"end_line":4645,"end_character":33},"updated":"2026-04-15 14:23:58.000000000","message":"not necessary to change the format to normal","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"9c8423858953192777b7b9e1269ff8c67798b2ec","unresolved":false,"context_lines":[{"line_number":4642,"context_line":"    def __repr__(self):"},{"line_number":4643,"context_line":"        return \u0027%s\u003c%r to %r as of %s, (%d, %d) as of %s, %s as of %s\u003e\u0027 % ("},{"line_number":4644,"context_line":"            self.__class__.__name__, self.lower, self.upper,"},{"line_number":4645,"context_line":"            self.timestamp.normal, self.object_count, self.bytes_used,"},{"line_number":4646,"context_line":"            self.meta_timestamp.normal, self.state_text,"},{"line_number":4647,"context_line":"            self.state_timestamp.normal)"},{"line_number":4648,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"cc4299a7_c276c5e8","line":4645,"range":{"start_line":4645,"start_character":27,"end_line":4645,"end_character":33},"in_reply_to":"4fffb7d0_a40390fb","updated":"2026-04-20 11:40:10.000000000","message":"Done","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"}],"swift/common/utils/timestamp.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d6ebb733966e5f0db52278ffd5f77298f3e747c6","unresolved":true,"context_lines":[{"line_number":168,"context_line":"    def __eq__(self, other):"},{"line_number":169,"context_line":"        if other is None:"},{"line_number":170,"context_line":"            return False"},{"line_number":171,"context_line":"        if not isinstance(other, BaseTimestamp):"},{"line_number":172,"context_line":"            try:"},{"line_number":173,"context_line":"                other \u003d self.__class__(other, check_bounds\u003dFalse)"},{"line_number":174,"context_line":"            except ValueError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"96cf4b8e_1826de0d","line":171,"updated":"2025-11-27 18:38:58.000000000","message":"need to think more about when a SimpleTimestamp is equal to a Timestamp etc","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"f2713af9e0b3d6bfd3684c2a296791b75d63ddb8","unresolved":false,"context_lines":[{"line_number":168,"context_line":"    def __eq__(self, other):"},{"line_number":169,"context_line":"        if other is None:"},{"line_number":170,"context_line":"            return False"},{"line_number":171,"context_line":"        if not isinstance(other, BaseTimestamp):"},{"line_number":172,"context_line":"            try:"},{"line_number":173,"context_line":"                other \u003d self.__class__(other, check_bounds\u003dFalse)"},{"line_number":174,"context_line":"            except ValueError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"98a11967_803d2741","line":171,"in_reply_to":"370ec80e_a772c3a5","updated":"2026-02-18 12:04:09.000000000","message":"Done","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"2b502d8617e24424a4ac2bb164dce3e4cc7f1625","unresolved":true,"context_lines":[{"line_number":168,"context_line":"    def __eq__(self, other):"},{"line_number":169,"context_line":"        if other is None:"},{"line_number":170,"context_line":"            return False"},{"line_number":171,"context_line":"        if not isinstance(other, BaseTimestamp):"},{"line_number":172,"context_line":"            try:"},{"line_number":173,"context_line":"                other \u003d self.__class__(other, check_bounds\u003dFalse)"},{"line_number":174,"context_line":"            except ValueError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"370ec80e_a772c3a5","line":171,"in_reply_to":"6b18cf2d_3d4fb0f7","updated":"2026-02-13 10:40:39.000000000","message":"yes, this @Matt - internal IS the canonical represntation for all BaseTimestamps","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"b1194a9c5f9754053d0941738e4f54ce3add924c","unresolved":true,"context_lines":[{"line_number":168,"context_line":"    def __eq__(self, other):"},{"line_number":169,"context_line":"        if other is None:"},{"line_number":170,"context_line":"            return False"},{"line_number":171,"context_line":"        if not isinstance(other, BaseTimestamp):"},{"line_number":172,"context_line":"            try:"},{"line_number":173,"context_line":"                other \u003d self.__class__(other, check_bounds\u003dFalse)"},{"line_number":174,"context_line":"            except ValueError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"b21346bf_5e334870","line":171,"in_reply_to":"96cf4b8e_1826de0d","updated":"2025-12-22 04:01:31.000000000","message":"I think we would need this, probably we have this somewhere\n```\n   if object_timestamp \u003e shard_range.epoch:\n       # Object is older than when sharding started\n```","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"572d340c845c40e8642037d5f840dce46721d3a2","unresolved":true,"context_lines":[{"line_number":168,"context_line":"    def __eq__(self, other):"},{"line_number":169,"context_line":"        if other is None:"},{"line_number":170,"context_line":"            return False"},{"line_number":171,"context_line":"        if not isinstance(other, BaseTimestamp):"},{"line_number":172,"context_line":"            try:"},{"line_number":173,"context_line":"                other \u003d self.__class__(other, check_bounds\u003dFalse)"},{"line_number":174,"context_line":"            except ValueError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"6b18cf2d_3d4fb0f7","line":171,"in_reply_to":"b21346bf_5e334870","updated":"2026-02-13 06:56:37.000000000","message":"Maybe this is a good reason to have internal? then we can just do a simple internal check, noraml vs internal basically a str check? and \u003e, \u003c etc should still work? \n\nor just check ts.timestamp (but then we\u0027d never check offsets.. )","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d6ebb733966e5f0db52278ffd5f77298f3e747c6","unresolved":true,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":""},{"line_number":199,"context_line":"@functools.total_ordering"},{"line_number":200,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":201,"context_line":"    \"\"\""},{"line_number":202,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":203,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":1,"id":"5c88bf49_ebf6e96d","line":200,"updated":"2025-11-27 18:38:58.000000000","message":"it\u0027s a empty subclass so that Timestamp is NOT an instance of SimpleTimestamp, which allows assertions when a SimpleTimestamp is expected and not a Timestamp","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":false,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":""},{"line_number":199,"context_line":"@functools.total_ordering"},{"line_number":200,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":201,"context_line":"    \"\"\""},{"line_number":202,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":203,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":1,"id":"9c00497c_3f314879","line":200,"in_reply_to":"121683e8_0f508106","updated":"2025-12-23 05:53:53.000000000","message":"Acknowledged","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":false,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":""},{"line_number":199,"context_line":"@functools.total_ordering"},{"line_number":200,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":201,"context_line":"    \"\"\""},{"line_number":202,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":203,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":1,"id":"c42a4ed5_e73a7dea","line":200,"in_reply_to":"121683e8_0f508106","updated":"2025-12-23 12:37:13.000000000","message":"Acknowledged","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"b1194a9c5f9754053d0941738e4f54ce3add924c","unresolved":true,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":""},{"line_number":199,"context_line":"@functools.total_ordering"},{"line_number":200,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":201,"context_line":"    \"\"\""},{"line_number":202,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":203,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":1,"id":"121683e8_0f508106","line":200,"in_reply_to":"5c88bf49_ebf6e96d","updated":"2025-12-22 04:01:31.000000000","message":"This is a good design choice. If SimpleTimestamp didn\u0027t exist, for below code:\n```\nif isinstance(ts, BaseTimestamp):\n    return ts\n```\nSince ts inherits from BaseTimestamp, ``isinstance(ts, BaseTimestamp)`` would be ``True`` for BOTH simple and offset timestamps.","commit_id":"c815f735c1ed95ca41559dec6b8797b5cc4ebd98"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"b1194a9c5f9754053d0941738e4f54ce3add924c","unresolved":true,"context_lines":[{"line_number":37,"context_line":"class BaseTimestamp:"},{"line_number":38,"context_line":"    def __init__(self, timestamp, delta\u003d0, check_bounds\u003dTrue):"},{"line_number":39,"context_line":"        \"\"\""},{"line_number":40,"context_line":"        Create a new SimpleTimestamp."},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"        :param timestamp: time in seconds since the Epoch, may be any of:"},{"line_number":43,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"74b90c9a_272105c3","line":40,"updated":"2025-12-22 04:01:31.000000000","message":"how about just use ``Create a new BaseTimestamp``?","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":false,"context_lines":[{"line_number":37,"context_line":"class BaseTimestamp:"},{"line_number":38,"context_line":"    def __init__(self, timestamp, delta\u003d0, check_bounds\u003dTrue):"},{"line_number":39,"context_line":"        \"\"\""},{"line_number":40,"context_line":"        Create a new SimpleTimestamp."},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"        :param timestamp: time in seconds since the Epoch, may be any of:"},{"line_number":43,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"5abaac49_3abdd26e","line":40,"in_reply_to":"74b90c9a_272105c3","updated":"2025-12-23 05:53:53.000000000","message":"Done","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"b1194a9c5f9754053d0941738e4f54ce3add924c","unresolved":true,"context_lines":[{"line_number":55,"context_line":"            timestamp \u003d timestamp.decode(\u0027ascii\u0027)"},{"line_number":56,"context_line":"        if isinstance(timestamp, str) and \u0027_\u0027 in timestamp:"},{"line_number":57,"context_line":"            # note: python will cast 1.2_3 to a float!"},{"line_number":58,"context_line":"            raise ValueError(\u0027SimpleTimestamp must not contain \"_\"\u0027)"},{"line_number":59,"context_line":"        float_timestamp \u003d float(timestamp)"},{"line_number":60,"context_line":"        self.raw \u003d int(round(float_timestamp / PRECISION))"},{"line_number":61,"context_line":"        # add delta"}],"source_content_type":"text/x-python","patch_set":4,"id":"0900c12e_a79f8c30","line":58,"updated":"2025-12-22 04:01:31.000000000","message":"``\u0027SimpleTimestamp must not contain \"_\"\u0027``, I thought this is a bug, but later realized that ``Timestamp `` has its own constructor and ``Timestamp.__init__`` removes the underscore before calling ``super().__init__()``, so ``BaseTimestamp.__init__`` never sees the underscore and offset.\n\nAnd ``SimpleTimestamp`` has no ``__init__``, so it goes straight to ``BaseTimestamp.__init__``\n```\nts \u003d SimpleTimestamp(\u00271234.56_01\u0027)\n```\nthis will raise ``ValueError(\u0027SimpleTimestamp must not contain \"_\"\u0027)``\n\nAfter I understand why, I feel the error message below can help avoid confusing.\n```\nif isinstance(timestamp, str) and \u0027_\u0027 in timestamp:\n    raise ValueError(\n        \u0027timestamp string must not contain \"_\"; \u0027\n        \u0027use Timestamp class for offset values, not SimpleTimestamp\u0027)\n```","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":false,"context_lines":[{"line_number":55,"context_line":"            timestamp \u003d timestamp.decode(\u0027ascii\u0027)"},{"line_number":56,"context_line":"        if isinstance(timestamp, str) and \u0027_\u0027 in timestamp:"},{"line_number":57,"context_line":"            # note: python will cast 1.2_3 to a float!"},{"line_number":58,"context_line":"            raise ValueError(\u0027SimpleTimestamp must not contain \"_\"\u0027)"},{"line_number":59,"context_line":"        float_timestamp \u003d float(timestamp)"},{"line_number":60,"context_line":"        self.raw \u003d int(round(float_timestamp / PRECISION))"},{"line_number":61,"context_line":"        # add delta"}],"source_content_type":"text/x-python","patch_set":4,"id":"03817c0e_c68112e0","line":58,"in_reply_to":"0900c12e_a79f8c30","updated":"2025-12-23 05:53:53.000000000","message":"Done","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":false,"context_lines":[{"line_number":55,"context_line":"            timestamp \u003d timestamp.decode(\u0027ascii\u0027)"},{"line_number":56,"context_line":"        if isinstance(timestamp, str) and \u0027_\u0027 in timestamp:"},{"line_number":57,"context_line":"            # note: python will cast 1.2_3 to a float!"},{"line_number":58,"context_line":"            raise ValueError(\u0027SimpleTimestamp must not contain \"_\"\u0027)"},{"line_number":59,"context_line":"        float_timestamp \u003d float(timestamp)"},{"line_number":60,"context_line":"        self.raw \u003d int(round(float_timestamp / PRECISION))"},{"line_number":61,"context_line":"        # add delta"}],"source_content_type":"text/x-python","patch_set":4,"id":"94f2e934_1cd68ce9","line":58,"in_reply_to":"0900c12e_a79f8c30","updated":"2025-12-23 12:37:13.000000000","message":"ok, I think this can also be clearer by moving the string parsing to each subclass","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"b1194a9c5f9754053d0941738e4f54ce3add924c","unresolved":true,"context_lines":[{"line_number":215,"context_line":"    The normalized form of time looks like a float with a fixed width to ensure"},{"line_number":216,"context_line":"    stable string sorting - normalized timestamps look like \"1402464677.04188\""},{"line_number":217,"context_line":"    \"\"\""},{"line_number":218,"context_line":"    # this empty subclass allows tests to mock SimpleTimestamp without changing"},{"line_number":219,"context_line":"    # superclass behavior inherited by Timestamp"},{"line_number":220,"context_line":""},{"line_number":221,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"a78c1526_006924b9","line":218,"updated":"2025-12-22 04:01:31.000000000","message":"I used an example to help me understand this. for example, we can mock SimpleTimestamp.now() separately from Timestamp.now()\n```\nwith mock.patch.object(SimpleTimestamp, \u0027now\u0027, return_value\u003dxxx):\n    sr \u003d ShardRange(...)  # Uses mocked SimpleTimestamp\n    # But Timestamp.now() still works normally elsewhere\n```\nIf ``SimpleTimestamp`` was just ``BaseTimestamp``, mocking it would affect ``Timestamp`` too since they share the base class.","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":false,"context_lines":[{"line_number":215,"context_line":"    The normalized form of time looks like a float with a fixed width to ensure"},{"line_number":216,"context_line":"    stable string sorting - normalized timestamps look like \"1402464677.04188\""},{"line_number":217,"context_line":"    \"\"\""},{"line_number":218,"context_line":"    # this empty subclass allows tests to mock SimpleTimestamp without changing"},{"line_number":219,"context_line":"    # superclass behavior inherited by Timestamp"},{"line_number":220,"context_line":""},{"line_number":221,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"d7f8803d_901d12f5","line":218,"in_reply_to":"a78c1526_006924b9","updated":"2025-12-23 05:53:53.000000000","message":"Acknowledged","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":false,"context_lines":[{"line_number":215,"context_line":"    The normalized form of time looks like a float with a fixed width to ensure"},{"line_number":216,"context_line":"    stable string sorting - normalized timestamps look like \"1402464677.04188\""},{"line_number":217,"context_line":"    \"\"\""},{"line_number":218,"context_line":"    # this empty subclass allows tests to mock SimpleTimestamp without changing"},{"line_number":219,"context_line":"    # superclass behavior inherited by Timestamp"},{"line_number":220,"context_line":""},{"line_number":221,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"dd2e444d_ba514c05","line":218,"in_reply_to":"a78c1526_006924b9","updated":"2025-12-23 12:37:13.000000000","message":"Acknowledged","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":true,"context_lines":[{"line_number":172,"context_line":"                other \u003d self.__class__(other, check_bounds\u003dFalse)"},{"line_number":173,"context_line":"            except ValueError:"},{"line_number":174,"context_line":"                return False"},{"line_number":175,"context_line":"        return self.internal \u003d\u003d other.internal"},{"line_number":176,"context_line":""},{"line_number":177,"context_line":"    def __ne__(self, other):"},{"line_number":178,"context_line":"        return not (self \u003d\u003d other)"}],"source_content_type":"text/x-python","patch_set":5,"id":"2e23a90f_cc1ad273","line":175,"updated":"2025-12-23 05:53:53.000000000","message":"it won\u0027t work when we compare a SimpleTimestamp against a Timestamp, the internal of Timestamp has a random jitter.","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"f2713af9e0b3d6bfd3684c2a296791b75d63ddb8","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                other \u003d self.__class__(other, check_bounds\u003dFalse)"},{"line_number":173,"context_line":"            except ValueError:"},{"line_number":174,"context_line":"                return False"},{"line_number":175,"context_line":"        return self.internal \u003d\u003d other.internal"},{"line_number":176,"context_line":""},{"line_number":177,"context_line":"    def __ne__(self, other):"},{"line_number":178,"context_line":"        return not (self \u003d\u003d other)"}],"source_content_type":"text/x-python","patch_set":5,"id":"4672f789_2a60e29d","line":175,"in_reply_to":"1a539864_cf2b2b60","updated":"2026-02-18 12:04:09.000000000","message":"Acknowledged","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":true,"context_lines":[{"line_number":172,"context_line":"                other \u003d self.__class__(other, check_bounds\u003dFalse)"},{"line_number":173,"context_line":"            except ValueError:"},{"line_number":174,"context_line":"                return False"},{"line_number":175,"context_line":"        return self.internal \u003d\u003d other.internal"},{"line_number":176,"context_line":""},{"line_number":177,"context_line":"    def __ne__(self, other):"},{"line_number":178,"context_line":"        return not (self \u003d\u003d other)"}],"source_content_type":"text/x-python","patch_set":5,"id":"1a539864_cf2b2b60","line":175,"in_reply_to":"2e23a90f_cc1ad273","updated":"2025-12-23 12:37:13.000000000","message":"right, but a SimpleTimestamp should not be equal to a Timestamp with jitter, I think.\n\nWhat is now true is that a SimpleTimestamp can be equal to a Timestamp when the Timestamp has zero jitter","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":false,"context_lines":[{"line_number":227,"context_line":"        if isinstance(timestamp, str) and \u0027_\u0027 in timestamp:"},{"line_number":228,"context_line":"            # note: python will cast 1.2_3 to a float, and we do not want to"},{"line_number":229,"context_line":"            # accidentally parse a Timestamp (with offset) as a SimpleTimestamp"},{"line_number":230,"context_line":"            raise ValueError(\u0027timestamp must not contain \"_\"\u0027)"},{"line_number":231,"context_line":"        super().__init__(float(timestamp), delta, check_bounds\u003dcheck_bounds)"},{"line_number":232,"context_line":""},{"line_number":233,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"deb22ad1_0e75e635","line":230,"updated":"2025-12-23 05:53:53.000000000","message":"Nice, this makes much more sense now.","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"b1f6423916fc6c6b1e98409ba3263f36e32e56fe","unresolved":true,"context_lines":[{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    @property"},{"line_number":101,"context_line":"    def internal(self):"},{"line_number":102,"context_line":"        return self.normal"},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    @property"},{"line_number":105,"context_line":"    def isoformat(self):"}],"source_content_type":"text/x-python","patch_set":21,"id":"a4f856e1_69128a68","line":102,"updated":"2026-02-03 15:28:48.000000000","message":"does this need to be in the BaseTimestamp since it is only relevant to Timestamp?","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    @property"},{"line_number":101,"context_line":"    def internal(self):"},{"line_number":102,"context_line":"        return self.normal"},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    @property"},{"line_number":105,"context_line":"    def isoformat(self):"}],"source_content_type":"text/x-python","patch_set":21,"id":"1a6d0100_f6bec88d","line":102,"in_reply_to":"4b91d8ac_daf6c94b","updated":"2026-02-19 14:46:16.000000000","message":"Update: I changed it back because we want callers to be able to use ``internal`` without knowing which BaseTimestamp subclass they have","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"2b502d8617e24424a4ac2bb164dce3e4cc7f1625","unresolved":true,"context_lines":[{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    @property"},{"line_number":101,"context_line":"    def internal(self):"},{"line_number":102,"context_line":"        return self.normal"},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    @property"},{"line_number":105,"context_line":"    def isoformat(self):"}],"source_content_type":"text/x-python","patch_set":21,"id":"f0ebc635_7a261e87","line":102,"in_reply_to":"a4f856e1_69128a68","updated":"2026-02-13 10:40:39.000000000","message":"I realised we do need all BaseTimestamps to have internal because this is the attribute used to evaluate equality/ordering of BaseTimestamp instances.\n\nI should add a comment.\n\nIt might be more conventional to have that be ``__str__`` but I guess historically it was felt that str(timestamp) should be outlawed to prevent anyone getting the wrong form???","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"572d340c845c40e8642037d5f840dce46721d3a2","unresolved":true,"context_lines":[{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    @property"},{"line_number":101,"context_line":"    def internal(self):"},{"line_number":102,"context_line":"        return self.normal"},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    @property"},{"line_number":105,"context_line":"    def isoformat(self):"}],"source_content_type":"text/x-python","patch_set":21,"id":"3cf17b84_27bc4073","line":102,"in_reply_to":"a4f856e1_69128a68","updated":"2026-02-13 06:56:37.000000000","message":"oh now that\u0027s a good question, internal doesn\u0027t seem to be something related to a SimpleTimestamp or Base. However, on that same note, why do we need a Noraml then, the fact that there is a normal does mean there is also something not normal? what is normal.\n\nI guess it comes down to how we plan to use these, will we use them polymorphically? With the current seperation with shardrange epochs etc, I fell we\u0027re not going to use a BaseTimesamp polymorphically so I say, no it probalby doesn\u0027t need `internal` it\u0027s doesn\u0027t make sense for it to have one.","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"8c52914928ded2e95cfa5d02408405cd92995b04","unresolved":true,"context_lines":[{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    @property"},{"line_number":101,"context_line":"    def internal(self):"},{"line_number":102,"context_line":"        return self.normal"},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    @property"},{"line_number":105,"context_line":"    def isoformat(self):"}],"source_content_type":"text/x-python","patch_set":21,"id":"4b91d8ac_daf6c94b","line":102,"in_reply_to":"f0ebc635_7a261e87","updated":"2026-02-13 15:48:34.000000000","message":"Update: I changed this to use a \u0027private\u0027 property for comparison purposes so that the base class does not have internal.\n\nIdeally we\u0027d use ``__repr__`` but \n``Timestamp(0).__repr__() !\u003d SimpleTimestamp(0).__repr__()``\n😞","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"b1f6423916fc6c6b1e98409ba3263f36e32e56fe","unresolved":true,"context_lines":[{"line_number":195,"context_line":"        return self.__class__((999999999999999 - self.raw) * PRECISION)"},{"line_number":196,"context_line":""},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"@functools.total_ordering"},{"line_number":199,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":200,"context_line":"    \"\"\""},{"line_number":201,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"}],"source_content_type":"text/x-python","patch_set":21,"id":"197684f0_b5867912","line":198,"updated":"2026-02-03 15:28:48.000000000","message":"do this need to be repeated on the subclass?","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"2b502d8617e24424a4ac2bb164dce3e4cc7f1625","unresolved":true,"context_lines":[{"line_number":195,"context_line":"        return self.__class__((999999999999999 - self.raw) * PRECISION)"},{"line_number":196,"context_line":""},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"@functools.total_ordering"},{"line_number":199,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":200,"context_line":"    \"\"\""},{"line_number":201,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"}],"source_content_type":"text/x-python","patch_set":21,"id":"ba132612_704b7fe2","line":198,"in_reply_to":"197684f0_b5867912","updated":"2026-02-13 10:40:39.000000000","message":"apparently not","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"8c52914928ded2e95cfa5d02408405cd92995b04","unresolved":false,"context_lines":[{"line_number":195,"context_line":"        return self.__class__((999999999999999 - self.raw) * PRECISION)"},{"line_number":196,"context_line":""},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"@functools.total_ordering"},{"line_number":199,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":200,"context_line":"    \"\"\""},{"line_number":201,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"}],"source_content_type":"text/x-python","patch_set":21,"id":"269a1a2e_1910f016","line":198,"in_reply_to":"ba132612_704b7fe2","updated":"2026-02-13 15:48:34.000000000","message":"Done","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"a5472c6890c1c279417ce2e40bdc04e9286335cc","unresolved":true,"context_lines":[{"line_number":196,"context_line":""},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"@functools.total_ordering"},{"line_number":199,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":200,"context_line":"    \"\"\""},{"line_number":201,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":202,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":21,"id":"5134cd42_3378111f","line":199,"updated":"2026-02-02 05:51:04.000000000","message":"I kinda like the idea, but long term what are simple timestamps going to be used for? Shard epochs, meta?\n\nJust thinking out loud","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"572d340c845c40e8642037d5f840dce46721d3a2","unresolved":false,"context_lines":[{"line_number":196,"context_line":""},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"@functools.total_ordering"},{"line_number":199,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":200,"context_line":"    \"\"\""},{"line_number":201,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":202,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":21,"id":"77c38c47_17ca1bc7","line":199,"in_reply_to":"2e133f8f_5df727f4","updated":"2026-02-13 06:56:37.000000000","message":"Acknowledged","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"b1f6423916fc6c6b1e98409ba3263f36e32e56fe","unresolved":true,"context_lines":[{"line_number":196,"context_line":""},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"@functools.total_ordering"},{"line_number":199,"context_line":"class SimpleTimestamp(BaseTimestamp):"},{"line_number":200,"context_line":"    \"\"\""},{"line_number":201,"context_line":"    A SimpleTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":202,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":21,"id":"2e133f8f_5df727f4","line":199,"in_reply_to":"5134cd42_3378111f","updated":"2026-02-03 15:28:48.000000000","message":"I have used them for ALL shard range timestamps, but epoch is the critical one because it ends up determining the container db name that we mustn\u0027t change.\n\nI went for making ALL the shard range timestamps be SimpleTimestamps for consistency - having a mix just begs the question why? But it was more churn :/","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"a5472c6890c1c279417ce2e40bdc04e9286335cc","unresolved":true,"context_lines":[{"line_number":346,"context_line":"            raise ValueError(\u0027Cannot invert timestamps with offsets\u0027)"},{"line_number":347,"context_line":"        return super().__invert__()"},{"line_number":348,"context_line":""},{"line_number":349,"context_line":"    def simplify(self):"},{"line_number":350,"context_line":"        \"\"\""},{"line_number":351,"context_line":"        Get a simplified version of this Timestamp absent any offset or jitter"},{"line_number":352,"context_line":"        components."}],"source_content_type":"text/x-python","patch_set":21,"id":"db1c7ec5_809db62a","line":349,"updated":"2026-02-02 05:51:04.000000000","message":"This is pretty cool","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"572d340c845c40e8642037d5f840dce46721d3a2","unresolved":false,"context_lines":[{"line_number":346,"context_line":"            raise ValueError(\u0027Cannot invert timestamps with offsets\u0027)"},{"line_number":347,"context_line":"        return super().__invert__()"},{"line_number":348,"context_line":""},{"line_number":349,"context_line":"    def simplify(self):"},{"line_number":350,"context_line":"        \"\"\""},{"line_number":351,"context_line":"        Get a simplified version of this Timestamp absent any offset or jitter"},{"line_number":352,"context_line":"        components."}],"source_content_type":"text/x-python","patch_set":21,"id":"0541bae7_3c4c77ff","line":349,"in_reply_to":"a29c3495_df3c3d92","updated":"2026-02-13 06:56:37.000000000","message":"Acknowledged","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"b1f6423916fc6c6b1e98409ba3263f36e32e56fe","unresolved":true,"context_lines":[{"line_number":346,"context_line":"            raise ValueError(\u0027Cannot invert timestamps with offsets\u0027)"},{"line_number":347,"context_line":"        return super().__invert__()"},{"line_number":348,"context_line":""},{"line_number":349,"context_line":"    def simplify(self):"},{"line_number":350,"context_line":"        \"\"\""},{"line_number":351,"context_line":"        Get a simplified version of this Timestamp absent any offset or jitter"},{"line_number":352,"context_line":"        components."}],"source_content_type":"text/x-python","patch_set":21,"id":"a29c3495_df3c3d92","line":349,"in_reply_to":"db1c7ec5_809db62a","updated":"2026-02-03 15:28:48.000000000","message":"I ended up needing to change this in the next patch, IIRC so that tests that assert the timestamp type would be consistent for object PUTs and POSTs etc","commit_id":"c12de992b0bdf36e3fc2ca3fb6b828fc0f2cdd69"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":true,"context_lines":[{"line_number":80,"context_line":"    def __repr__(self):"},{"line_number":81,"context_line":"        return self.normal"},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"    # TODO: do we need to be so brittle on the base class?"},{"line_number":84,"context_line":"    def __str__(self):"},{"line_number":85,"context_line":"        raise TypeError(\u0027You must specify which string format is required\u0027)"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"a8e993d4_6d73ecb6","line":83,"updated":"2026-02-19 06:22:12.000000000","message":"I\u0027d think this should just default to ts.normal, ie the string representation. Then we don\u0027t need to override this in NormalTimestamp. Especially because we can\u0027t provide a format\n\nWhen we get to Timestamp, we either add the TypeError or default to ts.internal and allow an option to specify the format.","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"83ba7f3d242a9e8612aab1c2549ada7eb5149402","unresolved":true,"context_lines":[{"line_number":80,"context_line":"    def __repr__(self):"},{"line_number":81,"context_line":"        return self.normal"},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"    # TODO: do we need to be so brittle on the base class?"},{"line_number":84,"context_line":"    def __str__(self):"},{"line_number":85,"context_line":"        raise TypeError(\u0027You must specify which string format is required\u0027)"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"a93e0bde_269eb5b1","line":83,"in_reply_to":"1b71aee9_cc0c8fda","updated":"2026-03-11 22:46:42.000000000","message":"heh, I had the same question!\n\nfor a NormalTimestamp instance `n` the choice of `n.normal` and `n.internal` is meaningless; it might be perfectly reasonable for `NormalTimestamp.__str__` to return `self.normal` and maybe even `Timestamp.__str__` to return `self.internal`\n\n... but for now I think I\u0027m ok with maintaining this behavior in the base class?","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1a6e80757476af569a8bced393bd8dcb3affbfc8","unresolved":true,"context_lines":[{"line_number":80,"context_line":"    def __repr__(self):"},{"line_number":81,"context_line":"        return self.normal"},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"    # TODO: do we need to be so brittle on the base class?"},{"line_number":84,"context_line":"    def __str__(self):"},{"line_number":85,"context_line":"        raise TypeError(\u0027You must specify which string format is required\u0027)"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"1b71aee9_cc0c8fda","line":83,"in_reply_to":"59608bdb_f30ac755","updated":"2026-03-02 16:19:44.000000000","message":"https://review.opendev.org/c/openstack/swift/+/977330?usp\u003demail","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":true,"context_lines":[{"line_number":80,"context_line":"    def __repr__(self):"},{"line_number":81,"context_line":"        return self.normal"},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"    # TODO: do we need to be so brittle on the base class?"},{"line_number":84,"context_line":"    def __str__(self):"},{"line_number":85,"context_line":"        raise TypeError(\u0027You must specify which string format is required\u0027)"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"59608bdb_f30ac755","line":83,"in_reply_to":"a8e993d4_6d73ecb6","updated":"2026-02-19 14:46:16.000000000","message":"I want to do this but I am concerned that in the same way we have internal on the base class so that callers don\u0027t need to know which type they have, we also should NOT have __str__ because then a caller could use str(ts) with a NormalTimestamp but it will blow up with a Timestamp??\n\nmaybe I am fretting too much.\n\nI\u0027ll put it in a follow-on patch","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    def __repr__(self):"},{"line_number":81,"context_line":"        return self.normal"},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"    # TODO: do we need to be so brittle on the base class?"},{"line_number":84,"context_line":"    def __str__(self):"},{"line_number":85,"context_line":"        raise TypeError(\u0027You must specify which string format is required\u0027)"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"2a06a9a9_eda07b8f","line":83,"in_reply_to":"a93e0bde_269eb5b1","updated":"2026-04-15 14:23:58.000000000","message":"Having lived with this for a while... we know that there are cases where the type of a timestamp may change from NormalTimestamp to Timestamp in the future. When that happens it would be unfortunate to have code that blows up because it was using str(timestamp) that no longer works when handed a Timestamp instance. So I am inclined to leave this prohibition.\n\nPerhaps with hindsight we\u0027d have made ``str \u003d internal``, and provided ``normal`` for the exceptional use cases that want an abbreviated form.","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":true,"context_lines":[{"line_number":209,"context_line":"        return self.__class__((999999999999999 - self.raw) * PRECISION)"},{"line_number":210,"context_line":""},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"class NormalTimestamp(BaseTimestamp):"},{"line_number":213,"context_line":"    \"\"\""},{"line_number":214,"context_line":"    A NormalTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":215,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":27,"id":"68bdc9e3_19d36781","line":212,"updated":"2026-02-19 06:22:12.000000000","message":"A timestamp that only represents a `.normal`. Yeah that\u0027s more descriptive then simple. Kudos.","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":209,"context_line":"        return self.__class__((999999999999999 - self.raw) * PRECISION)"},{"line_number":210,"context_line":""},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"class NormalTimestamp(BaseTimestamp):"},{"line_number":213,"context_line":"    \"\"\""},{"line_number":214,"context_line":"    A NormalTimestamp encapsulates a timestamp rounded to the nearest"},{"line_number":215,"context_line":"    deca-microsecond."}],"source_content_type":"text/x-python","patch_set":27,"id":"f4a644b6_1a613fbd","line":212,"in_reply_to":"68bdc9e3_19d36781","updated":"2026-02-19 14:46:16.000000000","message":"Acknowledged","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e3bbfd83d964c254d91a6ba76e1bff0b8c1a47b2","unresolved":true,"context_lines":[{"line_number":230,"context_line":"        except ValueError:"},{"line_number":231,"context_line":"            raise TypeError("},{"line_number":232,"context_line":"                \"\u0027\u003e\u0027 not supported between instances of %r and %r\" %"},{"line_number":233,"context_line":"                (type(self).__name__, type(other).__name__))"},{"line_number":234,"context_line":"        if other_ts.timestamp \u003c 0:"},{"line_number":235,"context_line":"            return False"},{"line_number":236,"context_line":"        if other_ts.timestamp \u003e\u003d 10000000000:"}],"source_content_type":"text/x-python","patch_set":34,"id":"bda224bc_41caa00d","line":233,"updated":"2026-02-26 18:07:11.000000000","message":"Jianjian told me that I can just return NotImplemented here","commit_id":"c8343131b0d830f5be20c6a6ae21267ecfa93d7d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1a6e80757476af569a8bced393bd8dcb3affbfc8","unresolved":false,"context_lines":[{"line_number":230,"context_line":"        except ValueError:"},{"line_number":231,"context_line":"            raise TypeError("},{"line_number":232,"context_line":"                \"\u0027\u003e\u0027 not supported between instances of %r and %r\" %"},{"line_number":233,"context_line":"                (type(self).__name__, type(other).__name__))"},{"line_number":234,"context_line":"        if other_ts.timestamp \u003c 0:"},{"line_number":235,"context_line":"            return False"},{"line_number":236,"context_line":"        if other_ts.timestamp \u003e\u003d 10000000000:"}],"source_content_type":"text/x-python","patch_set":34,"id":"6566cd4f_1eae4939","line":233,"in_reply_to":"bda224bc_41caa00d","updated":"2026-03-02 16:19:44.000000000","message":"Done","commit_id":"c8343131b0d830f5be20c6a6ae21267ecfa93d7d"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"f48936d48919e0c678b9a5fee1ad804dcaf72e68","unresolved":true,"context_lines":[{"line_number":260,"context_line":"        \"\"\""},{"line_number":261,"context_line":"        Create a new NormalTimestamp."},{"line_number":262,"context_line":""},{"line_number":263,"context_line":"        :param timestamp: time in seconds since the Epoch, may be any of:"},{"line_number":264,"context_line":""},{"line_number":265,"context_line":"            * a float or integer"},{"line_number":266,"context_line":"            * a string or bytes representation of a float that must not contain"}],"source_content_type":"text/x-python","patch_set":48,"id":"2519722d_8b67ae93","line":263,"updated":"2026-04-13 02:59:41.000000000","message":"should we move the docstring of ``timestamp``,``delta``, and ``check_bounds`` to be within ``BaseTimestamp``?","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":260,"context_line":"        \"\"\""},{"line_number":261,"context_line":"        Create a new NormalTimestamp."},{"line_number":262,"context_line":""},{"line_number":263,"context_line":"        :param timestamp: time in seconds since the Epoch, may be any of:"},{"line_number":264,"context_line":""},{"line_number":265,"context_line":"            * a float or integer"},{"line_number":266,"context_line":"            * a string or bytes representation of a float that must not contain"}],"source_content_type":"text/x-python","patch_set":48,"id":"b92d8e61_f2df4672","line":263,"in_reply_to":"2519722d_8b67ae93","updated":"2026-04-15 14:23:58.000000000","message":"I wasn\u0027t not sure how to write the docstring in the BaseTimestamp because for ``timestamp`` it is specific to the subclass. I\u0027ll try an we can see what we think.\n\nAlso, BaseTimestamp.__init__ cannot be called directly so perhaps doesn\u0027t need to be documented in addition to the concrete subclass constructors.","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"37bc60e79489953e9ba47e2267406af4798cb835","unresolved":false,"context_lines":[{"line_number":260,"context_line":"        \"\"\""},{"line_number":261,"context_line":"        Create a new NormalTimestamp."},{"line_number":262,"context_line":""},{"line_number":263,"context_line":"        :param timestamp: time in seconds since the Epoch, may be any of:"},{"line_number":264,"context_line":""},{"line_number":265,"context_line":"            * a float or integer"},{"line_number":266,"context_line":"            * a string or bytes representation of a float that must not contain"}],"source_content_type":"text/x-python","patch_set":48,"id":"f3df9567_fd15888c","line":263,"in_reply_to":"b92d8e61_f2df4672","updated":"2026-04-17 00:27:26.000000000","message":"new docstring looks great!","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"f48936d48919e0c678b9a5fee1ad804dcaf72e68","unresolved":true,"context_lines":[{"line_number":266,"context_line":"            * a string or bytes representation of a float that must not contain"},{"line_number":267,"context_line":"              underscores"},{"line_number":268,"context_line":"            * any other type that can be cast to a float including another"},{"line_number":269,"context_line":"            * instance of BaseTimestamp"},{"line_number":270,"context_line":""},{"line_number":271,"context_line":"        :param delta: (int) deca-microsecond difference to be added to the"},{"line_number":272,"context_line":"            ``timestamp`` value."}],"source_content_type":"text/x-python","patch_set":48,"id":"aeea28df_d66b4064","line":269,"updated":"2026-04-13 02:59:41.000000000","message":"nit: remove the ``*``","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":false,"context_lines":[{"line_number":266,"context_line":"            * a string or bytes representation of a float that must not contain"},{"line_number":267,"context_line":"              underscores"},{"line_number":268,"context_line":"            * any other type that can be cast to a float including another"},{"line_number":269,"context_line":"            * instance of BaseTimestamp"},{"line_number":270,"context_line":""},{"line_number":271,"context_line":"        :param delta: (int) deca-microsecond difference to be added to the"},{"line_number":272,"context_line":"            ``timestamp`` value."}],"source_content_type":"text/x-python","patch_set":48,"id":"39cfefea_896e20aa","line":269,"in_reply_to":"aeea28df_d66b4064","updated":"2026-04-15 14:23:58.000000000","message":"Done","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":266,"context_line":"            * a string or bytes representation of a float that must not contain"},{"line_number":267,"context_line":"              underscores"},{"line_number":268,"context_line":"            * any other type that can be cast to a float including another"},{"line_number":269,"context_line":"            * instance of BaseTimestamp"},{"line_number":270,"context_line":""},{"line_number":271,"context_line":"        :param delta: (int) deca-microsecond difference to be added to the"},{"line_number":272,"context_line":"            ``timestamp`` value."}],"source_content_type":"text/x-python","patch_set":50,"id":"8ee4e3af_12ff3806","line":269,"range":{"start_line":269,"start_character":14,"end_line":269,"end_character":39},"updated":"2026-04-15 14:23:58.000000000","message":"this isn\u0027t true: you cannot construct a NormalTimestamp using a Timestamp-with-jitter","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"9c8423858953192777b7b9e1269ff8c67798b2ec","unresolved":false,"context_lines":[{"line_number":266,"context_line":"            * a string or bytes representation of a float that must not contain"},{"line_number":267,"context_line":"              underscores"},{"line_number":268,"context_line":"            * any other type that can be cast to a float including another"},{"line_number":269,"context_line":"            * instance of BaseTimestamp"},{"line_number":270,"context_line":""},{"line_number":271,"context_line":"        :param delta: (int) deca-microsecond difference to be added to the"},{"line_number":272,"context_line":"            ``timestamp`` value."}],"source_content_type":"text/x-python","patch_set":50,"id":"a7d24270_31c29bf0","line":269,"range":{"start_line":269,"start_character":14,"end_line":269,"end_character":39},"in_reply_to":"8ee4e3af_12ff3806","updated":"2026-04-20 11:40:10.000000000","message":"Done","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"}],"swift/container/backend.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"f48936d48919e0c678b9a5fee1ad804dcaf72e68","unresolved":true,"context_lines":[{"line_number":2070,"context_line":"        Updates this broker\u0027s own shard range with the given epoch, sets its"},{"line_number":2071,"context_line":"        state to SHARDING and persists it in the DB."},{"line_number":2072,"context_line":""},{"line_number":2073,"context_line":"        :param epoch: a :class:`~swift.utils.common.NormalTimestamp`"},{"line_number":2074,"context_line":"        :return: the broker\u0027s updated own shard range."},{"line_number":2075,"context_line":"        \"\"\""},{"line_number":2076,"context_line":"        own_shard_range \u003d self.get_own_shard_range()"}],"source_content_type":"text/x-python","patch_set":48,"id":"fc4153a2_432106f5","line":2073,"updated":"2026-04-13 02:59:41.000000000","message":"nit: a wrong path, it should be ``~swift.common.utils.timestamp.NormalTimestamp``","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":false,"context_lines":[{"line_number":2070,"context_line":"        Updates this broker\u0027s own shard range with the given epoch, sets its"},{"line_number":2071,"context_line":"        state to SHARDING and persists it in the DB."},{"line_number":2072,"context_line":""},{"line_number":2073,"context_line":"        :param epoch: a :class:`~swift.utils.common.NormalTimestamp`"},{"line_number":2074,"context_line":"        :return: the broker\u0027s updated own shard range."},{"line_number":2075,"context_line":"        \"\"\""},{"line_number":2076,"context_line":"        own_shard_range \u003d self.get_own_shard_range()"}],"source_content_type":"text/x-python","patch_set":48,"id":"9bac548f_93247b87","line":2073,"in_reply_to":"fc4153a2_432106f5","updated":"2026-04-15 14:23:58.000000000","message":"Done","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"}],"swift/container/replicator.py":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"64fba0d90b3e7f669a54fcaa4c6e5e2628b0aa90","unresolved":true,"context_lines":[{"line_number":32,"context_line":"from swift.common.swob import HTTPOk, HTTPAccepted"},{"line_number":33,"context_line":"from swift.common.http import is_success"},{"line_number":34,"context_line":"from swift.common.utils import majority_size, get_db_files, parse_options, \\"},{"line_number":35,"context_line":"    node_to_string, NormalTimestamp"},{"line_number":36,"context_line":""},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"def check_merge_own_shard_range(shards, broker, logger, source):"}],"source_content_type":"text/x-python","patch_set":50,"id":"f28748ee_b5484475","line":35,"updated":"2026-04-15 05:39:11.000000000","message":"from swift.common.utils.timestamp import NormalTimestamp","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":false,"context_lines":[{"line_number":32,"context_line":"from swift.common.swob import HTTPOk, HTTPAccepted"},{"line_number":33,"context_line":"from swift.common.http import is_success"},{"line_number":34,"context_line":"from swift.common.utils import majority_size, get_db_files, parse_options, \\"},{"line_number":35,"context_line":"    node_to_string, NormalTimestamp"},{"line_number":36,"context_line":""},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"def check_merge_own_shard_range(shards, broker, logger, source):"}],"source_content_type":"text/x-python","patch_set":50,"id":"5408f94e_bfd4e24a","line":35,"in_reply_to":"f28748ee_b5484475","updated":"2026-04-15 14:23:58.000000000","message":"Done","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"}],"swift/container/server.py":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"64fba0d90b3e7f669a54fcaa4c6e5e2628b0aa90","unresolved":true,"context_lines":[{"line_number":462,"context_line":"                # the original request may have been an object update with"},{"line_number":463,"context_line":"                # a hex part in the timestamp which we want to remove for the"},{"line_number":464,"context_line":"                # container timestamp"},{"line_number":465,"context_line":"                req_timestamp \u003d req_timestamp.normalized()"},{"line_number":466,"context_line":"                broker.initialize(req_timestamp.internal, policy_index)"},{"line_number":467,"context_line":"            except DatabaseAlreadyExists:"},{"line_number":468,"context_line":"                pass"}],"source_content_type":"text/x-python","patch_set":50,"id":"3988d50c_dc050e18","line":465,"updated":"2026-04-15 05:39:11.000000000","message":"normalized is only a method on Timestamp, so this will ALWAYS need to be an instance of a Timestamp. A req_timestamp should be in my opinion, so probably a moot point. Just just to be aware.","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"9c8423858953192777b7b9e1269ff8c67798b2ec","unresolved":false,"context_lines":[{"line_number":462,"context_line":"                # the original request may have been an object update with"},{"line_number":463,"context_line":"                # a hex part in the timestamp which we want to remove for the"},{"line_number":464,"context_line":"                # container timestamp"},{"line_number":465,"context_line":"                req_timestamp \u003d req_timestamp.normalized()"},{"line_number":466,"context_line":"                broker.initialize(req_timestamp.internal, policy_index)"},{"line_number":467,"context_line":"            except DatabaseAlreadyExists:"},{"line_number":468,"context_line":"                pass"}],"source_content_type":"text/x-python","patch_set":50,"id":"c10d04fd_0b87c4b7","line":465,"in_reply_to":"046d0bb8_82f6cc8c","updated":"2026-04-20 11:40:10.000000000","message":"Acknowledged","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"bf837843df5c9b581d833b3a385dbea0bd74c1a0","unresolved":true,"context_lines":[{"line_number":462,"context_line":"                # the original request may have been an object update with"},{"line_number":463,"context_line":"                # a hex part in the timestamp which we want to remove for the"},{"line_number":464,"context_line":"                # container timestamp"},{"line_number":465,"context_line":"                req_timestamp \u003d req_timestamp.normalized()"},{"line_number":466,"context_line":"                broker.initialize(req_timestamp.internal, policy_index)"},{"line_number":467,"context_line":"            except DatabaseAlreadyExists:"},{"line_number":468,"context_line":"                pass"}],"source_content_type":"text/x-python","patch_set":50,"id":"046d0bb8_82f6cc8c","line":465,"in_reply_to":"16bada83_6d536c68","updated":"2026-04-16 09:31:52.000000000","message":"\u003e this is also to stop bleeding jitter into the containers\nYes. AFAIK there is no problem having jitter in container resource requests, but we\u0027ve chosen not to do that yet in the proxy so makes sense to keep things consistent here.\n\nhmmm, strictly this change probably isn\u0027t needed until the jitter patch.","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":462,"context_line":"                # the original request may have been an object update with"},{"line_number":463,"context_line":"                # a hex part in the timestamp which we want to remove for the"},{"line_number":464,"context_line":"                # container timestamp"},{"line_number":465,"context_line":"                req_timestamp \u003d req_timestamp.normalized()"},{"line_number":466,"context_line":"                broker.initialize(req_timestamp.internal, policy_index)"},{"line_number":467,"context_line":"            except DatabaseAlreadyExists:"},{"line_number":468,"context_line":"                pass"}],"source_content_type":"text/x-python","patch_set":50,"id":"a6135be2_84cc341e","line":465,"in_reply_to":"3988d50c_dc050e18","updated":"2026-04-15 14:23:58.000000000","message":"``req_timestamp`` is always the return value from ``valid_timestamp`` which gets ``swob.Request.timestamp`` which is a ``Timestamp``\n\nBut, I do wonder if in general we should NOT be mixing NormalTimestamps and Timestamps when we are dealing with requests, to avoid this kind of potential interface mis-expectation. Now that Timestamps do not have jitter by default we could just use them as before???","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"26342b50f5cb0d1ecb2e88d3ff2963a9fd6a7ff2","unresolved":true,"context_lines":[{"line_number":462,"context_line":"                # the original request may have been an object update with"},{"line_number":463,"context_line":"                # a hex part in the timestamp which we want to remove for the"},{"line_number":464,"context_line":"                # container timestamp"},{"line_number":465,"context_line":"                req_timestamp \u003d req_timestamp.normalized()"},{"line_number":466,"context_line":"                broker.initialize(req_timestamp.internal, policy_index)"},{"line_number":467,"context_line":"            except DatabaseAlreadyExists:"},{"line_number":468,"context_line":"                pass"}],"source_content_type":"text/x-python","patch_set":50,"id":"16bada83_6d536c68","line":465,"in_reply_to":"a6135be2_84cc341e","updated":"2026-04-15 22:58:05.000000000","message":"I asusme this is also to stop bleeding jitter into the containers until we\u0027re ready for them everywhere, but in reality containers should start using ts references too, so eitherway, this seems like something we may remove soonish anyway.","commit_id":"2710b1ff9fc434b41f2d8427e864451bd2c064d7"}],"swift/container/sharder.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8b66979c2fde91de26ff0ce633811ef228046d51","unresolved":true,"context_lines":[{"line_number":1038,"context_line":""},{"line_number":1039,"context_line":"        if latest_context:"},{"line_number":1040,"context_line":"            info[\"total_replicate_time\"] \u003d latest_context[0].replication_time"},{"line_number":1041,"context_line":"            sharding_total_elapsed \u003d (float(latest_context_ts)"},{"line_number":1042,"context_line":"                                      - float(own_shard_range.epoch))"},{"line_number":1043,"context_line":"            info[\u0027total_sharding_time\u0027] \u003d sharding_total_elapsed"},{"line_number":1044,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"c15672b9_725eff89","line":1041,"updated":"2025-12-23 05:53:53.000000000","message":"this is an example we calculate the difference between a Timestamp and SimpleTimestamp","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":1038,"context_line":""},{"line_number":1039,"context_line":"        if latest_context:"},{"line_number":1040,"context_line":"            info[\"total_replicate_time\"] \u003d latest_context[0].replication_time"},{"line_number":1041,"context_line":"            sharding_total_elapsed \u003d (float(latest_context_ts)"},{"line_number":1042,"context_line":"                                      - float(own_shard_range.epoch))"},{"line_number":1043,"context_line":"            info[\u0027total_sharding_time\u0027] \u003d sharding_total_elapsed"},{"line_number":1044,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"7e1bb815_1f175538","line":1041,"in_reply_to":"87fc366b_c930fb4b","updated":"2026-02-19 14:46:16.000000000","message":"Done","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":true,"context_lines":[{"line_number":1038,"context_line":""},{"line_number":1039,"context_line":"        if latest_context:"},{"line_number":1040,"context_line":"            info[\"total_replicate_time\"] \u003d latest_context[0].replication_time"},{"line_number":1041,"context_line":"            sharding_total_elapsed \u003d (float(latest_context_ts)"},{"line_number":1042,"context_line":"                                      - float(own_shard_range.epoch))"},{"line_number":1043,"context_line":"            info[\u0027total_sharding_time\u0027] \u003d sharding_total_elapsed"},{"line_number":1044,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"87fc366b_c930fb4b","line":1041,"in_reply_to":"c15672b9_725eff89","updated":"2025-12-23 12:37:13.000000000","message":"I\u0027m not sure I understand the concern? Maybe we should discuss so I can understand better.\n\nTimestamps do not support arithmetic operations, so get time differences we have to cast to floats, and accept that any offset (or in the future, jitter) will be lost.","commit_id":"de2ad1c2885dc0548755ab16cbe4f20b8422b432"}],"swift/obj/expirer.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"f48936d48919e0c678b9a5fee1ad804dcaf72e68","unresolved":true,"context_lines":[{"line_number":497,"context_line":"                continue"},{"line_number":498,"context_line":""},{"line_number":499,"context_line":"            if delete_timestamp \u003e NormalTimestamp.now("},{"line_number":500,"context_line":"                    delta\u003d-1e5 * delay_reaping) and not is_async:"},{"line_number":501,"context_line":"                # we shouldn\u0027t yield the object during the delay"},{"line_number":502,"context_line":"                self.logger.increment(\u0027tasks.delayed\u0027)"},{"line_number":503,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":48,"id":"aa8285c2_32376380","line":500,"updated":"2026-04-13 02:59:41.000000000","message":"delta is an integer by definition, but ``-1e5 * delay_reaping`` is a float.\n```\n        :param delta: (int) deca-microsecond difference to be added to the\n            ``timestamp`` value.\n```\n\n``delay_reaping`` is in seconds, so technically there won\u0027t be any precision loss. However, it would be type correct to change to ``delta\u003dint(-1e5 * delay_reaping)``, because ``self.raw \u003d self.raw + delta`` in BaseTimestamp constructor will have ``self.raw`` become a float instead of integer.","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"37bc60e79489953e9ba47e2267406af4798cb835","unresolved":false,"context_lines":[{"line_number":497,"context_line":"                continue"},{"line_number":498,"context_line":""},{"line_number":499,"context_line":"            if delete_timestamp \u003e NormalTimestamp.now("},{"line_number":500,"context_line":"                    delta\u003d-1e5 * delay_reaping) and not is_async:"},{"line_number":501,"context_line":"                # we shouldn\u0027t yield the object during the delay"},{"line_number":502,"context_line":"                self.logger.increment(\u0027tasks.delayed\u0027)"},{"line_number":503,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":48,"id":"f953733e_ced26c1c","line":500,"in_reply_to":"2e00fc87_73039af3","updated":"2026-04-17 00:27:26.000000000","message":"Done","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":497,"context_line":"                continue"},{"line_number":498,"context_line":""},{"line_number":499,"context_line":"            if delete_timestamp \u003e NormalTimestamp.now("},{"line_number":500,"context_line":"                    delta\u003d-1e5 * delay_reaping) and not is_async:"},{"line_number":501,"context_line":"                # we shouldn\u0027t yield the object during the delay"},{"line_number":502,"context_line":"                self.logger.increment(\u0027tasks.delayed\u0027)"},{"line_number":503,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":48,"id":"2e00fc87_73039af3","line":500,"in_reply_to":"aa8285c2_32376380","updated":"2026-04-15 14:23:58.000000000","message":"good catch!\n\nI\u0027d really like to move away from using the ``__init__(float)`` constructor, so I am going to fix this as suggested. Note that delay_reaping can be a float.\n\nHowever, I think a better solution would be 984723: timestamp: round delta to nearest int | https://review.opendev.org/c/openstack/swift/+/984723","commit_id":"fa792e5ad5eec34d69c624136d995c5f9ff689b1"}],"test/unit/__init__.py":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":true,"context_lines":[{"line_number":75,"context_line":""},{"line_number":76,"context_line":"        :return: an instance of NormalTimestamp"},{"line_number":77,"context_line":"        \"\"\""},{"line_number":78,"context_line":"        return next(self.normal_ts_iter)"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"# try not to import this module from swift"}],"source_content_type":"text/x-python","patch_set":27,"id":"d496806a_970dd014","line":78,"updated":"2026-02-19 06:22:12.000000000","message":"Should this patch place the `def ts(self)` because we place this one here now. The next patch adds the ts.. I guess it can wait until we use the method (which is the next one).","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":75,"context_line":""},{"line_number":76,"context_line":"        :return: an instance of NormalTimestamp"},{"line_number":77,"context_line":"        \"\"\""},{"line_number":78,"context_line":"        return next(self.normal_ts_iter)"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"# try not to import this module from swift"}],"source_content_type":"text/x-python","patch_set":27,"id":"f0ffe42d_8de1f579","line":78,"in_reply_to":"d496806a_970dd014","updated":"2026-02-19 14:46:16.000000000","message":"``ts`` is on master now 😊","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":true,"context_lines":[{"line_number":1160,"context_line":"@contextmanager"},{"line_number":1161,"context_line":"def mock_timestamp_now_with_iter(ts_iter):"},{"line_number":1162,"context_line":"    with mocklib.patch(\u0027swift.common.utils.timestamp.BaseTimestamp.now\u0027,"},{"line_number":1163,"context_line":"                       side_effect\u003dts_iter):"},{"line_number":1164,"context_line":"        yield"},{"line_number":1165,"context_line":""},{"line_number":1166,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"82a90986_7a22c8cd","line":1163,"updated":"2026-02-19 06:22:12.000000000","message":"Does this work with Timestamp classes? As they override the BaseTimestamp classes now function and don\u0027t call super?\n\nUpdate: Nope it doesn\u0027t\n\nSeems this is only used in sharding tests, but the name seems incorrect. We should change this name to `mock_normal_timestamp_now_with_iter`","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":1160,"context_line":"@contextmanager"},{"line_number":1161,"context_line":"def mock_timestamp_now_with_iter(ts_iter):"},{"line_number":1162,"context_line":"    with mocklib.patch(\u0027swift.common.utils.timestamp.BaseTimestamp.now\u0027,"},{"line_number":1163,"context_line":"                       side_effect\u003dts_iter):"},{"line_number":1164,"context_line":"        yield"},{"line_number":1165,"context_line":""},{"line_number":1166,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"66960b15_17aef30e","line":1163,"in_reply_to":"82a90986_7a22c8cd","updated":"2026-02-19 14:46:16.000000000","message":"eek! good catch","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"83ba7f3d242a9e8612aab1c2549ada7eb5149402","unresolved":true,"context_lines":[{"line_number":1154,"context_line":"    if now is None:"},{"line_number":1155,"context_line":"        now \u003d klass.now()"},{"line_number":1156,"context_line":"    with mocklib.patch.object("},{"line_number":1157,"context_line":"            klass, \u0027now\u0027, classmethod(lambda *args, **kwargs: now)):"},{"line_number":1158,"context_line":"        yield now"},{"line_number":1159,"context_line":""},{"line_number":1160,"context_line":""}],"source_content_type":"text/x-python","patch_set":41,"id":"1cdbace5_c67d80fa","line":1157,"updated":"2026-03-11 22:46:42.000000000","message":"do we want to support the `klass` kwarg now that we have `mock_normal_timestamp_now` ???\n\nI guess this has something to do with `klass\u003dS3Timestamp` 😕\n\nhttps://review.opendev.org/c/openstack/swift/+/839975/5/test/unit/__init__.py","commit_id":"26432faab511caaa3a7b4ad12c13ea69e17d7b0a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":1154,"context_line":"    if now is None:"},{"line_number":1155,"context_line":"        now \u003d klass.now()"},{"line_number":1156,"context_line":"    with mocklib.patch.object("},{"line_number":1157,"context_line":"            klass, \u0027now\u0027, classmethod(lambda *args, **kwargs: now)):"},{"line_number":1158,"context_line":"        yield now"},{"line_number":1159,"context_line":""},{"line_number":1160,"context_line":""}],"source_content_type":"text/x-python","patch_set":41,"id":"43d20018_0415d94f","line":1157,"in_reply_to":"1cdbace5_c67d80fa","updated":"2026-04-15 14:23:58.000000000","message":"looks like we\u0027ve stooped using klass with 973272: s3api: do not set x-timestamp header | https://review.opendev.org/c/openstack/swift/+/973272 so yeah let\u0027s ditch it","commit_id":"26432faab511caaa3a7b4ad12c13ea69e17d7b0a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"83ba7f3d242a9e8612aab1c2549ada7eb5149402","unresolved":true,"context_lines":[{"line_number":1164,"context_line":"        now \u003d NormalTimestamp.now()"},{"line_number":1165,"context_line":"    with mocklib.patch.object("},{"line_number":1166,"context_line":"            NormalTimestamp, \u0027now\u0027, classmethod(lambda *args, **kwargs: now)):"},{"line_number":1167,"context_line":"        yield now"},{"line_number":1168,"context_line":""},{"line_number":1169,"context_line":""},{"line_number":1170,"context_line":"@contextmanager"}],"source_content_type":"text/x-python","patch_set":41,"id":"ad3d617d_b5efe340","line":1167,"updated":"2026-03-11 22:46:42.000000000","message":"do we want to rephrase this as:\n\n```\nwith mock_timestamp_now(now, klass\u003dNormalTimestamp):\n    yield now\n```","commit_id":"26432faab511caaa3a7b4ad12c13ea69e17d7b0a"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"64fba0d90b3e7f669a54fcaa4c6e5e2628b0aa90","unresolved":true,"context_lines":[{"line_number":1164,"context_line":"        now \u003d NormalTimestamp.now()"},{"line_number":1165,"context_line":"    with mocklib.patch.object("},{"line_number":1166,"context_line":"            NormalTimestamp, \u0027now\u0027, classmethod(lambda *args, **kwargs: now)):"},{"line_number":1167,"context_line":"        yield now"},{"line_number":1168,"context_line":""},{"line_number":1169,"context_line":""},{"line_number":1170,"context_line":"@contextmanager"}],"source_content_type":"text/x-python","patch_set":41,"id":"da33725f_e536c096","line":1167,"in_reply_to":"ad3d617d_b5efe340","updated":"2026-04-15 05:39:11.000000000","message":"ohh nice, I like Clay\u0027s suggestion here!","commit_id":"26432faab511caaa3a7b4ad12c13ea69e17d7b0a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ff0598f89ebbfb8df994132f6792ccf4575a785b","unresolved":true,"context_lines":[{"line_number":1164,"context_line":"        now \u003d NormalTimestamp.now()"},{"line_number":1165,"context_line":"    with mocklib.patch.object("},{"line_number":1166,"context_line":"            NormalTimestamp, \u0027now\u0027, classmethod(lambda *args, **kwargs: now)):"},{"line_number":1167,"context_line":"        yield now"},{"line_number":1168,"context_line":""},{"line_number":1169,"context_line":""},{"line_number":1170,"context_line":"@contextmanager"}],"source_content_type":"text/x-python","patch_set":41,"id":"70f61c4d_cba6a16c","line":1167,"in_reply_to":"da33725f_e536c096","updated":"2026-04-15 14:23:58.000000000","message":"we could, but I\u0027m not sure it is simpler to understand or maintain :shrug:, given that klass is actually unused at the moment and can be removed.\n\nLet me know if you feel it is worth it","commit_id":"26432faab511caaa3a7b4ad12c13ea69e17d7b0a"}],"test/unit/common/test_utils.py":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"8b74aaadcdf7621f0196b2e88621eb027e29f980","unresolved":true,"context_lines":[{"line_number":5846,"context_line":"        with self.assertRaises(ValueError):"},{"line_number":5847,"context_line":"            utils.ShardName.create(\u0027a\u0027, \u0027root\u0027, \u0027hash\u0027, \u0027bad\u0027, \u00270\u0027)"},{"line_number":5848,"context_line":"        with self.assertRaises(ValueError):"},{"line_number":5849,"context_line":"            utils.ShardName.create(\u0027a\u0027, \u0027root\u0027, None, \u00271235678\u0027, \u0027bad\u0027)"},{"line_number":5850,"context_line":""},{"line_number":5851,"context_line":""},{"line_number":5852,"context_line":"class BaseNamespaceShardRange(object):"}],"source_content_type":"text/x-python","patch_set":27,"id":"88f0c083_873bf571","line":5849,"updated":"2026-02-19 06:22:12.000000000","message":"We should add a test using the wrong Timestamp:\n```\ndiff --git i/test/unit/common/test_utils.py w/test/unit/common/test_utils.py\nindex 38e776dc5..3c4ced2b1 100644\n--- i/test/unit/common/test_utils.py\n+++ w/test/unit/common/test_utils.py\n@@ -68,7 +68,7 @@ from swift.common.exceptions import Timeout, LockTimeout, \\\n from swift.common import utils\n from swift.common.utils import set_swift_dir, md5, ShardRangeList, \\\n     CooperativeCachePopulator\n-from swift.common.utils.timestamp import NormalTimestamp\n+from swift.common.utils.timestamp import NormalTimestamp, Timestamp\n from swift.common.container_sync_realms import ContainerSyncRealms\n from swift.common.header_key_dict import HeaderKeyDict\n from swift.common.storage_policy import POLICIES, reload_storage_policies\n@@ -5847,6 +5847,9 @@ class TestShardName(unittest.TestCase):\n             utils.ShardName.create(\u0027a\u0027, \u0027root\u0027, \u0027hash\u0027, \u0027bad\u0027, \u00270\u0027)\n         with self.assertRaises(ValueError):\n             utils.ShardName.create(\u0027a\u0027, \u0027root\u0027, None, \u00271235678\u0027, \u0027bad\u0027)\n+        with self.assertRaises(TypeError):\n+            ts \u003d Timestamp.now()\n+            utils.ShardName.create(\u0027a\u0027, \u0027root\u0027, \u0027parent\u0027, ts, 1)\n```","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1202426517992e300293be3a5a391e866c1cb7ff","unresolved":false,"context_lines":[{"line_number":5846,"context_line":"        with self.assertRaises(ValueError):"},{"line_number":5847,"context_line":"            utils.ShardName.create(\u0027a\u0027, \u0027root\u0027, \u0027hash\u0027, \u0027bad\u0027, \u00270\u0027)"},{"line_number":5848,"context_line":"        with self.assertRaises(ValueError):"},{"line_number":5849,"context_line":"            utils.ShardName.create(\u0027a\u0027, \u0027root\u0027, None, \u00271235678\u0027, \u0027bad\u0027)"},{"line_number":5850,"context_line":""},{"line_number":5851,"context_line":""},{"line_number":5852,"context_line":"class BaseNamespaceShardRange(object):"}],"source_content_type":"text/x-python","patch_set":27,"id":"5ae25439_98960d8c","line":5849,"in_reply_to":"88f0c083_873bf571","updated":"2026-02-19 14:46:16.000000000","message":"thank you!","commit_id":"2df6b46445869d551a226c9071597575ec6f1170"}],"test/unit/common/utils/test_timestamp.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4eef62170af6cb936776da6e2a730d967e924a7f","unresolved":true,"context_lines":[{"line_number":129,"context_line":"        self.assertEqual(0, ts_zero.offset)"},{"line_number":130,"context_line":"        self.assertEqual(ts_zero.internal, \u00270000000000.00000\u0027)"},{"line_number":131,"context_line":"        self.assertEqual(SimpleTimestamp.zero(), ts_zero)"},{"line_number":132,"context_line":"        ts_other \u003d timestamp.Timestamp(timestamp.Timestamp.zero())"},{"line_number":133,"context_line":"        self.assertEqual(timestamp.Timestamp.zero(), ts_other)"},{"line_number":134,"context_line":"        self.assertEqual(timestamp.Timestamp(\u00270\u0027), ts_zero)"},{"line_number":135,"context_line":"        self.assertEqual(timestamp.Timestamp(0), ts_zero)"}],"source_content_type":"text/x-python","patch_set":5,"id":"b2c22675_d32acc14","line":132,"updated":"2025-12-23 12:37:13.000000000","message":"the mix of import styles looks odd\n\ntimestamp.Timestamp vs SimpleTimestamp","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"f2713af9e0b3d6bfd3684c2a296791b75d63ddb8","unresolved":false,"context_lines":[{"line_number":129,"context_line":"        self.assertEqual(0, ts_zero.offset)"},{"line_number":130,"context_line":"        self.assertEqual(ts_zero.internal, \u00270000000000.00000\u0027)"},{"line_number":131,"context_line":"        self.assertEqual(SimpleTimestamp.zero(), ts_zero)"},{"line_number":132,"context_line":"        ts_other \u003d timestamp.Timestamp(timestamp.Timestamp.zero())"},{"line_number":133,"context_line":"        self.assertEqual(timestamp.Timestamp.zero(), ts_other)"},{"line_number":134,"context_line":"        self.assertEqual(timestamp.Timestamp(\u00270\u0027), ts_zero)"},{"line_number":135,"context_line":"        self.assertEqual(timestamp.Timestamp(0), ts_zero)"}],"source_content_type":"text/x-python","patch_set":5,"id":"0ecb345c_51dfd9ed","line":132,"in_reply_to":"b2c22675_d32acc14","updated":"2026-02-18 12:04:09.000000000","message":"Done","commit_id":"4cfae210350dcb0bf82ca2f3b4dcc23c6c3e5e9d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e3bbfd83d964c254d91a6ba76e1bff0b8c1a47b2","unresolved":true,"context_lines":[{"line_number":123,"context_line":"        self.assertGreater(ts1, \u0027-1\u0027)"},{"line_number":124,"context_line":"        self.assertGreater(ts1, \u0027-123.456_0\u0027)"},{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    def test_comparison_unsupported(self):"},{"line_number":127,"context_line":"        ts \u003d timestamp.NormalTimestamp.now()"},{"line_number":128,"context_line":"        with self.assertRaises(TypeError) as cm:"},{"line_number":129,"context_line":"            self.assertGreater(ts, True)"}],"source_content_type":"text/x-python","patch_set":34,"id":"a9adbfdc_0a7f77cd","line":126,"updated":"2026-02-26 18:07:11.000000000","message":"we need to replicate test for Timestamp","commit_id":"c8343131b0d830f5be20c6a6ae21267ecfa93d7d"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1a6e80757476af569a8bced393bd8dcb3affbfc8","unresolved":false,"context_lines":[{"line_number":123,"context_line":"        self.assertGreater(ts1, \u0027-1\u0027)"},{"line_number":124,"context_line":"        self.assertGreater(ts1, \u0027-123.456_0\u0027)"},{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    def test_comparison_unsupported(self):"},{"line_number":127,"context_line":"        ts \u003d timestamp.NormalTimestamp.now()"},{"line_number":128,"context_line":"        with self.assertRaises(TypeError) as cm:"},{"line_number":129,"context_line":"            self.assertGreater(ts, True)"}],"source_content_type":"text/x-python","patch_set":34,"id":"815b7bfb_cfcbb745","line":126,"in_reply_to":"a9adbfdc_0a7f77cd","updated":"2026-03-02 16:19:44.000000000","message":"Done","commit_id":"c8343131b0d830f5be20c6a6ae21267ecfa93d7d"}]}
