)]}'
{"nova/conductor/manager.py":[{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"bfc72d3bbab22ee3a6f33340afaefb2b48312090","unresolved":false,"context_lines":[{"line_number":461,"context_line":"        # marked as changed, we need to assume it\u0027s newly changed."},{"line_number":462,"context_line":"        for field in objinst.what_changed():"},{"line_number":463,"context_line":"            updates[field] \u003d objinst._attr_to_primitive(field)"},{"line_number":464,"context_line":"        return updates, result"}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAPH%2F%2F020%3D","line":464,"updated":"2013-05-22 06:45:33.000000000","message":"Hmm.. Does the deserialize response code actually iterate through tuples?  Ie, what if \u0027result\u0027 is an object.","commit_id":"bf9f21f3dcf3171357263e5ce49bafba5d80ef9c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"875fcd4c8739c2edcce6fc82be7bc72751dfb513","unresolved":false,"context_lines":[{"line_number":461,"context_line":"        # marked as changed, we need to assume it\u0027s newly changed."},{"line_number":462,"context_line":"        for field in objinst.what_changed():"},{"line_number":463,"context_line":"            updates[field] \u003d objinst._attr_to_primitive(field)"},{"line_number":464,"context_line":"        return updates, result"}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAPH%2F%2F0II%3D","line":464,"in_reply_to":"AAAAPH%2F%2F020%3D","updated":"2013-05-22 13:39:46.000000000","message":"Hmm, good call. I wonder why this is working...","commit_id":"bf9f21f3dcf3171357263e5ce49bafba5d80ef9c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"e246fc9c3a58b5898c41e740e3eb3c8702b99919","unresolved":false,"context_lines":[{"line_number":461,"context_line":"        # marked as changed, we need to assume it\u0027s newly changed."},{"line_number":462,"context_line":"        for field in objinst.what_changed():"},{"line_number":463,"context_line":"            updates[field] \u003d objinst._attr_to_primitive(field)"},{"line_number":464,"context_line":"        return updates, result"}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAPH%2F%2FzYE%3D","line":464,"in_reply_to":"AAAAPH%2F%2F0II%3D","updated":"2013-05-22 18:00:28.000000000","message":"Noting here for posterity:\n\nIt\u0027s working because we don\u0027t ever return objects from non-static object operations right now. This can be fixed in the future if needed/desired by making RpcProxy iterate. For now, I\u0027m going to punt as it\u0027s not strictly needed.","commit_id":"bf9f21f3dcf3171357263e5ce49bafba5d80ef9c"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"b79ed34bceb6cfbd0bae89619a73ce8e4a1e6a50","unresolved":false,"context_lines":[{"line_number":16,"context_line":""},{"line_number":17,"context_line":"import copy"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"from nova.api.ec2 import ec2utils"},{"line_number":21,"context_line":"from nova.compute import api as compute_api"},{"line_number":22,"context_line":"from nova.compute import utils as compute_utils"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FzEs%3D","line":19,"updated":"2013-05-22 20:20:30.000000000","message":"one too many blank lines…","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":2271,"name":"Michael Still","email":"mikal@stillhq.com","username":"mikalstill"},"change_message_id":"d1e238bc120e3f973eb35422454fb8a98699ec6d","unresolved":false,"context_lines":[{"line_number":466,"context_line":"                            objver, **kwargs):"},{"line_number":467,"context_line":"        \"\"\"Perform a classmethod action on an object.\"\"\""},{"line_number":468,"context_line":"        objclass \u003d nova_object.NovaObject.obj_class_from_name(objname,"},{"line_number":469,"context_line":"                                                              objver)"},{"line_number":470,"context_line":"        return getattr(objclass, objmethod)(context, **kwargs)"},{"line_number":471,"context_line":""},{"line_number":472,"context_line":"    def object_action(self, context, objinst, objmethod, objver,"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2Folg%3D","line":469,"updated":"2013-05-28 21:27:11.000000000","message":"Slight indent fail here.","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"32fa57b1bc3b8497ed187138a9b1faad6b3a92a9","unresolved":false,"context_lines":[{"line_number":466,"context_line":"                            objver, **kwargs):"},{"line_number":467,"context_line":"        \"\"\"Perform a classmethod action on an object.\"\"\""},{"line_number":468,"context_line":"        objclass \u003d nova_object.NovaObject.obj_class_from_name(objname,"},{"line_number":469,"context_line":"                                                              objver)"},{"line_number":470,"context_line":"        return getattr(objclass, objmethod)(context, **kwargs)"},{"line_number":471,"context_line":""},{"line_number":472,"context_line":"    def object_action(self, context, objinst, objmethod, objver,"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2FofA%3D","line":469,"in_reply_to":"AAAAPH%2F%2FogQ%3D","updated":"2013-05-28 21:54:01.000000000","message":"Yeah, it lines up right where it should, just after the open parenthesis on the preceding line…Proportional font fail?","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"1e7831899fda22213aa6d873e5a7aea26650e7c8","unresolved":false,"context_lines":[{"line_number":466,"context_line":"                            objver, **kwargs):"},{"line_number":467,"context_line":"        \"\"\"Perform a classmethod action on an object.\"\"\""},{"line_number":468,"context_line":"        objclass \u003d nova_object.NovaObject.obj_class_from_name(objname,"},{"line_number":469,"context_line":"                                                              objver)"},{"line_number":470,"context_line":"        return getattr(objclass, objmethod)(context, **kwargs)"},{"line_number":471,"context_line":""},{"line_number":472,"context_line":"    def object_action(self, context, objinst, objmethod, objver,"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2Foeg%3D","line":469,"in_reply_to":"AAAAPH%2F%2FogQ%3D","updated":"2013-05-28 21:54:41.000000000","message":"variable width fonts fool me a lot in gerrit too.  it doesn\u0027t look aligned, but i\u0027m guessing it really is.","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"6685f24f53bbe84da78ee77470e7ff6aa74a87b4","unresolved":false,"context_lines":[{"line_number":466,"context_line":"                            objver, **kwargs):"},{"line_number":467,"context_line":"        \"\"\"Perform a classmethod action on an object.\"\"\""},{"line_number":468,"context_line":"        objclass \u003d nova_object.NovaObject.obj_class_from_name(objname,"},{"line_number":469,"context_line":"                                                              objver)"},{"line_number":470,"context_line":"        return getattr(objclass, objmethod)(context, **kwargs)"},{"line_number":471,"context_line":""},{"line_number":472,"context_line":"    def object_action(self, context, objinst, objmethod, objver,"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2FogQ%3D","line":469,"in_reply_to":"AAAAPH%2F%2Folg%3D","updated":"2013-05-28 21:49:44.000000000","message":"Hmm how? Looks okay to me...","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"}],"nova/object.py":[{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"f66056475d876ee9bf77900ae6358129ad48e0b0","unresolved":false,"context_lines":[{"line_number":174,"context_line":"    def make_namespaced_msg(method, namespace, **kwargs):"},{"line_number":175,"context_line":"        s_kwargs \u003d {}"},{"line_number":176,"context_line":"        for key, value in kwargs.iteritems():"},{"line_number":177,"context_line":"            if isinstance(NovaObject):"},{"line_number":178,"context_line":"                value \u003d value.to_primitive()"},{"line_number":179,"context_line":"            s_kwargs[key] \u003d value"},{"line_number":180,"context_line":"        return nova.openstack.common.rpc.proxy.RpcProxy.make_namespaced_msg("}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAOn%2F%2Fq5k%3D","line":177,"updated":"2013-04-29 19:20:19.000000000","message":"bug!","commit_id":"8b2deb4d598c535862ed6db178021ce75c5912d4"}],"nova/object/__init__.py":[{"author":{"_account_id":2271,"name":"Michael Still","email":"mikal@stillhq.com","username":"mikalstill"},"change_message_id":"d1e238bc120e3f973eb35422454fb8a98699ec6d","unresolved":false,"context_lines":[{"line_number":1,"context_line":"#    Copyright 2013 IBM Corp."},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"#    not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2FolI%3D","line":1,"updated":"2013-05-28 21:27:11.000000000","message":"The TC recently discussed asking developers to stop adding these copyright statements to new files. I\u0027m not going to block this review, but it would be good if you could consider removing this line. Sean Dague has the backstory if that helps.","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"}],"nova/object/base.py":[{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"bfc72d3bbab22ee3a6f33340afaefb2b48312090","unresolved":false,"context_lines":[{"line_number":104,"context_line":"                context, self, fn.__name__, self.version, kwargs)"},{"line_number":105,"context_line":"            for key, value in updates.iteritems():"},{"line_number":106,"context_line":"                self[key] \u003d value"},{"line_number":107,"context_line":"            self.reset_changes(updates.keys())"},{"line_number":108,"context_line":"            return result"},{"line_number":109,"context_line":"        else:"},{"line_number":110,"context_line":"            return fn(self, context, **kwargs)"}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAPH%2F%2F03U%3D","line":107,"updated":"2013-05-22 06:45:33.000000000","message":"\u0027updates\u0027 is the list of fields that the remote says have not been saved yet.  It seems like you want to reset all OTHER fields, right, because they must have been committed?\n\nSeparate issue: What if remote modifies a field and does a save().  Nothing is returned as dirty here... and we have no idea that we need to update the field on this client side. :-/","commit_id":"bf9f21f3dcf3171357263e5ce49bafba5d80ef9c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"875fcd4c8739c2edcce6fc82be7bc72751dfb513","unresolved":false,"context_lines":[{"line_number":104,"context_line":"                context, self, fn.__name__, self.version, kwargs)"},{"line_number":105,"context_line":"            for key, value in updates.iteritems():"},{"line_number":106,"context_line":"                self[key] \u003d value"},{"line_number":107,"context_line":"            self.reset_changes(updates.keys())"},{"line_number":108,"context_line":"            return result"},{"line_number":109,"context_line":"        else:"},{"line_number":110,"context_line":"            return fn(self, context, **kwargs)"}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAPH%2F%2F0HI%3D","line":107,"in_reply_to":"AAAAPH%2F%2F03U%3D","updated":"2013-05-22 13:39:46.000000000","message":"Oh right, I still need to resolve that. Thanks :)","commit_id":"bf9f21f3dcf3171357263e5ce49bafba5d80ef9c"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"bfc72d3bbab22ee3a6f33340afaefb2b48312090","unresolved":false,"context_lines":[{"line_number":279,"context_line":"        \"\"\""},{"line_number":280,"context_line":"        if fields:"},{"line_number":281,"context_line":"            for field in fields:"},{"line_number":282,"context_line":"                self._changed_fields.discard(field)"},{"line_number":283,"context_line":"        else:"},{"line_number":284,"context_line":"            self._changed_fields.clear()"},{"line_number":285,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAPH%2F%2F04s%3D","line":282,"updated":"2013-05-22 06:45:33.000000000","message":"Crazy thought: self._changed_files -\u003d set(fields)","commit_id":"bf9f21f3dcf3171357263e5ce49bafba5d80ef9c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"875fcd4c8739c2edcce6fc82be7bc72751dfb513","unresolved":false,"context_lines":[{"line_number":279,"context_line":"        \"\"\""},{"line_number":280,"context_line":"        if fields:"},{"line_number":281,"context_line":"            for field in fields:"},{"line_number":282,"context_line":"                self._changed_fields.discard(field)"},{"line_number":283,"context_line":"        else:"},{"line_number":284,"context_line":"            self._changed_fields.clear()"},{"line_number":285,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAPH%2F%2F0HY%3D","line":282,"in_reply_to":"AAAAPH%2F%2F04s%3D","updated":"2013-05-22 13:39:46.000000000","message":"Haha. Sets!","commit_id":"bf9f21f3dcf3171357263e5ce49bafba5d80ef9c"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"b79ed34bceb6cfbd0bae89619a73ce8e4a1e6a50","unresolved":false,"context_lines":[{"line_number":71,"context_line":"            cls._obj_classes[cls.objname()].append(cls)"},{"line_number":72,"context_line":""},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"# These are decorators that mark an opject\u0027s method as remotable."},{"line_number":75,"context_line":"# If the metaclass is configured to forward object methods to an"},{"line_number":76,"context_line":"# indirection service, these will result in making an RPC call"},{"line_number":77,"context_line":"# instead of directly calling the implementation in the object. Instead,"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FzDY%3D","line":74,"updated":"2013-05-22 20:20:30.000000000","message":"s/opject/object/","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"4e5095a9f8f39c6db9a62df11d79c0ff8fcc763d","unresolved":false,"context_lines":[{"line_number":104,"context_line":"                context, self, fn.__name__, self.version, kwargs)"},{"line_number":105,"context_line":"            for key, value in updates.iteritems():"},{"line_number":106,"context_line":"                if key in self.fields:"},{"line_number":107,"context_line":"                    self[key] \u003d value"},{"line_number":108,"context_line":"            self._changed_fields \u003d set(updates.get(\u0027what_changed\u0027, []))"},{"line_number":109,"context_line":"            return result"},{"line_number":110,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy4k%3D","line":107,"updated":"2013-05-22 21:15:27.000000000","message":"\u0027value\u0027 here is a primitive... we need to from_primitive it, right?","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"7fd21ee6159fe0ec3e24872d248e53004191f525","unresolved":false,"context_lines":[{"line_number":104,"context_line":"                context, self, fn.__name__, self.version, kwargs)"},{"line_number":105,"context_line":"            for key, value in updates.iteritems():"},{"line_number":106,"context_line":"                if key in self.fields:"},{"line_number":107,"context_line":"                    self[key] \u003d value"},{"line_number":108,"context_line":"            self._changed_fields \u003d set(updates.get(\u0027what_changed\u0027, []))"},{"line_number":109,"context_line":"            return result"},{"line_number":110,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy2Q%3D","line":107,"in_reply_to":"AAAAPH%2F%2Fy3c%3D","updated":"2013-05-22 21:35:43.000000000","message":"discussed on IRC: the value itself is attr_to_primitive on the manager side... so i think we need attr_from_primitive here regardless if the value is an object or not.","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"955c41c947076f055aefb0dc656cb55ec8c77063","unresolved":false,"context_lines":[{"line_number":104,"context_line":"                context, self, fn.__name__, self.version, kwargs)"},{"line_number":105,"context_line":"            for key, value in updates.iteritems():"},{"line_number":106,"context_line":"                if key in self.fields:"},{"line_number":107,"context_line":"                    self[key] \u003d value"},{"line_number":108,"context_line":"            self._changed_fields \u003d set(updates.get(\u0027what_changed\u0027, []))"},{"line_number":109,"context_line":"            return result"},{"line_number":110,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy3c%3D","line":107,"in_reply_to":"AAAAPH%2F%2Fy4k%3D","updated":"2013-05-22 21:23:34.000000000","message":"Only if it were an object, which we don\u0027t have an instance of yet. At one point we talked about not having any nested objects... How about we punt on that as well as the result iteration until we need it? Until we have an object that does that, we couldn\u0027t get this far anyway in a client that was still running code from before we supported nesting, so I don\u0027t think it\u0027s a sequencing problem...","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"b79ed34bceb6cfbd0bae89619a73ce8e4a1e6a50","unresolved":false,"context_lines":[{"line_number":124,"context_line":"        server_major, _server_minor \u003d server.split(\u0027.\u0027)"},{"line_number":125,"context_line":"        client_minor \u003d int(_client_minor)"},{"line_number":126,"context_line":"        server_minor \u003d int(_server_minor)"},{"line_number":127,"context_line":"    except Exception:"},{"line_number":128,"context_line":"        raise exception.IncompatibleObjectVersion("},{"line_number":129,"context_line":"            _(\u0027Invalid version string\u0027))"},{"line_number":130,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FzCc%3D","line":127,"updated":"2013-05-22 20:20:30.000000000","message":"You should be able to tighten this to just catch ValueError…","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"955c41c947076f055aefb0dc656cb55ec8c77063","unresolved":false,"context_lines":[{"line_number":124,"context_line":"        server_major, _server_minor \u003d server.split(\u0027.\u0027)"},{"line_number":125,"context_line":"        client_minor \u003d int(_client_minor)"},{"line_number":126,"context_line":"        server_minor \u003d int(_server_minor)"},{"line_number":127,"context_line":"    except Exception:"},{"line_number":128,"context_line":"        raise exception.IncompatibleObjectVersion("},{"line_number":129,"context_line":"            _(\u0027Invalid version string\u0027))"},{"line_number":130,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy34%3D","line":127,"in_reply_to":"AAAAPH%2F%2FzCc%3D","updated":"2013-05-22 21:23:34.000000000","message":"Done","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"b79ed34bceb6cfbd0bae89619a73ce8e4a1e6a50","unresolved":false,"context_lines":[{"line_number":132,"context_line":"        raise exception.IncompatibleObjectMajorVersion("},{"line_number":133,"context_line":"            dict(client\u003dclient_major, server\u003dserver_major))"},{"line_number":134,"context_line":"    if client_minor \u003e server_minor:"},{"line_number":135,"context_line":"        raise exception.IncompatibleObjectMinorVersion("},{"line_number":136,"context_line":"            dict(client\u003dclient_minor, server\u003dserver_minor))"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FzCs%3D","line":135,"updated":"2013-05-22 20:20:30.000000000","message":"Do we have different behavior when the major version doesn\u0027t match vs. when the minor version is incompatible?","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"67cbf54f6f2bb0a3732edd2255af6c7195720013","unresolved":false,"context_lines":[{"line_number":132,"context_line":"        raise exception.IncompatibleObjectMajorVersion("},{"line_number":133,"context_line":"            dict(client\u003dclient_major, server\u003dserver_major))"},{"line_number":134,"context_line":"    if client_minor \u003e server_minor:"},{"line_number":135,"context_line":"        raise exception.IncompatibleObjectMinorVersion("},{"line_number":136,"context_line":"            dict(client\u003dclient_minor, server\u003dserver_minor))"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FyzY%3D","line":135,"in_reply_to":"AAAAPH%2F%2Fy38%3D","updated":"2013-05-22 21:59:16.000000000","message":"I think I\u0027d prefer to try to reign in our ongoing exception explosion, then :)","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"955c41c947076f055aefb0dc656cb55ec8c77063","unresolved":false,"context_lines":[{"line_number":132,"context_line":"        raise exception.IncompatibleObjectMajorVersion("},{"line_number":133,"context_line":"            dict(client\u003dclient_major, server\u003dserver_major))"},{"line_number":134,"context_line":"    if client_minor \u003e server_minor:"},{"line_number":135,"context_line":"        raise exception.IncompatibleObjectMinorVersion("},{"line_number":136,"context_line":"            dict(client\u003dclient_minor, server\u003dserver_minor))"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy38%3D","line":135,"in_reply_to":"AAAAPH%2F%2FzCs%3D","updated":"2013-05-22 21:23:34.000000000","message":"I just figured it was worth breaking them out, but it\u0027s not necessarily useful :)","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"b79ed34bceb6cfbd0bae89619a73ce8e4a1e6a50","unresolved":false,"context_lines":[{"line_number":140,"context_line":"    \"\"\"Base class and object factory."},{"line_number":141,"context_line":""},{"line_number":142,"context_line":"    This forms the base of all objects that can be remoted or instantiated"},{"line_number":143,"context_line":"    via RPC. Simply defining a class that inerhits from this base class"},{"line_number":144,"context_line":"    will make it remotely instantiatable. Objects should implement the"},{"line_number":145,"context_line":"    necessary \"get\" classmethod routines as well as \"save\" object methods"},{"line_number":146,"context_line":"    as appropriate."}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FzCQ%3D","line":143,"updated":"2013-05-22 20:20:30.000000000","message":"s/inerhits/inherits/","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"b79ed34bceb6cfbd0bae89619a73ce8e4a1e6a50","unresolved":false,"context_lines":[{"line_number":141,"context_line":""},{"line_number":142,"context_line":"    This forms the base of all objects that can be remoted or instantiated"},{"line_number":143,"context_line":"    via RPC. Simply defining a class that inerhits from this base class"},{"line_number":144,"context_line":"    will make it remotely instantiatable. Objects should implement the"},{"line_number":145,"context_line":"    necessary \"get\" classmethod routines as well as \"save\" object methods"},{"line_number":146,"context_line":"    as appropriate."},{"line_number":147,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FzB4%3D","line":144,"updated":"2013-05-22 20:20:30.000000000","message":"I think s/instantiatable/instantiable/ would be advisable here, though neither is, strictly speaking, an English word (that I know of, anyway ;)","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"67cbf54f6f2bb0a3732edd2255af6c7195720013","unresolved":false,"context_lines":[{"line_number":141,"context_line":""},{"line_number":142,"context_line":"    This forms the base of all objects that can be remoted or instantiated"},{"line_number":143,"context_line":"    via RPC. Simply defining a class that inerhits from this base class"},{"line_number":144,"context_line":"    will make it remotely instantiatable. Objects should implement the"},{"line_number":145,"context_line":"    necessary \"get\" classmethod routines as well as \"save\" object methods"},{"line_number":146,"context_line":"    as appropriate."},{"line_number":147,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fyy0%3D","line":144,"in_reply_to":"AAAAPH%2F%2Fy4I%3D","updated":"2013-05-22 21:59:16.000000000","message":"Well, I *could* try to argue with that, but I *won\u0027t* :)","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"955c41c947076f055aefb0dc656cb55ec8c77063","unresolved":false,"context_lines":[{"line_number":141,"context_line":""},{"line_number":142,"context_line":"    This forms the base of all objects that can be remoted or instantiated"},{"line_number":143,"context_line":"    via RPC. Simply defining a class that inerhits from this base class"},{"line_number":144,"context_line":"    will make it remotely instantiatable. Objects should implement the"},{"line_number":145,"context_line":"    necessary \"get\" classmethod routines as well as \"save\" object methods"},{"line_number":146,"context_line":"    as appropriate."},{"line_number":147,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy4I%3D","line":144,"in_reply_to":"AAAAPH%2F%2FzB4%3D","updated":"2013-05-22 21:23:34.000000000","message":"Yeah, and I think I prefer the instantiatable non-word over the instantiable non-word, personally. How can you argue with that? :)","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"b79ed34bceb6cfbd0bae89619a73ce8e4a1e6a50","unresolved":false,"context_lines":[{"line_number":284,"context_line":"            self._changed_fields.clear()"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    # dictish syntactic sugar"},{"line_number":287,"context_line":"    def iteritems(self):"},{"line_number":288,"context_line":"        for name in self.fields:"},{"line_number":289,"context_line":"            if hasattr(self, get_attrname(name)):"},{"line_number":290,"context_line":"                yield name, getattr(self, name)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FzA8%3D","line":287,"updated":"2013-05-22 20:20:30.000000000","message":"Any reason we shouldn\u0027t name this just \"items\"?  Or perhaps we could provide both forms by adding \"items \u003d iteritems\" somewhere below.  Just a thought…","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"67cbf54f6f2bb0a3732edd2255af6c7195720013","unresolved":false,"context_lines":[{"line_number":284,"context_line":"            self._changed_fields.clear()"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    # dictish syntactic sugar"},{"line_number":287,"context_line":"    def iteritems(self):"},{"line_number":288,"context_line":"        for name in self.fields:"},{"line_number":289,"context_line":"            if hasattr(self, get_attrname(name)):"},{"line_number":290,"context_line":"                yield name, getattr(self, name)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fyyo%3D","line":287,"in_reply_to":"AAAAPH%2F%2Fy4U%3D","updated":"2013-05-22 21:59:16.000000000","message":"To my mind, items() and iteritems() are essentially the same thing; it\u0027s just that, in implementation, one returns a list and the other an iterator.  I figured that, since this isn\u0027t really a dictionary, we can just say that items() is an iterator, and if you want a list, you just pass the result to list().","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"955c41c947076f055aefb0dc656cb55ec8c77063","unresolved":false,"context_lines":[{"line_number":284,"context_line":"            self._changed_fields.clear()"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    # dictish syntactic sugar"},{"line_number":287,"context_line":"    def iteritems(self):"},{"line_number":288,"context_line":"        for name in self.fields:"},{"line_number":289,"context_line":"            if hasattr(self, get_attrname(name)):"},{"line_number":290,"context_line":"                yield name, getattr(self, name)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy4U%3D","line":287,"in_reply_to":"AAAAPH%2F%2FzA8%3D","updated":"2013-05-22 21:23:34.000000000","message":"Well, they\u0027re different, right? We can have an items too, I was just implementing the more efficient of the two.","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"ce6a6e0eec00353ce5ea0794045e31ae466d4078","unresolved":false,"context_lines":[{"line_number":289,"context_line":"            if hasattr(self, get_attrname(name)):"},{"line_number":290,"context_line":"                yield name, getattr(self, name)"},{"line_number":291,"context_line":""},{"line_number":292,"context_line":"    def __getitem__(self, name):"},{"line_number":293,"context_line":"        return getattr(self, name)"},{"line_number":294,"context_line":""},{"line_number":295,"context_line":"    def __setitem__(self, name, value):"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy4Q%3D","line":292,"updated":"2013-05-22 21:18:24.000000000","message":"Docstrings to say this is for backwards compat for now might be good.  Also, should we validate that name is in fields?  It could help catch errors.","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":1297,"name":"Joshua Harlow","email":"jxharlow@godaddy.com","username":"harlowja"},"change_message_id":"a69b221228a2258da01304c8cbd5bfafe6a5d7fc","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    \"\"\"Decorator for remotable object methods.\"\"\""},{"line_number":96,"context_line":"    def wrapper(self, context\u003dNone, **kwargs):"},{"line_number":97,"context_line":"        if context is None:"},{"line_number":98,"context_line":"            context \u003d self._context"},{"line_number":99,"context_line":"        if context is None:"},{"line_number":100,"context_line":"            raise exception.OrphanedObjectError(method\u003dfn.__name__,"},{"line_number":101,"context_line":"                                                objtype\u003dself.objname())"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FyA4%3D","line":98,"updated":"2013-05-23 06:25:30.000000000","message":"Why is the context being extracted like this, might be a useful place for a comment to explain why?","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":1297,"name":"Joshua Harlow","email":"jxharlow@godaddy.com","username":"harlowja"},"change_message_id":"62328c7a9cf9ab9ac365855b7642d719144332da","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    \"\"\"Decorator for remotable object methods.\"\"\""},{"line_number":96,"context_line":"    def wrapper(self, context\u003dNone, **kwargs):"},{"line_number":97,"context_line":"        if context is None:"},{"line_number":98,"context_line":"            context \u003d self._context"},{"line_number":99,"context_line":"        if context is None:"},{"line_number":100,"context_line":"            raise exception.OrphanedObjectError(method\u003dfn.__name__,"},{"line_number":101,"context_line":"                                                objtype\u003dself.objname())"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2Fwok%3D","line":98,"in_reply_to":"AAAAPH%2F%2FxTE%3D","updated":"2013-05-23 17:34:04.000000000","message":"Sounds great, wasn\u0027t so clear to me at least.","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"dfd072176b7da7630ece095875975a23a7f4d87c","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    \"\"\"Decorator for remotable object methods.\"\"\""},{"line_number":96,"context_line":"    def wrapper(self, context\u003dNone, **kwargs):"},{"line_number":97,"context_line":"        if context is None:"},{"line_number":98,"context_line":"            context \u003d self._context"},{"line_number":99,"context_line":"        if context is None:"},{"line_number":100,"context_line":"            raise exception.OrphanedObjectError(method\u003dfn.__name__,"},{"line_number":101,"context_line":"                                                objtype\u003dself.objname())"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FxTE%3D","line":98,"in_reply_to":"AAAAPH%2F%2FyA4%3D","updated":"2013-05-23 13:39:52.000000000","message":"Isn\u0027t it pretty clear? If context is not provided, nor embedded in the object, then it\u0027s Orphaned and can\u0027t have the remoted method called on it. The context is used a few lines below when the call to the indirection_api is made. Perhaps a bit more explanation in the block comment above _classmethod above would be warranted.","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":1297,"name":"Joshua Harlow","email":"jxharlow@godaddy.com","username":"harlowja"},"change_message_id":"a69b221228a2258da01304c8cbd5bfafe6a5d7fc","unresolved":false,"context_lines":[{"line_number":156,"context_line":"    #            \u0027bar\u0027: str,"},{"line_number":157,"context_line":"    #            \u0027baz\u0027: lambda x: str(x).ljust(8),"},{"line_number":158,"context_line":"    #          }"},{"line_number":159,"context_line":"    fields \u003d {}"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    def __init__(self):"},{"line_number":162,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FyAQ%3D","line":159,"updated":"2013-05-23 06:25:30.000000000","message":"How does inheritance work if each class defines its fields like this? Does the following work?\n\nclass A(NovaObject):\n  fields \u003d {\u0027b\u0027: \u0027blah\u0027}\n\nclass B(A):\n  fields \u003d {\u0027e\u0027: ...}\n\nDidn\u0027t B just lose A\u0027s fields?","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"7410230f66b8ada9187eee98c56787f9241aa36e","unresolved":false,"context_lines":[{"line_number":156,"context_line":"    #            \u0027bar\u0027: str,"},{"line_number":157,"context_line":"    #            \u0027baz\u0027: lambda x: str(x).ljust(8),"},{"line_number":158,"context_line":"    #          }"},{"line_number":159,"context_line":"    fields \u003d {}"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    def __init__(self):"},{"line_number":162,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FwyU%3D","line":159,"in_reply_to":"AAAAPH%2F%2Fw0E%3D","updated":"2013-05-23 16:25:52.000000000","message":"Okay, good call. Do you think those are worth a one-off hack, or do you think it\u0027s better to iterate through the bases? I dunno why I don\u0027t like the latter, but it seems like it might be bad.","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"9192c52701840c2ecf71d891059968f991959682","unresolved":false,"context_lines":[{"line_number":156,"context_line":"    #            \u0027bar\u0027: str,"},{"line_number":157,"context_line":"    #            \u0027baz\u0027: lambda x: str(x).ljust(8),"},{"line_number":158,"context_line":"    #          }"},{"line_number":159,"context_line":"    fields \u003d {}"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    def __init__(self):"},{"line_number":162,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2Fw0E%3D","line":159,"in_reply_to":"AAAAPH%2F%2Fw2Q%3D","updated":"2013-05-23 16:18:54.000000000","message":"Well, there are some common fields on every database object, e.g., created_at, updated_at, etc.; it could reduce duplication a bit to allow at least some restricted inheritance.  Just a thought…","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"2e02bc8107fd0f53ba4104d92839f275ed620408","unresolved":false,"context_lines":[{"line_number":156,"context_line":"    #            \u0027bar\u0027: str,"},{"line_number":157,"context_line":"    #            \u0027baz\u0027: lambda x: str(x).ljust(8),"},{"line_number":158,"context_line":"    #          }"},{"line_number":159,"context_line":"    fields \u003d {}"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    def __init__(self):"},{"line_number":162,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2Fw2Q%3D","line":159,"in_reply_to":"AAAAPH%2F%2Fw9g%3D","updated":"2013-05-23 16:04:25.000000000","message":"I actually don\u0027t want to do that because I don\u0027t really want subclasses overriding the schema. That kinda defeats the purpose. If we have a base Instance, a subclass of that should provide a different implementation of the database code or something, but not change the format at all. I can\u0027t think of any reason why subclassing instance to provide an extended schema would be a good idea...","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"61c7a3da3ce0fd8311f8dbd072e95a0801f10799","unresolved":false,"context_lines":[{"line_number":156,"context_line":"    #            \u0027bar\u0027: str,"},{"line_number":157,"context_line":"    #            \u0027baz\u0027: lambda x: str(x).ljust(8),"},{"line_number":158,"context_line":"    #          }"},{"line_number":159,"context_line":"    fields \u003d {}"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    def __init__(self):"},{"line_number":162,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2Fwno%3D","line":159,"in_reply_to":"AAAAPH%2F%2FwwU%3D","updated":"2013-05-23 17:38:12.000000000","message":"So, discussion on IRC seems to lean towards the hack approach, simply because right now we officially want to declare the act of subclassing something to extend the schema as off-limits. The hack will avoid the duplication for now and if we decide to implement the proper inheritance, we\u0027ll fit the base attributes into that scheme. I don\u0027t think there\u0027s any significant problem with doing that later. Hope that\u0027s agreeable to avoid too much feature creep :)","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ef36e64a8f1b2f2903d9a56ae3181336a1ee5097","unresolved":false,"context_lines":[{"line_number":156,"context_line":"    #            \u0027bar\u0027: str,"},{"line_number":157,"context_line":"    #            \u0027baz\u0027: lambda x: str(x).ljust(8),"},{"line_number":158,"context_line":"    #          }"},{"line_number":159,"context_line":"    fields \u003d {}"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    def __init__(self):"},{"line_number":162,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FwwU%3D","line":159,"in_reply_to":"AAAAPH%2F%2FwyU%3D","updated":"2013-05-23 16:38:19.000000000","message":"I like iterating over the bases, which is what I used in vobj.SchemaMeta, because it closely replicates Python inheritance.  (If you really want to stick with Python, I\u0027ve done all the work in metatools…)\n\nI\u0027m in the opposite boat from you; I don\u0027t like the idea of a one-off hack for this, though I can\u0027t really put my finger on why.  Perhaps it violates my mental picture of how inheritance is supposed to work?  *shrug*","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"1621e67b4682545e7069213c5a8658cec3565bba","unresolved":false,"context_lines":[{"line_number":156,"context_line":"    #            \u0027bar\u0027: str,"},{"line_number":157,"context_line":"    #            \u0027baz\u0027: lambda x: str(x).ljust(8),"},{"line_number":158,"context_line":"    #          }"},{"line_number":159,"context_line":"    fields \u003d {}"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    def __init__(self):"},{"line_number":162,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2Fw9g%3D","line":159,"in_reply_to":"AAAAPH%2F%2FxSo%3D","updated":"2013-05-23 15:28:55.000000000","message":"You could consider iterating over the bases and forming a merged fields dictionary.  You can look at my metatools and vobj packages for ideas on that (both on my github, https://github.com/klmitch/)","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"dfd072176b7da7630ece095875975a23a7f4d87c","unresolved":false,"context_lines":[{"line_number":156,"context_line":"    #            \u0027bar\u0027: str,"},{"line_number":157,"context_line":"    #            \u0027baz\u0027: lambda x: str(x).ljust(8),"},{"line_number":158,"context_line":"    #          }"},{"line_number":159,"context_line":"    fields \u003d {}"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    def __init__(self):"},{"line_number":162,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FxSo%3D","line":159,"in_reply_to":"AAAAPH%2F%2FyAQ%3D","updated":"2013-05-23 13:39:52.000000000","message":"Yes, B would need to use A.fields in constructing its own. That is, you know, how inheritance and overriding work :)","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"f1eadccfde3a9c630b1255f6c4449675f6e9b54e","unresolved":false,"context_lines":[{"line_number":292,"context_line":"    items \u003d lambda self: list(self.iteritems())"},{"line_number":293,"context_line":""},{"line_number":294,"context_line":"    def __getitem__(self, name):"},{"line_number":295,"context_line":"        return getattr(self, name)"},{"line_number":296,"context_line":""},{"line_number":297,"context_line":"    def __setitem__(self, name, value):"},{"line_number":298,"context_line":"        setattr(self, name, value)"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FyHQ%3D","line":295,"updated":"2013-05-23 05:21:59.000000000","message":"Docstrings to say this is for backwards compat for now might be good. Also, should we validate that name is in fields? It could help catch errors.","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"dfd072176b7da7630ece095875975a23a7f4d87c","unresolved":false,"context_lines":[{"line_number":292,"context_line":"    items \u003d lambda self: list(self.iteritems())"},{"line_number":293,"context_line":""},{"line_number":294,"context_line":"    def __getitem__(self, name):"},{"line_number":295,"context_line":"        return getattr(self, name)"},{"line_number":296,"context_line":""},{"line_number":297,"context_line":"    def __setitem__(self, name, value):"},{"line_number":298,"context_line":"        setattr(self, name, value)"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FxSU%3D","line":295,"in_reply_to":"AAAAPH%2F%2FyHQ%3D","updated":"2013-05-23 13:39:52.000000000","message":"Oops, sorry, forgot to do this in this revision. Will get it in the next one.","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"72f6f136da4967e162f9a17081b714133c734284","unresolved":false,"context_lines":[{"line_number":48,"context_line":"            except Exception, e:"},{"line_number":49,"context_line":"                # This should probably be a log call, but print for now"},{"line_number":50,"context_line":"                attr \u003d \"%s.%s\" % (self.obj_name(), name)"},{"line_number":51,"context_line":"                LOG.exception(_(\u0027Error setting %(attr)s\u0027) % locals())"},{"line_number":52,"context_line":"                raise"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"        setattr(cls, name, property(getter, setter))"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw8g%3D","line":51,"updated":"2013-05-23 15:40:23.000000000","message":"We seem to be trying to eliminate locals() throughout the code.  Also, this doesn\u0027t look like a print, so maybe a comment update is in order?","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"86532679ab2dea8752531dd59aeb4a967fa10795","unresolved":false,"context_lines":[{"line_number":48,"context_line":"            except Exception, e:"},{"line_number":49,"context_line":"                # This should probably be a log call, but print for now"},{"line_number":50,"context_line":"                attr \u003d \"%s.%s\" % (self.obj_name(), name)"},{"line_number":51,"context_line":"                LOG.exception(_(\u0027Error setting %(attr)s\u0027) % locals())"},{"line_number":52,"context_line":"                raise"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"        setattr(cls, name, property(getter, setter))"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw2I%3D","line":51,"in_reply_to":"AAAAPH%2F%2Fw8g%3D","updated":"2013-05-23 16:08:47.000000000","message":"Hah, yep, thanks.","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"98ec51c1cd9b8aece14f2a3a26efce2f372beff0","unresolved":false,"context_lines":[{"line_number":95,"context_line":"#"},{"line_number":96,"context_line":"# Note that this will use either the provided context, or the one"},{"line_number":97,"context_line":"# stashed in the object. If neither are present, the object is"},{"line_number":98,"context_line":"# \"orphaned\" and remotable methods cannot be called."},{"line_number":99,"context_line":"def remotable(fn):"},{"line_number":100,"context_line":"    \"\"\"Decorator for remotable object methods.\"\"\""},{"line_number":101,"context_line":"    def wrapper(self, context\u003dNone, **kwargs):"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw%2Fg%3D","line":98,"updated":"2013-05-23 15:10:24.000000000","message":"Added a comment here clarifying general context usage. Hope that clears it up.","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":1297,"name":"Joshua Harlow","email":"jxharlow@godaddy.com","username":"harlowja"},"change_message_id":"0f113f46ca73d22d912c85e7a1a42cf76448e417","unresolved":false,"context_lines":[{"line_number":95,"context_line":"#"},{"line_number":96,"context_line":"# Note that this will use either the provided context, or the one"},{"line_number":97,"context_line":"# stashed in the object. If neither are present, the object is"},{"line_number":98,"context_line":"# \"orphaned\" and remotable methods cannot be called."},{"line_number":99,"context_line":"def remotable(fn):"},{"line_number":100,"context_line":"    \"\"\"Decorator for remotable object methods.\"\"\""},{"line_number":101,"context_line":"    def wrapper(self, context\u003dNone, **kwargs):"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fwn0%3D","line":98,"in_reply_to":"AAAAPH%2F%2Fw%2Fg%3D","updated":"2013-05-23 17:39:00.000000000","message":"Thanks!","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"98ec51c1cd9b8aece14f2a3a26efce2f372beff0","unresolved":false,"context_lines":[{"line_number":168,"context_line":"        self._context \u003d None"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    @classmethod"},{"line_number":171,"context_line":"    def obj_name(cls):"},{"line_number":172,"context_line":"        \"\"\"Return a canonical name for this object which will be used over"},{"line_number":173,"context_line":"        the wire for remote hydration.\"\"\""},{"line_number":174,"context_line":"        return cls.__name__"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw%2Fc%3D","line":171,"updated":"2013-05-23 15:10:24.000000000","message":"Prefixed all public methods with \"obj_\" for namespacing. Left \"fields\" bare and didn\u0027t namespace \"save()\" since it\u0027s not part of the base object scaffolding, but rather something we expect the subclasses to implement.","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"72f6f136da4967e162f9a17081b714133c734284","unresolved":false,"context_lines":[{"line_number":176,"context_line":"    @classmethod"},{"line_number":177,"context_line":"    def obj_class_from_name(cls, objname, objver):"},{"line_number":178,"context_line":"        \"\"\"Returns a class from the registry based on a name and version.\"\"\""},{"line_number":179,"context_line":"        if objname not in cls._obj_classes:"},{"line_number":180,"context_line":"            LOG.error(_(\u0027Unable to instantiate unregistered object type \u0027"},{"line_number":181,"context_line":"                        \u0027%(objtype)s\u0027) % dict(objtype\u003dobjname))"},{"line_number":182,"context_line":"            raise exception.UnsupportedObjectError(objtype\u003dobjname)"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw8M%3D","line":179,"updated":"2013-05-23 15:40:23.000000000","message":"any thoughts on using entrypoints for this?","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"d61235ce7ab4e6c64ee68a2b6108feefe2e79cf1","unresolved":false,"context_lines":[{"line_number":176,"context_line":"    @classmethod"},{"line_number":177,"context_line":"    def obj_class_from_name(cls, objname, objver):"},{"line_number":178,"context_line":"        \"\"\"Returns a class from the registry based on a name and version.\"\"\""},{"line_number":179,"context_line":"        if objname not in cls._obj_classes:"},{"line_number":180,"context_line":"            LOG.error(_(\u0027Unable to instantiate unregistered object type \u0027"},{"line_number":181,"context_line":"                        \u0027%(objtype)s\u0027) % dict(objtype\u003dobjname))"},{"line_number":182,"context_line":"            raise exception.UnsupportedObjectError(objtype\u003dobjname)"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw08%3D","line":179,"in_reply_to":"AAAAPH%2F%2Fw2A%3D","updated":"2013-05-23 16:15:48.000000000","message":"Oh, of course we\u0027ll need the metaclass; my thinking was just, like you say, trying to smooth over the import hack.  It could also allow nova extensions to define more objects, but I don\u0027t know if that has any utility…","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"86532679ab2dea8752531dd59aeb4a967fa10795","unresolved":false,"context_lines":[{"line_number":176,"context_line":"    @classmethod"},{"line_number":177,"context_line":"    def obj_class_from_name(cls, objname, objver):"},{"line_number":178,"context_line":"        \"\"\"Returns a class from the registry based on a name and version.\"\"\""},{"line_number":179,"context_line":"        if objname not in cls._obj_classes:"},{"line_number":180,"context_line":"            LOG.error(_(\u0027Unable to instantiate unregistered object type \u0027"},{"line_number":181,"context_line":"                        \u0027%(objtype)s\u0027) % dict(objtype\u003dobjname))"},{"line_number":182,"context_line":"            raise exception.UnsupportedObjectError(objtype\u003dobjname)"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw2A%3D","line":179,"in_reply_to":"AAAAPH%2F%2Fw8M%3D","updated":"2013-05-23 16:08:47.000000000","message":"What would it buy us? We still need the magic metaclass to provide the manged get/set properties. Maybe entrypoints would help us avoid the need for the oddball import hack we\u0027re going to have to do to get everything registered? I honestly don\u0027t know :)","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"7cc6921533fa51f6f29e8800161a62761d4362f9","unresolved":false,"context_lines":[{"line_number":33,"context_line":""},{"line_number":34,"context_line":"def make_class_properties(cls):"},{"line_number":35,"context_line":"    # NOTE(danms): Inherit NovaObject\u0027s base fields only"},{"line_number":36,"context_line":"    cls.fields.update(NovaObject.fields)"},{"line_number":37,"context_line":"    for name, typefn in cls.fields.iteritems():"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"        def getter(self, name\u003dname, typefn\u003dtypefn):"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAPH%2F%2Fwdc%3D","line":36,"updated":"2013-05-23 18:46:35.000000000","message":"Added explicit base-only inheritance here for now.","commit_id":"a02cde858a6805d1e6b18ac4dded63b2ec2cc0ac"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"7cc6921533fa51f6f29e8800161a62761d4362f9","unresolved":false,"context_lines":[{"line_number":170,"context_line":"        \u0027created_at\u0027: obj_utils.datetime_or_none,"},{"line_number":171,"context_line":"        \u0027updated_at\u0027: obj_utils.datetime_or_none,"},{"line_number":172,"context_line":"        \u0027deleted_at\u0027: obj_utils.datetime_or_none,"},{"line_number":173,"context_line":"        }"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    def __init__(self):"},{"line_number":176,"context_line":"        self._changed_fields \u003d set()"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAPH%2F%2Fwdo%3D","line":173,"updated":"2013-05-23 18:46:35.000000000","message":"Added the base attributes here...","commit_id":"a02cde858a6805d1e6b18ac4dded63b2ec2cc0ac"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"7cc6921533fa51f6f29e8800161a62761d4362f9","unresolved":false,"context_lines":[{"line_number":185,"context_line":"    @classmethod"},{"line_number":186,"context_line":"    def obj_class_from_name(cls, objname, objver):"},{"line_number":187,"context_line":"        \"\"\"Returns a class from the registry based on a name and version.\"\"\""},{"line_number":188,"context_line":"        if objname not in cls._obj_classes:"},{"line_number":189,"context_line":"            LOG.error(_(\u0027Unable to instantiate unregistered object type \u0027"},{"line_number":190,"context_line":"                        \u0027%(objtype)s\u0027) % dict(objtype\u003dobjname))"},{"line_number":191,"context_line":"            raise exception.UnsupportedObjectError(objtype\u003dobjname)"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAPH%2F%2Fwdw%3D","line":188,"updated":"2013-05-23 18:46:35.000000000","message":"Punting on this until Chris can finish his evaluation of methods for supporting multiple DB backends without db.api.py. I think that we can change that around post-merge if we decide that entrypoints is a good way to handle that or something.","commit_id":"a02cde858a6805d1e6b18ac4dded63b2ec2cc0ac"},{"author":{"_account_id":2271,"name":"Michael Still","email":"mikal@stillhq.com","username":"mikalstill"},"change_message_id":"d1e238bc120e3f973eb35422454fb8a98699ec6d","unresolved":false,"context_lines":[{"line_number":1,"context_line":"#    Copyright 2013 IBM Corp."},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"#    not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2FolE%3D","line":1,"updated":"2013-05-28 21:27:11.000000000","message":"Ditto on the copyright statement.","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"}],"nova/object/utils.py":[{"author":{"_account_id":2271,"name":"Michael Still","email":"mikal@stillhq.com","username":"mikalstill"},"change_message_id":"d1e238bc120e3f973eb35422454fb8a98699ec6d","unresolved":false,"context_lines":[{"line_number":1,"context_line":"#    Copyright 2013 IBM Corp."},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"#    not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2Foko%3D","line":1,"updated":"2013-05-28 21:27:11.000000000","message":"You get the idea.","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"}],"nova/objects/base.py":[{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"5a5f7ba2149dfc4867e6aeca41559f2093ecc249","unresolved":false,"context_lines":[{"line_number":271,"context_line":"        for name in self.fields:"},{"line_number":272,"context_line":"            if hasattr(self, get_attrname(name)):"},{"line_number":273,"context_line":"                primitive[name] \u003d self._attr_to_primitive(name)"},{"line_number":274,"context_line":"        obj \u003d {\u0027nova_object.name\u0027: \u0027nova.\u0027 + self.obj_name(),"},{"line_number":275,"context_line":"               \u0027nova_object.version\u0027: self.version,"},{"line_number":276,"context_line":"               \u0027nova_object.data\u0027: primitive}"},{"line_number":277,"context_line":"        if self.obj_what_changed():"}],"source_content_type":"text/x-python","patch_set":16,"id":"AAAAPH%2F%2Foac%3D","line":274,"updated":"2013-05-28 22:08:17.000000000","message":"Namespaced the object names just for future stuff.","commit_id":"985d1c70b20b6157838a7ae12d245626e0ba3955"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"24ea6d47e140158fa41392e563497dd729ada4f0","unresolved":false,"context_lines":[{"line_number":271,"context_line":"        for name in self.fields:"},{"line_number":272,"context_line":"            if hasattr(self, get_attrname(name)):"},{"line_number":273,"context_line":"                primitive[name] \u003d self._attr_to_primitive(name)"},{"line_number":274,"context_line":"        obj \u003d {\u0027nova_object.name\u0027: \u0027nova.\u0027 + self.obj_name(),"},{"line_number":275,"context_line":"               \u0027nova_object.version\u0027: self.version,"},{"line_number":276,"context_line":"               \u0027nova_object.data\u0027: primitive}"},{"line_number":277,"context_line":"        if self.obj_what_changed():"}],"source_content_type":"text/x-python","patch_set":16,"id":"AAAAPH%2F%2FoR4%3D","line":274,"in_reply_to":"AAAAPH%2F%2FoT0%3D","updated":"2013-05-28 23:03:10.000000000","message":"Done","commit_id":"985d1c70b20b6157838a7ae12d245626e0ba3955"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"3a06f84e4f0c854040dd4b15045e2aa46f58e8af","unresolved":false,"context_lines":[{"line_number":271,"context_line":"        for name in self.fields:"},{"line_number":272,"context_line":"            if hasattr(self, get_attrname(name)):"},{"line_number":273,"context_line":"                primitive[name] \u003d self._attr_to_primitive(name)"},{"line_number":274,"context_line":"        obj \u003d {\u0027nova_object.name\u0027: \u0027nova.\u0027 + self.obj_name(),"},{"line_number":275,"context_line":"               \u0027nova_object.version\u0027: self.version,"},{"line_number":276,"context_line":"               \u0027nova_object.data\u0027: primitive}"},{"line_number":277,"context_line":"        if self.obj_what_changed():"}],"source_content_type":"text/x-python","patch_set":16,"id":"AAAAPH%2F%2FoT0%3D","line":274,"in_reply_to":"AAAAPH%2F%2Foac%3D","updated":"2013-05-28 22:51:27.000000000","message":"I wonder if this would be better as nova_object.namespace?  Haven\u0027t thought about it too much... just throwing it out there.","commit_id":"985d1c70b20b6157838a7ae12d245626e0ba3955"}],"nova/tests/object/__init__.py":[{"author":{"_account_id":2271,"name":"Michael Still","email":"mikal@stillhq.com","username":"mikalstill"},"change_message_id":"d1e238bc120e3f973eb35422454fb8a98699ec6d","unresolved":false,"context_lines":[{"line_number":1,"context_line":"#    Copyright 2013 IBM Corp."},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"#    not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2Fokk%3D","line":1,"updated":"2013-05-28 21:27:11.000000000","message":"Yeah, that thing.","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"}],"nova/tests/object/test_object.py":[{"author":{"_account_id":2271,"name":"Michael Still","email":"mikal@stillhq.com","username":"mikalstill"},"change_message_id":"d1e238bc120e3f973eb35422454fb8a98699ec6d","unresolved":false,"context_lines":[{"line_number":1,"context_line":"#    Copyright 2013 IBM Corp."},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"#    not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":15,"id":"AAAAPH%2F%2Fokg%3D","line":1,"updated":"2013-05-28 21:27:11.000000000","message":"...","commit_id":"5945b5b90d8e98ba182cc143e538116685347529"}],"nova/tests/test_object.py":[{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"b79ed34bceb6cfbd0bae89619a73ce8e4a1e6a50","unresolved":false,"context_lines":[{"line_number":243,"context_line":"    base.NovaObject.indirection_api \u003d _api"},{"line_number":244,"context_line":""},{"line_number":245,"context_line":""},{"line_number":246,"context_line":"class _RemoteTest(_ObjectTest):"},{"line_number":247,"context_line":"    def _testable_conductor(self):"},{"line_number":248,"context_line":"        self.conductor_service \u003d self.start_service("},{"line_number":249,"context_line":"            \u0027conductor\u0027, manager\u003d\u0027nova.conductor.manager.ConductorManager\u0027)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2FzAg%3D","line":246,"updated":"2013-05-22 20:20:30.000000000","message":"Do you provide this class just to parallel _ObjectTest above, or are you intending to make more subclasses of _RemoteTest at some point?  (And I don\u0027t really think there\u0027s any point in using \u0027_\u0027-prefixed function or class names in tests, but *shrug*)","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"7fd21ee6159fe0ec3e24872d248e53004191f525","unresolved":false,"context_lines":[{"line_number":243,"context_line":"    base.NovaObject.indirection_api \u003d _api"},{"line_number":244,"context_line":""},{"line_number":245,"context_line":""},{"line_number":246,"context_line":"class _RemoteTest(_ObjectTest):"},{"line_number":247,"context_line":"    def _testable_conductor(self):"},{"line_number":248,"context_line":"        self.conductor_service \u003d self.start_service("},{"line_number":249,"context_line":"            \u0027conductor\u0027, manager\u003d\u0027nova.conductor.manager.ConductorManager\u0027)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy2I%3D","line":246,"in_reply_to":"AAAAPH%2F%2Fy30%3D","updated":"2013-05-22 21:35:43.000000000","message":"I prefer the underscore so that it\u0027s not picked up at all, even with no methods.  Agree this seems to be convention (or should be the convention :)","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"955c41c947076f055aefb0dc656cb55ec8c77063","unresolved":false,"context_lines":[{"line_number":243,"context_line":"    base.NovaObject.indirection_api \u003d _api"},{"line_number":244,"context_line":""},{"line_number":245,"context_line":""},{"line_number":246,"context_line":"class _RemoteTest(_ObjectTest):"},{"line_number":247,"context_line":"    def _testable_conductor(self):"},{"line_number":248,"context_line":"        self.conductor_service \u003d self.start_service("},{"line_number":249,"context_line":"            \u0027conductor\u0027, manager\u003d\u0027nova.conductor.manager.ConductorManager\u0027)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAPH%2F%2Fy30%3D","line":246,"in_reply_to":"AAAAPH%2F%2FzAg%3D","updated":"2013-05-22 21:23:34.000000000","message":"I think I was thinking of it being potentially a mixin-type thing. I need to consolidate these anyway, so I will do that.\n\nRe: naming, it seems to be convention for a base class with no tests, so that it doesn\u0027t get picked up by the test gatherer thingy. I suppose if there are no actual test_foo() methods inside, it might not matter.","commit_id":"59b202a16f94b540c7ef08f984075c0a1bcfb37b"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"f1eadccfde3a9c630b1255f6c4449675f6e9b54e","unresolved":false,"context_lines":[{"line_number":193,"context_line":""},{"line_number":194,"context_line":"class _TestObject(object):"},{"line_number":195,"context_line":"    def _no_remotes(self):"},{"line_number":196,"context_line":"        self.remote_object_calls \u003d [1]"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    @no_remotes"},{"line_number":199,"context_line":"    def test_hydration_type_error(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FyHc%3D","line":196,"updated":"2013-05-23 05:21:59.000000000","message":"Leftover before you created the decorator?","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"dfd072176b7da7630ece095875975a23a7f4d87c","unresolved":false,"context_lines":[{"line_number":193,"context_line":""},{"line_number":194,"context_line":"class _TestObject(object):"},{"line_number":195,"context_line":"    def _no_remotes(self):"},{"line_number":196,"context_line":"        self.remote_object_calls \u003d [1]"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    @no_remotes"},{"line_number":199,"context_line":"    def test_hydration_type_error(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAPH%2F%2FxSI%3D","line":196,"in_reply_to":"AAAAPH%2F%2FyHc%3D","updated":"2013-05-23 13:39:52.000000000","message":"Oops, yep, thanks :)","commit_id":"54b0238487a6378049d849ef33f1234fe2eab54e"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"72f6f136da4967e162f9a17081b714133c734284","unresolved":false,"context_lines":[{"line_number":180,"context_line":"        self.assertNotEqual(self.remote_object_calls, [])"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"def no_remotes(fn):"},{"line_number":184,"context_line":"    \"\"\"Decorator that will fool the tearDown routine on _RemoteTest"},{"line_number":185,"context_line":"    tests that aren\u0027t expected to trigger any remote calls."},{"line_number":186,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw7Y%3D","line":183,"updated":"2013-05-23 15:40:23.000000000","message":"Ugh.  This doesn\u0027t really feel right to me, having any tests in tearDown().  What if the reason remote_object_calls is an empty list is because the test failed?  Then the assertNotEqual() in tearDown() will obscure the actual test failure.  I think you should have this explicit, either in each test method, or as part of a method call made from each test method…that would also eliminate the need for this decorator.","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"d61235ce7ab4e6c64ee68a2b6108feefe2e79cf1","unresolved":false,"context_lines":[{"line_number":180,"context_line":"        self.assertNotEqual(self.remote_object_calls, [])"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"def no_remotes(fn):"},{"line_number":184,"context_line":"    \"\"\"Decorator that will fool the tearDown routine on _RemoteTest"},{"line_number":185,"context_line":"    tests that aren\u0027t expected to trigger any remote calls."},{"line_number":186,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw0o%3D","line":183,"in_reply_to":"AAAAPH%2F%2Fw1o%3D","updated":"2013-05-23 16:15:48.000000000","message":"Hmmm; I thought it would obscure it, but I guess not.  Anyway, I just don\u0027t really like this way of constructing tests…","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"86532679ab2dea8752531dd59aeb4a967fa10795","unresolved":false,"context_lines":[{"line_number":180,"context_line":"        self.assertNotEqual(self.remote_object_calls, [])"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"def no_remotes(fn):"},{"line_number":184,"context_line":"    \"\"\"Decorator that will fool the tearDown routine on _RemoteTest"},{"line_number":185,"context_line":"    tests that aren\u0027t expected to trigger any remote calls."},{"line_number":186,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAPH%2F%2Fw1o%3D","line":183,"in_reply_to":"AAAAPH%2F%2Fw7Y%3D","updated":"2013-05-23 16:08:47.000000000","message":"It doesn\u0027t obscure it, does it? On my machine, I see the original failure and the subsequent one in tearDown() alongside it.\n\nI wanted to make it explicit to the contrary, meaning we always expect a _RemoteTest test to generate some remote activity unless it\u0027s specifically not a remoted operation, just to keep everyone honest. However, if this is really that unpleasant, I can change it I guess.","commit_id":"150bf5cf9c4263176048815a12a090f646401c4c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"7cc6921533fa51f6f29e8800161a62761d4362f9","unresolved":false,"context_lines":[{"line_number":314,"context_line":"        obj \u003d MyObj.get(ctxt1)"},{"line_number":315,"context_line":"        obj.update_test(ctxt2)"},{"line_number":316,"context_line":"        self.assertEqual(obj.bar, \u0027alternate-context\u0027)"},{"line_number":317,"context_line":"        self.assertRemotes()"},{"line_number":318,"context_line":""},{"line_number":319,"context_line":"    def test_orphaned_object(self):"},{"line_number":320,"context_line":"        ctxt \u003d context.get_admin_context()"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAAPH%2F%2FwdM%3D","line":317,"updated":"2013-05-23 18:46:35.000000000","message":"Replaced the decorator with explicit checks of the empty or non-empty-ness of the remote list.","commit_id":"a02cde858a6805d1e6b18ac4dded63b2ec2cc0ac"}]}
