def refresh_modules(self, module_string=None, exact=True):
        """
        Update modules.
        if module_string is None all modules are refreshed
        if module_string then modules with the exact name or those starting
        with the given string depending on exact parameter will be refreshed.
        If a module is an i3status one then we refresh i3status.
        To prevent abuse, we rate limit this function to 100ms for full
        refreshes.
        """
        if not module_string:
            if time.time() > (self.last_refresh_ts + 0.1):
                self.last_refresh_ts = time.time()
            else:
                # rate limiting
                return
        update_i3status = False
        for name, module in self.output_modules.items():
            if (
                module_string is None
                or (exact and name == module_string)
                or (not exact and name.startswith(module_string))
            ):
                if module["type"] == "py3status":
                    if self.config["debug"]:
                        self.log("refresh py3status module {}".format(name))
                    module["module"].force_update()
                else:
                    if self.config["debug"]:
                        self.log("refresh i3status module {}".format(name))
                    update_i3status = True
        if update_i3status:
            self.i3status_thread.refresh_i3status()
Update modules.
        if module_string is None all modules are refreshed
        if module_string then modules with the exact name or those starting
        with the given string depending on exact parameter will be refreshed.
        If a module is an i3status one then we refresh i3status.
        To prevent abuse, we rate limit this function to 100ms for full
        refreshes.