Exemple #1
0
    def _spawn_analysis(self):

        if rpc_client.get_client(admin=True).create_analysis_job(
                AnalysisModelFactory.to_dict(
                    AnalysisModelFactory.create(
                        chain=True,
                        compile_instructions=self._compile_instructions_path,
                        compilation=self._compile_job.path,
                        email=self._compile_job.email))):
            self._logger.info("Enqueued analysis")

            return True

        else:

            self._mail(
                "Scan-o-Matic: Compilation of '{path}' completed",
                """This is an automated email, please don't reply!

The project '{path}' on """ + AppConfig().computer_human_name +
                """ has completed. Downstream analysis was refused.

All the best,

Scan-o-Matic""", self._compile_job)

            self._logger.warning("Enquing analysis was refused")
            return False
    def _do_report_error_obtaining_scanner(self):

        self._logger.error("Server never gave me my scanner.")
        self._do_request_scanner_off()

        if not self._scanning_effector_data.warned_scanner_usb:
            self._scanning_effector_data.warned_scanner_usb = True
            self._mail(
                "Scan-o-Matic: Project '{project_name}' could not acquire its Scanner",
                """This is an automated email, please don't reply!

The project '{project_name}' on ''""" + AppConfig().computer_human_name +
                """' could not get scanner {scanner} powered up.
Please hurry to correct this so that the project won't be spoiled.

The scanning project will attempt a new scan in {time_between_scans} minutes,
but note that you won't be warned again if the error persists.

Instead you will be notified when/if error is resolved.

All the best,

Scan-o-Matic""", self._scanning_job)

        return SCAN_STEP.TruncateIteration
    def setup(self, job, redirect_logging=True):

        job = RPC_Job_Model_Factory.serializer.load_serialized_object(job)[0]
        paths_object = paths.Paths()
        self._scanning_job.id = job.id
        self._scanning_job.computer = AppConfig().computer_human_name
        self._setup_directory()

        if redirect_logging:
            file_path = os.path.join(
                self._project_directory,
                paths_object.scan_log_file_pattern.format(
                    self._scanning_job.project_name))
            self._logger.info(
                "{0} is setting up; logging will be directed to file {1}".
                format(job, file_path))
            self._logger.set_output_target(file_path,
                                           catch_stdout=True,
                                           catch_stderr=True)

            self._logger.surpress_prints = False

        self._logger.info("Doing setup")

        self._scanning_effector_data.current_image_path_pattern = os.path.join(
            self._project_directory,
            paths_object.experiment_scan_image_pattern)

        self._scanner = sane.SaneBase(
            scan_mode=self._scanning_job.mode,
            model=self._scanning_job.scanner_hardware)

        self._scanning_effector_data.compile_project_model = compile_project_factory.CompileProjectFactory.create(
            compile_action=COMPILE_ACTION.Initiate
            if self._scanning_job.number_of_scans > 1 else
            COMPILE_ACTION.InitiateAndSpawnAnalysis,
            path=paths_object.get_project_settings_path_from_scan_model(
                self._scanning_job),
            fixture_type=FIXTURE.Global,
            fixture_name=self._scanning_job.fixture)

        self._scanning_effector_data.compile_project_model.images = []

        scan_project_file_path = os.path.join(
            self._project_directory,
            paths_object.scan_project_file_pattern.format(
                self._scanning_job.project_name))

        if ScanningModelFactory.serializer.dump(self._scanning_job,
                                                scan_project_file_path):

            self._logger.info("Saved project settings to '{0}'".format(
                scan_project_file_path))

        else:

            self._logger.error(
                "Could not save project settings to '{0}'".format(
                    scan_project_file_path))
        self._allow_start = True
    def _do_report_error_scanning(self):

        self._logger.info("Job {0} reports scanning error".format(
            self._scanning_job.id))
        self._logger.error("Could not scan file {0}".format(
            self._scanning_effector_data.current_image_path))

        if not self._scanning_effector_data.warned_scanner_error:
            self._scanning_effector_data.warned_scanner_error = True
            self._mail(
                "Scan-o-Matic: Project '{project_name}' error while scanning",
                """This is an automated email, please don't reply!

The project '{project_name}' on ''""" + AppConfig().computer_human_name +
                """' reports an error while scanning.
Please hurry to correct this so that the project won't be spoiled.

The scanning project will attempt a new scan in {time_between_scans} minutes,
but note that you won't be warned again if the error persists.

Instead you will be notified when/if error is resolved.

All the best,

Scan-o-Matic""", self._scanning_job)

        return SCAN_STEP.NextMajor
Exemple #5
0
    def enact_stop(self):

        self._stopping = True

        self._mail(
            "Scan-o-Matic: Compilation of '{path}' completed",
            """This is an automated email, please don't reply!

The project '{path}' on """ + AppConfig().computer_human_name +
            """ has completed. No downstream analysis requested.

All the best,

Scan-o-Matic""", self._compile_job)

        raise StopIteration
    def next(self):

        if self.waiting:
            return super(PhenotypeExtractionEffector, self).next()

        if self._stopping:
            self._progress = None
            self._running = False

        if self._iteration_index is None:
            self._setup_extraction_iterator()

        if not self._paused and self._running:
            try:
                self._progress = self._phenotype_iterator.next()
            except StopIteration:
                self._running = False
                self._progress = None
            self._logger.info(
                "One phenotype extraction iteration completed. " +
                "Resume {0}".format(self._running))

        if not self._running:
            if not self._stopping:

                self._phenotyper.save_state(self._analysis_base_path,
                                            ask_if_overwrite=False)

                self._phenotyper.save_phenotypes(
                    dir_path=self._analysis_base_path, ask_if_overwrite=False)

            self._mail(
                "Scan-o-Matic: Feature extraction of '{analysis_directory}' completed",
                """This is an automated email, please don't reply!

The project '{analysis_directory}' on """ + AppConfig().computer_human_name +
                """ has completed. Downstream analysis exists. All is done.
Hope you find cool results!

All the best,

Scan-o-Matic""", self._feature_job)

            raise StopIteration
    def _do_report_scanning_soon_done(self):

        self._scanning_effector_data.informed_close_to_end = True
        self._mail(
            "Scan-o-Matic: Project '{project_name}' on scanning is soon done.",
            """This is an automated email, please don't reply!

The project '{project_name} on ''""" + AppConfig().computer_human_name +
            """' is reporting that it will soon stop using scanner {scanner} and launch
the automatic analysis.

""" + "Scanning estimated to end in {0:0.0f} minutes".format(
                self.seconds_left / 60.) + """

It's a great time to start preparing the next experiment.

All the best,

Scan-o-Matic""", self._scanning_job)
Exemple #8
0
    def _mail_issues(self, issues):
        self._has_mailed_issues = True
        self._mail(
            "Scan-o-Matic: Problems compiling project '{path}'",
            """This is an automated email, please don't reply!

The project '{path}' on """ + AppConfig().computer_human_name +
            """ has experienced a problems with compiling the current project.
                   """
            "* Image seems rotated ({0} radians).\n".format(issues['rotation'])
            if 'rotation' in issues else ""
            "* Part of calibrated fixture falls outside image ({0}).\n".format(
                issues['overflow'] if isinstance(issues['overflow'], str) else
                "Plate {0}".format(issues["overflow"]))
            if 'overflow' in issues else ""
            """

All the best,

Scan-o-Matic""", self._compile_job)
Exemple #9
0
    def _finalize_analysis(self):

        self._xmlWriter.close()

        self._logger.info("ANALYSIS, Full analysis took {0} minutes".format(
            ((time.time() - self._start_time) / 60.0)))

        self._logger.info('Analysis completed at ' + str(time.time()))

        if self._analysis_job.chain:

            try:
                rc = rpc_client.get_client(admin=True)
                if rc.create_feature_extract_job(
                        FeaturesFactory.to_dict(
                            FeaturesFactory.create(
                                analysis_directory=self._analysis_job.
                                output_directory,
                                email=self._analysis_job.email))):

                    self._logger.info("Enqueued feature extraction job")
                else:
                    self._logger.warning(
                        "Enqueing of feature extraction job refused")
            except:
                self._logger.error(
                    "Could not spawn analysis at directory {0}".format(
                        self._analysis_job.output_directory))
        else:
            self._mail(
                "Scan-o-Matic: Analysis for project '{project_name}' done.",
                """This is an automated email, please don't reply!

The project '{compile_instructions}' on """ + AppConfig().computer_human_name +
                """ is done and no further action requested.

All the best,

Scan-o-Matic""", self._analysis_job)

        self._running = False
    def _do_verify_discspace(self):
        def get_free_space():

            try:
                vfs = os.statvfs(
                    self._scanning_job.directory_containing_project)
                return vfs.f_frsize * vfs.f_bavail
            except OSError:
                return 0

        if self._scanning_effector_data.known_file_size and not self._scanning_effector_data.warned_discspace:

            bytes_needed = (self._scanning_job.number_of_scans - self._scanning_effector_data.current_image) * \
                self._scanning_effector_data.known_file_size

            if bytes_needed * DISKSPACE_MARGIN_FACTOR > get_free_space():
                self._scanning_effector_data.warned_discspace = True
                self._mail(
                    "Scan-o-Matic: Project '{project_name}' may not have enough disc space",
                    """This is an automated email, please don't reply!

The project '{project_name}' on ''""" + AppConfig().computer_human_name +
                    """' is reporting that the remaining space the
drive it is saving its data to may not be enough for the remainder of the project
to complete.

Note that this is an estimate, as the project is unaware of other projects running
at the same time, but please verify remaining space.

""" + "Report triggered after acquiring image index {0}".format(
                        self._scanning_effector_data.current_image) +
                    """ of {number_of_scans}.

No further warnings about disc space will be sent for this project.

All the best,

Scan-o-Matic""", self._scanning_job)

        return SCAN_STEP.NextMajor
        def _do_mail(title, message, model):

            try:
                if not model.email:
                    return

                if AppConfig().mail.server:
                    server = mail.get_server(
                        AppConfig().mail.server,
                        smtp_port=AppConfig().mail.port,
                        login=AppConfig().mail.user,
                        password=AppConfig().mail.password)
                else:
                    server = None

                mail.mail(AppConfig().mail.user,
                          model.email,
                          title.format(**model),
                          message.format(**model),
                          server=server)
            except:
                self._logger.warning(
                    "Mailing message '{0}' to '{1}' failed".format(
                        title, model.email))
    def _do_verify_image_size(self):
        def get_size_of_last_image():
            try:
                return os.stat(
                    self._scanning_effector_data.current_image_path).st_size
            except OSError:
                return 0

        current_size = get_size_of_last_image()
        largest_known_size = max(current_size,
                                 self._scanning_effector_data.known_file_size)

        if current_size < TOO_SMALL_SIZE:

            self._removed_current_image()

            if self._scanning_effector_data.warned_file_size is False:
                self._scanning_effector_data.warned_file_size = True
                self._mail(
                    "Scan-o-Matic: Project '{project_name}' got suspicious image",
                    """This is an automated email, please don't reply!

The project '{project_name}' on ''""" + AppConfig().computer_human_name +
                    """' got an image of very small size.

""" + "{0}:\t{1} bytes\n".format(
                        self._scanning_effector_data.current_image_path,
                        current_size) + """

Several reasons are probable:

   1) The hard drive is full
   2) The scanner lost power or crashed while acquiring the image

All the best,

Scan-o-Matic""", self._scanning_job)

            return SCAN_STEP.TruncateIteration

        elif (self._scanning_effector_data.known_file_size and
              abs(self._scanning_effector_data.known_file_size - current_size)
              / largest_known_size > FILE_SIZE_DEVIATION_ALLOWANCE):

            if current_size < self._scanning_effector_data.known_file_size:
                self._removed_current_image()

            if self._scanning_effector_data.warned_file_size is False:
                self._scanning_effector_data.warned_file_size = True
                self._mail(
                    "Scan-o-Matic: Project '{project_name}' got suspicious image",
                    """This is an automated email, please don't reply!

The project '{project_name}' on ''""" + AppConfig().computer_human_name +
                    """' got an image of unexpected size.

""" + "{0}:\t{1} bytes\n\n".format(
                        self._scanning_effector_data.current_image_path,
                        current_size) +
                    "Previously, the largest size was {0}, such deviations aren't expected."
                    .format(self._scanning_effector_data.known_file_size) + """
Several reasons are probable:

   1) The hard drive is full
   2) The scanner lost power or crashed while acquiring the image

All the best,

Scan-o-Matic""", self._scanning_job)

            return SCAN_STEP.TruncateIteration

        elif self._scanning_effector_data.warned_file_size is True:

            self._scanning_effector_data.warned_file_size = False
            self._mail(
                "Scan-o-Matic: Resolved, project '{project_name}' now got normal image",
                """This is an automated email, please don't reply!

The project '{project_name}' got image of expected size again! Yay.

All the best,

Scan-o-Matic""", self._scanning_job)

        self._scanning_effector_data.known_file_size = largest_known_size
        return SCAN_STEP.NextMinor
    def next(self):

        if self.waiting:
            return super(ScannerEffector, self).next()
        elif not self._stopping:
            try:
                step_action = self._scan_cycle[
                    self._scanning_effector_data.current_cycle_step]()
            except KeyError:
                self._logger.warning(
                    "Error performing step {0}, no known method for that step".
                    format(self._scanning_effector_data.current_cycle_step))

                step_action = self._get_step_to_next_scan_cycle_step()

            self._update_scan_cycle_step(step_action)
        else:
            self._logger.info("Interrupted progress {0} at {1} ({2})".format(
                self._scanning_job,
                self._scanning_effector_data.current_cycle_step,
                self._scanning_effector_data.previous_scan_cycle_start))
            if not self._scanning_effector_data.warned_terminated:
                self._mail(
                    "Scan-o-Matic: Terminated project '{project_name}' by user",
                    """This is an automated email, please don't reply!

    The project '{project_name}' on scanner {scanner} on """ +
                    AppConfig().computer_human_name +
                    """ has been requested to be terminated by user and is therefore
    shutting down.

    All the best,

    Scan-o-Matic""", self._scanning_job)

                self._scanning_effector_data.warned_terminated = True

            if (self._scanning_effector_data.current_cycle_step
                    in (SCAN_CYCLE.RequestScanner,
                        SCAN_CYCLE.RequestScannerOff,
                        SCAN_CYCLE.ReportNotObtainedUSB,
                        SCAN_CYCLE.ReportScanError, SCAN_CYCLE.Scan,
                        SCAN_CYCLE.WaitForUSB)):
                self._do_request_scanner_off()
                self._scanning_effector_data.current_cycle_step = SCAN_CYCLE.Wait

            elif self._scanning_effector_data.current_cycle_step == SCAN_CYCLE.WaitForScanComplete:

                if self._do_wait_for_scan() == SCAN_STEP.NextMajor:
                    self._do_request_scanner_off()
                    self._scanning_effector_data.current_cycle_step = SCAN_CYCLE.Wait

            if self.current_image == 0:
                self._scanning_effector_data.current_image = None
            else:
                self._scanning_effector_data.current_image = self._scanning_job.number_of_scans

            self._scanning_effector_data.current_cycle_step == SCAN_CYCLE.Wait

        if (not self._scanning_effector_data.informed_close_to_end
                and self.seconds_left / 60.0 <
                AppConfig().mail.warn_scanning_done_minutes_before):

            self._do_report_scanning_soon_done()

        if self._job_completed and self._scanning_effector_data.current_cycle_step == SCAN_CYCLE.Wait:
            self._stopping = True

            if self._scanning_effector_data.compilation_state is not COMPILE_STATE.Finalized:

                self._scanning_effector_data.compile_project_model.compile_action = \
                    COMPILE_ACTION.AppendAndSpawnAnalysis if self._scanning_effector_data.compilation_state is \
                    COMPILE_STATE.Initialized else COMPILE_ACTION.InitiateAndSpawnAnalysis

                self._do_request_project_compilation()

            raise StopIteration
        else:
            return self._scanning_effector_data.current_cycle_step