pyjallib.namingConfig API documentation

# pyjallib.namingConfig

namingConfig 모듈 - Naming 클래스의 설정을 관리하는 기능 제공 NamePart 객체를 기반으로 네이밍 설정을 저장하고 불러오는 기능 구현

View Source

      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

class NamingConfig: View Source

     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 파일로 저장/불러오기 기능 제공.

NamingConfig( padding_num: int = 2, name_parts: typing.Optional[typing.List[pyjallib.namePart.NamePart]] = None, config_file_path: str = '', default_file_name: str = 'namingConfig.json', required_parts: typing.Optional[typing.List[str]] = None) View Source

    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"])

name_parts
padding_num
part_order
required_parts
config_file_path
default_file_name
default_file_path
def get_part_names(self) -> List[str]: View Source

    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 이름 목록

def get_part_order(self) -> List[str]: View Source

    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 이름 순서 목록

def get_part(self, name: str) -> Optional[pyjallib.namePart.NamePart]: View Source

    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

def add_part( self, name: str, part_type: pyjallib.namePart.NamePartType = <NamePartType.UNDEFINED: 5>, values: typing.Optional[typing.List[str]] = None, descriptions: typing.Optional[typing.List[str]] = None, korean_descriptions: typing.Optional[typing.List[str]] = None) -> bool: View Source

    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)

def remove_part(self, name: str) -> bool: View Source

    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)

def reorder_parts(self, new_order: typing.List[str]) -> bool: View Source

    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)

def set_padding_num(self, padding_num: int) -> bool: View Source

    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)

def set_part_type(self, part_name: str, part_type: pyjallib.namePart.NamePartType) -> bool: View Source

    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)

def get_part_type(self, part_name: str) -> Optional[pyjallib.namePart.NamePartType]: View Source

    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

def set_part_values( self, part_name: str, values: typing.List[str], descriptions: typing.Optional[typing.List[str]] = None, korean_descriptions: typing.Optional[typing.List[str]] = None) -> bool: View Source

    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)

def set_part_value_by_csv(self, part_name: str, csv_file_path: str) -> bool: View Source

    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)

def add_part_value( self, part_name: str, value: str, description: typing.Optional[str] = None, korean_description: typing.Optional[str] = None) -> bool: View Source

    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)

def remove_part_value(self, part_name: str, value: str) -> bool: View Source

    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)

def set_part_descriptions(self, part_name: str, descriptions: typing.List[str]) -> bool: View Source

    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)

def get_part_descriptions(self, part_name: str) -> List[str]: View Source

    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: 설명 목록

def set_part_korean_descriptions(self, part_name: str, korean_descriptions: typing.List[str]) -> bool: View Source

    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)

def get_part_korean_descriptions(self, part_name: str) -> List[str]: View Source

    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: 한국어 설명 목록

def get_prefix_parts(self) -> List[pyjallib.namePart.NamePart]: View Source

    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 객체 리스트

def get_suffix_parts(self) -> List[pyjallib.namePart.NamePart]: View Source

    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 객체 리스트

def get_realname_part(self) -> Optional[pyjallib.namePart.NamePart]: View Source

    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

def get_index_part(self) -> Optional[pyjallib.namePart.NamePart]: View Source

    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

def save(self, file_path: typing.Optional[str] = None) -> bool: View Source

    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)

def load(self, file_path: typing.Optional[str] = None) -> bool: View Source

    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)

def apply_to_naming(self, naming_instance) -> bool: View Source

    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)

def insert_part( self, name: str, part_type: pyjallib.namePart.NamePartType, position: int, values: typing.Optional[typing.List[str]] = None, descriptions: typing.Optional[typing.List[str]] = None, korean_descriptions: typing.Optional[typing.List[str]] = None) -> bool: View Source

    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)