)]}'
{"swift/common/ring/builder.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2e888045b69f66e04d36d5ce8dd1d87d97f3e8a8","unresolved":false,"context_lines":[{"line_number":131,"context_line":"        # a device overrides this behavior as it\u0027s assumed that\u0027s only"},{"line_number":132,"context_line":"        # done because of device failure."},{"line_number":133,"context_line":"        self._last_part_moves \u003d array(\u0027B\u0027, itertools.repeat(0, self.parts))"},{"line_number":134,"context_line":"        self._ever_rebalanced \u003d False"},{"line_number":135,"context_line":"        # _part_moved_bitmap record parts have been moved"},{"line_number":136,"context_line":"        self._part_moved_bitmap \u003d None"},{"line_number":137,"context_line":"        # _last_part_moves_epoch indicates the time the offsets in"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_cdc58c0c","line":134,"updated":"2017-09-01 19:54:36.000000000","message":"Maybe just use self.ever_rebalanced, and drop the @property below?\n\nI guess we lose the hint that we don\u0027t expect consumers to set ever_rebalanced themselves, though... *shrug*","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2e888045b69f66e04d36d5ce8dd1d87d97f3e8a8","unresolved":false,"context_lines":[{"line_number":225,"context_line":"        b.copy_from(builder_data)"},{"line_number":226,"context_line":"        return b"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    def copy_from(self, builder):"},{"line_number":229,"context_line":"        \"\"\""},{"line_number":230,"context_line":"        Reinitializes this RingBuilder instance from data obtained from the"},{"line_number":231,"context_line":"        builder dict given. Code example::"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_75e2de03","line":228,"updated":"2017-09-01 19:54:36.000000000","message":"Should this learn about _ever_rebalanced?","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ab83a01278095265ac3a02d7d867d6e652cd3676","unresolved":false,"context_lines":[{"line_number":225,"context_line":"        b.copy_from(builder_data)"},{"line_number":226,"context_line":"        return b"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    def copy_from(self, builder):"},{"line_number":229,"context_line":"        \"\"\""},{"line_number":230,"context_line":"        Reinitializes this RingBuilder instance from data obtained from the"},{"line_number":231,"context_line":"        builder dict given. Code example::"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_b8ac40ed","line":228,"in_reply_to":"7f287b81_75e2de03","updated":"2017-09-07 13:52:00.000000000","message":"Yes, if we keep it. good catch.","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2e888045b69f66e04d36d5ce8dd1d87d97f3e8a8","unresolved":false,"context_lines":[{"line_number":283,"context_line":"    def __deepcopy__(self, memo):"},{"line_number":284,"context_line":"        return type(self).from_dict(deepcopy(self.to_dict(), memo))"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    def to_dict(self):"},{"line_number":287,"context_line":"        \"\"\""},{"line_number":288,"context_line":"        Returns a dict that can be used later with copy_from to"},{"line_number":289,"context_line":"        restore a RingBuilder. swift-ring-builder uses this to"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_d5b4f2f4","line":286,"updated":"2017-09-01 19:54:36.000000000","message":"...and this...","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2e888045b69f66e04d36d5ce8dd1d87d97f3e8a8","unresolved":false,"context_lines":[{"line_number":507,"context_line":"        old_replica2part2dev \u003d copy.deepcopy(self._replica2part2dev)"},{"line_number":508,"context_line":""},{"line_number":509,"context_line":"        if not self.ever_rebalanced:"},{"line_number":510,"context_line":"            self.logger.debug(\"New builder; performing initial balance\")"},{"line_number":511,"context_line":"        self._ever_rebalanced \u003d True"},{"line_number":512,"context_line":"        self._update_last_part_moves()"},{"line_number":513,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_f5d6ce27","line":510,"updated":"2017-09-01 19:54:36.000000000","message":"Am I right to think that this log message is the *only* reason we have self._ever_rebalanced?","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ab83a01278095265ac3a02d7d867d6e652cd3676","unresolved":false,"context_lines":[{"line_number":507,"context_line":"        old_replica2part2dev \u003d copy.deepcopy(self._replica2part2dev)"},{"line_number":508,"context_line":""},{"line_number":509,"context_line":"        if not self.ever_rebalanced:"},{"line_number":510,"context_line":"            self.logger.debug(\"New builder; performing initial balance\")"},{"line_number":511,"context_line":"        self._ever_rebalanced \u003d True"},{"line_number":512,"context_line":"        self._update_last_part_moves()"},{"line_number":513,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_02488184","line":510,"in_reply_to":"7f287b81_f5d6ce27","updated":"2017-09-07 13:52:00.000000000","message":"I think it is. hmm. I wonder if there is another way to tell that no rebalance has been performed.","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":4608,"name":"Kota Tsuyuzaki","email":"bloodeagle40234@gmail.com","username":"tsuyuzaki-kota"},"change_message_id":"9abdf2445e8681a33121adc152cc6c9c2a683e14","unresolved":false,"context_lines":[{"line_number":130,"context_line":"        # within a given number of hours (24 is my usual test). Removing"},{"line_number":131,"context_line":"        # a device overrides this behavior as it\u0027s assumed that\u0027s only"},{"line_number":132,"context_line":"        # done because of device failure."},{"line_number":133,"context_line":"        self._last_part_moves \u003d array(\u0027B\u0027, itertools.repeat(0, self.parts))"},{"line_number":134,"context_line":"        # _part_moved_bitmap record parts have been moved"},{"line_number":135,"context_line":"        self._part_moved_bitmap \u003d None"},{"line_number":136,"context_line":"        # _last_part_moves_epoch indicates the time the offsets in"}],"source_content_type":"text/x-python","patch_set":2,"id":"5f2577a7_0c2a0f7e","line":133,"updated":"2017-10-26 09:05:32.000000000","message":"Nice. I remember, I tried to make it like this in the previous change but gave up at that time.\n\nBuilding _last_part_moves at *init* should win!","commit_id":"7597c55a8a20faf0f66356550808bec619f76e93"}],"swift/common/ring/composite_builder.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2e888045b69f66e04d36d5ce8dd1d87d97f3e8a8","unresolved":false,"context_lines":[{"line_number":684,"context_line":"        # starts moving parts; this will effectively be a no-op for builders"},{"line_number":685,"context_line":"        # that have already been updated in last hour"},{"line_number":686,"context_line":"        for b in self._builders:"},{"line_number":687,"context_line":"            b.update_last_part_moves()"},{"line_number":688,"context_line":""},{"line_number":689,"context_line":""},{"line_number":690,"context_line":"class CooperativeRingBuilder(RingBuilder):"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_e8c0362d","line":687,"updated":"2017-09-01 19:54:36.000000000","message":"I\u0027m inclined to just inline this above now, since the only caller is internal and we\u0027ve reduced the crazy\n\n CompositeBuilder.rebalance -\u003e\n CooperativeBuilder.rebalance -\u003e\n CooperativeBuilder._update_last_part_moves -\u003e\n CompositeBuilder.update_last_part_moves -\u003e\n CooperativeBuilder.update_last_part_moves -\u003e\n RingBuilder._update_last_part_moves\n\nstack down to just\n\n CompositeBuilder.rebalance -\u003e\n CompositeBuilder.update_last_part_moves -\u003e\n CooperativeBuilder.update_last_part_moves -\u003e\n RingBuilder._update_last_part_moves\n\nWe may as well go all the way to\n\n CompositeBuilder.rebalance -\u003e\n CooperativeBuilder.update_last_part_moves -\u003e\n RingBuilder._update_last_part_moves","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ab83a01278095265ac3a02d7d867d6e652cd3676","unresolved":false,"context_lines":[{"line_number":684,"context_line":"        # starts moving parts; this will effectively be a no-op for builders"},{"line_number":685,"context_line":"        # that have already been updated in last hour"},{"line_number":686,"context_line":"        for b in self._builders:"},{"line_number":687,"context_line":"            b.update_last_part_moves()"},{"line_number":688,"context_line":""},{"line_number":689,"context_line":""},{"line_number":690,"context_line":"class CooperativeRingBuilder(RingBuilder):"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_9d45f6b6","line":687,"in_reply_to":"7f287b81_e8c0362d","updated":"2017-09-07 13:52:00.000000000","message":"I considered that and it\u0027s a valid suggestion. However I left the separate method because (a) it provides greater flixibility to users of CompositeRingBuilder. The rebalance() method does a lot (update_last_part_moves, rebalance, validate and save builders) - some users might want to implement their own rebalance workflow and take advantage of the separate update_last_part_moves.\n\nAlso, we might want to be cautious about removing the method from the interface.","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2e888045b69f66e04d36d5ce8dd1d87d97f3e8a8","unresolved":false,"context_lines":[{"line_number":720,"context_line":"        :return: True if the partition can be moved, False otherwise."},{"line_number":721,"context_line":"        \"\"\""},{"line_number":722,"context_line":"        # called by parent_builder - now forward to the superclass"},{"line_number":723,"context_line":"        return (not self.ever_rebalanced or"},{"line_number":724,"context_line":"                super(CooperativeRingBuilder, self)._can_part_move(part))"},{"line_number":725,"context_line":""},{"line_number":726,"context_line":"    def _update_last_part_moves(self):"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_cd610c14","line":723,"range":{"start_line":723,"start_character":16,"end_line":723,"end_character":40},"updated":"2017-09-01 19:54:36.000000000","message":"Is this still needed? Dropping it causes\n\n # rb1 has never been rebalanced so no calls propagate from its\n # can_part_move method to to its superclass _can_part_move method\n self.assertEqual([rb2], can_part_move_calls.keys())\n\nto fail (which makes sense), but I wonder if that may have been testing the internals a bit too much anyway. Removing the assertion, the rest of the test passes.","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"f01203d4341e1bcc888703c41c4b7c388af77372","unresolved":false,"context_lines":[{"line_number":720,"context_line":"        :return: True if the partition can be moved, False otherwise."},{"line_number":721,"context_line":"        \"\"\""},{"line_number":722,"context_line":"        # called by parent_builder - now forward to the superclass"},{"line_number":723,"context_line":"        return (not self.ever_rebalanced or"},{"line_number":724,"context_line":"                super(CooperativeRingBuilder, self)._can_part_move(part))"},{"line_number":725,"context_line":""},{"line_number":726,"context_line":"    def _update_last_part_moves(self):"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_5c0f8987","line":723,"range":{"start_line":723,"start_character":16,"end_line":723,"end_character":40},"in_reply_to":"7f287b81_3d53a219","updated":"2017-09-07 17:52:17.000000000","message":"the superclass _can_part_move also requires self._has_part_moved to be initialised, which happens in _update_last_part_moves, so probably has been init\u0027d before this method has been called in the context of composite rebalance, but it might be safest to leave the check on self.ever_rebalanced in place regardless","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ab83a01278095265ac3a02d7d867d6e652cd3676","unresolved":false,"context_lines":[{"line_number":720,"context_line":"        :return: True if the partition can be moved, False otherwise."},{"line_number":721,"context_line":"        \"\"\""},{"line_number":722,"context_line":"        # called by parent_builder - now forward to the superclass"},{"line_number":723,"context_line":"        return (not self.ever_rebalanced or"},{"line_number":724,"context_line":"                super(CooperativeRingBuilder, self)._can_part_move(part))"},{"line_number":725,"context_line":""},{"line_number":726,"context_line":"    def _update_last_part_moves(self):"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_3d53a219","line":723,"range":{"start_line":723,"start_character":16,"end_line":723,"end_character":40},"in_reply_to":"7f287b81_cd610c14","updated":"2017-09-07 13:52:00.000000000","message":"probably not needed, good spot. Previously the condition was there bacause before rebalance the _last_part_moves array was None so calling _can_part_move would fail.\n\nAnd yeah, one of the tests is a little too white-box...but feels wrong to rip it out??","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cc7911f0410f2df107692f66d5d8aeac8341eae9","unresolved":false,"context_lines":[{"line_number":727,"context_line":"        # overrides superclass method - parent builder should have called"},{"line_number":728,"context_line":"        # update_last_part_moves() before rebalance; calling the superclass"},{"line_number":729,"context_line":"        # method here would reset _part_moved_bitmap which is state we rely on"},{"line_number":730,"context_line":"        # when min_part_hours iz zero"},{"line_number":731,"context_line":"        pass"},{"line_number":732,"context_line":""},{"line_number":733,"context_line":"    def update_last_part_moves(self):"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_599aa213","line":730,"range":{"start_line":730,"start_character":30,"end_line":730,"end_character":32},"updated":"2017-08-31 15:13:48.000000000","message":"nit: is","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2e888045b69f66e04d36d5ce8dd1d87d97f3e8a8","unresolved":false,"context_lines":[{"line_number":736,"context_line":"        in this builder."},{"line_number":737,"context_line":"        \"\"\""},{"line_number":738,"context_line":"        # called by parent_builder - now forward to the superclass"},{"line_number":739,"context_line":"        return super(CooperativeRingBuilder, self)._update_last_part_moves()"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_8833f262","line":739,"updated":"2017-09-01 19:54:36.000000000","message":"So this is getting called less often now...interesting... but since we don\u0027t have the early exit for ever_rebalanced, it comes out about the same? Just all up-front instead of smeared out across the initial rebalances.","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ab83a01278095265ac3a02d7d867d6e652cd3676","unresolved":false,"context_lines":[{"line_number":736,"context_line":"        in this builder."},{"line_number":737,"context_line":"        \"\"\""},{"line_number":738,"context_line":"        # called by parent_builder - now forward to the superclass"},{"line_number":739,"context_line":"        return super(CooperativeRingBuilder, self)._update_last_part_moves()"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_387cd081","line":739,"in_reply_to":"7f287b81_8833f262","updated":"2017-09-07 13:52:00.000000000","message":"Yes. previously, some calls to this were unnecessary (effectively a no-op after the first call), now we just call each component once.","commit_id":"009671fcfe24faf639bc7fb1f051d7f0430a051a"},{"author":{"_account_id":4608,"name":"Kota Tsuyuzaki","email":"bloodeagle40234@gmail.com","username":"tsuyuzaki-kota"},"change_message_id":"9abdf2445e8681a33121adc152cc6c9c2a683e14","unresolved":false,"context_lines":[{"line_number":728,"context_line":"        # update_last_part_moves() before rebalance; calling the superclass"},{"line_number":729,"context_line":"        # method here would reset _part_moved_bitmap which is state we rely on"},{"line_number":730,"context_line":"        # when min_part_hours is zero"},{"line_number":731,"context_line":"        pass"},{"line_number":732,"context_line":""},{"line_number":733,"context_line":"    def update_last_part_moves(self):"},{"line_number":734,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":3,"id":"3f4b6375_082e35fa","line":731,"updated":"2017-10-26 09:05:32.000000000","message":"Exactly this is super safe but perhaps too much safe. Now we move the _update_last_part_moves to be called at the begining of CompositeRingBuilder rebalance. That seems good because all co-operative rings keeps almost same timestamp at _last_part_moves_epoch. Thinking of the fact, re-calling rebalance in co-operative builder would be safe because parent builder\u0027s _update_last_part_moves skips to reset it...\n\n  elapsed_hours \u003d int(time() - self._last_part_moves_epoch) / 3600\n  if elapsed_hours \u003c\u003d 0:\n\nunless other rebalance takes more than 1 hour.\n\nIf we could assume a ring rebalance doesn\u0027t take 1 hour OR we can accepts co-operative builder rebalance on that case, we could simplify the code like:\n\nhttps://gist.github.com/bloodeagle40234/fe86c82656e0cf574a48952953a718fd\n\n\nBUT... while writing the comments above, I\u0027m realizing we should keep current super-safe implementation because this attempts to move more than 1 part at the same time. Even that rebalance take a long time we should follow the rule to ensure the object accessibility. Make sense.","commit_id":"348bd83b7eb638d3309ff6313d9a6501c540fa24"}],"test/unit/common/ring/test_builder.py":[{"author":{"_account_id":4608,"name":"Kota Tsuyuzaki","email":"bloodeagle40234@gmail.com","username":"tsuyuzaki-kota"},"change_message_id":"9abdf2445e8681a33121adc152cc6c9c2a683e14","unresolved":false,"context_lines":[{"line_number":859,"context_line":"        self.assertTrue(rb.ever_rebalanced)"},{"line_number":860,"context_line":"        rb.save(builder_file)"},{"line_number":861,"context_line":"        rb \u003d ring.RingBuilder.load(builder_file)"},{"line_number":862,"context_line":"        self.assertTrue(rb.ever_rebalanced)"},{"line_number":863,"context_line":""},{"line_number":864,"context_line":"    def test_rerebalance(self):"},{"line_number":865,"context_line":"        rb \u003d ring.RingBuilder(8, 3, 1)"}],"source_content_type":"text/x-python","patch_set":2,"id":"5f2577a7_2cba6b09","line":862,"updated":"2017-10-26 09:05:32.000000000","message":"looks good.","commit_id":"7597c55a8a20faf0f66356550808bec619f76e93"}],"test/unit/common/ring/test_composite_builder.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cc7911f0410f2df107692f66d5d8aeac8341eae9","unresolved":false,"context_lines":[{"line_number":1107,"context_line":"                            fake_can_part_move):"},{"line_number":1108,"context_line":"                yield calls"},{"line_number":1109,"context_line":""},{"line_number":1110,"context_line":"        # single component builder in parent builder"},{"line_number":1111,"context_line":"        cb \u003d CompositeRingBuilder()"},{"line_number":1112,"context_line":"        rb1 \u003d self._make_coop_builder(1, cb)"},{"line_number":1113,"context_line":"        with mock_update_last_part_moves() as update_calls:"},{"line_number":1114,"context_line":"            with mock_can_part_move() as can_part_move_calls:"},{"line_number":1115,"context_line":"                rb1.rebalance()"},{"line_number":1116,"context_line":"        self.assertEqual([rb1], update_calls)"},{"line_number":1117,"context_line":"        self.assertEqual([rb1], can_part_move_calls.keys())"},{"line_number":1118,"context_line":"        self.assertEqual(512, len(can_part_move_calls[rb1]))"},{"line_number":1119,"context_line":""},{"line_number":1120,"context_line":"        # two component builders with same parent builder"},{"line_number":1121,"context_line":"        cb \u003d CompositeRingBuilder()"},{"line_number":1122,"context_line":"        rb1 \u003d self._make_coop_builder(1, cb)"},{"line_number":1123,"context_line":"        rb2 \u003d self._make_coop_builder(2, cb)"},{"line_number":1124,"context_line":"        cb._builders \u003d [rb1, rb2]"},{"line_number":1125,"context_line":"        with mock_update_last_part_moves() as update_calls:"},{"line_number":1126,"context_line":"            with mock_can_part_move() as can_part_move_calls:"},{"line_number":1127,"context_line":"                rb2.rebalance()"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_79f2fe71","side":"PARENT","line":1124,"range":{"start_line":1110,"start_character":8,"end_line":1124,"end_character":33},"updated":"2017-08-31 15:13:48.000000000","message":"this was pointless/bogus - CompositeRingBuilders must have \u003e1 component","commit_id":"add2a94cd84a5091592b14525733d6bdf4c7e0cf"},{"author":{"_account_id":4608,"name":"Kota Tsuyuzaki","email":"bloodeagle40234@gmail.com","username":"tsuyuzaki-kota"},"change_message_id":"9abdf2445e8681a33121adc152cc6c9c2a683e14","unresolved":false,"context_lines":[{"line_number":1048,"context_line":"        if min_part_hours \u003e 0:"},{"line_number":1049,"context_line":"            self.assertEqual(0, self.num_parts_can_move(builders[0]))"},{"line_number":1050,"context_line":"            self.assertEqual(0, self.num_parts_can_move(builders[1]))"},{"line_number":1051,"context_line":"            self.assertEqual(0, self.num_parts_can_move(builders[2]))"},{"line_number":1052,"context_line":""},{"line_number":1053,"context_line":"        with mock.patch(\u0027swift.common.ring.composite_builder.shuffle\u0027,"},{"line_number":1054,"context_line":"                        lambda x: x):"}],"source_content_type":"text/x-python","patch_set":2,"id":"5f2577a7_174fbc6b","line":1051,"updated":"2017-10-26 09:05:32.000000000","message":"Strictly testing,\n\nelse:\n  self.assertEqual(builders[0].parts, self.num_parts_can_move(builders[0]))\n  self.assertEqual(builders[1].parts, self.num_parts_can_move(builders[1]))\n  self.assertEqual(builders[2].parts, self.num_parts_can_move(builders[2]))\n\n??\n\nbecause we have a test case with min_part_hours \u003d\u003d 0.","commit_id":"7597c55a8a20faf0f66356550808bec619f76e93"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"19e2cda02b67f7d17f4af76dc0fa5331baeeaba9","unresolved":false,"context_lines":[{"line_number":995,"context_line":"        for p in range(before.parts):"},{"line_number":996,"context_line":"            if ({uniqueness(dev) for dev in before._devs_for_part(p)} !\u003d"},{"line_number":997,"context_line":"                    {uniqueness(dev) for dev in after._devs_for_part(p)}):"},{"line_number":998,"context_line":"                    moved_parts.add(p)"},{"line_number":999,"context_line":"        return moved_parts"},{"line_number":1000,"context_line":""},{"line_number":1001,"context_line":"    def num_parts_can_move(self, builder):"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f4b6375_d62ae57c","line":998,"range":{"start_line":998,"start_character":20,"end_line":998,"end_character":38},"updated":"2017-10-27 02:33:26.000000000","message":"This line is indented too much","commit_id":"348bd83b7eb638d3309ff6313d9a6501c540fa24"},{"author":{"_account_id":4608,"name":"Kota Tsuyuzaki","email":"bloodeagle40234@gmail.com","username":"tsuyuzaki-kota"},"change_message_id":"9abdf2445e8681a33121adc152cc6c9c2a683e14","unresolved":false,"context_lines":[{"line_number":1262,"context_line":"                rb2.rebalance()"},{"line_number":1263,"context_line":"        self.assertFalse(update_calls)"},{"line_number":1264,"context_line":"        # rb1 has never been rebalanced so no calls propagate from its"},{"line_number":1265,"context_line":"        # can_part_move method to to its superclass _can_part_move method"},{"line_number":1266,"context_line":"        self.assertEqual([rb2], can_part_move_calls.keys())"},{"line_number":1267,"context_line":""},{"line_number":1268,"context_line":"        with mock_update_last_part_moves() as update_calls:"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f4b6375_e3041a17","line":1265,"range":{"start_line":1265,"start_character":34,"end_line":1265,"end_character":36},"updated":"2017-10-26 09:05:32.000000000","message":"nits) not related to this change but the \"to\" is redundant.","commit_id":"348bd83b7eb638d3309ff6313d9a6501c540fa24"}]}
