)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"4561bcb56e67b8c43c3aa3bda74c0902ec994510","unresolved":true,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Reimplement the singleton class"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Now the singleton class used in Neutron is a metaclass. It also adds"},{"line_number":10,"context_line":"the subclass method ``destroy`` that removes the created instance"},{"line_number":11,"context_line":"from the singleton, allowing the user to create another instance. This"},{"line_number":12,"context_line":"destroy method is idempotent."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"Closes-Bug: #2102083"},{"line_number":15,"context_line":"Change-Id: Ib237c7c1e1ba29626a03765a0521180fc2718c32"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"5a56bc16_1e55caf3","line":12,"range":{"start_line":9,"start_character":56,"end_line":12,"end_character":29},"updated":"2025-03-12 17:05:13.000000000","message":"This is no longer true.","commit_id":"9600af01d8f2d7d57641bcbd418a1c374b66313c"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"861329c603e344ac1fb261ea18c5383a0cab7f78","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Reimplement the singleton class"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Now the singleton class used in Neutron is a metaclass. It also adds"},{"line_number":10,"context_line":"the subclass method ``destroy`` that removes the created instance"},{"line_number":11,"context_line":"from the singleton, allowing the user to create another instance. This"},{"line_number":12,"context_line":"destroy method is idempotent."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"Closes-Bug: #2102083"},{"line_number":15,"context_line":"Change-Id: Ib237c7c1e1ba29626a03765a0521180fc2718c32"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"7e45b826_9bdd6de6","line":12,"range":{"start_line":9,"start_character":56,"end_line":12,"end_character":29},"in_reply_to":"5a56bc16_1e55caf3","updated":"2025-03-12 22:16:46.000000000","message":"Right, I missed this.","commit_id":"9600af01d8f2d7d57641bcbd418a1c374b66313c"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"ad7e154506b87c08f9e5e49bbcfdef989fd558db","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"6bf949ef_7b1ed1de","updated":"2025-03-12 13:56:22.000000000","message":"destroy() in this makes it possible for there to be different instances of the \"Singleton\" in this case. Example:\n\n```\nclass Thing(metaclass\u003dSingletonMetaclass):\n    def __init__(self, value):\n        self.value \u003d value\n\nt1 \u003d Thing(1)\nt2 \u003d Thing(2)\n# t1 is t2, both value 1\nt1.destroy()\n# t1 gone, t2 exists and has value 1, but no _instance\nt1 \u003d Thing(100)\n# t1 and t2 exist, t1.value \u003d 100, t2.value \u003d 1 and are now different completely different objects due to __new__() not seeing an instance even though t2 is still out there\n\nIf you just use `del` on t1 and t2 they would already behave as expected. Once the last reference to the Singleton is deleted, it is deleted and a new instance can be made, so I don\u0027t think we really need a `destroy()` method.","commit_id":"21995ce8d270bf9e8ee76047b1cb104e663c30b6"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"861329c603e344ac1fb261ea18c5383a0cab7f78","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"79417eb5_45d7e41c","in_reply_to":"615cfbd7_5a58d6c0","updated":"2025-03-12 22:16:46.000000000","message":"PS3 address these concerns.","commit_id":"21995ce8d270bf9e8ee76047b1cb104e663c30b6"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"22344e23b3b9c00e56581e0caefd07a684995265","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"615cfbd7_5a58d6c0","in_reply_to":"6bf949ef_7b1ed1de","updated":"2025-03-12 14:00:51.000000000","message":"Trying again with the formatting.\n\n```\nclass Thing(metaclass\u003dSingletonMetaclass):\n    def init(self, value):\n    self.value \u003d value\n\nt1 \u003d Thing(1)\nt2 \u003d Thing(2)\n# t1 is t2, both value 1\n\nt1.destroy()  # t1 gone, t2 exists and has value 1, but no _instance\nt1 \u003d Thing(100)\n# t1 and t2 exist, t1.value \u003d 100, t2.value \u003d 1 and are now different completely different objects due to new() not seeing an instance even though t2 is still out there\n```\n\nIf you just use del on t1 and t2 they would already behave as expected. Once the last reference to the Singleton is deleted, it is deleted and a new instance can be made, so I don\u0027t think we really need a destroy() method.","commit_id":"21995ce8d270bf9e8ee76047b1cb104e663c30b6"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"4561bcb56e67b8c43c3aa3bda74c0902ec994510","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"f7382f46_e56ae924","updated":"2025-03-12 17:05:13.000000000","message":"I\u0027m getting a lot of the following errors when running unit tests:\n```\n--- import errors ---\nFailed to import test module: neutron.tests.unit.agent.common.test_ovs_lib\nTraceback (most recent call last):\n  File \"/usr/lib64/python3.12/unittest/loader.py\", line 396, in _find_test_path\n    module \u003d self._get_module_from_name(name)\n             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/lib64/python3.12/unittest/loader.py\", line 339, in _get_module_from_name\n    __import__(name)\n  File \"/home/twilson/src/neutron/neutron/tests/unit/agent/common/test_ovs_lib.py\", line 26, in \u003cmodule\u003e\n    from neutron.agent.common import ovs_lib\n  File \"/home/twilson/src/neutron/neutron/agent/common/ovs_lib.py\", line 40, in \u003cmodule\u003e\n    from neutron.agent.ovsdb import impl_idl\n  File \"/home/twilson/src/neutron/neutron/agent/ovsdb/impl_idl.py\", line 73, in \u003cmodule\u003e\n    class NeutronOvsdbIdl(impl_idl.OvsdbIdl, metaclass\u003dutils.SingletonMetaclass):\nTypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases\n```","commit_id":"9600af01d8f2d7d57641bcbd418a1c374b66313c"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"23fe84f960ce1653cd3ddb2ee689339c738e55d1","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"81d4957d_da05cd64","updated":"2025-03-14 07:01:40.000000000","message":"recheck neutron-tempest-plugin-ovn-ubuntu-jammy","commit_id":"1e560ecd8a2a620b7b6d677bae962764302136a0"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"afc75b2b3a84a53675ea84221769f79569bf1008","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"2f1747c1_f0e1d807","updated":"2025-03-14 10:37:26.000000000","message":"recheck ubuntu-jammy","commit_id":"1e560ecd8a2a620b7b6d677bae962764302136a0"}],"neutron/common/utils.py":[{"author":{"_account_id":1131,"name":"Brian Haley","email":"haleyb.dev@gmail.com","username":"brian-haley"},"change_message_id":"0c152c328fa0ace12d20f76f95fdc15279217863","unresolved":true,"context_lines":[{"line_number":959,"context_line":"        return cls._instance"},{"line_number":960,"context_line":""},{"line_number":961,"context_line":"    @staticmethod"},{"line_number":962,"context_line":"    def destroy(self):"},{"line_number":963,"context_line":"        cls \u003d self.__class__"},{"line_number":964,"context_line":"        if hasattr(cls, \u0027_instance\u0027) and cls._instance:"},{"line_number":965,"context_line":"            del cls._instance"}],"source_content_type":"text/x-python","patch_set":2,"id":"00575b59_45be605d","line":962,"range":{"start_line":962,"start_character":16,"end_line":962,"end_character":20},"updated":"2025-03-12 12:36:30.000000000","message":"s/cls","commit_id":"21995ce8d270bf9e8ee76047b1cb104e663c30b6"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"861329c603e344ac1fb261ea18c5383a0cab7f78","unresolved":false,"context_lines":[{"line_number":959,"context_line":"        return cls._instance"},{"line_number":960,"context_line":""},{"line_number":961,"context_line":"    @staticmethod"},{"line_number":962,"context_line":"    def destroy(self):"},{"line_number":963,"context_line":"        cls \u003d self.__class__"},{"line_number":964,"context_line":"        if hasattr(cls, \u0027_instance\u0027) and cls._instance:"},{"line_number":965,"context_line":"            del cls._instance"}],"source_content_type":"text/x-python","patch_set":2,"id":"1738007a_07564b75","line":962,"range":{"start_line":962,"start_character":16,"end_line":962,"end_character":20},"in_reply_to":"00575b59_45be605d","updated":"2025-03-12 22:16:46.000000000","message":"Done","commit_id":"21995ce8d270bf9e8ee76047b1cb104e663c30b6"},{"author":{"_account_id":4694,"name":"Miguel Lavalle","email":"miguel@mlavalle.com","username":"minsel"},"change_message_id":"b1a583ff105ad0a19978633c6650109cb17e2bdc","unresolved":true,"context_lines":[{"line_number":948,"context_line":"class SingletonMetaclass(type):"},{"line_number":949,"context_line":"    _instances \u003d weakref.WeakValueDictionary()"},{"line_number":950,"context_line":""},{"line_number":951,"context_line":"    def __call__(cls, *args, **kwargs):"},{"line_number":952,"context_line":"        if cls not in cls._instances:"},{"line_number":953,"context_line":"            instance \u003d super().__call__(*args, **kwargs)"},{"line_number":954,"context_line":"            cls._instances[cls] \u003d instance"}],"source_content_type":"text/x-python","patch_set":3,"id":"7d063459_1b0255a5","line":951,"range":{"start_line":951,"start_character":8,"end_line":951,"end_character":16},"updated":"2025-03-12 19:05:49.000000000","message":"Doesn\u0027t this have to be __new__? https://realpython.com/python-metaclasses/#custom-metaclasses","commit_id":"9600af01d8f2d7d57641bcbd418a1c374b66313c"},{"author":{"_account_id":4694,"name":"Miguel Lavalle","email":"miguel@mlavalle.com","username":"minsel"},"change_message_id":"a4b1996a4872f0e2cc36c0de243f750f8ef97b1a","unresolved":true,"context_lines":[{"line_number":948,"context_line":"class SingletonMetaclass(type):"},{"line_number":949,"context_line":"    _instances \u003d weakref.WeakValueDictionary()"},{"line_number":950,"context_line":""},{"line_number":951,"context_line":"    def __call__(cls, *args, **kwargs):"},{"line_number":952,"context_line":"        if cls not in cls._instances:"},{"line_number":953,"context_line":"            instance \u003d super().__call__(*args, **kwargs)"},{"line_number":954,"context_line":"            cls._instances[cls] \u003d instance"}],"source_content_type":"text/x-python","patch_set":3,"id":"8704849d_5c3435e2","line":951,"range":{"start_line":951,"start_character":8,"end_line":951,"end_character":16},"in_reply_to":"7d063459_1b0255a5","updated":"2025-03-12 21:13:51.000000000","message":"I meant \\_\\_new\\_\\_. We are going from a decorator, which needs a \\_\\_call\\_\\_ method, to a metaclass, which needs a \\_\\_new\\_\\_ method.","commit_id":"9600af01d8f2d7d57641bcbd418a1c374b66313c"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"861329c603e344ac1fb261ea18c5383a0cab7f78","unresolved":false,"context_lines":[{"line_number":948,"context_line":"class SingletonMetaclass(type):"},{"line_number":949,"context_line":"    _instances \u003d weakref.WeakValueDictionary()"},{"line_number":950,"context_line":""},{"line_number":951,"context_line":"    def __call__(cls, *args, **kwargs):"},{"line_number":952,"context_line":"        if cls not in cls._instances:"},{"line_number":953,"context_line":"            instance \u003d super().__call__(*args, **kwargs)"},{"line_number":954,"context_line":"            cls._instances[cls] \u003d instance"}],"source_content_type":"text/x-python","patch_set":3,"id":"5e7311e6_7662f99e","line":951,"range":{"start_line":951,"start_character":8,"end_line":951,"end_character":16},"in_reply_to":"8704849d_5c3435e2","updated":"2025-03-12 22:16:46.000000000","message":"That\u0027s not totally correct. The ``__new__`` method declared in the metadata class, will be called both when the metadata class is created and when the subclass is defined (not instantiated).\n\nThe ``__call__`` method makes the new type (in this case the subclasses) callable and it will be called when the subclass is instantiated. This method is what we need if we need it only when a subclass object is created.\n\nhttps://stackoverflow.com/questions/6760685/what-is-the-best-way-of-implementing-singleton-in-python","commit_id":"9600af01d8f2d7d57641bcbd418a1c374b66313c"}],"neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/extensions/test_placement.py":[{"author":{"_account_id":8313,"name":"Lajos Katona","display_name":"lajoskatona","email":"katonalala@gmail.com","username":"elajkat","status":"Ericsson Software Technology"},"change_message_id":"66ce260e7bcdb2334e0aed1ba522ada8d46fbc4d","unresolved":true,"context_lines":[{"line_number":76,"context_line":"        self.addCleanup(self._reset_placement_singleton)"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    def _reset_placement_singleton(self):"},{"line_number":79,"context_line":"        del self.ovn_client.placement_extension"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def _build_other_config(self, bandwidths, inventory_defaults, hypervisors):"},{"line_number":82,"context_line":"        options \u003d []"}],"source_content_type":"text/x-python","patch_set":10,"id":"19391bd1_997e34b8","line":79,"updated":"2025-03-24 08:31:07.000000000","message":"I suppose \"... \u003d weakref.WeakValueDictionary()\" should also work here","commit_id":"1e560ecd8a2a620b7b6d677bae962764302136a0"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"b7bd67c50cd141c510722485e0ebf118f36d82f5","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        self.addCleanup(self._reset_placement_singleton)"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    def _reset_placement_singleton(self):"},{"line_number":79,"context_line":"        del self.ovn_client.placement_extension"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def _build_other_config(self, bandwidths, inventory_defaults, hypervisors):"},{"line_number":82,"context_line":"        options \u003d []"}],"source_content_type":"text/x-python","patch_set":10,"id":"db078507_218c305a","line":79,"in_reply_to":"19391bd1_997e34b8","updated":"2025-03-24 08:42:48.000000000","message":"Yes, for sure. But I actually prefer to delete the created object and thus the weak reference will expire.","commit_id":"1e560ecd8a2a620b7b6d677bae962764302136a0"}]}
