from multiprocessing.managers import BaseProxy


class SharedMockProxy(BaseProxy):
    _exposed_ = (
        "__call__",
        "__enter__",
        "__exit__",
        "assert_called",
        "assert_not_called",
        "assert_called_with",
        "assert_any_call",
        "assert_enter_called",
        "assert_exit_called",
        "assert_exit_called_without_exception",
        "assert_exit_called_with_exception",
        "_set_return_value",
        "_set_side_effect",
    )

    _exposed_props = (
        "called",
        "call_count",
        "call_args",
        "call_args_list",
        "return_value",
        "side_effect",
    )

    def __call__(self, *args, **kwargs):
        return self._callmethod("__call__", args, kwargs)

    def __enter__(self):
        return self._callmethod("__enter__")

    def __exit__(self, exc_type, exc_val, exc_tb):
        # NOTE: exc_tb is always empty because it can't be pickled
        return self._callmethod("__exit__", (exc_type, exc_val, None))

    def assert_called(self):
        return self._callmethod("assert_called")

    def assert_not_called(self):
        return self._callmethod("assert_not_called")

    def assert_called_with(self, *args, **kwargs):
        return self._callmethod("assert_called_with", args, kwargs)

    def assert_any_call(self, *args, **kwargs):
        return self._callmethod("assert_any_call", args, kwargs)

    def assert_enter_called(self):
        return self._callmethod("assert_enter_called")

    def assert_exit_called(self):
        return self._callmethod("assert_exit_called")

    def assert_exit_called_without_exception(self):
        return self._callmethod("assert_exit_called_without_exception")

    def assert_exit_called_with_exception(self):
        return self._callmethod("assert_exit_called_with_exception")

    def __getattr__(self, name):
        if name in self._exposed_props:
            return getattr(self._getvalue(), name)
        else:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        if name == "return_value":
            self._callmethod("_set_return_value", (value,))
        elif name == "side_effect":
            self._callmethod("_set_side_effect", (value,))
        else:
            super().__setattr__(name, value)
