)]}'
{"openstack/cloud/openstackcloud.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":793,"context_line":"                dep_graph.add_node(dep)"},{"line_number":794,"context_line":"                dep_graph.add_edge(k, dep)"},{"line_number":795,"context_line":""},{"line_number":796,"context_line":"        with concurrent.futures.ThreadPoolExecutor("},{"line_number":797,"context_line":"                max_workers\u003dnum_threads) as executor:"},{"line_number":798,"context_line":"            for service in dep_graph.walk(timeout\u003dwait_timeout):"},{"line_number":799,"context_line":"                fn \u003d None"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_f2ae7b2f","line":796,"range":{"start_line":796,"start_character":12,"end_line":796,"end_character":50},"updated":"2020-02-10 17:05:59.000000000","message":"Could we at least provide a way for the caller to specify an executor, defaulting to the sync one? I\u0027m not sure how well using this will play with greenlet-based projects.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":793,"context_line":"                dep_graph.add_node(dep)"},{"line_number":794,"context_line":"                dep_graph.add_edge(k, dep)"},{"line_number":795,"context_line":""},{"line_number":796,"context_line":"        with concurrent.futures.ThreadPoolExecutor("},{"line_number":797,"context_line":"                max_workers\u003dnum_threads) as executor:"},{"line_number":798,"context_line":"            for service in dep_graph.walk(timeout\u003dwait_timeout):"},{"line_number":799,"context_line":"                fn \u003d None"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_5fe12597","line":796,"range":{"start_line":796,"start_character":12,"end_line":796,"end_character":50},"in_reply_to":"3fa7e38b_4e6b20b7","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"d96df9174298bd5930e849ab683c3d0a2292cf6b","unresolved":false,"context_lines":[{"line_number":793,"context_line":"                dep_graph.add_node(dep)"},{"line_number":794,"context_line":"                dep_graph.add_edge(k, dep)"},{"line_number":795,"context_line":""},{"line_number":796,"context_line":"        with concurrent.futures.ThreadPoolExecutor("},{"line_number":797,"context_line":"                max_workers\u003dnum_threads) as executor:"},{"line_number":798,"context_line":"            for service in dep_graph.walk(timeout\u003dwait_timeout):"},{"line_number":799,"context_line":"                fn \u003d None"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_4e6b20b7","line":796,"range":{"start_line":796,"start_character":12,"end_line":796,"end_character":50},"in_reply_to":"3fa7e38b_93d13f59","updated":"2020-02-11 09:31:23.000000000","message":"bypassing completely. not sure all callers will be fond of having threads created underneath.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"b60820fbc9b604f421b13205d2ec8a01b0e107d6","unresolved":false,"context_lines":[{"line_number":793,"context_line":"                dep_graph.add_node(dep)"},{"line_number":794,"context_line":"                dep_graph.add_edge(k, dep)"},{"line_number":795,"context_line":""},{"line_number":796,"context_line":"        with concurrent.futures.ThreadPoolExecutor("},{"line_number":797,"context_line":"                max_workers\u003dnum_threads) as executor:"},{"line_number":798,"context_line":"            for service in dep_graph.walk(timeout\u003dwait_timeout):"},{"line_number":799,"context_line":"                fn \u003d None"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_93d13f59","line":796,"range":{"start_line":796,"start_character":12,"end_line":796,"end_character":50},"in_reply_to":"3fa7e38b_f2ae7b2f","updated":"2020-02-11 08:36:34.000000000","message":"do you mind passing num_threads\u003d1, or having possibility to bypass usage of ThreadPoolExecutor?","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":794,"context_line":"                dep_graph.add_edge(k, dep)"},{"line_number":795,"context_line":""},{"line_number":796,"context_line":"        with concurrent.futures.ThreadPoolExecutor("},{"line_number":797,"context_line":"                max_workers\u003dnum_threads) as executor:"},{"line_number":798,"context_line":"            for service in dep_graph.walk(timeout\u003dwait_timeout):"},{"line_number":799,"context_line":"                fn \u003d None"},{"line_number":800,"context_line":"                if hasattr(self, service):"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_12b47780","line":797,"range":{"start_line":797,"start_character":16,"end_line":797,"end_character":39},"updated":"2020-02-10 17:05:59.000000000","message":"As a bonus, you won\u0027t need to support all possible options of all possible executors.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"254208cea787ad0628f7079c67ed4addccdac194","unresolved":false,"context_lines":[{"line_number":805,"context_line":"                        cleanup_fn(dry_run\u003ddry_run, status_queue\u003dstatus_queue)"},{"line_number":806,"context_line":"                dep_graph.node_done(service)"},{"line_number":807,"context_line":"        else:"},{"line_number":808,"context_line":"            with concurrent.futures.ThreadPoolExecutor("},{"line_number":809,"context_line":"                    max_workers\u003dnum_threads) as executor:"},{"line_number":810,"context_line":"                for service in dep_graph.walk(timeout\u003dwait_timeout):"},{"line_number":811,"context_line":"                    fn \u003d None"},{"line_number":812,"context_line":"                    if hasattr(self, service):"}],"source_content_type":"text/x-python","patch_set":10,"id":"3fa7e38b_557c7621","line":809,"range":{"start_line":808,"start_character":0,"end_line":809,"end_character":57},"updated":"2020-02-20 13:07:22.000000000","message":"Why not just allow passing an executor (or None)? This will reduce the amount of code here and will allow people to use custom executors.","commit_id":"d31c31c739050249cc75e9b392377dcb54059463"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"20d596a146e3d56464596016337094103bd4e845","unresolved":false,"context_lines":[{"line_number":805,"context_line":"                        cleanup_fn(dry_run\u003ddry_run, status_queue\u003dstatus_queue)"},{"line_number":806,"context_line":"                dep_graph.node_done(service)"},{"line_number":807,"context_line":"        else:"},{"line_number":808,"context_line":"            with concurrent.futures.ThreadPoolExecutor("},{"line_number":809,"context_line":"                    max_workers\u003dnum_threads) as executor:"},{"line_number":810,"context_line":"                for service in dep_graph.walk(timeout\u003dwait_timeout):"},{"line_number":811,"context_line":"                    fn \u003d None"},{"line_number":812,"context_line":"                    if hasattr(self, service):"}],"source_content_type":"text/x-python","patch_set":10,"id":"3fa7e38b_c000a6b3","line":809,"range":{"start_line":808,"start_character":0,"end_line":809,"end_character":57},"in_reply_to":"3fa7e38b_5565561b","updated":"2020-02-20 13:44:09.000000000","message":"You cannot serious call \"reinventing wheel\" calling a constructor with one argument...","commit_id":"d31c31c739050249cc75e9b392377dcb54059463"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"f27dd8efc58552d92f06c9e7856e12680e29b06f","unresolved":false,"context_lines":[{"line_number":805,"context_line":"                        cleanup_fn(dry_run\u003ddry_run, status_queue\u003dstatus_queue)"},{"line_number":806,"context_line":"                dep_graph.node_done(service)"},{"line_number":807,"context_line":"        else:"},{"line_number":808,"context_line":"            with concurrent.futures.ThreadPoolExecutor("},{"line_number":809,"context_line":"                    max_workers\u003dnum_threads) as executor:"},{"line_number":810,"context_line":"                for service in dep_graph.walk(timeout\u003dwait_timeout):"},{"line_number":811,"context_line":"                    fn \u003d None"},{"line_number":812,"context_line":"                    if hasattr(self, service):"}],"source_content_type":"text/x-python","patch_set":10,"id":"3fa7e38b_5565561b","line":809,"range":{"start_line":808,"start_character":0,"end_line":809,"end_character":57},"in_reply_to":"3fa7e38b_557c7621","updated":"2020-02-20 13:37:29.000000000","message":"well, I guess this will make situation even worse - nobody knows how to use it and reinvent a wheel or copy paste the same code over and over. I would like SDK to offer function, that can be consumed, and not that it needs additional glue to work. While I can move this to another \"wrapper\" function and have possibility to inject executor here, this will lead to 2 public functions. Is this better?","commit_id":"d31c31c739050249cc75e9b392377dcb54059463"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"5b8ae51a6fc7a48d29e755a045e2820c64f14352","unresolved":false,"context_lines":[{"line_number":764,"context_line":"            to comlete the cleanup."},{"line_number":765,"context_line":"        :param queue status_queue: a threading queue object used to get current"},{"line_number":766,"context_line":"            process status. The queue contain processed resources."},{"line_number":767,"context_line":"        :param executor: A concurrent.futures compatible executor"},{"line_number":768,"context_line":"            (ThreadExecutorPool, ProcessPoolExecutor, GreenThreadPoolExecutor)"},{"line_number":769,"context_line":"            or None for single threaded execution."},{"line_number":770,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":13,"id":"1fa4df85_25d3d73a","line":767,"updated":"2020-02-26 15:16:35.000000000","message":"In openstack/cloud/_object_store.py we have self.__pool_executor and a TODO about making it possible to do just this. \n\nWhy don\u0027t we make it a Connection level parameter. That way we can allow people to set up their Connection correctly when they make it for whatever scenario they are in. Then here we can just use self.__pool_executor and be done with it.\n\nAs absurd as it sounds, maybe we even implement a SynchronousExecutor which is what people can pass an instance of if they don\u0027t want any concurrency at all. (it\u0027s three methods, might be super simple?)","commit_id":"de826f92dad4835aa28cf201a3d60d8755d36825"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"aa2163332382b80d1ea2d01256ee612126b0859a","unresolved":false,"context_lines":[{"line_number":764,"context_line":"            to comlete the cleanup."},{"line_number":765,"context_line":"        :param queue status_queue: a threading queue object used to get current"},{"line_number":766,"context_line":"            process status. The queue contain processed resources."},{"line_number":767,"context_line":"        :param executor: A concurrent.futures compatible executor"},{"line_number":768,"context_line":"            (ThreadExecutorPool, ProcessPoolExecutor, GreenThreadPoolExecutor)"},{"line_number":769,"context_line":"            or None for single threaded execution."},{"line_number":770,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":13,"id":"1fa4df85_8acb7870","line":767,"in_reply_to":"1fa4df85_25d3d73a","updated":"2020-03-02 16:07:41.000000000","message":"++ to a connection-level parameter, then we won\u0027t have to have this discussion again.\n\nThe futurist library has a synchronous executor, but I\u0027m not sure if we want a dependency.","commit_id":"de826f92dad4835aa28cf201a3d60d8755d36825"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"5b8ae51a6fc7a48d29e755a045e2820c64f14352","unresolved":false,"context_lines":[{"line_number":766,"context_line":"            process status. The queue contain processed resources."},{"line_number":767,"context_line":"        :param executor: A concurrent.futures compatible executor"},{"line_number":768,"context_line":"            (ThreadExecutorPool, ProcessPoolExecutor, GreenThreadPoolExecutor)"},{"line_number":769,"context_line":"            or None for single threaded execution."},{"line_number":770,"context_line":"        \"\"\""},{"line_number":771,"context_line":"        dependencies \u003d {}"},{"line_number":772,"context_line":"        get_dep_fn_name \u003d \u0027_get_cleanup_dependencies\u0027"}],"source_content_type":"text/x-python","patch_set":13,"id":"1fa4df85_65778f3c","line":769,"updated":"2020-02-26 15:16:35.000000000","message":"I\u0027d prefer for the default behavior to be ThreadPool. The reason for this is the same reason we started with that for object uploads and left the others as a \"we\u0027ll get to it later\" ... which is that we should always make sdk do the best thing for the default situation by default and not make normal users opt-in to \"good\" behavior.\n\nOperating in an environment where Threads might not work is not normal, it\u0027s an advanced paradigm and it\u0027s reasonable to expect users of the SDK who are operating in such a paradigm to know that they are and thus that they need to pass a GreenthreadExecutor. If someone is just writing a script to do some cleanup, there is no reason for them to not want parallel operation here (it\u0027s remote network calls, not CPU intensive things that\u0027ll kill a machine) - so it\u0027s not reasonable to ask them to pass executor\u003dThreadPoolExecutor() to get reasonable performance.","commit_id":"de826f92dad4835aa28cf201a3d60d8755d36825"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"aa2163332382b80d1ea2d01256ee612126b0859a","unresolved":false,"context_lines":[{"line_number":766,"context_line":"            process status. The queue contain processed resources."},{"line_number":767,"context_line":"        :param executor: A concurrent.futures compatible executor"},{"line_number":768,"context_line":"            (ThreadExecutorPool, ProcessPoolExecutor, GreenThreadPoolExecutor)"},{"line_number":769,"context_line":"            or None for single threaded execution."},{"line_number":770,"context_line":"        \"\"\""},{"line_number":771,"context_line":"        dependencies \u003d {}"},{"line_number":772,"context_line":"        get_dep_fn_name \u003d \u0027_get_cleanup_dependencies\u0027"}],"source_content_type":"text/x-python","patch_set":13,"id":"1fa4df85_4ac5805a","line":769,"in_reply_to":"1fa4df85_65778f3c","updated":"2020-03-02 16:07:41.000000000","message":"I\u0027m probably okay with defaulting to a thread pool, as long as it can be completely overridden.","commit_id":"de826f92dad4835aa28cf201a3d60d8755d36825"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"e8cff7b13ea829dba57b7c48b085948205b6eba8","unresolved":false,"context_lines":[{"line_number":788,"context_line":"                dep_graph.add_node(dep)"},{"line_number":789,"context_line":"                dep_graph.add_edge(k, dep)"},{"line_number":790,"context_line":""},{"line_number":791,"context_line":"        if not use_pool_executor:"},{"line_number":792,"context_line":"            # Since some might not be fans of threads underneath - this"},{"line_number":793,"context_line":"            # is the way to bypass them"},{"line_number":794,"context_line":"            for service in dep_graph.walk(timeout\u003dwait_timeout):"}],"source_content_type":"text/x-python","patch_set":14,"id":"df33271e_3bc5a48f","line":791,"updated":"2020-03-23 14:12:48.000000000","message":"I think since we\u0027re using futurist for the pool executor now we could just point people at the single threaded executor from futurist?","commit_id":"16f6344e25e647b19ee3442572dfbfbd62d72559"}],"openstack/config/cloud_region.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":365,"context_line":"        all_services \u003d [k[\u0027service_type\u0027] for k in"},{"line_number":366,"context_line":"                        self._service_type_manager.services]"},{"line_number":367,"context_line":"        all_services.extend(k[4:] for k in"},{"line_number":368,"context_line":"                            self.config.keys() if k.startswith(\u0027has_\u0027))"},{"line_number":369,"context_line":""},{"line_number":370,"context_line":"        for srv in all_services:"},{"line_number":371,"context_line":"            ep \u003d self.get_endpoint_from_catalog(srv)"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_f28f5b1e","line":368,"range":{"start_line":368,"start_character":39,"end_line":368,"end_character":46},"updated":"2020-02-10 17:05:59.000000000","message":"nit: keys() not needed","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"}],"openstack/connection.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":470,"context_line":"                attr_name.replace(\u0027-\u0027, \u0027_\u0027),"},{"line_number":471,"context_line":"                property(fget\u003dgetter)"},{"line_number":472,"context_line":"            )"},{"line_number":473,"context_line":"        self.config.enable_service(service.service_type)"},{"line_number":474,"context_line":""},{"line_number":475,"context_line":"    def authorize(self):"},{"line_number":476,"context_line":"        \"\"\"Authorize this Connection"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_f263db16","line":473,"range":{"start_line":473,"start_character":0,"end_line":473,"end_character":56},"updated":"2020-02-10 17:05:59.000000000","message":"This seems a potentially breaking change, no?","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"b60820fbc9b604f421b13205d2ec8a01b0e107d6","unresolved":false,"context_lines":[{"line_number":470,"context_line":"                attr_name.replace(\u0027-\u0027, \u0027_\u0027),"},{"line_number":471,"context_line":"                property(fget\u003dgetter)"},{"line_number":472,"context_line":"            )"},{"line_number":473,"context_line":"        self.config.enable_service(service.service_type)"},{"line_number":474,"context_line":""},{"line_number":475,"context_line":"    def authorize(self):"},{"line_number":476,"context_line":"        \"\"\"Authorize this Connection"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_f3d67354","line":473,"range":{"start_line":473,"start_character":0,"end_line":473,"end_character":56},"in_reply_to":"3fa7e38b_f263db16","updated":"2020-02-11 08:36:34.000000000","message":"Don\u0027t think so. Actually I doubt anyone is using this interface except me, and I would rather treat this as a bugfix to allow existing connection interfaces to work properly for added services","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"}],"openstack/proxy.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":502,"context_line":"        res \u003d self._get_resource(resource_type, value, **attrs)"},{"line_number":503,"context_line":"        return res.head(self, base_path\u003dbase_path)"},{"line_number":504,"context_line":""},{"line_number":505,"context_line":"    @abc.abstractmethod"},{"line_number":506,"context_line":"    def _get_cleanup_dependencies(self):"},{"line_number":507,"context_line":"        pass"},{"line_number":508,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_d26edffc","line":505,"range":{"start_line":505,"start_character":1,"end_line":505,"end_character":23},"updated":"2020-02-10 17:05:59.000000000","message":"You\u0027re forcing all proxies to implement it, even those that don\u0027t support projects at all. Why not default to `return None`?\n\nAnd IIRC using abstractmethod requires using ABCMeta as the classes\u0027s metaclass.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":502,"context_line":"        res \u003d self._get_resource(resource_type, value, **attrs)"},{"line_number":503,"context_line":"        return res.head(self, base_path\u003dbase_path)"},{"line_number":504,"context_line":""},{"line_number":505,"context_line":"    @abc.abstractmethod"},{"line_number":506,"context_line":"    def _get_cleanup_dependencies(self):"},{"line_number":507,"context_line":"        pass"},{"line_number":508,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_dff43559","line":505,"range":{"start_line":505,"start_character":1,"end_line":505,"end_character":23},"in_reply_to":"3fa7e38b_b3b55b1c","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"b60820fbc9b604f421b13205d2ec8a01b0e107d6","unresolved":false,"context_lines":[{"line_number":502,"context_line":"        res \u003d self._get_resource(resource_type, value, **attrs)"},{"line_number":503,"context_line":"        return res.head(self, base_path\u003dbase_path)"},{"line_number":504,"context_line":""},{"line_number":505,"context_line":"    @abc.abstractmethod"},{"line_number":506,"context_line":"    def _get_cleanup_dependencies(self):"},{"line_number":507,"context_line":"        pass"},{"line_number":508,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_b3b55b1c","line":505,"range":{"start_line":505,"start_character":1,"end_line":505,"end_character":23},"in_reply_to":"3fa7e38b_d26edffc","updated":"2020-02-11 08:36:34.000000000","message":"agree, will change that","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":506,"context_line":"    def _get_cleanup_dependencies(self):"},{"line_number":507,"context_line":"        pass"},{"line_number":508,"context_line":""},{"line_number":509,"context_line":"    @abc.abstractmethod"},{"line_number":510,"context_line":"    def _service_cleanup(self, dry_run\u003dTrue, status_queue\u003dNone):"},{"line_number":511,"context_line":"        pass"},{"line_number":512,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_7277ebd3","line":509,"updated":"2020-02-10 17:05:59.000000000","message":"ditto","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":506,"context_line":"    def _get_cleanup_dependencies(self):"},{"line_number":507,"context_line":"        pass"},{"line_number":508,"context_line":""},{"line_number":509,"context_line":"    @abc.abstractmethod"},{"line_number":510,"context_line":"    def _service_cleanup(self, dry_run\u003dTrue, status_queue\u003dNone):"},{"line_number":511,"context_line":"        pass"},{"line_number":512,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_fff1f165","line":509,"in_reply_to":"3fa7e38b_7277ebd3","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":518,"context_line":"            try:"},{"line_number":519,"context_line":"                del_fn(obj)"},{"line_number":520,"context_line":"            except exceptions.SDKException:"},{"line_number":521,"context_line":"                self.log.error(\u0027Cannot delete resource\u0027)"},{"line_number":522,"context_line":""},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"def _json_response(response, result_key\u003dNone, error_message\u003dNone):"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_52318f09","line":521,"updated":"2020-02-10 17:05:59.000000000","message":"Since you\u0027re silencing the error, let us log both obj and the actual exception.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":518,"context_line":"            try:"},{"line_number":519,"context_line":"                del_fn(obj)"},{"line_number":520,"context_line":"            except exceptions.SDKException:"},{"line_number":521,"context_line":"                self.log.error(\u0027Cannot delete resource\u0027)"},{"line_number":522,"context_line":""},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"def _json_response(response, result_key\u003dNone, error_message\u003dNone):"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_9f8c7ddf","line":521,"in_reply_to":"3fa7e38b_52318f09","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"254208cea787ad0628f7079c67ed4addccdac194","unresolved":false,"context_lines":[{"line_number":515,"context_line":"            try:"},{"line_number":516,"context_line":"                del_fn(obj)"},{"line_number":517,"context_line":"            except exceptions.SDKException as e:"},{"line_number":518,"context_line":"                self.log.error(\u0027Cannot delete resource %s: %s\u0027, obj, str(e))"},{"line_number":519,"context_line":""},{"line_number":520,"context_line":""},{"line_number":521,"context_line":"def _json_response(response, result_key\u003dNone, error_message\u003dNone):"}],"source_content_type":"text/x-python","patch_set":10,"id":"3fa7e38b_d56f065f","line":518,"updated":"2020-02-20 13:07:22.000000000","message":"nit: str() not needed, implied by %s","commit_id":"d31c31c739050249cc75e9b392377dcb54059463"}],"openstack/utils.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":194,"context_line":"    return discover.version_to_string(result)"},{"line_number":195,"context_line":""},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"class TinyDAG(six.Iterator):"},{"line_number":198,"context_line":"    \"\"\"Tiny DAG"},{"line_number":199,"context_line":""},{"line_number":200,"context_line":"    Bases on the Kahn\u0027s algorithm, and enables parallel visiting of the nodes"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_123797ff","line":197,"updated":"2020-02-10 17:05:59.000000000","message":"I wonder if there is a ready-to-use library.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"b60820fbc9b604f421b13205d2ec8a01b0e107d6","unresolved":false,"context_lines":[{"line_number":194,"context_line":"    return discover.version_to_string(result)"},{"line_number":195,"context_line":""},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"class TinyDAG(six.Iterator):"},{"line_number":198,"context_line":"    \"\"\"Tiny DAG"},{"line_number":199,"context_line":""},{"line_number":200,"context_line":"    Bases on the Kahn\u0027s algorithm, and enables parallel visiting of the nodes"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_935fffe2","line":197,"in_reply_to":"3fa7e38b_123797ff","updated":"2020-02-11 08:36:34.000000000","message":"Well, there are similar libraries, but:\n1) I was not able to find one, which would allow parallel walking\n2) using \"unmaintaned\" libs is not good\n3) pulling big maintainer lib for this amount of code is not reasonable\n4) due to specific processing pattern better to have it under our control\n\n-\u003e I was doing investigation and came to conclusion, that it is better to have own impl","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":203,"context_line":""},{"line_number":204,"context_line":"    def __init__(self, data\u003dNone):"},{"line_number":205,"context_line":"        self._reset()"},{"line_number":206,"context_line":"        self._lock \u003d threading.Lock()"},{"line_number":207,"context_line":"        if data and isinstance(data, dict):"},{"line_number":208,"context_line":"            self.from_dict(data)"},{"line_number":209,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_b208032e","line":206,"range":{"start_line":206,"start_character":21,"end_line":206,"end_character":37},"updated":"2020-02-10 17:05:59.000000000","message":"Similarly to my earlier comment, we shouldn\u0027t assume normal threading (or monkey patching). Actually, using Queue assumes it as well (and removes the requirement of a Lock).","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":212,"context_line":"        self._in_degree \u003d dict()"},{"line_number":213,"context_line":"        self._wait_timeout \u003d 120"},{"line_number":214,"context_line":""},{"line_number":215,"context_line":"    def get_graph(self):"},{"line_number":216,"context_line":"        \"\"\"Get graph as adjacency dict"},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        return self._graph"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_78e34d3b","line":215,"updated":"2020-02-10 17:05:59.000000000","message":"nit:\n\n @property\n def graph(self)","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":212,"context_line":"        self._in_degree \u003d dict()"},{"line_number":213,"context_line":"        self._wait_timeout \u003d 120"},{"line_number":214,"context_line":""},{"line_number":215,"context_line":"    def get_graph(self):"},{"line_number":216,"context_line":"        \"\"\"Get graph as adjacency dict"},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        return self._graph"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_bf9139f9","line":215,"in_reply_to":"3fa7e38b_78e34d3b","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":218,"context_line":"        return self._graph"},{"line_number":219,"context_line":""},{"line_number":220,"context_line":"    def add_node(self, node):"},{"line_number":221,"context_line":"        if node not in self._graph:"},{"line_number":222,"context_line":"            self._graph[node] \u003d set()"},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"    def add_edge(self, u, v):"},{"line_number":225,"context_line":"        self._graph[u].add(v)"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_f8917d9c","line":222,"range":{"start_line":221,"start_character":0,"end_line":222,"end_character":37},"updated":"2020-02-10 17:05:59.000000000","message":"nit:\n\n self._graph.setdefault(node, set())","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":218,"context_line":"        return self._graph"},{"line_number":219,"context_line":""},{"line_number":220,"context_line":"    def add_node(self, node):"},{"line_number":221,"context_line":"        if node not in self._graph:"},{"line_number":222,"context_line":"            self._graph[node] \u003d set()"},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"    def add_edge(self, u, v):"},{"line_number":225,"context_line":"        self._graph[u].add(v)"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_5f9605f1","line":222,"range":{"start_line":221,"start_character":0,"end_line":222,"end_character":37},"in_reply_to":"3fa7e38b_f8917d9c","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":226,"context_line":""},{"line_number":227,"context_line":"    def from_dict(self, data):"},{"line_number":228,"context_line":"        for k in data.keys():"},{"line_number":229,"context_line":"            self.add_node(k)"},{"line_number":230,"context_line":"        for k, v in data.items():"},{"line_number":231,"context_line":"            for dep in v:"},{"line_number":232,"context_line":"                self.add_edge(k, dep)"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_78ccadbd","line":229,"range":{"start_line":229,"start_character":0,"end_line":229,"end_character":28},"updated":"2020-02-10 17:05:59.000000000","message":"nit: can be merged in the next loop, no need to traverse the dict twice.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":226,"context_line":""},{"line_number":227,"context_line":"    def from_dict(self, data):"},{"line_number":228,"context_line":"        for k in data.keys():"},{"line_number":229,"context_line":"            self.add_node(k)"},{"line_number":230,"context_line":"        for k, v in data.items():"},{"line_number":231,"context_line":"            for dep in v:"},{"line_number":232,"context_line":"                self.add_edge(k, dep)"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_7f9bc115","line":229,"range":{"start_line":229,"start_character":0,"end_line":229,"end_character":28},"in_reply_to":"3fa7e38b_78ccadbd","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":235,"context_line":"        \"\"\"Start the walking"},{"line_number":236,"context_line":"        \"\"\""},{"line_number":237,"context_line":"        if timeout:"},{"line_number":238,"context_line":"            self._wait_timeout \u003d timeout"},{"line_number":239,"context_line":"        return self"},{"line_number":240,"context_line":""},{"line_number":241,"context_line":"    def __iter__(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_180a591d","line":238,"range":{"start_line":238,"start_character":0,"end_line":238,"end_character":40},"updated":"2020-02-10 17:05:59.000000000","message":"Why cannot we do this in __init__? I don\u0027t see a point in this function, to be honest..","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":235,"context_line":"        \"\"\"Start the walking"},{"line_number":236,"context_line":"        \"\"\""},{"line_number":237,"context_line":"        if timeout:"},{"line_number":238,"context_line":"            self._wait_timeout \u003d timeout"},{"line_number":239,"context_line":"        return self"},{"line_number":240,"context_line":""},{"line_number":241,"context_line":"    def __iter__(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_1f808d9d","line":238,"range":{"start_line":238,"start_character":0,"end_line":238,"end_character":40},"in_reply_to":"3fa7e38b_180a591d","updated":"2020-02-18 08:52:49.000000000","message":"because normally you might want to go through the DAG multiple times - this is an entry point. Iterator can be also used, but ideally \"walk\" should be used, especially if using timeout","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":243,"context_line":"        return self"},{"line_number":244,"context_line":""},{"line_number":245,"context_line":"    def __next__(self):"},{"line_number":246,"context_line":"        with self._lock:"},{"line_number":247,"context_line":"            # Thread safety - do not start to wait, if we already returned"},{"line_number":248,"context_line":"            # overall size (start waiting before thread completes task)"},{"line_number":249,"context_line":"            size \u003d len(self._graph.keys())"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_9875e999","line":246,"updated":"2020-02-10 17:05:59.000000000","message":"Seems not needed. Queue is thread-safe, len() is likely pseudo-atomic because of GIL.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"b60820fbc9b604f421b13205d2ec8a01b0e107d6","unresolved":false,"context_lines":[{"line_number":243,"context_line":"        return self"},{"line_number":244,"context_line":""},{"line_number":245,"context_line":"    def __next__(self):"},{"line_number":246,"context_line":"        with self._lock:"},{"line_number":247,"context_line":"            # Thread safety - do not start to wait, if we already returned"},{"line_number":248,"context_line":"            # overall size (start waiting before thread completes task)"},{"line_number":249,"context_line":"            size \u003d len(self._graph.keys())"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_d3f577ca","line":246,"in_reply_to":"3fa7e38b_9875e999","updated":"2020-02-11 08:36:34.000000000","message":"I will test without lock. I was fighting with some corner cases in case of multiple processor threads, but not sure now whether this was to solve one of them","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":243,"context_line":"        return self"},{"line_number":244,"context_line":""},{"line_number":245,"context_line":"    def __next__(self):"},{"line_number":246,"context_line":"        with self._lock:"},{"line_number":247,"context_line":"            # Thread safety - do not start to wait, if we already returned"},{"line_number":248,"context_line":"            # overall size (start waiting before thread completes task)"},{"line_number":249,"context_line":"            size \u003d len(self._graph.keys())"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_ff7491cf","line":246,"in_reply_to":"3fa7e38b_d3f577ca","updated":"2020-02-18 08:52:49.000000000","message":"Well, difficult topic.\n1) I personally prefer to write a readable code, which can be understood without knowing deep shortcuts (not against using them for critical performance paths)\n2) corner case is when multiple threads start fighting/waiting for last entry, where there are less possible items, than workers. The condition inside helps here, but still require atomic check.\n3) the condition might be reworked and lock removed, but it becomes much worse in readability\n4) simply removing lock does not help - from time to time it fails","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":246,"context_line":"        with self._lock:"},{"line_number":247,"context_line":"            # Thread safety - do not start to wait, if we already returned"},{"line_number":248,"context_line":"            # overall size (start waiting before thread completes task)"},{"line_number":249,"context_line":"            size \u003d len(self._graph.keys())"},{"line_number":250,"context_line":"            if (not self._queue.empty()"},{"line_number":251,"context_line":"                    or ("},{"line_number":252,"context_line":"                        # We excpect something might still appear"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_b8122555","line":249,"updated":"2020-02-10 17:05:59.000000000","message":"nit: keys() redundant","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":247,"context_line":"            # Thread safety - do not start to wait, if we already returned"},{"line_number":248,"context_line":"            # overall size (start waiting before thread completes task)"},{"line_number":249,"context_line":"            size \u003d len(self._graph.keys())"},{"line_number":250,"context_line":"            if (not self._queue.empty()"},{"line_number":251,"context_line":"                    or ("},{"line_number":252,"context_line":"                        # We excpect something might still appear"},{"line_number":253,"context_line":"                        self._retrieved \u003c size)):"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_38187570","line":250,"updated":"2020-02-10 17:05:59.000000000","message":"nit: _queue should be initialized in __init__","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":247,"context_line":"            # Thread safety - do not start to wait, if we already returned"},{"line_number":248,"context_line":"            # overall size (start waiting before thread completes task)"},{"line_number":249,"context_line":"            size \u003d len(self._graph.keys())"},{"line_number":250,"context_line":"            if (not self._queue.empty()"},{"line_number":251,"context_line":"                    or ("},{"line_number":252,"context_line":"                        # We excpect something might still appear"},{"line_number":253,"context_line":"                        self._retrieved \u003c size)):"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_7f42e169","line":250,"in_reply_to":"3fa7e38b_38187570","updated":"2020-02-18 08:52:49.000000000","message":"initialized in _start_traverse, since we can walk multiple times through the graph","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":259,"context_line":"                    return res"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"                except queue.Empty:"},{"line_number":262,"context_line":"                    raise exceptions.SDKException(\u0027Timeout\u0027)"},{"line_number":263,"context_line":"            else:"},{"line_number":264,"context_line":"                raise StopIteration"},{"line_number":265,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_386635f2","line":262,"updated":"2020-02-10 17:05:59.000000000","message":"This definitely needs a better error message, how should an admin react to this?","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":259,"context_line":"                    return res"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"                except queue.Empty:"},{"line_number":262,"context_line":"                    raise exceptions.SDKException(\u0027Timeout\u0027)"},{"line_number":263,"context_line":"            else:"},{"line_number":264,"context_line":"                raise StopIteration"},{"line_number":265,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_1f572d2b","line":262,"in_reply_to":"3fa7e38b_386635f2","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    def _get_in_degree(self):"},{"line_number":287,"context_line":"        \"\"\"Calculate the in_degree (conunt incoming) for nodes\"\"\""},{"line_number":288,"context_line":"        if not self._in_degree:"},{"line_number":289,"context_line":"            self._in_degree \u003d {u: 0 for u in self._graph.keys()}"},{"line_number":290,"context_line":"            for u in self._graph:"},{"line_number":291,"context_line":"                for v in self._graph[u]:"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_f86dfd99","line":288,"range":{"start_line":288,"start_character":15,"end_line":288,"end_character":30},"updated":"2020-02-10 17:05:59.000000000","message":"you don\u0027t seem to use self._in_degree anywhere else, maybe use a local variable and avoid copy() in start_traverse?","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"254208cea787ad0628f7079c67ed4addccdac194","unresolved":false,"context_lines":[{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    def _get_in_degree(self):"},{"line_number":287,"context_line":"        \"\"\"Calculate the in_degree (conunt incoming) for nodes\"\"\""},{"line_number":288,"context_line":"        if not self._in_degree:"},{"line_number":289,"context_line":"            self._in_degree \u003d {u: 0 for u in self._graph.keys()}"},{"line_number":290,"context_line":"            for u in self._graph:"},{"line_number":291,"context_line":"                for v in self._graph[u]:"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_55df960a","line":288,"range":{"start_line":288,"start_character":15,"end_line":288,"end_character":30},"in_reply_to":"3fa7e38b_3f546923","updated":"2020-02-20 13:07:22.000000000","message":"Doesn\u0027t seem done?","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"f27dd8efc58552d92f06c9e7856e12680e29b06f","unresolved":false,"context_lines":[{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    def _get_in_degree(self):"},{"line_number":287,"context_line":"        \"\"\"Calculate the in_degree (conunt incoming) for nodes\"\"\""},{"line_number":288,"context_line":"        if not self._in_degree:"},{"line_number":289,"context_line":"            self._in_degree \u003d {u: 0 for u in self._graph.keys()}"},{"line_number":290,"context_line":"            for u in self._graph:"},{"line_number":291,"context_line":"                for v in self._graph[u]:"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_609d32b9","line":288,"range":{"start_line":288,"start_character":15,"end_line":288,"end_character":30},"in_reply_to":"3fa7e38b_55df960a","updated":"2020-02-20 13:37:29.000000000","message":"well, right, not done in this sense. Instead I have rechecked, that there is need for _in_degree for each \"traverse\" run (might be multiple). And thus - _get_in_degree fills the structure for the current state of graph and _start_traverse get\u0027s a runtime copy, since it needs to alter it upon \"node_done\". When we add additional node/edge - we invalidate _in_degree.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    def _get_in_degree(self):"},{"line_number":287,"context_line":"        \"\"\"Calculate the in_degree (conunt incoming) for nodes\"\"\""},{"line_number":288,"context_line":"        if not self._in_degree:"},{"line_number":289,"context_line":"            self._in_degree \u003d {u: 0 for u in self._graph.keys()}"},{"line_number":290,"context_line":"            for u in self._graph:"},{"line_number":291,"context_line":"                for v in self._graph[u]:"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_3f546923","line":288,"range":{"start_line":288,"start_character":15,"end_line":288,"end_character":30},"in_reply_to":"3fa7e38b_f86dfd99","updated":"2020-02-18 08:52:49.000000000","message":"Done","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":293,"context_line":""},{"line_number":294,"context_line":"        return self._in_degree"},{"line_number":295,"context_line":""},{"line_number":296,"context_line":"    def topological_sort(self):"},{"line_number":297,"context_line":"        \"\"\"Return the graph nodes in the topological order\"\"\""},{"line_number":298,"context_line":"        result \u003d []"},{"line_number":299,"context_line":"        for node in self:"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_f8a89dda","line":296,"updated":"2020-02-10 17:05:59.000000000","message":"nit: maybe use \"pop\" in the name since it actually modifies the object.","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"74c86426e569721aa5eba56e31f8bcebd85e3eef","unresolved":false,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"        return result"},{"line_number":304,"context_line":""},{"line_number":305,"context_line":"    def size(self):"},{"line_number":306,"context_line":"        return len(self._graph.keys())"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_1861f9d4","line":305,"updated":"2020-02-10 17:05:59.000000000","message":"Maybe use the standard __len__ contract?","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"8108a6955a6f80d55aa81a5a0387b7b831ecfc77","unresolved":false,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"        return result"},{"line_number":304,"context_line":""},{"line_number":305,"context_line":"    def size(self):"},{"line_number":306,"context_line":"        return len(self._graph.keys())"}],"source_content_type":"text/x-python","patch_set":7,"id":"3fa7e38b_7f3741ff","line":305,"in_reply_to":"3fa7e38b_1861f9d4","updated":"2020-02-18 08:52:49.000000000","message":"I prefer to use public methods, rather than internal implementation of the \"foreign\" stuff (unless definitely required)","commit_id":"e1d658aee7a026fd898c90468033d69f24c97114"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"254208cea787ad0628f7079c67ed4addccdac194","unresolved":false,"context_lines":[{"line_number":219,"context_line":"        return self._graph"},{"line_number":220,"context_line":""},{"line_number":221,"context_line":"    def add_node(self, node):"},{"line_number":222,"context_line":"        if node not in self._graph:"},{"line_number":223,"context_line":"            self._graph.setdefault(node, set())"},{"line_number":224,"context_line":"        # reset in_degree for safety"},{"line_number":225,"context_line":"        self._in_degree \u003d None"}],"source_content_type":"text/x-python","patch_set":10,"id":"3fa7e38b_5591d644","line":222,"range":{"start_line":222,"start_character":0,"end_line":222,"end_character":35},"updated":"2020-02-20 13:07:22.000000000","message":"This line can be removed, it\u0027s what setdefault does","commit_id":"d31c31c739050249cc75e9b392377dcb54059463"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"f27dd8efc58552d92f06c9e7856e12680e29b06f","unresolved":false,"context_lines":[{"line_number":219,"context_line":"        return self._graph"},{"line_number":220,"context_line":""},{"line_number":221,"context_line":"    def add_node(self, node):"},{"line_number":222,"context_line":"        if node not in self._graph:"},{"line_number":223,"context_line":"            self._graph.setdefault(node, set())"},{"line_number":224,"context_line":"        # reset in_degree for safety"},{"line_number":225,"context_line":"        self._in_degree \u003d None"}],"source_content_type":"text/x-python","patch_set":10,"id":"3fa7e38b_80794e82","line":222,"range":{"start_line":222,"start_character":0,"end_line":222,"end_character":35},"in_reply_to":"3fa7e38b_5591d644","updated":"2020-02-20 13:37:29.000000000","message":"I wonder I commited it in this state :D","commit_id":"d31c31c739050249cc75e9b392377dcb54059463"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"254208cea787ad0628f7079c67ed4addccdac194","unresolved":false,"context_lines":[{"line_number":272,"context_line":""},{"line_number":273,"context_line":"    def node_done(self, node):"},{"line_number":274,"context_line":"        \"\"\"Mark node as \"processed\" and put following items into the queue\"\"\""},{"line_number":275,"context_line":"        self._done.add(node)"},{"line_number":276,"context_line":""},{"line_number":277,"context_line":"        for v in self._graph[node]:"},{"line_number":278,"context_line":"            self._run_in_degree[v] -\u003d 1"}],"source_content_type":"text/x-python","patch_set":10,"id":"3fa7e38b_35ed3ab9","line":275,"updated":"2020-02-20 13:07:22.000000000","message":"You need to use self._lock in this function, that\u0027s the place that actually races with __next__. Otherwise the lock is useless.","commit_id":"d31c31c739050249cc75e9b392377dcb54059463"},{"author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"change_message_id":"f27dd8efc58552d92f06c9e7856e12680e29b06f","unresolved":false,"context_lines":[{"line_number":272,"context_line":""},{"line_number":273,"context_line":"    def node_done(self, node):"},{"line_number":274,"context_line":"        \"\"\"Mark node as \"processed\" and put following items into the queue\"\"\""},{"line_number":275,"context_line":"        self._done.add(node)"},{"line_number":276,"context_line":""},{"line_number":277,"context_line":"        for v in self._graph[node]:"},{"line_number":278,"context_line":"            self._run_in_degree[v] -\u003d 1"}],"source_content_type":"text/x-python","patch_set":10,"id":"3fa7e38b_f5fa4210","line":275,"in_reply_to":"3fa7e38b_35ed3ab9","updated":"2020-02-20 13:37:29.000000000","message":"You are right - lock need to be here as well","commit_id":"d31c31c739050249cc75e9b392377dcb54059463"}]}
