Gooey: 거의 모든 Python 커맨드라인 프로그램을 완전한 GUI 애플리케이션으로 변환
(github.com/chriskiehl)- Gooey는 Python 3 콘솔 애플리케이션을 최종 사용자가 쓰기 쉬운 GUI 애플리케이션으로 바꾸며,
argparse선언이 있는 함수에 데코레이터 한 줄을 붙이는 방식으로 동작함 - 기본 설치는
pip install Gooey로 가능하고,@Gooey데코레이터와ArgumentParser를 함께 쓰면 Gooey가 인자를 읽어 WX 컴포넌트 기반 UI를 구성함 - 기본 위젯 선택이 부족할 때는
GooeyParser를ArgumentParser대체로 넣고widget인자를 지정해FileChooser,DateChooser,PasswordField,Slider같은 커스텀 위젯을 선택할 수 있음 - 대상 사용자는 직접 CLI를 다루는 개발자용 도구보다, 사무실용 “실행 후 완료” 스크립트나 비프로그래머 대상 도구이며, 고급/기본/설정 없는 실행 모드와 메뉴, 진행률 표시, 국제화, 아이콘 변경, 패키징을 지원함
- 동적 검증과 생명주기 이벤트는 실험적 기능으로 표시되어 있으며,
optparse는 현재 지원하지 않고ArgumentParser기반 코드와 선택적 이벤트 구독을 전제로 함
콘솔 프로그램을 GUI로 바꾸는 방식
- Gooey는 콘솔 애플리케이션을 최종 사용자가 다루기 쉬운 GUI 애플리케이션으로 변환함
- 핵심 사용법은
argparse선언이 들어 있는 함수에@Gooey데코레이터를 붙이는 것임
from gooey import Gooey
@Gooey
def main():
parser = ArgumentParser(...)
# rest of code
- 스타일과 동작은 데코레이터 인자로 조정할 수 있음
advanced: 고급 설정 화면 표시 여부language: JSON 기반 번역 선택auto_start: 설정 화면을 건너뛰고 즉시 실행target: 하위 프로세스로 실행할 명령 지정program_name,program_description: GUI 표시 이름과 설명default_size: GUI 초기 크기dump_build_config,load_build_config: Gooey 빌드 설정 JSON 저장/로드monospace_display: 출력 화면에 고정폭 글꼴 사용
설치와 예제
- 가장 쉬운 설치 방법은 pip임
pip install Gooey
- 저장소를 클론한 뒤
setup.py를 실행해 설치할 수도 있음
git clone https://github.com/chriskiehl/Gooey.git
python setup.py install
- 준비된 예제 스크립트는 Gooey Examples 저장소에서 받을 수 있음
- 예제 저장소는 Gooey의 여러 레이아웃, 위젯, 기능을 둘러보는 용도로 제공됨
왜 필요한가
- Gooey는 명령 프롬프트를 익숙하지 않은 사용자에게 보여주는 문제를 줄이기 위해 만들어짐
- 프로그램이 하나 이상의 작업을 하려면 옵션을 받아야 하고, 기존에는 GUI를 직접 만들거나 콘솔 애플리케이션에 인자를 전달하는 방법을 설명해야 했음
- Gooey는 개발자가 익숙한 방식으로 구성 가능한 프로그램을 만들면서, 표시와 상호작용을 GUI로 제공할 수 있게 함
적합한 사용자와 비적합한 경우
- 자기 자신이나 다른 프로그래머를 위한 유틸리티, 다른 콘솔 애플리케이션으로 파이프할 결과를 만드는 도구에는 Gooey가 적합하지 않을 수 있음
- 사무실용 실행 스크립트, 지점 A에서 B로 데이터를 옮기는 도구, 비프로그래머 대상 프로그램에는 적합함
- 복잡한 애플리케이션을 만들면서 GUI 쪽을 추가 비용 없이 얻는 것이 목표임
내부 동작과 argparse 매핑
- Gooey는 런타임에 Python 스크립트에서
ArgumentParser참조를 파싱함 optparse는 현재 지원하지 않음- 추출된 인자들은 제공하는
action에 따라 component type을 배정받고 GUI 구성에 사용됨 ArgumentParser._actions는 기본적으로 다음과 같은 WX 컴포넌트에 매핑됨store:TextCtrlstore_const,store_true,store_False,version:CheckBoxappend:TextCtrlcount:DropDownMutually Exclusive Group:RadioGroupchoice:DropDown
GooeyParser와 커스텀 위젯
- 기본 위젯 선택이 충분하지 않으면
ArgumentParser의 드롭인 대체인 GooeyParser를 사용할 수 있음 GooeyParser는 추가 키워드 인자widget을 제공해 표시할 컴포넌트 이름을 지정할 수 있음
from gooey import Gooey, GooeyParser
@Gooey
def main():
parser = GooeyParser(description="My Cool GUI Program!")
parser.add_argument('Filename', widget="FileChooser")
parser.add_argument('Date', widget="DateChooser")
- 지원되는 커스텀 위젯에는 다음이 포함됨
DirChooser,FileChooser,MultiFileChooserFileSaver,MultiFileSaverDateChooser,TimeChooserPasswordFieldListboxBlockCheckboxColourChooserFilterableDropdownIntegerField,DecimalFieldSlider
DateChooser와TimeChooser가 애플리케이션에 전달하는 값은 항상 ISO format이며, GUI 일부에는 최종 사용자 설정에 따른 지역화 값이 보일 수 있음BlockCheckbox는 긴 도움말 텍스트가 있을 때 기본 인라인 체크박스보다 보기 좋게 만들기 위해 텍스트 블록을 일반 위치로 옮기고, 컨트롤 옆에는 짧은block_label을 표시함
국제화
- Gooey는 데코레이터의
language인자로 표시 언어를 선택함
@Gooey(language='russian')
def main():
...
- 모든 프로그램 텍스트는 외부 JSON 파일에 저장됨
- 새 언어 지원은
gooey/languages/디렉터리에 키/값을 추가하는 방식임 - 현재 18개 이상의 번역이 기본 제공됨
전역 설정과 UI 구성
- Gooey의 전반적인 모양과 동작은 데코레이터 인자로 조정함
- 주요 설정에는 다음이 포함됨
encoding: 표시 문자 인코딩, 기본값은utf-8advanced: 전체 설정 화면 또는 단순화 화면 선택auto_start: 설정 없이 즉시 실행target: Gooey가 자신을 다시 실행할 방법 지정suppress_gooey_flag: 커스텀target사용 시 추가 CLI 파라미터 주입 방지fullscreen: 전체 화면으로 시작image_dir: 커스텀 이미지/아이콘 디렉터리language_dir: 커스텀 언어 파일 디렉터리disable_stop_button,show_stop_warning: 실행 중 중지 버튼과 경고 제어show_success_modal,show_failure_modal: 성공/실패 요약 모달 표시 여부run_validators: 프로그램 호출 전 검증 수행 여부progress_regex,progress_expr: 진행률 텍스트 파싱과 변환navigation:TABBED또는SIDEBARbody_bg_color,header_bg_color,footer_bg_color,sidebar_bg_color: 색상 설정terminal_font_family,terminal_font_size,terminal_font_color: 터미널 표시 글꼴 설정menus: 커스텀 메뉴 그룹과 항목clear_before_run: 재실행 시 이전 출력 삭제
레이아웃과 실행 모드
- Gooey는 입력을 기본적으로
positional과optional두 그룹으로 나눔 argparse의add_argument_group()을 쓰면 입력을 논리 그룹으로 묶고 각 그룹의 레이아웃을 조정할 수 있음
parser = ArgumentParser()
search_group = parser.add_argument_group(
"Search Options",
"Customize the search options"
)
search_group.add_argument(
'--query',
help='Base search string'
)
- 지원되는 전체 레이아웃 옵션에는
show_sidebar=True,show_sidebar=False,navigation='TABBED',tabbed_groups=True가 포함됨 -
Advanced
- 기본 화면은 full/advanced 설정 화면임
- 대부분의 애플리케이션에는 CLI 구조와 맞는 플랫 레이아웃이 적합함
- 여러 경로 또는 작은 도구들의 조합으로 된 CLI에는 컬럼 레이아웃이 적합함
- 컬럼 레이아웃은 기본 경로를 왼쪽 열에, 대응하는 인자를 오른쪽에 표시함
- 현재 레이아웃은 파라미터로 명시 지정할 수 없고, 코드에
subparsers가 있는지에 따라 구성됨
-
Basic
advanced=False를 설정하면 기본 보기로 전환됨- 사용자가 콘솔 애플리케이션에 익숙하지만 단순 터미널보다 더 다듬어진 화면을 원할 때 적합함
@gooey(advanced=False) def main(): # rest of code -
No Config
auto_start=True를 설정하면 설정 화면 없이 바로 표시 영역으로 이동해 호스트 프로그램을 실행함- 작은 일회성 스크립트의 외형을 개선하는 데 쓰임
@Gooey(auto_start=True) def main(): ...
메뉴 기능
- Gooey 1.0.2부터 상단에 Menu Bar를 추가할 수 있음
- 메뉴는
@Gooey(menu=[{}, {}, ...])형태의 맵 목록으로 지정함 - 각 메뉴 그룹은
name과items를 가짐 - 각 메뉴 항목은 항상
type과menuTitle을 포함함 - 지원되는 메뉴 항목 타입은 다음과 같음
AboutDialog: 이름, 버전, 라이선스 등 프로그램 정보 표시MessageDialog: 사용자에게 정보성 메시지 표시Link: 지정 URL을 기본 브라우저로 열기HtmlDialog: 제한된 HTML 하위 집합을 이용한 다이얼로그 표시
동적 검증
- Dynamic Validation은 실험적 기능이며 API가 바뀌거나 제거될 수 있음
- Gooey는 사용자 입력을 프로그램에 넘기기 전에 선택적으로 사전 검증을 수행할 수 있음
- 이 기능은 대부분의 Argparse 인자 타입에서 사용할 수 있는
type파라미터를 활용함
def must_be_exactly_ten(value):
number = int(value)
if number == 10:
return number
else:
raise TypeError("Hey! you need to provide exactly the number 10!")
- 검증은 기본적으로 실행되지 않음
- 활성화하려면
VALIDATE_FORM이벤트를 구독해야 함
from gooey import Gooey, Events
@Gooey(use_events=[Events.VALIDATE_FORM])
def main():
...
- 이 기능은 내부에서 강한 Monkey Patching을 사용하기 때문에 현재 옵트인 방식임
생명주기 이벤트와 UI 제어
- Gooey 1.2.0부터 프로그램에 생명주기 훅을 노출함
- 이 기능도 실험적이며 API가 바뀌거나 제거될 수 있음
- 현재 주요 훅은 두 가지임
on_successon_error
- 두 훅은 프로세스 완료 후 실행됨
- 핸들러는 파싱된 Argparse 객체와 현재 Gooey UI 상태를 받으며, 업데이트된 상태를 반환하면 UI에 반영될 수 있음
- 핸들러는
GooeyParser생성 시 연결함
parser = GooeyParser(
on_success=my_success_handler,
on_failure=my_failure_handler)
- 사용하려면 이벤트를 명시적으로 구독해야 함
from gooey import Gooey, Events
@Gooey(use_events=[Events.ON_SUCCESS, Events.ON_ERROR])
def main():
...
진행률과 시간 표시
- Gooey는 기존 텍스트 진행률 출력을 읽어 Progress Bar를 구동할 수 있음
- 단순한 경우
Progress 83%같은 문자열을 정규식으로 매칭해 진행률로 변환함
@Gooey(progress_regex=r"^progress: (\d+)%$")
- 더 복잡한 출력은
progress_expr로 정규식 매칭 결과를 변환할 수 있음
@Gooey(progress_regex=r"^progress: (?P<current>\d+)/(?P<total>\d+)$",
progress_expr="current / total * 100")
hide_progress_msg=True를 지정하면 진행률에 매칭된 텍스트 출력을 콘솔에서 숨길 수 있음timing_options를 사용하면 경과 시간과 남은 시간을 표시할 수 있음- 시간 표시는
progress_regex와progress_expr를 사용할 때만 동작함
아이콘과 패키징
- Gooey는 기본 아이콘 6개를 제공하며,
image_dir인자로 커스텀 이미지 디렉터리를 지정해 덮어쓸 수 있음 - 파일 이름 기준으로 이미지를 찾으며, 덮어쓸 수 있는 파일명은 다음과 같음
program_icon.pngsuccess_icon.pngrunning_icon.pngloading_icon.gifconfig_icon.pngerror_icon.png
- 실행 파일 패키징은 PyInstaller 사용 예시를 제공함
- 요약 절차는 애플리케이션 루트에
build.spec을 두고APPPNAME,name,pathex값을 프로젝트에 맞게 수정한 뒤 실행하는 것임
pyinstaller -F --windowed build.spec
- 자세한 패키징 절차는 Packaging-Gooey.md에 있음
댓글과 토론
Hacker News 의견들
-
어, 이거 내 프로젝트인데 ^_^ 왜 HN 맨 위에 올라와 있지?
argparse관련 댓글에 짧게 답하자면, Gooey는 이제 꽤 오래된 프로젝트고 시작 당시에는argparse가 탄탄한 선택이었음
요즘 Gooey 자체는 JSON으로 동작하고argparse와는 분리되어 있지만, 다른 인터페이스를 만든 사람이 거의 없어서argparse가 여전히 주된 “공식” 인터페이스로 남아 있음
재미있는 점으로는 Python뿐 아니라 임의의 실행 파일도 호출할 수 있어서 꽤 유용함: https://chriskiehl.com/article/gooey-as-a-universal-frontend
마지막 커밋이 2년 전이라는 얘기에 대해서는, 나이가 들고 우선순위가 바뀌면 틈새 소프트웨어를 무료로 계속 유지할 명분을 찾기 어려워짐 :( 위안이 될지는 모르겠지만 항상 죄책감은 느낌
이상하게도 사는 동네 곳곳에 “GOOEY” 그래피티가 있어서, 방치된 이슈 트래커를 계속 떠올리게 해주는 상시 알림처럼 보임 hahaargparse는 여전히 꽤 좋은 선택임. 워낙 널리 쓰이고 문서도 잘 되어 있으며 비교적 쉬움
Typer와 Click도 사용성이 좋지만, Typer의 “튜토리얼”식 문서는Typer.App()이 어떤 인자를 받는지 같은 답을 찾기엔 검색하기가 꽤 어렵다고 느낌
지금 작업 중인 프로그램은 사용자가 직접 인자 파싱을 시작하는 구조라argparse가 잘 맞음. 사용자에게 텍스트 기반 UI를 선택지로 제공하고 싶지만 Textualize는 Click이 필요했던 것 같고, Textual을 코드에 직접 붙여 UI를 만들려 해도 몇 시간을 썼는데 시작조차 못 했음- 정말 멋진 아이디어임. API와 분리된 인터페이스를 좋아함
요즘 애플리케이션을 프로그래밍으로 제어할 수 없어서 생기는 짜증이 너무 많음. 솔직히 모든 애플리케이션 기능에는 API가 있어야 한다는 법이 있었으면 좋겠음 - 멋진 프로젝트임! 궁금한 게 있는데, 왜
sys.argv를 현재 작업 디렉터리의 로컬 파일로 덤프하나요? https://github.com/chriskiehl/Gooey/blob/be4b11b8f27f500e732...
tmp.txt는 고유한 이름과는 거리가 먼데, 뭔가 놓친 게 있는지 궁금함 - “요즘 Gooey 자체는 JSON으로 동작하고
argparse와는 분리되어 있다”는 부분이 멋짐
제목만 보고 클릭하기 전엔 “분명argparse에 강하게 의존하겠지”라고 생각했는데, 좋은 의미로 놀라움
나는 열성적인getopt팬인데, 개발자 편의보다 사용자 편의가 훨씬 중요하다고 보기 때문임. 사용자는 개발자가 어떤 프로그래밍 언어나 옵션 파싱 라이브러리를 골랐는지 신경 쓸 필요가 없어야 함
argparse, Click, Go의flag/X11 스타일 등 많은 라이브러리는 반세기 동안 쌓인 집단적 근육 기억에 박힌 관례를 깨뜨림. 하지만 중간 계층이 있다면 두 마리 토끼를 잡을 수 있어 보임 - Gooey가 아주 오래된 이유는 방치했기 때문임. 비난하려는 건 아니고 그냥 현실이 그렇다는 뜻
더 나쁜 건 이를 대체할 만한 실행 가능한 대안도 나오지 않았고, 두 포크 중 어느 것도 traction을 얻지 못했다는 점임
-
이건 “
argparse기반”이라고 한정해야 하지 않나?
argparse는 단순한 용도에는 좋지만, Click 기반 CLI도 많고 인기 있는 CLI 라이브러리 상당수가 Click 위에 구축되어 있음.argparse나 Click이 아닌 Python CLI 도구도 있지만, 이 둘이 아마 가장 인기 있는 편이긴 함
Click에서도 동작하는지 확인됐나? 지금은argparse관련 내용만 보임. 답이 아니라면 “거의 모든”이라는 표현은 명백히 거짓이고, 더 정확한 제목은 “거의 모든argparse기반 Python 명령줄 프로그램을 완전한 GUI 애플리케이션으로 바꾸기”가 됨
마지막 의미 있는 커밋이 2년 넘게 전이라는 점도 있음. 그 자체로 나쁜 건 아니지만 열린 이슈 수를 보면 프로젝트에 대한 신뢰가 크게 생기지는 않음
그래도 멋진 프로젝트임. 이런 걸 더 보고 싶음. README에서 말하듯 힘을 배가하는 도구라서, 누군가 CLI로 자동화를 만들고 비기술 직군 사무실 사람들에게 쉽게 공유할 수 있음. Access가 데이터베이스에 해줬던 역할과 비슷함
Access처럼 규모나 복잡도가 생기면 한계에 부딪히겠지만, 작은 사무실 용도에는 충분히 “좋은 정도”가 될 수 있음argparse에서 어떤 부족함을 보는지 궁금함. 내 성향은 외부 의존성 최소화 쪽임- 이전 직장에서 정확히 이런 용도로 썼음. 많은 작업을 자동화하고 팀을 위한 도구를 만들었는데, 대부분 Python 프로그래머가 아니라서 Gooey로 스크립트 위에 단순한 GUI를 얹었음. 아주 잘 동작했음
- 정확히
argparse로 못 하는 게 뭐가 있나?
-
관련 글:
Gooey: Turn almost any Python command line program into a GUI application - https://news.ycombinator.com/item?id=27490291 - 2021년 6월, 댓글 115개
Gooey: Turn command line programs into GUI applications - https://news.ycombinator.com/item?id=8218785 - 2014년 8월, 댓글 74개 -
운영체제와 셸이 특정 파싱 라이브러리에 기대지 않고도 프로그램 실행 방식을 더 잘 이해할 수 있으면 좋겠음
프로그램들이 타입이 있는 JSON/proto 형식으로 통신하고, 기대하는 입력·출력 타입을 들여다보는 것만으로 셸 명령 구조화·자동완성이나 완전한 GUI를 얻을 수 있으면 좋겠음
지금은 조심스럽게 빨대를 꽂아 만든 수준이 최선처럼 보임. 프로그램마다 여러 셸용 자동완성 파일을 내보내야 하고, 프로그램과 파싱 라이브러리마다 플래그 스타일이 크게 다르며, 당연히 GUI도 없음- 이제 PowerShell이라는 게 있음. 좀 더 진지하게 답하면, 이런 걸 정말 시도한 운영체제는 아마 Plan 9가 유일했을 것 같음
- 운영체제 네이티브 지원이 있는 범용 gRPC 교환/CLI API 같은 걸 말하는 건가? 그런 건 꽤 근사할 수 있음
다만 gRPC의 주된 문제는 많은 개발자, 나를 포함해서, 언어 안에서 자연스럽게 쓰는 해법보다 다루기가 좀 거추장스럽다고 느낀다는 점일 듯함 - PowerShell을 써보는 게 좋음. 기본적으로 Microsoft의 .NET 생태계를 대화형 명령줄로 빚어낸 것임
PowerShell이 핵심을 이루는 정적 타입을 완전히 활용할 수 있는지는 확실치 않지만, 명령줄에서 객체를 주고받는 능력은 거의 독보적임
Linux에서는jc(https://github.com/kellyjonbrazil/jc)와jq(https://jqlang.github.io/jq/)를 조합해 명령줄을 이어 붙일 수 있지만, PowerShell의 내장 기능에 비하면 여전히 두 단계를 더 처리해야 함
-
GUI는 가끔 위로 음식 같은 느낌임. 드물게 쓰는 CLI에서 생길 수 있는 인지 부담 없이 GUI 인터페이스를 그냥 둘러볼 수 있기 때문임
약간 다른 얘기지만, 몇 달 전 여기서 CUDATEXT 편집기를 알게 됐는데 단일 파일 Python API로 MENU, INPUTS 같은 임의의 GUI 요소를 쓸 수 있게 해줌. 이 요소들은 편집기 자체도 사용하는 것들임
지금은 그런 단순한 GUI 요소로 설정을 하고, 편집기 안에서 바로 블로그를 생성하고 있음 -
함께 볼 만한 것:
“Textual: Python용 가벼운 애플리케이션 프레임워크. 단순한 Python API로 정교한 사용자 인터페이스를 만들고, 앱을 터미널과 웹 브라우저에서 실행” https://github.com/textualize/textual/- Gooey와 비슷한 것도 있음: https://github.com/Textualize/trogon “Click CLI를 강력한 터미널 애플리케이션으로 쉽게 바꾸기”
- 와, 이게 어떻게 가능한 거지? 터미널 예제가 상상했던 것보다 훨씬 더 디테일함
- camply에 Textual 지원을 추가하는 건 꽤 쉬웠던 모양임. 내가 구현한 건 아니고, 가끔 프로젝트에 기여만 함: https://juftin.com/camply/command_line_usage/#tui
camply: https://juftin.com/camply/
-
이 훌륭한 소프트웨어를 만들어줘서 고맙다고 말하고 싶음. Gooey를 좋아하고 여러 프로그램에서 많이 써왔음
내게는 Python 스크립트가 중요한 일을 하고 있고, 이제 비프로그래머도 쓰게 만들어야 하는 딱 그 영역에 완벽하게 맞음 -
이건 naked objects가 떠오름. Java 클래스에 몇 가지 애너테이션과 테마만 정의하면 전체 GUI, 또는 웹 프런트엔드 애플리케이션이 생성된다는 아이디어였음
아주 멋진 아이디어였지만, 내가 알기로는 결국 잘 풀리지는 않았음- Django도 비슷한 철학이 있음. 모델을 정의하면 데이터베이스 테이블에 바로 반영되고, 그 모델로 폼을 자동 생성할 수 있음
내 생각에 문제는 프레젠테이션, 도메인, 인프라 같은 수직 관심사가 서로 결합된다는 점임. 도메인 모델의 화면 표현과 데이터베이스 표현이 단순할 때는 괜찮음
하지만 편의 기능이 많은 복잡한 인터페이스를 만들고 싶으면 그 요구사항이 도메인 계층으로 새어 들어가야 함. 반대로 복잡한 도메인 모델을 만들고 싶으면 언어 수준에서 불변 조건을 강제하기가 비현실적임.Model참조를 가진 어떤 코드든 임의로 건드릴 수 있기 때문임
- Django도 비슷한 철학이 있음. 모델을 정의하면 데이터베이스 테이블에 바로 반영되고, 그 모델로 폼을 자동 생성할 수 있음
-
반대로 해주는 것도 있으면 좋겠음
- GUI로
argparse에서 가져온 정보를 바탕으로 파라미터 스윕을 설정한 뒤, 결과를 적절히 실행·저장하는 셸 스크립트로 다시 변환할 수 있으면 좋겠음 - WYSIWYG 편집기가 CLI를 뱉어내는 걸 말하는 건가? 꽤 멋질 것 같지만, 필연적으로 어느 정도 제약이 있을 듯함. 누가 그런 접근을 시도했는지 궁금한데, 떠오르는 예는 없음
- GUI로
-
예전 Macintosh Programmer's Workshop, 즉 80~90년대 Mac OS용 텍스트 기반 셸인 MPW에는 거의 모든 명령에 대해 Commando라는 비슷한 기능이 있었음
Commando 정보는cmdo리소스에 보관됐음. 확장 속성 지원이 들쭉날쭉하지 않았다면 오늘날에도 비슷한 걸 할 수 있었을 것임
찾아보니 A/UX에도 Commando가 있었음. Finder에서 터미널 명령을 더블클릭하면 CLI 옵션을 고르는 Commando 상자가 뜨고, 그다음 셸 창에서 실행됐음. 요즘 Finder에서 터미널 명령을 실행하면 인자 없이 셸 창에서 그냥 실행될 뿐임
https://cohost.org/boredzo/post/804893-i-still-want-a-moder
http://toastytech.com/guis/aux3.html