From c2a0321d6a190fd6a10ad36e0fbbc6ca98520f68 Mon Sep 17 00:00:00 2001 From: Justin Drew <2396364+jdrew82@users.noreply.github.com> Date: Fri, 20 Mar 2026 10:14:38 -0500 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20=E2=8F=AA=EF=B8=8F=20Revert=20additi?= =?UTF-8?q?on=20of=20dunder=20new=20method.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changes/346.fixed | 1 + diffsync/__init__.py | 13 ------------- 2 files changed, 1 insertion(+), 13 deletions(-) create mode 100644 changes/346.fixed diff --git a/changes/346.fixed b/changes/346.fixed new file mode 100644 index 00000000..2c1335a7 --- /dev/null +++ b/changes/346.fixed @@ -0,0 +1 @@ +Reverted addition of dunder new method to Adapter class as it's still causing problems and we should handle in SSoT. diff --git a/diffsync/__init__.py b/diffsync/__init__.py index 402320ea..47f2be24 100644 --- a/diffsync/__init__.py +++ b/diffsync/__init__.py @@ -482,19 +482,6 @@ def __init_subclass__(cls) -> None: if not isclass(value) or not issubclass(value, DiffSyncModel): raise AttributeError(f'top_level references attribute "{name}" but it is not a DiffSyncModel subclass!') - def __new__(cls, **kwargs): # type: ignore[no-untyped-def] - """Document keyword arguments that were used to initialize Adapter.""" - meta_kwargs = {} - for key, value in kwargs.items(): - try: - meta_kwargs[key] = deepcopy(value) - except Exception: # pylint: disable=broad-exception-caught - # Some objects (e.g. Kafka Consumer, DB connections) cannot be deep copied - meta_kwargs[key] = value - instance = super().__new__(cls) - instance._meta_kwargs = meta_kwargs - return instance - def __str__(self) -> StrType: """String representation of an Adapter.""" if self.type != self.name: From edf49605d16e54eedd254095627ff9683431289b Mon Sep 17 00:00:00 2001 From: Justin Drew <2396364+jdrew82@users.noreply.github.com> Date: Fri, 20 Mar 2026 10:17:50 -0500 Subject: [PATCH 2/5] Remove import --- diffsync/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/diffsync/__init__.py b/diffsync/__init__.py index 47f2be24..904fedbd 100644 --- a/diffsync/__init__.py +++ b/diffsync/__init__.py @@ -16,7 +16,6 @@ """ import sys -from copy import deepcopy from inspect import isclass from typing import ( Any, From 267d97db065f2a31186039798f4f9961cc279dad Mon Sep 17 00:00:00 2001 From: Justin Drew <2396364+jdrew82@users.noreply.github.com> Date: Fri, 20 Mar 2026 10:21:13 -0500 Subject: [PATCH 3/5] docs: Tweak changelog statement. --- changes/346.fixed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes/346.fixed b/changes/346.fixed index 2c1335a7..7013268d 100644 --- a/changes/346.fixed +++ b/changes/346.fixed @@ -1 +1 @@ -Reverted addition of dunder new method to Adapter class as it's still causing problems and we should handle in SSoT. +Reverted addition of __new__ method to Adapter class to resolve instantiation issues. From 9f43c6894e63060520a5eff8b593fee4a81a6178 Mon Sep 17 00:00:00 2001 From: Justin Drew <2396364+jdrew82@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:24:52 -0500 Subject: [PATCH 4/5] =?UTF-8?q?test:=20=E2=8F=AA=EF=B8=8F=20Remove=20tests?= =?UTF-8?q?=20that=20are=20no=20longer=20relevant.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/unit/test_diffsync.py | 126 ------------------------------------ 1 file changed, 126 deletions(-) diff --git a/tests/unit/test_diffsync.py b/tests/unit/test_diffsync.py index 26a2f1cb..33c93485 100644 --- a/tests/unit/test_diffsync.py +++ b/tests/unit/test_diffsync.py @@ -1142,129 +1142,3 @@ def test_diffsync_get_initial_value_order(): "interface", "person", ] - - -def test_adapter_new_stores_kwargs(): - """Test that __new__ stores keyword arguments in _meta_kwargs.""" - adapter = Adapter(name="test_adapter") - assert hasattr(adapter, "_meta_kwargs") - assert adapter._meta_kwargs == {"name": "test_adapter"} # pylint: disable=protected-access - - -def test_adapter_new_with_no_kwargs(): - """Test that __new__ works with no keyword arguments.""" - adapter = Adapter() - assert hasattr(adapter, "_meta_kwargs") - assert adapter._meta_kwargs == {} # pylint: disable=protected-access - - -def test_adapter_new_with_multiple_kwargs(): - """Test that __new__ stores multiple keyword arguments.""" - adapter = Adapter(name="test", internal_storage_engine=LocalStore) - assert adapter._meta_kwargs == { # pylint: disable=protected-access - "name": "test", - "internal_storage_engine": LocalStore, - } - - -def test_adapter_new_with_subclass(): - """Test that __new__ works correctly with Adapter subclasses.""" - adapter = BackendA(name="test_backend") - assert hasattr(adapter, "_meta_kwargs") # pylint: disable=protected-access - assert adapter._meta_kwargs == {"name": "test_backend"} # pylint: disable=protected-access - - -def test_adapter_new_independent_instances(): - """Test that different Adapter instances have independent _meta_kwargs.""" - adapter1 = Adapter(name="adapter1", internal_storage_engine=LocalStore) - adapter2 = Adapter(name="adapter2", internal_storage_engine=LocalStore) - - assert adapter1._meta_kwargs["name"] == "adapter1" # pylint: disable=protected-access - assert adapter1._meta_kwargs["internal_storage_engine"] == LocalStore # pylint: disable=protected-access - assert adapter2._meta_kwargs["name"] == "adapter2" # pylint: disable=protected-access - assert adapter2._meta_kwargs["internal_storage_engine"] == LocalStore # pylint: disable=protected-access - - -class _AdapterWithExtraKwargs(Adapter): - """Minimal Adapter subclass that accepts extra kwargs for testing __new__ serialization.""" - - def __init__(self, name=None, internal_storage_engine=LocalStore, **kwargs): - super().__init__(name=name, internal_storage_engine=internal_storage_engine) - - -def test_adapter_new_serializable_objects_are_deep_copied(): - """Test that serializable objects passed to __new__ are deep-copied into _meta_kwargs.""" - mutable_config = {"host": "localhost", "port": 5432} - mutable_list = [1, 2, 3] - adapter = _AdapterWithExtraKwargs( - name="test", - config=mutable_config, - tags=mutable_list, - internal_storage_engine=LocalStore, - ) - - # Verify values are stored - assert adapter._meta_kwargs["config"] == {"host": "localhost", "port": 5432} # pylint: disable=protected-access - assert adapter._meta_kwargs["tags"] == [1, 2, 3] # pylint: disable=protected-access - - # Mutate the original objects - _meta_kwargs should retain the original values (deep copy) - mutable_config["port"] = 9999 - mutable_list.append(4) - - assert adapter._meta_kwargs["config"] == {"host": "localhost", "port": 5432} # pylint: disable=protected-access - assert adapter._meta_kwargs["tags"] == [1, 2, 3] # pylint: disable=protected-access - - -def test_adapter_new_non_serializable_type_error_stored_as_is(): - """Test that objects raising TypeError on deepcopy are stored as-is in _meta_kwargs.""" - - class NonCopyableTypeError: - """Object that raises TypeError when deep-copied (e.g. DB connection, Kafka Consumer).""" - - def __deepcopy__(self, memo=None): - raise TypeError("Cannot deep copy this object") - - non_copyable = NonCopyableTypeError() - adapter = _AdapterWithExtraKwargs(name="test", non_copyable=non_copyable, internal_storage_engine=LocalStore) - - assert adapter._meta_kwargs["non_copyable"] is non_copyable # pylint: disable=protected-access - - -def test_adapter_new_non_serializable_attribute_error_stored_as_is(): - """Test that objects raising AttributeError on deepcopy are stored as-is in _meta_kwargs.""" - - class NonCopyableAttributeError: - """Object that raises AttributeError when deep-copied.""" - - def __deepcopy__(self, memo=None): - raise AttributeError("Cannot deep copy - missing attribute") - - non_copyable = NonCopyableAttributeError() - adapter = _AdapterWithExtraKwargs(name="test", non_copyable=non_copyable, internal_storage_engine=LocalStore) - - assert adapter._meta_kwargs["non_copyable"] is non_copyable # pylint: disable=protected-access - - -def test_adapter_new_mixed_serializable_and_non_serializable_kwargs(): - """Test that __new__ handles mix of serializable and non-serializable kwargs correctly.""" - - class NonCopyable: - def __deepcopy__(self, memo=None): - raise TypeError("Cannot copy") - - serializable_dict = {"key": "value"} - non_copyable = NonCopyable() - - adapter = _AdapterWithExtraKwargs( - name="test", - config=serializable_dict, - connection=non_copyable, - internal_storage_engine=LocalStore, - ) - - # Serializable: deep-copied (independent copy) - assert adapter._meta_kwargs["config"] == {"key": "value"} # pylint: disable=protected-access - assert adapter._meta_kwargs["config"] is not serializable_dict - - # Non-serializable: stored by reference - assert adapter._meta_kwargs["connection"] is non_copyable # pylint: disable=protected-access From a8d94c77d9592192a730e35e27528b999b299a20 Mon Sep 17 00:00:00 2001 From: Justin Drew <2396364+jdrew82@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:31:54 -0500 Subject: [PATCH 5/5] =?UTF-8?q?test:=20=F0=9F=9A=A8=20Fix=20ruff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/unit/test_diffsync.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/test_diffsync.py b/tests/unit/test_diffsync.py index 33c93485..49621409 100644 --- a/tests/unit/test_diffsync.py +++ b/tests/unit/test_diffsync.py @@ -9,7 +9,6 @@ from diffsync import Adapter, DiffSyncModel from diffsync.enum import DiffSyncFlags, DiffSyncModelFlags from diffsync.exceptions import DiffClassMismatch, ObjectAlreadyExists, ObjectCrudException, ObjectNotFound -from diffsync.store.local import LocalStore from .conftest import BackendA, Device, Interface, PersonA, Site, TrackedDiff