예제 #1
0
    def open_graph_view(self, index):
        """Open reference in Graph view form.

        Args:
            index (QModelIndex): Index of the selected reference in View properties
        """
        reference = self._references[index.row()]
        db_url = reference['url']
        try:
            graph_view_form = self.graph_view_form_refs[db_url]
            graph_view_form.raise_()
            return
        except KeyError:
            pass
        database = reference['database']
        username = reference['username']
        try:
            db_map = DiffDatabaseMapping(db_url, username)
        except SpineDBAPIError as e:
            self._toolbox.msg_error.emit(e.msg)
            return
        try:
            graph_view_form = GraphViewForm(self, db_map, database, read_only=True)
        except:
            db_map.close()
            raise
        graph_view_form.show()
        graph_view_form.destroyed.connect(lambda : self.graph_view_form_refs.pop(db_url))
        self.graph_view_form_refs[db_url] = graph_view_form
예제 #2
0
 def open_tabular_view(self):
     """Open reference in Data Store tabular view."""
     if self.tabular_view_form:
         if self.tabular_view_form.windowState() & Qt.WindowMinimized:
             # Remove minimized status and restore window with the previous state (maximized/normal state)
             self.tabular_view_form.setWindowState(
                 self.tabular_view_form.windowState()
                 & ~Qt.WindowMinimized | Qt.WindowActive)
             self.tabular_view_form.activateWindow()
         else:
             self.tabular_view_form.raise_()
         return
     if self._toolbox.ui.comboBox_dialect.currentIndex() < 0:
         self._toolbox.msg_warning.emit("Please select dialect first")
         return
     reference = self.make_reference()
     if not reference:
         return
     db_url = reference['url']
     database = reference['database']
     username = reference['username']
     try:
         db_map = DiffDatabaseMapping(db_url, username)
     except SpineDBAPIError as e:
         self._toolbox.msg_error.emit(e.msg)
         return
     try:
         self.tabular_view_form = TabularViewForm(self, db_map, database)
     except:
         db_map.close()
         raise
     self.tabular_view_form.destroyed.connect(
         self.tabular_view_form_destroyed)
     self.tabular_view_form.show()
예제 #3
0
 def open_tree_view(self):
     """Open reference in tree view form."""
     reference = self.make_reference()
     if not reference:
         return
     if self.tree_view_form:
         # If the url hasn't changed, just raise the current form
         if self.tree_view_form.db_map.db_url == reference['url']:
             if self.tree_view_form.windowState() & Qt.WindowMinimized:
                 # Remove minimized status and restore window with the previous state (maximized/normal state)
                 self.tree_view_form.setWindowState(
                     self.tree_view_form.windowState()
                     & ~Qt.WindowMinimized | Qt.WindowActive)
                 self.tree_view_form.activateWindow()
             else:
                 self.tree_view_form.raise_()
             return
         self.tree_view_form.destroyed.disconnect(
             self.tree_view_form_destroyed)
         self.tree_view_form.close()
     db_url = reference['url']
     database = reference['database']
     username = reference['username']
     try:
         db_map = DiffDatabaseMapping(db_url, username)
     except SpineDBAPIError as e:
         self._toolbox.msg_error.emit(e.msg)
         return
     try:
         self.tree_view_form = TreeViewForm(self, db_map, database)
     except:
         db_map.close()
         raise
     self.tree_view_form.show()
     self.tree_view_form.destroyed.connect(self.tree_view_form_destroyed)
예제 #4
0
 def setUp(self):
     """Overridden method. Runs before each test. Makes instance of TreeViewForm class.
     """
     # # Set logging level to Error to silence "Logging level: All messages" print
     with mock.patch("data_store.DataStore") as mock_data_store:
         logging.disable(level=logging.ERROR)  # Disable logging
         try:
             os.remove('mock_db.sqlite')
         except OSError:
             pass
         db_url = "sqlite:///mock_db.sqlite"
         create_new_spine_database(db_url)
         db_map = DiffDatabaseMapping(db_url, "UnitTest")
         db_map.reset_mapping()
         self.tree_view_form = TreeViewForm(mock_data_store, db_map, "mock_db")
         logging.disable(level=logging.NOTSET)  # Enable logging
 def __init__(self, db_url, datapackage_descriptor, datapackage_base_path):
     super().__init__()
     self.db_url = db_url
     create_new_spine_database(self.db_url)
     self.db_map = DiffDatabaseMapping(db_url, getpass.getuser())
     self.datapackage = Package(datapackage_descriptor,
                                datapackage_base_path)
     self.signaler = Signaler()
     self.resource_data = dict()
     self.object_class_count = None
     self.object_count = None
     self.relationship_class_count = None
     self.relationship_count = None
     self.parameter_count = None
     self.parameter_value_count = None
     for resource in self.datapackage.resources:
         self.resource_data[resource.name] = resource.read(cast=False)
class DatapackageToSpineConverter(QRunnable):
    def __init__(self, db_url, datapackage_descriptor, datapackage_base_path):
        super().__init__()
        self.db_url = db_url
        create_new_spine_database(self.db_url)
        self.db_map = DiffDatabaseMapping(db_url, getpass.getuser())
        self.datapackage = Package(datapackage_descriptor,
                                   datapackage_base_path)
        self.signaler = Signaler()
        self.resource_data = dict()
        self.object_class_count = None
        self.object_count = None
        self.relationship_class_count = None
        self.relationship_count = None
        self.parameter_count = None
        self.parameter_value_count = None
        for resource in self.datapackage.resources:
            self.resource_data[resource.name] = resource.read(cast=False)

    def number_of_steps(self):
        self.object_class_count = len(self.datapackage.resources)
        self.object_count = sum(
            len(self.resource_data[x.name])
            for x in self.datapackage.resources)
        self.relationship_class_count = len(
            [x for x in self.datapackage.resources if x.schema.foreign_keys])
        self.relationship_count = sum(
            len(self.resource_data[x.name]) for x in self.datapackage.resources
            if x.schema.foreign_keys)
        self.parameter_count = sum(
            len(x.schema.fields) - len(x.schema.primary_key) \
            - len([i for fk in x.schema.foreign_keys for i in fk["fields"]])
            for x in self.datapackage.resources)
        self.parameter_value_count = sum(
            len(self.resource_data[x.name]) \
                * (len(x.schema.fields) - len(x.schema.primary_key) \
                - len([i for fk in x.schema.foreign_keys for i in fk["fields"]]))
            for x in self.datapackage.resources)
        return self.object_class_count \
            + self.object_count \
            + self.relationship_class_count \
            + self.relationship_count \
            + self.parameter_count \
            + self.parameter_value_count

    def run(self):
        try:
            self._run()
            self.signaler.finished.emit()
        except (SpineDBAPIError, SpineIntegrityError) as e:
            self.signaler.failed.emit(e.msg)

    def _run(self):
        step = 0
        self.signaler.progressed.emit(step, "")
        object_class_names = [x.name for x in self.db_map.object_class_list()]
        parameter_names = [x.name for x in self.db_map.parameter_list()]
        object_class_name_lists = [
            x.object_class_name_list.split(",")
            for x in self.db_map.wide_relationship_class_list()
        ]
        object_classes = list()
        pre_relationship_classes = list()
        pre_parameters = list()
        for resource in self.datapackage.resources:
            if resource.name not in object_class_names:
                object_classes.append(dict(name=resource.name))
                object_class_names.append(resource.name)
            primary_key = resource.schema.primary_key
            foreign_keys = resource.schema.foreign_keys
            reference_resource_names = [
                fk["reference"]["resource"] for fk in foreign_keys
            ]
            for reference_resource_name in reference_resource_names:
                if reference_resource_name not in object_class_names:
                    object_classes.append(dict(name=reference_resource_name))
                    object_class_names.append(reference_resource_name)
            if reference_resource_names:
                object_class_name_list = [resource.name
                                          ] + reference_resource_names
                relationship_class_name = "__".join(object_class_name_list)
                pre_relationship_classes.append(
                    dict(object_class_name_list=object_class_name_list,
                         name=relationship_class_name))
                object_class_name_lists.append(object_class_name_list)
            for field in resource.schema.fields:
                # Skip fields in primary key
                if field.name in primary_key:
                    continue
                # Skip fields in any foreign key
                if field in [x for fk in foreign_keys for x in fk["fields"]]:
                    continue
                parameter_name = resource.name + "_" + field.name
                if parameter_name not in parameter_names:
                    pre_parameters.append(
                        dict(object_class_name=resource.name,
                             name=parameter_name))
                    parameter_names.append(parameter_name)
        self.signaler.progressed.emit(step, "Adding object classes...")
        self.db_map.add_object_classes(*object_classes)
        step += self.object_class_count
        object_class_name_id = {
            x.name: x.id
            for x in self.db_map.object_class_list()
        }
        relationship_classes = [
            dict(object_class_id_list=[
                object_class_name_id[n] for n in r['object_class_name_list']
            ],
                 name=r['name']) for r in pre_relationship_classes
        ]
        self.signaler.progressed.emit(step, "Adding relationship classes...")
        self.db_map.add_wide_relationship_classes(*relationship_classes)
        step += self.relationship_class_count
        parameters = [
            dict(object_class_id=object_class_name_id[p['object_class_name']],
                 name=p['name']) for p in pre_parameters
        ]
        self.signaler.progressed.emit(step, "Adding parameters...")
        self.db_map.add_parameters(*parameters)
        step += self.parameter_count
        relationship_class_name_id = {
            x.name: x.id
            for x in self.db_map.wide_relationship_class_list()
        }
        parameter_name_id = {
            x.name: x.id
            for x in self.db_map.parameter_list()
        }
        object_names = [x.name for x in self.db_map.object_list()]
        # Create list of object and preliminary parameter value dicts.
        objects = list()
        pre_parameter_values = list()
        for resource in self.datapackage.resources:
            object_class_id = object_class_name_id[resource.name]
            primary_key = resource.schema.primary_key
            foreign_keys = resource.schema.foreign_keys
            foreign_keys_fields = [
                x for fk in foreign_keys for x in fk["fields"]
            ]
            for i, row in enumerate(self.resource_data[resource.name]):
                row_dict = dict(zip(resource.schema.field_names, row))
                if primary_key:
                    object_name_suffix = "_".join(row_dict[field]
                                                  for field in primary_key)
                else:
                    object_name_suffix = str(i)
                object_name = resource.name + "_" + object_name_suffix
                if not object_name in object_names:
                    objects.append(
                        dict(class_id=object_class_id, name=object_name))
                    object_names.append(object_name)
                for field_name, value in row_dict.items():
                    if field_name in primary_key:
                        continue
                    if field_name in foreign_keys_fields:
                        continue
                    parameter_name = resource.name + "_" + field_name
                    parameter_id = parameter_name_id[parameter_name]
                    pre_parameter_values.append(
                        dict(object_name=object_name,
                             parameter_id=parameter_id,
                             value=value))
        self.signaler.progressed.emit(step, "Adding objects...")
        self.db_map.add_objects(*objects)
        step += self.object_count
        object_name_id = {x.name: x.id for x in self.db_map.object_list()}
        parameter_values = [
            dict(object_id=object_name_id[p['object_name']],
                 parameter_id=p['parameter_id'],
                 value=p['value']) for p in pre_parameter_values
        ]
        self.signaler.progressed.emit(step, "Adding parameter values...")
        self.db_map.add_parameter_values(*parameter_values)
        step += self.parameter_value_count
        # Create dictionary of reference resource names => list of reference fields names
        reference_resource_dict = dict()
        for resource in self.datapackage.resources:
            foreign_keys = resource.schema.foreign_keys
            for foreign_key in foreign_keys:
                reference_resource_name = foreign_key["reference"]["resource"]
                reference_fields_names = foreign_key["reference"]["fields"]
                reference_resource_dict.setdefault(reference_resource_name, list()).\
                    append(reference_fields_names)
        # Create dictionary of reference resource name => reference fields names
        # => reference key => object id
        reference_object_id_dict = dict()
        for reference_resource_name, reference_fields_names_list in reference_resource_dict.items(
        ):
            reference_resource = self.datapackage.get_resource(
                reference_resource_name)
            reference_primary_key = reference_resource.schema.primary_key
            reference_object_id_dict[reference_resource_name] = d1 = dict()
            for reference_fields_names in reference_fields_names_list:
                d1[",".join(reference_fields_names)] = d2 = dict()
                for i, row in enumerate(
                        self.resource_data[reference_resource_name]):
                    row_dict = dict(
                        zip(reference_resource.schema.field_names, row))
                    # Find object id
                    if reference_primary_key:
                        reference_object_name_suffix = "_".join(
                            row_dict[field] for field in reference_primary_key)
                    else:
                        reference_object_name_suffix = str(i)
                    reference_object_name = reference_resource_name + reference_object_name_suffix
                    reference_object_id = object_name_id[reference_object_name]
                    key = ",".join(
                        [row_dict[x] for x in reference_fields_names])
                    d2[key] = (reference_object_id, reference_object_name)
        # Create list of relationships
        relationships = list()
        for resource in self.datapackage.resources:
            primary_key = resource.schema.primary_key
            foreign_keys = resource.schema.foreign_keys
            reference_resource_names = [
                fk['reference']['resource'] for fk in foreign_keys
            ]
            if not reference_resource_names:
                continue
            object_class_name_list = [resource.name] + reference_resource_names
            relationship_class_name = "__".join(object_class_name_list)
            relationship_class_id = relationship_class_name_id[
                relationship_class_name]
            for i, row in enumerate(self.resource_data[resource.name]):
                row_dict = dict(zip(resource.schema.field_names, row))
                if primary_key:
                    object_name_suffix = "_".join(row_dict[field]
                                                  for field in primary_key)
                else:
                    object_name_suffix = str(i)
                object_name = resource.name + object_name_suffix
                object_id = object_name_id[object_name]
                object_id_list = [object_id]
                object_name_list = [object_name]
                for fk in foreign_keys:
                    fields_names = fk['fields']
                    reference_resource_name = fk['reference']['resource']
                    reference_fields_names = fk['reference']['fields']
                    key = ",".join([row_dict[x] for x in fields_names])
                    d1 = reference_object_id_dict[reference_resource_name]
                    d2 = d1[",".join(reference_fields_names)]
                    try:
                        reference_object_id, reference_object_name = d2[key]
                    except KeyError:
                        break
                    object_id_list.append(reference_object_id)
                    object_name_list.append(reference_object_name)
                else:
                    relationship_name = relationship_class_name + "_" + "__".join(
                        object_name_list)
                    relationships.append(
                        dict(class_id=relationship_class_id,
                             object_id_list=object_id_list,
                             name=relationship_name))
        self.signaler.progressed.emit(step, "Adding relationships...")
        self.db_map.add_wide_relationships(*relationships)
        step += self.relationship_count
        self.db_map.commit_session("Automatically generated by Spine Toolbox.")
        self.db_map.close()
        self.signaler.progressed.emit(step, "")
    def setUp(self):
        """Overridden method. Runs before each test.
        """
        # temp file for excel export
        self.temp_excel_filename = str(uuid.uuid4()) + '.xlsx'

        # create a in memory database with objects, relationship, parameters and values
        input_db = create_new_spine_database('sqlite://')
        db_map = DiffDatabaseMapping("",
                                     username='******',
                                     create_all=False)
        db_map.engine = input_db
        db_map.engine.connect()
        db_map.session = Session(db_map.engine, autoflush=False)
        db_map.create_mapping()
        db_map.create_diff_tables_and_mapping()
        db_map.init_next_id()

        # create empty database for loading excel into
        input_db_test = create_new_spine_database('sqlite://')
        db_map_test = DiffDatabaseMapping("",
                                          username='******',
                                          create_all=False)
        db_map_test.engine = input_db_test
        db_map_test.engine.connect()
        db_map_test.session = Session(db_map_test.engine, autoflush=False)
        db_map_test.create_mapping()
        db_map_test.create_diff_tables_and_mapping()
        db_map_test.init_next_id()

        # delete all object_classes to empty database
        oc = set(oc.id for oc in db_map_test.object_class_list().all())
        if oc:
            db_map_test.remove_items(object_class_ids=oc)
        db_map_test.commit_session('empty database')

        oc = set(oc.id for oc in db_map.object_class_list().all())
        if oc:
            db_map.remove_items(object_class_ids=oc)
        db_map.commit_session('empty database')

        # create object classes
        oc_1 = db_map.add_object_class(**{'name': 'object_class_1'})
        oc_2 = db_map.add_object_class(**{'name': 'object_class_2'})

        # create relationship classes
        relc1 = db_map.add_wide_relationship_class(
            **{
                'name': 'relationship_class',
                'object_class_id_list': [oc_1.id, oc_2.id]
            })

        # create objects
        oc1_obj1 = db_map.add_object(**{
            'name': 'oc1_obj1',
            'class_id': oc_1.id
        })
        oc1_obj2 = db_map.add_object(**{
            'name': 'oc1_obj2',
            'class_id': oc_1.id
        })
        oc2_obj1 = db_map.add_object(**{
            'name': 'oc2_obj1',
            'class_id': oc_2.id
        })
        oc2_obj2 = db_map.add_object(**{
            'name': 'oc2_obj2',
            'class_id': oc_2.id
        })

        # add relationships
        rel1 = db_map.add_wide_relationship(
            **{
                'name': 'rel1',
                'class_id': relc1.id,
                'object_id_list': [oc1_obj1.id, oc2_obj1.id]
            })
        rel2 = db_map.add_wide_relationship(
            **{
                'name': 'rel2',
                'class_id': relc1.id,
                'object_id_list': [oc1_obj2.id, oc2_obj2.id]
            })

        # create parameters
        p1 = db_map.add_parameter(**{
            'name': 'parameter1',
            'object_class_id': oc_1.id
        })
        p2 = db_map.add_parameter(**{
            'name': 'parameter2',
            'object_class_id': oc_1.id
        })
        p3 = db_map.add_parameter(**{
            'name': 'parameter3',
            'object_class_id': oc_2.id
        })
        p4 = db_map.add_parameter(**{
            'name': 'parameter4',
            'object_class_id': oc_2.id
        })
        rel_p1 = db_map.add_parameter(**{
            'name': 'rel_parameter1',
            'relationship_class_id': relc1.id
        })
        rel_p2 = db_map.add_parameter(**{
            'name': 'rel_parameter2',
            'relationship_class_id': relc1.id
        })
        rel_p3 = db_map.add_parameter(**{
            'name': 'rel_parameter3',
            'relationship_class_id': relc1.id
        })
        rel_p4 = db_map.add_parameter(**{
            'name': 'rel_parameter4',
            'relationship_class_id': relc1.id
        })

        # add parameter values
        db_map.add_parameter_value(**{
            'parameter_id': p1.id,
            'object_id': oc1_obj1.id,
            'value': 0
        })
        db_map.add_parameter_value(**{
            'parameter_id': p2.id,
            'object_id': oc1_obj2.id,
            'value': 3.5
        })
        db_map.add_parameter_value(
            **{
                'parameter_id': p3.id,
                'object_id': oc2_obj1.id,
                'json': '[1, 2, 3, 4]'
            })
        db_map.add_parameter_value(**{
            'parameter_id': p4.id,
            'object_id': oc2_obj2.id,
            'json': '[5, 6, 7]'
        })
        db_map.add_parameter_value(**{
            'parameter_id': rel_p1.id,
            'relationship_id': rel1.id,
            'value': 0
        })
        db_map.add_parameter_value(**{
            'parameter_id': rel_p2.id,
            'relationship_id': rel2.id,
            'value': 4
        })
        db_map.add_parameter_value(
            **{
                'parameter_id': rel_p3.id,
                'relationship_id': rel1.id,
                'json': '[5, 6, 7]'
            })
        db_map.add_parameter_value(
            **{
                'parameter_id': rel_p4.id,
                'relationship_id': rel2.id,
                'json': '[1, 2, 3, 4]'
            })

        # commit
        db_map.commit_session('test')

        self.db_map = db_map
        self.empty_db_map = db_map_test