)]}'
{"watcher/cmd/api.py":[{"author":{"_account_id":16495,"name":"Jean-Emile DARTOIS","email":"jean-emile.dartois@b-com.com","username":"JeD"},"change_message_id":"d3ae3960637e2349ff5b4f17a0830dc2a8810d2f","unresolved":false,"context_lines":[{"line_number":36,"context_line":"    host, port \u003d cfg.CONF.api.host, cfg.CONF.api.port"},{"line_number":37,"context_line":"    protocol \u003d \"http\" if not CONF.api.enable_ssl_api else \"https\""},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"    # Enable object backporting via the conductor"},{"line_number":40,"context_line":"    base.WatcherObject.indirection_api \u003d base.WatcherObjectIndirectionAPI()"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    # Build and start the WSGI app"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_02cb5a73","line":39,"updated":"2016-06-23 08:34:06.000000000","message":"What is the conductor in watcher ?","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":36,"context_line":"    host, port \u003d cfg.CONF.api.host, cfg.CONF.api.port"},{"line_number":37,"context_line":"    protocol \u003d \"http\" if not CONF.api.enable_ssl_api else \"https\""},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"    # Enable object backporting via the conductor"},{"line_number":40,"context_line":"    base.WatcherObject.indirection_api \u003d base.WatcherObjectIndirectionAPI()"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    # Build and start the WSGI app"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_77cbe9a5","line":39,"in_reply_to":"3aaa91ec_02cb5a73","updated":"2016-06-23 13:14:08.000000000","message":"As of now, the client side of the Indirection API is activated here on the Watcher API with the server side of it attached to the Decision Engine process. Other projects are doing it in a separate \"Conductor\" process although this was a PoC so I didn\u0027t bother at the time.","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"}],"watcher/decision_engine/messaging/indirection_api.py":[{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"868e3bfdfc5dc799d48c4446bf447036486faaee","unresolved":false,"context_lines":[{"line_number":19,"context_line":""},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"class IndirectionApiEndpoint(object):"},{"line_number":22,"context_line":"    \"Indirection API callbacks\""},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    def __init__(self, messaging):"},{"line_number":25,"context_line":"        self._messaging \u003d messaging"}],"source_content_type":"text/x-python","patch_set":3,"id":"3aaa91ec_443bd638","line":22,"range":{"start_line":22,"start_character":5,"end_line":22,"end_character":30},"updated":"2016-06-22 14:45:53.000000000","message":"nit: need make this a docstring","commit_id":"c7142cad8b57a4c29d4b3cb52c280ac969a7d7dd"}],"watcher/decision_engine/strategy/strategies/dummy_strategy.py":[{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":9,"context_line":"#"},{"line_number":10,"context_line":"# http://www.apache.org/licenses/LICENSE-2.0"},{"line_number":11,"context_line":"#"},{"line_number":12,"context_line":"# Unless required by applicable law or agreed to in writing, software"},{"line_number":13,"context_line":"# distributed under the License is distributed on an \"AS IS\" BASIS,"},{"line_number":14,"context_line":"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or"},{"line_number":15,"context_line":"# implied."}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_3208612c","line":12,"updated":"2016-06-23 13:14:08.000000000","message":"all changes made to this file should be reverted as well since it\u0027s not related to OVO","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"}],"watcher/metrics_engine/cluster_model_collector/loading.py":[{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# -*- encoding: utf-8 -*-"},{"line_number":2,"context_line":"# Copyright (c) 2016 b\u003c\u003ecom"},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\");"},{"line_number":5,"context_line":"# you may not use this file except in compliance with the License."},{"line_number":6,"context_line":"# You may obtain a copy of the License at"},{"line_number":7,"context_line":"#"},{"line_number":8,"context_line":"# http://www.apache.org/licenses/LICENSE-2.0"},{"line_number":9,"context_line":"#"},{"line_number":10,"context_line":"# Unless required by applicable law or agreed to in writing, software"},{"line_number":11,"context_line":"# distributed under the License is distributed on an \"AS IS\" BASIS,"},{"line_number":12,"context_line":"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or"},{"line_number":13,"context_line":"# implied."},{"line_number":14,"context_line":"# See the License for the specific language governing permissions and"},{"line_number":15,"context_line":"# limitations under the License."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"from watcher.common.loader import default"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"class ClusterModelCollectorLoader(default.DefaultLoader):"},{"line_number":21,"context_line":"    def __init__(self):"},{"line_number":22,"context_line":"        super(ClusterModelCollectorLoader, self).__init__("},{"line_number":23,"context_line":"            namespace\u003d\u0027watcher_cluster_model_collectors\u0027)"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_92167553","line":23,"range":{"start_line":1,"start_character":0,"end_line":23,"end_character":57},"updated":"2016-06-23 13:14:08.000000000","message":"this file is not related to OVO, so we should remove it.","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"}],"watcher/objects/base.py":[{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":61,"context_line":"    }"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    def obj_refresh(self, loaded_object):"},{"line_number":64,"context_line":"        \"\"\"Applies updates for objects that inherit from base.IronicObject."},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"        Checks for updated attributes in an object. Updates are applied from"},{"line_number":67,"context_line":"        the loaded object column by column in comparison with the current"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_442c3d02","line":64,"range":{"start_line":64,"start_character":62,"end_line":64,"end_character":74},"updated":"2016-06-23 13:14:08.000000000","message":"s/IronicObject/WatcherObject","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"},{"author":{"_account_id":16495,"name":"Jean-Emile DARTOIS","email":"jean-emile.dartois@b-com.com","username":"JeD"},"change_message_id":"359177c9a62853559186f1942139e9544daf623e","unresolved":false,"context_lines":[{"line_number":94,"context_line":"    def __init__(self):"},{"line_number":95,"context_line":"        super(WatcherObjectIndirectionAPI, self).__init__()"},{"line_number":96,"context_line":"        from watcher.decision_engine import rpcapi as conductor_api"},{"line_number":97,"context_line":"        self._conductor \u003d conductor_api.DecisionEngineAPI()"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    def object_action(self, context, objinst, objmethod, args, kwargs):"},{"line_number":100,"context_line":"        return self._conductor.object_action(context, objinst, objmethod,"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_b2273163","line":97,"updated":"2016-06-23 08:43:32.000000000","message":"IMHO, we should discuss what is the best place for the conductor ?","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":94,"context_line":"    def __init__(self):"},{"line_number":95,"context_line":"        super(WatcherObjectIndirectionAPI, self).__init__()"},{"line_number":96,"context_line":"        from watcher.decision_engine import rpcapi as conductor_api"},{"line_number":97,"context_line":"        self._conductor \u003d conductor_api.DecisionEngineAPI()"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    def object_action(self, context, objinst, objmethod, args, kwargs):"},{"line_number":100,"context_line":"        return self._conductor.object_action(context, objinst, objmethod,"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_458c4935","line":97,"in_reply_to":"3aaa91ec_b2273163","updated":"2016-06-23 13:14:08.000000000","message":"True. The choice I made here was to attach the indirection API service to the Decision Engine process. Nova (but also Ironic and Magnum) is doing it in a separate process running a Conductor API service (see https://github.com/openstack/nova/blob/master/nova/cmd/conductor.py) whereas","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"}],"watcher/tests/objects/test_objects.py":[{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"868e3bfdfc5dc799d48c4446bf447036486faaee","unresolved":false,"context_lines":[{"line_number":1,"context_line":"#    Copyright 2015 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"},{"line_number":5,"context_line":"#    a copy of the License at"},{"line_number":6,"context_line":"#"},{"line_number":7,"context_line":"#         http://www.apache.org/licenses/LICENSE-2.0"},{"line_number":8,"context_line":"#"},{"line_number":9,"context_line":"#    Unless required by applicable law or agreed to in writing, software"},{"line_number":10,"context_line":"#    distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT"},{"line_number":11,"context_line":"#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the"},{"line_number":12,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"#    under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"import datetime"},{"line_number":16,"context_line":"import gettext"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"import iso8601"},{"line_number":19,"context_line":"import netaddr"},{"line_number":20,"context_line":"from oslo_utils import timeutils"},{"line_number":21,"context_line":"import six"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"from watcher.objects import base"},{"line_number":24,"context_line":"from watcher.objects import utils"},{"line_number":25,"context_line":"from watcher.tests import base as test_base"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"gettext.install(\u0027watcher\u0027)"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"class MyObj(base.WatcherObject):"},{"line_number":31,"context_line":"    VERSION \u003d \u00271.0\u0027"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"    fields \u003d {\u0027foo\u0027: int,"},{"line_number":34,"context_line":"              \u0027bar\u0027: str,"},{"line_number":35,"context_line":"              \u0027missing\u0027: str,"},{"line_number":36,"context_line":"              }"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"    def obj_load_attr(self, attrname):"},{"line_number":39,"context_line":"        setattr(self, attrname, \u0027loaded!\u0027)"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    def query(cls, context):"},{"line_number":42,"context_line":"        obj \u003d cls(context)"},{"line_number":43,"context_line":"        obj.foo \u003d 1"},{"line_number":44,"context_line":"        obj.bar \u003d \u0027bar\u0027"},{"line_number":45,"context_line":"        obj.obj_reset_changes()"},{"line_number":46,"context_line":"        return obj"},{"line_number":47,"context_line":""},{"line_number":48,"context_line":"    def marco(self, context):"},{"line_number":49,"context_line":"        return \u0027polo\u0027"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    def update_test(self, context):"},{"line_number":52,"context_line":"        if context.project_id \u003d\u003d \u0027alternate\u0027:"},{"line_number":53,"context_line":"            self.bar \u003d \u0027alternate-context\u0027"},{"line_number":54,"context_line":"        else:"},{"line_number":55,"context_line":"            self.bar \u003d \u0027updated\u0027"},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"    def save(self, context):"},{"line_number":58,"context_line":"        self.obj_reset_changes()"},{"line_number":59,"context_line":""},{"line_number":60,"context_line":"    def refresh(self, context):"},{"line_number":61,"context_line":"        self.foo \u003d 321"},{"line_number":62,"context_line":"        self.bar \u003d \u0027refreshed\u0027"},{"line_number":63,"context_line":"        self.obj_reset_changes()"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"    def modify_save_modify(self, context):"},{"line_number":66,"context_line":"        self.bar \u003d \u0027meow\u0027"},{"line_number":67,"context_line":"        self.save()"},{"line_number":68,"context_line":"        self.foo \u003d 42"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"class MyObj2(object):"},{"line_number":72,"context_line":"    @classmethod"},{"line_number":73,"context_line":"    def obj_name(cls):"},{"line_number":74,"context_line":"        return \u0027MyObj\u0027"},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"    def get(cls, *args, **kwargs):"},{"line_number":77,"context_line":"        pass"},{"line_number":78,"context_line":""},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"class DummySubclassedObject(MyObj):"},{"line_number":81,"context_line":"    fields \u003d {\u0027new_field\u0027: str}"},{"line_number":82,"context_line":""},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"class TestMetaclass(test_base.TestCase):"},{"line_number":85,"context_line":"    def test_obj_tracking(self):"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"        @six.add_metaclass(base.WatcherObjectMetaclass)"},{"line_number":88,"context_line":"        class NewBaseClass(object):"},{"line_number":89,"context_line":"            fields \u003d {}"},{"line_number":90,"context_line":""},{"line_number":91,"context_line":"            @classmethod"},{"line_number":92,"context_line":"            def obj_name(cls):"},{"line_number":93,"context_line":"                return cls.__name__"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"        class Test1(NewBaseClass):"},{"line_number":96,"context_line":"            @staticmethod"},{"line_number":97,"context_line":"            def obj_name():"},{"line_number":98,"context_line":"                return \u0027fake1\u0027"},{"line_number":99,"context_line":""},{"line_number":100,"context_line":"        class Test2(NewBaseClass):"},{"line_number":101,"context_line":"            pass"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"        class Test2v2(NewBaseClass):"},{"line_number":104,"context_line":"            @staticmethod"},{"line_number":105,"context_line":"            def obj_name():"},{"line_number":106,"context_line":"                return \u0027Test2\u0027"},{"line_number":107,"context_line":""},{"line_number":108,"context_line":"        expected \u003d {\u0027fake1\u0027: [Test1], \u0027Test2\u0027: [Test2, Test2v2]}"},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"        self.assertEqual(expected, NewBaseClass._obj_classes)"},{"line_number":111,"context_line":"        # The following should work, also."},{"line_number":112,"context_line":"        self.assertEqual(expected, Test1._obj_classes)"},{"line_number":113,"context_line":"        self.assertEqual(expected, Test2._obj_classes)"},{"line_number":114,"context_line":""},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"class TestUtils(test_base.TestCase):"},{"line_number":117,"context_line":""},{"line_number":118,"context_line":"    def test_datetime_or_none(self):"},{"line_number":119,"context_line":"        naive_dt \u003d datetime.datetime.now()"},{"line_number":120,"context_line":"        dt \u003d timeutils.parse_isotime(timeutils.isotime(naive_dt))"},{"line_number":121,"context_line":"        self.assertEqual(dt, utils.datetime_or_none(dt))"},{"line_number":122,"context_line":"        self.assertEqual(naive_dt.replace(tzinfo\u003diso8601.iso8601.Utc(),"},{"line_number":123,"context_line":"                                          microsecond\u003d0),"},{"line_number":124,"context_line":"                         utils.datetime_or_none(dt))"},{"line_number":125,"context_line":"        self.assertIsNone(utils.datetime_or_none(None))"},{"line_number":126,"context_line":"        self.assertRaises(ValueError, utils.datetime_or_none, \u0027foo\u0027)"},{"line_number":127,"context_line":""},{"line_number":128,"context_line":"    def test_datetime_or_str_or_none(self):"},{"line_number":129,"context_line":"        dts \u003d timeutils.isotime()"},{"line_number":130,"context_line":"        dt \u003d timeutils.parse_isotime(dts)"},{"line_number":131,"context_line":"        self.assertEqual(dt, utils.datetime_or_str_or_none(dt))"},{"line_number":132,"context_line":"        self.assertIsNone(utils.datetime_or_str_or_none(None))"},{"line_number":133,"context_line":"        self.assertEqual(dt, utils.datetime_or_str_or_none(dts))"},{"line_number":134,"context_line":"        self.assertRaises(ValueError, utils.datetime_or_str_or_none, \u0027foo\u0027)"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":"    def test_int_or_none(self):"},{"line_number":137,"context_line":"        self.assertEqual(1, utils.int_or_none(1))"},{"line_number":138,"context_line":"        self.assertEqual(1, utils.int_or_none(\u00271\u0027))"},{"line_number":139,"context_line":"        self.assertIsNone(utils.int_or_none(None))"},{"line_number":140,"context_line":"        self.assertRaises(ValueError, utils.int_or_none, \u0027foo\u0027)"},{"line_number":141,"context_line":""},{"line_number":142,"context_line":"    def test_str_or_none(self):"},{"line_number":143,"context_line":"        class Obj(object):"},{"line_number":144,"context_line":"            pass"},{"line_number":145,"context_line":"        self.assertEqual(\u0027foo\u0027, utils.str_or_none(\u0027foo\u0027))"},{"line_number":146,"context_line":"        self.assertEqual(\u00271\u0027, utils.str_or_none(1))"},{"line_number":147,"context_line":"        self.assertIsNone(utils.str_or_none(None))"},{"line_number":148,"context_line":""},{"line_number":149,"context_line":"    def test_ip_or_none(self):"},{"line_number":150,"context_line":"        ip4 \u003d netaddr.IPAddress(\u00271.2.3.4\u0027, 4)"},{"line_number":151,"context_line":"        ip6 \u003d netaddr.IPAddress(\u00271::2\u0027, 6)"},{"line_number":152,"context_line":"        self.assertEqual(ip4, utils.ip_or_none(4)(\u00271.2.3.4\u0027))"},{"line_number":153,"context_line":"        self.assertEqual(ip6, utils.ip_or_none(6)(\u00271::2\u0027))"},{"line_number":154,"context_line":"        self.assertIsNone(utils.ip_or_none(4)(None))"},{"line_number":155,"context_line":"        self.assertIsNone(utils.ip_or_none(6)(None))"},{"line_number":156,"context_line":"        self.assertRaises(netaddr.AddrFormatError, utils.ip_or_none(4), \u0027foo\u0027)"},{"line_number":157,"context_line":"        self.assertRaises(netaddr.AddrFormatError, utils.ip_or_none(6), \u0027foo\u0027)"},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    def test_dt_serializer(self):"},{"line_number":160,"context_line":"        class Obj(object):"},{"line_number":161,"context_line":"            foo \u003d utils.dt_serializer(\u0027bar\u0027)"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"        obj \u003d Obj()"},{"line_number":164,"context_line":"        obj.bar \u003d timeutils.parse_isotime(\u00271955-11-05T00:00:00Z\u0027)"},{"line_number":165,"context_line":"        self.assertEqual(\u00271955-11-05T00:00:00Z\u0027, obj.foo())"},{"line_number":166,"context_line":"        obj.bar \u003d None"},{"line_number":167,"context_line":"        self.assertIsNone(obj.foo())"},{"line_number":168,"context_line":"        obj.bar \u003d \u0027foo\u0027"},{"line_number":169,"context_line":"        self.assertRaises(AttributeError, obj.foo)"},{"line_number":170,"context_line":""},{"line_number":171,"context_line":"    def test_dt_deserializer(self):"},{"line_number":172,"context_line":"        dt \u003d timeutils.parse_isotime(\u00271955-11-05T00:00:00Z\u0027)"},{"line_number":173,"context_line":"        self.assertEqual(dt, utils.dt_deserializer(timeutils.isotime(dt)))"},{"line_number":174,"context_line":"        self.assertIsNone(utils.dt_deserializer(None))"},{"line_number":175,"context_line":"        self.assertRaises(ValueError, utils.dt_deserializer, \u0027foo\u0027)"},{"line_number":176,"context_line":""},{"line_number":177,"context_line":"    def test_obj_to_primitive_list(self):"},{"line_number":178,"context_line":"        class MyList(base.ObjectListBase, base.WatcherObject):"},{"line_number":179,"context_line":"            pass"},{"line_number":180,"context_line":"        mylist \u003d MyList(self.context)"},{"line_number":181,"context_line":"        mylist.objects \u003d [1, 2, 3]"},{"line_number":182,"context_line":"        self.assertEqual([1, 2, 3], base.obj_to_primitive(mylist))"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"    def test_obj_to_primitive_dict(self):"},{"line_number":185,"context_line":"        myobj \u003d MyObj(self.context)"},{"line_number":186,"context_line":"        myobj.foo \u003d 1"},{"line_number":187,"context_line":"        myobj.bar \u003d \u0027foo\u0027"},{"line_number":188,"context_line":"        self.assertEqual({\u0027foo\u0027: 1, \u0027bar\u0027: \u0027foo\u0027},"},{"line_number":189,"context_line":"                         base.obj_to_primitive(myobj))"},{"line_number":190,"context_line":""},{"line_number":191,"context_line":"    def test_obj_to_primitive_recursive(self):"},{"line_number":192,"context_line":"        class MyList(base.ObjectListBase, base.WatcherObject):"},{"line_number":193,"context_line":"            pass"},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        mylist \u003d MyList(self.context)"},{"line_number":196,"context_line":"        mylist.objects \u003d [MyObj(self.context), MyObj(self.context)]"},{"line_number":197,"context_line":"        for i, value in enumerate(mylist):"},{"line_number":198,"context_line":"            value.foo \u003d i"},{"line_number":199,"context_line":"        self.assertEqual([{\u0027foo\u0027: 0}, {\u0027foo\u0027: 1}],"},{"line_number":200,"context_line":"                         base.obj_to_primitive(mylist))"},{"line_number":201,"context_line":""},{"line_number":202,"context_line":""},{"line_number":203,"context_line":"class TestObjectListBase(test_base.TestCase):"},{"line_number":204,"context_line":""},{"line_number":205,"context_line":"    def test_list_like_operations(self):"},{"line_number":206,"context_line":"        class Foo(base.ObjectListBase, base.WatcherObject):"},{"line_number":207,"context_line":"            pass"},{"line_number":208,"context_line":""},{"line_number":209,"context_line":"        objlist \u003d Foo(self.context)"},{"line_number":210,"context_line":"        objlist._context \u003d \u0027foo\u0027"},{"line_number":211,"context_line":"        objlist.objects \u003d [1, 2, 3]"},{"line_number":212,"context_line":"        self.assertEqual(list(objlist), objlist.objects)"},{"line_number":213,"context_line":"        self.assertEqual(3, len(objlist))"},{"line_number":214,"context_line":"        self.assertIn(2, objlist)"},{"line_number":215,"context_line":"        self.assertEqual([1], list(objlist[:1]))"},{"line_number":216,"context_line":"        self.assertEqual(\u0027foo\u0027, objlist[:1]._context)"},{"line_number":217,"context_line":"        self.assertEqual(3, objlist[2])"},{"line_number":218,"context_line":"        self.assertEqual(1, objlist.count(1))"},{"line_number":219,"context_line":"        self.assertEqual(1, objlist.index(2))"},{"line_number":220,"context_line":""},{"line_number":221,"context_line":"    def test_serialization(self):"},{"line_number":222,"context_line":"        class Foo(base.ObjectListBase, base.WatcherObject):"},{"line_number":223,"context_line":"            pass"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":"        class Bar(base.WatcherObject):"},{"line_number":226,"context_line":"            fields \u003d {\u0027foo\u0027: str}"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"        obj \u003d Foo(self.context)"},{"line_number":229,"context_line":"        obj.objects \u003d []"},{"line_number":230,"context_line":"        for i in \u0027abc\u0027:"},{"line_number":231,"context_line":"            bar \u003d Bar(self.context)"},{"line_number":232,"context_line":"            bar.foo \u003d i"},{"line_number":233,"context_line":"            obj.objects.append(bar)"},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"        obj2 \u003d base.WatcherObject.obj_from_primitive(obj.obj_to_primitive())"},{"line_number":236,"context_line":"        self.assertFalse(obj is obj2)"},{"line_number":237,"context_line":"        self.assertEqual([x.foo for x in obj],"},{"line_number":238,"context_line":"                         [y.foo for y in obj2])"},{"line_number":239,"context_line":""},{"line_number":240,"context_line":"    def _test_object_list_version_mappings(self, list_obj_class):"},{"line_number":241,"context_line":"        # Figure out what sort of object this list is for"},{"line_number":242,"context_line":"        list_field \u003d list_obj_class.fields[\u0027objects\u0027]"},{"line_number":243,"context_line":"        item_obj_field \u003d list_field._type._element_type"},{"line_number":244,"context_line":"        item_obj_name \u003d item_obj_field._type._obj_name"},{"line_number":245,"context_line":""},{"line_number":246,"context_line":"        # Look through all object classes of this type and make sure that"},{"line_number":247,"context_line":"        # the versions we find are covered by the parent list class"},{"line_number":248,"context_line":"        for item_class in base.WatcherObject._obj_classes[item_obj_name]:"},{"line_number":249,"context_line":"            self.assertIn("},{"line_number":250,"context_line":"                item_class.VERSION,"},{"line_number":251,"context_line":"                list_obj_class.child_versions.values())"},{"line_number":252,"context_line":""},{"line_number":253,"context_line":"    def test_object_version_mappings(self):"},{"line_number":254,"context_line":"        # Find all object list classes and make sure that they at least handle"},{"line_number":255,"context_line":"        # all the current object versions"},{"line_number":256,"context_line":"        for obj_classes in base.WatcherObject._obj_classes.values():"},{"line_number":257,"context_line":"            for obj_class in obj_classes:"},{"line_number":258,"context_line":"                if issubclass(obj_class, base.ObjectListBase):"},{"line_number":259,"context_line":"                    self._test_object_list_version_mappings(obj_class)"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"    def test_list_changes(self):"},{"line_number":262,"context_line":"        class Foo(base.ObjectListBase, base.WatcherObject):"},{"line_number":263,"context_line":"            pass"},{"line_number":264,"context_line":""},{"line_number":265,"context_line":"        class Bar(base.WatcherObject):"},{"line_number":266,"context_line":"            fields \u003d {\u0027foo\u0027: str}"},{"line_number":267,"context_line":""},{"line_number":268,"context_line":"        obj \u003d Foo(self.context, objects\u003d[])"},{"line_number":269,"context_line":"        self.assertEqual(set([\u0027objects\u0027]), obj.obj_what_changed())"},{"line_number":270,"context_line":"        obj.objects.append(Bar(self.context, foo\u003d\u0027test\u0027))"},{"line_number":271,"context_line":"        self.assertEqual(set([\u0027objects\u0027]), obj.obj_what_changed())"},{"line_number":272,"context_line":"        obj.obj_reset_changes()"},{"line_number":273,"context_line":"        # This should still look dirty because the child is dirty"},{"line_number":274,"context_line":"        self.assertEqual(set([\u0027objects\u0027]), obj.obj_what_changed())"},{"line_number":275,"context_line":"        obj.objects[0].obj_reset_changes()"},{"line_number":276,"context_line":"        # This should now look clean because the child is clean"},{"line_number":277,"context_line":"        self.assertEqual(set(), obj.obj_what_changed())"},{"line_number":278,"context_line":""},{"line_number":279,"context_line":""},{"line_number":280,"context_line":"class TestObjectSerializer(test_base.TestCase):"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":"    def test_serialize_entity_primitive(self):"},{"line_number":283,"context_line":"        ser \u003d base.WatcherObjectSerializer()"},{"line_number":284,"context_line":"        for thing in (1, \u0027foo\u0027, [1, 2], {\u0027foo\u0027: \u0027bar\u0027}):"},{"line_number":285,"context_line":"            self.assertEqual(thing, ser.serialize_entity(None, thing))"},{"line_number":286,"context_line":""},{"line_number":287,"context_line":"    def test_deserialize_entity_primitive(self):"},{"line_number":288,"context_line":"        ser \u003d base.WatcherObjectSerializer()"},{"line_number":289,"context_line":"        for thing in (1, \u0027foo\u0027, [1, 2], {\u0027foo\u0027: \u0027bar\u0027}):"},{"line_number":290,"context_line":"            self.assertEqual(thing, ser.deserialize_entity(None, thing))"},{"line_number":291,"context_line":""},{"line_number":292,"context_line":"    def test_object_serialization(self):"},{"line_number":293,"context_line":"        ser \u003d base.WatcherObjectSerializer()"},{"line_number":294,"context_line":"        obj \u003d MyObj(self.context)"},{"line_number":295,"context_line":"        primitive \u003d ser.serialize_entity(self.context, obj)"},{"line_number":296,"context_line":"        self.assertTrue(\u0027watcher_object.name\u0027 in primitive)"},{"line_number":297,"context_line":"        obj2 \u003d ser.deserialize_entity(self.context, primitive)"},{"line_number":298,"context_line":"        self.assertIsInstance(obj2, MyObj)"},{"line_number":299,"context_line":"        self.assertEqual(self.context, obj2._context)"},{"line_number":300,"context_line":""},{"line_number":301,"context_line":"    def test_object_serialization_iterables(self):"},{"line_number":302,"context_line":"        ser \u003d base.WatcherObjectSerializer()"},{"line_number":303,"context_line":"        obj \u003d MyObj(self.context)"},{"line_number":304,"context_line":"        for iterable in (list, tuple, set):"},{"line_number":305,"context_line":"            thing \u003d iterable([obj])"},{"line_number":306,"context_line":"            primitive \u003d ser.serialize_entity(self.context, thing)"},{"line_number":307,"context_line":"            self.assertEqual(1, len(primitive))"},{"line_number":308,"context_line":"            for item in primitive:"},{"line_number":309,"context_line":"                self.assertFalse(isinstance(item, base.WatcherObject))"},{"line_number":310,"context_line":"            thing2 \u003d ser.deserialize_entity(self.context, primitive)"},{"line_number":311,"context_line":"            self.assertEqual(1, len(thing2))"},{"line_number":312,"context_line":"            for item in thing2:"},{"line_number":313,"context_line":"                self.assertIsInstance(item, MyObj)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3aaa91ec_c4bfc65e","side":"PARENT","line":313,"range":{"start_line":1,"start_character":0,"end_line":313,"end_character":50},"updated":"2016-06-22 14:45:53.000000000","message":"This should be refactored instead of being removed like in nova: see https://github.com/openstack/nova/blob/master/nova/tests/unit/objects/test_objects.py","commit_id":"73cf5a98aec5cc8b4e1e21b1c9d7b66050b0a691"}],"watcher_tempest_plugin/tests/api/admin/test_audit_template.py":[{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"868e3bfdfc5dc799d48c4446bf447036486faaee","unresolved":false,"context_lines":[{"line_number":29,"context_line":""},{"line_number":30,"context_line":"    @test.attr(type\u003d\u0027smoke\u0027)"},{"line_number":31,"context_line":"    def test_create_audit_template(self):"},{"line_number":32,"context_line":"        goal_name \u003d \"dummy\""},{"line_number":33,"context_line":"        _, goal \u003d self.client.show_goal(goal_name)"},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"        params \u003d {"}],"source_content_type":"text/x-python","patch_set":3,"id":"3aaa91ec_e4180287","line":32,"range":{"start_line":32,"start_character":20,"end_line":32,"end_character":27},"updated":"2016-06-22 14:45:53.000000000","message":"This is actually a separate bug that we should report","commit_id":"c7142cad8b57a4c29d4b3cb52c280ac969a7d7dd"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"868e3bfdfc5dc799d48c4446bf447036486faaee","unresolved":false,"context_lines":[{"line_number":58,"context_line":""},{"line_number":59,"context_line":"    @test.attr(type\u003d\u0027smoke\u0027)"},{"line_number":60,"context_line":"    def test_create_audit_template_unicode_description(self):"},{"line_number":61,"context_line":"        goal_name \u003d \"dummy\""},{"line_number":62,"context_line":"        _, goal \u003d self.client.show_goal(goal_name)"},{"line_number":63,"context_line":"        # Use a unicode string for testing:"},{"line_number":64,"context_line":"        params \u003d {"}],"source_content_type":"text/x-python","patch_set":3,"id":"3aaa91ec_0416ee54","line":61,"range":{"start_line":61,"start_character":21,"end_line":61,"end_character":26},"updated":"2016-06-22 14:45:53.000000000","message":"ditto","commit_id":"c7142cad8b57a4c29d4b3cb52c280ac969a7d7dd"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"868e3bfdfc5dc799d48c4446bf447036486faaee","unresolved":false,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    @test.attr(type\u003d\u0027smoke\u0027)"},{"line_number":88,"context_line":"    def test_delete_audit_template(self):"},{"line_number":89,"context_line":"        _, goal \u003d self.client.show_goal(\"dummy\")"},{"line_number":90,"context_line":"        _, body \u003d self.create_audit_template(goal\u003dgoal[\u0027uuid\u0027])"},{"line_number":91,"context_line":"        audit_uuid \u003d body[\u0027uuid\u0027]"},{"line_number":92,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"3aaa91ec_640d323e","line":89,"range":{"start_line":89,"start_character":41,"end_line":89,"end_character":46},"updated":"2016-06-22 14:45:53.000000000","message":"ditto","commit_id":"c7142cad8b57a4c29d4b3cb52c280ac969a7d7dd"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"868e3bfdfc5dc799d48c4446bf447036486faaee","unresolved":false,"context_lines":[{"line_number":102,"context_line":"    @classmethod"},{"line_number":103,"context_line":"    def resource_setup(cls):"},{"line_number":104,"context_line":"        super(TestAuditTemplate, cls).resource_setup()"},{"line_number":105,"context_line":"        _, cls.goal \u003d cls.client.show_goal(\"dummy\")"},{"line_number":106,"context_line":"        _, cls.strategy \u003d cls.client.show_strategy(\"dummy\")"},{"line_number":107,"context_line":"        _, cls.audit_template \u003d cls.create_audit_template("},{"line_number":108,"context_line":"            goal\u003dcls.goal[\u0027uuid\u0027], strategy\u003dcls.strategy[\u0027uuid\u0027])"}],"source_content_type":"text/x-python","patch_set":3,"id":"3aaa91ec_4408f62d","line":105,"range":{"start_line":105,"start_character":44,"end_line":105,"end_character":49},"updated":"2016-06-22 14:45:53.000000000","message":"ditto","commit_id":"c7142cad8b57a4c29d4b3cb52c280ac969a7d7dd"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":29,"context_line":""},{"line_number":30,"context_line":"    @test.attr(type\u003d\u0027smoke\u0027)"},{"line_number":31,"context_line":"    def test_create_audit_template(self):"},{"line_number":32,"context_line":"        goal_name \u003d \"dummy\""},{"line_number":33,"context_line":"        _, goal \u003d self.client.show_goal(goal_name)"},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"        params \u003d {"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_04223500","line":32,"range":{"start_line":32,"start_character":21,"end_line":32,"end_character":26},"updated":"2016-06-23 13:14:08.000000000","message":"This was a bug that needs to be treated in a separate bug ticket. See the ticket I just created: https://bugs.launchpad.net/watcher/+bug/1595534","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":58,"context_line":""},{"line_number":59,"context_line":"    @test.attr(type\u003d\u0027smoke\u0027)"},{"line_number":60,"context_line":"    def test_create_audit_template_unicode_description(self):"},{"line_number":61,"context_line":"        goal_name \u003d \"dummy\""},{"line_number":62,"context_line":"        _, goal \u003d self.client.show_goal(goal_name)"},{"line_number":63,"context_line":"        # Use a unicode string for testing:"},{"line_number":64,"context_line":"        params \u003d {"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_247db1e7","line":61,"range":{"start_line":61,"start_character":21,"end_line":61,"end_character":26},"updated":"2016-06-23 13:14:08.000000000","message":"ditto","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    @test.attr(type\u003d\u0027smoke\u0027)"},{"line_number":88,"context_line":"    def test_delete_audit_template(self):"},{"line_number":89,"context_line":"        _, goal \u003d self.client.show_goal(\"dummy\")"},{"line_number":90,"context_line":"        _, body \u003d self.create_audit_template(goal\u003dgoal[\u0027uuid\u0027])"},{"line_number":91,"context_line":"        audit_uuid \u003d body[\u0027uuid\u0027]"},{"line_number":92,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_848465d4","line":89,"range":{"start_line":89,"start_character":41,"end_line":89,"end_character":46},"updated":"2016-06-23 13:14:08.000000000","message":"ditto","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"},{"author":{"_account_id":18971,"name":"Vincent Françoise","email":"Vincent.FRANCOISE@b-com.com","username":"v-francoise"},"change_message_id":"be03dc44680e60e063298001e2d3d8e926443e7b","unresolved":false,"context_lines":[{"line_number":102,"context_line":"    @classmethod"},{"line_number":103,"context_line":"    def resource_setup(cls):"},{"line_number":104,"context_line":"        super(TestAuditTemplate, cls).resource_setup()"},{"line_number":105,"context_line":"        _, cls.goal \u003d cls.client.show_goal(\"dummy\")"},{"line_number":106,"context_line":"        _, cls.strategy \u003d cls.client.show_strategy(\"dummy\")"},{"line_number":107,"context_line":"        _, cls.audit_template \u003d cls.create_audit_template("},{"line_number":108,"context_line":"            goal\u003dcls.goal[\u0027uuid\u0027], strategy\u003dcls.strategy[\u0027uuid\u0027])"}],"source_content_type":"text/x-python","patch_set":5,"id":"3aaa91ec_e473a913","line":105,"range":{"start_line":105,"start_character":44,"end_line":105,"end_character":49},"updated":"2016-06-23 13:14:08.000000000","message":"ditto","commit_id":"2d206cb9701ce86de816e52bd79f3db243c0c224"}]}
