pyjallib.namingConfig
namingConfig 모듈 - Naming 클래스의 설정을 관리하는 기능 제공 NamePart 객체를 기반으로 네이밍 설정을 저장하고 불러오는 기능 구현
1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4""" 5namingConfig 모듈 - Naming 클래스의 설정을 관리하는 기능 제공 6NamePart 객체를 기반으로 네이밍 설정을 저장하고 불러오는 기능 구현 7""" 8 9import json 10import os 11import copy 12from typing import List, Dict, Any, Optional, Union 13import csv # Import the csv module 14 15 16# NamePart 클래스 임포트 17from pyjallib.namePart import NamePart, NamePartType 18 19 20class NamingConfig: 21 """ 22 Naming 클래스의 설정을 관리하는 클래스. 23 NamePart 객체 리스트를 관리하고 JSON 파일로 저장/불러오기 기능 제공. 24 """ 25 26 def __init__(self, padding_num: int = 2, name_parts: Optional[List[NamePart]] = None, 27 config_file_path: str = "", default_file_name: str = "namingConfig.json", 28 required_parts: Optional[List[str]] = None): 29 """ 30 클래스 초기화 및 기본 설정값 정의 31 32 Args: 33 padding_num: 인덱스 패딩 자릿수 (기본값: 2) 34 name_parts: 초기 NamePart 객체 리스트 (기본값: None, 기본 파트로 초기화) 35 config_file_path: 설정 파일 경로 (기본값: 빈 문자열) 36 default_file_name: 기본 파일명 (기본값: "namingConfig.json") 37 required_parts: 필수 namePart 목록 (기본값: ["RealName"]) 38 """ 39 # NamePart 객체 리스트 40 self.name_parts = name_parts or [] 41 42 # 추가 설정 43 self.padding_num = padding_num 44 45 # NamePart 순서 정보 저장 46 self.part_order = [] 47 48 # 필수 namePart 정의 (삭제 불가능) 49 self.required_parts = required_parts or ["RealName"] 50 51 # 설정 파일 경로 및 기본 파일명 52 self.config_file_path = config_file_path 53 self.default_file_name = default_file_name 54 55 # 스크립트 디렉토리 기준 기본 경로 설정 56 script_dir = os.path.dirname(os.path.abspath(__file__)) 57 config_dir = os.path.join(script_dir, "ConfigFiles") 58 self.default_file_path = os.path.join(config_dir, self.default_file_name) 59 60 # name_parts가 제공되지 않은 경우에만 기본 NamePart 초기화 61 if not self.name_parts: 62 self._initialize_default_parts() 63 else: 64 # 제공된 name_parts가 있는 경우 순서 업데이트 및 타입 자동 업데이트 65 self._update_part_order() 66 self._update_part_types_based_on_order() 67 68 def _initialize_default_parts(self): 69 """기본 NamePart 객체들 초기화""" 70 # 기본 순서 정의 (명시적으로 순서를 저장) 71 self.part_order = [] 72 73 # Prefix 부분 (PREFIX 타입) 74 prefixPart = NamePart("Prefix", NamePartType.PREFIX, ["Pr"], ["Prefix"], False, ["접두사"]) # Add korean descriptions 75 76 # RealName 부분 (REALNAME 타입) 77 realNamePart = NamePart("RealName", NamePartType.REALNAME, [], [], False, []) # Add korean descriptions 78 79 # Index 부분 (INDEX 타입) 80 indexPart = NamePart("Index", NamePartType.INDEX, [], [], False, []) # Add korean descriptions 81 82 # Suffix 부분 (SUFFIX 타입) 83 suffixPart = NamePart("Suffix", NamePartType.SUFFIX, ["Su"], ["Suffix"], False, ["접미사"]) # Add korean descriptions 84 85 # 기본 순서대로 설정 86 self.name_parts = [prefixPart, realNamePart, indexPart, suffixPart] 87 88 self._update_part_order() # 초기화 후 순서 업데이트 89 90 # 타입 자동 업데이트 91 self._update_part_types_based_on_order() 92 93 def _update_part_order(self): 94 """ 95 NamePart 순서 업데이트 - 기본적으로 NamePart 객체의 순서에 따라 업데이트 96 """ 97 self.part_order = [part.get_name() for part in self.name_parts] 98 99 def _get_real_name_index(self) -> int: 100 """ 101 RealName 파트의 인덱스를 반환합니다. 102 103 Returns: 104 RealName 파트의 인덱스, 없으면 -1 105 """ 106 for i, part in enumerate(self.name_parts): 107 if part.get_type() == NamePartType.REALNAME: 108 return i 109 return -1 110 111 def _update_part_types_based_on_order(self) -> bool: 112 """ 113 NamePart 순서에 따라 파트의 타입을 자동으로 업데이트합니다. 114 RealName을 기준으로 앞에 있는 파트는 PREFIX, 뒤에 있는 파트는 SUFFIX로 설정합니다. 115 (RealName과 Index 파트는 예외) 116 117 Returns: 118 업데이트 성공 여부 (True/False) 119 """ 120 # RealName 파트 인덱스 찾기 121 real_name_index = self._get_real_name_index() 122 if real_name_index == -1: 123 print("경고: RealName 파트를 찾을 수 없어 타입 자동 업데이트를 수행할 수 없습니다.") 124 return False 125 126 # 각 파트의 타입을 순서에 따라 업데이트 127 for i, part in enumerate(self.name_parts): 128 partName = part.get_name() 129 130 # RealName은 항상 REALNAME 타입 131 if partName == "RealName": 132 part.set_type(NamePartType.REALNAME) 133 continue 134 135 # Index는 항상 INDEX 타입 136 if partName == "Index": 137 part.set_type(NamePartType.INDEX) 138 continue 139 140 # RealName 앞의 파트는 PREFIX, 뒤의 파트는 SUFFIX 141 if i < real_name_index: 142 part.set_type(NamePartType.PREFIX) 143 else: 144 part.set_type(NamePartType.SUFFIX) 145 146 return True 147 148 def get_part_names(self) -> List[str]: 149 """ 150 모든 NamePart 이름 목록 반환 151 152 Returns: 153 NamePart 이름 목록 154 """ 155 return [part.get_name() for part in self.name_parts] 156 157 def get_part_order(self) -> List[str]: 158 """ 159 NamePart 순서 목록 반환 160 161 Returns: 162 NamePart 이름 순서 목록 163 """ 164 return self.part_order.copy() 165 166 def get_part(self, name: str) -> Optional[NamePart]: 167 """ 168 이름으로 NamePart 객체 가져오기 169 170 Args: 171 name: NamePart 이름 172 173 Returns: 174 NamePart 객체, 없으면 None 175 """ 176 for part in self.name_parts: 177 if part.get_name() == name: 178 return part 179 return None 180 181 def add_part(self, name: str, part_type: NamePartType = NamePartType.UNDEFINED, 182 values: Optional[List[str]] = None, descriptions: Optional[List[str]] = None, 183 korean_descriptions: Optional[List[str]] = None) -> bool: # Add korean_descriptions parameter 184 """ 185 새 NamePart 객체 추가 186 187 Args: 188 name: 추가할 NamePart 이름 189 part_type: NamePart 타입 (기본값: UNDEFINED) 190 values: 사전 정의된 값 목록 (기본값: None) 191 descriptions: 값에 대한 설명 목록 (기본값: None, 값과 동일하게 설정됨) 192 korean_descriptions: 값에 대한 한국어 설명 목록 (기본값: None, 값과 동일하게 설정됨) # Add korean_descriptions doc 193 194 Returns: 195 추가 성공 여부 (True/False) 196 """ 197 if not name: 198 print("오류: 유효한 NamePart 이름을 입력하세요.") 199 return False 200 201 # 이미 존재하는지 확인 202 if self.get_part(name) is not None: 203 print(f"오류: '{name}' NamePart가 이미 존재합니다.") 204 return False 205 206 # 새 NamePart 객체 생성 - NamePart 클래스의 생성자 활용 207 new_part = NamePart(name, part_type, values or [], descriptions, False, korean_descriptions) # Pass korean_descriptions 208 209 # 리스트에 추가 210 self.name_parts.append(new_part) 211 212 # 순서 목록에 추가 213 if name not in self.part_order: 214 self.part_order.append(name) 215 216 # 순서에 따라 타입 업데이트 217 self._update_part_types_based_on_order() 218 return True 219 220 def remove_part(self, name: str) -> bool: 221 """ 222 NamePart 객체 제거 (필수 부분은 제거 불가) 223 224 Args: 225 name: 제거할 NamePart 이름 226 227 Returns: 228 제거 성공 여부 (True/False) 229 """ 230 # 필수 부분은 제거 불가능 231 if name in self.required_parts: 232 print(f"오류: 필수 NamePart '{name}'는 제거할 수 없습니다.") 233 return False 234 235 # 찾아서 제거 236 for i, part in enumerate(self.name_parts): 237 if part.get_name() == name: 238 del self.name_parts[i] 239 240 # 순서 목록에서도 제거 241 if name in self.part_order: 242 self.part_order.remove(name) 243 244 # 순서에 따라 타입 업데이트 245 self._update_part_types_based_on_order() 246 return True 247 248 print(f"오류: '{name}' NamePart가 존재하지 않습니다.") 249 return False 250 251 def reorder_parts(self, new_order: List[str]) -> bool: 252 """ 253 NamePart 순서 변경 254 255 Args: 256 new_order: 새로운 NamePart 이름 순서 배열 257 258 Returns: 259 변경 성공 여부 (True/False) 260 """ 261 # 배열 길이 확인 262 if len(new_order) != len(self.name_parts): 263 print("오류: 새 순서의 항목 수가 기존 NamePart와 일치하지 않습니다.") 264 return False 265 266 # 모든 필수 부분이 포함되어 있는지 확인 267 for part in self.required_parts: 268 if part not in new_order: 269 print(f"오류: 필수 NamePart '{part}'가 새 순서에 포함되어 있지 않습니다.") 270 return False 271 272 # 모든 이름이 현재 존재하는지 확인 273 current_names = self.get_part_names() 274 for name in new_order: 275 if name not in current_names: 276 print(f"오류: '{name}' NamePart가 존재하지 않습니다.") 277 return False 278 279 # 순서 변경을 위한 새 리스트 생성 280 reordered_parts = [] 281 for name in new_order: 282 part = self.get_part(name) 283 if part: 284 reordered_parts.append(part) 285 286 # 새 순서로 업데이트 287 self.name_parts = reordered_parts 288 self.part_order = new_order.copy() 289 290 # 순서에 따라 타입 업데이트 291 self._update_part_types_based_on_order() 292 return True 293 294 def set_padding_num(self, padding_num: int) -> bool: 295 """ 296 인덱스 자릿수 설정 297 298 Args: 299 padding_num: 설정할 패딩 자릿수 300 301 Returns: 302 설정 성공 여부 (True/False) 303 """ 304 if not isinstance(padding_num, int) or padding_num < 1: 305 print("오류: 패딩 자릿수는 1 이상의 정수여야 합니다.") 306 return False 307 308 self.padding_num = padding_num 309 return True 310 311 def set_part_type(self, part_name: str, part_type: NamePartType) -> bool: 312 """ 313 특정 NamePart의 타입 설정 314 315 Args: 316 part_name: NamePart 이름 317 part_type: 설정할 타입 (NamePartType 열거형 값) 318 319 Returns: 320 설정 성공 여부 (True/False) 321 """ 322 part = self.get_part(part_name) 323 if not part: 324 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 325 return False 326 327 # 필수 RealName 부분은 항상 REALNAME 타입이어야 함 328 if part_name == "RealName" and part_type != NamePartType.REALNAME: 329 print("오류: RealName 부분은 반드시 REALNAME 타입이어야 합니다.") 330 return False 331 332 # Index 부분은 항상 INDEX 타입이어야 함 333 if part_name == "Index" and part_type != NamePartType.INDEX: 334 print("오류: Index 부분은 반드시 INDEX 타입이어야 합니다.") 335 return False 336 337 part.set_type(part_type) 338 return True 339 340 def get_part_type(self, part_name: str) -> Optional[NamePartType]: 341 """ 342 특정 NamePart의 타입 가져오기 343 344 Args: 345 part_name: NamePart 이름 346 347 Returns: 348 NamePart 타입, 없으면 None 349 """ 350 part = self.get_part(part_name) 351 if not part: 352 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 353 return None 354 355 return part.get_type() 356 357 def set_part_values(self, part_name: str, values: List[str], 358 descriptions: Optional[List[str]] = None, 359 korean_descriptions: Optional[List[str]] = None) -> bool: # Add korean_descriptions parameter 360 """ 361 특정 NamePart의 사전 정의 값 설정 362 363 Args: 364 part_name: NamePart 이름 365 values: 설정할 사전 정의 값 리스트 366 descriptions: 설정할 설명 목록 (기본값: None, 값과 같은 설명 사용) 367 korean_descriptions: 설정할 한국어 설명 목록 (기본값: None, 값과 같은 설명 사용) # Add korean_descriptions doc 368 369 Returns: 370 설정 성공 여부 (True/False) 371 """ 372 part = self.get_part(part_name) 373 if not part: 374 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 375 return False 376 377 # REALNAME이나 INDEX 타입은 사전 정의 값 설정 불가 378 if part.is_realname() or part.is_index(): 379 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 설정할 수 없습니다.") 380 return False 381 382 if not values: 383 print(f"오류: {part_name} 부분의 사전 정의 값은 적어도 하나 이상 있어야 합니다.") 384 return False 385 386 # 값 설정 387 part.set_predefined_values(values, descriptions, korean_descriptions) # Pass korean_descriptions 388 389 return True 390 391 def set_part_value_by_csv(self, part_name: str, csv_file_path: str) -> bool: 392 """ 393 특정 NamePart의 사전 정의 값을 CSV 파일로 설정 394 CSV 파일 형식: value,description,koreanDescription (각 줄당) 395 396 Args: 397 part_name: NamePart 이름 398 csv_file_path: CSV 파일 경로 399 400 Returns: 401 설정 성공 여부 (True/False) 402 """ 403 part = self.get_part(part_name) 404 if not part: 405 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 406 return False 407 408 # REALNAME이나 INDEX 타입은 사전 정의 값 설정 불가 409 if part.is_realname() or part.is_index(): 410 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 설정할 수 없습니다.") 411 return False 412 413 # CSV 파일에서 값, 설명, 한국어 설명 읽기 414 values = [] 415 descriptions = [] 416 korean_descriptions = [] 417 try: 418 with open(csv_file_path, 'r', encoding='utf-8', newline='') as f: 419 reader = csv.reader(f) 420 for row in reader: 421 if len(row) >= 3: # Ensure row has at least 3 columns 422 value = row[0].strip() 423 description = row[1].strip() 424 korean_description = row[2].strip() 425 if value: # Skip empty values 426 values.append(value) 427 descriptions.append(description if description else value) # Use value if description is empty 428 korean_descriptions.append(korean_description if korean_description else value) # Use value if korean_description is empty 429 elif len(row) == 2: # Handle case with value and description only 430 value = row[0].strip() 431 description = row[1].strip() 432 if value: 433 values.append(value) 434 descriptions.append(description if description else value) 435 korean_descriptions.append(value) # Use value as korean description 436 elif len(row) == 1: # Handle case with value only 437 value = row[0].strip() 438 if value: 439 values.append(value) 440 descriptions.append(value) 441 korean_descriptions.append(value) 442 443 if not values: 444 print(f"오류: CSV 파일 '{csv_file_path}'에서 유효한 값을 찾을 수 없습니다.") 445 return False 446 447 # 값, 설명, 한국어 설명 설정 448 return self.set_part_values(part_name, values, descriptions, korean_descriptions) 449 except FileNotFoundError: 450 print(f"오류: CSV 파일을 찾을 수 없습니다: {csv_file_path}") 451 return False 452 except Exception as e: 453 print(f"오류: CSV 파일을 읽는 중 오류 발생: {e}") 454 return False 455 456 def add_part_value(self, part_name: str, value: str, 457 description: Optional[str] = None, 458 korean_description: Optional[str] = None) -> bool: # Add korean_description parameter 459 """ 460 특정 NamePart에 사전 정의 값 추가 461 462 Args: 463 part_name: NamePart 이름 464 value: 추가할 사전 정의 값 465 description: 추가할 값의 설명 (기본값: None, 값과 같은 설명 사용) 466 korean_description: 추가할 값의 한국어 설명 (기본값: None, 값과 같은 설명 사용) # Add korean_description doc 467 468 Returns: 469 추가 성공 여부 (True/False) 470 """ 471 part = self.get_part(part_name) 472 if not part: 473 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 474 return False 475 476 # REALNAME이나 INDEX 타입은 사전 정의 값 추가 불가 477 if part.is_realname() or part.is_index(): 478 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 추가할 수 없습니다.") 479 return False 480 481 # 값이 이미 존재하는지 확인 482 if part.contains_value(value): 483 print(f"오류: '{value}'가 이미 {part_name} 부분의 사전 정의 값에 존재합니다.") 484 return False 485 486 # description이 없으면 값을 설명으로 사용 487 if description is None: 488 description = value 489 490 # korean_description이 없으면 값을 설명으로 사용 491 if korean_description is None: 492 korean_description = value 493 494 # NamePart 클래스의 add_predefined_value 메소드 직접 활용 495 return part.add_predefined_value(value, description, korean_description) # Pass korean_description 496 497 def remove_part_value(self, part_name: str, value: str) -> bool: 498 """ 499 특정 NamePart에서 사전 정의 값과 해당 설명 제거 500 501 Args: 502 part_name: NamePart 이름 503 value: 제거할 사전 정의 값 504 505 Returns: 506 제거 성공 여부 (True/False) 507 """ 508 part = self.get_part(part_name) 509 if not part: 510 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 511 return False 512 513 # REALNAME이나 INDEX 타입은 사전 정의 값 제거 불가 514 if part.is_realname() or part.is_index(): 515 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 제거할 수 없습니다.") 516 return False 517 518 # 값이 존재하는지 확인 519 if not part.contains_value(value): 520 print(f"오류: '{value}'가 {part_name} 부분의 사전 정의 값에 존재하지 않습니다.") 521 return False 522 523 # 마지막 값인지 확인 524 if part.get_value_count() <= 1: 525 print(f"오류: {part_name} 부분의 사전 정의 값은 적어도 하나 이상 있어야 합니다.") 526 return False 527 528 # NamePart 클래스의 remove_predefined_value 메소드 직접 활용 529 return part.remove_predefined_value(value) 530 531 def set_part_descriptions(self, part_name: str, descriptions: List[str]) -> bool: 532 """ 533 특정 NamePart의 설명 목록 설정 534 535 Args: 536 part_name: NamePart 이름 537 descriptions: 설정할 설명 목록 538 539 Returns: 540 설정 성공 여부 (True/False) 541 """ 542 part = self.get_part(part_name) 543 if not part: 544 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 545 return False 546 547 # REALNAME이나 INDEX 타입은 설명 설정 불가 548 if part.is_realname() or part.is_index(): 549 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 설명을 설정할 수 없습니다.") 550 return False 551 552 # NamePart 클래스 메소드 활용하여 설명 설정 553 values = part.get_predefined_values() 554 555 # 길이 맞추기 556 if len(descriptions) < len(values): 557 descriptions.extend([""] * (len(values) - len(descriptions))) 558 elif len(descriptions) > len(values): 559 descriptions = descriptions[:len(values)] 560 561 # 각 값에 대한 설명 설정 (NamePart.set_description 사용) 562 success = True 563 for i, value in enumerate(values): 564 if not part.set_description(value, descriptions[i]): 565 success = False # 실패 시 기록 (이론상 발생하지 않음) 566 567 return success 568 569 def get_part_descriptions(self, part_name: str) -> List[str]: 570 """ 571 특정 NamePart의 설명 목록 가져오기 572 573 Args: 574 part_name: NamePart 이름 575 576 Returns: 577 설명 목록 578 """ 579 part = self.get_part(part_name) 580 if not part: 581 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 582 return [] 583 584 return part.get_descriptions() 585 586 def set_part_korean_descriptions(self, part_name: str, korean_descriptions: List[str]) -> bool: 587 """ 588 특정 NamePart의 한국어 설명 목록 설정 589 590 Args: 591 part_name: NamePart 이름 592 korean_descriptions: 설정할 한국어 설명 목록 593 594 Returns: 595 설정 성공 여부 (True/False) 596 """ 597 part = self.get_part(part_name) 598 if not part: 599 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 600 return False 601 602 # REALNAME이나 INDEX 타입은 설명 설정 불가 603 if part.is_realname() or part.is_index(): 604 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 한국어 설명을 설정할 수 없습니다.") 605 return False 606 607 # NamePart 클래스 메소드 활용하여 설명 설정 608 values = part.get_predefined_values() 609 610 # 길이 맞추기 611 if len(korean_descriptions) < len(values): 612 korean_descriptions.extend([""] * (len(values) - len(korean_descriptions))) 613 elif len(korean_descriptions) > len(values): 614 korean_descriptions = korean_descriptions[:len(values)] 615 616 # 각 값에 대한 한국어 설명 설정 (NamePart.set_korean_description 사용) 617 success = True 618 for i, value in enumerate(values): 619 if not part.set_korean_description(value, korean_descriptions[i]): 620 success = False # 실패 시 기록 (이론상 발생하지 않음) 621 622 return success 623 624 def get_part_korean_descriptions(self, part_name: str) -> List[str]: 625 """ 626 특정 NamePart의 한국어 설명 목록 가져오기 627 628 Args: 629 part_name: NamePart 이름 630 631 Returns: 632 한국어 설명 목록 633 """ 634 part = self.get_part(part_name) 635 if not part: 636 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 637 return [] 638 639 return part.get_korean_descriptions() 640 641 def get_prefix_parts(self) -> List[NamePart]: 642 """ 643 모든 PREFIX 타입 NamePart 가져오기 644 645 Returns: 646 PREFIX 타입의 NamePart 객체 리스트 647 """ 648 return [part for part in self.name_parts if part.is_prefix()] 649 650 def get_suffix_parts(self) -> List[NamePart]: 651 """ 652 모든 SUFFIX 타입 NamePart 가져오기 653 654 Returns: 655 SUFFIX 타입의 NamePart 객체 리스트 656 """ 657 return [part for part in self.name_parts if part.is_suffix()] 658 659 def get_realname_part(self) -> Optional[NamePart]: 660 """ 661 REALNAME 타입 NamePart 가져오기 662 663 Returns: 664 REALNAME 타입의 NamePart 객체, 없으면 None 665 """ 666 for part in self.name_parts: 667 if part.is_realname(): 668 return part 669 return None 670 671 def get_index_part(self) -> Optional[NamePart]: 672 """ 673 INDEX 타입 NamePart 가져오기 674 675 Returns: 676 INDEX 타입의 NamePart 객체, 없으면 None 677 """ 678 for part in self.name_parts: 679 if part.is_index(): 680 return part 681 return None 682 683 def save(self, file_path: Optional[str] = None) -> bool: 684 """ 685 현재 설정을 JSON 파일로 저장 686 687 Args: 688 file_path: 저장할 파일 경로 (기본값: self.default_file_path) 689 690 Returns: 691 저장 성공 여부 (True/False) 692 """ 693 save_path = file_path or self.default_file_path 694 695 try: 696 # 저장할 데이터 준비 697 save_data = { 698 "paddingNum": self.padding_num, 699 "partOrder": self.part_order, # 순서 정보 저장 700 "nameParts": [] 701 } 702 703 # 각 NamePart 객체를 딕셔너리로 변환하여 추가 704 for part in self.name_parts: 705 save_data["nameParts"].append(part.to_dict()) 706 707 # JSON 파일로 저장 708 with open(save_path, 'w', encoding='utf-8') as f: 709 json.dump(save_data, f, indent=4, ensure_ascii=False) 710 711 self.config_file_path = save_path 712 return True 713 except Exception as e: 714 print(f"설정 저장 중 오류 발생: {e}") 715 return False 716 717 def load(self, file_path: Optional[str] = None) -> bool: 718 """ 719 JSON 파일에서 설정 불러오기 720 721 Args: 722 file_path: 불러올 파일 경로 (기본값: self.default_file_path) 723 724 Returns: 725 로드 성공 여부 (True/False) 726 """ 727 load_path = file_path or self.default_file_path 728 729 try: 730 if os.path.exists(load_path): 731 with open(load_path, 'r', encoding='utf-8') as f: 732 loaded_data = json.load(f) 733 734 # 필수 키가 있는지 확인 735 if "nameParts" not in loaded_data: 736 print("경고: 설정 파일에 필수 키 'nameParts'가 없습니다.") 737 return False 738 739 # paddingNum 불러오기 740 if "paddingNum" in loaded_data: 741 self.padding_num = loaded_data["paddingNum"] 742 743 # 파트 순서 불러오기 744 if "partOrder" in loaded_data: 745 self.part_order = loaded_data["partOrder"] 746 else: 747 # 없으면 기본 순서 생성 748 self.part_order = [part_data["name"] for part_data in loaded_data["nameParts"]] 749 750 # NamePart 객체 리스트 생성 751 new_parts = [] 752 for part_data in loaded_data["nameParts"]: 753 part = NamePart.from_dict(part_data) 754 new_parts.append(part) 755 756 # 필수 NamePart가 포함되어 있는지 확인 757 part_names = [part.get_name() for part in new_parts] 758 for required_name in self.required_parts: 759 if required_name not in part_names: 760 print(f"경고: 필수 NamePart '{required_name}'가 설정에 포함되어 있지 않습니다.") 761 return False 762 763 # 모든 확인이 통과되면 데이터 업데이트 764 self.name_parts = new_parts 765 self.config_file_path = load_path 766 767 # 순서에 따라 타입 업데이트 768 self._update_part_types_based_on_order() 769 self._update_part_order() # 순서 업데이트 770 return True 771 else: 772 print(f"설정 파일을 찾을 수 없습니다: {load_path}") 773 return False 774 except Exception as e: 775 print(f"설정 로드 중 오류 발생: {e}") 776 return False 777 778 def apply_to_naming(self, naming_instance) -> bool: 779 """ 780 설정을 Naming 인스턴스에 적용 781 782 Args: 783 naming_instance: 설정을 적용할 Naming 클래스 인스턴스 784 785 Returns: 786 적용 성공 여부 (True/False) 787 """ 788 try: 789 # NamePart 객체 리스트 복사하여 적용 790 naming_instance._nameParts = copy.deepcopy(self.name_parts) 791 792 # paddingNum 설정 793 naming_instance._paddingNum = self.padding_num 794 795 return True 796 except Exception as e: 797 print(f"설정 적용 중 오류 발생: {e}") 798 return False 799 800 def insert_part(self, name: str, part_type: NamePartType, position: int, 801 values: Optional[List[str]] = None, 802 descriptions: Optional[List[str]] = None, 803 korean_descriptions: Optional[List[str]] = None) -> bool: # Add value/description parameters 804 """ 805 특정 위치에 새 NamePart 삽입 806 807 Args: 808 name: 삽입할 NamePart 이름 809 part_type: NamePart 타입 810 position: 삽입할 위치 (인덱스) 811 values: 사전 정의된 값 목록 (기본값: None) # Add doc 812 descriptions: 값에 대한 설명 목록 (기본값: None) # Add doc 813 korean_descriptions: 값에 대한 한국어 설명 목록 (기본값: None) # Add doc 814 815 Returns: 816 삽입 성공 여부 (True/False) 817 """ 818 if not name: 819 print("오류: 유효한 NamePart 이름을 입력하세요.") 820 return False 821 822 # 이미 존재하는지 확인 823 if self.get_part(name) is not None: 824 print(f"오류: '{name}' NamePart가 이미 존재합니다.") 825 return False 826 827 # 위치 범위 확인 828 if position < 0 or position > len(self.name_parts): 829 print(f"오류: 위치가 유효하지 않습니다. 0에서 {len(self.name_parts)} 사이의 값이어야 합니다.") 830 return False 831 832 # 새 NamePart 생성 (값과 설명 포함) 833 new_part = NamePart(name, part_type, values or [], descriptions, False, korean_descriptions) # Pass values/descriptions 834 835 # 지정된 위치에 삽입 836 self.name_parts.insert(position, new_part) 837 838 # 순서 목록 업데이트 839 if name not in self.part_order: 840 self.part_order.insert(position, name) 841 842 # 순서에 따라 타입 업데이트 843 self._update_part_types_based_on_order() 844 return True
21class NamingConfig: 22 """ 23 Naming 클래스의 설정을 관리하는 클래스. 24 NamePart 객체 리스트를 관리하고 JSON 파일로 저장/불러오기 기능 제공. 25 """ 26 27 def __init__(self, padding_num: int = 2, name_parts: Optional[List[NamePart]] = None, 28 config_file_path: str = "", default_file_name: str = "namingConfig.json", 29 required_parts: Optional[List[str]] = None): 30 """ 31 클래스 초기화 및 기본 설정값 정의 32 33 Args: 34 padding_num: 인덱스 패딩 자릿수 (기본값: 2) 35 name_parts: 초기 NamePart 객체 리스트 (기본값: None, 기본 파트로 초기화) 36 config_file_path: 설정 파일 경로 (기본값: 빈 문자열) 37 default_file_name: 기본 파일명 (기본값: "namingConfig.json") 38 required_parts: 필수 namePart 목록 (기본값: ["RealName"]) 39 """ 40 # NamePart 객체 리스트 41 self.name_parts = name_parts or [] 42 43 # 추가 설정 44 self.padding_num = padding_num 45 46 # NamePart 순서 정보 저장 47 self.part_order = [] 48 49 # 필수 namePart 정의 (삭제 불가능) 50 self.required_parts = required_parts or ["RealName"] 51 52 # 설정 파일 경로 및 기본 파일명 53 self.config_file_path = config_file_path 54 self.default_file_name = default_file_name 55 56 # 스크립트 디렉토리 기준 기본 경로 설정 57 script_dir = os.path.dirname(os.path.abspath(__file__)) 58 config_dir = os.path.join(script_dir, "ConfigFiles") 59 self.default_file_path = os.path.join(config_dir, self.default_file_name) 60 61 # name_parts가 제공되지 않은 경우에만 기본 NamePart 초기화 62 if not self.name_parts: 63 self._initialize_default_parts() 64 else: 65 # 제공된 name_parts가 있는 경우 순서 업데이트 및 타입 자동 업데이트 66 self._update_part_order() 67 self._update_part_types_based_on_order() 68 69 def _initialize_default_parts(self): 70 """기본 NamePart 객체들 초기화""" 71 # 기본 순서 정의 (명시적으로 순서를 저장) 72 self.part_order = [] 73 74 # Prefix 부분 (PREFIX 타입) 75 prefixPart = NamePart("Prefix", NamePartType.PREFIX, ["Pr"], ["Prefix"], False, ["접두사"]) # Add korean descriptions 76 77 # RealName 부분 (REALNAME 타입) 78 realNamePart = NamePart("RealName", NamePartType.REALNAME, [], [], False, []) # Add korean descriptions 79 80 # Index 부분 (INDEX 타입) 81 indexPart = NamePart("Index", NamePartType.INDEX, [], [], False, []) # Add korean descriptions 82 83 # Suffix 부분 (SUFFIX 타입) 84 suffixPart = NamePart("Suffix", NamePartType.SUFFIX, ["Su"], ["Suffix"], False, ["접미사"]) # Add korean descriptions 85 86 # 기본 순서대로 설정 87 self.name_parts = [prefixPart, realNamePart, indexPart, suffixPart] 88 89 self._update_part_order() # 초기화 후 순서 업데이트 90 91 # 타입 자동 업데이트 92 self._update_part_types_based_on_order() 93 94 def _update_part_order(self): 95 """ 96 NamePart 순서 업데이트 - 기본적으로 NamePart 객체의 순서에 따라 업데이트 97 """ 98 self.part_order = [part.get_name() for part in self.name_parts] 99 100 def _get_real_name_index(self) -> int: 101 """ 102 RealName 파트의 인덱스를 반환합니다. 103 104 Returns: 105 RealName 파트의 인덱스, 없으면 -1 106 """ 107 for i, part in enumerate(self.name_parts): 108 if part.get_type() == NamePartType.REALNAME: 109 return i 110 return -1 111 112 def _update_part_types_based_on_order(self) -> bool: 113 """ 114 NamePart 순서에 따라 파트의 타입을 자동으로 업데이트합니다. 115 RealName을 기준으로 앞에 있는 파트는 PREFIX, 뒤에 있는 파트는 SUFFIX로 설정합니다. 116 (RealName과 Index 파트는 예외) 117 118 Returns: 119 업데이트 성공 여부 (True/False) 120 """ 121 # RealName 파트 인덱스 찾기 122 real_name_index = self._get_real_name_index() 123 if real_name_index == -1: 124 print("경고: RealName 파트를 찾을 수 없어 타입 자동 업데이트를 수행할 수 없습니다.") 125 return False 126 127 # 각 파트의 타입을 순서에 따라 업데이트 128 for i, part in enumerate(self.name_parts): 129 partName = part.get_name() 130 131 # RealName은 항상 REALNAME 타입 132 if partName == "RealName": 133 part.set_type(NamePartType.REALNAME) 134 continue 135 136 # Index는 항상 INDEX 타입 137 if partName == "Index": 138 part.set_type(NamePartType.INDEX) 139 continue 140 141 # RealName 앞의 파트는 PREFIX, 뒤의 파트는 SUFFIX 142 if i < real_name_index: 143 part.set_type(NamePartType.PREFIX) 144 else: 145 part.set_type(NamePartType.SUFFIX) 146 147 return True 148 149 def get_part_names(self) -> List[str]: 150 """ 151 모든 NamePart 이름 목록 반환 152 153 Returns: 154 NamePart 이름 목록 155 """ 156 return [part.get_name() for part in self.name_parts] 157 158 def get_part_order(self) -> List[str]: 159 """ 160 NamePart 순서 목록 반환 161 162 Returns: 163 NamePart 이름 순서 목록 164 """ 165 return self.part_order.copy() 166 167 def get_part(self, name: str) -> Optional[NamePart]: 168 """ 169 이름으로 NamePart 객체 가져오기 170 171 Args: 172 name: NamePart 이름 173 174 Returns: 175 NamePart 객체, 없으면 None 176 """ 177 for part in self.name_parts: 178 if part.get_name() == name: 179 return part 180 return None 181 182 def add_part(self, name: str, part_type: NamePartType = NamePartType.UNDEFINED, 183 values: Optional[List[str]] = None, descriptions: Optional[List[str]] = None, 184 korean_descriptions: Optional[List[str]] = None) -> bool: # Add korean_descriptions parameter 185 """ 186 새 NamePart 객체 추가 187 188 Args: 189 name: 추가할 NamePart 이름 190 part_type: NamePart 타입 (기본값: UNDEFINED) 191 values: 사전 정의된 값 목록 (기본값: None) 192 descriptions: 값에 대한 설명 목록 (기본값: None, 값과 동일하게 설정됨) 193 korean_descriptions: 값에 대한 한국어 설명 목록 (기본값: None, 값과 동일하게 설정됨) # Add korean_descriptions doc 194 195 Returns: 196 추가 성공 여부 (True/False) 197 """ 198 if not name: 199 print("오류: 유효한 NamePart 이름을 입력하세요.") 200 return False 201 202 # 이미 존재하는지 확인 203 if self.get_part(name) is not None: 204 print(f"오류: '{name}' NamePart가 이미 존재합니다.") 205 return False 206 207 # 새 NamePart 객체 생성 - NamePart 클래스의 생성자 활용 208 new_part = NamePart(name, part_type, values or [], descriptions, False, korean_descriptions) # Pass korean_descriptions 209 210 # 리스트에 추가 211 self.name_parts.append(new_part) 212 213 # 순서 목록에 추가 214 if name not in self.part_order: 215 self.part_order.append(name) 216 217 # 순서에 따라 타입 업데이트 218 self._update_part_types_based_on_order() 219 return True 220 221 def remove_part(self, name: str) -> bool: 222 """ 223 NamePart 객체 제거 (필수 부분은 제거 불가) 224 225 Args: 226 name: 제거할 NamePart 이름 227 228 Returns: 229 제거 성공 여부 (True/False) 230 """ 231 # 필수 부분은 제거 불가능 232 if name in self.required_parts: 233 print(f"오류: 필수 NamePart '{name}'는 제거할 수 없습니다.") 234 return False 235 236 # 찾아서 제거 237 for i, part in enumerate(self.name_parts): 238 if part.get_name() == name: 239 del self.name_parts[i] 240 241 # 순서 목록에서도 제거 242 if name in self.part_order: 243 self.part_order.remove(name) 244 245 # 순서에 따라 타입 업데이트 246 self._update_part_types_based_on_order() 247 return True 248 249 print(f"오류: '{name}' NamePart가 존재하지 않습니다.") 250 return False 251 252 def reorder_parts(self, new_order: List[str]) -> bool: 253 """ 254 NamePart 순서 변경 255 256 Args: 257 new_order: 새로운 NamePart 이름 순서 배열 258 259 Returns: 260 변경 성공 여부 (True/False) 261 """ 262 # 배열 길이 확인 263 if len(new_order) != len(self.name_parts): 264 print("오류: 새 순서의 항목 수가 기존 NamePart와 일치하지 않습니다.") 265 return False 266 267 # 모든 필수 부분이 포함되어 있는지 확인 268 for part in self.required_parts: 269 if part not in new_order: 270 print(f"오류: 필수 NamePart '{part}'가 새 순서에 포함되어 있지 않습니다.") 271 return False 272 273 # 모든 이름이 현재 존재하는지 확인 274 current_names = self.get_part_names() 275 for name in new_order: 276 if name not in current_names: 277 print(f"오류: '{name}' NamePart가 존재하지 않습니다.") 278 return False 279 280 # 순서 변경을 위한 새 리스트 생성 281 reordered_parts = [] 282 for name in new_order: 283 part = self.get_part(name) 284 if part: 285 reordered_parts.append(part) 286 287 # 새 순서로 업데이트 288 self.name_parts = reordered_parts 289 self.part_order = new_order.copy() 290 291 # 순서에 따라 타입 업데이트 292 self._update_part_types_based_on_order() 293 return True 294 295 def set_padding_num(self, padding_num: int) -> bool: 296 """ 297 인덱스 자릿수 설정 298 299 Args: 300 padding_num: 설정할 패딩 자릿수 301 302 Returns: 303 설정 성공 여부 (True/False) 304 """ 305 if not isinstance(padding_num, int) or padding_num < 1: 306 print("오류: 패딩 자릿수는 1 이상의 정수여야 합니다.") 307 return False 308 309 self.padding_num = padding_num 310 return True 311 312 def set_part_type(self, part_name: str, part_type: NamePartType) -> bool: 313 """ 314 특정 NamePart의 타입 설정 315 316 Args: 317 part_name: NamePart 이름 318 part_type: 설정할 타입 (NamePartType 열거형 값) 319 320 Returns: 321 설정 성공 여부 (True/False) 322 """ 323 part = self.get_part(part_name) 324 if not part: 325 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 326 return False 327 328 # 필수 RealName 부분은 항상 REALNAME 타입이어야 함 329 if part_name == "RealName" and part_type != NamePartType.REALNAME: 330 print("오류: RealName 부분은 반드시 REALNAME 타입이어야 합니다.") 331 return False 332 333 # Index 부분은 항상 INDEX 타입이어야 함 334 if part_name == "Index" and part_type != NamePartType.INDEX: 335 print("오류: Index 부분은 반드시 INDEX 타입이어야 합니다.") 336 return False 337 338 part.set_type(part_type) 339 return True 340 341 def get_part_type(self, part_name: str) -> Optional[NamePartType]: 342 """ 343 특정 NamePart의 타입 가져오기 344 345 Args: 346 part_name: NamePart 이름 347 348 Returns: 349 NamePart 타입, 없으면 None 350 """ 351 part = self.get_part(part_name) 352 if not part: 353 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 354 return None 355 356 return part.get_type() 357 358 def set_part_values(self, part_name: str, values: List[str], 359 descriptions: Optional[List[str]] = None, 360 korean_descriptions: Optional[List[str]] = None) -> bool: # Add korean_descriptions parameter 361 """ 362 특정 NamePart의 사전 정의 값 설정 363 364 Args: 365 part_name: NamePart 이름 366 values: 설정할 사전 정의 값 리스트 367 descriptions: 설정할 설명 목록 (기본값: None, 값과 같은 설명 사용) 368 korean_descriptions: 설정할 한국어 설명 목록 (기본값: None, 값과 같은 설명 사용) # Add korean_descriptions doc 369 370 Returns: 371 설정 성공 여부 (True/False) 372 """ 373 part = self.get_part(part_name) 374 if not part: 375 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 376 return False 377 378 # REALNAME이나 INDEX 타입은 사전 정의 값 설정 불가 379 if part.is_realname() or part.is_index(): 380 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 설정할 수 없습니다.") 381 return False 382 383 if not values: 384 print(f"오류: {part_name} 부분의 사전 정의 값은 적어도 하나 이상 있어야 합니다.") 385 return False 386 387 # 값 설정 388 part.set_predefined_values(values, descriptions, korean_descriptions) # Pass korean_descriptions 389 390 return True 391 392 def set_part_value_by_csv(self, part_name: str, csv_file_path: str) -> bool: 393 """ 394 특정 NamePart의 사전 정의 값을 CSV 파일로 설정 395 CSV 파일 형식: value,description,koreanDescription (각 줄당) 396 397 Args: 398 part_name: NamePart 이름 399 csv_file_path: CSV 파일 경로 400 401 Returns: 402 설정 성공 여부 (True/False) 403 """ 404 part = self.get_part(part_name) 405 if not part: 406 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 407 return False 408 409 # REALNAME이나 INDEX 타입은 사전 정의 값 설정 불가 410 if part.is_realname() or part.is_index(): 411 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 설정할 수 없습니다.") 412 return False 413 414 # CSV 파일에서 값, 설명, 한국어 설명 읽기 415 values = [] 416 descriptions = [] 417 korean_descriptions = [] 418 try: 419 with open(csv_file_path, 'r', encoding='utf-8', newline='') as f: 420 reader = csv.reader(f) 421 for row in reader: 422 if len(row) >= 3: # Ensure row has at least 3 columns 423 value = row[0].strip() 424 description = row[1].strip() 425 korean_description = row[2].strip() 426 if value: # Skip empty values 427 values.append(value) 428 descriptions.append(description if description else value) # Use value if description is empty 429 korean_descriptions.append(korean_description if korean_description else value) # Use value if korean_description is empty 430 elif len(row) == 2: # Handle case with value and description only 431 value = row[0].strip() 432 description = row[1].strip() 433 if value: 434 values.append(value) 435 descriptions.append(description if description else value) 436 korean_descriptions.append(value) # Use value as korean description 437 elif len(row) == 1: # Handle case with value only 438 value = row[0].strip() 439 if value: 440 values.append(value) 441 descriptions.append(value) 442 korean_descriptions.append(value) 443 444 if not values: 445 print(f"오류: CSV 파일 '{csv_file_path}'에서 유효한 값을 찾을 수 없습니다.") 446 return False 447 448 # 값, 설명, 한국어 설명 설정 449 return self.set_part_values(part_name, values, descriptions, korean_descriptions) 450 except FileNotFoundError: 451 print(f"오류: CSV 파일을 찾을 수 없습니다: {csv_file_path}") 452 return False 453 except Exception as e: 454 print(f"오류: CSV 파일을 읽는 중 오류 발생: {e}") 455 return False 456 457 def add_part_value(self, part_name: str, value: str, 458 description: Optional[str] = None, 459 korean_description: Optional[str] = None) -> bool: # Add korean_description parameter 460 """ 461 특정 NamePart에 사전 정의 값 추가 462 463 Args: 464 part_name: NamePart 이름 465 value: 추가할 사전 정의 값 466 description: 추가할 값의 설명 (기본값: None, 값과 같은 설명 사용) 467 korean_description: 추가할 값의 한국어 설명 (기본값: None, 값과 같은 설명 사용) # Add korean_description doc 468 469 Returns: 470 추가 성공 여부 (True/False) 471 """ 472 part = self.get_part(part_name) 473 if not part: 474 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 475 return False 476 477 # REALNAME이나 INDEX 타입은 사전 정의 값 추가 불가 478 if part.is_realname() or part.is_index(): 479 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 추가할 수 없습니다.") 480 return False 481 482 # 값이 이미 존재하는지 확인 483 if part.contains_value(value): 484 print(f"오류: '{value}'가 이미 {part_name} 부분의 사전 정의 값에 존재합니다.") 485 return False 486 487 # description이 없으면 값을 설명으로 사용 488 if description is None: 489 description = value 490 491 # korean_description이 없으면 값을 설명으로 사용 492 if korean_description is None: 493 korean_description = value 494 495 # NamePart 클래스의 add_predefined_value 메소드 직접 활용 496 return part.add_predefined_value(value, description, korean_description) # Pass korean_description 497 498 def remove_part_value(self, part_name: str, value: str) -> bool: 499 """ 500 특정 NamePart에서 사전 정의 값과 해당 설명 제거 501 502 Args: 503 part_name: NamePart 이름 504 value: 제거할 사전 정의 값 505 506 Returns: 507 제거 성공 여부 (True/False) 508 """ 509 part = self.get_part(part_name) 510 if not part: 511 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 512 return False 513 514 # REALNAME이나 INDEX 타입은 사전 정의 값 제거 불가 515 if part.is_realname() or part.is_index(): 516 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 제거할 수 없습니다.") 517 return False 518 519 # 값이 존재하는지 확인 520 if not part.contains_value(value): 521 print(f"오류: '{value}'가 {part_name} 부분의 사전 정의 값에 존재하지 않습니다.") 522 return False 523 524 # 마지막 값인지 확인 525 if part.get_value_count() <= 1: 526 print(f"오류: {part_name} 부분의 사전 정의 값은 적어도 하나 이상 있어야 합니다.") 527 return False 528 529 # NamePart 클래스의 remove_predefined_value 메소드 직접 활용 530 return part.remove_predefined_value(value) 531 532 def set_part_descriptions(self, part_name: str, descriptions: List[str]) -> bool: 533 """ 534 특정 NamePart의 설명 목록 설정 535 536 Args: 537 part_name: NamePart 이름 538 descriptions: 설정할 설명 목록 539 540 Returns: 541 설정 성공 여부 (True/False) 542 """ 543 part = self.get_part(part_name) 544 if not part: 545 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 546 return False 547 548 # REALNAME이나 INDEX 타입은 설명 설정 불가 549 if part.is_realname() or part.is_index(): 550 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 설명을 설정할 수 없습니다.") 551 return False 552 553 # NamePart 클래스 메소드 활용하여 설명 설정 554 values = part.get_predefined_values() 555 556 # 길이 맞추기 557 if len(descriptions) < len(values): 558 descriptions.extend([""] * (len(values) - len(descriptions))) 559 elif len(descriptions) > len(values): 560 descriptions = descriptions[:len(values)] 561 562 # 각 값에 대한 설명 설정 (NamePart.set_description 사용) 563 success = True 564 for i, value in enumerate(values): 565 if not part.set_description(value, descriptions[i]): 566 success = False # 실패 시 기록 (이론상 발생하지 않음) 567 568 return success 569 570 def get_part_descriptions(self, part_name: str) -> List[str]: 571 """ 572 특정 NamePart의 설명 목록 가져오기 573 574 Args: 575 part_name: NamePart 이름 576 577 Returns: 578 설명 목록 579 """ 580 part = self.get_part(part_name) 581 if not part: 582 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 583 return [] 584 585 return part.get_descriptions() 586 587 def set_part_korean_descriptions(self, part_name: str, korean_descriptions: List[str]) -> bool: 588 """ 589 특정 NamePart의 한국어 설명 목록 설정 590 591 Args: 592 part_name: NamePart 이름 593 korean_descriptions: 설정할 한국어 설명 목록 594 595 Returns: 596 설정 성공 여부 (True/False) 597 """ 598 part = self.get_part(part_name) 599 if not part: 600 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 601 return False 602 603 # REALNAME이나 INDEX 타입은 설명 설정 불가 604 if part.is_realname() or part.is_index(): 605 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 한국어 설명을 설정할 수 없습니다.") 606 return False 607 608 # NamePart 클래스 메소드 활용하여 설명 설정 609 values = part.get_predefined_values() 610 611 # 길이 맞추기 612 if len(korean_descriptions) < len(values): 613 korean_descriptions.extend([""] * (len(values) - len(korean_descriptions))) 614 elif len(korean_descriptions) > len(values): 615 korean_descriptions = korean_descriptions[:len(values)] 616 617 # 각 값에 대한 한국어 설명 설정 (NamePart.set_korean_description 사용) 618 success = True 619 for i, value in enumerate(values): 620 if not part.set_korean_description(value, korean_descriptions[i]): 621 success = False # 실패 시 기록 (이론상 발생하지 않음) 622 623 return success 624 625 def get_part_korean_descriptions(self, part_name: str) -> List[str]: 626 """ 627 특정 NamePart의 한국어 설명 목록 가져오기 628 629 Args: 630 part_name: NamePart 이름 631 632 Returns: 633 한국어 설명 목록 634 """ 635 part = self.get_part(part_name) 636 if not part: 637 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 638 return [] 639 640 return part.get_korean_descriptions() 641 642 def get_prefix_parts(self) -> List[NamePart]: 643 """ 644 모든 PREFIX 타입 NamePart 가져오기 645 646 Returns: 647 PREFIX 타입의 NamePart 객체 리스트 648 """ 649 return [part for part in self.name_parts if part.is_prefix()] 650 651 def get_suffix_parts(self) -> List[NamePart]: 652 """ 653 모든 SUFFIX 타입 NamePart 가져오기 654 655 Returns: 656 SUFFIX 타입의 NamePart 객체 리스트 657 """ 658 return [part for part in self.name_parts if part.is_suffix()] 659 660 def get_realname_part(self) -> Optional[NamePart]: 661 """ 662 REALNAME 타입 NamePart 가져오기 663 664 Returns: 665 REALNAME 타입의 NamePart 객체, 없으면 None 666 """ 667 for part in self.name_parts: 668 if part.is_realname(): 669 return part 670 return None 671 672 def get_index_part(self) -> Optional[NamePart]: 673 """ 674 INDEX 타입 NamePart 가져오기 675 676 Returns: 677 INDEX 타입의 NamePart 객체, 없으면 None 678 """ 679 for part in self.name_parts: 680 if part.is_index(): 681 return part 682 return None 683 684 def save(self, file_path: Optional[str] = None) -> bool: 685 """ 686 현재 설정을 JSON 파일로 저장 687 688 Args: 689 file_path: 저장할 파일 경로 (기본값: self.default_file_path) 690 691 Returns: 692 저장 성공 여부 (True/False) 693 """ 694 save_path = file_path or self.default_file_path 695 696 try: 697 # 저장할 데이터 준비 698 save_data = { 699 "paddingNum": self.padding_num, 700 "partOrder": self.part_order, # 순서 정보 저장 701 "nameParts": [] 702 } 703 704 # 각 NamePart 객체를 딕셔너리로 변환하여 추가 705 for part in self.name_parts: 706 save_data["nameParts"].append(part.to_dict()) 707 708 # JSON 파일로 저장 709 with open(save_path, 'w', encoding='utf-8') as f: 710 json.dump(save_data, f, indent=4, ensure_ascii=False) 711 712 self.config_file_path = save_path 713 return True 714 except Exception as e: 715 print(f"설정 저장 중 오류 발생: {e}") 716 return False 717 718 def load(self, file_path: Optional[str] = None) -> bool: 719 """ 720 JSON 파일에서 설정 불러오기 721 722 Args: 723 file_path: 불러올 파일 경로 (기본값: self.default_file_path) 724 725 Returns: 726 로드 성공 여부 (True/False) 727 """ 728 load_path = file_path or self.default_file_path 729 730 try: 731 if os.path.exists(load_path): 732 with open(load_path, 'r', encoding='utf-8') as f: 733 loaded_data = json.load(f) 734 735 # 필수 키가 있는지 확인 736 if "nameParts" not in loaded_data: 737 print("경고: 설정 파일에 필수 키 'nameParts'가 없습니다.") 738 return False 739 740 # paddingNum 불러오기 741 if "paddingNum" in loaded_data: 742 self.padding_num = loaded_data["paddingNum"] 743 744 # 파트 순서 불러오기 745 if "partOrder" in loaded_data: 746 self.part_order = loaded_data["partOrder"] 747 else: 748 # 없으면 기본 순서 생성 749 self.part_order = [part_data["name"] for part_data in loaded_data["nameParts"]] 750 751 # NamePart 객체 리스트 생성 752 new_parts = [] 753 for part_data in loaded_data["nameParts"]: 754 part = NamePart.from_dict(part_data) 755 new_parts.append(part) 756 757 # 필수 NamePart가 포함되어 있는지 확인 758 part_names = [part.get_name() for part in new_parts] 759 for required_name in self.required_parts: 760 if required_name not in part_names: 761 print(f"경고: 필수 NamePart '{required_name}'가 설정에 포함되어 있지 않습니다.") 762 return False 763 764 # 모든 확인이 통과되면 데이터 업데이트 765 self.name_parts = new_parts 766 self.config_file_path = load_path 767 768 # 순서에 따라 타입 업데이트 769 self._update_part_types_based_on_order() 770 self._update_part_order() # 순서 업데이트 771 return True 772 else: 773 print(f"설정 파일을 찾을 수 없습니다: {load_path}") 774 return False 775 except Exception as e: 776 print(f"설정 로드 중 오류 발생: {e}") 777 return False 778 779 def apply_to_naming(self, naming_instance) -> bool: 780 """ 781 설정을 Naming 인스턴스에 적용 782 783 Args: 784 naming_instance: 설정을 적용할 Naming 클래스 인스턴스 785 786 Returns: 787 적용 성공 여부 (True/False) 788 """ 789 try: 790 # NamePart 객체 리스트 복사하여 적용 791 naming_instance._nameParts = copy.deepcopy(self.name_parts) 792 793 # paddingNum 설정 794 naming_instance._paddingNum = self.padding_num 795 796 return True 797 except Exception as e: 798 print(f"설정 적용 중 오류 발생: {e}") 799 return False 800 801 def insert_part(self, name: str, part_type: NamePartType, position: int, 802 values: Optional[List[str]] = None, 803 descriptions: Optional[List[str]] = None, 804 korean_descriptions: Optional[List[str]] = None) -> bool: # Add value/description parameters 805 """ 806 특정 위치에 새 NamePart 삽입 807 808 Args: 809 name: 삽입할 NamePart 이름 810 part_type: NamePart 타입 811 position: 삽입할 위치 (인덱스) 812 values: 사전 정의된 값 목록 (기본값: None) # Add doc 813 descriptions: 값에 대한 설명 목록 (기본값: None) # Add doc 814 korean_descriptions: 값에 대한 한국어 설명 목록 (기본값: None) # Add doc 815 816 Returns: 817 삽입 성공 여부 (True/False) 818 """ 819 if not name: 820 print("오류: 유효한 NamePart 이름을 입력하세요.") 821 return False 822 823 # 이미 존재하는지 확인 824 if self.get_part(name) is not None: 825 print(f"오류: '{name}' NamePart가 이미 존재합니다.") 826 return False 827 828 # 위치 범위 확인 829 if position < 0 or position > len(self.name_parts): 830 print(f"오류: 위치가 유효하지 않습니다. 0에서 {len(self.name_parts)} 사이의 값이어야 합니다.") 831 return False 832 833 # 새 NamePart 생성 (값과 설명 포함) 834 new_part = NamePart(name, part_type, values or [], descriptions, False, korean_descriptions) # Pass values/descriptions 835 836 # 지정된 위치에 삽입 837 self.name_parts.insert(position, new_part) 838 839 # 순서 목록 업데이트 840 if name not in self.part_order: 841 self.part_order.insert(position, name) 842 843 # 순서에 따라 타입 업데이트 844 self._update_part_types_based_on_order() 845 return True
Naming 클래스의 설정을 관리하는 클래스. NamePart 객체 리스트를 관리하고 JSON 파일로 저장/불러오기 기능 제공.
27 def __init__(self, padding_num: int = 2, name_parts: Optional[List[NamePart]] = None, 28 config_file_path: str = "", default_file_name: str = "namingConfig.json", 29 required_parts: Optional[List[str]] = None): 30 """ 31 클래스 초기화 및 기본 설정값 정의 32 33 Args: 34 padding_num: 인덱스 패딩 자릿수 (기본값: 2) 35 name_parts: 초기 NamePart 객체 리스트 (기본값: None, 기본 파트로 초기화) 36 config_file_path: 설정 파일 경로 (기본값: 빈 문자열) 37 default_file_name: 기본 파일명 (기본값: "namingConfig.json") 38 required_parts: 필수 namePart 목록 (기본값: ["RealName"]) 39 """ 40 # NamePart 객체 리스트 41 self.name_parts = name_parts or [] 42 43 # 추가 설정 44 self.padding_num = padding_num 45 46 # NamePart 순서 정보 저장 47 self.part_order = [] 48 49 # 필수 namePart 정의 (삭제 불가능) 50 self.required_parts = required_parts or ["RealName"] 51 52 # 설정 파일 경로 및 기본 파일명 53 self.config_file_path = config_file_path 54 self.default_file_name = default_file_name 55 56 # 스크립트 디렉토리 기준 기본 경로 설정 57 script_dir = os.path.dirname(os.path.abspath(__file__)) 58 config_dir = os.path.join(script_dir, "ConfigFiles") 59 self.default_file_path = os.path.join(config_dir, self.default_file_name) 60 61 # name_parts가 제공되지 않은 경우에만 기본 NamePart 초기화 62 if not self.name_parts: 63 self._initialize_default_parts() 64 else: 65 # 제공된 name_parts가 있는 경우 순서 업데이트 및 타입 자동 업데이트 66 self._update_part_order() 67 self._update_part_types_based_on_order()
클래스 초기화 및 기본 설정값 정의
Args: padding_num: 인덱스 패딩 자릿수 (기본값: 2) name_parts: 초기 NamePart 객체 리스트 (기본값: None, 기본 파트로 초기화) config_file_path: 설정 파일 경로 (기본값: 빈 문자열) default_file_name: 기본 파일명 (기본값: "namingConfig.json") required_parts: 필수 namePart 목록 (기본값: ["RealName"])
149 def get_part_names(self) -> List[str]: 150 """ 151 모든 NamePart 이름 목록 반환 152 153 Returns: 154 NamePart 이름 목록 155 """ 156 return [part.get_name() for part in self.name_parts]
모든 NamePart 이름 목록 반환
Returns: NamePart 이름 목록
158 def get_part_order(self) -> List[str]: 159 """ 160 NamePart 순서 목록 반환 161 162 Returns: 163 NamePart 이름 순서 목록 164 """ 165 return self.part_order.copy()
NamePart 순서 목록 반환
Returns: NamePart 이름 순서 목록
167 def get_part(self, name: str) -> Optional[NamePart]: 168 """ 169 이름으로 NamePart 객체 가져오기 170 171 Args: 172 name: NamePart 이름 173 174 Returns: 175 NamePart 객체, 없으면 None 176 """ 177 for part in self.name_parts: 178 if part.get_name() == name: 179 return part 180 return None
이름으로 NamePart 객체 가져오기
Args: name: NamePart 이름
Returns: NamePart 객체, 없으면 None
182 def add_part(self, name: str, part_type: NamePartType = NamePartType.UNDEFINED, 183 values: Optional[List[str]] = None, descriptions: Optional[List[str]] = None, 184 korean_descriptions: Optional[List[str]] = None) -> bool: # Add korean_descriptions parameter 185 """ 186 새 NamePart 객체 추가 187 188 Args: 189 name: 추가할 NamePart 이름 190 part_type: NamePart 타입 (기본값: UNDEFINED) 191 values: 사전 정의된 값 목록 (기본값: None) 192 descriptions: 값에 대한 설명 목록 (기본값: None, 값과 동일하게 설정됨) 193 korean_descriptions: 값에 대한 한국어 설명 목록 (기본값: None, 값과 동일하게 설정됨) # Add korean_descriptions doc 194 195 Returns: 196 추가 성공 여부 (True/False) 197 """ 198 if not name: 199 print("오류: 유효한 NamePart 이름을 입력하세요.") 200 return False 201 202 # 이미 존재하는지 확인 203 if self.get_part(name) is not None: 204 print(f"오류: '{name}' NamePart가 이미 존재합니다.") 205 return False 206 207 # 새 NamePart 객체 생성 - NamePart 클래스의 생성자 활용 208 new_part = NamePart(name, part_type, values or [], descriptions, False, korean_descriptions) # Pass korean_descriptions 209 210 # 리스트에 추가 211 self.name_parts.append(new_part) 212 213 # 순서 목록에 추가 214 if name not in self.part_order: 215 self.part_order.append(name) 216 217 # 순서에 따라 타입 업데이트 218 self._update_part_types_based_on_order() 219 return True
새 NamePart 객체 추가
Args: name: 추가할 NamePart 이름 part_type: NamePart 타입 (기본값: UNDEFINED) values: 사전 정의된 값 목록 (기본값: None) descriptions: 값에 대한 설명 목록 (기본값: None, 값과 동일하게 설정됨) korean_descriptions: 값에 대한 한국어 설명 목록 (기본값: None, 값과 동일하게 설정됨) # Add korean_descriptions doc
Returns: 추가 성공 여부 (True/False)
221 def remove_part(self, name: str) -> bool: 222 """ 223 NamePart 객체 제거 (필수 부분은 제거 불가) 224 225 Args: 226 name: 제거할 NamePart 이름 227 228 Returns: 229 제거 성공 여부 (True/False) 230 """ 231 # 필수 부분은 제거 불가능 232 if name in self.required_parts: 233 print(f"오류: 필수 NamePart '{name}'는 제거할 수 없습니다.") 234 return False 235 236 # 찾아서 제거 237 for i, part in enumerate(self.name_parts): 238 if part.get_name() == name: 239 del self.name_parts[i] 240 241 # 순서 목록에서도 제거 242 if name in self.part_order: 243 self.part_order.remove(name) 244 245 # 순서에 따라 타입 업데이트 246 self._update_part_types_based_on_order() 247 return True 248 249 print(f"오류: '{name}' NamePart가 존재하지 않습니다.") 250 return False
NamePart 객체 제거 (필수 부분은 제거 불가)
Args: name: 제거할 NamePart 이름
Returns: 제거 성공 여부 (True/False)
252 def reorder_parts(self, new_order: List[str]) -> bool: 253 """ 254 NamePart 순서 변경 255 256 Args: 257 new_order: 새로운 NamePart 이름 순서 배열 258 259 Returns: 260 변경 성공 여부 (True/False) 261 """ 262 # 배열 길이 확인 263 if len(new_order) != len(self.name_parts): 264 print("오류: 새 순서의 항목 수가 기존 NamePart와 일치하지 않습니다.") 265 return False 266 267 # 모든 필수 부분이 포함되어 있는지 확인 268 for part in self.required_parts: 269 if part not in new_order: 270 print(f"오류: 필수 NamePart '{part}'가 새 순서에 포함되어 있지 않습니다.") 271 return False 272 273 # 모든 이름이 현재 존재하는지 확인 274 current_names = self.get_part_names() 275 for name in new_order: 276 if name not in current_names: 277 print(f"오류: '{name}' NamePart가 존재하지 않습니다.") 278 return False 279 280 # 순서 변경을 위한 새 리스트 생성 281 reordered_parts = [] 282 for name in new_order: 283 part = self.get_part(name) 284 if part: 285 reordered_parts.append(part) 286 287 # 새 순서로 업데이트 288 self.name_parts = reordered_parts 289 self.part_order = new_order.copy() 290 291 # 순서에 따라 타입 업데이트 292 self._update_part_types_based_on_order() 293 return True
NamePart 순서 변경
Args: new_order: 새로운 NamePart 이름 순서 배열
Returns: 변경 성공 여부 (True/False)
295 def set_padding_num(self, padding_num: int) -> bool: 296 """ 297 인덱스 자릿수 설정 298 299 Args: 300 padding_num: 설정할 패딩 자릿수 301 302 Returns: 303 설정 성공 여부 (True/False) 304 """ 305 if not isinstance(padding_num, int) or padding_num < 1: 306 print("오류: 패딩 자릿수는 1 이상의 정수여야 합니다.") 307 return False 308 309 self.padding_num = padding_num 310 return True
인덱스 자릿수 설정
Args: padding_num: 설정할 패딩 자릿수
Returns: 설정 성공 여부 (True/False)
312 def set_part_type(self, part_name: str, part_type: NamePartType) -> bool: 313 """ 314 특정 NamePart의 타입 설정 315 316 Args: 317 part_name: NamePart 이름 318 part_type: 설정할 타입 (NamePartType 열거형 값) 319 320 Returns: 321 설정 성공 여부 (True/False) 322 """ 323 part = self.get_part(part_name) 324 if not part: 325 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 326 return False 327 328 # 필수 RealName 부분은 항상 REALNAME 타입이어야 함 329 if part_name == "RealName" and part_type != NamePartType.REALNAME: 330 print("오류: RealName 부분은 반드시 REALNAME 타입이어야 합니다.") 331 return False 332 333 # Index 부분은 항상 INDEX 타입이어야 함 334 if part_name == "Index" and part_type != NamePartType.INDEX: 335 print("오류: Index 부분은 반드시 INDEX 타입이어야 합니다.") 336 return False 337 338 part.set_type(part_type) 339 return True
특정 NamePart의 타입 설정
Args: part_name: NamePart 이름 part_type: 설정할 타입 (NamePartType 열거형 값)
Returns: 설정 성공 여부 (True/False)
341 def get_part_type(self, part_name: str) -> Optional[NamePartType]: 342 """ 343 특정 NamePart의 타입 가져오기 344 345 Args: 346 part_name: NamePart 이름 347 348 Returns: 349 NamePart 타입, 없으면 None 350 """ 351 part = self.get_part(part_name) 352 if not part: 353 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 354 return None 355 356 return part.get_type()
특정 NamePart의 타입 가져오기
Args: part_name: NamePart 이름
Returns: NamePart 타입, 없으면 None
358 def set_part_values(self, part_name: str, values: List[str], 359 descriptions: Optional[List[str]] = None, 360 korean_descriptions: Optional[List[str]] = None) -> bool: # Add korean_descriptions parameter 361 """ 362 특정 NamePart의 사전 정의 값 설정 363 364 Args: 365 part_name: NamePart 이름 366 values: 설정할 사전 정의 값 리스트 367 descriptions: 설정할 설명 목록 (기본값: None, 값과 같은 설명 사용) 368 korean_descriptions: 설정할 한국어 설명 목록 (기본값: None, 값과 같은 설명 사용) # Add korean_descriptions doc 369 370 Returns: 371 설정 성공 여부 (True/False) 372 """ 373 part = self.get_part(part_name) 374 if not part: 375 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 376 return False 377 378 # REALNAME이나 INDEX 타입은 사전 정의 값 설정 불가 379 if part.is_realname() or part.is_index(): 380 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 설정할 수 없습니다.") 381 return False 382 383 if not values: 384 print(f"오류: {part_name} 부분의 사전 정의 값은 적어도 하나 이상 있어야 합니다.") 385 return False 386 387 # 값 설정 388 part.set_predefined_values(values, descriptions, korean_descriptions) # Pass korean_descriptions 389 390 return True
특정 NamePart의 사전 정의 값 설정
Args: part_name: NamePart 이름 values: 설정할 사전 정의 값 리스트 descriptions: 설정할 설명 목록 (기본값: None, 값과 같은 설명 사용) korean_descriptions: 설정할 한국어 설명 목록 (기본값: None, 값과 같은 설명 사용) # Add korean_descriptions doc
Returns: 설정 성공 여부 (True/False)
392 def set_part_value_by_csv(self, part_name: str, csv_file_path: str) -> bool: 393 """ 394 특정 NamePart의 사전 정의 값을 CSV 파일로 설정 395 CSV 파일 형식: value,description,koreanDescription (각 줄당) 396 397 Args: 398 part_name: NamePart 이름 399 csv_file_path: CSV 파일 경로 400 401 Returns: 402 설정 성공 여부 (True/False) 403 """ 404 part = self.get_part(part_name) 405 if not part: 406 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 407 return False 408 409 # REALNAME이나 INDEX 타입은 사전 정의 값 설정 불가 410 if part.is_realname() or part.is_index(): 411 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 설정할 수 없습니다.") 412 return False 413 414 # CSV 파일에서 값, 설명, 한국어 설명 읽기 415 values = [] 416 descriptions = [] 417 korean_descriptions = [] 418 try: 419 with open(csv_file_path, 'r', encoding='utf-8', newline='') as f: 420 reader = csv.reader(f) 421 for row in reader: 422 if len(row) >= 3: # Ensure row has at least 3 columns 423 value = row[0].strip() 424 description = row[1].strip() 425 korean_description = row[2].strip() 426 if value: # Skip empty values 427 values.append(value) 428 descriptions.append(description if description else value) # Use value if description is empty 429 korean_descriptions.append(korean_description if korean_description else value) # Use value if korean_description is empty 430 elif len(row) == 2: # Handle case with value and description only 431 value = row[0].strip() 432 description = row[1].strip() 433 if value: 434 values.append(value) 435 descriptions.append(description if description else value) 436 korean_descriptions.append(value) # Use value as korean description 437 elif len(row) == 1: # Handle case with value only 438 value = row[0].strip() 439 if value: 440 values.append(value) 441 descriptions.append(value) 442 korean_descriptions.append(value) 443 444 if not values: 445 print(f"오류: CSV 파일 '{csv_file_path}'에서 유효한 값을 찾을 수 없습니다.") 446 return False 447 448 # 값, 설명, 한국어 설명 설정 449 return self.set_part_values(part_name, values, descriptions, korean_descriptions) 450 except FileNotFoundError: 451 print(f"오류: CSV 파일을 찾을 수 없습니다: {csv_file_path}") 452 return False 453 except Exception as e: 454 print(f"오류: CSV 파일을 읽는 중 오류 발생: {e}") 455 return False
특정 NamePart의 사전 정의 값을 CSV 파일로 설정 CSV 파일 형식: value,description,koreanDescription (각 줄당)
Args: part_name: NamePart 이름 csv_file_path: CSV 파일 경로
Returns: 설정 성공 여부 (True/False)
457 def add_part_value(self, part_name: str, value: str, 458 description: Optional[str] = None, 459 korean_description: Optional[str] = None) -> bool: # Add korean_description parameter 460 """ 461 특정 NamePart에 사전 정의 값 추가 462 463 Args: 464 part_name: NamePart 이름 465 value: 추가할 사전 정의 값 466 description: 추가할 값의 설명 (기본값: None, 값과 같은 설명 사용) 467 korean_description: 추가할 값의 한국어 설명 (기본값: None, 값과 같은 설명 사용) # Add korean_description doc 468 469 Returns: 470 추가 성공 여부 (True/False) 471 """ 472 part = self.get_part(part_name) 473 if not part: 474 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 475 return False 476 477 # REALNAME이나 INDEX 타입은 사전 정의 값 추가 불가 478 if part.is_realname() or part.is_index(): 479 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 추가할 수 없습니다.") 480 return False 481 482 # 값이 이미 존재하는지 확인 483 if part.contains_value(value): 484 print(f"오류: '{value}'가 이미 {part_name} 부분의 사전 정의 값에 존재합니다.") 485 return False 486 487 # description이 없으면 값을 설명으로 사용 488 if description is None: 489 description = value 490 491 # korean_description이 없으면 값을 설명으로 사용 492 if korean_description is None: 493 korean_description = value 494 495 # NamePart 클래스의 add_predefined_value 메소드 직접 활용 496 return part.add_predefined_value(value, description, korean_description) # Pass korean_description
특정 NamePart에 사전 정의 값 추가
Args: part_name: NamePart 이름 value: 추가할 사전 정의 값 description: 추가할 값의 설명 (기본값: None, 값과 같은 설명 사용) korean_description: 추가할 값의 한국어 설명 (기본값: None, 값과 같은 설명 사용) # Add korean_description doc
Returns: 추가 성공 여부 (True/False)
498 def remove_part_value(self, part_name: str, value: str) -> bool: 499 """ 500 특정 NamePart에서 사전 정의 값과 해당 설명 제거 501 502 Args: 503 part_name: NamePart 이름 504 value: 제거할 사전 정의 값 505 506 Returns: 507 제거 성공 여부 (True/False) 508 """ 509 part = self.get_part(part_name) 510 if not part: 511 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 512 return False 513 514 # REALNAME이나 INDEX 타입은 사전 정의 값 제거 불가 515 if part.is_realname() or part.is_index(): 516 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 사전 정의 값을 제거할 수 없습니다.") 517 return False 518 519 # 값이 존재하는지 확인 520 if not part.contains_value(value): 521 print(f"오류: '{value}'가 {part_name} 부분의 사전 정의 값에 존재하지 않습니다.") 522 return False 523 524 # 마지막 값인지 확인 525 if part.get_value_count() <= 1: 526 print(f"오류: {part_name} 부분의 사전 정의 값은 적어도 하나 이상 있어야 합니다.") 527 return False 528 529 # NamePart 클래스의 remove_predefined_value 메소드 직접 활용 530 return part.remove_predefined_value(value)
특정 NamePart에서 사전 정의 값과 해당 설명 제거
Args: part_name: NamePart 이름 value: 제거할 사전 정의 값
Returns: 제거 성공 여부 (True/False)
532 def set_part_descriptions(self, part_name: str, descriptions: List[str]) -> bool: 533 """ 534 특정 NamePart의 설명 목록 설정 535 536 Args: 537 part_name: NamePart 이름 538 descriptions: 설정할 설명 목록 539 540 Returns: 541 설정 성공 여부 (True/False) 542 """ 543 part = self.get_part(part_name) 544 if not part: 545 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 546 return False 547 548 # REALNAME이나 INDEX 타입은 설명 설정 불가 549 if part.is_realname() or part.is_index(): 550 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 설명을 설정할 수 없습니다.") 551 return False 552 553 # NamePart 클래스 메소드 활용하여 설명 설정 554 values = part.get_predefined_values() 555 556 # 길이 맞추기 557 if len(descriptions) < len(values): 558 descriptions.extend([""] * (len(values) - len(descriptions))) 559 elif len(descriptions) > len(values): 560 descriptions = descriptions[:len(values)] 561 562 # 각 값에 대한 설명 설정 (NamePart.set_description 사용) 563 success = True 564 for i, value in enumerate(values): 565 if not part.set_description(value, descriptions[i]): 566 success = False # 실패 시 기록 (이론상 발생하지 않음) 567 568 return success
특정 NamePart의 설명 목록 설정
Args: part_name: NamePart 이름 descriptions: 설정할 설명 목록
Returns: 설정 성공 여부 (True/False)
570 def get_part_descriptions(self, part_name: str) -> List[str]: 571 """ 572 특정 NamePart의 설명 목록 가져오기 573 574 Args: 575 part_name: NamePart 이름 576 577 Returns: 578 설명 목록 579 """ 580 part = self.get_part(part_name) 581 if not part: 582 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 583 return [] 584 585 return part.get_descriptions()
특정 NamePart의 설명 목록 가져오기
Args: part_name: NamePart 이름
Returns: 설명 목록
587 def set_part_korean_descriptions(self, part_name: str, korean_descriptions: List[str]) -> bool: 588 """ 589 특정 NamePart의 한국어 설명 목록 설정 590 591 Args: 592 part_name: NamePart 이름 593 korean_descriptions: 설정할 한국어 설명 목록 594 595 Returns: 596 설정 성공 여부 (True/False) 597 """ 598 part = self.get_part(part_name) 599 if not part: 600 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 601 return False 602 603 # REALNAME이나 INDEX 타입은 설명 설정 불가 604 if part.is_realname() or part.is_index(): 605 print(f"오류: {part_name} 부분은 {part.get_type().name} 타입이므로 한국어 설명을 설정할 수 없습니다.") 606 return False 607 608 # NamePart 클래스 메소드 활용하여 설명 설정 609 values = part.get_predefined_values() 610 611 # 길이 맞추기 612 if len(korean_descriptions) < len(values): 613 korean_descriptions.extend([""] * (len(values) - len(korean_descriptions))) 614 elif len(korean_descriptions) > len(values): 615 korean_descriptions = korean_descriptions[:len(values)] 616 617 # 각 값에 대한 한국어 설명 설정 (NamePart.set_korean_description 사용) 618 success = True 619 for i, value in enumerate(values): 620 if not part.set_korean_description(value, korean_descriptions[i]): 621 success = False # 실패 시 기록 (이론상 발생하지 않음) 622 623 return success
특정 NamePart의 한국어 설명 목록 설정
Args: part_name: NamePart 이름 korean_descriptions: 설정할 한국어 설명 목록
Returns: 설정 성공 여부 (True/False)
625 def get_part_korean_descriptions(self, part_name: str) -> List[str]: 626 """ 627 특정 NamePart의 한국어 설명 목록 가져오기 628 629 Args: 630 part_name: NamePart 이름 631 632 Returns: 633 한국어 설명 목록 634 """ 635 part = self.get_part(part_name) 636 if not part: 637 print(f"오류: '{part_name}' NamePart가 존재하지 않습니다.") 638 return [] 639 640 return part.get_korean_descriptions()
특정 NamePart의 한국어 설명 목록 가져오기
Args: part_name: NamePart 이름
Returns: 한국어 설명 목록
642 def get_prefix_parts(self) -> List[NamePart]: 643 """ 644 모든 PREFIX 타입 NamePart 가져오기 645 646 Returns: 647 PREFIX 타입의 NamePart 객체 리스트 648 """ 649 return [part for part in self.name_parts if part.is_prefix()]
모든 PREFIX 타입 NamePart 가져오기
Returns: PREFIX 타입의 NamePart 객체 리스트
651 def get_suffix_parts(self) -> List[NamePart]: 652 """ 653 모든 SUFFIX 타입 NamePart 가져오기 654 655 Returns: 656 SUFFIX 타입의 NamePart 객체 리스트 657 """ 658 return [part for part in self.name_parts if part.is_suffix()]
모든 SUFFIX 타입 NamePart 가져오기
Returns: SUFFIX 타입의 NamePart 객체 리스트
660 def get_realname_part(self) -> Optional[NamePart]: 661 """ 662 REALNAME 타입 NamePart 가져오기 663 664 Returns: 665 REALNAME 타입의 NamePart 객체, 없으면 None 666 """ 667 for part in self.name_parts: 668 if part.is_realname(): 669 return part 670 return None
REALNAME 타입 NamePart 가져오기
Returns: REALNAME 타입의 NamePart 객체, 없으면 None
672 def get_index_part(self) -> Optional[NamePart]: 673 """ 674 INDEX 타입 NamePart 가져오기 675 676 Returns: 677 INDEX 타입의 NamePart 객체, 없으면 None 678 """ 679 for part in self.name_parts: 680 if part.is_index(): 681 return part 682 return None
INDEX 타입 NamePart 가져오기
Returns: INDEX 타입의 NamePart 객체, 없으면 None
684 def save(self, file_path: Optional[str] = None) -> bool: 685 """ 686 현재 설정을 JSON 파일로 저장 687 688 Args: 689 file_path: 저장할 파일 경로 (기본값: self.default_file_path) 690 691 Returns: 692 저장 성공 여부 (True/False) 693 """ 694 save_path = file_path or self.default_file_path 695 696 try: 697 # 저장할 데이터 준비 698 save_data = { 699 "paddingNum": self.padding_num, 700 "partOrder": self.part_order, # 순서 정보 저장 701 "nameParts": [] 702 } 703 704 # 각 NamePart 객체를 딕셔너리로 변환하여 추가 705 for part in self.name_parts: 706 save_data["nameParts"].append(part.to_dict()) 707 708 # JSON 파일로 저장 709 with open(save_path, 'w', encoding='utf-8') as f: 710 json.dump(save_data, f, indent=4, ensure_ascii=False) 711 712 self.config_file_path = save_path 713 return True 714 except Exception as e: 715 print(f"설정 저장 중 오류 발생: {e}") 716 return False
현재 설정을 JSON 파일로 저장
Args: file_path: 저장할 파일 경로 (기본값: self.default_file_path)
Returns: 저장 성공 여부 (True/False)
718 def load(self, file_path: Optional[str] = None) -> bool: 719 """ 720 JSON 파일에서 설정 불러오기 721 722 Args: 723 file_path: 불러올 파일 경로 (기본값: self.default_file_path) 724 725 Returns: 726 로드 성공 여부 (True/False) 727 """ 728 load_path = file_path or self.default_file_path 729 730 try: 731 if os.path.exists(load_path): 732 with open(load_path, 'r', encoding='utf-8') as f: 733 loaded_data = json.load(f) 734 735 # 필수 키가 있는지 확인 736 if "nameParts" not in loaded_data: 737 print("경고: 설정 파일에 필수 키 'nameParts'가 없습니다.") 738 return False 739 740 # paddingNum 불러오기 741 if "paddingNum" in loaded_data: 742 self.padding_num = loaded_data["paddingNum"] 743 744 # 파트 순서 불러오기 745 if "partOrder" in loaded_data: 746 self.part_order = loaded_data["partOrder"] 747 else: 748 # 없으면 기본 순서 생성 749 self.part_order = [part_data["name"] for part_data in loaded_data["nameParts"]] 750 751 # NamePart 객체 리스트 생성 752 new_parts = [] 753 for part_data in loaded_data["nameParts"]: 754 part = NamePart.from_dict(part_data) 755 new_parts.append(part) 756 757 # 필수 NamePart가 포함되어 있는지 확인 758 part_names = [part.get_name() for part in new_parts] 759 for required_name in self.required_parts: 760 if required_name not in part_names: 761 print(f"경고: 필수 NamePart '{required_name}'가 설정에 포함되어 있지 않습니다.") 762 return False 763 764 # 모든 확인이 통과되면 데이터 업데이트 765 self.name_parts = new_parts 766 self.config_file_path = load_path 767 768 # 순서에 따라 타입 업데이트 769 self._update_part_types_based_on_order() 770 self._update_part_order() # 순서 업데이트 771 return True 772 else: 773 print(f"설정 파일을 찾을 수 없습니다: {load_path}") 774 return False 775 except Exception as e: 776 print(f"설정 로드 중 오류 발생: {e}") 777 return False
JSON 파일에서 설정 불러오기
Args: file_path: 불러올 파일 경로 (기본값: self.default_file_path)
Returns: 로드 성공 여부 (True/False)
779 def apply_to_naming(self, naming_instance) -> bool: 780 """ 781 설정을 Naming 인스턴스에 적용 782 783 Args: 784 naming_instance: 설정을 적용할 Naming 클래스 인스턴스 785 786 Returns: 787 적용 성공 여부 (True/False) 788 """ 789 try: 790 # NamePart 객체 리스트 복사하여 적용 791 naming_instance._nameParts = copy.deepcopy(self.name_parts) 792 793 # paddingNum 설정 794 naming_instance._paddingNum = self.padding_num 795 796 return True 797 except Exception as e: 798 print(f"설정 적용 중 오류 발생: {e}") 799 return False
설정을 Naming 인스턴스에 적용
Args: naming_instance: 설정을 적용할 Naming 클래스 인스턴스
Returns: 적용 성공 여부 (True/False)
801 def insert_part(self, name: str, part_type: NamePartType, position: int, 802 values: Optional[List[str]] = None, 803 descriptions: Optional[List[str]] = None, 804 korean_descriptions: Optional[List[str]] = None) -> bool: # Add value/description parameters 805 """ 806 특정 위치에 새 NamePart 삽입 807 808 Args: 809 name: 삽입할 NamePart 이름 810 part_type: NamePart 타입 811 position: 삽입할 위치 (인덱스) 812 values: 사전 정의된 값 목록 (기본값: None) # Add doc 813 descriptions: 값에 대한 설명 목록 (기본값: None) # Add doc 814 korean_descriptions: 값에 대한 한국어 설명 목록 (기본값: None) # Add doc 815 816 Returns: 817 삽입 성공 여부 (True/False) 818 """ 819 if not name: 820 print("오류: 유효한 NamePart 이름을 입력하세요.") 821 return False 822 823 # 이미 존재하는지 확인 824 if self.get_part(name) is not None: 825 print(f"오류: '{name}' NamePart가 이미 존재합니다.") 826 return False 827 828 # 위치 범위 확인 829 if position < 0 or position > len(self.name_parts): 830 print(f"오류: 위치가 유효하지 않습니다. 0에서 {len(self.name_parts)} 사이의 값이어야 합니다.") 831 return False 832 833 # 새 NamePart 생성 (값과 설명 포함) 834 new_part = NamePart(name, part_type, values or [], descriptions, False, korean_descriptions) # Pass values/descriptions 835 836 # 지정된 위치에 삽입 837 self.name_parts.insert(position, new_part) 838 839 # 순서 목록 업데이트 840 if name not in self.part_order: 841 self.part_order.insert(position, name) 842 843 # 순서에 따라 타입 업데이트 844 self._update_part_types_based_on_order() 845 return True
특정 위치에 새 NamePart 삽입
Args: name: 삽입할 NamePart 이름 part_type: NamePart 타입 position: 삽입할 위치 (인덱스) values: 사전 정의된 값 목록 (기본값: None) # Add doc descriptions: 값에 대한 설명 목록 (기본값: None) # Add doc korean_descriptions: 값에 대한 한국어 설명 목록 (기본값: None) # Add doc
Returns: 삽입 성공 여부 (True/False)