[Python] IO - INI 다루기


Development note/Python  2019. 12. 27. 09:00

안녕하세요. 명월입니다.


이 글은 Python에서 Ini(환경 설정 파일)을 다루는 방법에 대한 글입니다.


제가 예전에 Python에서 파일을 다루는 방법에 대해 설명한 적이 있습니다.

링크 - [Python] IO (파일 입출력)

예전에 CSV와 XML, JSON 다루는 방법에 대해 설명한 적이 있습니다. Json을 다루는 것과는 관련성이 적으니 따로 링크는 생략하고 아래의 카테고리 관련 글로 확인해 주시기 바랍니다.


INI는 Initialization 설정 파일이라고 해서 흔히 확장자가 ini로 이루어져 있습니다. 그러나 꼭 ini는 아니고 conf나 cfg로 사용하는 경우도 있습니다.

INI 설정은 크게 섹션과 key 값으로 이루어져 있고 주석은 특이하게 세미 콜론(;)을 사용하는 설정 파일입니다.


Python에서 이 ini 파일을 다루는 이유는 역시 Python은 로컬 스크립트 언어로써 자주 사용하고 후에 jenkins나 빌드 설정을 동적으로 할 때 이 Python을 이용해서 환경 설정 파일을 만들게 된다면 매우 유용하기 떄문입니다.

# ini를 다루기 위해서는 configparser을 import해야 한다.
import configparser;
# configparser의 ConfigParser함수를 호출한다.
config = configparser.ConfigParser();
# configparser는 딕셔너리의 키를 설정하는 것처럼 넣으면 섹션을 설정하고 그 값을 딕셔너리로 입력하면 키부분이 환경설정의 키가 되고 값부분이 값이 된다.
config["DB"] = { "test" : "hello"};

# IO를 이용해서 출력한다.
with open('example.ini', 'w') as handle:
  config.write(handle);

config를 딕셔너리의 키처럼 섹션명을 넣고 값을 딕셔너리 값으로 넣으면 위 처럼 ini 환경 설정 파일이 만들어 집니다.

# ini를 다루기 위해서는 configparser을 import해야 한다.
import configparser;
# configparser의 ConfigParser함수를 호출한다.
config = configparser.ConfigParser();
# example.ini파일을 읽어 온다.
config.read('example.ini');
# 세션 종류를 가져온다.
print(config.sections());

# DB 세션의 키들을 가져온다.
keys = config["DB"].keys();
for key in keys:
  # 키를 통해 값을 출력한다.
  print("key : " + key + ", value :" + config["DB"][key]);

ini를 읽어 와서 sections함수를 통해 세션 키를 가져올 수 있습니다. 그리고 keys로 키를 찾을 수 있고, 그 키를 통해 값을 출력하였습니다.


좀 더 현실적인 예제로 ini파일을 읽어 보겠습니다.

제 PC에는 현재 PHP가 설치되어 있는데 이 php.ini를 확인해 보겠습니다.

위는 기본 php.ini를 메모장으로 연 모습입니다. 친절하게 주석이 매우 많이 있습니다. 친절하기는 한데.. 가끔 이 주석이 너무 많아서 값을 찾기가 매우 어려울 때가 있습니다.

어차피 영어로 된 이 주석을 이해도 못하는 거 다 지워버리고 싶을 때가 있습니다.

# ini를 다루기 위해서는 configparser을 import해야 한다.
import configparser;
# configparser의 ConfigParser함수를 호출한다.
config = configparser.ConfigParser();
# php.ini파일을 읽어 온다.
config.read('php.ini');
# IO를 이용해서 출력한다.
with open('phpex.ini', 'w') as handle:
  config.write(handle);

위대로 작성하면 예상으로는 주석이 제거된 깨끗한 ini파일이 생길 것이라고 생각됩니다.

그러나 실제는 에러가 발생하는데, 이유는 표준 ini에서는 세션 안에 같은 키가 존재하지 않습니다.

링크 - https://stackoverflow.com/questions/15848674


위 스택 오버플로우를 보니 누군가가 해결을 했네요.

# ini를 다루기 위해서는 configparser을 import해야 한다.
import configparser;
# 중복 키를 list로 해결하기 위한 방법
class MultiValueDict(dict):
  def __setitem__(self, key, value):
    if isinstance(value, list) and key in self:
      self[key].extend(value);
    else:
      super().__setitem__(key, value);    

# 여기서 strict, empty_lines_in_values, dict_type 이 세 옵션을 다 설정해야 한다.
config = configparser.RawConfigParser(strict=False, empty_lines_in_values=False,dict_type=MultiValueDict);
config.read('php.ini');

# 출력합ㄴ디ㅏ.
with open('phpex.ini', 'w') as handle:
  config.write(handle);

결과는 주석이 싹 제거되고 ini가 새로 만들어 졌습니다. 그런데 아까 extension에 있던 중복키 부분이 이상하게 입력이 되어 있습니다.

역시 제대로 할려면 손이 들어가야 합니다.

import configparser;
class MultiValueDict(dict):
  def __setitem__(self, key, value):
    if isinstance(value, list) and key in self:
      self[key].extend(value);
    else:
      super().__setitem__(key, value);    
            
config = configparser.RawConfigParser(strict=False, empty_lines_in_values=False,dict_type=MultiValueDict);
config.read('php.ini');

with open('phpex.ini', 'w', newline = '') as handle:
  # 세션 키를 가져온다.
  sessionkeys = config.keys();
  for sessionkey in sessionkeys:
    # 세션 키를 file로 출력한다. 형태는 [세션 키]이다.
    print("["+sessionkey+"]",file=handle);
    keys = config[sessionkey].keys();
    for key in keys:
      # 각 키의 값을 개행으로 기준으로 리스트를 만든 후에 출력한다.
      for item in config[sessionkey][key].split("\n"):
        print(key+"="+item,file=handle);

주석이 싹 제거된 ini파일로 재 출력을 했습니다.


여기까지 Python에서 Ini(환경 설정 파일)을 다루는 방법에 관한 설명이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.