Attach a module to the pipeline system

def attach(self, module_factory, name=None, **kwargs):
        """Attach a module to the pipeline system"""
        if self.anybar: self.anybar.change("yellow")

        fac = module_factory

        if name is None:
            name = fac.__name__

        log.info("Attaching module '{0}'".format(name))

        if (inspect.isclass(fac) and issubclass(fac, Module)) or \
                name == 'GenericPump':
            log.debug("Attaching as regular module")
            if name in self.module_configuration:
                log.debug(
                    "Applying pipeline configuration file for module '%s'" %
                    name
                )
                for key, value in self.module_configuration[name].items():
                    if key in kwargs:
                        self.log.info(
                            "Overwriting parameter '%s' in module '%s' from "
                            "the pipeline configuration file." % (key, name)
                        )
                    kwargs[key] = value
            module = fac(name=name, **kwargs)
            if hasattr(module, "provided_services"):
                for service_name, obj in module.provided_services.items():
                    self.services.register(service_name, obj)
            if hasattr(module, "required_services"):
                updated_required_services = {}
                updated_required_services.update(self.required_services)
                updated_required_services.update(module.required_services)
                self.required_services = updated_required_services
            module.services = self.services
            module.pipeline = self
        else:
            if isinstance(fac, types.FunctionType):
                log.debug("Attaching as function module")
            else:
                log.critical(
                    "Don't know how to attach module '{0}'!\n"
                    "But I'll do my best".format(name)
                )
            module = fac
            module.name = name
            module.timeit = self.timeit

        # Special parameters
        if 'only_if' in kwargs:
            required_keys = kwargs['only_if']
            if isinstance(required_keys, basestring):
                required_keys = [required_keys]
            module.only_if = set(required_keys)
        else:
            module.only_if = set()

        if 'blob_keys' in kwargs:
            module.blob_keys = kwargs['blob_keys']
        else:
            module.blob_keys = None

        if 'every' in kwargs:
            module.every = kwargs['every']
        else:
            module.every = 1

        self._timeit[module] = {
            'process': deque(maxlen=STAT_LIMIT),
            'process_cpu': deque(maxlen=STAT_LIMIT),
            'finish': 0,
            'finish_cpu': 0
        }

        if hasattr(module, 'get_detector'):    # Calibration-like module
            self.log.deprecation(
                "Calibration-like modules will not be supported in future "
                "versions of KM3Pipe. Please use services instead.\n"
                "If you are attaching the `calib.Calibration` as a module, "
                "switch to `calib.CalibrationService` and use the "
                "`self.services['calibrate']()` method in your modules "
                "to apply calibration.\n\n"
                "This means:\n\n"
                "    pipe.attach(kp.calib.CalibrationService, ...)\n\n"
                "And inside the attached modules, you can apply the "
                "calibration with e.g.:\n\n"
                "    cal_hits = self.services['calibrate'](blob['Hits'])\n"
            )
            self.calibration = module
            if module._should_apply:
                self.modules.append(module)
        else:    # normal module
            module.calibration = self.calibration
            self.modules.append(module)