From fb7c73d96b09a5bf1240f547a3c4863284bd0f85 Mon Sep 17 00:00:00 2001 From: Hidorikun Date: Mon, 6 May 2024 12:06:30 +0300 Subject: [PATCH 1/4] Add pytest support --- README.md | 7 +- requirements-dev.txt | 1 + tagstudio/src/core/constants.py | 137 ++++++++++++++++++++ tagstudio/src/core/library.py | 36 +++--- tagstudio/src/core/ts_core.py | 138 --------------------- tagstudio/src/qt/modals/build_tag.py | 2 +- tagstudio/src/qt/ts_qt.py | 4 +- tagstudio/src/qt/widgets/collage_icon.py | 2 +- tagstudio/src/qt/widgets/item_thumb.py | 2 +- tagstudio/src/qt/widgets/preview_panel.py | 2 +- tagstudio/src/qt/widgets/thumb_renderer.py | 2 +- tagstudio/tests/core/test_tags.py | 27 ++-- 12 files changed, 182 insertions(+), 178 deletions(-) create mode 100644 tagstudio/src/core/constants.py diff --git a/README.md b/README.md index d9d223bd..3c5e39bb 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,12 @@ TagStudio is a photo & file organization application with an underlying system t - Linux/macOS: `source .venv/bin/activate` 3. Install the required packages: - `pip install -r requirements.txt` + +- required to run the app: `pip install -r requirements.txt` +- required to develop: `pip install -r requirements-dev.txt` + + +To run all the tests use `python -m pytest tests/` from the `tagstudio` folder. _Learn more about setting up a virtual environment [here](https://docs.python.org/3/tutorial/venv.html)._ diff --git a/requirements-dev.txt b/requirements-dev.txt index 4745ae0c..6f21acd3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,3 @@ ruff==0.4.2 pre-commit==3.7.0 +pytest==8.2.0 \ No newline at end of file diff --git a/tagstudio/src/core/constants.py b/tagstudio/src/core/constants.py new file mode 100644 index 00000000..4198e51a --- /dev/null +++ b/tagstudio/src/core/constants.py @@ -0,0 +1,137 @@ + +VERSION: str = "9.2.0" # Major.Minor.Patch +VERSION_BRANCH: str = "Alpha" # 'Alpha', 'Beta', or '' for Full Release + +# The folder & file names where TagStudio keeps its data relative to a library. +TS_FOLDER_NAME: str = ".TagStudio" +BACKUP_FOLDER_NAME: str = "backups" +COLLAGE_FOLDER_NAME: str = "collages" +LIBRARY_FILENAME: str = "ts_library.json" + +# TODO: Turn this whitelist into a user-configurable blacklist. +IMAGE_TYPES: list[str] = [ + "png", + "jpg", + "jpeg", + "jpg_large", + "jpeg_large", + "jfif", + "gif", + "tif", + "tiff", + "heic", + "heif", + "webp", + "bmp", + "svg", + "avif", + "apng", + "jp2", + "j2k", + "jpg2", +] +VIDEO_TYPES: list[str] = [ + "mp4", + "webm", + "mov", + "hevc", + "mkv", + "avi", + "wmv", + "flv", + "gifv", + "m4p", + "m4v", + "3gp", +] +AUDIO_TYPES: list[str] = [ + "mp3", + "mp4", + "mpeg4", + "m4a", + "aac", + "wav", + "flac", + "alac", + "wma", + "ogg", + "aiff", +] +DOC_TYPES: list[str] = ["txt", "rtf", "md", "doc", "docx", "pdf", "tex", "odt", "pages"] +PLAINTEXT_TYPES: list[str] = [ + "txt", + "md", + "css", + "html", + "xml", + "json", + "js", + "ts", + "ini", + "htm", + "csv", + "php", + "sh", + "bat", +] +SPREADSHEET_TYPES: list[str] = ["csv", "xls", "xlsx", "numbers", "ods"] +PRESENTATION_TYPES: list[str] = ["ppt", "pptx", "key", "odp"] +ARCHIVE_TYPES: list[str] = ["zip", "rar", "tar", "tar.gz", "tgz", "7z"] +PROGRAM_TYPES: list[str] = ["exe", "app"] +SHORTCUT_TYPES: list[str] = ["lnk", "desktop", "url"] + +ALL_FILE_TYPES: list[str] = ( + IMAGE_TYPES + + VIDEO_TYPES + + AUDIO_TYPES + + DOC_TYPES + + SPREADSHEET_TYPES + + PRESENTATION_TYPES + + ARCHIVE_TYPES + + PROGRAM_TYPES + + SHORTCUT_TYPES +) + +BOX_FIELDS = ["tag_box", "text_box"] +TEXT_FIELDS = ["text_line", "text_box"] +DATE_FIELDS = ["datetime"] + +TAG_COLORS = [ + "", + "black", + "dark gray", + "gray", + "light gray", + "white", + "light pink", + "pink", + "red", + "red orange", + "orange", + "yellow orange", + "yellow", + "lime", + "light green", + "mint", + "green", + "teal", + "cyan", + "light blue", + "blue", + "blue violet", + "violet", + "purple", + "lavender", + "berry", + "magenta", + "salmon", + "auburn", + "dark brown", + "brown", + "light brown", + "blonde", + "peach", + "warm gray", + "cool gray", + "olive", +] \ No newline at end of file diff --git a/tagstudio/src/core/library.py b/tagstudio/src/core/library.py index a57fc362..6d4ca7d3 100644 --- a/tagstudio/src/core/library.py +++ b/tagstudio/src/core/library.py @@ -17,9 +17,9 @@ import ujson from src.core.json_typing import JsonCollation, JsonEntry, JsonLibary, JsonTag -from src.core import ts_core from src.core.utils.str import strip_punctuation from src.core.utils.web import strip_web_protocol +from src.core.constants import BACKUP_FOLDER_NAME, COLLAGE_FOLDER_NAME, TEXT_FIELDS, TS_FOLDER_NAME, VERSION TYPE = ["file", "meta", "alt", "mask"] @@ -438,8 +438,8 @@ def create_library(self, path) -> int: path = os.path.normpath(path).rstrip("\\") # If '.TagStudio' is included in the path, trim the path up to it. - if ts_core.TS_FOLDER_NAME in path: - path = path.split(ts_core.TS_FOLDER_NAME)[0] + if TS_FOLDER_NAME in path: + path = path.split(TS_FOLDER_NAME)[0] try: self.clear_internal_vars() @@ -456,12 +456,12 @@ def create_library(self, path) -> int: def verify_ts_folders(self) -> None: """Verifies/creates folders required by TagStudio.""" - full_ts_path = os.path.normpath(f"{self.library_dir}/{ts_core.TS_FOLDER_NAME}") + full_ts_path = os.path.normpath(f"{self.library_dir}/{TS_FOLDER_NAME}") full_backup_path = os.path.normpath( - f"{self.library_dir}/{ts_core.TS_FOLDER_NAME}/{ts_core.BACKUP_FOLDER_NAME}" + f"{self.library_dir}/{TS_FOLDER_NAME}/{BACKUP_FOLDER_NAME}" ) full_collage_path = os.path.normpath( - f"{self.library_dir}/{ts_core.TS_FOLDER_NAME}/{ts_core.COLLAGE_FOLDER_NAME}" + f"{self.library_dir}/{TS_FOLDER_NAME}/{COLLAGE_FOLDER_NAME}" ) if not os.path.isdir(full_ts_path): @@ -499,16 +499,16 @@ def open_library(self, path: str) -> int: path = os.path.normpath(path).rstrip("\\") # If '.TagStudio' is included in the path, trim the path up to it. - if ts_core.TS_FOLDER_NAME in path: - path = path.split(ts_core.TS_FOLDER_NAME)[0] + if TS_FOLDER_NAME in path: + path = path.split(TS_FOLDER_NAME)[0] if os.path.exists( - os.path.normpath(f"{path}/{ts_core.TS_FOLDER_NAME}/ts_library.json") + os.path.normpath(f"{path}/{TS_FOLDER_NAME}/ts_library.json") ): try: with open( os.path.normpath( - f"{path}/{ts_core.TS_FOLDER_NAME}/ts_library.json" + f"{path}/{TS_FOLDER_NAME}/ts_library.json" ), "r", encoding="utf-8", @@ -718,10 +718,10 @@ def open_library(self, path: str) -> int: # If the Library is loaded, continue other processes. if return_code == 1: if not os.path.exists( - os.path.normpath(f"{self.library_dir}/{ts_core.TS_FOLDER_NAME}") + os.path.normpath(f"{self.library_dir}/{TS_FOLDER_NAME}") ): os.makedirs( - os.path.normpath(f"{self.library_dir}/{ts_core.TS_FOLDER_NAME}") + os.path.normpath(f"{self.library_dir}/{TS_FOLDER_NAME}") ) self._map_filenames_to_entry_ids() @@ -769,7 +769,7 @@ def to_json(self): """ file_to_save: JsonLibary = { - "ts-version": ts_core.VERSION, + "ts-version": VERSION, "ignored_extensions": [], "tags": [], "collations": [], @@ -807,7 +807,7 @@ def save_library_to_disk(self): self.verify_ts_folders() with open( - os.path.normpath(f"{self.library_dir}/{ts_core.TS_FOLDER_NAME}/{filename}"), + os.path.normpath(f"{self.library_dir}/{TS_FOLDER_NAME}/{filename}"), "w", encoding="utf-8", ) as outfile: @@ -836,7 +836,7 @@ def save_library_backup_to_disk(self) -> str: self.verify_ts_folders() with open( os.path.normpath( - f"{self.library_dir}/{ts_core.TS_FOLDER_NAME}/{ts_core.BACKUP_FOLDER_NAME}/{filename}" + f"{self.library_dir}/{TS_FOLDER_NAME}/{BACKUP_FOLDER_NAME}/{filename}" ), "w", encoding="utf-8", @@ -893,13 +893,13 @@ def refresh_dir(self): # Scans the directory for files, keeping track of: # - Total file count # - Files without library entries - # for type in ts_core.TYPES: + # for type in TYPES: start_time = time.time() for f in glob.glob(self.library_dir + "/**/*", recursive=True): # p = Path(os.path.normpath(f)) if ( "$RECYCLE.BIN" not in f - and ts_core.TS_FOLDER_NAME not in f + and TS_FOLDER_NAME not in f and "tagstudio_thumbs" not in f and not os.path.isdir(f) ): @@ -2113,7 +2113,7 @@ def add_field_to_entry(self, entry_id: int, field_id: int) -> None: # entry = self.entries[entry_index] entry = self.get_entry(entry_id) field_type = self.get_field_obj(field_id)["type"] - if field_type in ts_core.TEXT_FIELDS: + if field_type in TEXT_FIELDS: entry.fields.append({int(field_id): ""}) elif field_type == "tag_box": entry.fields.append({int(field_id): []}) diff --git a/tagstudio/src/core/ts_core.py b/tagstudio/src/core/ts_core.py index abbfdda8..6edab037 100644 --- a/tagstudio/src/core/ts_core.py +++ b/tagstudio/src/core/ts_core.py @@ -9,144 +9,6 @@ from src.core.library import Entry, Library -VERSION: str = "9.2.0" # Major.Minor.Patch -VERSION_BRANCH: str = "Alpha" # 'Alpha', 'Beta', or '' for Full Release - -# The folder & file names where TagStudio keeps its data relative to a library. -TS_FOLDER_NAME: str = ".TagStudio" -BACKUP_FOLDER_NAME: str = "backups" -COLLAGE_FOLDER_NAME: str = "collages" -LIBRARY_FILENAME: str = "ts_library.json" - -# TODO: Turn this whitelist into a user-configurable blacklist. -IMAGE_TYPES: list[str] = [ - "png", - "jpg", - "jpeg", - "jpg_large", - "jpeg_large", - "jfif", - "gif", - "tif", - "tiff", - "heic", - "heif", - "webp", - "bmp", - "svg", - "avif", - "apng", - "jp2", - "j2k", - "jpg2", -] -VIDEO_TYPES: list[str] = [ - "mp4", - "webm", - "mov", - "hevc", - "mkv", - "avi", - "wmv", - "flv", - "gifv", - "m4p", - "m4v", - "3gp", -] -AUDIO_TYPES: list[str] = [ - "mp3", - "mp4", - "mpeg4", - "m4a", - "aac", - "wav", - "flac", - "alac", - "wma", - "ogg", - "aiff", -] -DOC_TYPES: list[str] = ["txt", "rtf", "md", "doc", "docx", "pdf", "tex", "odt", "pages"] -PLAINTEXT_TYPES: list[str] = [ - "txt", - "md", - "css", - "html", - "xml", - "json", - "js", - "ts", - "ini", - "htm", - "csv", - "php", - "sh", - "bat", -] -SPREADSHEET_TYPES: list[str] = ["csv", "xls", "xlsx", "numbers", "ods"] -PRESENTATION_TYPES: list[str] = ["ppt", "pptx", "key", "odp"] -ARCHIVE_TYPES: list[str] = ["zip", "rar", "tar", "tar.gz", "tgz", "7z"] -PROGRAM_TYPES: list[str] = ["exe", "app"] -SHORTCUT_TYPES: list[str] = ["lnk", "desktop", "url"] - -ALL_FILE_TYPES: list[str] = ( - IMAGE_TYPES - + VIDEO_TYPES - + AUDIO_TYPES - + DOC_TYPES - + SPREADSHEET_TYPES - + PRESENTATION_TYPES - + ARCHIVE_TYPES - + PROGRAM_TYPES - + SHORTCUT_TYPES -) - -BOX_FIELDS = ["tag_box", "text_box"] -TEXT_FIELDS = ["text_line", "text_box"] -DATE_FIELDS = ["datetime"] - -TAG_COLORS = [ - "", - "black", - "dark gray", - "gray", - "light gray", - "white", - "light pink", - "pink", - "red", - "red orange", - "orange", - "yellow orange", - "yellow", - "lime", - "light green", - "mint", - "green", - "teal", - "cyan", - "light blue", - "blue", - "blue violet", - "violet", - "purple", - "lavender", - "berry", - "magenta", - "salmon", - "auburn", - "dark brown", - "brown", - "light brown", - "blonde", - "peach", - "warm gray", - "cool gray", - "olive", -] - - class TagStudioCore: """ Instantiate this to establish a TagStudio session. diff --git a/tagstudio/src/qt/modals/build_tag.py b/tagstudio/src/qt/modals/build_tag.py index 579ffe1c..f4abdb4a 100644 --- a/tagstudio/src/qt/modals/build_tag.py +++ b/tagstudio/src/qt/modals/build_tag.py @@ -20,7 +20,7 @@ from src.core.library import Library, Tag from src.core.palette import ColorType, get_tag_color -from src.core.ts_core import TAG_COLORS +from src.core.constants import TAG_COLORS from src.qt.widgets import PanelWidget, PanelModal, TagWidget from src.qt.modals import TagSearchPanel diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index eabafdb5..114651df 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -45,9 +45,9 @@ from humanfriendly import format_timespan from src.core.library import ItemType -from src.core.ts_core import ( +from src.core.ts_core import TagStudioCore +from src.core.constants import ( PLAINTEXT_TYPES, - TagStudioCore, TAG_COLORS, DATE_FIELDS, TEXT_FIELDS, diff --git a/tagstudio/src/qt/widgets/collage_icon.py b/tagstudio/src/qt/widgets/collage_icon.py index 0b1bb01c..d8cb133b 100644 --- a/tagstudio/src/qt/widgets/collage_icon.py +++ b/tagstudio/src/qt/widgets/collage_icon.py @@ -23,7 +23,7 @@ ) from src.core.library import Library -from src.core.ts_core import DOC_TYPES, VIDEO_TYPES, IMAGE_TYPES +from src.core.constants import DOC_TYPES, VIDEO_TYPES, IMAGE_TYPES ERROR = f"[ERROR]" diff --git a/tagstudio/src/qt/widgets/item_thumb.py b/tagstudio/src/qt/widgets/item_thumb.py index 1c5f4057..dc4a4770 100644 --- a/tagstudio/src/qt/widgets/item_thumb.py +++ b/tagstudio/src/qt/widgets/item_thumb.py @@ -24,7 +24,7 @@ ) from src.core.library import ItemType, Library -from src.core.ts_core import AUDIO_TYPES, VIDEO_TYPES, IMAGE_TYPES +from src.core.constants import AUDIO_TYPES, VIDEO_TYPES, IMAGE_TYPES from src.qt.flowlayout import FlowWidget from src.qt.helpers import FileOpenerHelper from src.qt.widgets import ThumbRenderer, ThumbButton diff --git a/tagstudio/src/qt/widgets/preview_panel.py b/tagstudio/src/qt/widgets/preview_panel.py index 5ede8bd4..d1e7c17c 100644 --- a/tagstudio/src/qt/widgets/preview_panel.py +++ b/tagstudio/src/qt/widgets/preview_panel.py @@ -28,7 +28,7 @@ from humanfriendly import format_size from src.core.library import Entry, ItemType, Library -from src.core.ts_core import VIDEO_TYPES, IMAGE_TYPES +from src.core.constants import VIDEO_TYPES, IMAGE_TYPES from src.qt.helpers import FileOpenerLabel, FileOpenerHelper, open_file from src.qt.modals import AddFieldModal from src.qt.widgets import ( diff --git a/tagstudio/src/qt/widgets/thumb_renderer.py b/tagstudio/src/qt/widgets/thumb_renderer.py index 37630324..8d45ee40 100644 --- a/tagstudio/src/qt/widgets/thumb_renderer.py +++ b/tagstudio/src/qt/widgets/thumb_renderer.py @@ -22,7 +22,7 @@ ) from PySide6.QtCore import QObject, Signal, QSize from PySide6.QtGui import QPixmap -from src.core.ts_core import PLAINTEXT_TYPES, VIDEO_TYPES, IMAGE_TYPES +from src.core.constants import PLAINTEXT_TYPES, VIDEO_TYPES, IMAGE_TYPES ERROR = f"[ERROR]" diff --git a/tagstudio/tests/core/test_tags.py b/tagstudio/tests/core/test_tags.py index f3cd5791..6a82215c 100644 --- a/tagstudio/tests/core/test_tags.py +++ b/tagstudio/tests/core/test_tags.py @@ -1,18 +1,17 @@ from src.core.library import Tag -class TestTags: - def test_construction(self): - tag = Tag( - id=1, - name="Tag Name", - shorthand="TN", - aliases=["First A", "Second A"], - subtags_ids=[2, 3, 4], - color="", - ) - assert tag +def test_construction(): + tag = Tag( + id=1, + name="Tag Name", + shorthand="TN", + aliases=["First A", "Second A"], + subtags_ids=[2, 3, 4], + color="", + ) + assert tag - def test_empty_construction(self): - tag = Tag(id=1, name="", shorthand="", aliases=[], subtags_ids=[], color="") - assert tag +def test_empty_construction(): + tag = Tag(id=1, name="", shorthand="", aliases=[], subtags_ids=[], color="") + assert tag From b6848bb81f6483b9c3707f49ce5b28c80befdbb2 Mon Sep 17 00:00:00 2001 From: Hidorikun Date: Wed, 8 May 2024 17:32:15 +0300 Subject: [PATCH 2/4] Ruff format --- tagstudio/src/core/constants.py | 3 +-- tagstudio/src/core/library.py | 20 ++++++++++---------- tagstudio/src/core/ts_core.py | 1 + tagstudio/tests/core/test_tags.py | 1 + 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/tagstudio/src/core/constants.py b/tagstudio/src/core/constants.py index 4198e51a..b4ff6dde 100644 --- a/tagstudio/src/core/constants.py +++ b/tagstudio/src/core/constants.py @@ -1,4 +1,3 @@ - VERSION: str = "9.2.0" # Major.Minor.Patch VERSION_BRANCH: str = "Alpha" # 'Alpha', 'Beta', or '' for Full Release @@ -134,4 +133,4 @@ "warm gray", "cool gray", "olive", -] \ No newline at end of file +] diff --git a/tagstudio/src/core/library.py b/tagstudio/src/core/library.py index 6d4ca7d3..c24e61c7 100644 --- a/tagstudio/src/core/library.py +++ b/tagstudio/src/core/library.py @@ -19,7 +19,13 @@ from src.core.json_typing import JsonCollation, JsonEntry, JsonLibary, JsonTag from src.core.utils.str import strip_punctuation from src.core.utils.web import strip_web_protocol -from src.core.constants import BACKUP_FOLDER_NAME, COLLAGE_FOLDER_NAME, TEXT_FIELDS, TS_FOLDER_NAME, VERSION +from src.core.constants import ( + BACKUP_FOLDER_NAME, + COLLAGE_FOLDER_NAME, + TEXT_FIELDS, + TS_FOLDER_NAME, + VERSION, +) TYPE = ["file", "meta", "alt", "mask"] @@ -502,14 +508,10 @@ def open_library(self, path: str) -> int: if TS_FOLDER_NAME in path: path = path.split(TS_FOLDER_NAME)[0] - if os.path.exists( - os.path.normpath(f"{path}/{TS_FOLDER_NAME}/ts_library.json") - ): + if os.path.exists(os.path.normpath(f"{path}/{TS_FOLDER_NAME}/ts_library.json")): try: with open( - os.path.normpath( - f"{path}/{TS_FOLDER_NAME}/ts_library.json" - ), + os.path.normpath(f"{path}/{TS_FOLDER_NAME}/ts_library.json"), "r", encoding="utf-8", ) as f: @@ -720,9 +722,7 @@ def open_library(self, path: str) -> int: if not os.path.exists( os.path.normpath(f"{self.library_dir}/{TS_FOLDER_NAME}") ): - os.makedirs( - os.path.normpath(f"{self.library_dir}/{TS_FOLDER_NAME}") - ) + os.makedirs(os.path.normpath(f"{self.library_dir}/{TS_FOLDER_NAME}")) self._map_filenames_to_entry_ids() diff --git a/tagstudio/src/core/ts_core.py b/tagstudio/src/core/ts_core.py index 6edab037..ca623c33 100644 --- a/tagstudio/src/core/ts_core.py +++ b/tagstudio/src/core/ts_core.py @@ -9,6 +9,7 @@ from src.core.library import Entry, Library + class TagStudioCore: """ Instantiate this to establish a TagStudio session. diff --git a/tagstudio/tests/core/test_tags.py b/tagstudio/tests/core/test_tags.py index 6a82215c..e8e48754 100644 --- a/tagstudio/tests/core/test_tags.py +++ b/tagstudio/tests/core/test_tags.py @@ -12,6 +12,7 @@ def test_construction(): ) assert tag + def test_empty_construction(): tag = Tag(id=1, name="", shorthand="", aliases=[], subtags_ids=[], color="") assert tag From 8733c8d30130ae2b0f85e2d7a2a8b5c03651396b Mon Sep 17 00:00:00 2001 From: Vele George Date: Thu, 16 May 2024 10:37:34 +0300 Subject: [PATCH 3/4] Update constants.py --- tagstudio/src/core/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tagstudio/src/core/constants.py b/tagstudio/src/core/constants.py index b4ff6dde..9e4eea76 100644 --- a/tagstudio/src/core/constants.py +++ b/tagstudio/src/core/constants.py @@ -1,5 +1,5 @@ -VERSION: str = "9.2.0" # Major.Minor.Patch -VERSION_BRANCH: str = "Alpha" # 'Alpha', 'Beta', or '' for Full Release +VERSION: str = "9.2.1" # Major.Minor.Patch +VERSION_BRANCH: str = "Pre-Release" # 'Alpha', 'Beta', or '' for Full Release # The folder & file names where TagStudio keeps its data relative to a library. TS_FOLDER_NAME: str = ".TagStudio" From 5f60ec17022fda91ea70d8cd69edf20e81413cdf Mon Sep 17 00:00:00 2001 From: Travis Abendshien <46939827+CyanVoxel@users.noreply.github.com> Date: Fri, 17 May 2024 21:12:02 -0700 Subject: [PATCH 4/4] Add missing imports to ts_core.py --- tagstudio/src/core/ts_core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tagstudio/src/core/ts_core.py b/tagstudio/src/core/ts_core.py index 31ece55c..8958b01f 100644 --- a/tagstudio/src/core/ts_core.py +++ b/tagstudio/src/core/ts_core.py @@ -8,6 +8,7 @@ import os from src.core.library import Entry, Library +from src.core.constants import TS_FOLDER_NAME, TEXT_FIELDS class TagStudioCore: