)]}'
{"neutron/common/utils.py":[{"author":{"_account_id":5948,"name":"Oleg Bondarev","email":"obondarev@mirantis.com","username":"obondarev"},"change_message_id":"4e8b3c6598114a43288bbc1799b78d75925c6b36","unresolved":false,"context_lines":[{"line_number":44,"context_line":""},{"line_number":45,"context_line":"def cache_method_results(name\u003dNone, cache_ttl\u003dNone):"},{"line_number":46,"context_line":"    def wrap_func(func):"},{"line_number":47,"context_line":"        if name is None:"},{"line_number":48,"context_line":"            func_name \u003d func.__name__"},{"line_number":49,"context_line":"        else:"},{"line_number":50,"context_line":"            func_name \u003d name"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAUX%2F%2FlCs%3D","line":47,"updated":"2014-02-12 08:29:37.000000000","message":"func_name \u003d name or func.__name__","commit_id":"47e155da4b4d2ca320f90522345147d008591716"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"07ff0bce6a5c303469a4850674f85407194a5c99","unresolved":false,"context_lines":[{"line_number":44,"context_line":""},{"line_number":45,"context_line":"def cache_method_results(name\u003dNone, cache_ttl\u003dNone):"},{"line_number":46,"context_line":"    def wrap_func(func):"},{"line_number":47,"context_line":"        if name is None:"},{"line_number":48,"context_line":"            func_name \u003d func.__name__"},{"line_number":49,"context_line":"        else:"},{"line_number":50,"context_line":"            func_name \u003d name"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAUX%2F%2Fk6s%3D","line":47,"in_reply_to":"AAAAUX%2F%2FlCs%3D","updated":"2014-02-12 09:16:19.000000000","message":"Done","commit_id":"47e155da4b4d2ca320f90522345147d008591716"},{"author":{"_account_id":5948,"name":"Oleg Bondarev","email":"obondarev@mirantis.com","username":"obondarev"},"change_message_id":"4e8b3c6598114a43288bbc1799b78d75925c6b36","unresolved":false,"context_lines":[{"line_number":55,"context_line":"            if not args or not hasattr(self, \u0027_cache\u0027):"},{"line_number":56,"context_line":"                return func(*args, **kwargs)"},{"line_number":57,"context_line":""},{"line_number":58,"context_line":"            key \u003d (func_name,) + args"},{"line_number":59,"context_line":"            try:"},{"line_number":60,"context_line":"                item \u003d self._cache.get(key)"},{"line_number":61,"context_line":"            except TypeError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAUX%2F%2Fk9o%3D","line":58,"updated":"2014-02-12 08:29:37.000000000","message":"Still have a concern regarding the key which doesn\u0027t include kwargs in any way. Consider following example:\n\n @cache_method_results()\n def _method1(self, a, b):\n  ...\n def method2(self):\n  x \u003d self._method1(1, b\u003d2)\n  ...\n  y \u003d self._method1(1, b\u003d3)\nThe result for y will be served from the cache which is wrong. Am I missing smth?","commit_id":"47e155da4b4d2ca320f90522345147d008591716"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"07ff0bce6a5c303469a4850674f85407194a5c99","unresolved":false,"context_lines":[{"line_number":55,"context_line":"            if not args or not hasattr(self, \u0027_cache\u0027):"},{"line_number":56,"context_line":"                return func(*args, **kwargs)"},{"line_number":57,"context_line":""},{"line_number":58,"context_line":"            key \u003d (func_name,) + args"},{"line_number":59,"context_line":"            try:"},{"line_number":60,"context_line":"                item \u003d self._cache.get(key)"},{"line_number":61,"context_line":"            except TypeError:"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAUX%2F%2Fk6w%3D","line":58,"in_reply_to":"AAAAUX%2F%2Fk9o%3D","updated":"2014-02-12 09:16:19.000000000","message":"you\u0027re right. I was missing something :)","commit_id":"47e155da4b4d2ca320f90522345147d008591716"},{"author":{"_account_id":8788,"name":"Miguel Angel Ajo","email":"mangelajo@redhat.com","username":"mangelajo"},"change_message_id":"76962151c309f1d1ad2ce5d6069b6b6e3cdcbbea","unresolved":false,"context_lines":[{"line_number":45,"context_line":"def dict2tuple(d):"},{"line_number":46,"context_line":"    items \u003d d.items()"},{"line_number":47,"context_line":"    items.sort(key\u003dlambda x: x[0])"},{"line_number":48,"context_line":"    return tuple(items)"},{"line_number":49,"context_line":""},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"def cache_method_results(name\u003dNone, cache_ttl\u003dNone):"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAAUX%2F%2BnfQ%3D","line":48,"updated":"2014-02-20 07:08:52.000000000","message":"We have a common.utils in python with lost of functions like this one,\n\n(dict2str, etc..). may be you could put this one there.","commit_id":"2cc9a55e550a5317f1eab5abc63c721d94258d6c"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"5b808bd7e5189f6d9974dd33a586f55dba65c676","unresolved":false,"context_lines":[{"line_number":45,"context_line":"def dict2tuple(d):"},{"line_number":46,"context_line":"    items \u003d d.items()"},{"line_number":47,"context_line":"    items.sort(key\u003dlambda x: x[0])"},{"line_number":48,"context_line":"    return tuple(items)"},{"line_number":49,"context_line":""},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"def cache_method_results(name\u003dNone, cache_ttl\u003dNone):"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAAUX%2F%2Bl48%3D","line":48,"in_reply_to":"AAAAUX%2F%2BnfQ%3D","updated":"2014-02-20 11:28:11.000000000","message":"I don\u0027t understand, this module is neutron.common.utils.","commit_id":"2cc9a55e550a5317f1eab5abc63c721d94258d6c"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"742a53d53cb60b7d0f07cbf551bd266dedb5af64","unresolved":false,"context_lines":[{"line_number":63,"context_line":"                key +\u003d dict2tuple(kwargs)"},{"line_number":64,"context_line":"            try:"},{"line_number":65,"context_line":"                item \u003d self._cache.get(key)"},{"line_number":66,"context_line":"            except TypeError:"},{"line_number":67,"context_line":"                return func(self, *args, **kwargs)"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"            if item is None:"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAAUX%2F%2Bnik%3D","line":66,"updated":"2014-02-20 07:03:12.000000000","message":"I don\u0027t think the error handling here is sufficient.  If for some reason a client of this decorator ends up passing an unhashable type as an argument, is it really desirable to silently stop caching?  I would expect an error to be logged, at least, so that the problem could be discovered.\n\nAn alternate approach might be to ensure that nested unhashable types are stringified (e.g. by jsonifying the kwargs) before being added to the key to ensure that TypeError will not occur.","commit_id":"2cc9a55e550a5317f1eab5abc63c721d94258d6c"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"5b808bd7e5189f6d9974dd33a586f55dba65c676","unresolved":false,"context_lines":[{"line_number":63,"context_line":"                key +\u003d dict2tuple(kwargs)"},{"line_number":64,"context_line":"            try:"},{"line_number":65,"context_line":"                item \u003d self._cache.get(key)"},{"line_number":66,"context_line":"            except TypeError:"},{"line_number":67,"context_line":"                return func(self, *args, **kwargs)"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"            if item is None:"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAAUX%2F%2BlVE%3D","line":66,"in_reply_to":"AAAAUX%2F%2Bnik%3D","updated":"2014-02-20 11:28:11.000000000","message":"I agree with logging, I\u0027m not sure about the stringifying - passed parameters could be complex objects containing unhashable attributes (lists, dicts). This applies also on args.","commit_id":"2cc9a55e550a5317f1eab5abc63c721d94258d6c"},{"author":{"_account_id":8788,"name":"Miguel Angel Ajo","email":"mangelajo@redhat.com","username":"mangelajo"},"change_message_id":"2b5f4457d9b604fdb0461ac26bea59e6b8be16bd","unresolved":false,"context_lines":[{"line_number":63,"context_line":"                key +\u003d dict2tuple(kwargs)"},{"line_number":64,"context_line":"            try:"},{"line_number":65,"context_line":"                item \u003d self._cache.get(key)"},{"line_number":66,"context_line":"            except TypeError:"},{"line_number":67,"context_line":"                return func(self, *args, **kwargs)"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"            if item is None:"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAAUX%2F%2Bngs%3D","line":66,"in_reply_to":"AAAAUX%2F%2Bnik%3D","updated":"2014-02-20 07:07:44.000000000","message":"What Maru said is a very good point.","commit_id":"2cc9a55e550a5317f1eab5abc63c721d94258d6c"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"c7ee948c2bb1bdd8e9291dfa2adabf7c1600e180","unresolved":false,"context_lines":[{"line_number":56,"context_line":"        @functools.wraps(func)"},{"line_number":57,"context_line":"        def get_from_cache(self, *args, **kwargs):"},{"line_number":58,"context_line":"            if not args or not hasattr(self, \u0027_cache\u0027):"},{"line_number":59,"context_line":"                return func(*args, **kwargs)"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"            key \u003d (func_name,) + args"},{"line_number":62,"context_line":"            if kwargs:"}],"source_content_type":"text/x-python","patch_set":5,"id":"AAAAUX%2F%2BiIQ%3D","line":59,"updated":"2014-02-20 17:04:00.000000000","message":"Missing self","commit_id":"3cb7af8238fb784f65ec5255041bdb85befb895e"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"053b4e5a3efd34e289a5ef37ca291eb9520caacd","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAAU3%2F%2F6Yg%3D","line":70,"updated":"2014-02-24 05:04:46.000000000","message":"Given that a name parameter can override func.__name, shouldn\u0027t this be func_name?","commit_id":"dfd3909ff47a8284d6365bf0bf74eb3d836495b2"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"041c690d9ef07dc0b08dead95780dd1df596ab16","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAAU3%2F%2F5f8%3D","line":70,"in_reply_to":"AAAAU3%2F%2F6Yg%3D","updated":"2014-02-24 07:34:59.000000000","message":"Depends, I thought func.__name__ would be easier to debug because when method is called in the code func.__name__ is used and its name passed to decorator is only at the method definition.\n\nIf you think func_name would be better, I will change it.","commit_id":"dfd3909ff47a8284d6365bf0bf74eb3d836495b2"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"d7cd0b57ba3ce283ec204f73f90847ddaf25ee1c","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    return tuple(items)"},{"line_number":49,"context_line":""},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"def cache_method_results(name\u003dNone, cache_ttl\u003dNone):"},{"line_number":52,"context_line":"    def wrap_func(func):"},{"line_number":53,"context_line":"        func_name \u003d name or func.__name__"},{"line_number":54,"context_line":"        ttl \u003d cache_ttl"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2FzVg%3D","line":51,"updated":"2014-02-24 18:12:01.000000000","message":"Neither of these parameters are used by the follow-on patch, so I invoke YAGNI and suggest you remove them.\n\nReference: http://c2.com/xp/YouArentGonnaNeedIt.html","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"3bc17d9b5f703d84603d189368873fa24a0d0f97","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    return tuple(items)"},{"line_number":49,"context_line":""},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"def cache_method_results(name\u003dNone, cache_ttl\u003dNone):"},{"line_number":52,"context_line":"    def wrap_func(func):"},{"line_number":53,"context_line":"        func_name \u003d name or func.__name__"},{"line_number":54,"context_line":"        ttl \u003d cache_ttl"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2FpIg%3D","line":51,"in_reply_to":"AAAAU3%2F%2FzVg%3D","updated":"2014-02-25 14:09:46.000000000","message":"Done","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"d7cd0b57ba3ce283ec204f73f90847ddaf25ee1c","unresolved":false,"context_lines":[{"line_number":55,"context_line":""},{"line_number":56,"context_line":"        @functools.wraps(func)"},{"line_number":57,"context_line":"        def get_from_cache(self, *args, **kwargs):"},{"line_number":58,"context_line":"            if not hasattr(self, \u0027_cache\u0027):"},{"line_number":59,"context_line":"                return func(self, *args, **kwargs)"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"            key \u003d (func_name,) + args"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2FzTA%3D","line":58,"updated":"2014-02-24 18:12:01.000000000","message":"Would it make sense to log the fact that caching is disabled the first time this gets hit?","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"3bc17d9b5f703d84603d189368873fa24a0d0f97","unresolved":false,"context_lines":[{"line_number":55,"context_line":""},{"line_number":56,"context_line":"        @functools.wraps(func)"},{"line_number":57,"context_line":"        def get_from_cache(self, *args, **kwargs):"},{"line_number":58,"context_line":"            if not hasattr(self, \u0027_cache\u0027):"},{"line_number":59,"context_line":"                return func(self, *args, **kwargs)"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"            key \u003d (func_name,) + args"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2FpIQ%3D","line":58,"in_reply_to":"AAAAU3%2F%2FzTA%3D","updated":"2014-02-25 14:09:46.000000000","message":"Done","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e6f863a2c620a223930ff16552aef2cd42955489","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2F5DU%3D","line":70,"updated":"2014-02-24 08:48:42.000000000","message":"There still needs to be discussed whether func_name or func.__name__ is better.","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"d7cd0b57ba3ce283ec204f73f90847ddaf25ee1c","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2FzXU%3D","line":70,"in_reply_to":"AAAAU3%2F%2F3Ho%3D","updated":"2014-02-24 18:12:01.000000000","message":"If you want unambiguous identification, I think the fully qualified module path makes sense.","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":5948,"name":"Oleg Bondarev","email":"obondarev@mirantis.com","username":"obondarev"},"change_message_id":"180a8355dc5ef2eb69abb1da50c7639a3674890d","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2F3Ho%3D","line":70,"in_reply_to":"AAAAU3%2F%2F3NI%3D","updated":"2014-02-24 13:05:11.000000000","message":"Yeah, may consider using __module__ also. Anyway let\u0027s wait for other reviewers\u0027 opinions","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"813f7647619a4cb208144e614db1e3514116e9b9","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2F3NI%3D","line":70,"in_reply_to":"AAAAU3%2F%2F3PU%3D","updated":"2014-02-24 12:57:19.000000000","message":"Yes, I did. Also class names are not unique in project, could be same name in different module or package. If my idea seems too much paranoid I can change it to class name + method name. :)\n\nBut still my opinion is that passing the name as optional parameter is the best choice and should be done by developer.","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":5948,"name":"Oleg Bondarev","email":"obondarev@mirantis.com","username":"obondarev"},"change_message_id":"4358b3e736dc709fec53a28a51ffd07886582f1a","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2F3PU%3D","line":70,"in_reply_to":"AAAAU3%2F%2F3Vk%3D","updated":"2014-02-24 12:50:15.000000000","message":"Good point. However it\u0027s probably not a best approach to make this the responsibility of a developer. Did you consider adding class name (func.im_class.__name__) along with func name to the key?","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"a0a38b606f008d380d21c882e22ce51dbb257eee","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2F3Vk%3D","line":70,"in_reply_to":"AAAAU3%2F%2F3p8%3D","updated":"2014-02-24 12:36:11.000000000","message":"I can imagine its usage for methods with same name but different class. It could cause false positive cache hits in case two methods are called with same parameters. Passing name to decorator gives programmer option to avoid such situation when methods\u0027 names are given.","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":5948,"name":"Oleg Bondarev","email":"obondarev@mirantis.com","username":"obondarev"},"change_message_id":"adb97ab9f9c10b8f7610e8a623d2cc75f75c2e9f","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2F3p8%3D","line":70,"in_reply_to":"AAAAU3%2F%2F5DU%3D","updated":"2014-02-24 12:19:21.000000000","message":"Another question is whether \u0027name\u0027 parameter is needed for the decorator at all","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"3bc17d9b5f703d84603d189368873fa24a0d0f97","unresolved":false,"context_lines":[{"line_number":67,"context_line":"                LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":68,"context_line":"                              \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":69,"context_line":"                              \"%(kwargs)s\"),"},{"line_number":70,"context_line":"                            {\u0027func_name\u0027: func.__name__,"},{"line_number":71,"context_line":"                             \u0027args\u0027: args,"},{"line_number":72,"context_line":"                             \u0027kwargs\u0027: kwargs})"},{"line_number":73,"context_line":"                return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAU3%2F%2FpH4%3D","line":70,"in_reply_to":"AAAAU3%2F%2FzXU%3D","updated":"2014-02-25 14:09:46.000000000","message":"Done","commit_id":"0d04ccd09f0531a7e074c0e1797cb6533470c5d9"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"c82506f71d46983bfbfedea71ca65fa241ec7fc4","unresolved":false,"context_lines":[{"line_number":42,"context_line":"synchronized \u003d lockutils.synchronized_with_prefix(SYNCHRONIZED_PREFIX)"},{"line_number":43,"context_line":""},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"class SingletonWrapper(object):"},{"line_number":46,"context_line":"    def __init__(self, value):"},{"line_number":47,"context_line":"        self.value \u003d value"},{"line_number":48,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2Fe18%3D","line":45,"updated":"2014-02-26 11:57:42.000000000","message":"What advantage does this class have over a simple boolean?\n\nfirst_call \u003d True\nif first_call:\n     first_call \u003d False","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"725be16f89bf148240839e9b123e615890f2acb3","unresolved":false,"context_lines":[{"line_number":42,"context_line":"synchronized \u003d lockutils.synchronized_with_prefix(SYNCHRONIZED_PREFIX)"},{"line_number":43,"context_line":""},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"class SingletonWrapper(object):"},{"line_number":46,"context_line":"    def __init__(self, value):"},{"line_number":47,"context_line":"        self.value \u003d value"},{"line_number":48,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FefE%3D","line":45,"in_reply_to":"AAAAU3%2F%2Fe18%3D","updated":"2014-02-26 12:33:52.000000000","message":"Problem is that \u0027first_call \u003d True\u0027 is in the closure and once \u0027first_call \u003d False\u0027 is called in get_from_cache(), Python creates a new reference to \u0027first_call\u0027 in the local scope of get_from_cache(). Causing \u0027if first_call:\u0027 is not declared by the time of calling because assignment is done later for the local scope variable. Maybe a docstring would be helpful here.\n\nWrapping the singletons in another object causes that first_call in get_from_cache() is used from the closure because the reference to object is still the same even in decorator function and is not changed.\n\nIf you don\u0027t like the idea of creating a new class for such a dumb thing I can rewrite the decorator using class and setting first_call boolean as attribute of this decorator class.","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"c82506f71d46983bfbfedea71ca65fa241ec7fc4","unresolved":false,"context_lines":[{"line_number":57,"context_line":"    def get_from_cache(self, *args, **kwargs):"},{"line_number":58,"context_line":"        if not hasattr(self, \u0027_cache\u0027):"},{"line_number":59,"context_line":"            if first_call:"},{"line_number":60,"context_line":"                LOG.warning(_(\"Instance of class %(class)s doesn\u0027t contain \""},{"line_number":61,"context_line":"                              \"attribute _cache therefore results are not \""},{"line_number":62,"context_line":"                              \"cached.\"), {\u0027class\u0027: self.__class__.__name__})"},{"line_number":63,"context_line":"                first_call.value \u003d False"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2Fe00%3D","line":60,"updated":"2014-02-26 11:57:42.000000000","message":"The class name should be qualified by the module name to prevent ambiguity.","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"725be16f89bf148240839e9b123e615890f2acb3","unresolved":false,"context_lines":[{"line_number":57,"context_line":"    def get_from_cache(self, *args, **kwargs):"},{"line_number":58,"context_line":"        if not hasattr(self, \u0027_cache\u0027):"},{"line_number":59,"context_line":"            if first_call:"},{"line_number":60,"context_line":"                LOG.warning(_(\"Instance of class %(class)s doesn\u0027t contain \""},{"line_number":61,"context_line":"                              \"attribute _cache therefore results are not \""},{"line_number":62,"context_line":"                              \"cached.\"), {\u0027class\u0027: self.__class__.__name__})"},{"line_number":63,"context_line":"                first_call.value \u003d False"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FebY%3D","line":60,"in_reply_to":"AAAAU3%2F%2Fe00%3D","updated":"2014-02-26 12:33:52.000000000","message":"Done","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"c82506f71d46983bfbfedea71ca65fa241ec7fc4","unresolved":false,"context_lines":[{"line_number":77,"context_line":"            LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":78,"context_line":"                          \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":79,"context_line":"                          \"%(kwargs)s\"),"},{"line_number":80,"context_line":"                        {\u0027func_name\u0027: func.__name__,"},{"line_number":81,"context_line":"                         \u0027args\u0027: args,"},{"line_number":82,"context_line":"                         \u0027kwargs\u0027: kwargs})"},{"line_number":83,"context_line":"            return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2Fe0s%3D","line":80,"updated":"2014-02-26 11:57:42.000000000","message":"func.__name__ \u003d\u003e func_name","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"725be16f89bf148240839e9b123e615890f2acb3","unresolved":false,"context_lines":[{"line_number":77,"context_line":"            LOG.warning(_(\"Method %(func_name)s cannot be cached due to \""},{"line_number":78,"context_line":"                          \"unhashable parameters: args: %(args)s, kwargs: \""},{"line_number":79,"context_line":"                          \"%(kwargs)s\"),"},{"line_number":80,"context_line":"                        {\u0027func_name\u0027: func.__name__,"},{"line_number":81,"context_line":"                         \u0027args\u0027: args,"},{"line_number":82,"context_line":"                         \u0027kwargs\u0027: kwargs})"},{"line_number":83,"context_line":"            return func(self, *args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FebQ%3D","line":80,"in_reply_to":"AAAAU3%2F%2Fe0s%3D","updated":"2014-02-26 12:33:52.000000000","message":"Done","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":2592,"name":"Mark McClain","email":"mark@mcclain.xyz","username":"markmcclain"},"change_message_id":"17e723ba3fa555fce00e2620106991e94fd62fdc","unresolved":false,"context_lines":[{"line_number":57,"context_line":"        return self.value"},{"line_number":58,"context_line":""},{"line_number":59,"context_line":""},{"line_number":60,"context_line":"def cache_method_results(func):"},{"line_number":61,"context_line":"    first_call \u003d SingletonWrapper(True)"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    @functools.wraps(func)"}],"source_content_type":"text/x-python","patch_set":11,"id":"AAAAVX%2F%2F%2BZg%3D","line":60,"updated":"2014-02-27 02:40:54.000000000","message":"Did you consider constructing the decorator as a class instead of method?  Doing so would allow you to abstract this out better.  Also this method seems to only work on methods which are bound to a class instance. Methods defined outside of a class and unbound methods will not work with decorator.","commit_id":"78f88a42ed65fc23b858661aba95128e6ce84b98"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"44fd0cab26de5a79083162d9e5b8a34bf9a3ab3f","unresolved":false,"context_lines":[{"line_number":57,"context_line":"        return self.value"},{"line_number":58,"context_line":""},{"line_number":59,"context_line":""},{"line_number":60,"context_line":"def cache_method_results(func):"},{"line_number":61,"context_line":"    first_call \u003d SingletonWrapper(True)"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    @functools.wraps(func)"}],"source_content_type":"text/x-python","patch_set":11,"id":"AAAAVX%2F%2F79o%3D","line":60,"in_reply_to":"AAAAVX%2F%2F%2BZg%3D","updated":"2014-02-27 09:11:05.000000000","message":"Yes, I considered class (mentioned in one of comments in previous patchsets). Do you want me to remake it to class?\n\nThis decorator is not intended to functions and static methods because cache must be part of instance of class due to restriction of obtaining url to cache.","commit_id":"78f88a42ed65fc23b858661aba95128e6ce84b98"},{"author":{"_account_id":841,"name":"Akihiro Motoki","email":"amotoki@gmail.com","username":"amotoki"},"change_message_id":"a7fadfda22d27d6ae1e9d741def1bdd809f4da54","unresolved":false,"context_lines":[{"line_number":57,"context_line":"        return self.value"},{"line_number":58,"context_line":""},{"line_number":59,"context_line":""},{"line_number":60,"context_line":"def cache_method_results(func):"},{"line_number":61,"context_line":"    first_call \u003d SingletonWrapper(True)"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    @functools.wraps(func)"}],"source_content_type":"text/x-python","patch_set":11,"id":"AAAAVX%2F%2FrC4%3D","line":60,"in_reply_to":"AAAAVX%2F%2F79o%3D","updated":"2014-03-01 09:07:30.000000000","message":"Please add docstring about how to use this decorator. According to the comments above, this method is only applied to class methods.","commit_id":"78f88a42ed65fc23b858661aba95128e6ce84b98"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"c66ca63020bdf69fda2ee23f1b5261a096e8f0dd","unresolved":false,"context_lines":[{"line_number":57,"context_line":"        return self.value"},{"line_number":58,"context_line":""},{"line_number":59,"context_line":""},{"line_number":60,"context_line":"def cache_method_results(func):"},{"line_number":61,"context_line":"    first_call \u003d SingletonWrapper(True)"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    @functools.wraps(func)"}],"source_content_type":"text/x-python","patch_set":11,"id":"AAAAVn%2F%2F5bA%3D","line":60,"in_reply_to":"AAAAVX%2F%2FrC4%3D","updated":"2014-03-03 15:18:27.000000000","message":"Done, also reimplemented as class per Mark\u0027s suggestion.","commit_id":"78f88a42ed65fc23b858661aba95128e6ce84b98"},{"author":{"_account_id":8788,"name":"Miguel Angel Ajo","email":"mangelajo@redhat.com","username":"mangelajo"},"change_message_id":"1b9f5faa2750d9f82a35104d44fe4376f5e8e51f","unresolved":false,"context_lines":[{"line_number":72,"context_line":"                              \"contain attribute _cache therefore results are \""},{"line_number":73,"context_line":"                              \"not cached.\"),"},{"line_number":74,"context_line":"                            {\u0027module_class\u0027: module_class_name})"},{"line_number":75,"context_line":"                first_call.value \u003d False"},{"line_number":76,"context_line":"            return func(self, *args, **kwargs)"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"        func_name \u003d \"%(module_class)s.%(func_name)s\" % {"}],"source_content_type":"text/x-python","patch_set":11,"id":"AAAAVX%2F%2FyIY%3D","line":75,"updated":"2014-02-28 10:06:28.000000000","message":"It\u0027s not possible to create the _cache if it doesn\u0027t exist?","commit_id":"78f88a42ed65fc23b858661aba95128e6ce84b98"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"6530209da5e59d2f14caa36d95ddc7463219ae6b","unresolved":false,"context_lines":[{"line_number":72,"context_line":"                              \"contain attribute _cache therefore results are \""},{"line_number":73,"context_line":"                              \"not cached.\"),"},{"line_number":74,"context_line":"                            {\u0027module_class\u0027: module_class_name})"},{"line_number":75,"context_line":"                first_call.value \u003d False"},{"line_number":76,"context_line":"            return func(self, *args, **kwargs)"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"        func_name \u003d \"%(module_class)s.%(func_name)s\" % {"}],"source_content_type":"text/x-python","patch_set":11,"id":"AAAAVX%2F%2FyB4%3D","line":75,"in_reply_to":"AAAAVX%2F%2FyIY%3D","updated":"2014-02-28 10:18:53.000000000","message":"This is for case when you don\u0027t want to have your results cached.","commit_id":"78f88a42ed65fc23b858661aba95128e6ce84b98"},{"author":{"_account_id":841,"name":"Akihiro Motoki","email":"amotoki@gmail.com","username":"amotoki"},"change_message_id":"a7fadfda22d27d6ae1e9d741def1bdd809f4da54","unresolved":false,"context_lines":[{"line_number":93,"context_line":"                         \u0027kwargs\u0027: kwargs})"},{"line_number":94,"context_line":"            return func(self, *args, **kwargs)"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        if item is None:"},{"line_number":97,"context_line":"            item \u003d func(self, *args, **kwargs)"},{"line_number":98,"context_line":"            self._cache.set(key, item, None)"},{"line_number":99,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"AAAAVX%2F%2FrC8%3D","line":96,"updated":"2014-03-01 09:07:30.000000000","message":"question: it means None is not cache. Is it the intended behavior?","commit_id":"78f88a42ed65fc23b858661aba95128e6ce84b98"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"c66ca63020bdf69fda2ee23f1b5261a096e8f0dd","unresolved":false,"context_lines":[{"line_number":93,"context_line":"                         \u0027kwargs\u0027: kwargs})"},{"line_number":94,"context_line":"            return func(self, *args, **kwargs)"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        if item is None:"},{"line_number":97,"context_line":"            item \u003d func(self, *args, **kwargs)"},{"line_number":98,"context_line":"            self._cache.set(key, item, None)"},{"line_number":99,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"AAAAVn%2F%2F5ok%3D","line":96,"in_reply_to":"AAAAVX%2F%2FrC8%3D","updated":"2014-03-03 15:18:27.000000000","message":"You mean that if function returns None then it will be in the cache but still the function would be called?\n\nIt comes from the restriction of oslo-incubator memory cache, it doesn\u0027t raise KeyError but returns \"default\" instead. I can pass a \"FakeObject\" to be returned as a default value if it\u0027s ok.","commit_id":"78f88a42ed65fc23b858661aba95128e6ce84b98"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"6dd4b9defd55f432af1b8eb96884cff40265c1cd","unresolved":false,"context_lines":[{"line_number":39,"context_line":"synchronized \u003d lockutils.synchronized_with_prefix(SYNCHRONIZED_PREFIX)"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"class CacheMethodResults(object):"},{"line_number":43,"context_line":"    \"\"\"This decorator is intended for object methods only.\"\"\""},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    def __init__(self, f):"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F378%3D","line":42,"updated":"2014-03-03 17:52:18.000000000","message":"Since this class will be used primarily as a callable, please use the convention of  will be used as a decorator, please use the naming convention for functions.  Whether you rename the class directly or create an alias (e.g. cache_method_results \u003d _CacheMethodResults) is up to you.\n\nSee: pep8 on class names","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"779e07b7417782315d334534eafe174659541937","unresolved":false,"context_lines":[{"line_number":39,"context_line":"synchronized \u003d lockutils.synchronized_with_prefix(SYNCHRONIZED_PREFIX)"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"class CacheMethodResults(object):"},{"line_number":43,"context_line":"    \"\"\"This decorator is intended for object methods only.\"\"\""},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    def __init__(self, f):"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F3t8%3D","line":42,"in_reply_to":"AAAAVn%2F%2F378%3D","updated":"2014-03-03 17:54:48.000000000","message":"Arg, retry:\n\nSince this class will be used primarily as a callable, please use the naming convention for functions. Whether you rename the class directly or create an alias (e.g. cache_method_results \u003d _CacheMethodResults) is up to you.\n\nSee: pep8 on class names","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"0837ae08725a82bee21fbf4f6b248b09b9514eb2","unresolved":false,"context_lines":[{"line_number":39,"context_line":"synchronized \u003d lockutils.synchronized_with_prefix(SYNCHRONIZED_PREFIX)"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"class CacheMethodResults(object):"},{"line_number":43,"context_line":"    \"\"\"This decorator is intended for object methods only.\"\"\""},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    def __init__(self, f):"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F3oY%3D","line":42,"in_reply_to":"AAAAVn%2F%2F3t8%3D","updated":"2014-03-03 21:08:34.000000000","message":"Done","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"6dd4b9defd55f432af1b8eb96884cff40265c1cd","unresolved":false,"context_lines":[{"line_number":48,"context_line":"        self._first_call \u003d True"},{"line_number":49,"context_line":"        self._not_cached \u003d object()"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    def _get_from_cache(self, obj_self, *args, **kwargs):"},{"line_number":52,"context_line":"        func_name \u003d \"%(module)s.%(class)s.%(func_name)s\" % {"},{"line_number":53,"context_line":"            \u0027module\u0027: obj_self.__module__,"},{"line_number":54,"context_line":"            \u0027class\u0027: obj_self.__class__.__name__,"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F4BM%3D","line":51,"updated":"2014-03-03 17:52:18.000000000","message":"(Suggestion only) obj_self -\u003e target_self","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"0837ae08725a82bee21fbf4f6b248b09b9514eb2","unresolved":false,"context_lines":[{"line_number":48,"context_line":"        self._first_call \u003d True"},{"line_number":49,"context_line":"        self._not_cached \u003d object()"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    def _get_from_cache(self, obj_self, *args, **kwargs):"},{"line_number":52,"context_line":"        func_name \u003d \"%(module)s.%(class)s.%(func_name)s\" % {"},{"line_number":53,"context_line":"            \u0027module\u0027: obj_self.__module__,"},{"line_number":54,"context_line":"            \u0027class\u0027: obj_self.__class__.__name__,"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F3oM%3D","line":51,"in_reply_to":"AAAAVn%2F%2F4BM%3D","updated":"2014-03-03 21:08:34.000000000","message":"Done","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"6dd4b9defd55f432af1b8eb96884cff40265c1cd","unresolved":false,"context_lines":[{"line_number":68,"context_line":"                         \u0027kwargs\u0027: kwargs})"},{"line_number":69,"context_line":"            return self.f(obj_self, *args, **kwargs)"},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"        if item is self._not_cached:"},{"line_number":72,"context_line":"            item \u003d self.f(obj_self, *args, **kwargs)"},{"line_number":73,"context_line":"            obj_self._cache.set(key, item, None)"},{"line_number":74,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F4AY%3D","line":71,"updated":"2014-03-03 17:52:18.000000000","message":"That reads nicely!","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"6dd4b9defd55f432af1b8eb96884cff40265c1cd","unresolved":false,"context_lines":[{"line_number":79,"context_line":"            if self._first_call:"},{"line_number":80,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""},{"line_number":81,"context_line":"                              \"contain attribute _cache therefore results are \""},{"line_number":82,"context_line":"                              \"not cached.\"),"},{"line_number":83,"context_line":"                            {\u0027module\u0027: self.__module__,"},{"line_number":84,"context_line":"                             \u0027class\u0027: self.__class__.__name__})"},{"line_number":85,"context_line":"                self._first_call \u003d False"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F3%2Fg%3D","line":82,"updated":"2014-03-03 17:52:18.000000000","message":"(Suggestion only) are not cached -\u003e cannot be cached for %(func_name)s","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"0837ae08725a82bee21fbf4f6b248b09b9514eb2","unresolved":false,"context_lines":[{"line_number":79,"context_line":"            if self._first_call:"},{"line_number":80,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""},{"line_number":81,"context_line":"                              \"contain attribute _cache therefore results are \""},{"line_number":82,"context_line":"                              \"not cached.\"),"},{"line_number":83,"context_line":"                            {\u0027module\u0027: self.__module__,"},{"line_number":84,"context_line":"                             \u0027class\u0027: self.__class__.__name__})"},{"line_number":85,"context_line":"                self._first_call \u003d False"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F3jM%3D","line":82,"in_reply_to":"AAAAVn%2F%2F3%2Fg%3D","updated":"2014-03-03 21:08:34.000000000","message":"Done","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":2031,"name":"Nachi Ueno","email":"nati.ueno@gmail.com","username":"nati-ueno"},"change_message_id":"9930e1686077aa2510826a56bd8856cfc3608633","unresolved":false,"context_lines":[{"line_number":42,"context_line":"class cache_method_results(object):"},{"line_number":43,"context_line":"    \"\"\"This decorator is intended for object methods only.\"\"\""},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    def __init__(self, f):"},{"line_number":46,"context_line":"        self.f \u003d f"},{"line_number":47,"context_line":"        functools.update_wrapper(self, f)"},{"line_number":48,"context_line":"        self._first_call \u003d True"}],"source_content_type":"text/x-python","patch_set":15,"id":"bad4c104_cdfe9c6b","line":45,"updated":"2014-04-29 20:24:16.000000000","message":"nit:f -\u003e func","commit_id":"2b3a4516227615ece4468672e7330969b751dcce"},{"author":{"_account_id":2592,"name":"Mark McClain","email":"mark@mcclain.xyz","username":"markmcclain"},"change_message_id":"31a533cc8469554629be95f9af56a0d2ccf894da","unresolved":false,"context_lines":[{"line_number":77,"context_line":"    def __call__(self, target_self, *args, **kwargs):"},{"line_number":78,"context_line":"        if not hasattr(target_self, \u0027_cache\u0027):"},{"line_number":79,"context_line":"            if self._first_call:"},{"line_number":80,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""},{"line_number":81,"context_line":"                              \"contain attribute _cache therefore results \""},{"line_number":82,"context_line":"                              \"cannot be cached for %(func_name)s.\"),"},{"line_number":83,"context_line":"                            {\u0027module\u0027: target_self.__module__,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7adec928_e90fc2df","line":80,"updated":"2014-05-08 17:54:02.000000000","message":"Why does this need to be a warning?  Seems like LOG.debug would be more appropriate.  If we warn the operator, there is nothing they can do to fix it.","commit_id":"5bf881e3cccdef368fa4932f27ab506cbd11a13e"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"11bc6d3afc6535399c0488cc332a51cece7cf1c9","unresolved":false,"context_lines":[{"line_number":77,"context_line":"    def __call__(self, target_self, *args, **kwargs):"},{"line_number":78,"context_line":"        if not hasattr(target_self, \u0027_cache\u0027):"},{"line_number":79,"context_line":"            if self._first_call:"},{"line_number":80,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""},{"line_number":81,"context_line":"                              \"contain attribute _cache therefore results \""},{"line_number":82,"context_line":"                              \"cannot be cached for %(func_name)s.\"),"},{"line_number":83,"context_line":"                            {\u0027module\u0027: target_self.__module__,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7adec928_5c1f9909","line":80,"in_reply_to":"7adec928_71d71ec0","updated":"2014-05-21 17:00:55.000000000","message":"When I removed it and tried to make the metadata agent caching (review 70689) I realized I have a use case for this. Cache is in metadata agent configurable and if no caching backend is provided, cache is not created.","commit_id":"5bf881e3cccdef368fa4932f27ab506cbd11a13e"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"ea780c7bc22cb2d48f57b1307c8784540d2c56c6","unresolved":false,"context_lines":[{"line_number":77,"context_line":"    def __call__(self, target_self, *args, **kwargs):"},{"line_number":78,"context_line":"        if not hasattr(target_self, \u0027_cache\u0027):"},{"line_number":79,"context_line":"            if self._first_call:"},{"line_number":80,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""},{"line_number":81,"context_line":"                              \"contain attribute _cache therefore results \""},{"line_number":82,"context_line":"                              \"cannot be cached for %(func_name)s.\"),"},{"line_number":83,"context_line":"                            {\u0027module\u0027: target_self.__module__,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7adec928_71d71ec0","line":80,"in_reply_to":"7adec928_d6170853","updated":"2014-05-21 16:40:39.000000000","message":"ok, will remove that. Thanks","commit_id":"5bf881e3cccdef368fa4932f27ab506cbd11a13e"},{"author":{"_account_id":7787,"name":"Kevin Benton","email":"kevin@benton.pub","username":"blak111"},"change_message_id":"1df02f2e3c56e493cb82bc0f73437110ccc7324f","unresolved":false,"context_lines":[{"line_number":77,"context_line":"    def __call__(self, target_self, *args, **kwargs):"},{"line_number":78,"context_line":"        if not hasattr(target_self, \u0027_cache\u0027):"},{"line_number":79,"context_line":"            if self._first_call:"},{"line_number":80,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""},{"line_number":81,"context_line":"                              \"contain attribute _cache therefore results \""},{"line_number":82,"context_line":"                              \"cannot be cached for %(func_name)s.\"),"},{"line_number":83,"context_line":"                            {\u0027module\u0027: target_self.__module__,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7adec928_d6170853","line":80,"in_reply_to":"7adec928_e90fc2df","updated":"2014-05-21 16:24:10.000000000","message":"Does it make sense to just raise an exception instead? I can\u0027t think of a case where a developer would wrap a function with the cache decorator that isn\u0027t cacheable.","commit_id":"5bf881e3cccdef368fa4932f27ab506cbd11a13e"},{"author":{"_account_id":2592,"name":"Mark McClain","email":"mark@mcclain.xyz","username":"markmcclain"},"change_message_id":"31a533cc8469554629be95f9af56a0d2ccf894da","unresolved":false,"context_lines":[{"line_number":235,"context_line":""},{"line_number":236,"context_line":"def dict2tuple(d):"},{"line_number":237,"context_line":"    items \u003d d.items()"},{"line_number":238,"context_line":"    items.sort(key\u003dlambda x: x[0])"},{"line_number":239,"context_line":"    return tuple(items)"},{"line_number":240,"context_line":""},{"line_number":241,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"7adec928_09b14ef8","line":238,"updated":"2014-05-08 17:54:02.000000000","message":"items.sort()\n\nPassing the key should be unnecessary as the tuples are sorted based on their value.","commit_id":"5bf881e3cccdef368fa4932f27ab506cbd11a13e"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"ea780c7bc22cb2d48f57b1307c8784540d2c56c6","unresolved":false,"context_lines":[{"line_number":235,"context_line":""},{"line_number":236,"context_line":"def dict2tuple(d):"},{"line_number":237,"context_line":"    items \u003d d.items()"},{"line_number":238,"context_line":"    items.sort(key\u003dlambda x: x[0])"},{"line_number":239,"context_line":"    return tuple(items)"},{"line_number":240,"context_line":""},{"line_number":241,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"7adec928_5a8948ea","line":238,"in_reply_to":"7adec928_09b14ef8","updated":"2014-05-21 16:40:39.000000000","message":"Done","commit_id":"5bf881e3cccdef368fa4932f27ab506cbd11a13e"},{"author":{"_account_id":7787,"name":"Kevin Benton","email":"kevin@benton.pub","username":"blak111"},"change_message_id":"6587dd45e0ef7611030cfbb460eea9ba6b27f4e8","unresolved":false,"context_lines":[{"line_number":79,"context_line":"        return item"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def __call__(self, target_self, *args, **kwargs):"},{"line_number":82,"context_line":"        if not hasattr(target_self, \u0027_cache\u0027):"},{"line_number":83,"context_line":"            if self._first_call:"},{"line_number":84,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""},{"line_number":85,"context_line":"                              \"contain attribute _cache therefore results \""}],"source_content_type":"text/x-python","patch_set":18,"id":"7adec928_3ced6d8c","line":82,"updated":"2014-05-21 17:15:32.000000000","message":"Could you make the difference between not being cacheable and having a cache disabled explicit by setting _cache to False? \n\nSo in the dependent patch you would set it to False if self.conf.cache_url wasn\u0027t present. Then the logic here would become something like:\n\n\nif not hasattr(target_self, \u0027_cache\u0027):\n\n    raise NotImplemented(\u0027The decorated method is not cacheable\u0027)\n\nself._first_call \u0026\u003d not self._first_call\n\nreturn self._get_from_cache(target_self, *args, **kwargs)","commit_id":"7043e77e622bad96f258f7ef6b5d06d0b8295cf1"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"1f26b1e2dff2c49ad820f790851dd107f5ded211","unresolved":false,"context_lines":[{"line_number":79,"context_line":"        return item"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def __call__(self, target_self, *args, **kwargs):"},{"line_number":82,"context_line":"        if not hasattr(target_self, \u0027_cache\u0027):"},{"line_number":83,"context_line":"            if self._first_call:"},{"line_number":84,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""},{"line_number":85,"context_line":"                              \"contain attribute _cache therefore results \""}],"source_content_type":"text/x-python","patch_set":18,"id":"7adec928_971f3ab7","line":82,"in_reply_to":"7adec928_3ced6d8c","updated":"2014-05-21 17:39:01.000000000","message":"If I would set _cache attribute to False then it would have to explicitly check in this decorator, whether it\u0027s False. Because here it\u0027s treated as cache from oslo-incubator.","commit_id":"7043e77e622bad96f258f7ef6b5d06d0b8295cf1"},{"author":{"_account_id":7787,"name":"Kevin Benton","email":"kevin@benton.pub","username":"blak111"},"change_message_id":"1682a24c9551d952b2f40a2066208b5c32391273","unresolved":false,"context_lines":[{"line_number":78,"context_line":""},{"line_number":79,"context_line":"        return item"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def __call__(self, target_self, *args, **kwargs):"},{"line_number":82,"context_line":"        if not hasattr(target_self, \u0027_cache\u0027):"},{"line_number":83,"context_line":"            if self._first_call:"},{"line_number":84,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_77738ee7","line":81,"updated":"2014-05-21 17:47:34.000000000","message":"Carrying conversation onto current patch:\n\nI forgot about checking if _cache is False, so it would become something like:\n\nif not hasattr(target_self, \u0027_cache\u0027):\n    raise NotImplemented(\u0027The decorated method is not cacheable\u0027)\nif not target_self._cache:\n    LOG.debug(\"cache disabled on function...\")\n    return self.func(target_self, *args, **kwargs)\nself._first_call \u0026\u003d not self._first_call\nreturn self._get_from_cache(target_self, *args, **kwargs)\n\n\nNot as much of a reduction of code, but I like the idea of making sure that a developer using the decorator will get exceptions of he/she misses the required step of setting up the _cache attribute.","commit_id":"a2c50613529d449703d95a1a16f17c5349ac6571"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"37f1f6be6a08547477f6804891dcc034dc0c39cf","unresolved":false,"context_lines":[{"line_number":78,"context_line":""},{"line_number":79,"context_line":"        return item"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def __call__(self, target_self, *args, **kwargs):"},{"line_number":82,"context_line":"        if not hasattr(target_self, \u0027_cache\u0027):"},{"line_number":83,"context_line":"            if self._first_call:"},{"line_number":84,"context_line":"                LOG.warning(_(\"Instance of class %(module)s.%(class)s doesn\u0027t \""}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_6b1f140a","line":81,"in_reply_to":"7adec928_77738ee7","updated":"2014-05-22 10:36:15.000000000","message":"ok, will change. Thanks for comments","commit_id":"a2c50613529d449703d95a1a16f17c5349ac6571"}],"neutron/tests/unit/test_common_utils.py":[{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"c82506f71d46983bfbfedea71ca65fa241ec7fc4","unresolved":false,"context_lines":[{"line_number":333,"context_line":"            return self.func_retval"},{"line_number":334,"context_line":"        self.func \u003d testing_func"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":"    def _cache_miss_helper(self, expected_key, args, kwargs):"},{"line_number":337,"context_line":"        self._prep_func()"},{"line_number":338,"context_line":"        with mock.patch.object(self._cache, \u0027get\u0027) as mock_get:"},{"line_number":339,"context_line":"            mock_get.return_value \u003d None"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FelA%3D","line":336,"updated":"2014-02-26 11:57:42.000000000","message":"There is zero value in checking the cases of no args, args, kwargs independently.  Please combine this helper with test_cache_miss_kwargs and remove test_cache_miss and test_cache_miss_args, and do the same for the *_hit_* test methods as well.\n\nWhen sequences are used in python, it\u0027s often the case that one doesn\u0027t have to test empty vs non-empty behavior, because they are effectively the same.  So args vs no args, kwargs vs no kwargs really doesn\u0027t matter, and it\u0027s possible to test the relevant paths in one pass by providing both args and kwargs.","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"725be16f89bf148240839e9b123e615890f2acb3","unresolved":false,"context_lines":[{"line_number":333,"context_line":"            return self.func_retval"},{"line_number":334,"context_line":"        self.func \u003d testing_func"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":"    def _cache_miss_helper(self, expected_key, args, kwargs):"},{"line_number":337,"context_line":"        self._prep_func()"},{"line_number":338,"context_line":"        with mock.patch.object(self._cache, \u0027get\u0027) as mock_get:"},{"line_number":339,"context_line":"            mock_get.return_value \u003d None"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FeW0%3D","line":336,"in_reply_to":"AAAAU3%2F%2FelA%3D","updated":"2014-02-26 12:33:52.000000000","message":"Done","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"c82506f71d46983bfbfedea71ca65fa241ec7fc4","unresolved":false,"context_lines":[{"line_number":408,"context_line":"        self.assertEqual(self.func_retval, retval)"},{"line_number":409,"context_line":""},{"line_number":410,"context_line":""},{"line_number":411,"context_line":"class TestDict2Tuples(base.BaseTestCase):"},{"line_number":412,"context_line":"    def _test_dict(self, expected, input):"},{"line_number":413,"context_line":"        output_tuple \u003d utils.dict2tuple(input)"},{"line_number":414,"context_line":"        self.assertEqual(expected, output_tuple)"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2Ferw%3D","line":411,"updated":"2014-02-26 11:57:42.000000000","message":"This is a lot of testing for a 3-line method. Exceptional cases aside, a good rule of thumb in python is that your test code line count shouldn\u0027t exceed 100% of the number of lines that are being tested.","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"725be16f89bf148240839e9b123e615890f2acb3","unresolved":false,"context_lines":[{"line_number":408,"context_line":"        self.assertEqual(self.func_retval, retval)"},{"line_number":409,"context_line":""},{"line_number":410,"context_line":""},{"line_number":411,"context_line":"class TestDict2Tuples(base.BaseTestCase):"},{"line_number":412,"context_line":"    def _test_dict(self, expected, input):"},{"line_number":413,"context_line":"        output_tuple \u003d utils.dict2tuple(input)"},{"line_number":414,"context_line":"        self.assertEqual(expected, output_tuple)"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FeTo%3D","line":411,"in_reply_to":"AAAAU3%2F%2Ferw%3D","updated":"2014-02-26 12:33:52.000000000","message":"Done","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"c82506f71d46983bfbfedea71ca65fa241ec7fc4","unresolved":false,"context_lines":[{"line_number":417,"context_line":"        input_dict \u003d {\u0027foo\u0027: \u0027bar\u0027, 42: \u0027baz\u0027}"},{"line_number":418,"context_line":"        expected \u003d ((42, \u0027baz\u0027), (\u0027foo\u0027, \u0027bar\u0027))"},{"line_number":419,"context_line":"        self._test_dict(expected, input_dict)"},{"line_number":420,"context_line":"        input_dict \u003d {42: \u0027baz\u0027, \u0027foo\u0027: \u0027bar\u0027}"},{"line_number":421,"context_line":"        self._test_dict(expected, input_dict)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"    def test_empty_dict(self):"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2Few0%3D","line":420,"updated":"2014-02-26 11:57:42.000000000","message":"This second check is pointless since dictionary keys are stored in hashed order.  Changing the order in which keys are defined does not change the hashed order (compare dict.items() for different ordering of keys to see what I mean).\n\nThough you can vary the keys rather than their order to validate that you are always getting results in sorted order, consider that it should be enough to ensure that sorting is taking place once by picking keys that hash in a different order than they will be sorted.  The underlying sorting algorithm isn\u0027t what\u0027s being tested, after all - just that itis being called.","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"725be16f89bf148240839e9b123e615890f2acb3","unresolved":false,"context_lines":[{"line_number":417,"context_line":"        input_dict \u003d {\u0027foo\u0027: \u0027bar\u0027, 42: \u0027baz\u0027}"},{"line_number":418,"context_line":"        expected \u003d ((42, \u0027baz\u0027), (\u0027foo\u0027, \u0027bar\u0027))"},{"line_number":419,"context_line":"        self._test_dict(expected, input_dict)"},{"line_number":420,"context_line":"        input_dict \u003d {42: \u0027baz\u0027, \u0027foo\u0027: \u0027bar\u0027}"},{"line_number":421,"context_line":"        self._test_dict(expected, input_dict)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"    def test_empty_dict(self):"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FeUA%3D","line":420,"in_reply_to":"AAAAU3%2F%2Few0%3D","updated":"2014-02-26 12:33:52.000000000","message":"Done","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"c82506f71d46983bfbfedea71ca65fa241ec7fc4","unresolved":false,"context_lines":[{"line_number":420,"context_line":"        input_dict \u003d {42: \u0027baz\u0027, \u0027foo\u0027: \u0027bar\u0027}"},{"line_number":421,"context_line":"        self._test_dict(expected, input_dict)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"    def test_empty_dict(self):"},{"line_number":424,"context_line":"        input_dict \u003d dict()"},{"line_number":425,"context_line":"        expected \u003d tuple()"},{"line_number":426,"context_line":"        self._test_dict(expected, input_dict)"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FewA%3D","line":423,"updated":"2014-02-26 11:57:42.000000000","message":"This is a pointless test.  Bounds checking might make sense if one were writing an adt, but this is a unit test that exercises built-in types with established behaviour.  dict.items() returns a list regardless of the contents of the dict, a list can be safely sorted regardless of its size, and a tuple can accept a list of any size as an argument.  \n\nRemember, whitebox testing can take advantage of implementation knowledge to target what needs to be tested, and skip what does not.","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"725be16f89bf148240839e9b123e615890f2acb3","unresolved":false,"context_lines":[{"line_number":420,"context_line":"        input_dict \u003d {42: \u0027baz\u0027, \u0027foo\u0027: \u0027bar\u0027}"},{"line_number":421,"context_line":"        self._test_dict(expected, input_dict)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"    def test_empty_dict(self):"},{"line_number":424,"context_line":"        input_dict \u003d dict()"},{"line_number":425,"context_line":"        expected \u003d tuple()"},{"line_number":426,"context_line":"        self._test_dict(expected, input_dict)"}],"source_content_type":"text/x-python","patch_set":9,"id":"AAAAU3%2F%2FeTs%3D","line":423,"in_reply_to":"AAAAU3%2F%2FewA%3D","updated":"2014-02-26 12:33:52.000000000","message":"Done","commit_id":"3b29c3ca1deae15e9c54d379895aabd2166ac534"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"6dd4b9defd55f432af1b8eb96884cff40265c1cd","unresolved":false,"context_lines":[{"line_number":328,"context_line":"        self.func_retval \u003d \u0027bar\u0027"},{"line_number":329,"context_line":""},{"line_number":330,"context_line":"    def _prep_func(self):"},{"line_number":331,"context_line":"        @utils.CacheMethodResults"},{"line_number":332,"context_line":"        def testing_func(obj_self, *args, **kwargs):"},{"line_number":333,"context_line":"            return obj_self.func_retval"},{"line_number":334,"context_line":"        self.func \u003d testing_func"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F3vo%3D","line":331,"updated":"2014-03-03 17:52:18.000000000","message":"The decorator\u0027s __get__ method is not tested by this use of the decorator.  Please update to use a nested class method, e.g.\n\nclass foo:\n  @utils.cached_method_results\n  def func(...)\n    pass\n\nself.func \u003d foo.func","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"0837ae08725a82bee21fbf4f6b248b09b9514eb2","unresolved":false,"context_lines":[{"line_number":328,"context_line":"        self.func_retval \u003d \u0027bar\u0027"},{"line_number":329,"context_line":""},{"line_number":330,"context_line":"    def _prep_func(self):"},{"line_number":331,"context_line":"        @utils.CacheMethodResults"},{"line_number":332,"context_line":"        def testing_func(obj_self, *args, **kwargs):"},{"line_number":333,"context_line":"            return obj_self.func_retval"},{"line_number":334,"context_line":"        self.func \u003d testing_func"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F1uk%3D","line":331,"in_reply_to":"AAAAVn%2F%2F3vo%3D","updated":"2014-03-03 21:08:34.000000000","message":"Done","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":2035,"name":"Maru Newby","email":"marun@redhat.com","username":"maru"},"change_message_id":"18ff59ec14c5fb766939a486a098e48623b950ff","unresolved":false,"context_lines":[{"line_number":331,"context_line":"        @utils.CacheMethodResults"},{"line_number":332,"context_line":"        def testing_func(obj_self, *args, **kwargs):"},{"line_number":333,"context_line":"            return obj_self.func_retval"},{"line_number":334,"context_line":"        self.func \u003d testing_func"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":"    def test_cache_miss(self):"},{"line_number":337,"context_line":"        expected_key \u003d (self.func_name, 1, 2, (\u0027foo\u0027, \u0027bar\u0027))"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F3sA%3D","line":334,"updated":"2014-03-03 17:58:06.000000000","message":"(Suggestion only) Consider returning the func rather than setting it on the instance since it is only used in the context of the caller.","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"0837ae08725a82bee21fbf4f6b248b09b9514eb2","unresolved":false,"context_lines":[{"line_number":331,"context_line":"        @utils.CacheMethodResults"},{"line_number":332,"context_line":"        def testing_func(obj_self, *args, **kwargs):"},{"line_number":333,"context_line":"            return obj_self.func_retval"},{"line_number":334,"context_line":"        self.func \u003d testing_func"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":"    def test_cache_miss(self):"},{"line_number":337,"context_line":"        expected_key \u003d (self.func_name, 1, 2, (\u0027foo\u0027, \u0027bar\u0027))"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAVn%2F%2F1tI%3D","line":334,"in_reply_to":"AAAAVn%2F%2F3sA%3D","updated":"2014-03-03 21:08:34.000000000","message":"This method won\u0027t exist in next patch.","commit_id":"a8218e363dbad1663f8d1092f8287ea9c82f1599"}]}
