IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  AIX and UNIX  >

파이썬에서 플러그인 작성하기

파이썬에서 명령행을 확장해 첫 플러그인 작성 방법을 익히자

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

Noah Gift, 소프트웨어 엔지니어, Giftcs

옮긴이: 박재호 이해영 dwkorea@kr.ibm.com

2008 년 11 월 04 일

플러그인을 작성하는 방법으로 파이썬 명령행 도구를 확장하는 방법을 익혀봅시다.

도입

플러그인이란 무엇일까?

플러그인 활용 중에 가장 대표적인 예를 찾으면 파이어폭스 플러그인 공동체가 빠지지 않는다. 플래시 재생기, 웹 개발, RSS 피드 관리 등을 위한 파이어폭스 플러그인이 나와 있다. 플러그인을 가장 흔하게 사용하는 경우는, 외부 개발자들이 응용을 확장할 때다. 이는 아주 강력한 아이디어이며, 원래 개발자가 상상조차 하지 못했던 방식으로 자기 제품을 확장하도록 힘을 실어준다. 참고자료 절을 참조해 플러그인에 대한 세부 정보를 확인하기 바란다.

직전 IBM developerworks 기사에서, 파이썬으로 명령행 도구를 만드는 즐거움에 대해 기사를 썼다. 이 기사에서는 다음 단계로 플러그인을 만들어 명령행 도구를 확장하는 방법을 다룬다. 플러그인과 명령행 도구는 현존하는 코드 기능을 확장하는 편리한 방법을 제공한다. 플러그인을 명령행과 함께 사용하면 정말 강력한 도구가 될 수 있다.

플러그인 작성 방법을 시작하기 앞서, pathtool라는 이름의 오픈 소스 파이썬 패키지를 사용해야 한다. 이 패키지는 파일 시스템을 돌아다니며 파일 객체를 만들어내는 생성기를 사용한다. 이 라이브러리는 파일 객체에 뭔가를 적용하는 독자적인 필터를 작성해 결과를 반환하는 방법으로 개발자 쪽에서 확장이 가능하도록 만들어졌다.

실제 파이썬 모듈 코드 크기는 이 기사에서 보는 코드 크기보다 좀 더 크기 때문에, 실제로 사용하는 API 일부만 보여줄 계획이다.


Listing 1. pathtool API
      
def path(fullpath, pattern="*", action=(lambda rec: print_rec(rec))):
    """이 함수는 경로(fullpath), 셸 패턴(pattern), action 콜백을 받는다.
    이 함수는 체크섬을 계산하기 위해 좀 더 늦은 pathattr 함수를 사용한다.
    """ 
    for rec in pathattr(fullpath):
        for new_record in match(pattern, rec):  # 필터를 적용한다.
            action(new_record)  # 객체 생성을 위해 람다 콜백을 적용한다.
       

이 예제를 보면, path 함수가 옵션으로 pattern 키워드 인수, 람다 콜백이라는 action 인수와 함께 경로 위치 인수를 필수적으로 받는다는 사실을 확인할 수 있다. path를 위한 기본 콜백은 예제로 파일 이름만 출력한다. 개발자는 easy_install pathtool을 사용하기만 하면 된다. easy_install 명령을 사용하는 방법은 참고자료 절에 나와 있다. 모듈 import와 함수 호출은 다음과 같다.

      from pathtool import path
      path("/tmp", pattern="*.mp3", action=(lambda rec: print_rec(rec)))
      

참고: 편의상 pathtool을 위한 원시 코드를 이 기사에 포함시켰다. 이 예제를 소개하는 이유는 람다 활용 때문이다. 참고자료 절에서 파이썬 튜토리얼 항목에 나온 링크를 따라가면 람다에 대한 설명이 나온다. 간략하게 요약하자면, 람다는 함수에게 다른 함수를 "호출"하라고 알려주는 편리한 방법이다.

플러그인 명령행 도구 작성하기

이제 콜백을 포함한 경로 탐색 라이브러리 활용법에 대한 일반적인 아이디어를 얻었으므로, 플러그인을 사용해 확장 가능한 명령행 도구를 실제로 작성할 시간이 다가왔다. 첫 번째 버전을 살펴본 다음에 좀 더 작은 조각으로 나눠 설명할 것이다.


Listing 2. 플러그인 방식으로 동작하는 명령행 도구
       
#!/usr/bin/env python
# encoding: utf-8
"""
pathtool-cli.py 0.1

파일 시스템을 돌아다니는 명령행 도구
plugin 디렉터리에서 Action plugins 콜백을 얻는다.

action=(lambda rec: print_rec(rec))

"""

from pathtool import path
import optparse
import re
import os
import sys

try:
    plugin_available = True
    from plugin import *
    from plugin import __all__ # 등록된 플러그인 전체 목록을 얻기 위해
except ImportError:
    plugin_available = False
        
def path_controller():
    descriptionMessage = """
    A command line tool for walking a filesystem.\
    Takes callback 'Action' functions as plugins.\
    
    example: pathtool_cli /tmp print_path_ext
    """
    p = optparse.OptionParser(description=descriptionMessage,
                                prog='pathtool',
                                version='pathtool 0.1.1',
                                usage= '%prog [starting directory][action]')
    p.add_option('--pattern', '-p',
                help='Pattern Match Examples: *.txt, *.iso, music[0-5].mp3\
                plain number defaults to * or match all.  \
                Uses UNIX standard wildcard syntax.',
                default='*')

    p.add_option('--list', '-l',
            action="store_true",
            help='lists available action plugins',
            default=False)
                    
    options, arguments = p.parse_args()
    if options.list:
        try:
            print "Action Plugins Available:"
            if plugin_available:
                for p in __all__:
                    print p
        finally:
            sys.exit(0)
            
    if len(arguments) == 2:
        fullpath = arguments[0]
        try:
            action_plugin = eval(arguments[1])   
            # 플러그인 작성자는 다음과 같은 이름 관례에 따라 메서드를 작성해야 한다.
            #path(fullpath,options.pattern,action=(lambda rec: move_to_tmp.plugin(rec)))
            path(fullpath, options.pattern,action=(lambda rec: action_plugin.plugin(rec)))
        except NameError:
            sys.stderr.write("Plugin Not Found")
            sys.exit(1)
    else:
        print p.print_help()

def main():
    path_controller()

if __name__ == '__main__':
    main()

       

이 예제를 돌리면 다음과 같은 결과를 얻는다.

# python pathtool_cli.py
Usage: pathtool [starting directory][action]

     A command line tool for walking a filesystem.    Takes callback 'Action'
functions as plugins.         example: pathtool_cli /tmp print_path_ext

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -p PATTERN, --pattern=PATTERN
                        Pattern Match Examples: *.txt, *.iso, music[0-5].mp3
                        plain number defaults to * or match all.
                        Uses UNIX standard wildcard syntax.
  -l, --list            lists available action plugins


명령어 결과를 보면 이 도구는 fullpath와 "action"을 요구한다. action은 개발자가 만든 플러그인이다. 명령행에 옵션 목록을 추가해 어떤 플러그인이 사용 가능한지를 보여주도록 만들었다. 출력 결과는 다음과 같다.

# python pathtool_cli.py -l
Action Plugins Available:
move_to_tmp
print_file_path_ext

도구가 동작하는 원리에 대해 잘 모르더라도, 이름만 봐서 어떤 동작을 할지 눈치챌 수 있다. 직전에 작성한 print_file_path_ext action는 file, path, ext를 출력한다. 실제 동작 결과는 다음과 같다.

# python pathtool_cli.py /tmp print_file_path_ext
/tmp/foo0.txt | foo0.txt | .txt
/tmp/foo1.txt | foo1.txt | .txt
/tmp/foo10.txt | foo10.txt | .txt
/tmp/foo2.txt | foo2.txt | .txt
/tmp/foo3.txt | foo3.txt | .txt
/tmp/foo4.txt | foo4.txt | .txt
/tmp/foo5.txt | foo5.txt | .txt
/tmp/foo6.txt | foo6.txt | .txt
/tmp/foo7.txt | foo7.txt | .txt
/tmp/foo8.txt | foo8.txt | .txt
/tmp/foo9.txt | foo9.txt | .txt

실행 전에 임시 파일을 touch foo{0..10}.txt로 만들었으며, 명령행 도구는 전체 경로, 파일 이름, 확장자를 "|" 문자로 구분해 출력한다.

플러그인 아키텍처 개괄

지금까지 "마법의" 플러그인이 어디서 왔는지를 말해주지 않고 설명을 진행했다. 가장 먼저 살펴볼 내용은 모듈 최상단에 위치한 import 문이다. 다음과 같이 시도해보자.

    plugin_available = True
    from plugin import *
    from plugin import __all__ # 등록된 플러그인 전체 목록을 얻기 위해
except ImportError:
    plugin_available = False

import 문은 놀랄 만큼 간단한 플러그인 아키텍처를 설명하는 비밀의 열쇠를 제공한다. 공식 파이썬 문서는 일반적으로 "from package import *" 구문 사용을 권장하지 않지만, 플러그인을 작성할 때에는 이런 구문을 사용해도 좋다. 하지만 이럴 경우, 플러그인 작성자는 플러그인 디렉터리에 위치한 __init__.py에 항목을 생성할 책임이 있다.

"""Lists all of the importable plugins"""
__all__ = ["move_to_tmp", "print_file_path_ext"]

"from package import *" 구문을 사용하면 패키지 내부에 속한 모든 모듈을 *로 import한다. 다음으로 실제 __all__ 목록을 import 해 사용자에게 사용 가능한 플러그인 목록을 보여주는 수단으로 활용한다. 마지막으로 조금 마법과 같은 내용을 소개하겠다. 명령행 도구는 어떤 플러그인 action을 사용할지 실행 전까지 알지 못하므로 eval을 활용해 명령행에서 action 문자열을 호출 가능한 함수로 변환한다. 마법의 행은 다음과 같다.

action_plugin = eval(arguments[1]) 

일반적으로 eval을 사용할 때 아주 조심해야 하지만, 플러그인 메서드를 활용하기 위한 목적으로 제격이다.

플러그인 살펴보기

이제 플러그인 아키텍처 동작 원리를 이해했으므로, 실제 플러그인을 살펴보자. 플러그인 아키텍처가 동작하려면 파이썬 사이트 패키지 디렉터리나 현재 작업 디렉터리에 플러그인 디렉터리가 위치해야 한다. print_file_path.py라는 플러그인에는 plugin이라는 메서드가 있다. 이게 바로 플러그인 개발자가 반드시 구현해야 하는 API다.


Listing 3. 예제 plug-in

#!/usr/bin/env python
# encoding: utf-8
"""
prints path, name, ext, plugin
"""

def plugin(rec, verbose=True):
    """Moves matched files to tmp directory"""
    path = rec["path"]
    filename = rec["filename"]
    ext = rec["ext"]
    print "%s | %s | %s" % (path, filename, ext)

이 plugin은 아주 단순한 함수지만, pathtool 모듈이 생성하는 사전인 rec 매개변수를 받는다. 사전은 다음 API를 포함한다.

{"path": path, "filename": file, "ext": ext, "size": size,
"unique_id": unique_id, "mtime": mtime, "ctime": ctime}

이 예제에서, 호출될 매 시간마다 특정 파일 객체 값을 출력하도록 값을 인쇄하기 위해 사전 키를 활용한다. 플러그인 작성자는 파일 변환, 이름 변경, 파일 아카이브 등을 수행하는 다른 유용한 action을 작성할 수 있다.

요약

이 기사는 파이썬에서 명령행 도구를 확장하기 위한 유용한 수단으로 적당하게 단순한 플러그인 아키텍처를 보여준다. 하지만 여기서 주목해야 할 몇 가지 사항이 있다. 먼저, 참고자료에 포함된 easy_install과 함께 구현하는 좀 더 복잡한 플러그인 시스템이 있다. 이 플러그인 시스템은 사용자가 특정 도구를 위한 플러그인을 정의하도록 진입 지점 생성을 허용한다. 다음으로 이 기사에서 소개한 명령행 작성 방식을 따르면 단지 한 가지 "action" 플러그인만 수용 가능하다. 무제한 "연결된" 콜백 action을 받아들이는 명령행 도구로 수정하는 구현 방식은 독자들에게 연습 문제로 남겨두겠다.

연결된 플러그인을 만들 때, 사용하는 API 본질을 고려해 설계를 해야 한다는 사실을 잠재적으로 깨달을 것이다. 이 기사에서는 결과를 생성하는 플러그인 코드 기초를 만들었다. 여기서 소개한 프로그램이 플러그인을 함께 연결하려면, 작업을 수행하는 동시에 사전 레코드를 뒤로 돌려야 한다. 이 기사가 명령행 도구 형식에 맞춰 각자 플러그인을 작성할 수 있는 영감을 불러일으켰기를 바란다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
예제 CLI 플러그인 코드cli_plugin_code.zip15KBHTTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기

토론


필자소개

Photo of Noah GIft

Noah Gift는 오라일리에서 나온 "Python For Unix and Linux" 공동 저자다. Gift는 저자이자 연사이자 컨설턴트이자 공동체 리더로 IBM developerWorks, Red Hat Magazine, 오라일리, MacTech에 기고한다. Gift가 운영하는 컨설팅 회사 웹 사이트는 www.giftcs.com이며, 개인 웹 사이트는 www.noahgift.com이다. Noah는 또한 아틀란타 파이썬 사용자 그룹 홈 페이지인 www.pyatl.org를 담당하는 현재 조직장이다. Gift는 칼 스테이트 로스 엔젤레스에서 CIS 석사 학위를 받았으며, 칼 폴리 산 루이스 오비스포에서 영양학 학사 학위를 받았다. 애플과 LPI 인증 시스템 관리자이며 칼텍, 디즈니 피처 애니메이션, 소니 이미지웍스, 터너 스튜디오에서 일한다. 남는 시간에는 부인 Leah, 아들 Liam과 함께 피아노를 연주하며 종교적인 수양을 하면서 보낸다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



 


 


 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us





위로


developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의