def send_email(self, **kwargs): email = self._build_email(**kwargs) success = self._try_send(email) if not success: err_msg = 'Failed to send message with following args: ' + str( kwargs) raise EGCGError(err_msg)
def notify(self, msg): email = self.build_email(msg) success = self._try_send(email) if not success: err_msg = 'Failed to send message: ' + str(msg) if self.strict: raise EGCGError(err_msg) else: self.critical(err_msg)
def _job_finished(self): statuses = self._job_statuses() for s in statuses: if s in self.finished_statuses: pass elif s in self.unfinished_statuses: return False else: raise EGCGError('Bad job status: %s', s) return True
def join(self, timeout=None): # noinspection PyCallByClass Thread.join(self, timeout) if self.exception: self._stop() self.error(self.exception.__class__.__name__ + ': ' + str(self.exception)) raise EGCGError('Commands failed: ' + str(self.exit_statuses)) self.info('Exit statuses: ' + str(self.exit_statuses)) return sum(self.exit_statuses)
def join(self, timeout=None): """ Ensure that both the thread and the subprocess have finished, and return self.proc's exit status. :param int timeout: As Thread.join """ super().join(timeout=timeout) if self.exception: self._stop() self.error('Encountered a %s error: %s', self.exception.__class__.__name__, self.exception) raise EGCGError('Command failed: ' + self.cmd) from self.exception return self.proc.wait()
def find_all_fastq_pairs(location): """ Return the results of find_all_fastqs as a list of fastq pair tuples. Assumes that fastq pairs come together from sorting by name. :param str location: Directory to search :return: Full paths to all fastq.gz files in the input dir, aggregated per pair :rtype: list[tuple[str, str]] """ fastqs = find_all_fastqs(location) if len(fastqs) % 2 != 0: raise EGCGError('Expected even number of fastq files in %s, found %s' % (location, len(fastqs))) fastqs.sort() return list(zip(*[iter(fastqs)] * 2))
def test_notify_failure(self, mocked_log): self.notification_centre.subscribers = { 'asana': Mock(notify=Mock(side_effect=EGCGError('Something broke'))), 'email': Mock(notify=Mock(side_effect=ValueError('Something else broke'))) } with self.assertRaises(EGCGError) as e: self.notification_centre.notify('a message', ('asana', 'email')) mocked_log.assert_called() assert str(e.exception) == ( 'Encountered the following errors during notification: ' 'EGCGError: Something broke, ' 'ValueError: Something else broke')
def join(self): """ Set self.proc to a Popen and start. :rtype: tuple[bytes, bytes] :raises: EGCGError on any exception """ try: out, err = self._process().communicate() for stream, emit in ((out, self.info), (err, self.error)): for line in stream.decode('utf-8').split('\n'): emit(line) return self.proc.poll() except Exception as e: raise EGCGError('Command failed: ' + self.cmd) from e
def notify(self, msg, attachments=None): try: if self.email_template: self.email_sender.send_email(title=self.name, body=self._prepare_string(msg), attachments=attachments) else: self.email_sender.send_email(text_message=msg, attachments=attachments) except EGCGError: err_msg = 'Failed to send message: ' + str(msg) if self.strict: raise EGCGError(err_msg) else: self.critical(err_msg)
def add_job_array(self, *cmds): if self.parameters.get('jobs'): raise EGCGError( 'Already written a job array - can only have one per script') if len(cmds) == 1: self.register_cmd(cmds[0]) else: self._start_array() for idx, cmd in enumerate(cmds): self._register_array_cmd( idx + 1, cmd, log_file=self.log_file + str(idx + 1) if self.log_commands else None) self._finish_array() self.parameters['jobs'] = len(cmds)
def _build_email(self, **kwargs): """ Create a MIMEText from plain text or Jinja2-formatted html and send by email. If attachments are provided, the message will be a MIMEMultipart containing the MimeText message plus MIMEApplication attachments. _build_email has two modes: plain text and html. The following keyword args are useable for both: - email_subject: (str) override the EmailSender subject - email_sender: (str) override the EmailSender sender - email_recipients: (list) override the EmailSender recipients - attachments: list of file paths to attach to the email In plain text mode: - text_message (str) is required and contains the plain text to send in the email In html mode: - email_template (str) can be user to override the EmailSender email_template - all other keyword args are passed to the Jinja template """ email_template = kwargs.get('email_template', self.email_template) if email_template: content = jinja2.Template(open(email_template).read()) text = MIMEText(content.render(**kwargs), 'html') elif 'text_message' in kwargs: text = MIMEText(kwargs.get('text_message')) else: raise EGCGError( 'EmailSender needs either a text_message or an email template') if 'attachments' in kwargs and kwargs['attachments']: if isinstance(kwargs['attachments'], str): kwargs['attachments'] = [kwargs['attachments']] msg = MIMEMultipart() msg.attach(text) for attachment in kwargs['attachments']: with open(attachment, 'rb') as f: part = MIMEApplication(f.read(), Name=basename(attachment)) part[ 'Content-Disposition'] = 'attachment; filename="%s"' % basename( attachment) msg.attach(part) else: msg = text msg['Subject'] = kwargs.get('email_subject', self.subject) msg['From'] = kwargs.get('email_sender', self.sender) msg['To'] = COMMASPACE.join( kwargs.get('email_recipients', self.recipients)) return msg
def cluster_execute(*cmds, env=None, prelim_cmds=None, **cluster_config): """ Execute commands on a compute cluster :param cmds: :param env: The kind of resource manager being run :param prelim_cmds: Any commands to execute before starting a job array :param cluster_config: :return: ClusterExecutor """ env = env or cfg.query('executor', 'job_execution') if env == 'slurm': cls = SlurmExecutor else: raise EGCGError('Unknown execution environment: %s' % env) e = cls(*cmds, prelim_cmds=prelim_cmds, **cluster_config) e.start() return e
def notify(self, msg, subs): exceptions = [] for s in subs: if s in self.subscribers: try: self.subscribers[s].notify(msg) except Exception as e: etype, value, tb = sys.exc_info() stacktrace = ''.join(traceback.format_exception(etype, value, tb)) self.critical(stacktrace) exceptions.append(e) else: self.debug('Tried to notify by %s, but no configuration present', s) if exceptions: raise EGCGError( 'Encountered the following errors during notification: %s' % ', '.join( '%s: %s' % (e.__class__.__name__, str(e)) for e in exceptions ) )
def _submit_job(self): self.job_id = self._run_and_retry(cfg['executor']['qsub'] + ' ' + self.writer.script_name) if self.job_id is None: raise EGCGError('Job submission failed')
def get_species_name(query_species): raise EGCGError('Could not import egcg_core.ncbi.get_species_name - sqlite3 seems to be unavailable.')