Repository: sdv-dev/SDV

Issue:
Sample not backwards compatible with older synthesizers
### Environment Details

Please indicate the following details about the environment in which you found the bug:

* SDV version: 1.24.2.dev0
* Python version: 3.12
* Operating System: macOS

### Error Description

HMA synthesizers from old versions of SDV are failing to sample when run with the current, unreleased version of SDV.  Code added in #2615 references an attribute not present in older HMA synthesizers.




Discussion:

Patch:
diff --git a/sdv/multi_table/hma.py b/sdv/multi_table/hma.py
index 43279a793..c049f4378 100644
--- a/sdv/multi_table/hma.py
+++ b/sdv/multi_table/hma.py
@@ -565,9 +565,9 @@ def _recreate_child_synthesizer(self, child_name, parent_name, parent_row):
                 )
                 synthesizer = self._synthesizer(table_meta, **self._table_parameters[child_name])
 
-            self._set_extended_columns_distributions(
-                synthesizer, child_name, self._parent_extended_columns[child_name]
-            )
+            extended_columns = getattr(self, '_parent_extended_columns', {}).get(child_name, [])
+            if extended_columns:
+                self._set_extended_columns_distributions(synthesizer, child_name, extended_columns)
             synthesizer._set_parameters(parameters, default_parameters)
         else:
             synthesizer = self._null_child_synthesizers[f'__{child_name}__{foreign_key}']


Test patch:
diff --git a/tests/unit/multi_table/test_hma.py b/tests/unit/multi_table/test_hma.py
index 30575aff0..a26222e06 100644
--- a/tests/unit/multi_table/test_hma.py
+++ b/tests/unit/multi_table/test_hma.py
@@ -482,6 +482,44 @@ def test__recreate_child_synthesizer(self):
             parent_row,
         )
 
+        # Assert
+        assert synthesizer == instance._synthesizer.return_value
+        assert synthesizer._data_processor == table_synthesizer._data_processor
+        instance.metadata.get_table_metadata.assert_called_once_with('users')
+        instance._synthesizer.assert_called_once_with(
+            instance.metadata.get_table_metadata.return_value, a=1
+        )
+        synthesizer._set_parameters.assert_called_once_with(
+            instance._extract_parameters.return_value,
+            {'colA': 'default_param', 'colB': 'default_param'},
+        )
+        instance._extract_parameters.assert_called_once_with(parent_row, table_name, 'session_id')
+        instance._set_extended_columns_distributions.assert_not_called()
+
+    def test__recreate_child_synthesizer_set_extended_columns_distributions(self):
+        """Test that this method returns a synthesizer for the given child table."""
+        # Setup
+        instance = Mock()
+        parent_row = 'row'
+        table_name = 'users'
+        parent_table_name = 'sessions'
+        table_meta = Mock()
+        table_synthesizer = Mock()
+        instance.metadata.tables = {'users': table_meta}
+        instance.metadata._get_foreign_keys.return_value = ['session_id']
+        instance._table_parameters = {'users': {'a': 1}}
+        instance._table_synthesizers = {'users': table_synthesizer}
+        instance._default_parameters = {'users': {'colA': 'default_param', 'colB': 'default_param'}}
+        instance._parent_extended_columns = {'users': ['mock_extended_column']}
+
+        # Run
+        synthesizer = HMASynthesizer._recreate_child_synthesizer(
+            instance,
+            table_name,
+            parent_table_name,
+            parent_row,
+        )
+
         # Assert
         assert synthesizer == instance._synthesizer.return_value
         assert synthesizer._data_processor == table_synthesizer._data_processor
@@ -495,7 +533,7 @@ def test__recreate_child_synthesizer(self):
         )
         instance._extract_parameters.assert_called_once_with(parent_row, table_name, 'session_id')
         instance._set_extended_columns_distributions.assert_called_once_with(
-            synthesizer, table_name, []
+            synthesizer, table_name, ['mock_extended_column']
         )
 
     def test__get_likelihoods(self):