def catch_factory(attr):
    """
    Factory returning a catch function
    """

    def _catch(s, *args, **kw):
        """
        This is used to catch and process all calls.
        """

        def process(value):
            """
            return the actual value after processing
            """
            if attr.startswith("__"):
                # __repr__, __str__ etc
                return getattr(value, attr)(*args, **kw)
            else:
                # upper, lower etc
                return getattr(u"".__class__, attr)(value, *args, **kw)

        stack = inspect.stack()
        mod = inspect.getmodule(stack[1][0])
        # We are called from the owning module so allow
        if mod.__name__.split(".")[-1] == s._module_name:
            return process(s._value)
        # very shallow calling no stack
        if len(stack) < 3:
            return process(s._private)
        # Check if this is an internal or external module.  We need to allow
        # calls to modules like requests etc
        remote = not inspect.getmodule(stack[2][0]).__name__.startswith("py3status")
        valid = False
        # go through the stack to see how we came through the code
        for frame in stack[2:]:
            mod = inspect.getmodule(frame[0])
            if remote and mod.__name__.split(".")[-1] == s._module_name:
                # the call to an external module started in the correct module
                # so allow this usage
                valid = True
                break
            if mod.__name__ == "py3status.py3" and frame[3] == "request":
                # Py3.request has special needs due so it is allowed to access
                # private variables.
                valid = True
                break
            if mod.__name__.startswith("py3status"):
                # We were somewhere else in py3status than the module, maybe we
                # are doing some logging.  Prevent usage
                return process(s._private)
        if valid:
            return process(s._value)
        return process(s._private)

    return _catch
Factory returning a catch function