Fixed Crashes related to recent DB Changes

Fixed a few bugs/crashes that were caused by code still expecting tag name lists being returned by the DB API instead of the new dictionaries.

I should really automate tests or do something to catch these better in the future ...
dev
Peery 1 year ago
parent 1596faee7f
commit 24feb63e5e

@ -165,7 +165,7 @@ class ArtNetManager:
already_applied_tags = self.db_connection.get_art_tags_by_ID(art_ID) already_applied_tags = self.db_connection.get_art_tags_by_ID(art_ID)
for i in range(len(already_applied_tags)): # converting the list to List[str] for i in range(len(already_applied_tags)): # converting the list to List[str]
already_applied_tags[i] = self.db_connection.get_tag_by_ID(already_applied_tags[i])[0][1].strip() already_applied_tags[i] = self.db_connection.get_tag_by_ID(already_applied_tags[i])
importable_tags = [] importable_tags = []
importable_artists = [] importable_artists = []
@ -173,23 +173,29 @@ class ArtNetManager:
for i in tags.values(): for i in tags.values():
scraped_tags += i scraped_tags += i
for tag in scraped_tags: for tag_name in scraped_tags:
result = self.db_connection.get_tag_by_name(tag) result = self.db_connection.get_tag_by_name(tag_name)
if len(result) == 0: # tag does not exist yet if result is None: # tag does not exist yet
if tag in tags['artists']: if tag_name in tags['artists']:
importable_artists.append(tag) importable_artists.append(tag_name)
continue continue
importable_tags.append(tag) importable_tags.append(tag_name)
continue continue
if tag in already_applied_tags: # tag is already applied is_in_applied_tags = False
for t in already_applied_tags:
if t["name"] == tag_name:
is_in_applied_tags = True
if is_in_applied_tags: # tag is already applied
continue continue
result = self.db_connection.get_tag_impliers_by_name(tag) result = self.db_connection.get_tag_impliers_by_name(tag_name)
if len(result) != 0: # tag is implied by some other tag if len(result) != 0: # tag is implied by some other tag
skip = False skip = False
for implier_tag_id in result: for implier_tag_id in result:
implier_tag_id, implier_tag_name, _, _ = self.db_connection.get_tag_by_ID(implier_tag_id)[0] data = self.db_connection.get_tag_by_ID(implier_tag_id)
implier_tag_id = data["id"]
implier_tag_name = data["name"]
if implier_tag_name.strip() in scraped_tags: if implier_tag_name.strip() in scraped_tags:
skip = True skip = True
@ -197,14 +203,14 @@ class ArtNetManager:
if skip: # skipping the current tag as it is implied by another tag if skip: # skipping the current tag as it is implied by another tag
continue continue
result = self.db_connection.get_tag_aliases_by_name(tag) result = self.db_connection.get_tag_aliases_by_name(tag_name)
if len(result) != 0: # tag is already tagged by an alias if len(result) != 0: # tag is already tagged by an alias
continue continue
if tag in tags['artists']: if tag_name in tags['artists']:
importable_artists.append(tag) importable_artists.append(tag_name)
continue continue
importable_tags.append(tag) # tag must be known and not tagged yet importable_tags.append(tag_name) # tag must be known and not tagged yet
return importable_tags, importable_artists return importable_tags, importable_artists
@ -216,7 +222,7 @@ class ArtNetManager:
""" """
for tag in tags: for tag in tags:
if len(self.db_connection.get_tag_by_name(tag)) == 0: # tag doesn't exist yet if self.db_connection.get_tag_by_name(tag) is None: # tag doesn't exist yet
result = self.import_window.force_edit_tag_dialog(name=tag) result = self.import_window.force_edit_tag_dialog(name=tag)
if result is None: # tag creation was aborted if result is None: # tag creation was aborted
@ -224,8 +230,8 @@ class ArtNetManager:
tag = result['name'] # overwrite with possibly new tag name tag = result['name'] # overwrite with possibly new tag name
tag = self.db_connection.get_tag_by_name(tag)[0][0] tag_data = self.db_connection.get_tag_by_name(tag)
self.import_window.curr_tags.append(tag) self.import_window.curr_tags.append(tag_data)
self.import_window.data_changed = True self.import_window.data_changed = True
def get_md5_of_image(self, path: str): def get_md5_of_image(self, path: str):
@ -416,8 +422,7 @@ class ArtNetManager:
self.all_images[self.curr_image_index], self.all_images[self.curr_image_index],
art_ID, image_link, file_name=s[-1], description=image_description, art_ID, image_link, file_name=s[-1], description=image_description,
collections=collections) collections=collections)
tmp = [self.db_connection.get_tag_by_ID(x) for x in self.db_connection.get_art_tags_by_ID(art_ID)] tags = [self.db_connection.get_tag_by_ID(x) for x in self.db_connection.get_art_tags_by_ID(art_ID)]
tags = [{"id": int(t[0][0]), "name": t[0][1].strip(), "description": t[0][2].strip(), "category": t[0][3]} for t in tmp]
self.curr_active_window.set_tag_list(tags) self.curr_active_window.set_tag_list(tags)
self.curr_active_window.data_changed = False self.curr_active_window.data_changed = False

@ -73,7 +73,7 @@ class DBAdapter:
:return: :return:
""" """
logging.debug("Saving Image {0}:{1} authors: {2} path: {3} tags: {4} link: {5} hash:{6} desc:{7}" logging.debug("Saving Image {0}:{1} authors: {2} path: {3} tags: {4} link: {5} hash:{6} desc:{7}"
.format(ID, title, authors, path, tags, link, md5_hash, desc)) .format(ID, title, authors, path, [t["name"] for t in tags], link, md5_hash, desc))
d = {"title": title, "path": path, "id": ID, "link": link, "hash": md5_hash, "desc": desc} # TODO implement try/except for database errors and rollback! d = {"title": title, "path": path, "id": ID, "link": link, "hash": md5_hash, "desc": desc} # TODO implement try/except for database errors and rollback!
if self.get_art_by_path(path) is None: if self.get_art_by_path(path) is None:
if ID is None: if ID is None:
@ -98,11 +98,11 @@ class DBAdapter:
ID = self.get_art_by_path(path)["ID"] ID = self.get_art_by_path(path)["ID"]
assert (ID != None) # was checked before, should never fail assert (ID != None) # was checked before, should never fail
old_tags = [self.get_tag_by_ID(x)[0][1].strip() for x in self.get_art_tags_by_ID(ID)] old_tags = [self.get_tag_by_ID(x)["name"].strip() for x in self.get_art_tags_by_ID(ID)]
for tag in tags: for tag in tags:
if tag in old_tags: # already present if tag in old_tags: # already present
continue continue
d = {"id": ID, "tag": self.get_tag_ID(tag)} d = {"id": ID, "tag": tag["id"]}
try: try:
self.db_cursor.execute("INSERT INTO art_to_tag (art_id, tag_ID) VALUES (%(id)s, %(tag)s)", d) self.db_cursor.execute("INSERT INTO art_to_tag (art_id, tag_ID) VALUES (%(id)s, %(tag)s)", d)
self.db.commit() self.db.commit()
@ -115,7 +115,11 @@ class DBAdapter:
raise e raise e
for old_tag in old_tags: for old_tag in old_tags:
if old_tag not in tags: # need to remove old tag is_in_tags = False
for t in tags:
if t["name"] == old_tag:
is_in_tags = True
if not is_in_tags: # need to remove old tag
self.remove_tag_from_image(art_ID=ID, tag_ID=self.get_tag_ID(old_tag)) self.remove_tag_from_image(art_ID=ID, tag_ID=self.get_tag_ID(old_tag))
old_authors = self.get_authors_of_art_by_ID(ID) old_authors = self.get_authors_of_art_by_ID(ID)
@ -831,7 +835,7 @@ class DBAdapter:
return rows[0] return rows[0]
def get_tag_by_name(self, name: str) -> list: def get_tag_by_name(self, name: str) -> dict:
""" """
Search the tag in the DB via its name. Search the tag in the DB via its name.
@ -843,20 +847,21 @@ class DBAdapter:
self.db_cursor.execute( self.db_cursor.execute(
"SELECT name, description, category_id, ID FROM tag where LOWER(name) = LOWER(%(name)s)", d) "SELECT name, description, category_id, ID FROM tag where LOWER(name) = LOWER(%(name)s)", d)
rows = [] new_row = []
for row in self.db_cursor.fetchall(): row = self.db_cursor.fetchall()
new_row = [] if len(row) == 0:
for value in row: return None
if value is None: row = row[0]
new_row.append("") for value in row:
elif type(value) == str: if value is None:
new_row.append(value.strip()) new_row.append("")
else: elif type(value) == str:
new_row.append(value) new_row.append(value.strip())
rows.append(new_row) else:
return rows new_row.append(value)
return {"name": new_row[0], "description": new_row[1], "category": new_row[2], "id": new_row[3]}
def get_tag_by_ID(self, ID: int) -> list: def get_tag_by_ID(self, ID: int) -> dict:
""" """
Search the tag in the DB via its ID. Search the tag in the DB via its ID.
@ -867,9 +872,21 @@ class DBAdapter:
d = {"ID": ID} d = {"ID": ID}
self.db_cursor.execute("SELECT ID, name, description, category_id FROM tag where ID = %(ID)s", d) self.db_cursor.execute("SELECT ID, name, description, category_id FROM tag where ID = %(ID)s", d)
return self.db_cursor.fetchall() new_row = []
rows = self.db_cursor.fetchall()
if len(rows) != 1:
raise Exception("Something went terribly wrong!")
row = rows[0]
for value in row:
if value is None:
new_row.append("")
elif type(value) == str:
new_row.append(value.strip())
else:
new_row.append(value)
return {"name": new_row[1], "description": new_row[2], "category": new_row[3], "id": new_row[0]}
def get_tag_aliases_by_name(self, name: str) -> list: def get_tag_aliases_by_name(self, name: str) -> List[dict]:
""" """
Search for the tag's aliases and the alias's aliases Search for the tag's aliases and the alias's aliases
:param name: :param name:
@ -880,7 +897,7 @@ class DBAdapter:
for alias in aliases: for alias in aliases:
tag_data = self.get_tag_by_ID(alias) tag_data = self.get_tag_by_ID(alias)
if len(tag_data) > 0: # tag exists if len(tag_data) > 0: # tag exists
result.append(tag_data[0][1].strip()) result.append(tag_data)
return result return result
def get_tag_aliases_by_ID(self, tag_ID: int) -> list: def get_tag_aliases_by_ID(self, tag_ID: int) -> list:
@ -931,8 +948,7 @@ class DBAdapter:
for tag_ID in collected_tags: for tag_ID in collected_tags:
tag_data = self.get_tag_by_ID(tag_ID) tag_data = self.get_tag_by_ID(tag_ID)
if len(tag_data) != 0: if len(tag_data) != 0:
result.append({"name": tag_data[0][1].strip(), "id": int(tag_data[0][0]), result.append(tag_data)
"description": tag_data[0][2].strip(), "category": int(tag_data[0][3])})
return result return result
def get_all_tag_impliers_by_ID(self, ID: int) -> list: def get_all_tag_impliers_by_ID(self, ID: int) -> list:

@ -1,7 +1,10 @@
from typing import List
import validators import validators
import os import os
import logging import logging
import re import re
import json
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt, QSize, QUrl from PyQt5.QtCore import Qt, QSize, QUrl
@ -493,7 +496,7 @@ class ImporterWindow(ArtnetMainWindow):
""" """
return self.main.db_connection.search_fuzzy_tag(name, all_if_empty=True) return self.main.db_connection.search_fuzzy_tag(name, all_if_empty=True)
def set_tag_search_result_list(self, tags: list): def set_tag_search_result_list(self, tags: List[dict]):
""" """
Set the tags in the search result list to tags Set the tags in the search result list to tags
:param tags: :param tags:
@ -510,9 +513,21 @@ class ImporterWindow(ArtnetMainWindow):
if tag_name not in self.curr_implied_tags: if tag_name not in self.curr_implied_tags:
# new tag and not implied yet # new tag and not implied yet
item.setData(Qt.Unchecked, Qt.CheckStateRole) item.setData(Qt.Unchecked, Qt.CheckStateRole)
item.setToolTip(f"Tag ID: {tag['id']}\n\n"+tag["description"]+f"\nCategory: {tag['category']}") if 'id' in tag.keys() and 'description' in tag.keys() and 'category' in tag.keys():
s = f"Tag ID: {tag['id']}\n\n"
if len(tag["description"]) != 0:
s += tag["description"]+"\n\n"
s += f"Category: {tag['category']}"
item.setToolTip(s)
item.setData(json.dumps(tag), Qt.UserRole)
flags |= Qt.ItemIsUserCheckable flags |= Qt.ItemIsUserCheckable
if self.curr_tags is not None and tag_name in (self.curr_tags + self.curr_implied_tags + self.curr_tag_aliases):
is_in_tags = False
for i in range(len((self.curr_tags + self.curr_implied_tags + self.curr_tag_aliases))):
if item.text() == (self.curr_tags + self.curr_implied_tags + self.curr_tag_aliases)[i]["name"]:
is_in_tags = True
if self.curr_tags is not None and is_in_tags:
# already selected, implied or aliased tags # already selected, implied or aliased tags
item.setCheckState(Qt.Checked) item.setCheckState(Qt.Checked)
item.setFlags(flags) item.setFlags(flags)
@ -555,7 +570,12 @@ class ImporterWindow(ArtnetMainWindow):
if tag_name not in self.curr_implied_tags: if tag_name not in self.curr_implied_tags:
# new tag and not implied yet # new tag and not implied yet
item.setData(Qt.Unchecked, Qt.CheckStateRole) item.setData(Qt.Unchecked, Qt.CheckStateRole)
item.setToolTip(f"Tag ID: {tag['id']}\n\n" + tag["description"] + f"\nCategory: {tag['category']}") if 'id' in tag.keys() and 'description' in tag.keys() and 'category' in tag.keys():
s = f"Tag ID: {tag['id']}\n\n"
if len(tag["description"]) != 0:
s += tag["description"] + "\n\n"
s += f"Category: {tag['category']}"
item.setToolTip(s)
flags |= Qt.ItemIsUserCheckable flags |= Qt.ItemIsUserCheckable
if set_checked: if set_checked:
@ -588,7 +608,12 @@ class ImporterWindow(ArtnetMainWindow):
else: else:
done.append(tag_name) done.append(tag_name)
item = QStandardItem(tag_name) item = QStandardItem(tag_name)
item.setToolTip(f"Tag ID: {tag['id']}\n\n"+tag["description"]+f"\nCategory: {tag['category']}") if 'id' in tag.keys() and 'description' in tag.keys() and 'category' in tag.keys():
s = f"Tag ID: {tag['id']}\n\n"
if len(tag["description"]) != 0:
s += tag["description"] + "\n\n"
s += f"Category: {tag['category']}"
item.setToolTip(s)
item_model.appendRow(item) item_model.appendRow(item)
self.ui.implied_tag_list.setModel(item_model) self.ui.implied_tag_list.setModel(item_model)
@ -764,15 +789,15 @@ class ImporterWindow(ArtnetMainWindow):
if self.ui.search_result_list.model().rowCount() == 1: # only 1 search result left if self.ui.search_result_list.model().rowCount() == 1: # only 1 search result left
model_index = self.ui.search_result_list.model().index(0, 0) model_index = self.ui.search_result_list.model().index(0, 0)
item_data = self.ui.search_result_list.model().itemData(model_index) item_data = json.loads(self.ui.search_result_list.model().itemData(model_index)[Qt.UserRole])
if item_data[0] not in self.curr_tags: # add/remove new selected tag to the lists if item_data not in self.curr_tags: # add/remove new selected tag to the lists
self.curr_tags.append(item_data[0]) self.curr_tags.append(item_data)
else: else:
self.curr_tags.remove(item_data[0]) self.curr_tags.remove(item_data)
self.set_tag_list(self.curr_tags) # update relevant lists self.set_tag_list(self.curr_tags) # update relevant lists
self.set_tag_search_result_list([item_data[0]]) self.set_tag_search_result_list([item_data])
logging.debug(item_data) logging.debug(item_data)
def on_movie_player_state_changed(self, state: int): def on_movie_player_state_changed(self, state: int):
@ -823,8 +848,8 @@ class ImporterWindow(ArtnetMainWindow):
i = 0 i = 0
while i < len(tags): # workaround for an issue with altering lists during iteration while i < len(tags): # workaround for an issue with altering lists during iteration
r = self.main.db_connection.get_tag_by_name(tags[i]) r = self.main.db_connection.get_tag_by_name(tags[i])
if len(r) > 0: if r is not None:
self.curr_tags.append(tags[i]) self.curr_tags.append(r)
self.data_changed = True self.data_changed = True
tags.remove(tags[i]) tags.remove(tags[i])
continue continue
@ -995,9 +1020,10 @@ class ImporterWindow(ArtnetMainWindow):
"No tag is allowed without a category!") "No tag is allowed without a category!")
return None return None
if len(self.get_tag(tag_data['name'])) > 0: if self.get_tag(tag_data['name']) is not None:
QtWidgets.QMessageBox.information(self, "Tag already exists", QtWidgets.QMessageBox.information(self, "Tag already exists",
"The Tag \"{0}\" you wanted to create already exists! Skipping...") f"The Tag \"{tag_data['name']}\" you wanted to create already exists! Skipping...")
return None
else: else:
self.main.db_connection.create_tag(name=tag_data["name"], description=tag_data["description"], self.main.db_connection.create_tag(name=tag_data["name"], description=tag_data["description"],
aliases=tag_data["aliases"], implications=tag_data["implications"], aliases=tag_data["aliases"], implications=tag_data["implications"],
@ -1043,7 +1069,8 @@ class ImporterWindow(ArtnetMainWindow):
def on_tag_search_item_changed(self, item: QStandardItem): def on_tag_search_item_changed(self, item: QStandardItem):
if item.checkState() == Qt.Checked: if item.checkState() == Qt.Checked:
self.curr_tags.append(item.text()) tag_data = self.main.db_connection.get_tag_by_name(item.text())
self.curr_tags.append(tag_data)
aliases = self.main.db_connection.get_tag_aliases_by_name(item.text()) aliases = self.main.db_connection.get_tag_aliases_by_name(item.text())
for alias in aliases: for alias in aliases:
@ -1052,15 +1079,20 @@ class ImporterWindow(ArtnetMainWindow):
for implication in implications: for implication in implications:
self.curr_tags.append(implication) self.curr_tags.append(implication)
if item.checkState() == Qt.Unchecked: if item.checkState() == Qt.Unchecked:
if item.text() in self.curr_tags: is_in_tags = False
self.curr_tags.remove(item.text()) for i in range(len(self.curr_tags)):
if item.text() == self.curr_tags[i]["name"]:
tags_index = i
is_in_tags = True
if is_in_tags:
self.curr_tags.pop(tags_index)
aliases = self.main.db_connection.get_tag_aliases_by_name(item.text()) aliases = self.main.db_connection.get_tag_aliases_by_name(item.text())
for alias in aliases: for alias in aliases:
if alias in self.curr_tags: if alias in self.curr_tags:
self.curr_tags.remove(alias) self.curr_tags.remove(alias)
implications = self.main.db_connection.get_all_tag_implications_by_name(item.text()) implications = self.main.db_connection.get_all_tag_implications_by_name(item.text())
for implication in implications: for implication in implications:
self.curr_tags.remove(implication) self.curr_tags.remove({"name": implication})
else: else:
raise Exception("Something went terribly wrong!") raise Exception("Something went terribly wrong!")
@ -1070,13 +1102,22 @@ class ImporterWindow(ArtnetMainWindow):
def on_tag_item_changed(self, item: QStandardItem): def on_tag_item_changed(self, item: QStandardItem):
logging.debug("Item {0} has changed!".format(item.text())) logging.debug("Item {0} has changed!".format(item.text()))
if item.checkState() == Qt.Unchecked: if item.checkState() == Qt.Unchecked:
if item.text() in self.curr_tags: is_in_tags = False
for i in range(len(self.curr_tags)):
if item.text() == self.curr_tags[i]["name"]:
tags_index = i
is_in_tags = True
if is_in_tags:
aliases = self.main.db_connection.get_tag_aliases_by_name(item.text()) aliases = self.main.db_connection.get_tag_aliases_by_name(item.text())
if len(aliases) > 0: # tag has aliases, might need to also remove them if len(aliases) > 0: # tag has aliases, might need to also remove them
for alias in aliases: for alias in aliases:
self.curr_tags.remove(alias) self.curr_tags.remove(alias)
self.curr_tags.remove(item.text()) for i in range(len(self.curr_tags)):
if item.text() == self.curr_tags[i]["name"]:
tags_index = i
self.curr_tags.pop(tags_index)
self.set_tag_list(self.curr_tags) self.set_tag_list(self.curr_tags)
self.on_tag_search_change() self.on_tag_search_change()
else: else:

Loading…
Cancel
Save