3 คะแนน โดย GN⁺ 2023-12-10 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Gooey เปลี่ยนแอปพลิเคชันคอนโซล Python 3 ให้เป็นแอปพลิเคชัน GUI ที่ผู้ใช้ปลายทางใช้งานได้ง่าย โดยทำงานด้วยการใส่ decorator เพียงบรรทัดเดียวให้กับฟังก์ชันที่มีการประกาศ argparse
  • การติดตั้งพื้นฐานทำได้ด้วย pip install Gooey และเมื่อใช้ decorator @Gooey ร่วมกับ ArgumentParser Gooey จะอ่านอาร์กิวเมนต์และประกอบ UI บนพื้นฐาน WX components
  • เมื่อการเลือกวิดเจ็ตพื้นฐานยังไม่พอ สามารถใช้ GooeyParser แทน ArgumentParser แบบ drop-in แล้วระบุอาร์กิวเมนต์ widget เพื่อเลือก custom widgets เช่น FileChooser, DateChooser, PasswordField, Slider ได้
  • กลุ่มผู้ใช้เป้าหมายไม่ใช่เครื่องมือสำหรับนักพัฒนาที่ใช้งาน CLI โดยตรง แต่เป็นสคริปต์แบบ “รันแล้วเสร็จ” สำหรับงานสำนักงานหรือเครื่องมือสำหรับผู้ที่ไม่ใช่โปรแกรมเมอร์ โดยรองรับโหมดรันแบบขั้นสูง/พื้นฐาน/ไม่มีการตั้งค่า เมนู การแสดงความคืบหน้า การทำ internationalization การเปลี่ยนไอคอน และการแพ็กเกจ
  • Dynamic validation และ lifecycle events ถูกระบุว่าเป็นฟีเจอร์ทดลอง โดยปัจจุบันยังไม่รองรับ optparse และตั้งอยู่บนโค้ดที่ใช้ ArgumentParser พร้อมการสมัครรับ event แบบเลือกใช้

วิธีเปลี่ยนโปรแกรมคอนโซลเป็น GUI

  • Gooey แปลงแอปพลิเคชันคอนโซลให้เป็นแอปพลิเคชัน GUI ที่ผู้ใช้ปลายทางใช้งานได้ง่าย
  • วิธีใช้หลักคือการใส่ decorator @Gooey ให้กับฟังก์ชันที่มีการประกาศ argparse
from gooey import Gooey

@Gooey
def main():
  parser = ArgumentParser(...)

# rest of code
  • สไตล์และพฤติกรรมสามารถปรับได้ผ่านอาร์กิวเมนต์ของ decorator
    • advanced: จะแสดงหน้าจอตั้งค่าขั้นสูงหรือไม่
    • language: เลือกคำแปลที่อิง JSON
    • auto_start: ข้ามหน้าจอตั้งค่าและเริ่มรันทันที
    • target: ระบุคำสั่งที่จะรันเป็น subprocess
    • program_name, program_description: ชื่อและคำอธิบายที่แสดงใน GUI
    • default_size: ขนาดเริ่มต้นของ GUI
    • dump_build_config, load_build_config: บันทึก/โหลดการตั้งค่า build ของ Gooey เป็น JSON
    • monospace_display: ใช้ฟอนต์ความกว้างคงที่ในหน้าจอ output

การติดตั้งและตัวอย่าง

  • วิธีติดตั้งที่ง่ายที่สุดคือใช้ pip
pip install Gooey
  • สามารถ clone repository แล้วรัน setup.py เพื่อติดตั้งได้เช่นกัน
git clone https://github.com/chriskiehl/Gooey.git
python setup.py install
  • สคริปต์ตัวอย่างที่เตรียมไว้สามารถรับได้จาก repository Gooey Examples
  • repository ตัวอย่างมีไว้สำหรับสำรวจ layout, widget และฟีเจอร์ต่าง ๆ ของ Gooey

ทำไมจึงจำเป็น

  • Gooey ถูกสร้างขึ้นเพื่อลดปัญหาการต้องแสดง command prompt ให้ผู้ใช้ที่ไม่คุ้นเคยเห็น
  • หากโปรแกรมต้องทำงานมากกว่าหนึ่งแบบก็จำเป็นต้องรับ option และเดิมทีต้องสร้าง GUI เอง หรืออธิบายวิธีส่งอาร์กิวเมนต์ให้แอปพลิเคชันคอนโซล
  • Gooey ช่วยให้นักพัฒนาสร้างโปรแกรมที่กำหนดค่าได้ในรูปแบบที่คุ้นเคย พร้อมนำเสนอการแสดงผลและการโต้ตอบเป็น GUI

ผู้ใช้ที่เหมาะสมและกรณีที่ไม่เหมาะ

  • Gooey อาจไม่เหมาะกับ utility สำหรับตัวเองหรือนักพัฒนาโปรแกรมคนอื่น ๆ หรือเครื่องมือที่สร้างผลลัพธ์เพื่อนำไป pipe เข้ากับแอปพลิเคชันคอนโซลอื่น
  • เหมาะกับ สคริปต์รันงานสำนักงาน, เครื่องมือย้ายข้อมูลจากจุด A ไปยัง B และโปรแกรมสำหรับผู้ที่ไม่ใช่โปรแกรมเมอร์
  • เป้าหมายคือการสร้างแอปพลิเคชันที่ซับซ้อน พร้อมได้ส่วน GUI เพิ่มมาโดยไม่มีต้นทุนเพิ่มเติม

การทำงานภายในและการแมป argparse

  • Gooey จะ parse reference ของ ArgumentParser จากสคริปต์ Python ในช่วง runtime
  • ปัจจุบันยังไม่รองรับ optparse
  • อาร์กิวเมนต์ที่ดึงออกมาจะได้รับการกำหนด component type ตาม action ที่ให้มา และถูกใช้สร้าง GUI
  • โดยพื้นฐานแล้ว ArgumentParser._actions จะถูกแมปกับ WX components ดังนี้
    • store: TextCtrl
    • store_const, store_true, store_False, version: CheckBox
    • append: TextCtrl
    • count: DropDown
    • Mutually Exclusive Group: RadioGroup
    • choice: DropDown

GooeyParser และ custom widgets

  • หากการเลือก widget พื้นฐานยังไม่เพียงพอ สามารถใช้ GooeyParser ซึ่งเป็นตัวแทนแบบ drop-in ของ ArgumentParser ได้
  • GooeyParser ให้อาร์กิวเมนต์ keyword เพิ่มเติมคือ widget เพื่อระบุชื่อ component ที่จะแสดง
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")
  • custom widgets ที่รองรับมีดังนี้
    • DirChooser, FileChooser, MultiFileChooser
    • FileSaver, MultiFileSaver
    • DateChooser, TimeChooser
    • PasswordField
    • Listbox
    • BlockCheckbox
    • ColourChooser
    • FilterableDropdown
    • IntegerField, DecimalField
    • Slider
  • ค่าที่ DateChooser และ TimeChooser ส่งให้แอปพลิเคชันจะเป็น ISO format เสมอ ขณะที่บางส่วนของ GUI อาจแสดงค่าที่ localize ตามการตั้งค่าของผู้ใช้ปลายทาง
  • BlockCheckbox จะย้ายบล็อกข้อความไปยังตำแหน่งปกติและแสดง block_label สั้น ๆ ข้าง control เพื่อให้ดูดีกว่า checkbox แบบ inline พื้นฐานเมื่อมีข้อความช่วยเหลือยาว ๆ

Internationalization

  • Gooey เลือกภาษาที่แสดงผลผ่านอาร์กิวเมนต์ language ของ decorator
@Gooey(language='russian')
def main():
    ...
  • ข้อความทั้งหมดของโปรแกรมถูกเก็บไว้ใน ไฟล์ JSON ภายนอก
  • การรองรับภาษาใหม่ทำได้โดยเพิ่ม key/value ในไดเรกทอรี gooey/languages/
  • ปัจจุบันมีคำแปลมากกว่า 18 ภาษาให้มาในตัว

การตั้งค่าทั่วไปและการจัดองค์ประกอบ UI

  • รูปลักษณ์และพฤติกรรมโดยรวมของ Gooey ปรับได้ผ่านอาร์กิวเมนต์ของ decorator
  • การตั้งค่าหลักมีดังนี้
    • encoding: encoding ของตัวอักษรที่แสดง ค่าเริ่มต้นคือ utf-8
    • advanced: เลือกหน้าจอตั้งค่าเต็มรูปแบบหรือหน้าจอแบบย่อ
    • auto_start: รันทันทีโดยไม่ต้องตั้งค่า
    • target: ระบุวิธีที่ Gooey จะรันตัวเองอีกครั้ง
    • suppress_gooey_flag: ป้องกันการฉีดพารามิเตอร์ CLI เพิ่มเติมเมื่อใช้ target แบบ custom
    • fullscreen: เริ่มต้นแบบเต็มหน้าจอ
    • image_dir: ไดเรกทอรีรูป/ไอคอน custom
    • language_dir: ไดเรกทอรีไฟล์ภาษา custom
    • disable_stop_button, show_stop_warning: ควบคุมปุ่มหยุดและคำเตือนระหว่างรัน
    • show_success_modal, show_failure_modal: จะแสดง modal สรุปผลสำเร็จ/ล้มเหลวหรือไม่
    • run_validators: จะทำ validation ก่อนเรียกโปรแกรมหรือไม่
    • progress_regex, progress_expr: parse และแปลงข้อความความคืบหน้า
    • navigation: TABBED หรือ SIDEBAR
    • body_bg_color, header_bg_color, footer_bg_color, sidebar_bg_color: การตั้งค่าสี
    • terminal_font_family, terminal_font_size, terminal_font_color: การตั้งค่าฟอนต์สำหรับแสดง terminal
    • menus: กลุ่มและรายการเมนู custom
    • clear_before_run: ลบ output เดิมเมื่อรันซ้ำ

Layout และโหมดการรัน

  • โดยพื้นฐานแล้ว Gooey จะแบ่ง input ออกเป็นสองกลุ่มคือ positional และ optional
  • เมื่อใช้ add_argument_group() ของ argparse จะสามารถจัด input เป็นกลุ่มเชิงตรรกะและปรับ layout ของแต่ละกลุ่มได้
parser = ArgumentParser()
search_group = parser.add_argument_group(
    "Search Options",
    "Customize the search options"
)
search_group.add_argument(
    '--query',
    help='Base search string'
)
  • ตัวเลือก layout โดยรวมที่รองรับได้แก่ show_sidebar=True, show_sidebar=False, navigation='TABBED', tabbed_groups=True
  • Advanced

    • หน้าจอพื้นฐานคือหน้าจอตั้งค่าแบบ full/advanced
    • สำหรับแอปพลิเคชันส่วนใหญ่ layout แบบแบนที่สอดคล้องกับโครงสร้าง CLI จะเหมาะสม
    • CLI ที่ประกอบด้วยหลาย path หรือชุดเครื่องมือขนาดเล็กเหมาะกับ layout แบบคอลัมน์
    • layout แบบคอลัมน์จะแสดง path พื้นฐานไว้ในคอลัมน์ซ้าย และอาร์กิวเมนต์ที่สอดคล้องกันไว้ทางขวา
    • ปัจจุบันไม่สามารถระบุ layout อย่างชัดเจนด้วยพารามิเตอร์ได้ และจะจัดตามว่ามี subparsers อยู่ในโค้ดหรือไม่
  • Basic

    • เมื่อตั้งค่า advanced=False จะสลับเป็นมุมมองพื้นฐาน
    • เหมาะเมื่อผู้ใช้คุ้นเคยกับแอปพลิเคชันคอนโซล แต่ต้องการหน้าจอที่ขัดเกลากว่า terminal แบบเรียบ ๆ
    @gooey(advanced=False)
    def main():
    
    # rest of code
    
  • No Config

    • เมื่อตั้งค่า auto_start=True จะข้ามหน้าจอตั้งค่าและไปยังพื้นที่แสดงผลทันทีเพื่อรันโปรแกรม host
    • ใช้เพื่อปรับรูปลักษณ์ของสคริปต์ใช้งานครั้งเดียวขนาดเล็กให้ดูดีขึ้น
    @Gooey(auto_start=True)
    def main():
        ...
    

ฟีเจอร์เมนู

  • ตั้งแต่ Gooey 1.0.2 เป็นต้นมา สามารถเพิ่ม Menu Bar ด้านบนได้
  • เมนูกำหนดเป็นรายการของ map ในรูปแบบ @Gooey(menu=[{}, {}, ...])
  • แต่ละกลุ่มเมนูมี name และ items
  • แต่ละรายการเมนูต้องมี type และ menuTitle เสมอ
  • ประเภทรายการเมนูที่รองรับมีดังนี้
    • AboutDialog: แสดงข้อมูลโปรแกรม เช่น ชื่อ เวอร์ชัน ใบอนุญาต
    • MessageDialog: แสดงข้อความให้ข้อมูลแก่ผู้ใช้
    • Link: เปิด URL ที่ระบุใน browser เริ่มต้น
    • HtmlDialog: แสดง dialog โดยใช้ subset ของ HTML ที่จำกัด

Dynamic Validation

  • Dynamic Validation เป็นฟีเจอร์ทดลอง และ API อาจเปลี่ยนแปลงหรือถูกนำออกได้
  • Gooey สามารถทำ pre-validation กับ input ของผู้ใช้ก่อนส่งให้โปรแกรมได้แบบเลือกใช้
  • ฟีเจอร์นี้ใช้ประโยชน์จากพารามิเตอร์ type ที่ใช้ได้กับอาร์กิวเมนต์ Argparse ส่วนใหญ่
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!")
  • โดยพื้นฐานแล้ว validation จะไม่ถูกเรียกใช้
  • หากต้องการเปิดใช้งาน ต้อง subscribe event VALIDATE_FORM
from gooey import Gooey, Events

@Gooey(use_events=[Events.VALIDATE_FORM])
def main():
    ...
  • ฟีเจอร์นี้ใช้ Monkey Patching อย่างหนักภายใน จึงเป็นแบบ opt-in ในปัจจุบัน

Lifecycle events และการควบคุม UI

  • ตั้งแต่ Gooey 1.2.0 เป็นต้นมา มีการเปิดเผย lifecycle hooks ให้โปรแกรมใช้
  • ฟีเจอร์นี้ก็เป็นแบบทดลองเช่นกัน และ API อาจเปลี่ยนแปลงหรือถูกนำออกได้
  • hook หลักในปัจจุบันมีสองรายการ
    • on_success
    • on_error
  • hook ทั้งสองจะถูกรันหลัง process เสร็จสิ้น
  • handler จะได้รับ object Argparse ที่ parse แล้วและสถานะ UI ปัจจุบันของ Gooey และหากส่งคืนสถานะที่อัปเดตแล้วก็สามารถนำไปสะท้อนใน UI ได้
  • handler เชื่อมต่อเมื่อสร้าง GooeyParser
parser = GooeyParser(
    on_success=my_success_handler,
    on_failure=my_failure_handler)
  • หากต้องการใช้ ต้อง subscribe event อย่างชัดเจน
from gooey import Gooey, Events

@Gooey(use_events=[Events.ON_SUCCESS, Events.ON_ERROR])
def main():
    ...

การแสดงความคืบหน้าและเวลา

  • Gooey สามารถอ่าน output ความคืบหน้าแบบข้อความเดิมเพื่อขับ Progress Bar ได้
  • ในกรณีง่าย ๆ จะแปลงเป็นความคืบหน้าด้วยการ match string อย่าง Progress 83% ด้วย regular expression
@Gooey(progress_regex=r"^progress: (\d+)%$")
  • output ที่ซับซ้อนกว่าสามารถใช้ progress_expr เพื่อแปลงผลการ match ของ regular expression ได้
@Gooey(progress_regex=r"^progress: (?P<current>\d+)/(?P<total>\d+)$",
       progress_expr="current / total * 100")
  • หากระบุ hide_progress_msg=True จะสามารถซ่อนข้อความ output ที่ match กับความคืบหน้าจาก console ได้
  • เมื่อใช้ timing_options สามารถแสดงเวลาที่ผ่านไปและเวลาที่เหลือได้
  • การแสดงเวลาจะทำงานเฉพาะเมื่อใช้ progress_regex และ progress_expr เท่านั้น

ไอคอนและการแพ็กเกจ

  • Gooey มีไอคอนพื้นฐานให้ 6 รายการ และสามารถระบุไดเรกทอรีรูป custom ด้วยอาร์กิวเมนต์ image_dir เพื่อเขียนทับได้
  • ค้นหารูปตามชื่อไฟล์ โดยชื่อไฟล์ที่เขียนทับได้มีดังนี้
    • program_icon.png
    • success_icon.png
    • running_icon.png
    • loading_icon.gif
    • config_icon.png
    • error_icon.png
  • การแพ็กเกจไฟล์ executable มีตัวอย่างการใช้ PyInstaller ให้
  • ขั้นตอนโดยสรุปคือวาง build.spec ไว้ที่ root ของแอปพลิเคชัน ปรับค่า APPPNAME, name, pathex ให้ตรงกับโปรเจกต์ แล้วรัน
pyinstaller -F --windowed build.spec
  • ขั้นตอนแพ็กเกจโดยละเอียดอยู่ที่ Packaging-Gooey.md

1 ความคิดเห็น

 
GN⁺ 2023-12-10
ความคิดเห็นบน Hacker News
  • เอ่อ นี่โปรเจกต์ของผมเอง ^_^ ทำไมถึงขึ้นไปอยู่บนสุดของ HN ได้เนี่ย?
    ขอตอบสั้น ๆ เรื่องคอมเมนต์เกี่ยวกับ argparse: Gooey เป็นโปรเจกต์ที่ค่อนข้างเก่าแล้ว และตอนเริ่มทำ argparse ก็เป็นตัวเลือกที่แข็งแรงดี
    ทุกวันนี้ตัว Gooey เองทำงานด้วย JSON และแยกออกจาก argparse แล้ว แต่แทบไม่มีใครทำอินเทอร์เฟซอื่นขึ้นมา ดังนั้น argparse จึงยังคงเป็นอินเทอร์เฟซ “ทางการ” หลักอยู่
    จุดที่น่าสนใจคือมันเรียกใช้ได้ไม่ใช่แค่ Python แต่รวมถึง ไฟล์ปฏิบัติการใด ๆ ด้วย จึงมีประโยชน์ทีเดียว: https://chriskiehl.com/article/gooey-as-a-universal-frontend
    ส่วนเรื่องที่คอมมิตล่าสุดเมื่อ 2 ปีก่อนนั้น พออายุมากขึ้นและลำดับความสำคัญเปลี่ยนไป ก็ยากที่จะหาเหตุผลมาดูแลซอฟต์แวร์เฉพาะทางเล็ก ๆ ต่อไปฟรี ๆ :( ไม่รู้ว่าจะช่วยปลอบใจได้ไหม แต่ผมรู้สึกผิดอยู่เสมอ
    แปลกดีที่แถว ๆ เมืองที่ผมอยู่มีกราฟฟิตี้คำว่า “GOOEY” อยู่หลายจุด มันเลยเหมือนตัวเตือนถาวรที่คอยทำให้นึกถึง issue tracker ที่ถูกทิ้งค้างไว้ haha

    • argparse ยังเป็นตัวเลือกที่ค่อนข้างดีอยู่ มันถูกใช้แพร่หลายมาก เอกสารก็ดี และค่อนข้างง่าย
      Typer กับ Click ก็ใช้งานดี แต่ผมรู้สึกว่าเอกสารแบบ “ทูตอเรียล” ของ Typer ค้นหาคำตอบอย่างเช่น Typer.App() รับอาร์กิวเมนต์อะไรบ้างได้ค่อนข้างยาก
      โปรแกรมที่ผมกำลังทำอยู่เป็นโครงสร้างที่ให้ผู้ใช้เริ่มการ parse อาร์กิวเมนต์เอง ดังนั้น argparse จึงเหมาะดี ผมอยากให้ผู้ใช้มี UI แบบข้อความเป็นตัวเลือก แต่จำได้ว่า Textualize ต้องใช้ Click และพอพยายามเอา Textual มาต่อเข้ากับโค้ดโดยตรงเพื่อทำ UI ใช้เวลาไปหลายชั่วโมงแล้วยังเริ่มไม่ได้ด้วยซ้ำ
    • เป็นไอเดียที่เจ๋งจริง ๆ ผมชอบ อินเทอร์เฟซที่แยกจาก API
      ทุกวันนี้มีเรื่องน่าหงุดหงิดมากมายเพราะเราไม่สามารถควบคุมแอปพลิเคชันด้วยการเขียนโปรแกรมได้ พูดตรง ๆ ผมอยากให้มีกฎหมายว่าฟีเจอร์ทุกอย่างของแอปพลิเคชันต้องมี API
    • โปรเจกต์ยอดเยี่ยม! มีเรื่องสงสัยนิดหนึ่ง ทำไมถึง dump sys.argv ไปเป็นไฟล์ local ในไดเรกทอรีทำงานปัจจุบันครับ? https://github.com/chriskiehl/Gooey/blob/be4b11b8f27f500e732...
      tmp.txt ดูห่างไกลจากชื่อที่ไม่ซ้ำกันมาก เลยสงสัยว่าผมพลาดอะไรไปหรือเปล่า
    • ส่วนที่ว่า “ทุกวันนี้ตัว Gooey เองทำงานด้วย JSON และแยกออกจาก argparse แล้ว” นั้นเจ๋งดี
      ตอนเห็นแค่ชื่อเรื่อง ก่อนคลิกเข้ามา ผมนึกว่า “ต้องพึ่ง argparse หนักแน่ ๆ” แต่ก็ประหลาดใจในทางที่ดี
      ผมเป็นแฟนตัวยงของ getopt เพราะมองว่าความสะดวกของผู้ใช้สำคัญกว่าความสะดวกของนักพัฒนามาก ผู้ใช้ไม่ควรต้องสนใจว่านักพัฒนาเลือกภาษาโปรแกรมหรือไลบรารี parse ออปชันอะไร
      ไลบรารีจำนวนมาก เช่น argparse, Click, flag ของ Go/สไตล์ X11 ฯลฯ ทำลายธรรมเนียมที่ฝังอยู่ในความจำกล้ามเนื้อร่วมกันตลอดครึ่งศตวรรษที่ผ่านมา แต่ถ้ามีเลเยอร์คั่นกลาง ก็ดูเหมือนจะ ได้ทั้งสองอย่าง
    • เหตุผลที่ Gooey เก่ามากก็เพราะมันถูกปล่อยทิ้งไว้ ไม่ได้จะตำหนิ แค่บอกว่านั่นคือความจริง
      ที่แย่กว่านั้นคือยังไม่มีทางเลือกอื่นที่ใช้แทนได้จริงออกมา และ fork ทั้งสองตัวก็ไม่มีตัวไหนได้รับแรงส่งเลย
  • อันนี้ไม่ควรระบุให้ชัดว่าเป็น “บนพื้นฐาน argparse” เหรอ?
    argparse ดีสำหรับงานง่าย ๆ แต่ก็มี CLI จำนวนมากที่ใช้ Click และไลบรารี CLI ยอดนิยมจำนวนไม่น้อยก็สร้างอยู่บน Click มีเครื่องมือ CLI ของ Python ที่ไม่ใช่ทั้ง argparse หรือ Click ด้วย แต่สองตัวนี้ก็น่าจะอยู่ในกลุ่มที่นิยมที่สุด
    ยืนยันแล้วหรือยังว่าทำงานกับ Click ได้? ตอนนี้เห็นแต่เนื้อหาเกี่ยวกับ argparse ถ้าคำตอบคือไม่ คำว่า “เกือบทุก” ก็เป็นเท็จอย่างชัดเจน และชื่อที่แม่นกว่าคือ “เปลี่ยนโปรแกรมบรรทัดคำสั่ง Python ที่ใช้ argparse เกือบทุกตัวให้เป็นแอปพลิเคชัน GUI เต็มรูปแบบ”
    อีกอย่างคือคอมมิตที่มีนัยสำคัญครั้งล่าสุดก็เกิน 2 ปีมาแล้ว ตัวมันเองไม่ได้แย่ แต่พอดูจำนวน issue ที่เปิดอยู่ ก็ไม่ได้ทำให้เกิดความเชื่อมั่นต่อโปรเจกต์มากนัก
    ถึงอย่างนั้นก็เป็นโปรเจกต์ที่เจ๋ง อยากเห็นอะไรแบบนี้มากขึ้น ตามที่ README บอก มันเป็น เครื่องมือทวีพลัง ทำให้ใครสักคนสร้างระบบอัตโนมัติด้วย CLI แล้วแชร์ให้คนในออฟฟิศสายงานที่ไม่ใช่เทคนิคใช้งานได้ง่าย คล้ายกับบทบาทที่ Access เคยทำให้กับฐานข้อมูล
    เหมือนกับ Access พอเริ่มมีขนาดหรือความซับซ้อนก็จะชนข้อจำกัด แต่สำหรับงานในออฟฟิศขนาดเล็ก มันอาจ “ดีพอ” ได้เลย

    • อยากรู้ว่าคุณเห็นว่า argparse ขาดอะไรไป แนวทางของผมคือ ลด dependency ภายนอกให้เหลือน้อยที่สุด
    • ที่ทำงานเก่าของผมใช้มันเพื่อจุดประสงค์แบบนี้เป๊ะ ๆ เรา automate งานจำนวนมากและสร้างเครื่องมือให้ทีม แต่คนส่วนใหญ่ไม่ใช่โปรแกรมเมอร์ Python เลยใช้ Gooey วาง GUI ง่าย ๆ ครอบสคริปต์ไว้ มันทำงานได้ดีมาก
    • แล้วมีอะไรบ้างที่ทำด้วย argparse ไม่ได้จริง ๆ?
  • บทความที่เกี่ยวข้อง:
    Gooey: Turn almost any Python command line program into a GUI application - https://news.ycombinator.com/item?id=27490291 - มิถุนายน 2021, 115 ความคิดเห็น
    Gooey: Turn command line programs into GUI applications - https://news.ycombinator.com/item?id=8218785 - สิงหาคม 2014, 74 ความคิดเห็น

  • คงจะดีถ้าระบบปฏิบัติการและเชลล์เข้าใจวิธีรันโปรแกรมได้ดีขึ้น โดยไม่ต้องพึ่งพาไลบรารีสำหรับ parsing เฉพาะตัว
    คงจะดีถ้าโปรแกรมต่าง ๆ สื่อสารกันด้วย รูปแบบ JSON/proto ที่มี type และแค่ตรวจดู type ของอินพุต/เอาต์พุตที่คาดหวัง ก็ได้โครงสร้างคำสั่งเชลล์กับการเติมคำอัตโนมัติ หรือแม้แต่ GUI เต็มรูปแบบ
    ตอนนี้สิ่งที่ดีที่สุดดูเหมือนทำได้แค่ระดับค่อย ๆ เอาหลอดเสียบเข้าไป โปรแกรมแต่ละตัวต้องส่งออกไฟล์ autocomplete สำหรับเชลล์หลายแบบ ไลบรารี parsing กับโปรแกรมแต่ละตัวก็มีสไตล์ flag ต่างกันมาก และแน่นอนว่าไม่มี GUI

    • ตอนนี้ก็มีสิ่งที่เรียกว่า PowerShell แล้ว ถ้าตอบจริงจังกว่านี้ ระบบปฏิบัติการที่เคยพยายามทำเรื่องแบบนี้จริง ๆ อาจมีแค่ Plan 9 เท่านั้น
    • หมายถึงอะไรอย่าง gRPC exchange/CLI API แบบทั่วไปที่มีการรองรับ native จากระบบปฏิบัติการหรือเปล่า? แบบนั้นน่าจะเท่มาก
      แต่ปัญหาหลักของ gRPC คงเป็นว่า developer จำนวนมาก รวมถึงผมเอง รู้สึกว่ามันใช้งานเกะกะกว่าวิธีแก้ที่ใช้ได้เป็นธรรมชาติภายในภาษา
    • น่าจะลองใช้ PowerShell ดู โดยพื้นฐานแล้วมันคือ ecosystem .NET ของ Microsoft ที่ถูกปั้นให้เป็น command line แบบโต้ตอบ
      ไม่แน่ใจว่า PowerShell ใช้ประโยชน์จาก static type ที่เป็นแกนหลักได้เต็มที่หรือไม่ แต่ความสามารถในการส่ง object ไปมาบน command line นั้นแทบไม่มีใครเทียบ
      บน Linux สามารถต่อ command line เข้าด้วยกันโดยใช้ jc(https://github.com/kellyjonbrazil/jc) ร่วมกับ jq(https://jqlang.github.io/jq/) ได้ แต่เมื่อเทียบกับฟีเจอร์ที่มีในตัวของ PowerShell แล้ว ก็ยังต้องประมวลผลเพิ่มอีกสองขั้นอยู่ดี
  • GUI บางครั้งให้ความรู้สึกเหมือน comfort food เพราะสามารถเปิดดู อินเทอร์เฟซ GUI ได้เลย โดยไม่มีภาระทางความคิดที่อาจเกิดขึ้นกับ CLI ที่ใช้นาน ๆ ครั้ง
    ออกนอกเรื่องนิดหน่อย เมื่อไม่กี่เดือนก่อนผมได้รู้จักเอดิเตอร์ CUDATEXT จากที่นี่ ซึ่งให้ใช้ element ของ GUI แบบใดก็ได้ เช่น MENU, INPUTS ผ่าน Python API ไฟล์เดียว element เหล่านี้เป็นตัวเดียวกับที่เอดิเตอร์เองก็ใช้
    ตอนนี้ผมใช้ element ของ GUI แบบง่าย ๆ เหล่านั้นสำหรับตั้งค่า และสร้างบล็อกได้โดยตรงในเอดิเตอร์

  • สิ่งที่น่าดูควบคู่กัน:
    “Textual: เฟรมเวิร์กแอปพลิเคชันน้ำหนักเบาสำหรับ Python สร้างอินเทอร์เฟซผู้ใช้ที่ประณีตด้วย Python API ที่เรียบง่าย และรันแอปได้ทั้งในเทอร์มินัลและเว็บเบราว์เซอร์” https://github.com/textualize/textual/

    • มีสิ่งที่คล้ายกับ Gooey ด้วย: https://github.com/Textualize/trogon “เปลี่ยน Click CLI ให้เป็นแอปพลิเคชันเทอร์มินัลทรงพลังได้ง่าย ๆ”
    • ว้าว นี่เป็นไปได้ยังไงกัน? ตัวอย่างเทอร์มินัลละเอียดกว่าที่จินตนาการไว้มาก
    • ดูเหมือนว่าการเพิ่มการรองรับ Textual ให้ camply จะค่อนข้างง่าย ผมไม่ได้เป็นคน implement เอง แค่มีส่วนร่วมกับโปรเจกต์เป็นครั้งคราว: https://juftin.com/camply/command_line_usage/#tui
      camply: https://juftin.com/camply/
  • อยากบอกว่าขอบคุณที่สร้างซอฟต์แวร์ยอดเยี่ยมนี้ขึ้นมา ผมชอบ Gooey และใช้มันมาเยอะในหลายโปรแกรม
    สำหรับผม มันพอดีกับพื้นที่นั้นเป๊ะ ๆ คือสคริปต์ Python กำลังทำงานสำคัญบางอย่างอยู่ และตอนนี้ต้องทำให้ คนที่ไม่ใช่โปรแกรมเมอร์ก็ใช้ได้

  • สิ่งนี้ทำให้นึกถึง naked objects แนวคิดคือแค่กำหนด annotation กับ theme บางอย่างในคลาส Java ก็จะสร้าง GUI ทั้งชุด หรือแอปพลิเคชัน web frontend ให้
    เป็นไอเดียที่เจ๋งมาก แต่เท่าที่ผมรู้ สุดท้ายก็ไม่ได้ไปได้สวยนัก

    • Django ก็มีปรัชญาคล้ายกัน กำหนด model แล้วสะท้อนไปเป็นตารางฐานข้อมูลได้ทันที และยังสร้าง form อัตโนมัติจาก model นั้นได้
      ในความเห็นผม ปัญหาคือ ข้อกังวลแนวตั้ง อย่าง presentation, domain และ infrastructure ถูกผูกเข้าด้วยกัน ถ้าการแสดงผลบนหน้าจอและการแทนค่าในฐานข้อมูลของ domain model เรียบง่ายก็ยังโอเค
      แต่ถ้าอยากทำอินเทอร์เฟซซับซ้อนที่มีฟีเจอร์อำนวยความสะดวกเยอะ ๆ ความต้องการเหล่านั้นก็ต้องรั่วไหลเข้าไปในชั้น domain ในทางกลับกัน ถ้าอยากทำ domain model ที่ซับซ้อน ก็แทบเป็นไปไม่ได้ที่จะบังคับ invariant ในระดับภาษา เพราะโค้ดใด ๆ ที่มี reference ไปยัง Model ก็แตะต้องมันได้ตามใจ
  • คงจะดีถ้ามีสิ่งที่ทำกลับกันได้ด้วย

    • คงจะดีถ้าสามารถตั้งค่า parameter sweep ใน GUI จากข้อมูลที่ดึงมาจาก argparse แล้วแปลงกลับเป็น shell script ที่รันและบันทึกผลลัพธ์ได้อย่างเหมาะสม
    • หมายถึง WYSIWYG editor ที่คาย CLI ออกมาหรือเปล่า? ฟังดูเท่มาก แต่คงมีข้อจำกัดบางอย่างอย่างเลี่ยงไม่ได้ อยากรู้ว่ามีใครเคยลองแนวทางแบบนั้นไหม แต่นึกตัวอย่างไม่ออก
  • Macintosh Programmer's Workshop รุ่นเก่า หรือ MPW ซึ่งเป็นเชลล์แบบข้อความสำหรับ Mac OS ยุค 80–90 มีฟีเจอร์คล้าย ๆ กันชื่อ Commando สำหรับแทบทุกคำสั่ง
    ข้อมูล Commando ถูกเก็บไว้ใน resource cmdo ถ้าการรองรับ extended attribute ไม่ได้กระท่อนกระแท่นแบบนี้ ทุกวันนี้ก็น่าจะทำอะไรคล้าย ๆ กันได้
    ลองค้นดูแล้ว A/UX ก็มี Commando ด้วย ถ้าดับเบิลคลิกคำสั่งเทอร์มินัลใน Finder จะมีกล่อง Commando โผล่มาให้เลือก option ของ CLI แล้วจากนั้นจึงรันในหน้าต่างเชลล์ ทุกวันนี้ถ้ารันคำสั่งเทอร์มินัลจาก Finder มันก็แค่รันในหน้าต่างเชลล์โดยไม่มี argument
    https://cohost.org/boredzo/post/804893-i-still-want-a-moder
    http://toastytech.com/guis/aux3.html