From 153e464387aa015ee17abaf8b147bee5f35e6d11 Mon Sep 17 00:00:00 2001 From: Rusfort Date: Wed, 30 Apr 2025 17:30:51 +0200 Subject: [PATCH] Gui Regression Fixes --- Presets/Poliigon.json | 3 +- __pycache__/asset_processor.cpython-313.pyc | Bin 150506 -> 153334 bytes __pycache__/main.cpython-313.pyc | Bin 28016 -> 28039 bytes asset_processor.py | 181 ++++++++++++++------ gui/__pycache__/main_window.cpython-313.pyc | Bin 120677 -> 120662 bytes gui/main_window.py | 4 +- main.py | 4 +- 7 files changed, 130 insertions(+), 62 deletions(-) diff --git a/Presets/Poliigon.json b/Presets/Poliigon.json index 0434a7f..ee3865c 100644 --- a/Presets/Poliigon.json +++ b/Presets/Poliigon.json @@ -43,8 +43,7 @@ "keywords": [ "NORMAL*", "NORM*", - "NRM*", - "N" + "NRM*" ] }, { diff --git a/__pycache__/asset_processor.cpython-313.pyc b/__pycache__/asset_processor.cpython-313.pyc index 50e3814d9697b5d4ddd576713c154d2ccf2eb49e..0d70fd5234006c26f05f08e7b3def5b756a526f4 100644 GIT binary patch delta 15993 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 x)M0Mh971#(o#@t6kx$rm%I#ve)Z%7yeB@ delta 13464 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%0DGW@c`ue02~0|W!JPg+NP!~$#@y4 zBjk^rSyUqF(e9yjbCJVuLGmoXIe_yNEN)h-*Q@FrJ_(dUmPSRiVqPA-*^LUMCK;Lk zZ}#39&>|-XNu)49b{5`7i{xfu3{9ENXFhax-0NGi`2zq7SuUrLMy`~{QZEAW62Qv<1_jG2pQss?S#3_nuK{@q;7yaO%p!E# zT$uUJi>{K1;}h<8An`dle|&0m7Q#;`SpFyK4GkNQ!8O4O(4PW)25=GJ76sZDuBisT zMiL8y!*FBq1b}_G6^L$AxXR!Z#PGLdd3M*eIeP!c@s9*Ayg#y!eUiOPF9v%EmONX4 bWtyFVrOM8+zrmZ_l*sV5kDWIsmF?&srqD|U delta 1539 zcmaJ>-D_KA7(egHSM!~;Njf`|HMG(uUA5!1qdF~?&B|t3ZQ{wYWlfg0sZEod6W?=E z=Txv>Y*bf89@)iuBcdX^5XQl|{RdttID~oxMG*8#CW2SH@O|FXbm>qJikWu*czY_sfj?x_Fm6SJdB)C&IBRhTl2Xr*rRbJy5AyMWdw53?$)<$z zK{*7u*nlI<2V+t3DEGz+qwOWg;dXrHaY#-_N4#=){}eJ?y$j77x-;PX?O(Ssl8}FFR_|vH#I)wftf(-#{@tmfMRy4J~UZLwq z6~H$+F?$}(DF$YErdqF@R`nURr7S;3sY>ZyPbn9D2Ziq|IhI7YFLs>!*C>*fM;_an9IFSboe=UjAV_2XKvU-4|iaE zU-*O!UBc2h0Oh0LUxjI}T&(J*M{ViNmR?$}Qo0TwEhG={d7k2mW?5e~9aXKos8N6) z7Saj4XTD|A^{Ps16{^t|Qs)rzkStD+Z8%em_u){cqgm2)YLX_sfqwo4)!@BinkaCm zcr5)ovTq=~iJ&ns-Pl%XNnNhc4J0okTrm=*B|>(Lw=e9t$>&g5JK_8g9e3cCP diff --git a/asset_processor.py b/asset_processor.py index f47abdf..18a4e10 100644 --- a/asset_processor.py +++ b/asset_processor.py @@ -232,18 +232,60 @@ class AssetProcessor: File-specific > Asset-specific > Source/General Rules > Config Default. """ # Prioritize File > Asset > Source > Config - if file_path and rule_key in rules.file_rules.get(str(file_path), {}): - log.debug(f"Rule '{rule_key}' found at File level for '{file_path}'.") - return rules.file_rules[str(file_path)][rule_key] - if asset_name and rule_key in rules.asset_rules.get(asset_name, {}): - log.debug(f"Rule '{rule_key}' found at Asset level for '{asset_name}'.") - return rules.asset_rules[asset_name][rule_key] + # Prioritize File > Asset > Source > Config + # Check File-specific rules by iterating through AssetRule and FileRule objects + if file_path and rules.assets: # Check if file_path is provided and there are assets to search + log.debug(f"Checking File level rules for '{file_path}'...") + for asset_rule in rules.assets: + # Check if the current asset_rule matches the asset_name being processed + # This requires asset_name to be passed correctly to this method + if asset_name and asset_rule.asset_name == asset_name: + log.debug(f" Found matching AssetRule for '{asset_name}'. Checking its files...") + for file_rule in asset_rule.files: + # Check if the file_rule's path matches the file_path being processed + if file_rule.file_path and Path(file_rule.file_path) == file_path: + log.debug(f" Found matching FileRule for '{file_path}'. Checking for rule_key '{rule_key}'.") + # Check if rule_key is in channel_merge_instructions + if rule_key in file_rule.channel_merge_instructions: + log.debug(f" Rule '{rule_key}' found in channel_merge_instructions.") + return file_rule.channel_merge_instructions[rule_key] + # Check if rule_key is a direct attribute of FileRule (e.g., map_type_override) + if hasattr(file_rule, rule_key) and getattr(file_rule, rule_key) is not None: + log.debug(f" Rule '{rule_key}' found as direct attribute in FileRule.") + return getattr(file_rule, rule_key) + log.debug(f" Rule '{rule_key}' not found in matching FileRule for '{file_path}'.") + # Found the file rule, but the key wasn't there, so no need to check other files for this asset + break + # Found the asset rule, checked its files, now break from asset loop + break + + # Check Asset-specific rules by iterating through the list of AssetRule objects + # Check Asset-specific rules by iterating through the list of AssetRule objects + if asset_name and rules.assets: + for asset_rule in rules.assets: + if asset_rule.asset_name == asset_name: + log.debug(f"Found matching AssetRule for '{asset_name}'. Checking for rule_key '{rule_key}'.") + # Check if rule_key is a direct attribute of AssetRule + if hasattr(asset_rule, rule_key) and getattr(asset_rule, rule_key) is not None: + log.debug(f"Rule '{rule_key}' found as direct attribute in AssetRule for '{asset_name}'.") + return getattr(asset_rule, rule_key) + # Check if rule_key is in common_metadata + if rule_key in asset_rule.common_metadata: + log.debug(f"Rule '{rule_key}' found in common_metadata for '{asset_name}'.") + return asset_rule.common_metadata[rule_key] + log.debug(f"Rule '{rule_key}' not found in matching AssetRule for '{asset_name}'.") + break # Found the asset rule, but the key wasn't there, so no need to continue searching assets if rule_key in rules.high_level_sorting_parameters: log.debug(f"Rule '{rule_key}' found at Source level.") return rules.high_level_sorting_parameters[rule_key] # Fallback to config log.debug(f"Rule '{rule_key}' not found in rules, falling back to config default.") - return getattr(self.config, rule_key, default) + config_default = getattr(self.config, rule_key, default) + # If the default is a callable method on the config object, call it + if callable(config_default) and hasattr(self.config, rule_key): + log.debug(f"Config default for '{rule_key}' is a callable method. Calling it.") + return config_default() + return config_default # --- New Helper Function: Load and Transform Source --- @@ -1058,18 +1100,27 @@ class AssetProcessor: for kw_regex, original_keyword, rule_index in regex_tuples: if kw_regex.search(file_stem): +# --- DIAGNOSTIC LOGGING START --- + log.debug(f" Checking file '{file_rel_path.name}' against keyword '{original_keyword}' (rule {rule_index}, pattern: '{kw_regex.pattern}') for base type '{base_map_type}'") + # --- DIAGNOSTIC LOGGING END --- log.debug(f" Match found: '{file_rel_path}' matches keyword '{original_keyword}' (rule {rule_index}, pattern: '{kw_regex.pattern}') for base type '{base_map_type}'") # Find the index of the matched keyword within its rule's list + keyword_index_in_rule = -1 # Default if not found + if original_keywords_list: try: # Use the original_keyword string directly keyword_index_in_rule = original_keywords_list.index(original_keyword) except ValueError: log.warning(f"Keyword '{original_keyword}' not found in its original rule list? {original_keywords_list}") + + # --- DIAGNOSTIC LOGGING START --- + log.debug(f" Checking file '{file_rel_path.name}' against keyword '{original_keyword}' (rule {rule_index}, pattern: '{kw_regex.pattern}') for base type '{base_map_type}'") + # --- DIAGNOSTIC LOGGING END --- else: - log.warning(f"Original keywords list empty for rule {rule_index}, cannot find index for '{original_keyword}'.") + log.warning(f"Original keywords list empty for rule {rule_index}, cannot find index for '{original_keyword}'.") # Add candidate only if not already added if not any(c['source_path'] == file_rel_path for c in potential_map_candidates): @@ -1362,11 +1413,11 @@ class AssetProcessor: log.debug(f"Determining category, archetype, and supplier for asset: '{asset_base_name}'") # Determine Supplier Name using fallback - determined_supplier_name = self._get_rule_with_fallback('supplier_name', asset_name=asset_base_name, default=self.config.supplier_name) + determined_supplier_name = self._get_rule_with_fallback(rules, 'supplier_name', asset_name=asset_base_name, default=self.config.supplier_name) log.debug(f" Determined Supplier Name for '{asset_base_name}': {determined_supplier_name}") - determined_category = self._get_rule_with_fallback('default_asset_category', asset_name=asset_base_name, default=self.config.default_asset_category) # Start with default from rules/config + determined_category = self._get_rule_with_fallback(rules, 'default_asset_category', asset_name=asset_base_name, default=self.config.default_asset_category) # Start with default from rules/config determined_archetype = "Unknown" # --- Determine Asset Category --- @@ -1376,7 +1427,7 @@ class AssetProcessor: else: # Check for Decal keywords only if not an Asset # Get decal keywords using fallback - decal_keywords = self._get_rule_with_fallback('decal_keywords', asset_name=asset_base_name, default=[]) + decal_keywords = self._get_rule_with_fallback(rules, 'decal_keywords', asset_name=asset_base_name, default=[]) found_decal = False # Check map names first for decal keywords candidate_files = [f['source_path'] for f in filtered_classified_files.get('maps', [])] @@ -1400,7 +1451,7 @@ class AssetProcessor: # --- Determine Archetype (Usage) --- # Get archetype rules using fallback - archetype_rules = self._get_rule_with_fallback('archetype_rules', asset_name=asset_base_name, default=[]) + archetype_rules = self._get_rule_with_fallback(rules, 'archetype_rules', asset_name=asset_base_name, default=[]) # Use stems from maps and models belonging *only* to this asset check_stems = [f['source_path'].stem.lower() for f in filtered_classified_files.get('maps', [])] check_stems.extend([f['source_path'].stem.lower() for f in filtered_classified_files.get('models', [])]) @@ -1468,11 +1519,11 @@ class AssetProcessor: ignored_rough_maps: List[Dict] = [] # Store ignored native rough maps # --- Settings retrieval using fallback --- - resolutions = self._get_rule_with_fallback('image_resolutions', asset_name=asset_name, default=self.config.image_resolutions) - stats_res_key = self._get_rule_with_fallback('calculate_stats_resolution', asset_name=asset_name, default=self.config.calculate_stats_resolution) + resolutions = self._get_rule_with_fallback(rules, 'image_resolutions', asset_name=asset_name, default=self.config.image_resolutions) + stats_res_key = self._get_rule_with_fallback(rules, 'calculate_stats_resolution', asset_name=asset_name, default=self.config.calculate_stats_resolution) stats_target_dim = resolutions.get(stats_res_key) if not stats_target_dim: log.warning(f"Stats resolution key '{stats_res_key}' not found in rules/config. Stats skipped for '{asset_name}'.") - gloss_keywords = self._get_rule_with_fallback('source_glossiness_keywords', asset_name=asset_name, default=self.config.source_glossiness_keywords) + gloss_keywords = self._get_rule_with_fallback(rules, 'source_glossiness_keywords', asset_name=asset_name, default=self.config.source_glossiness_keywords) # target_pattern = _get_rule_with_fallback('target_filename_pattern', asset_name=asset_name, default=self.config.target_filename_pattern) # Not needed here, handled by _save_image base_name = asset_name # Use the asset name passed in @@ -1505,7 +1556,7 @@ class AssetProcessor: derived_from_gloss_flag['ROUGH'] = False # --- Identify maps used in merge rules (using fallback) --- - merge_rules = self._get_rule_with_fallback('map_merge_rules', asset_name=asset_name, default=self.config.map_merge_rules) + merge_rules = self._get_rule_with_fallback(rules, 'map_merge_rules', asset_name=asset_name, default=self.config.map_merge_rules) merge_input_map_types = set() for rule in merge_rules: inputs_mapping = rule.get("inputs", {}) @@ -1515,26 +1566,12 @@ class AssetProcessor: merge_input_map_types.add(base_type) log.debug(f"Map types used as input for merge rules (from rules/config): {merge_input_map_types}") - # --- Filter maps to process individually --- - maps_to_process_individually = [] - for map_info in filtered_maps_list: - base_map_type = _get_base_map_type(map_info['map_type']) - # Skip if this base map type is used in *any* merge rule input - if base_map_type in merge_input_map_types: - log.debug(f"Skipping individual processing for {map_info['map_type']} ({map_info['source_path']}) as its base type '{base_map_type}' is used in merge rules (from rules/config).") - continue - # Skip native rough map if gloss was prioritized - if map_info['map_type'].startswith('ROUGH') and any(ignored['source_path'] == map_info['source_path'] for ignored in ignored_rough_maps): - log.debug(f"Skipping individual processing of native rough map '{map_info['source_path']}' as gloss version was prioritized.") - continue - maps_to_process_individually.append(map_info) - - log.info(f"Processing {len(maps_to_process_individually)} maps individually for asset '{asset_name}'...") + log.info(f"Processing individual map files for asset '{asset_name}'...") # --- Aspect Ratio Calculation Setup --- # We need original dimensions once per asset for aspect ratio. # Find the first map to process to get its dimensions. - first_map_info_for_aspect = next((m for m in maps_to_process_individually), None) + first_map_info_for_aspect = next((m for m in filtered_maps_list), None) # Use the original list orig_w_aspect, orig_h_aspect = None, None if first_map_info_for_aspect: # Load just to get dimensions (might hit cache if used later) @@ -1542,7 +1579,7 @@ class AssetProcessor: first_res_key = next(iter(resolutions)) temp_img_for_dims, _ = self._load_and_transform_source( first_map_info_for_aspect['source_path'], - first_map_info_for_aspect['map_type'], + first_map_info_for_aspect['map_type'], # Use original map type for loading first_res_key, False, # is_gloss_source doesn't matter for dims loaded_data_cache # Use the main cache @@ -1557,14 +1594,46 @@ class AssetProcessor: # --- Process Each Individual Map --- - for map_info in maps_to_process_individually: - map_type = map_info['map_type'] # Final type (e.g., COL-1) + # Iterate through the original list and filter/apply overrides here + for map_info in filtered_maps_list: source_path_rel = map_info['source_path'] original_extension = map_info.get('original_extension', '.png') + current_map_type = map_info['map_type'] # Start with the classified type + + # --- Apply map_type_override from FileRule (Step 2) --- + map_type_override = self._get_rule_with_fallback( + rules, + 'map_type_override', + file_path=source_path_rel, + asset_name=asset_name, + default=None + ) + if map_type_override is not None: + log.debug(f"Asset '{asset_name}': Applying map_type_override '{map_type_override}' for source '{source_path_rel.name}' (originally '{current_map_type}').") + map_type = map_type_override # Use the override + else: + map_type = current_map_type # Use the original classified type + + # --- Check if this map should be processed individually (Step 3) --- + base_map_type = _get_base_map_type(map_type) # Use the potentially updated map_type + if base_map_type in merge_input_map_types: + log.debug(f"Skipping individual processing for {map_type} (Source: {source_path_rel}) as its base type '{base_map_type}' is used in merge rules (from rules/config).") + continue # Skip to the next map in the loop + + # Skip native rough map if gloss was prioritized (keep this check) + # This check needs to use the *original* source path to see if it was the native rough that was ignored + # The ignored_rough_maps list contains the original map_info dicts. + if map_type.startswith('ROUGH') and any(ignored['source_path'] == source_path_rel for ignored in ignored_rough_maps): + log.debug(f"Skipping individual processing of native rough map '{source_path_rel}' as gloss version was prioritized.") + continue # Skip to the next map in the loop + + # Determine if this specific map type should use gloss inversion logic # If ROUGH-1, ROUGH-2 etc derive from gloss, they all use inversion + # This check should use the *final* map_type after override is_gloss_source_for_this_map = map_type.startswith('ROUGH') and derived_from_gloss_flag.get('ROUGH', False) + log.info(f"-- Asset '{asset_name}': Processing Individual Map: {map_type} (Source: {source_path_rel.name}) --") current_map_details = {"derived_from_gloss": is_gloss_source_for_this_map} source_bit_depth_found = None # Track if we've found the bit depth for this map type @@ -1622,17 +1691,17 @@ class AssetProcessor: 'involved_extensions': {original_extension} # Only self for individual maps } # Get bit depth rule using fallback logic - bit_depth_rules_map = self._get_rule_with_fallback('output_bit_depth_rules', file_path=source_path_rel, asset_name=asset_name, default={}) + bit_depth_rules_map = self._get_rule_with_fallback(rules, 'output_bit_depth_rules', file_path=source_path_rel, asset_name=asset_name, default={}) bit_depth_rule = bit_depth_rules_map.get(map_type, 'respect') # Default to 'respect' if map type not in rules/config # Get additional config values using fallback for _save_image - output_formats_16bit = self._get_rule_with_fallback('get_16bit_output_formats', file_path=source_path_rel, asset_name=asset_name, default=self.config.get_16bit_output_formats()) - output_format_8bit = self._get_rule_with_fallback('get_8bit_output_format', file_path=source_path_rel, asset_name=asset_name, default=self.config.get_8bit_output_format()) - resolution_threshold_for_jpg = self._get_rule_with_fallback('resolution_threshold_for_jpg', file_path=source_path_rel, asset_name=asset_name, default=self.config.resolution_threshold_for_jpg) - force_lossless_map_types = self._get_rule_with_fallback('force_lossless_map_types', asset_name=asset_name, default=self.config.force_lossless_map_types) # This rule applies to map type, not individual file path - jpg_quality = self._get_rule_with_fallback('jpg_quality', file_path=source_path_rel, asset_name=asset_name, default=self.config.jpg_quality) - png_compression_level = self._get_rule_with_fallback('_core_settings', asset_name=asset_name, default=self.config._core_settings).get('PNG_COMPRESSION_LEVEL', 6) # This rule applies broadly, not per file - target_filename_pattern = self._get_rule_with_fallback('target_filename_pattern', file_path=source_path_rel, asset_name=asset_name, default=self.config.target_filename_pattern) + output_formats_16bit = self._get_rule_with_fallback(rules, 'get_16bit_output_formats', file_path=source_path_rel, asset_name=asset_name, default=self.config.get_16bit_output_formats()) + output_format_8bit = self._get_rule_with_fallback(rules, 'get_8bit_output_format', file_path=source_path_rel, asset_name=asset_name, default=self.config.get_8bit_output_format()) + resolution_threshold_for_jpg = self._get_rule_with_fallback(rules, 'resolution_threshold_for_jpg', file_path=source_path_rel, asset_name=asset_name, default=self.config.resolution_threshold_for_jpg) + force_lossless_map_types = self._get_rule_with_fallback(rules, 'force_lossless_map_types', asset_name=asset_name, default=self.config.force_lossless_map_types) # This rule applies to map type, not individual file path + jpg_quality = self._get_rule_with_fallback(rules, 'jpg_quality', file_path=source_path_rel, asset_name=asset_name, default=self.config.jpg_quality) + png_compression_level = self._get_rule_with_fallback(rules, '_core_settings', asset_name=asset_name, default=self.config._core_settings).get('PNG_COMPRESSION_LEVEL', 6) # This rule applies broadly, not per file + target_filename_pattern = self._get_rule_with_fallback(rules, 'target_filename_pattern', file_path=source_path_rel, asset_name=asset_name, default=self.config.target_filename_pattern) # image_resolutions is already retrieved at the start of the method save_result = self._save_image( @@ -1699,10 +1768,10 @@ class AssetProcessor: if not self.temp_dir: raise AssetProcessingError("Workspace not setup.") asset_name = current_asset_metadata.get("asset_name", "UnknownAsset") # Get gloss keywords using fallback logic - gloss_keywords = self._get_rule_with_fallback('source_glossiness_keywords', asset_name=asset_name, default=self.config.source_glossiness_keywords) + gloss_keywords = self._get_rule_with_fallback(rules, 'source_glossiness_keywords', asset_name=asset_name, default=self.config.source_glossiness_keywords) # Get merge rules using fallback logic - merge_rules = self._get_rule_with_fallback('map_merge_rules', asset_name=asset_name, default=self.config.map_merge_rules) + merge_rules = self._get_rule_with_fallback(rules, 'map_merge_rules', asset_name=asset_name, default=self.config.map_merge_rules) log.info(f"Asset '{asset_name}': Applying {len(merge_rules)} map merging rule(s) from source (from rules/config)...") # Initialize results for this asset @@ -1765,7 +1834,7 @@ class AssetProcessor: # This assumes _process_individual_maps ran first and populated processed_maps_details_asset possible_resolutions_per_input = [] # Get resolutions using fallback - resolutions = self._get_rule_with_fallback('image_resolutions', asset_name=asset_name, default=self.config.image_resolutions) + resolutions = self._get_rule_with_fallback(rules, 'image_resolutions', asset_name=asset_name, default=self.config.image_resolutions) for input_type in set(inputs_mapping.values()): if input_type in processed_maps_details_asset: @@ -1925,13 +1994,13 @@ class AssetProcessor: # --- Save Merged Map using Helper --- # Get additional config values using fallback for _save_image - output_formats_16bit = self._get_rule_with_fallback('get_16bit_output_formats', asset_name=asset_name, default=self.config.get_16bit_output_formats()) - output_format_8bit = self._get_rule_with_fallback('get_8bit_output_format', asset_name=asset_name, default=self.config.get_8bit_output_format()) - resolution_threshold_for_jpg = self._get_rule_with_fallback('resolution_threshold_for_jpg', asset_name=asset_name, default=self.config.resolution_threshold_for_jpg) - force_lossless_map_types = self._get_rule_with_fallback('force_lossless_map_types', asset_name=asset_name, default=self.config.force_lossless_map_types) - jpg_quality = self._get_rule_with_fallback('jpg_quality', asset_name=asset_name, default=self.config.jpg_quality) - png_compression_level = self._get_rule_with_fallback('_core_settings', asset_name=asset_name, default=self.config._core_settings).get('PNG_COMPRESSION_LEVEL', 6) - target_filename_pattern = self._get_rule_with_fallback('target_filename_pattern', asset_name=asset_name, default=self.config.target_filename_pattern) + output_formats_16bit = self._get_rule_with_fallback(rules, 'get_16bit_output_formats', asset_name=asset_name, default=self.config.get_16bit_output_formats()) + output_format_8bit = self._get_rule_with_fallback(rules, 'get_8bit_output_format', asset_name=asset_name, default=self.config.get_8bit_output_format()) + resolution_threshold_for_jpg = self._get_rule_with_fallback(rules, 'resolution_threshold_for_jpg', asset_name=asset_name, default=self.config.resolution_threshold_for_jpg) + force_lossless_map_types = self._get_rule_with_fallback(rules, 'force_lossless_map_types', asset_name=asset_name, default=self.config.force_lossless_map_types) + jpg_quality = self._get_rule_with_fallback(rules, 'jpg_quality', asset_name=asset_name, default=self.config.jpg_quality) + png_compression_level = self._get_rule_with_fallback(rules, '_core_settings', asset_name=asset_name, default=self.config._core_settings).get('PNG_COMPRESSION_LEVEL', 6) + target_filename_pattern = self._get_rule_with_fallback(rules, 'target_filename_pattern', asset_name=asset_name, default=self.config.target_filename_pattern) # image_resolutions is already retrieved at the start of the method save_result = self._save_image( @@ -2006,9 +2075,9 @@ class AssetProcessor: final_metadata = current_asset_metadata.copy() # Apply hierarchical rules for specific metadata fields - final_metadata["supplier_name"] = self._get_rule_with_fallback('supplier_name', asset_name=asset_name, default=final_metadata.get("supplier_name", self.config.supplier_name)) - final_metadata["asset_category"] = self._get_rule_with_fallback('default_asset_category', asset_name=asset_name, default=final_metadata.get("asset_category", self.config.default_asset_category)) - final_metadata["archetype"] = self._get_rule_with_fallback('archetype', asset_name=asset_name, default=final_metadata.get("archetype", "Unknown")) # Archetype is determined earlier, but allow override + final_metadata["supplier_name"] = self._get_rule_with_fallback(rules, 'supplier_name', asset_name=asset_name, default=final_metadata.get("supplier_name", self.config.supplier_name)) + final_metadata["asset_category"] = self._get_rule_with_fallback(rules, 'default_asset_category', asset_name=asset_name, default=final_metadata.get("asset_category", self.config.default_asset_category)) + final_metadata["archetype"] = self._get_rule_with_fallback(rules, 'archetype', asset_name=asset_name, default=final_metadata.get("archetype", "Unknown")) # Archetype is determined earlier, but allow override # Populate map details from the specific asset's processing results # Add merged map channel stats diff --git a/gui/__pycache__/main_window.cpython-313.pyc b/gui/__pycache__/main_window.cpython-313.pyc index c59a33af341032dcf5eb08b13b0ccc6c8589b9ec..b7f40713288cd6e6549a4f502379371d5e01a38a 100644 GIT binary patch delta 2121 zcmZ{l2~3nn6vy}fExR1c;=*!>6_B+mC`dh`Xgx3zV^yw-7ipw`tEgOl?6OVTv81zUQoshYN4#2QIywYH6&x2v(O>6d)JnfGSiF>mIZ z?|QBG*R|fpUyMdSjeN4k2jvf_Hy&*Cclj+ZDzV$LOLA=a4QCp?y-aCcBhosDr+233 zbcW`B<)7DZ`Pg0`^fr{AenpYZ)w8PxO;mKwB3kr@fWE9i0vP*NR^jFsg?r_dK@BLGz6dxdXE{cF(LPv za1o-z+#aw0ylNCI$@)brI-HI@zCm} zTs9eNjBtntvv2_s@5neVUu%)Q(5mLxtS;Sho3*f1&ExP^`e6=ouz`|O5RWaSreF+e zXm1Kq^*edO2jXE0hU$ z1SS60iAiK0LO$eTPaH;>SAiU-7Yqm$DUBGRbzZt)ra$MyhZ33)?tBz)rc+1dj7?9|qHJO&HA` z=j7@Dnj#SF%&s;&J1s_f^EmeZQ&>rdPoNlM#gLPzgS@4?Paze1==o-p=o7g7X;j~g z!6=~aW)vb(OmD#yWG?HPyR7r&{LXyaJ&mRe(-qm+k<3l9lFm(rGEceBO`g*0Y21?C zBiVUMx>CkXltcMdqX~IUTxi7(C1R{BmAam{X^5hF3>U?9 zz+%#JmO6%sVWGtx=r7mc=)e%YJXAZof3o&Vn4{o6 xg?1xyvio2rv-7Ep*BNUW>lpLddM@{7G58Pd@|jdvyu@B$ouU?qRo(Je{x?3GSE>L2 delta 2155 zcmaKt3v82B6vzAjx^|DQ?&Yu>E35+tV{?d$fCz3wo?~NqRd=sd=^fj&oreDs%#lX_bmADi*aCriL==}Ba=o_F>p@#1; zAcyHOB_?G+jqO#xE?dk{6lt_M4jHs57FYk(X63f=u*nl~*b2nUrUazwO+P7f@iXHp zZ876Cexc>pA&cmB+n1RJUu4M+cWWw0cCPvC|odA@ciZM*8tsX!>*{J zBC5#EK?xl4{u~q-pp&g5uvJ49O&)~&^=!McV6ig&r|YhA+WbA=5{e6CursNv}s(WP=Y(M+>u<0fpP<+D))qOG%G zH*V$*&r8^mYk*yjbRcMePlhX%^XQ_I1#sGaRo;f<7K$alB@3Mo<{8B_UL-qPZsI_i z<^BaYpMXYs&4pZCq4!;|W*y>osoL`lQGC`i18L9NV6I+%=G7=-qgUV`gGaSfDtD6 zsk>3F-jj5p5mOR(aQ~eOcHyJ3O_*rxQNoHWTGxWimAEDJ@FZxYC%QD zDrFbe-{ta#HM>XT@I<{l^ygH(0hWp9xjvf%>txs&e}$45-6XsS;Uu@Kp}J1Eye?n0 z+o^W+1qy6HDOSr98*nk!6j_?6!}K1ZGLlZQhjQDIkG(XfT^-CudZQgV$q@%QhhjgY zi_W&gVv0-~$#I{&){f#>^ic5@+@g%d7L=Gc67ePDE9%*Tobmtf`|l?rvcX$9?8wGm zt?cRj1?uJ~cnRkcQ>QE0tA2G0MXxzcW_Mtp79XdsrWIq#J@*GnyDX#y;ZIIfDq&`r z7;&^Vh>@5jU4mrcvQ8 z*r?S%WlJSdU{d$0`{OlSA1 z3+H9Z??s)JAC_?PofYNPj*5A6?wnd(>Tpb*D@I552))#cVR(T0dQpp;Wzjy|fpX_@ zhch&%CRF1Nc^(eA9~sc;R-#N(#VoBt`;m((?b~P(k=#+q&0Weg4;Mr0wC{Dg^kuSd zKQ?RDB9+R>6DNkNeB0H*vhg}LF!JTfKGbQ6;e;jbx_V!Aozu6Nt{lQFWXj_AP>2*> zK=CF!9J$!9X|%E*l>nXUN0BA6ce;6`yHuC3(NnY3wa_Ot$~la=d1*Yel`(=5&*0Zd zWHC$(Gb4#!Jd6xf(2m0xTiD2|w|T}O;}sUW7|Ii!h+Mr{Tsz7*L)IheC}`|u3?qqQ zqlzQ2s2CO>!Hq_gQOj|4W6h^M$8pd!oqNn@pZC%F4^W_ Tuple[str, str, Optional[str]]: +def process_single_asset_wrapper(input_path_str: str, preset_name: str, output_dir_str: str, overwrite: bool, verbose: bool, rules) -> Tuple[str, str, Optional[str]]: """ Wrapper function for processing a single input path (which might contain multiple assets) in a separate process. Handles instantiation of Configuration and AssetProcessor, @@ -168,7 +168,7 @@ def process_single_asset_wrapper(input_path_str: str, preset_name: str, output_d processor = AssetProcessor(input_path_obj, config, output_base_path, overwrite=overwrite) # processor.process() now returns a Dict[str, List[str]] - status_dict = processor.process() + status_dict = processor.process(rules=rules) # --- Interpret the status dictionary --- processed_assets = status_dict.get("processed", [])