Пример #1
0
    def _maybe_restart_worker(self, paths, worker):
        """
        Restart the worker if it has been started less than `self.max_worker_starts` times previously. Otherwise, log an
        error, and save the error image.

        :param paths: Paths object representing the image file.
        :type paths: src.io.TreeWalker.Paths
        :param worker: Worker to maybe restart
        :type worker: src.Workers.BaseWorker
        :return: True if worker was restarted, False otherwise
        :rtype: bool
        """
        if worker.n_starts > self.max_worker_starts:
            LOGGER.error(
                __name__,
                f"{worker.__class__.__name__} failed for image: {paths.input_file}.",
                save=True,
                email=True,
                email_mode="error")
            return False
        else:
            worker.start()
            LOGGER.debug(
                __name__,
                f"Restarted {worker.__class__.__name__} for image: {paths.input_file}."
            )
            return True
Пример #2
0
def main():
    tree_walker, database_client = initialize()
    start_datetime = datetime.now()

    for i, paths in enumerate(tree_walker.walk()):
        count_str = f"{i + 1} of {tree_walker.n_valid_images}"
        LOGGER.info(__name__, LOG_SEP)
        LOGGER.info(__name__, f"Iteration: {count_str}.")
        LOGGER.info(__name__, f"Processing file {paths.input_file}")

        try:
            json_dict = load_json(paths)
            database_client.add_row(json_dict)
        except PROCESSING_EXCEPTIONS as err:
            LOGGER.error(
                __name__,
                f"Got error '{type(err).__name__}: {str(err)}' when writing JSON to Database. "
                f"File: {paths.input_file}")

    LOGGER.info(__name__, LOG_SEP)
    LOGGER.info(__name__, "Writing remaining files to Database")
    database_client.close()

    summary_str = get_summary(tree_walker, database_client, start_datetime)
    LOGGER.info(__name__, LOG_SEP)
    LOGGER.info(__name__, summary_str)
Пример #3
0
def send_mail(message_type, etype=None, ex=None, tb=None, msg=None):
    """
    Send an email of type `message_type`. The sender, receiver(s) and smtp-server are configured in `email_config.py`.
    If  `--log-folder` is specified to `src.main`, the log-file will be attached to the message.

    :param message_type: Type of message. This determines the subject and contents of the message. Must be one of

                         - `critical`: This is suitable for critical errors which cause the program to exit abnormally.
                                       A critical message requires `etype`, `ex` and `tb` to be specified, and will
                                       include the exception type in the subject, and the traceback in the contents.
                         - `error`: This message is suitable for processing errors which do not cause the program to
                                    exit.
                         - `finished`: This message type should be used when the program exits normally.

    :type message_type: str
    :param etype: Exception type
    :type etype: type | None
    :param ex: Exception instance
    :type ex: BaseException | None
    :param tb: Traceback object
    :type tb: traceback.traceback | None
    :param msg: Message to include in the contents of the email.
    :type msg: str | None
    """
    # Determine subject
    if message_type == "critical":
        msg = "".join(traceback.format_exception(etype, ex, tb))
        subject = CRITICAL_SUBJECT.format(etype=etype.__name__,
                                          hostname=gethostname())
    elif message_type == "error":
        subject = ERROR_SUBJECT.format(hostname=gethostname())
    elif message_type == "finished":
        subject = FINISHED_SUBJECT.format(hostname=gethostname())
    else:
        raise ValueError(
            f"Function `email.send_mail` got invalid message type: {message_type}"
        )
    # Create the message
    message = create_base_message(subject, msg)
    # Try to send the email. If sending fails, log the message as an error, and continue.
    try:
        with smtplib.SMTP(email_config.smtp_host, email_config.port) as smtp:
            smtp.sendmail(from_addr=email_config.from_address,
                          to_addrs=email_config.to_addresses,
                          msg=message)
    except Exception as err:
        LOGGER.error(
            __name__,
            f"Got error '{str(err)}' when attempting to send e-mail.")
Пример #4
0
def main():
    tree_walker = initialize()

    for i, paths in enumerate(tree_walker.walk()):
        count_str = f"{i + 1} of {tree_walker.n_valid_images}"
        LOGGER.info(__name__, LOG_SEP)
        LOGGER.info(__name__, f"Iteration: {count_str}.")
        LOGGER.info(__name__, f"Processing file {paths.input_file}")

        try:
            worker = EXIFWorker(None, paths, None)
            worker.get()
        except PROCESSING_EXCEPTIONS as err:
            LOGGER.error(
                f"Got error '{type(err).__name__}: {str(err)}' when creating JSON from image. "
                f"File: {paths.input_file}")
Пример #5
0
def main():
    """Run the masking."""
    # Initialize
    start_datetime = datetime.now()
    args, tree_walker, image_processor, dataset_iterator = initialize()
    n_imgs = "?" if config.lazy_paths else (tree_walker.n_valid_images +
                                            tree_walker.n_skipped_images)

    # Mask images
    time_at_iter_start = time.time()
    for i, paths in enumerate(tree_walker.walk()):
        count_str = f"{tree_walker.n_skipped_images + i + 1} of {n_imgs}"
        start_time = time.time()
        LOGGER.set_state(paths)
        LOGGER.info(__name__, LOG_SEP)
        LOGGER.info(__name__, f"Iteration: {count_str}.")

        # Catch potential exceptions raised while processing the image
        try:
            # Get the image
            img = next(dataset_iterator)
            # Do the processing
            image_processor.process_image(img, paths)
        except PROCESSING_EXCEPTIONS as err:
            error_msg = f"'{str(err)}'. File: {paths.input_file}"
            LOGGER.error(__name__,
                         error_msg,
                         save=True,
                         email=True,
                         email_mode="error")
            continue

        est_done = get_estimated_done(time_at_iter_start, n_imgs, i + 1)
        iter_time_delta = "{:.3f}".format(time.time() - start_time)
        LOGGER.info(__name__, f"Iteration finished in {iter_time_delta} s.")
        LOGGER.info(__name__, f"Estimated completion: {est_done}")

    # Close the image_processor. This will make sure that all exports are finished before we continue.
    LOGGER.info(__name__, LOG_SEP)
    LOGGER.info(__name__, f"Writing output files for the remaining images.")
    image_processor.close()

    # Summary
    summary_str = get_summary(tree_walker, image_processor, start_datetime)
    LOGGER.info(__name__, LOG_SEP)
    LOGGER.info(__name__, summary_str, email=True, email_mode="finished")
Пример #6
0
    def handle_errors(self, errors, rows, action="writing to"):
        """
        Log errors caused when running `cursor.executemany`.

        :param errors: Errors from `cursor.getbatcherrors`
        :type errors: list
        :param rows: Rows which caused the errors
        :type rows: list of dict
        :param action: Optional database action for the error message.
        :type action: str
        """
        # Increment total error counter
        self.total_errors += len(errors)

        # Create an error message
        msg = f"Got {len(errors)} error(s) while {action} the database:\n"
        msg += "\n".join([err.message for err in errors])
        # Log the error
        LOGGER.error(__name__, msg, save=False, email=True, email_mode="error")
Пример #7
0
def _handle_missing_files(paths, missing_files):
    """
    Handle any missing files identified for a given image. This will log an error, which saves the error image, and
    sends an error-email, if email sending is enabled.

    :param paths: Paths object representing the input image
    :type paths: src.io.TreeWalker.Paths
    :param missing_files: List of missing files
    :type missing_files: list of str
    """
    current_logger_state = LOGGER.get_state()
    LOGGER.set_state(paths)
    LOGGER.error(
        __name__,
        f"Missing output files {missing_files} for image: {paths.input_file}",
        save=True,
        email=True,
        email_mode="error")
    LOGGER.set_state(current_logger_state)
Пример #8
0
    def handle_error(self, err):
        """
        Handle an exception raised by an async worker.

        :param err: Exception raised by the worker
        :type err: BaseException
        """
        # Get the current state of the logger
        current_logger_state = LOGGER.get_state()

        # Set the state of the logger to reflect the failed image.
        LOGGER.set_state(self.paths)
        # Log the error
        LOGGER.error(__name__,
                     self.error_message.format(
                         image_path=self.paths.input_file, err=str(err)),
                     save=False,
                     email=False)
        # Reset the state
        LOGGER.set_state(current_logger_state)