)]}'
{"nova/tests/unit/virt/hyperv/test_namedpipe.py":[{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"ccca3e96e537ff04813d07475db0fa0fc5be91ed","unresolved":false,"context_lines":[{"line_number":105,"context_line":""},{"line_number":106,"context_line":"        for worker in self._handler._workers:"},{"line_number":107,"context_line":"            worker.join.assert_called_once_with()"},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"    def _test_start_io_worker(self, buff_update_func\u003dNone, exception\u003dNone):"},{"line_number":110,"context_line":"        self._handler._stopped.isSet.side_effect \u003d [False, True]"},{"line_number":111,"context_line":"        self._handler._pipe_handle \u003d mock.sentinel.pipe_handle"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_dac9307b","line":108,"updated":"2015-07-30 13:31:19.000000000","message":"no test for _cancel_io or _close_pipe or _open_pipe?","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"768ba70aeb3366ec9406db0a716f6aa7031e8ad9","unresolved":false,"context_lines":[{"line_number":105,"context_line":""},{"line_number":106,"context_line":"        for worker in self._handler._workers:"},{"line_number":107,"context_line":"            worker.join.assert_called_once_with()"},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"    def _test_start_io_worker(self, buff_update_func\u003dNone, exception\u003dNone):"},{"line_number":110,"context_line":"        self._handler._stopped.isSet.side_effect \u003d [False, True]"},{"line_number":111,"context_line":"        self._handler._pipe_handle \u003d mock.sentinel.pipe_handle"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_00dacae9","line":108,"in_reply_to":"3a50d1a3_dac9307b","updated":"2015-07-30 13:52:52.000000000","message":"Those seemed so straight forward that I thought it\u0027s unnecessary, but sure, I\u0027ll add unit tests.","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"ccca3e96e537ff04813d07475db0fa0fc5be91ed","unresolved":false,"context_lines":[{"line_number":168,"context_line":"        self.assertEqual(len(fake_data), num_bytes)"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    @mock.patch.object(namedpipe.NamedPipeHandler, \u0027_rotate_logs\u0027)"},{"line_number":171,"context_line":"    def _test_write_to_log(self, mock_rotate_logs, size_exceeded\u003dFalse):"},{"line_number":172,"context_line":"        self._mock_setup_pipe_handler()"},{"line_number":173,"context_line":"        self._handler._stopped.isSet.return_value \u003d False"},{"line_number":174,"context_line":"        fake_handle \u003d self._handler._log_file_handle"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_1acd58b7","line":171,"updated":"2015-07-30 13:31:19.000000000","message":"FYI, the exception branch is not tested.","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"768ba70aeb3366ec9406db0a716f6aa7031e8ad9","unresolved":false,"context_lines":[{"line_number":168,"context_line":"        self.assertEqual(len(fake_data), num_bytes)"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    @mock.patch.object(namedpipe.NamedPipeHandler, \u0027_rotate_logs\u0027)"},{"line_number":171,"context_line":"    def _test_write_to_log(self, mock_rotate_logs, size_exceeded\u003dFalse):"},{"line_number":172,"context_line":"        self._mock_setup_pipe_handler()"},{"line_number":173,"context_line":"        self._handler._stopped.isSet.return_value \u003d False"},{"line_number":174,"context_line":"        fake_handle \u003d self._handler._log_file_handle"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_00016a39","line":171,"in_reply_to":"3a50d1a3_1acd58b7","updated":"2015-07-30 13:52:52.000000000","message":"Done","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"ccca3e96e537ff04813d07475db0fa0fc5be91ed","unresolved":false,"context_lines":[{"line_number":218,"context_line":"                         self._handler._log_file_handle)"},{"line_number":219,"context_line":""},{"line_number":220,"context_line":"    @mock.patch.object(namedpipe, \u0027time\u0027)"},{"line_number":221,"context_line":"    def test_retry_if_file_in_use_exceeded_retries(self, mock_time):"},{"line_number":222,"context_line":"        class FakeWindowsException(Exception):"},{"line_number":223,"context_line":"            errno \u003d errno.EACCES"},{"line_number":224,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_1a0c783a","line":221,"updated":"2015-07-30 13:31:19.000000000","message":"might also be useful to have a test that succesfully retries, not just one that will timeout / fail.","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"768ba70aeb3366ec9406db0a716f6aa7031e8ad9","unresolved":false,"context_lines":[{"line_number":218,"context_line":"                         self._handler._log_file_handle)"},{"line_number":219,"context_line":""},{"line_number":220,"context_line":"    @mock.patch.object(namedpipe, \u0027time\u0027)"},{"line_number":221,"context_line":"    def test_retry_if_file_in_use_exceeded_retries(self, mock_time):"},{"line_number":222,"context_line":"        class FakeWindowsException(Exception):"},{"line_number":223,"context_line":"            errno \u003d errno.EACCES"},{"line_number":224,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_c0a86223","line":221,"in_reply_to":"3a50d1a3_1a0c783a","updated":"2015-07-30 13:52:52.000000000","message":"Good point, will add.","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"ccca3e96e537ff04813d07475db0fa0fc5be91ed","unresolved":false,"context_lines":[{"line_number":224,"context_line":""},{"line_number":225,"context_line":"        raise_count \u003d self._handler._MAX_LOG_ROTATE_RETRIES + 1"},{"line_number":226,"context_line":"        mock_func_side_eff \u003d [FakeWindowsException] * raise_count"},{"line_number":227,"context_line":"        mock_func \u003d mock.Mock(side_effect\u003dmock_func_side_eff)"},{"line_number":228,"context_line":""},{"line_number":229,"context_line":"        with mock.patch.object(namedpipe, \u0027WindowsError\u0027,"},{"line_number":230,"context_line":"                               FakeWindowsException, create\u003dTrue):"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_bf23f6bd","line":227,"updated":"2015-07-30 13:31:19.000000000","message":"you can just have:\n\n    mock_func \u003d mock.Mock(side_effect\u003dFakeWindowsException)\n\nrather than having as a side effect a whole array of the same exception. Works the same.","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"768ba70aeb3366ec9406db0a716f6aa7031e8ad9","unresolved":false,"context_lines":[{"line_number":224,"context_line":""},{"line_number":225,"context_line":"        raise_count \u003d self._handler._MAX_LOG_ROTATE_RETRIES + 1"},{"line_number":226,"context_line":"        mock_func_side_eff \u003d [FakeWindowsException] * raise_count"},{"line_number":227,"context_line":"        mock_func \u003d mock.Mock(side_effect\u003dmock_func_side_eff)"},{"line_number":228,"context_line":""},{"line_number":229,"context_line":"        with mock.patch.object(namedpipe, \u0027WindowsError\u0027,"},{"line_number":230,"context_line":"                               FakeWindowsException, create\u003dTrue):"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_60a2ae4d","line":227,"in_reply_to":"3a50d1a3_bf23f6bd","updated":"2015-07-30 13:52:52.000000000","message":"Done","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"}],"nova/virt/hyperv/namedpipe.py":[{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"79d71c4049e3f5836533e9d79572b7c18ced8f1f","unresolved":false,"context_lines":[{"line_number":166,"context_line":"        if self._log_file_handle:"},{"line_number":167,"context_line":"            self._write_to_log(data)"},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    def _get_data_to_write(self):"},{"line_number":170,"context_line":"        while not (self._stopped.isSet() or self._connect_event.isSet()):"},{"line_number":171,"context_line":"            time.sleep(1)"},{"line_number":172,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_a494c642","line":169,"updated":"2015-07-22 13:12:45.000000000","message":"since this puts the data in the w_buffer and returns the number of bytes of data read, the method name is a bit misleading... how about _write_data_from_input_queue or any other name that reflects this action?","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"5c75dfd664a5c24bd0f693669dcb029d496bb0d1","unresolved":false,"context_lines":[{"line_number":166,"context_line":"        if self._log_file_handle:"},{"line_number":167,"context_line":"            self._write_to_log(data)"},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    def _get_data_to_write(self):"},{"line_number":170,"context_line":"        while not (self._stopped.isSet() or self._connect_event.isSet()):"},{"line_number":171,"context_line":"            time.sleep(1)"},{"line_number":172,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_b6606a02","line":169,"in_reply_to":"3a50d1a3_1f0ce3eb","updated":"2015-07-22 17:16:53.000000000","message":"i suppose so, but the method naming implies that it should return data that will be written somewhere and instead it already writes the data as a side effect and returns the number of bytes written.\n\nbasically, method naming and method behaviour / return doesn\u0027t match.","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"32cc48ef1370112971918c848f0b1655513c440c","unresolved":false,"context_lines":[{"line_number":166,"context_line":"        if self._log_file_handle:"},{"line_number":167,"context_line":"            self._write_to_log(data)"},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    def _get_data_to_write(self):"},{"line_number":170,"context_line":"        while not (self._stopped.isSet() or self._connect_event.isSet()):"},{"line_number":171,"context_line":"            time.sleep(1)"},{"line_number":172,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_1f0ce3eb","line":169,"in_reply_to":"3a50d1a3_a494c642","updated":"2015-07-22 13:29:26.000000000","message":"Well, this could be seen as the method which updates the buffer used for writing to the serial console named pipe.","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"79d71c4049e3f5836533e9d79572b7c18ced8f1f","unresolved":false,"context_lines":[{"line_number":182,"context_line":""},{"line_number":183,"context_line":"        try:"},{"line_number":184,"context_line":"            log_size \u003d self._log_file_handle.tell() + len(data)"},{"line_number":185,"context_line":"            if (log_size \u003e\u003d constants.MAX_CONSOLE_LOG_FILE_SIZE):"},{"line_number":186,"context_line":"                self._rotate_logs()"},{"line_number":187,"context_line":"            self._log_file_handle.write(data)"},{"line_number":188,"context_line":"        except Exception:"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_846aeab1","line":185,"range":{"start_line":185,"start_character":12,"end_line":185,"end_character":14},"updated":"2015-07-22 13:12:45.000000000","message":"no need for paranthesis.","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"32cc48ef1370112971918c848f0b1655513c440c","unresolved":false,"context_lines":[{"line_number":182,"context_line":""},{"line_number":183,"context_line":"        try:"},{"line_number":184,"context_line":"            log_size \u003d self._log_file_handle.tell() + len(data)"},{"line_number":185,"context_line":"            if (log_size \u003e\u003d constants.MAX_CONSOLE_LOG_FILE_SIZE):"},{"line_number":186,"context_line":"                self._rotate_logs()"},{"line_number":187,"context_line":"            self._log_file_handle.write(data)"},{"line_number":188,"context_line":"        except Exception:"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_5f158be2","line":185,"in_reply_to":"3a50d1a3_846aeab1","updated":"2015-07-22 13:29:26.000000000","message":"Bad habit :)","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"79d71c4049e3f5836533e9d79572b7c18ced8f1f","unresolved":false,"context_lines":[{"line_number":192,"context_line":"        self._log_file_handle.flush()"},{"line_number":193,"context_line":"        self._log_file_handle.close()"},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        log_archive_path \u003d self._log_file_path + \u0027.1\u0027"},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"        if os.path.exists(log_archive_path):"},{"line_number":198,"context_line":"            self._retry_if_file_in_use(os.remove,"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_4432a2f3","line":195,"updated":"2015-07-22 13:12:45.000000000","message":"so basically, you can only have 2 log files of 1mb each and the old \u0027.1\u0027 log file is removed. is there no desire for more than 2mb of logs?","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"32cc48ef1370112971918c848f0b1655513c440c","unresolved":false,"context_lines":[{"line_number":192,"context_line":"        self._log_file_handle.flush()"},{"line_number":193,"context_line":"        self._log_file_handle.close()"},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        log_archive_path \u003d self._log_file_path + \u0027.1\u0027"},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"        if os.path.exists(log_archive_path):"},{"line_number":198,"context_line":"            self._retry_if_file_in_use(os.remove,"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_7f6f272b","line":195,"in_reply_to":"3a50d1a3_4432a2f3","updated":"2015-07-22 13:29:26.000000000","message":"The same workflow is used today as there is a 1 MB log cap, each log file having at most 512KB.","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"79d71c4049e3f5836533e9d79572b7c18ced8f1f","unresolved":false,"context_lines":[{"line_number":213,"context_line":"            try:"},{"line_number":214,"context_line":"                return f(*args, **kwargs)"},{"line_number":215,"context_line":"            except WindowsError as err:"},{"line_number":216,"context_line":"                if (err.errno \u003d\u003d errno.EACCES and"},{"line_number":217,"context_line":"                        retry_count \u003c self._MAX_LOG_ROTATE_RETRIES):"},{"line_number":218,"context_line":"                    retry_count +\u003d 1"},{"line_number":219,"context_line":"                    time.sleep(1)"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_d96f7bfa","line":216,"updated":"2015-07-22 13:12:45.000000000","message":"could you add a comment what this if is and what does it check? because it isn\u0027t clear at the first glance.","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"32cc48ef1370112971918c848f0b1655513c440c","unresolved":false,"context_lines":[{"line_number":213,"context_line":"            try:"},{"line_number":214,"context_line":"                return f(*args, **kwargs)"},{"line_number":215,"context_line":"            except WindowsError as err:"},{"line_number":216,"context_line":"                if (err.errno \u003d\u003d errno.EACCES and"},{"line_number":217,"context_line":"                        retry_count \u003c self._MAX_LOG_ROTATE_RETRIES):"},{"line_number":218,"context_line":"                    retry_count +\u003d 1"},{"line_number":219,"context_line":"                    time.sleep(1)"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_dfb8bb77","line":216,"in_reply_to":"3a50d1a3_d96f7bfa","updated":"2015-07-22 13:29:26.000000000","message":"That\u0027s actually stated a few lines above. That \"Access denied\" error is returned when the file is in use. I can add another comment, clearing this out if needed.","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"5c75dfd664a5c24bd0f693669dcb029d496bb0d1","unresolved":false,"context_lines":[{"line_number":213,"context_line":"            try:"},{"line_number":214,"context_line":"                return f(*args, **kwargs)"},{"line_number":215,"context_line":"            except WindowsError as err:"},{"line_number":216,"context_line":"                if (err.errno \u003d\u003d errno.EACCES and"},{"line_number":217,"context_line":"                        retry_count \u003c self._MAX_LOG_ROTATE_RETRIES):"},{"line_number":218,"context_line":"                    retry_count +\u003d 1"},{"line_number":219,"context_line":"                    time.sleep(1)"}],"source_content_type":"text/x-python","patch_set":4,"id":"3a50d1a3_96e0ce97","line":216,"in_reply_to":"3a50d1a3_dfb8bb77","updated":"2015-07-22 17:16:53.000000000","message":"you mean at L209-L210? Then, I guess you should specify there that if the log files are in use, an \"Access denied\" will be raised, having the error number \"errno.EACCES\", or something like that.","commit_id":"afe7bdd28c97e527ebd9072aaa1998d50689b4e8"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"ccca3e96e537ff04813d07475db0fa0fc5be91ed","unresolved":false,"context_lines":[{"line_number":59,"context_line":"                self._log_file_handle \u003d open(self._log_file_path, \u0027ab\u0027, 1)"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"            jobs \u003d [self._read_from_pipe]"},{"line_number":62,"context_line":"            if (self._input_queue and self._connect_event):"},{"line_number":63,"context_line":"                jobs.append(self._write_to_pipe)"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"            for job in jobs:"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_bf38d6d5","line":62,"updated":"2015-07-30 13:31:19.000000000","message":"useless parantheses.","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"768ba70aeb3366ec9406db0a716f6aa7031e8ad9","unresolved":false,"context_lines":[{"line_number":59,"context_line":"                self._log_file_handle \u003d open(self._log_file_path, \u0027ab\u0027, 1)"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"            jobs \u003d [self._read_from_pipe]"},{"line_number":62,"context_line":"            if (self._input_queue and self._connect_event):"},{"line_number":63,"context_line":"                jobs.append(self._write_to_pipe)"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"            for job in jobs:"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_8029faf4","line":62,"in_reply_to":"3a50d1a3_bf38d6d5","updated":"2015-07-30 13:52:52.000000000","message":"Done","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8213,"name":"Claudiu Belu","email":"cbelu@cloudbasesolutions.com","username":"claudiub"},"change_message_id":"ccca3e96e537ff04813d07475db0fa0fc5be91ed","unresolved":false,"context_lines":[{"line_number":154,"context_line":""},{"line_number":155,"context_line":"                func(self._pipe_handle, buff, num_bytes,"},{"line_number":156,"context_line":"                     overlapped_structure, completion_routine)"},{"line_number":157,"context_line":"        except Exception:"},{"line_number":158,"context_line":"            self._stopped.set()"},{"line_number":159,"context_line":""},{"line_number":160,"context_line":"    def _read_callback(self, num_bytes):"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_bfcc568b","line":157,"updated":"2015-07-30 13:31:19.000000000","message":"adding a log message might be useful for the time when an IO worker cannot start. Knowing that it failed and also why rather than just silently ignoring it is much more useful.","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"},{"author":{"_account_id":8543,"name":"Lucian Petrut","email":"lpetrut@cloudbasesolutions.com","username":"plucian"},"change_message_id":"768ba70aeb3366ec9406db0a716f6aa7031e8ad9","unresolved":false,"context_lines":[{"line_number":154,"context_line":""},{"line_number":155,"context_line":"                func(self._pipe_handle, buff, num_bytes,"},{"line_number":156,"context_line":"                     overlapped_structure, completion_routine)"},{"line_number":157,"context_line":"        except Exception:"},{"line_number":158,"context_line":"            self._stopped.set()"},{"line_number":159,"context_line":""},{"line_number":160,"context_line":"    def _read_callback(self, num_bytes):"}],"source_content_type":"text/x-python","patch_set":5,"id":"3a50d1a3_60862edd","line":157,"in_reply_to":"3a50d1a3_bfcc568b","updated":"2015-07-30 13:52:52.000000000","message":"Unfortunately, I can\u0027t. One of the downsides of using native threads is that when used along with green threads, you can\u0027t use logging.","commit_id":"49e064c038b3b28fa07239aa5a66bd26d1e07301"}]}
