def test_fabric_module_setattr():
    """Test that setattr sets attributes on the original module."""

    class OriginalModule(torch.nn.Module):
        def __init__(self):
            super().__init__()
            self.layer = torch.nn.Linear(2, 3)
            self.attribute = 1
            self._x = None

        @property
        def x(self):
            return self._x

        @x.setter
        def x(self, value):
            self._x = value

    original_module = OriginalModule()

    class ModuleWrapper(torch.nn.Module):
        def __init__(self):
            super().__init__()
            self.wrapped = original_module

    wrapped_module = ModuleWrapper()
    fabric_module = _FabricModule(wrapped_module, Mock(), original_module=original_module)

    # Check new attribute is set on original_module
    fabric_module.new_attribute = 100
    assert original_module.new_attribute == 100

    # Modify existing attribute on original_module
    fabric_module.attribute = 101
    # "attribute" is only in the original_module, so it shouldn't get set in the fabric_module
    assert "attribute" not in fabric_module.__dict__
    assert fabric_module.attribute == 101  # returns it from original_module
    assert original_module.attribute == 101

    # Check setattr of original_module
    fabric_module.x = 102
    assert original_module.x == 102

    # Check set submodule
    assert not hasattr(original_module, "linear")
    linear = torch.nn.Linear(2, 2)
    fabric_module.linear = linear
    assert hasattr(original_module, "linear")
    assert isinstance(original_module.linear, torch.nn.Module)
    assert linear in fabric_module.modules()
    assert linear in original_module.modules()

    # Check monkeypatching of methods
    fabric_module = _FabricModule(Mock(), Mock())
    original = id(fabric_module.forward)
    fabric_module.forward = lambda *_: None
    assert id(fabric_module.forward) != original
    # Check special methods
    assert "__repr__" in dir(fabric_module)
    assert "__repr__" not in fabric_module.__dict__
    assert "__repr__" not in _FabricModule.__dict__
    fabric_module.__repr__ = lambda *_: "test"
    assert fabric_module.__repr__() == "test"
    # needs to be monkeypatched on the class for `repr()` to change
    assert repr(fabric_module) == "_FabricModule()"
    with mock.patch.object(_FabricModule, "__repr__", return_value="test"):
        assert fabric_module.__repr__() == "test"
        assert repr(fabric_module) == "test"
Test that setattr sets attributes on the original module.
tests/tests_fabric/test_wrappers.py