Skip to content

Commit b74e872

Browse files
committed
fix: merge conflicts and review suggestions
1 parent 854c805 commit b74e872

File tree

16 files changed

+133
-206
lines changed

16 files changed

+133
-206
lines changed

requirements.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
appdirs==1.4.4
12
chardet==5.2.0
23
ffmpeg-python==0.2.0
34
humanfriendly==10.0
@@ -7,16 +8,15 @@ opencv_python==4.10.0.84
78
pillow-heif==0.16.0
89
pillow-jxl-plugin==1.3.0
910
Pillow==10.3.0
11+
pydantic==2.10.4
1012
pydub==0.25.1
1113
PySide6_Addons==6.8.0.1
1214
PySide6_Essentials==6.8.0.1
1315
PySide6==6.8.0.1
1416
rawpy==0.22.0
1517
SQLAlchemy==2.0.34
1618
structlog==24.4.0
19+
toml==0.10.2
1720
typing_extensions
1821
ujson>=5.8.0,<=5.9.0
19-
vtf2img==0.1.0
20-
toml==0.10.2
21-
appdirs==1.4.4
22-
pydantic==2.10.4
22+
vtf2img==0.1.0

tagstudio/resources/translations/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@
177177
"preview.no_selection": "No Items Selected",
178178
"select.all": "Select All",
179179
"select.clear": "Clear Selection",
180+
"settings.language": "Language",
180181
"settings.open_library_on_start": "Open Library on Start",
181182
"settings.show_filenames_in_grid": "Show Filenames in Grid",
182183
"settings.show_recent_libraries": "Show Recent Libraries",

tagstudio/src/core/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@
2424
TAG_META = 2
2525
RESERVED_TAG_START = 0
2626
RESERVED_TAG_END = 999
27+
28+
DEFAULT_LIB_VERSION = 3

tagstudio/src/core/enums.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,3 @@ def __new__(cls, value):
6262
@property
6363
def value(self):
6464
raise AttributeError("access the value via .default property instead")
65-
66-
67-
class LibraryPrefs(DefaultEnum):
68-
"""Library preferences with default value accessible via .default property."""
69-
70-
IS_EXCLUDE_LIST = True
71-
EXTENSION_LIST: list[str] = [".json", ".xmp", ".aae"]
72-
PAGE_SIZE: int = 500
73-
DB_VERSION: int = 3

tagstudio/src/core/library/alchemy/library.py

Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from os import makedirs
1313
from pathlib import Path
1414
from uuid import uuid4
15-
from warnings import catch_warnings
1615

1716
import structlog
1817
from humanfriendly import format_timespan
@@ -30,6 +29,7 @@
3029
func,
3130
or_,
3231
select,
32+
text,
3333
update,
3434
)
3535
from sqlalchemy.exc import IntegrityError
@@ -44,6 +44,7 @@
4444

4545
from ...constants import (
4646
BACKUP_FOLDER_NAME,
47+
DEFAULT_LIB_VERSION,
4748
LEGACY_TAG_FIELD_IDS,
4849
RESERVED_TAG_END,
4950
RESERVED_TAG_START,
@@ -52,7 +53,6 @@
5253
TAG_META,
5354
TS_FOLDER_NAME,
5455
)
55-
from ...enums import LibraryPrefs
5656
from ...settings import LibSettings
5757
from .db import make_tables
5858
from .enums import MAX_SQL_VARIABLES, FieldTypeEnum, FilterState, SortingModeEnum, TagColor
@@ -257,13 +257,10 @@ def open_library(self, library_dir: Path, storage_path: str | None = None) -> Li
257257
if storage_path == ":memory:":
258258
self.storage_path = storage_path
259259
is_new = True
260+
self.settings = LibSettings(filename="")
260261
return self.open_sqlite_library(library_dir, is_new)
261262
else:
262263
self.storage_path = library_dir / TS_FOLDER_NAME / self.SQL_FILENAME
263-
settings_path = library_dir / TS_FOLDER_NAME / "libsettings.toml"
264-
265-
self.settings = LibSettings.open(settings_path)
266-
267264
if self.verify_ts_folder(library_dir) and (is_new := not self.storage_path.exists()):
268265
json_path = library_dir / TS_FOLDER_NAME / self.JSON_FILENAME
269266
if json_path.exists():
@@ -307,29 +304,6 @@ def open_sqlite_library(self, library_dir: Path, is_new: bool) -> LibraryStatus:
307304
session.rollback()
308305

309306
# dont check db version when creating new library
310-
if not is_new:
311-
db_version = session.scalar(
312-
select(Preferences).where(Preferences.key == LibraryPrefs.DB_VERSION.name)
313-
)
314-
315-
if not db_version:
316-
return LibraryStatus(
317-
success=False,
318-
message=(
319-
"Library version mismatch.\n"
320-
f"Found: v0, expected: v{LibraryPrefs.DB_VERSION.default}"
321-
),
322-
)
323-
324-
for pref in LibraryPrefs:
325-
with catch_warnings(record=True):
326-
try:
327-
session.add(Preferences(key=pref.name, value=pref.default))
328-
session.commit()
329-
except IntegrityError:
330-
logger.debug("preference already exists", pref=pref)
331-
session.rollback()
332-
333307
for field in _FieldID:
334308
try:
335309
session.add(
@@ -346,21 +320,58 @@ def open_sqlite_library(self, library_dir: Path, is_new: bool) -> LibraryStatus:
346320
logger.debug("ValueType already exists", field=field)
347321
session.rollback()
348322

349-
db_version = session.scalar(
350-
select(Preferences).where(Preferences.key == LibraryPrefs.DB_VERSION.name)
351-
)
323+
settings_path = library_dir / TS_FOLDER_NAME / "notafile.toml"
324+
325+
# Will be set already if library was opened in-memory
326+
if self.settings is None:
327+
if settings_path.exists():
328+
self.settings = LibSettings.open(settings_path)
329+
else:
330+
if (
331+
session.execute(
332+
text(
333+
"""
334+
SELECT count(*)
335+
FROM sqlite_master
336+
WHERE type='table' AND lower(name)='preferences';
337+
"""
338+
)
339+
).scalar()
340+
== 0
341+
):
342+
# db was not created when settings were in db;
343+
# use default settings, store at default location
344+
self.settings = LibSettings(filename=str(settings_path))
345+
else:
346+
# copy settings from db, store them in default location on next save
347+
prefs = session.scalars(select(Preferences))
348+
settings = LibSettings(filename=str(settings_path))
349+
for pref in prefs:
350+
# the type ignores below are due to the fact that a Preference's value
351+
# is defined as a dict, while none of them are actually dicts.
352+
# i dont know why that is how it is, but it is
353+
if pref.key == "IS_EXCLUDE_LIST":
354+
settings.is_exclude_list = pref.value # type: ignore
355+
elif pref.key == "EXTENSION_LIST":
356+
settings.extension_list = pref.value # type: ignore
357+
elif pref.key == "PAGE_SIZE":
358+
settings.page_size = pref.value # type: ignore
359+
elif pref.key == "DB_VERSION":
360+
settings.db_version = pref.value # type: ignore
361+
362+
self.settings = settings
352363
# if the db version is different, we cant proceed
353-
if db_version.value != LibraryPrefs.DB_VERSION.default:
364+
if not is_new and self.settings.db_version != DEFAULT_LIB_VERSION:
354365
logger.error(
355366
"DB version mismatch",
356-
db_version=db_version.value,
357-
expected=LibraryPrefs.DB_VERSION.default,
367+
db_version=self.settings.db_version,
368+
expected=DEFAULT_LIB_VERSION,
358369
)
359370
return LibraryStatus(
360371
success=False,
361372
message=(
362373
"Library version mismatch.\n"
363-
f"Found: v{db_version.value}, expected: v{LibraryPrefs.DB_VERSION.default}"
374+
f"Found: v{self.settings.db_version}, expected: v{DEFAULT_LIB_VERSION}"
364375
),
365376
)
366377

@@ -1107,21 +1118,6 @@ def update_parent_tags(self, tag, parent_ids, session):
11071118
)
11081119
session.add(parent_tag)
11091120

1110-
def prefs(self, key: LibraryPrefs):
1111-
# load given item from Preferences table
1112-
with Session(self.engine) as session:
1113-
return session.scalar(select(Preferences).where(Preferences.key == key.name)).value
1114-
1115-
def set_prefs(self, key: LibraryPrefs, value) -> None:
1116-
# set given item in Preferences table
1117-
with Session(self.engine) as session:
1118-
# load existing preference and update value
1119-
pref = session.scalar(select(Preferences).where(Preferences.key == key.name))
1120-
pref.value = value
1121-
session.add(pref)
1122-
session.commit()
1123-
# TODO - try/except
1124-
11251121
def mirror_entry_fields(self, *entries: Entry) -> None:
11261122
"""Mirror fields among multiple Entry items."""
11271123
fields = {}

tagstudio/src/core/settings/libsettings.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
import toml
55
from pydantic import BaseModel, Field
66

7+
from ..constants import DEFAULT_LIB_VERSION
8+
79
logger = structlog.get_logger(__name__)
810

911

1012
class LibSettings(BaseModel):
1113
is_exclude_list: bool = Field(default=True)
1214
extension_list: list[str] = Field(default=[".json", ".xmp", ".aae"])
1315
page_size: int = Field(default=500)
14-
db_version: int = Field(default=2)
16+
db_version: int = Field(default=DEFAULT_LIB_VERSION)
1517
filename: str = Field(default="")
1618

1719
@staticmethod
@@ -27,10 +29,12 @@ def open(path_value: Path | str) -> "LibSettings":
2729
return LibSettings(**settings_data)
2830

2931
# either settings file did not exist or was empty - either way, use default settings
30-
settings = LibSettings(**dict(filename=str(path)))
32+
settings = LibSettings(filename=str(path))
3133
return settings
3234

3335
def save(self):
36+
if self.filename == "": # assume settings were opened for in-memory library
37+
return
3438
if not (parent_path := Path(self.filename).parent).exists():
3539
parent_path.mkdir()
3640

tagstudio/src/core/settings/tssettings.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ def read_settings(path: Path | str) -> "TSSettings":
2727
filecontents = file.read()
2828
if len(filecontents.strip()) != 0:
2929
settings_data = toml.loads(filecontents)
30-
settings = TSSettings(**settings_data)
31-
return settings
30+
return TSSettings(**settings_data)
3231

33-
return TSSettings(**dict(filename=str(path)))
32+
return TSSettings(filename=str(path))
3433

3534
def save(self, path: Path | str | None = None) -> None:
3635
path_value: Path = Path(path) if isinstance(path, str) else Path(self.filename)
36+
if path_value == "":
37+
pass
38+
# settings were probably opened for an in-memory library - save to preferences table
3739

3840
if not path_value.parent.exists():
3941
path_value.parent.mkdir(parents=True, exist_ok=True)

tagstudio/src/core/tscacheddata.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from datetime import datetime
21
from pathlib import Path
32

43
import structlog
@@ -16,7 +15,7 @@ class TSCachedData(BaseModel):
1615
model_config = ConfigDict(arbitrary_types_allowed=True)
1716
last_library: str | None = Field(default=None)
1817
# a dict of ISO formatted date strings -> paths
19-
library_history: dict[str, str] = Field(default_factory=dict[datetime, str])
18+
library_history: dict[str, str] = Field(default_factory=dict[str, str])
2019

2120
path: str = Field()
2221

@@ -44,7 +43,7 @@ def open(path_value: Path | str | None = None) -> "TSCachedData":
4443
logger.info("opening cache file at ", cache_location=path)
4544
return TSCachedData(**cache_data)
4645

47-
return TSCachedData(**dict(path=str(default_cache_location)))
46+
return TSCachedData(path=str(default_cache_location))
4847

4948
def save(self):
5049
with open(self.path, "w") as f:

tagstudio/src/qt/modals/settings_modal.py

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
QVBoxLayout,
1111
)
1212
from src.core.settings import TSSettings
13+
from src.qt.translations import Translations
1314
from src.qt.widgets.panel import PanelWidget
1415

1516

@@ -21,50 +22,38 @@ def __init__(self, settings: TSSettings):
2122
self.main = QVBoxLayout(self)
2223

2324
# ---
24-
self.language_Label = QLabel()
25-
self.language_Value = QComboBox()
26-
self.language_Row = QHBoxLayout()
27-
self.language_Row.addWidget(self.language_Label)
28-
self.language_Row.addWidget(self.language_Value)
25+
language_row = QHBoxLayout(self)
26+
language_label = QLabel(self)
27+
Translations.translate_qobject(language_label, "settings.language")
28+
language_value = QComboBox(self)
29+
language_row.addWidget(language_label)
30+
language_row.addWidget(language_value)
2931

30-
self.language_Label.setText("Language")
3132
translations_folder = Path("tagstudio/resources/translations")
3233
language_list = [x.stem for x in translations_folder.glob("*.json")]
33-
self.language_Value.addItems(language_list)
34-
self.language_Value.setCurrentIndex(language_list.index(self.tempSettings.language))
35-
self.language_Value.currentTextChanged.connect(
34+
language_value.addItems(language_list)
35+
language_value.setCurrentIndex(language_list.index(self.tempSettings.language))
36+
language_value.currentTextChanged.connect(
3637
lambda text: setattr(self.tempSettings, "language", text)
3738
)
3839

3940
# ---
40-
self.show_library_list_Label = QLabel()
41-
self.show_library_list_Value = QCheckBox()
42-
self.show_library_list_Row = QHBoxLayout()
43-
self.show_library_list_Row.addWidget(self.show_library_list_Label)
44-
self.show_library_list_Row.addWidget(self.show_library_list_Value)
45-
self.show_library_list_Label.setText("Load library list on startup (requires restart):")
46-
self.show_library_list_Value.setChecked(self.tempSettings.show_library_list)
41+
show_filenames_row = QHBoxLayout(self)
42+
show_filenames_label = QLabel(self)
43+
Translations.translate_qobject(show_filenames_label, "settings.show_filenames_in_grid")
44+
show_filenames_value = QCheckBox(self)
4745

48-
self.show_library_list_Value.stateChanged.connect(
49-
lambda state: setattr(self.tempSettings, "show_library_list", bool(state))
50-
)
51-
52-
# ---
53-
self.show_filenames_Label = QLabel()
54-
self.show_filenames_Value = QCheckBox()
55-
self.show_filenames_Row = QHBoxLayout()
56-
self.show_filenames_Row.addWidget(self.show_filenames_Label)
57-
self.show_filenames_Row.addWidget(self.show_filenames_Value)
58-
self.show_filenames_Label.setText("Show filenames in grid (requires restart)")
59-
self.show_filenames_Value.setChecked(self.tempSettings.show_filenames_in_grid)
46+
show_filenames_value.setChecked(self.tempSettings.show_filenames_in_grid)
47+
show_filenames_row.addWidget(show_filenames_label)
48+
show_filenames_row.addWidget(show_filenames_value)
6049

61-
self.show_filenames_Value.stateChanged.connect(
50+
show_filenames_value.stateChanged.connect(
6251
lambda state: setattr(self.tempSettings, "show_filenames_in_grid", bool(state))
6352
)
6453
# ---
65-
self.main.addLayout(self.language_Row)
66-
self.main.addLayout(self.show_library_list_Row)
67-
self.main.addLayout(self.show_filenames_Row)
54+
55+
self.main.addLayout(language_row)
56+
self.main.addLayout(show_filenames_row)
6857

6958
def set_property(self, prop_name: str, value: Any) -> None:
7059
setattr(self.tempSettings, prop_name, value)

0 commit comments

Comments
 (0)