예제 #1
0
    def test_stacktrace_html(self):
        """Stack traces can be caught and rendered as html
        """

        # This is about general exception handling, so ok to use catch-all
        # pylint: disable=W0703
        try:
            bbox_intersection('aoeu', 'oaeu', [])
        except Exception, e:
            # Display message and traceback

            message = get_error_message(e)
            # print message
            message = message.to_text()
            self.assertIn(str(e), message)
            self.assertIn('line', message)
            self.assertIn('file', message)

            message = get_error_message(e)
            message = message.to_html()
            assert str(e) in message

            message = message.decode('string_escape')
            control_file_path = test_data_path(
                'control',
                'files',
                'test-stacktrace-html.txt')
            expected_results = open(control_file_path).read().replace('\n', '')
            self.assertIn(expected_results, message)
예제 #2
0
    def test_stacktrace_html(self):
        """Stack traces can be caught and rendered as html
        """

        # This is about general exception handling, so ok to use catch-all
        # pylint: disable=W0703
        try:
            bbox_intersection('aoeu', 'oaeu', [])
        except Exception, e:
            # Display message and traceback

            message = get_error_message(e)
            # print message
            message = message.to_text()
            self.assertIn(str(e), message)
            self.assertIn('line', message)
            self.assertIn('file', message)

            message = get_error_message(e)
            message = message.to_html()
            assert str(e) in message

            message = message.decode('string_escape')
            control_file_path = test_data_path(
                'control',
                'files',
                'test-stacktrace-html.txt')
            expected_results = open(control_file_path).read().replace('\n', '')
            self.assertIn(expected_results, message)
예제 #3
0
    def save_metadata(self):
        """Save metadata based on the field mapping state."""
        metadata = self.field_mapping_widget.get_field_mapping()
        for key, value in metadata['fields'].items():
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_default_values']:
                self.metadata['inasafe_default_values'].pop(key)
            if value is None or value == []:
                if key in self.metadata['inasafe_fields']:
                    self.metadata['inasafe_fields'].pop(key)
            else:
                self.metadata['inasafe_fields'][key] = value

        for key, value in metadata['values'].items():
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_fields']:
                self.metadata['inasafe_fields'].pop(key)
            if value is None:
                if key in self.metadata['inasafe_default_values']:
                    self.metadata['inasafe_default_values'].pop(key)
            else:
                self.metadata['inasafe_default_values'][key] = value

        # Save metadata
        try:
            self.keyword_io.write_keywords(
                layer=self.layer, keywords=self.metadata)
        except InaSAFEError, e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self, self.tr('InaSAFE'),
                ((self.tr(
                    'An error was encountered when saving the following '
                    'keywords:\n %s') % error_message.to_html())))
예제 #4
0
    def save_current_keywords(self):
        """Save keywords to the layer.

        It will write out the keywords for the current layer.
        This method is based on the KeywordsDialog class.
        """
        current_keywords = self.get_keywords()
        try:
            self.keyword_io.write_keywords(layer=self.layer,
                                           keywords=current_keywords)
        except InaSAFEError as e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self, tr('InaSAFE'),
                tr('An error was encountered when saving the following '
                   'keywords:\n {error_message}').format(
                       error_message=error_message.to_html()))
        if self.dock is not None:
            # noinspection PyUnresolvedReferences
            self.dock.get_layers()

        # Save default value to QSetting
        if current_keywords.get('inasafe_default_values'):
            for key, value in (list(
                    current_keywords['inasafe_default_values'].items())):
                set_inasafe_default_value_qsetting(self.setting, RECENT, key,
                                                   value)
예제 #5
0
    def accept(self):
        """Automatic slot executed when the ok button is pressed.

        It will write out the keywords for the layer that is active.
        """
        self.apply_changes()
        keywords = self.get_keywords()

        # If it's postprocessing layer, we need to check if age ratio is valid
        if self.radPostprocessing.isChecked():
            valid_age_ratio, sum_age_ratios = self.age_ratios_are_valid(
                keywords)
            if not valid_age_ratio:
                message = self.tr(
                    'The sum of age ratios is %s which exceeds 1. Please '
                    'adjust  the age ration defaults so that their cumulative '
                    'value is not greater than 1.' % sum_age_ratios)
                if not self.test:
                    # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
                    QtGui.QMessageBox.warning(self, self.tr('InaSAFE'),
                                              message)
                return

        try:
            self.keyword_io.write_keywords(layer=self.layer, keywords=keywords)
        except InaSAFEError, e:
            error_message = get_error_message(e)
            message = self.tr(
                'An error was encountered when saving the keywords:\n'
                '%s' % error_message.to_html())
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QMessageBox.warning(self, self.tr('InaSAFE'), message)
예제 #6
0
    def save_metadata(self):
        """Save metadata based on the field mapping state."""
        metadata = self.field_mapping_widget.get_field_mapping()
        for key, value in metadata['fields'].items():
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_default_values']:
                self.metadata['inasafe_default_values'].pop(key)
            if value is None or value == []:
                if key in self.metadata['inasafe_fields']:
                    self.metadata['inasafe_fields'].pop(key)
            else:
                self.metadata['inasafe_fields'][key] = value

        for key, value in metadata['values'].items():
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_fields']:
                self.metadata['inasafe_fields'].pop(key)
            if value is None:
                if key in self.metadata['inasafe_default_values']:
                    self.metadata['inasafe_default_values'].pop(key)
            else:
                self.metadata['inasafe_default_values'][key] = value

        # Save metadata
        try:
            self.keyword_io.write_keywords(
                layer=self.layer, keywords=self.metadata)
        except InaSAFEError, e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self, self.tr('InaSAFE'),
                ((self.tr(
                    'An error was encountered when saving the following '
                    'keywords:\n %s') % error_message.to_html())))
예제 #7
0
    def accept(self):
        """Automatic slot executed when the ok button is pressed.

        It will write out the keywords for the layer that is active.
        """
        self.apply_changes()
        keywords = self.get_keywords()

        # If it's postprocessing layer, we need to check if age ratio is valid
        if self.radPostprocessing.isChecked():
            valid_age_ratio, sum_age_ratios = self.age_ratios_are_valid(
                keywords)
            if not valid_age_ratio:
                message = self.tr(
                    'The sum of age ratios is %s which exceeds 1. Please '
                    'adjust  the age ration defaults so that their cumulative '
                    'value is not greater than 1.' % sum_age_ratios)
                if not self.test:
                    # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
                    QtGui.QMessageBox.warning(
                        self, self.tr('InaSAFE'), message)
                return

        try:
            self.keyword_io.write_keywords(layer=self.layer, keywords=keywords)
        except InaSAFEError, e:
            error_message = get_error_message(e)
            message = self.tr(
                'An error was encountered when saving the keywords:\n'
                '%s' % error_message.to_html())
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QMessageBox.warning(self, self.tr('InaSAFE'), message)
예제 #8
0
    def save_current_keywords(self):
        """Save keywords to the layer.

        It will write out the keywords for the current layer.
        This method is based on the KeywordsDialog class.
        """
        current_keywords = self.get_keywords()
        try:
            self.keyword_io.write_keywords(
                layer=self.layer, keywords=current_keywords)
        except InaSAFEError as e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self,
                tr('InaSAFE'),
                tr('An error was encountered when saving the following '
                   'keywords:\n {error_message}').format(
                    error_message=error_message.to_html()))
        if self.dock is not None:
            # noinspection PyUnresolvedReferences
            self.dock.get_layers()

        # Save default value to QSetting
        if current_keywords.get('inasafe_default_values'):
            for key, value in (
                    list(current_keywords['inasafe_default_values'].items())):
                set_inasafe_default_value_qsetting(
                    self.setting, RECENT, key, value)
예제 #9
0
    def print_map_to_pdf(self, impact_report):
        """Print map to PDF given MapReport instance.

        :param impact_report: Impact Report instance that is ready to print
        :type impact_report: ImpactReport
        """
        impact_report.setup_composition()

        # Get Filename
        map_title = impact_report.map_title
        if map_title is not None:
            default_file_name = map_title + '.pdf'
            default_file_name = default_file_name.replace(' ', '_')
        else:
            self.show_error_message(self.tr('Keyword "map_title" not found.'))
            return

        # Get output path
        # noinspection PyCallByClass,PyTypeChecker
        output_path = QtGui.QFileDialog.getSaveFileName(
            self.parent, self.tr('Write to PDF'),
            os.path.join(temp_dir(), default_file_name),
            self.tr('Pdf File (*.pdf)'))
        output_path = str(output_path)

        if output_path is None or output_path == '':
            self.show_dynamic_message(
                self,
                m.Message(m.Heading(self.tr('Map Creator'), **WARNING_STYLE),
                          m.Text(self.tr('Printing cancelled!'))))
            return

        try:
            map_pdf_path, table_pdf_path = impact_report.print_to_pdf(
                output_path)

            # Make sure the file paths can wrap nicely:
            wrapped_map_path = map_pdf_path.replace(os.sep, '<wbr>' + os.sep)
            wrapped_table_path = table_pdf_path.replace(
                os.sep, '<wbr>' + os.sep)
            status = m.Message(
                m.Heading(self.tr('Map Creator'), **INFO_STYLE),
                m.Paragraph(
                    self.
                    tr('Your PDF was created....opening using the default PDF '
                       'viewer on your system. The generated pdfs were saved '
                       'as:')), m.Paragraph(wrapped_map_path),
                m.Paragraph(self.tr('and')), m.Paragraph(wrapped_table_path))

            # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(table_pdf_path))
            # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(map_pdf_path))

            self.show_dynamic_message(self, status)
        except TemplateLoadingError, e:
            self.show_error_message(get_error_message(e))
예제 #10
0
 def fake_error(self):
     """Make a fake error (helper for other tests)
     :returns: Contents of the message viewer as string and with newlines
         stripped off.
     :rtype : str
     """
     e = Exception()
     context = 'Something went wrong'
     message = get_error_message(e, context=context)
     self.message_viewer.error_message_event(None, message)
     text = self.message_viewer.page_to_text().replace('\n', '')
     return text
예제 #11
0
 def test_issue157(self):
     """Verify that we get the error class name back - issue #157
        .. seealso:: https://github.com/AIFDR/inasafe/issues/121
     """
     try:
         bbox_intersection('aoeu', 'oaeu', [])
     except BoundingBoxError, e:
         message = get_error_message(e)
         myString = 'BoundingBoxError'
         assert myString in message.to_text(), message
         myString = 'Western boundary'
         assert myString in message.to_text(), message
 def fake_error(self):
     """Make a fake error (helper for other tests)
     :returns: Contents of the message viewer as string and with newlines
         stripped off.
     :rtype : str
     """
     e = Exception()
     context = 'Something went wrong'
     message = get_error_message(e, context=context)
     self.message_viewer.error_message_event(None, message)
     text = self.message_viewer.page_to_text().replace('\n', '')
     return text
예제 #13
0
 def test_issue157(self):
     """Verify that we get the error class name back - issue #157
        .. seealso:: https://github.com/AIFDR/inasafe/issues/121
     """
     try:
         bbox_intersection('aoeu', 'oaeu', [])
     except BoundingBoxError, e:
         message = get_error_message(e)
         myString = 'BoundingBoxError'
         assert myString in message.to_text(), message
         myString = 'Western boundary'
         assert myString in message.to_text(), message
예제 #14
0
    def save_current_keywords(self):
        """Save keywords to the layer.

        It will write out the keywords for the current layer.
        This method is based on the KeywordsDialog class.
        """
        current_keywords = self.get_keywords()
        try:
            self.keyword_io.write_keywords(layer=self.layer,
                                           keywords=current_keywords)
        except InaSAFEError, e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QMessageBox.warning(
                self, self.tr('InaSAFE'),
                ((self.tr('An error was encountered when saving the following '
                          'keywords:\n %s') % error_message.to_html())))
예제 #15
0
    def save_current_keywords(self):
        """Save keywords to the layer.

        It will write out the keywords for the current layer.
        This method is based on the KeywordsDialog class.
        """
        current_keywords = self.get_keywords()
        try:
            self.keyword_io.write_keywords(
                layer=self.layer, keywords=current_keywords)
        except InaSAFEError, e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QMessageBox.warning(
                self, self.tr('InaSAFE'),
                ((self.tr(
                    'An error was encountered when saving the following '
                    'keywords:\n %s') % error_message.to_html())))
예제 #16
0
    def analysis_error(self, exception, message):
        """A helper to spawn an error and halt processing.

        An exception will be logged, busy status removed and a message
        displayed.

        .. note:: Copied from the dock

        :param message: an ErrorMessage to display
        :type message: ErrorMessage, Message

        :param exception: An exception that was raised
        :type exception: Exception
        """
        self.hide_busy()
        LOGGER.exception(message)
        message = get_error_message(exception, context=message)
        self.show_error_message(message)
        self.analysisDone.emit(False)
예제 #17
0
    def analysis_error(self, exception, message):
        """A helper to spawn an error and halt processing.

        An exception will be logged, busy status removed and a message
        displayed.

        .. note:: Copied from the dock

        :param message: an ErrorMessage to display
        :type message: ErrorMessage, Message

        :param exception: An exception that was raised
        :type exception: Exception
        """
        self.hide_busy()
        LOGGER.exception(message)
        message = get_error_message(exception, context=message)
        self.show_error_message(message)
        self.analysisDone.emit(False)
예제 #18
0
파일: signals.py 프로젝트: timlinux/inasafe
def analysis_error(sender, exception, message):
    """A helper to spawn an error and halt processing.

    An exception will be logged, busy status removed and a message
    displayed.

    .. versionadded:: 3.3

    :param sender: The sender.
    :type sender: object

    :param message: an ErrorMessage to display
    :type message: ErrorMessage, Message

    :param exception: An exception that was raised
    :type exception: Exception
    """
    LOGGER.exception(message)
    message = get_error_message(exception, context=message)
    send_error_message(sender, message)
예제 #19
0
def analysis_error(sender, exception, message):
    """A helper to spawn an error and halt processing.

    An exception will be logged, busy status removed and a message
    displayed.

    .. versionadded:: 3.3

    :param sender: The sender.
    :type sender: object

    :param message: an ErrorMessage to display
    :type message: ErrorMessage, Message

    :param exception: An exception that was raised
    :type exception: Exception
    """
    LOGGER.exception(message)
    message = get_error_message(exception, context=message)
    send_error_message(sender, message)
예제 #20
0
                       'viewer on your system. The generated pdfs were saved '
                       'as:')), m.Paragraph(wrapped_map_path),
                m.Paragraph(self.tr('and')), m.Paragraph(wrapped_table_path))

            # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(table_pdf_path))
            # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(map_pdf_path))

            self.show_dynamic_message(self, status)
        except TemplateLoadingError, e:
            self.show_error_message(get_error_message(e))
        except Exception, e:  # pylint: disable=broad-except
            self.show_error_message(get_error_message(e))

    def open_map_in_composer(self, impact_report):
        """Open map in composer given MapReport instance.

        ..note:: (AG) See https://github.com/AIFDR/inasafe/issues/911. We
            need to set the composition to the composer before loading the
            template.

        :param impact_report: Impact Report to be opened in composer.
        :type impact_report: ImpactReport
        """
        impact_report.setup_composition()
        self.composer = self.iface.createNewComposer()
        self.composer.setComposition(impact_report.composition)
        impact_report.load_template()
예제 #21
0
                m.Paragraph(wrapped_map_path),
                m.Paragraph(self.tr('and')),
                m.Paragraph(wrapped_table_path))

            # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(table_pdf_path))
            # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(map_pdf_path))

            self.show_dynamic_message(self, status)
        except TemplateLoadingError, e:
            self.show_error_message(get_error_message(e))
        except Exception, e:  # pylint: disable=broad-except
            self.show_error_message(get_error_message(e))

    def open_map_in_composer(self, impact_report):
        """Open map in composer given MapReport instance.

        ..note:: (AG) See https://github.com/AIFDR/inasafe/issues/911. We
            need to set the composition to the composer before loading the
            template.

        :param impact_report: Impact Report to be opened in composer.
        :type impact_report: ImpactReport
        """
        impact_report.setup_composition()
        self.composer = self.iface.createNewComposer()
        self.composer.setComposition(impact_report.composition)
        impact_report.load_template()
예제 #22
0
                m.Paragraph(self.tr('and')),
                m.Paragraph(wrapped_table_path))

            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(table_pdf_path))
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(map_pdf_path))

            # noinspection PyTypeChecker
            self.show_dynamic_message(self, status)
        except TemplateLoadingError, e:
            send_error_message(self, get_error_message(e))
        except Exception, e:  # pylint: disable=broad-except
            send_error_message(self, get_error_message(e))

    def open_map_in_composer(self, impact_report):
        """Open map in composer given MapReport instance.

        ..note:: (AG) See https://github.com/AIFDR/inasafe/issues/911. We
            need to set the composition to the composer before loading the
            template.

        :param impact_report: Impact Report to be opened in composer.
        :type impact_report: ImpactReport
        """
        impact_report.setup_composition()
        self.composer = self.iface.createNewComposer()
        self.composer.setComposition(impact_report.composition)
        impact_report.load_template()
예제 #23
0
    def accept(self):
        """Launch the multi exposure analysis."""
        if not isinstance(self._multi_exposure_if,
                          MultiExposureImpactFunction):
            # This should not happen as the "accept" button must be disabled if
            # the impact function is not ready.
            return ANALYSIS_FAILED_BAD_CODE, None

        self.tab_widget.setCurrentIndex(2)
        self.set_enabled_buttons(False)
        enable_busy_cursor()
        try:
            code, message, exposure = self._multi_exposure_if.run()
            message = basestring_to_message(message)
            if code == ANALYSIS_FAILED_BAD_INPUT:
                LOGGER.warning(
                    tr('The impact function could not run because of the inputs.'
                       ))
                send_error_message(self, message)
                LOGGER.warning(message.to_text())
                disable_busy_cursor()
                self.set_enabled_buttons(True)
                return code, message
            elif code == ANALYSIS_FAILED_BAD_CODE:
                LOGGER.warning(
                    tr('The impact function could not run because of a bug.'))
                LOGGER.exception(message.to_text())
                send_error_message(self, message)
                disable_busy_cursor()
                self.set_enabled_buttons(True)
                return code, message

            if setting('generate_report', True, bool):
                LOGGER.info(
                    'Reports are going to be generated for the multiexposure.')
                # Report for the multi exposure
                report = [standard_multi_exposure_impact_report_metadata_html]
                error_code, message = (
                    self._multi_exposure_if.generate_report(report))
                message = basestring_to_message(message)
                if error_code == ImpactReport.REPORT_GENERATION_FAILED:
                    LOGGER.warning('The impact report could not be generated.')
                    send_error_message(self, message)
                    LOGGER.exception(message.to_text())
                    disable_busy_cursor()
                    self.set_enabled_buttons(True)
                    return error_code, message
            else:
                LOGGER.warning(
                    'Reports are not generated because of your settings.')
                display_warning_message_bar(
                    tr('Reports'),
                    tr('Reports are not going to be generated because of your '
                       'InaSAFE settings.'),
                    duration=10,
                    iface_object=self.iface)

            # We always create the multi exposure group because we need
            # reports to be generated.
            root = QgsProject.instance().layerTreeRoot()

            if len(self.ordered_expected_layers()) == 0:
                group_analysis = root.insertGroup(0,
                                                  self._multi_exposure_if.name)
                group_analysis.setItemVisibilityChecked(True)
                group_analysis.setCustomProperty(MULTI_EXPOSURE_ANALYSIS_FLAG,
                                                 True)

                for layer in self._multi_exposure_if.outputs:
                    QgsProject.instance().addMapLayer(layer, False)
                    layer_node = group_analysis.addLayer(layer)
                    layer_node.setItemVisibilityChecked(False)

                    # set layer title if any
                    try:
                        title = layer.keywords['title']
                        if qgis_version() >= 21800:
                            layer.setName(title)
                        else:
                            layer.setLayerName(title)
                    except KeyError:
                        pass

                for analysis in self._multi_exposure_if.impact_functions:
                    detailed_group = group_analysis.insertGroup(
                        0, analysis.name)
                    detailed_group.setItemVisibilityChecked(True)
                    add_impact_layers_to_canvas(analysis, group=detailed_group)

                if self.iface:
                    self.iface.setActiveLayer(
                        self._multi_exposure_if.analysis_impacted)
            else:
                add_layers_to_canvas_with_custom_orders(
                    self.ordered_expected_layers(), self._multi_exposure_if,
                    self.iface)

            if setting('generate_report', True, bool):
                LOGGER.info(
                    'Reports are going to be generated for each single '
                    'exposure.')
                # Report for the single exposure with hazard
                for analysis in self._multi_exposure_if.impact_functions:
                    # we only want to generate non pdf/qpt report
                    html_components = [standard_impact_report_metadata_html]
                    error_code, message = (
                        analysis.generate_report(html_components))
                    message = basestring_to_message(message)
                    if error_code == (ImpactReport.REPORT_GENERATION_FAILED):
                        LOGGER.info(
                            'The impact report could not be generated.')
                        send_error_message(self, message)
                        LOGGER.info(message.to_text())
                        disable_busy_cursor()
                        self.set_enabled_buttons(True)
                        return error_code, message
            else:
                LOGGER.info(
                    'Reports are not generated because of your settings.')
                display_warning_message_bar(
                    tr('Reports'),
                    tr('Reports are not going to be generated because of your '
                       'InaSAFE settings.'),
                    duration=10,
                    iface_object=self.iface)

            # If zoom to impact is enabled
            if setting('setZoomToImpactFlag', expected_type=bool):
                self.iface.zoomToActiveLayer()

            # If hide exposure layers
            if setting('setHideExposureFlag', expected_type=bool):
                treeroot = QgsProject.instance().layerTreeRoot()
                for combo in list(self.combos_exposures.values()):
                    layer = layer_from_combo(combo)
                    if layer is not None:
                        treelayer = treeroot.findLayer(layer.id())
                        if treelayer:
                            treelayer.setItemVisibilityChecked(False)

            # Set last analysis extent
            self._extent.set_last_analysis_extent(
                self._multi_exposure_if.analysis_extent,
                self._multi_exposure_if.crs)

            self.done(QDialog.Accepted)

        except Exception as e:
            error_message = get_error_message(e)
            send_error_message(self, error_message)
            LOGGER.exception(e)
            LOGGER.debug(error_message.to_text())
        finally:
            disable_busy_cursor()
            self.set_enabled_buttons(True)
예제 #24
0
def clip_by_extent(layer, extent):
    """Clip a raster using a bounding box using processing.

    Issue https://github.com/inasafe/inasafe/issues/3183

    :param layer: The layer to clip.
    :type layer: QgsRasterLayer

    :param extent: The extent.
    :type extent: QgsRectangle

    :return: Clipped layer.
    :rtype: QgsRasterLayer

    .. versionadded:: 4.0
    """
    parameters = dict()
    # noinspection PyBroadException
    try:
        output_layer_name = quick_clip_steps['output_layer_name']
        output_layer_name = output_layer_name % layer.keywords['layer_purpose']

        output_raster = unique_filename(suffix='.tif', dir=temp_dir())

        # We make one pixel size buffer on the extent to cover every pixels.
        # See https://github.com/inasafe/inasafe/issues/3655
        pixel_size_x = layer.rasterUnitsPerPixelX()
        pixel_size_y = layer.rasterUnitsPerPixelY()
        buffer_size = max(pixel_size_x, pixel_size_y)
        extent = extent.buffered(buffer_size)

        if is_raster_y_inverted(layer):
            # The raster is Y inverted. We need to switch Y min and Y max.
            bbox = [
                str(extent.xMinimum()),
                str(extent.xMaximum()),
                str(extent.yMaximum()),
                str(extent.yMinimum())
            ]
        else:
            # The raster is normal.
            bbox = [
                str(extent.xMinimum()),
                str(extent.xMaximum()),
                str(extent.yMinimum()),
                str(extent.yMaximum())
            ]

        # These values are all from the processing algorithm.
        # https://github.com/qgis/QGIS/blob/master/python/plugins/processing/
        # algs/gdal/ClipByExtent.py
        # Please read the file to know these parameters.
        parameters['INPUT'] = layer.source()
        parameters['NO_DATA'] = ''
        parameters['PROJWIN'] = ','.join(bbox)
        parameters['DATA_TYPE'] = 5
        parameters['COMPRESS'] = 4
        parameters['JPEGCOMPRESSION'] = 75
        parameters['ZLEVEL'] = 6
        parameters['PREDICTOR'] = 1
        parameters['TILED'] = False
        parameters['BIGTIFF'] = 0
        parameters['TFW'] = False
        parameters['EXTRA'] = ''
        parameters['OUTPUT'] = output_raster

        initialize_processing()
        feedback = create_processing_feedback()
        context = create_processing_context(feedback=feedback)

        result = processing.run(
            "gdal:cliprasterbyextent",
            parameters,
            context=context)

        if result is None:
            raise ProcessingInstallationError

        clipped = QgsRasterLayer(result['OUTPUT'], output_layer_name)

        # We transfer keywords to the output.
        clipped.keywords = layer.keywords.copy()
        clipped.keywords['title'] = output_layer_name

        check_layer(clipped)

    except Exception as e:
        # This step clip_raster_by_extent was nice to speedup the analysis.
        # As we got an exception because the layer is invalid, we are not going
        # to stop the analysis. We will return the original raster layer.
        # It will take more processing time until we clip the vector layer.
        # Check https://github.com/inasafe/inasafe/issues/4026 why we got some
        # exceptions with this step.
        LOGGER.exception(parameters)
        LOGGER.exception(
            'Error from QGIS clip raster by extent. Please check the QGIS '
            'logs too !')
        LOGGER.info(
            'Even if we got an exception, we are continuing the analysis. The '
            'layer was not clipped.')
        LOGGER.exception(str(e))
        LOGGER.exception(get_error_message(e).to_text())
        clipped = layer

    return clipped
예제 #25
0
    def print_map_to_pdf(self, impact_report):
        """Print map to PDF given MapReport instance.

        :param impact_report: Impact Report instance that is ready to print
        :type impact_report: ImpactReport
        """
        impact_report.setup_composition()

        # Get Filename
        map_title = impact_report.map_title
        if map_title is not None:
            default_file_name = map_title + '.pdf'
            default_file_name = default_file_name.replace(' ', '_')
        else:
            self.show_error_message(
                self.tr('Keyword "map_title" not found.'))
            return

        # Get output path
        # noinspection PyCallByClass,PyTypeChecker
        output_path = QtGui.QFileDialog.getSaveFileName(
            self.parent,
            self.tr('Write to PDF'),
            os.path.join(temp_dir(), default_file_name),
            self.tr('Pdf File (*.pdf)'))
        output_path = str(output_path)

        if output_path is None or output_path == '':
            self.show_dynamic_message(
                self,
                m.Message(
                    m.Heading(self.tr('Map Creator'), **WARNING_STYLE),
                    m.Text(self.tr('Printing cancelled!'))))
            return

        try:
            map_pdf_path, table_pdf_path = impact_report.print_to_pdf(
                output_path)

            # Make sure the file paths can wrap nicely:
            wrapped_map_path = map_pdf_path.replace(os.sep, '<wbr>' + os.sep)
            wrapped_table_path = table_pdf_path.replace(os.sep,
                                                        '<wbr>' + os.sep)
            status = m.Message(
                m.Heading(self.tr('Map Creator'), **INFO_STYLE),
                m.Paragraph(self.tr(
                    'Your PDF was created....opening using the default PDF '
                    'viewer on your system. The generated pdfs were saved '
                    'as:')),
                m.Paragraph(wrapped_map_path),
                m.Paragraph(self.tr('and')),
                m.Paragraph(wrapped_table_path))

            # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(table_pdf_path))
            # noinspection PyCallByClass,PyTypeChecker,PyTypeChecker
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(map_pdf_path))

            self.show_dynamic_message(self, status)
        except TemplateLoadingError, e:
            self.show_error_message(get_error_message(e))
예제 #26
0
def clip_by_extent(layer, extent, callback=None):
    """Clip a raster using a bounding box using processing.

    Issue https://github.com/inasafe/inasafe/issues/3183

    :param layer: The layer to reproject.
    :type layer: QgsRasterLayer

    :param extent: The extent.
    :type extent: QgsRectangle

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int) and 'maximum' (int). Defaults to
        None.
    :type callback: function

    :return: Reprojected memory layer.
    :rtype: QgsRasterLayer

    .. versionadded:: 4.0
    """
    parameters = dict()
    # noinspection PyBroadException
    try:
        output_layer_name = quick_clip_steps['output_layer_name']
        processing_step = quick_clip_steps['step_name']
        output_layer_name = output_layer_name % layer.keywords['layer_purpose']

        output_raster = unique_filename(dir=temp_dir())

        # We make one pixel size buffer on the extent to cover every pixels.
        # See https://github.com/inasafe/inasafe/issues/3655
        pixel_size_x = layer.rasterUnitsPerPixelX()
        pixel_size_y = layer.rasterUnitsPerPixelY()
        buffer_size = max(pixel_size_x, pixel_size_y)
        extent = extent.buffer(buffer_size)

        if is_raster_y_inverted(layer):
            # The raster is Y inverted. We need to switch Y min and Y max.
            bbox = [
                str(extent.xMinimum()),
                str(extent.xMaximum()),
                str(extent.yMaximum()),
                str(extent.yMinimum())
            ]
        else:
            # The raster is normal.
            bbox = [
                str(extent.xMinimum()),
                str(extent.xMaximum()),
                str(extent.yMinimum()),
                str(extent.yMaximum())
            ]

        # These values are all from the processing algorithm.
        # https://github.com/qgis/QGIS/blob/master/python/plugins/processing/
        # algs/gdal/ClipByExtent.py
        # Please read the file to know these parameters.
        parameters['INPUT'] = layer.source()
        parameters['NO_DATA'] = ''
        parameters['PROJWIN'] = ','.join(bbox)
        parameters['RTYPE'] = 5
        parameters['COMPRESS'] = 4
        parameters['JPEGCOMPRESSION'] = 75
        parameters['ZLEVEL'] = 6
        parameters['PREDICTOR'] = 1
        parameters['TILED'] = False
        parameters['BIGTIFF'] = 0
        parameters['TFW'] = False
        parameters['EXTRA'] = ''
        parameters['OUTPUT'] = output_raster
        result = processing.runalg("gdalogr:cliprasterbyextent", parameters)

        if result is None:
            raise ProcessingInstallationError

        clipped = QgsRasterLayer(result['OUTPUT'], output_layer_name)

        # We transfer keywords to the output.
        clipped.keywords = layer.keywords.copy()
        clipped.keywords['title'] = output_layer_name

        check_layer(clipped)
    except Exception as e:
        # This step clip_raster_by_extent was nice to speedup the analysis.
        # As we got an exception because the layer is invalid, we are not going
        # to stop the analysis. We will return the original raster layer.
        # It will take more processing time until we clip the vector layer.
        # Check https://github.com/inasafe/inasafe/issues/4026 why we got some
        # exceptions with this step.
        LOGGER.exception(parameters)
        LOGGER.exception(
            'Error from QGIS clip raster by extent. Please check the QGIS '
            'logs too !')
        LOGGER.info(
            'Even if we got an exception, we are continuing the analysis. The '
            'layer is not clip.')
        LOGGER.exception(str(e))
        LOGGER.exception(get_error_message(e).to_text())
        clipped = layer

    return clipped
예제 #27
0
    def process_components(self):
        """Process context for each component and a given template.

        :returns: Tuple of error code and message
        :type: tuple

        .. versionadded:: 4.0
        """
        message = m.Message()
        warning_heading = m.Heading(
            tr('Report Generation issue'), **WARNING_STYLE)
        message.add(warning_heading)
        failed_extract_context = m.Heading(tr(
            'Failed to extract context'), **WARNING_STYLE)
        failed_render_context = m.Heading(tr(
            'Failed to render context'), **WARNING_STYLE)
        failed_find_extractor = m.Heading(tr(
            'Failed to load extractor method'), **WARNING_STYLE)
        failed_find_renderer = m.Heading(tr(
            'Failed to load renderer method'), **WARNING_STYLE)

        generation_error_code = self.REPORT_GENERATION_SUCCESS

        for component in self.metadata.components:
            # load extractors
            try:
                if not component.context:
                    if callable(component.extractor):
                        _extractor_method = component.extractor
                    else:
                        _package_name = (
                            '%(report-key)s.extractors.%(component-key)s')
                        _package_name %= {
                            'report-key': self.metadata.key,
                            'component-key': component.key
                        }
                        # replace dash with underscores
                        _package_name = _package_name.replace('-', '_')
                        _extractor_path = os.path.join(
                            self.metadata.template_folder,
                            component.extractor
                        )
                        _module = imp.load_source(
                            _package_name, _extractor_path)
                        _extractor_method = getattr(_module, 'extractor')
                else:
                    LOGGER.info('Predefined context. Extractor not needed.')
            except Exception as e:  # pylint: disable=broad-except
                generation_error_code = self.REPORT_GENERATION_FAILED
                LOGGER.info(e)
                if self.impact_function.debug_mode:
                    raise
                else:
                    message.add(failed_find_extractor)
                    message.add(component.info)
                    message.add(get_error_message(e))
                    continue

            # method signature:
            #  - this ImpactReport
            #  - this component
            try:
                if not component.context:
                    context = _extractor_method(self, component)
                    component.context = context
                else:
                    LOGGER.info('Using predefined context.')
            except Exception as e:  # pylint: disable=broad-except
                generation_error_code = self.REPORT_GENERATION_FAILED
                LOGGER.info(e)
                if self.impact_function.debug_mode:
                    raise
                else:
                    message.add(failed_extract_context)
                    message.add(get_error_message(e))
                    continue

            try:
                # load processor
                if callable(component.processor):
                    _renderer = component.processor
                else:
                    _package_name = '%(report-key)s.renderer.%(component-key)s'
                    _package_name %= {
                        'report-key': self.metadata.key,
                        'component-key': component.key
                    }
                    # replace dash with underscores
                    _package_name = _package_name.replace('-', '_')
                    _renderer_path = os.path.join(
                        self.metadata.template_folder,
                        component.processor
                    )
                    _module = imp.load_source(_package_name, _renderer_path)
                    _renderer = getattr(_module, 'renderer')
            except Exception as e:  # pylint: disable=broad-except
                generation_error_code = self.REPORT_GENERATION_FAILED
                LOGGER.info(e)
                if self.impact_function.debug_mode:
                    raise
                else:
                    message.add(failed_find_renderer)
                    message.add(component.info)
                    message.add(get_error_message(e))
                    continue

            # method signature:
            #  - this ImpactReport
            #  - this component
            if component.context:
                try:
                    output = _renderer(self, component)
                    output_path = self.component_absolute_output_path(
                        component.key)
                    if isinstance(output_path, dict):
                        try:
                            dirname = os.path.dirname(output_path.get('doc'))
                        except:
                            dirname = os.path.dirname(output_path.get('map'))
                    else:
                        dirname = os.path.dirname(output_path)
                    if component.resources:
                        for resource in component.resources:
                            target_resource = os.path.basename(resource)
                            target_dir = os.path.join(
                                dirname, 'resources', target_resource)
                            # copy here
                            shutil.copytree(resource, target_dir)
                    component.output = output
                except Exception as e:  # pylint: disable=broad-except
                    generation_error_code = self.REPORT_GENERATION_FAILED
                    LOGGER.info(e)
                    if self.impact_function.debug_mode:
                        raise
                    else:
                        message.add(failed_render_context)
                        message.add(get_error_message(e))
                        continue

        return generation_error_code, message
예제 #28
0
                m.Paragraph(self.tr('and')),
                m.Paragraph(wrapped_table_path))

            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(table_pdf_path))
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QtGui.QDesktopServices.openUrl(
                QtCore.QUrl.fromLocalFile(map_pdf_path))

            # noinspection PyTypeChecker
            self.show_dynamic_message(self, status)
        except TemplateLoadingError, e:
            send_error_message(self, get_error_message(e))
        except Exception, e:  # pylint: disable=broad-except
            send_error_message(self, get_error_message(e))

    def open_map_in_composer(self, impact_report):
        """Open map in composer given MapReport instance.

        ..note:: (AG) See https://github.com/AIFDR/inasafe/issues/911. We
            need to set the composition to the composer before loading the
            template.

        :param impact_report: Impact Report to be opened in composer.
        :type impact_report: ImpactReport
        """
        impact_report.setup_composition()
        self.composer = self.iface.createNewComposer()
        self.composer.setComposition(impact_report.composition)
        impact_report.load_template()