From 57078679420118f8c01c415ca12614923da460b6 Mon Sep 17 00:00:00 2001 From: Rusfort Date: Sat, 3 May 2025 18:57:24 +0200 Subject: [PATCH] "Standard_Map_Type" cleanup and refactor --- .../05_Processing_Pipeline.md | 3 +- configuration.py | 6 -- gui/config_editor_dialog.py | 8 --- gui/delegates.py | 2 +- gui/llm_prediction_handler.py | 1 - gui/prediction_handler.py | 11 +--- gui/unified_view_model.py | 55 +++---------------- processing_engine.py | 38 +++++++++---- rule_structure.py | 1 - 9 files changed, 41 insertions(+), 84 deletions(-) diff --git a/Documentation/02_Developer_Guide/05_Processing_Pipeline.md b/Documentation/02_Developer_Guide/05_Processing_Pipeline.md index 03c1c9d..127b66b 100644 --- a/Documentation/02_Developer_Guide/05_Processing_Pipeline.md +++ b/Documentation/02_Developer_Guide/05_Processing_Pipeline.md @@ -37,12 +37,13 @@ The pipeline steps are: * Resizes images based on `Configuration`. * Determines output bit depth and format based on `Configuration` and `SourceRule`. * Converts data types and saves images (`cv2.imwrite`). +* The output filename uses the `standard_type` alias (e.g., `COL`, `NRM`) retrieved from the `Configuration.FILE_TYPE_DEFINITIONS` based on the file's effective `item_type`. * Calculates image statistics. * Stores processed map details. 7. **Map Merging (`_merge_maps_from_source`)**: * Iterates through `MAP_MERGE_RULES` in `Configuration`. - * Identifies required source maps based on `SourceRule`. + * Identifies required source maps by checking the `item_type_override` within the `SourceRule` (specifically in the `FileRule` for each file). Files with a base `item_type` of `"FILE_IGNORE"` are explicitly excluded from consideration. * Loads source channels, handling missing inputs with defaults from `Configuration` or `SourceRule`. * Merges channels (`cv2.merge`). * Determines output format/bit depth and saves the merged map. diff --git a/configuration.py b/configuration.py index 3d4f77e..daa83f0 100644 --- a/configuration.py +++ b/configuration.py @@ -166,9 +166,6 @@ class Configuration: # Store the rule for potential priority access later (optional, index is now in tuple) # self._map_type_rule_order.append(mapping_rule) - if target_type not in self.standard_map_types: - log.warning(f"Map rule {rule_index} uses target_type '{target_type}' which is not in core config STANDARD_MAP_TYPES. Classification might be incomplete.") - # Continue processing anyway, as it might be intended for merging etc. # Compile keywords for this rule and store with context for keyword in source_keywords: @@ -291,9 +288,6 @@ class Configuration: def image_resolutions(self) -> dict[str, int]: return self._core_settings['IMAGE_RESOLUTIONS'] - @property - def standard_map_types(self) -> list[str]: - return self._core_settings['STANDARD_MAP_TYPES'] @property def map_type_mapping(self) -> list: diff --git a/gui/config_editor_dialog.py b/gui/config_editor_dialog.py index 4cd1e86..91cb8a7 100644 --- a/gui/config_editor_dialog.py +++ b/gui/config_editor_dialog.py @@ -282,10 +282,6 @@ class ConfigEditorDialog(QDialog): standard_maps_label = QLabel("Standard Map Types:") standard_maps_layout.addWidget(standard_maps_label) - self.standard_map_types_list = QListWidget() - self.standard_map_types_list.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Allow list to expand - standard_maps_layout.addWidget(self.standard_map_types_list) - self.widgets["STANDARD_MAP_TYPES_LIST"] = self.standard_map_types_list # Store list widget reference standard_maps_button_layout = QHBoxLayout() add_button = QPushButton("Add") @@ -1080,10 +1076,6 @@ class ConfigEditorDialog(QDialog): elif key == "MAP_BIT_DEPTH_RULES" and "MAP_BIT_DEPTH_RULES_TABLE" in self.widgets: self.populate_map_bit_depth_rules_table(self.widgets["MAP_BIT_DEPTH_RULES_TABLE"], value) - elif key == "STANDARD_MAP_TYPES" and "STANDARD_MAP_TYPES_LIST" in self.widgets and isinstance(value, list): - self.widgets["STANDARD_MAP_TYPES_LIST"].addItems(value) - # Populate DEFAULT_ASSET_CATEGORY ComboBox from Asset Types table (deferred) - # This will be done after the Asset Types table is populated. elif key == "MAP_MERGE_RULES" and hasattr(self, 'merge_rules_list'): # Check if the list widget exists self.populate_merge_rules_list(value) diff --git a/gui/delegates.py b/gui/delegates.py index 9026494..99a4624 100644 --- a/gui/delegates.py +++ b/gui/delegates.py @@ -255,7 +255,7 @@ class ItemTypeSearchDelegate(QStyledItemDelegate): value_to_set = final_text if final_text else None # Set None if empty after stripping # Set data in the model - # The model's setData handles updating the override and standard_map_type + # The model's setData handles updating the override and item_type model.setData(index, value_to_set, Qt.EditRole) # DO NOT add to a persistent list or save back to config diff --git a/gui/llm_prediction_handler.py b/gui/llm_prediction_handler.py index 2198de1..0582237 100644 --- a/gui/llm_prediction_handler.py +++ b/gui/llm_prediction_handler.py @@ -348,7 +348,6 @@ class LLMPredictionHandler(BasePredictionHandler): target_asset_name_override=asset_name, # Default to asset name output_format_override=None, is_gloss_source=False, # LLM doesn't predict this - standard_map_type=None, # LLM doesn't predict this directly resolution_override=None, channel_merge_instructions={} ) diff --git a/gui/prediction_handler.py b/gui/prediction_handler.py index 10a1abf..d20bf70 100644 --- a/gui/prediction_handler.py +++ b/gui/prediction_handler.py @@ -441,13 +441,9 @@ class RuleBasedPredictionHandler(BasePredictionHandler): log.warning(f"Predicted ItemType '{base_item_type}' (checked as '{final_item_type}') for file '{file_info['file_path']}' is not in FILE_TYPE_DEFINITIONS. Setting to FILE_IGNORE.") final_item_type = "FILE_IGNORE" - standard_map_type = None - file_type_details = file_type_definitions.get(final_item_type) - if file_type_details: standard_map_type = file_type_details.get('standard_type') - else: - file_type_details_alias = file_type_definitions.get(base_item_type) - if file_type_details_alias: standard_map_type = file_type_details_alias.get('standard_type') - elif base_item_type in file_type_definitions: standard_map_type = base_item_type + # standard_map_type is no longer stored on FileRule + # It will be looked up from config when needed for naming/output + # Remove the logic that determined and assigned it here. is_gloss_source_value = file_info.get('is_gloss_source', False) @@ -458,7 +454,6 @@ class RuleBasedPredictionHandler(BasePredictionHandler): target_asset_name_override=target_asset_name_override, output_format_override=None, is_gloss_source=is_gloss_source_value if isinstance(is_gloss_source_value, bool) else False, - standard_map_type=standard_map_type, resolution_override=None, channel_merge_instructions={}, ) diff --git a/gui/unified_view_model.py b/gui/unified_view_model.py index 4de3edf..54ca9d2 100644 --- a/gui/unified_view_model.py +++ b/gui/unified_view_model.py @@ -415,47 +415,16 @@ class UnifiedViewModel(QAbstractItemModel): if new_value == "": new_value = None # Treat empty string as None # Update item_type_override if item.item_type_override != new_value: - log.debug(f"setData COL_ITEM_TYPE: File='{Path(item.file_path).name}', Original Override='{item.item_type_override}', Original Standard='{getattr(item, 'standard_map_type', 'N/A')}', New Value='{new_value}'") # DEBUG LOG - Added getattr for safety + log.debug(f"setData COL_ITEM_TYPE: File='{Path(item.file_path).name}', Original Override='{item.item_type_override}', New Value='{new_value}'") # DEBUG LOG old_override = item.item_type_override # Store old value for logging item.item_type_override = new_value changed = True - # --- BEGIN FIX: Update standard_map_type --- - try: - base_config = load_base_config() - file_type_definitions = base_config.get('FILE_TYPE_DEFINITIONS', {}) + # standard_map_type is no longer stored on FileRule. + # Remove the logic that updated it here. + pass # No action needed to update standard_map_type - # Determine the type to look up (override first, then original) - type_to_lookup = new_value if new_value is not None else item.item_type - - new_standard_type = None - if type_to_lookup: - type_info = file_type_definitions.get(type_to_lookup) - if type_info: - new_standard_type = type_info.get("standard_type") - # If standard_type itself is missing in the definition, treat as None or keep old? Let's default to None. - if new_standard_type is None: - log.warning(f"setData: No 'standard_type' defined for item type '{type_to_lookup}' in FILE_TYPE_DEFINITIONS.") - else: - log.warning(f"setData: Item type '{type_to_lookup}' not found in FILE_TYPE_DEFINITIONS.") - # Fallback: Keep the existing standard_map_type if lookup fails completely - new_standard_type = getattr(item, 'standard_map_type', None) - else: - # If both override and original type are None, standard type should be None - new_standard_type = None - - # Update the standard_map_type if it changed or needs setting - current_standard_type = getattr(item, 'standard_map_type', None) - if current_standard_type != new_standard_type: - item.standard_map_type = new_standard_type - log.debug(f"setData: Updated standard_map_type from '{current_standard_type}' to '{new_standard_type}' for file '{Path(item.file_path).name}' based on type '{type_to_lookup}'") - # No need to set 'changed = True' again, already set above - - except Exception as e: - log.exception(f"setData: Error updating standard_map_type for file '{Path(item.file_path).name}': {e}") - # --- END FIX --- - - log.debug(f"setData COL_ITEM_TYPE: File='{Path(item.file_path).name}', Final Override='{item.item_type_override}', Final Standard='{getattr(item, 'standard_map_type', 'N/A')}'") # DEBUG LOG - Updated + log.debug(f"setData COL_ITEM_TYPE: File='{Path(item.file_path).name}', Final Override='{item.item_type_override}'") # DEBUG LOG - Updated if changed: @@ -653,17 +622,9 @@ class UnifiedViewModel(QAbstractItemModel): existing_file.item_type = new_file.item_type changed_roles.extend([Qt.DisplayRole, Qt.EditRole, Qt.BackgroundRole]) # Include BackgroundRole for color - # Update standard_map_type (assuming it's derived/set during prediction) - # Check if standard_map_type exists on both objects before comparing - new_standard_type = getattr(new_file, 'standard_map_type', None) - old_standard_type = getattr(existing_file, 'standard_map_type', None) - if old_standard_type != new_standard_type: - # Update only if item_type_override is not set, as override dictates standard type - if existing_file.item_type_override is None: - existing_file.standard_map_type = new_standard_type - # standard_map_type might not directly affect display, but item_type change covers it - if Qt.DisplayRole not in changed_roles: # Avoid duplicates - changed_roles.extend([Qt.DisplayRole, Qt.EditRole]) + # standard_map_type is no longer stored on FileRule. + # Remove the logic that updated it during merge. + pass # No action needed for standard_map_type during merge # Emit dataChanged only if something actually changed diff --git a/processing_engine.py b/processing_engine.py index 49b9988..0db4e5f 100644 --- a/processing_engine.py +++ b/processing_engine.py @@ -893,13 +893,21 @@ class ProcessingEngine: for file_rule in asset_rule.files: # --- Check if this file should be processed individually --- # Skip if no item type is assigned, if it's explicitly "EXTRA", or if marked to skip + # Check if this file should be processed individually or skipped should_skip = ( file_rule.item_type_override is None or file_rule.item_type_override == "EXTRA" or # Explicitly skip "EXTRA" type - getattr(file_rule, 'skip_processing', False) + getattr(file_rule, 'skip_processing', False) or + (hasattr(file_rule, 'file_type') and file_rule.file_type == "FILE_IGNORE") # Skip files marked as FILE_IGNORE ) if should_skip: - log.debug(f"Skipping individual processing for {file_rule.file_path} (ItemTypeOverride: {file_rule.item_type_override}, SkipProcessing: {getattr(file_rule, 'skip_processing', False)})") + skip_reason = [] + if file_rule.item_type_override is None: skip_reason.append("No ItemTypeOverride") + if file_rule.item_type_override == "EXTRA": skip_reason.append("Explicitly EXTRA type") + if getattr(file_rule, 'skip_processing', False): skip_reason.append("SkipProcessing flag set") + if hasattr(file_rule, 'file_type') and file_rule.file_type == "FILE_IGNORE": skip_reason.append("FILE_IGNORE type") + + log.debug(f"Skipping individual processing for {file_rule.file_path} ({', '.join(skip_reason)})") continue # Skip to the next file_rule # --- Proceed with processing for this file_rule --- @@ -974,8 +982,13 @@ class ProcessingEngine: # Get bit depth rule solely from the static configuration using the correct method signature bit_depth_rule = self.config_obj.get_bit_depth_rule(map_type) # Pass only map_type - # Determine the map_type to use for saving (prioritize standard_map_type) - save_map_type = file_rule.standard_map_type if file_rule.standard_map_type else map_type + # Determine the map_type to use for saving (use item_type_override) + save_map_type = file_rule.item_type_override + # If item_type_override is None, this file shouldn't be saved as an individual map. + # This case should ideally be caught by the skip logic earlier, but adding a check here for safety. + if save_map_type is None: + log.warning(f"Skipping save for {file_rule.file_path}: item_type_override is None.") + continue # Skip saving this file save_result = self._save_image( image_data=img_resized, @@ -1060,15 +1073,18 @@ class ProcessingEngine: found_rule_for_type = False # Search in the asset_rule's files for file_rule in asset_rule.files: - # Check if the file_rule's standard_map_type matches the required input type - # This uses the new alias system for exact matching - if hasattr(file_rule, 'standard_map_type') and file_rule.standard_map_type == input_type: - # TODO: Add prioritization logic if multiple files match (e.g., prefer non-gloss rough if gloss exists but isn't needed?) - # For now, take the first match. + # Check if the file_rule's item_type_override matches the required input type + item_override = getattr(file_rule, 'item_type_override', None) + item_base_type = getattr(file_rule, 'item_type', None) # Get base type for ignore check + + # Check if override matches the required input type AND the base type is not FILE_IGNORE + if item_override == input_type and item_base_type != "FILE_IGNORE": + # Found a valid match based on item_type_override and not ignored required_input_file_rules[input_type] = file_rule found_rule_for_type = True - log.debug(f"Found source FileRule for merge input '{input_type}': {file_rule.file_path} (StandardMapType: {file_rule.standard_map_type})") # Use standard_map_type in log - break # Found the first matching source for this input type + # Update log message (see step 2) + log.debug(f"Found source FileRule for merge input '{input_type}': {file_rule.file_path} (ItemTypeOverride: {item_override}, ItemType: {item_base_type})") + break # Take the first valid match found if not found_rule_for_type: log.warning(f"Asset '{asset_name}': Required source FileRule for input map type '{input_type}' not found in AssetRule. Cannot perform merge for '{output_map_type}'.") possible_to_find_sources = False diff --git a/rule_structure.py b/rule_structure.py index ad28267..edef277 100644 --- a/rule_structure.py +++ b/rule_structure.py @@ -11,7 +11,6 @@ class FileRule: channel_merge_instructions: Dict[str, Any] = dataclasses.field(default_factory=dict) output_format_override: str = None # Potentially others identified during integration is_gloss_source: bool = False # Added flag to indicate if source is glossiness - standard_map_type: Optional[str] = None # Added for map type unification def to_json(self) -> str: return json.dumps(dataclasses.asdict(self), indent=4)