From c32f500f3cfe5a3c4dea63ef3a29093bfe219fe7 Mon Sep 17 00:00:00 2001 From: Travis Abendshien <46939827+CyanVoxel@users.noreply.github.com> Date: Tue, 18 Aug 2026 13:56:35 -0700 Subject: [PATCH] refactor!: organize project layout (#1483) * refactor!: organize project layout * refactor: organize tests * fix: change main.py with __main__.py in tagstudio.spec * refactor: rename renderer.py to file_renderer.py --- contrib/.vscode/launch.json | 2 +- docs/entries.md | 4 +- docs/fields.md | 2 +- docs/roadmap.md | 4 +- docs/style.md | 4 +- docs/tags.md | 2 +- docs/usage.md | 2 +- pyproject.toml | 6 +- scripts/tagstudio.spec | 2 +- src/tagstudio/__main__.py | 69 +++++++++++++++- src/tagstudio/core/driver.py | 8 +- .../core/library/alchemy/migrations.py | 2 +- .../{qt => i18n}/platform_strings.py | 4 +- src/tagstudio/{qt => i18n}/translations.py | 4 +- src/tagstudio/main.py | 80 ------------------- .../renderer.py => previews/file_renderer.py} | 56 +++++++------ .../{qt/helpers => previews}/gradients.py | 0 .../{ => previews}/renderers/archive.py | 2 +- .../{ => previews}/renderers/audio.py | 2 +- .../{ => previews}/renderers/blender.py | 2 +- .../{ => previews}/renderers/clip_studio.py | 0 .../{ => previews}/renderers/ebook.py | 4 +- .../{ => previews}/renderers/font.py | 2 +- .../renderers/medibang_paint.py | 0 .../{ => previews}/renderers/paint_dot_net.py | 0 src/tagstudio/{ => previews}/renderers/pdf.py | 2 +- .../{ => previews}/renderers/raster_image.py | 0 .../{ => previews}/renderers/source_engine.py | 0 .../{ => previews}/renderers/text.py | 0 .../{ => previews}/renderers/vector_image.py | 0 .../{ => previews}/renderers/video.py | 2 +- .../vendored/blender_thumbnailer.py | 0 .../{renderers => previews}/vendored/probe.py | 0 .../vendored/pydub/audio_segment.py | 2 +- .../vendored/pydub/utils.py | 6 +- .../video_tester.py} | 4 +- .../{global_settings.py => app_settings.py} | 8 +- src/tagstudio/qt/cache_manager.py | 2 +- .../qt/controllers/autofill_line_edit.py | 8 +- .../clickable_slider.py | 4 +- .../controllers/edit_field_template_modal.py | 5 +- .../{edit_text_controller.py => edit_text.py} | 1 + .../qt/controllers/field_suggest_box.py | 8 +- ...ller.py => field_template_search_panel.py} | 6 +- ...controller.py => field_template_widget.py} | 3 +- .../qt/controllers/file_opener_label.py | 55 +++++++++++++ ...dal_controller.py => fix_ignored_modal.py} | 9 ++- ...re_modal_controller.py => ignore_modal.py} | 1 + ...eview_panel_controller.py => inspector.py} | 16 ++-- ...w_controller.py => library_info_window.py} | 7 +- .../qt/{views => controllers}/main_window.py | 21 ++--- .../merge_dupe_entries_progress.py} | 9 +-- ...w_thumb_controller.py => preview_thumb.py} | 5 +- .../qt/{mixed => controllers}/progress_bar.py | 1 + .../relink_entries_progress.py} | 6 +- ...ch_panel_controller.py => search_panel.py} | 4 +- .../qt/{views => controllers}/splash.py | 5 +- src/tagstudio/qt/controllers/suggest_box.py | 12 ++- .../{tag_box_controller.py => tag_box.py} | 3 +- ...anel_controller.py => tag_search_panel.py} | 4 +- .../qt/controllers/tag_suggest_box.py | 8 +- .../qt/controllers/underlined_widget.py | 2 + .../update_available_message_box.py | 7 +- src/tagstudio/qt/{ => helpers}/mnemonics.py | 6 +- src/tagstudio/qt/mixed/about_modal.py | 7 +- src/tagstudio/qt/mixed/build_color.py | 7 +- src/tagstudio/qt/mixed/build_namespace.py | 5 +- src/tagstudio/qt/mixed/build_tag.py | 7 +- src/tagstudio/qt/mixed/color_box.py | 5 +- src/tagstudio/qt/mixed/datetime_picker.py | 5 +- src/tagstudio/qt/mixed/drop_import_modal.py | 16 ++-- src/tagstudio/qt/mixed/field_containers.py | 11 +-- src/tagstudio/qt/mixed/field_widget.py | 5 +- src/tagstudio/qt/mixed/file_attributes.py | 14 ++-- src/tagstudio/qt/mixed/fix_dupe_files.py | 8 +- src/tagstudio/qt/mixed/fix_unlinked.py | 18 ++--- src/tagstudio/qt/mixed/folders_to_tags.py | 8 +- src/tagstudio/qt/mixed/item_thumb.py | 7 +- src/tagstudio/qt/mixed/landing.py | 7 +- src/tagstudio/qt/mixed/media_player.py | 9 ++- src/tagstudio/qt/mixed/migration_modal.py | 12 +-- .../qt/mixed/mirror_entries_modal.py | 7 +- .../qt/{views => mixed}/paged_body_wrapper.py | 2 - .../paged_panel.py} | 5 +- .../paged_panel_state.py | 2 +- src/tagstudio/qt/mixed/pagination.py | 5 +- .../qt/mixed/remove_ignored_modal.py | 17 ++-- .../qt/mixed/remove_unlinked_modal.py | 17 ++-- src/tagstudio/qt/mixed/settings_panel.py | 11 +-- src/tagstudio/qt/mixed/tag_color_label.py | 6 +- src/tagstudio/qt/mixed/tag_color_manager.py | 8 +- src/tagstudio/qt/mixed/tag_color_preview.py | 7 +- src/tagstudio/qt/mixed/tag_color_selection.py | 7 +- src/tagstudio/qt/mixed/tag_widget.py | 7 +- src/tagstudio/qt/mixed/text_field.py | 1 + src/tagstudio/qt/{ts_qt.py => qt_driver.py} | 30 +++---- src/tagstudio/qt/qt_file_renderer.py | 6 +- src/tagstudio/qt/utils/file_opener.py | 44 ---------- .../views/edit_field_template_modal_view.py | 4 +- src/tagstudio/qt/views/edit_text_view.py | 4 +- .../qt/views/field_template_widget_view.py | 5 +- .../qt/views/fix_ignored_modal_view.py | 5 +- src/tagstudio/qt/views/ignore_modal_view.py | 3 +- ...review_panel_view.py => inspector_view.py} | 10 +-- .../{ => views/layouts}/thumb_grid_layout.py | 2 +- .../qt/views/library_info_window_view.py | 11 +-- src/tagstudio/qt/views/modal_view.py | 4 +- src/tagstudio/qt/views/preview_thumb_view.py | 9 ++- src/tagstudio/qt/views/search_panel_view.py | 4 +- .../styles}/color_overlay.py | 2 +- .../styles}/image_effects.py | 0 .../qt/{models => views/styles}/palette.py | 0 .../rounded_pixmap_style.py | 0 .../{stylesheets => styles}/stylesheets.py | 8 +- src/tagstudio/qt/views/suggest_box_view.py | 2 +- src/tagstudio/qt/views/tag_box_view.py | 3 +- src/tagstudio/qt/views/thumb_button.py | 12 +-- .../qt/views/underlined_widget_view.py | 2 +- tests/conftest.py | 14 +++- .../{ => core/library}/test_json_migration.py | 2 +- tests/{ => core/library}/test_library.py | 0 .../library/test_migrations.py} | 22 ++--- .../library/test_refresh.py} | 0 tests/{ => core/library}/test_search.py | 0 .../library/test_unlinked_entries.py} | 2 +- tests/{ => core}/macros/test_folders_tags.py | 0 .../test_base_driver.py} | 17 ++-- tests/{macros => core}/test_dupe_files.py | 0 tests/{ => i18n}/test_translations.py | 2 +- ...lobal_settings.py => test_app_settings.py} | 22 ++++- tests/qt/test_build_tag_panel.py | 2 +- tests/qt/test_field_containers.py | 22 ++--- tests/qt/test_file_path_options.py | 6 +- ...est_preview_panel.py => test_inspector.py} | 10 +-- tests/qt/test_item_thumb.py | 2 +- tests/qt/test_qt_driver.py | 2 +- tests/qt/test_tag_panel.py | 2 +- tests/qt/test_tag_search_panel.py | 2 +- tests/qt/test_theme_system.py | 2 +- 139 files changed, 545 insertions(+), 514 deletions(-) rename src/tagstudio/{qt => i18n}/platform_strings.py (86%) rename src/tagstudio/{qt => i18n}/translations.py (96%) delete mode 100755 src/tagstudio/main.py rename src/tagstudio/{qt/previews/renderer.py => previews/file_renderer.py} (96%) rename src/tagstudio/{qt/helpers => previews}/gradients.py (100%) rename src/tagstudio/{ => previews}/renderers/archive.py (98%) rename src/tagstudio/{ => previews}/renderers/audio.py (98%) rename src/tagstudio/{ => previews}/renderers/blender.py (94%) rename src/tagstudio/{ => previews}/renderers/clip_studio.py (100%) rename src/tagstudio/{ => previews}/renderers/ebook.py (93%) rename src/tagstudio/{ => previews}/renderers/font.py (98%) rename src/tagstudio/{ => previews}/renderers/medibang_paint.py (100%) rename src/tagstudio/{ => previews}/renderers/paint_dot_net.py (100%) rename src/tagstudio/{ => previews}/renderers/pdf.py (96%) rename src/tagstudio/{ => previews}/renderers/raster_image.py (100%) rename src/tagstudio/{ => previews}/renderers/source_engine.py (100%) rename src/tagstudio/{ => previews}/renderers/text.py (100%) rename src/tagstudio/{ => previews}/renderers/vector_image.py (100%) rename src/tagstudio/{ => previews}/renderers/video.py (96%) rename src/tagstudio/{renderers => previews}/vendored/blender_thumbnailer.py (100%) rename src/tagstudio/{renderers => previews}/vendored/probe.py (100%) rename src/tagstudio/{renderers => previews}/vendored/pydub/audio_segment.py (99%) rename src/tagstudio/{renderers => previews}/vendored/pydub/utils.py (97%) rename src/tagstudio/{qt/helpers/file_tester.py => previews/video_tester.py} (88%) rename src/tagstudio/qt/{global_settings.py => app_settings.py} (96%) rename src/tagstudio/qt/{views => controllers}/clickable_slider.py (92%) rename src/tagstudio/qt/controllers/{edit_text_controller.py => edit_text.py} (98%) rename src/tagstudio/qt/controllers/{field_template_search_panel_controller.py => field_template_search_panel.py} (96%) rename src/tagstudio/qt/controllers/{field_template_widget_controller.py => field_template_widget.py} (93%) create mode 100644 src/tagstudio/qt/controllers/file_opener_label.py rename src/tagstudio/qt/controllers/{fix_ignored_modal_controller.py => fix_ignored_modal.py} (92%) rename src/tagstudio/qt/controllers/{ignore_modal_controller.py => ignore_modal.py} (97%) rename src/tagstudio/qt/controllers/{preview_panel_controller.py => inspector.py} (96%) rename src/tagstudio/qt/controllers/{library_info_window_controller.py => library_info_window.py} (96%) rename src/tagstudio/qt/{views => controllers}/main_window.py (97%) rename src/tagstudio/qt/{mixed/merge_dupe_entries.py => controllers/merge_dupe_entries_progress.py} (78%) rename src/tagstudio/qt/controllers/{preview_thumb_controller.py => preview_thumb.py} (97%) rename src/tagstudio/qt/{mixed => controllers}/progress_bar.py (98%) rename src/tagstudio/qt/{mixed/relink_entries_modal.py => controllers/relink_entries_progress.py} (86%) rename src/tagstudio/qt/controllers/{search_panel_controller.py => search_panel.py} (99%) rename src/tagstudio/qt/{views => controllers}/splash.py (98%) rename src/tagstudio/qt/controllers/{tag_box_controller.py => tag_box.py} (97%) rename src/tagstudio/qt/controllers/{tag_search_panel_controller.py => tag_search_panel.py} (98%) rename src/tagstudio/qt/{ => helpers}/mnemonics.py (97%) rename src/tagstudio/qt/{views => mixed}/paged_body_wrapper.py (90%) rename src/tagstudio/qt/{controllers/paged_panel_controller.py => mixed/paged_panel.py} (95%) rename src/tagstudio/qt/{controllers => mixed}/paged_panel_state.py (91%) rename src/tagstudio/qt/{ts_qt.py => qt_driver.py} (98%) rename src/tagstudio/qt/views/{preview_panel_view.py => inspector_view.py} (94%) rename src/tagstudio/qt/{ => views/layouts}/thumb_grid_layout.py (99%) rename src/tagstudio/qt/{helpers => views/styles}/color_overlay.py (98%) rename src/tagstudio/qt/{helpers => views/styles}/image_effects.py (100%) rename src/tagstudio/qt/{models => views/styles}/palette.py (100%) rename src/tagstudio/qt/views/{stylesheets => styles}/rounded_pixmap_style.py (100%) rename src/tagstudio/qt/views/{stylesheets => styles}/stylesheets.py (99%) rename tests/{ => core/library}/test_json_migration.py (93%) rename tests/{ => core/library}/test_library.py (100%) rename tests/{test_db_migrations.py => core/library/test_migrations.py} (55%) rename tests/{macros/test_refresh_dir.py => core/library/test_refresh.py} (100%) rename tests/{ => core/library}/test_search.py (100%) rename tests/{macros/test_missing_files.py => core/library/test_unlinked_entries.py} (96%) rename tests/{ => core}/macros/test_folders_tags.py (100%) rename tests/{test_driver.py => core/test_base_driver.py} (76%) rename tests/{macros => core}/test_dupe_files.py (100%) rename tests/{ => i18n}/test_translations.py (98%) rename tests/qt/{test_global_settings.py => test_app_settings.py} (55%) rename tests/qt/{test_preview_panel.py => test_inspector.py} (89%) diff --git a/contrib/.vscode/launch.json b/contrib/.vscode/launch.json index 28e5523d..941d90ca 100644 --- a/contrib/.vscode/launch.json +++ b/contrib/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "TagStudio", "type": "python", "request": "launch", - "program": "${workspaceRoot}/src/tagstudio/main.py", + "program": "${workspaceRoot}/src/tagstudio/__main__.py", "console": "integratedTerminal", "justMyCode": true, "args": ["-o", "~/Documents/Example"] diff --git a/docs/entries.md b/docs/entries.md index d16442c3..7b11939f 100644 --- a/docs/entries.md +++ b/docs/entries.md @@ -16,11 +16,11 @@ File entry data is stored within the `ts_library.sqlite` file inside each librar ## Appearance -File entries appear as thumbnails inside the grid display. The preview panel shows a more detailed preview of the file, along with extra file stats and all attached TagStudio tags and fields. +File entries appear as thumbnails inside the grid display. The inspector shows a more detailed preview of the file, along with extra file stats and all attached TagStudio tags and fields. ## Unlinked Entries -If the file that an entry is referencing has been moved, renamed, or deleted on disk, then TagStudio will display its unlinked status with a red chain-link icon instead of its thumbnail image. Certain uncached stats such as the file size and image dimensions will also be unavailable to see in the preview panel. +If the file that an entry is referencing has been moved, renamed, or deleted on disk, then TagStudio will display its unlinked status with a red chain-link icon instead of its thumbnail image. Certain uncached stats such as the file size and image dimensions will also be unavailable to see in the inspector. To fix file entries that have become unlinked, select the "Fix Unlinked Entries" option from the Tools menu. From there, refresh the unlinked entry count and choose whether to search and relink you files, and/or delete the file entries from your library. This will NOT delete or modify any files on disk. diff --git a/docs/fields.md b/docs/fields.md index c2d672dd..9f3e4572 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -12,7 +12,7 @@ Fields are extra pieces of information you can add to [file entries](./entries.m Unlike tags, fields are based on [templates](#templates) that contain pre-filled information such as the field type and title, and that information is _copied_ to fields when adding them to entries. Editing field information on entries **does not** modify the template it was created from. -To add a field to an entry, click the "Add Field" button in the preview panel. From there you can search and/or select a [field template](#field-templates) to choose from, or create a new one from the search bar. Alternatively you can create new field templates from **Edit -> Manage Field Templates**. +To add a field to an entry, click the "Add Field" button at the bottom of the inspector. From there you can search and/or select a [field template](#field-templates) to choose from, or create a new one from the search bar. Alternatively you can create new field templates from **Edit -> Manage Field Templates**.
![Fields Example](assets/fields_example.png) diff --git a/docs/roadmap.md b/docs/roadmap.md index da4c440f..518f44dd 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -203,8 +203,8 @@ Discrete library objects representing [attributes](