بناء برنامج CLI في بايثون باستخدام argparse | بايثون بعد الأساسيات 4

بناء برنامج سطر أوامر CLI بسيط في Python بعد تعلم الأساسيات

في هذا الدرس سنبني برنامج CLI عمليًا باستخدام بايثون، ثم نجعله يستقبل القيم والأوامر من Terminal أو CMD باستخدام مكتبة argparse. سنبدأ بمثال صغير يفهم منه الفرق بين input() وArguments، ثم نبني مشروع مهام يعمل بأوامر مثل add وlist وclear.

CLI اختصار لـ Command Line Interface، أي واجهة سطر أوامر يتعامل معها المستخدم بكتابة أمر ومعاملات بدل الضغط على أزرار في واجهة رسومية. مثلًا سيكون تشغيل مشروعنا لاحقًا بهذا الشكل:

python main.py add "تعلم argparse"
{alertInfo} لإنشاء برنامج CLI في بايثون: أنشئ ملفًا للبرنامج، عرّف Arguments باستخدام argparse.ArgumentParser وadd_argument()، اقرأها باستخدام parse_args()، ثم شغّل الملف من Terminal مع القيم المطلوبة.

{getToc} $title={محتوى المقال}

ما هو CLI في بايثون؟

برنامج CLI هو برنامج تتعامل معه من سطر الأوامر. بدل نافذة رسومية، تكتب أمرًا في Terminal أو CMD أو PowerShell وتضيف إليه القيم أو الخيارات التي يحتاجها البرنامج.

python main.py
python main.py Ali
python main.py Ali --lang en
python main.py add "مهمة جديدة"

في أمثلة هذا المقال سنستخدم الأمر python. إذا كان نظامك يشغّل بايثون بالأمر python3، استبدل python به فقط؛ بقية Arguments تبقى نفسها.

شرح فكرة برنامج CLI في Python وكيف يتعامل المستخدم معه من Terminal

ما الفرق بين input() و argparse؟

الفرق الأساسي هو وقت إدخال القيمة. الدالة input() تطلب من المستخدم قيمة بعد بدء تشغيل البرنامج، بينما argparse تقرأ Arguments التي كتبها المستخدم مع أمر التشغيل نفسه.

الطريقة كيف تستقبل القيمة؟ مثال
input() يسأل المستخدم أثناء تشغيل البرنامج name = input("اسمك: ")
argparse تقرأ القيمة من أمر Terminal python main.py Ali

للتوضيح، هذا برنامج طرفية تفاعلي بسيط باستخدام input():

name = input("اكتب اسمك: ")
print("مرحبًا", name)

تشغله أولًا:

python main.py

ثم يطلب الاسم. هذه طريقة صحيحة للتفاعل، لكنها ليست Arguments لسطر الأوامر. عندما نريد كتابة القيم مع أمر التشغيل نفسه نستخدم argparse.

أول برنامج CLI باستخدام argparse

مكتبة argparse جزء من مكتبة بايثون القياسية، لذلك لا تحتاج إلى تثبيتها بـpip. أنشئ ملفًا باسم main.py واكتب:

import argparse

parser = argparse.ArgumentParser(
    description="برنامج ترحيب بسيط يعمل من سطر الأوامر"
)

parser.add_argument("name", help="اسم المستخدم")

args = parser.parse_args()

print("مرحبًا", args.name)

شغّل البرنامج مع الاسم:

python main.py Ali

الناتج:

مرحبًا Ali
استخدام argparse في Python لاستقبال أوامر وخيارات من سطر الأوامر

شرح argparse خطوة بخطوة

1. إنشاء ArgumentParser

parser = argparse.ArgumentParser(
    description="برنامج ترحيب بسيط يعمل من سطر الأوامر"
)

الكائن parser يعرف Arguments المتاحة ويقرأ ما يكتبه المستخدم عند تشغيل البرنامج.

2. إضافة Argument مطلوب

parser.add_argument("name", help="اسم المستخدم")

لأن الاسم لا يبدأ بشرطتين مثل --name فهو positional argument؛ أي قيمة مطلوبة يكتبها المستخدم في موضعها:

python main.py Ali

3. قراءة Arguments

args = parser.parse_args()

بعدها تصل إلى القيمة باسم الخاصية التي عرّفتها:

args.name

إضافة Optional Argument باستخدام --lang

الآن نضيف خيارًا اختياريًا يبدأ بـ--. إذا لم يكتبه المستخدم، ستكون اللغة الافتراضية عربية:

import argparse

parser = argparse.ArgumentParser(
    description="برنامج ترحيب بسيط"
)

parser.add_argument("name", help="اسم المستخدم")
parser.add_argument(
    "--lang",
    choices=["ar", "en"],
    default="ar",
    help="لغة الرسالة"
)

args = parser.parse_args()

if args.lang == "en":
    print("Hello", args.name)
else:
    print("مرحبًا", args.name)

بالعربية:

python main.py Ali

وبالإنجليزية:

python main.py Ali --lang en

استخدمنا choices حتى تقبل --lang القيمتين ar وen فقط، وتعرض argparse رسالة خطأ إذا وصلت قيمة أخرى.

صفحة المساعدة --help

من أهم مزايا argparse أنها تنشئ صفحة مساعدة تلقائيًا. جرّب:

python main.py --help

ستظهر طريقة الاستخدام وArguments المتاحة والنصوص الموجودة في help. لذلك اكتب أوصافًا قصيرة وواضحة بدل أن تجعل المستخدم يخمن طريقة تشغيل الأداة.

مشروع عملي: برنامج مهام CLI

بعد المثال الصغير سنبني مشروعًا فعليًا يدعم ثلاثة subcommands:

  • add: إضافة مهمة.
  • list: عرض المهام.
  • clear: مسح كل المهام.

سيعمل بهذه الصورة:

python main.py add "تعلم argparse"
python main.py list
python main.py clear

سنخزن المهام داخل ملف data/tasks.txt. يبقى المشروع بسيطًا، لكنه يجمع Arguments وSubcommands والدوال والتعامل مع ملف حقيقي.

هيكل مشروع CLI

simple_cli/
│
├── main.py
└── data/
    └── tasks.txt

لا تحتاج إلى إنشاء مجلد data أو الملف يدويًا؛ الكود سينشئهما عند الحاجة.

هيكل مشروع Python بسيط لبناء برنامج CLI يحتوي على main.py و README

الكود الكامل لمشروع المهام CLI

ضع الكود التالي داخل main.py:

import argparse
from pathlib import Path


BASE_DIR = Path(__file__).resolve().parent
DATA_DIR = BASE_DIR / "data"
TASKS_FILE = DATA_DIR / "tasks.txt"


def prepare_storage():
    DATA_DIR.mkdir(exist_ok=True)
    TASKS_FILE.touch(exist_ok=True)


def add_task(task):
    task = task.strip()

    if not task:
        print("لا يمكن إضافة مهمة فارغة.")
        return

    prepare_storage()

    with TASKS_FILE.open("a", encoding="utf-8") as file:
        file.write(task + "\n")

    print("تمت إضافة المهمة:", task)


def list_tasks():
    prepare_storage()

    with TASKS_FILE.open("r", encoding="utf-8") as file:
        tasks = [
            line.strip()
            for line in file
            if line.strip()
        ]

    if not tasks:
        print("لا توجد مهام حاليًا.")
        return

    print("قائمة المهام:")

    for index, task in enumerate(tasks, start=1):
        print(f"{index}. {task}")


def clear_tasks():
    prepare_storage()
    TASKS_FILE.write_text("", encoding="utf-8")
    print("تم مسح جميع المهام.")


def main():
    parser = argparse.ArgumentParser(
        description="برنامج مهام بسيط يعمل من سطر الأوامر"
    )

    subparsers = parser.add_subparsers(
        dest="command",
        required=True
    )

    add_parser = subparsers.add_parser(
        "add",
        help="إضافة مهمة جديدة"
    )
    add_parser.add_argument("task", help="نص المهمة")

    subparsers.add_parser("list", help="عرض المهام")
    subparsers.add_parser("clear", help="مسح كل المهام")

    args = parser.parse_args()

    if args.command == "add":
        add_task(args.task)
    elif args.command == "list":
        list_tasks()
    elif args.command == "clear":
        clear_tasks()


if __name__ == "__main__":
    main()

تشغيل مشروع CLI وتجربة الأوامر

من Terminal افتح مجلد المشروع ثم جرّب الأوامر التالية.

إضافة مهمة

python main.py add "تعلم بناء CLI في بايثون"

الناتج:

تمت إضافة المهمة: تعلم بناء CLI في بايثون

عرض المهام

python main.py list

الناتج بعد إضافة المهمة السابقة:

قائمة المهام:
1. تعلم بناء CLI في بايثون

مسح المهام

python main.py clear

الناتج:

تم مسح جميع المهام.

عرض المساعدة

python main.py --help

ما معنى Subcommands في argparse؟

الأوامر add وlist وclear هي Subcommands. نستخدمها عندما تؤدي الأداة أكثر من عملية، بحيث يختار المستخدم العملية مباشرة من أمر التشغيل:

python main.py add "Task"
python main.py list
python main.py clear

داخل الكود أنشأناها باستخدام add_subparsers() ثم add_parser(). أما النص بعد add فهو positional argument اسمه task.

لماذا استخدمنا pathlib؟

استخدمنا pathlib لبناء مسار ملف المهام بطريقة تعمل على Windows وLinux وmacOS:

BASE_DIR = Path(__file__).resolve().parent
DATA_DIR = BASE_DIR / "data"
TASKS_FILE = DATA_DIR / "tasks.txt"

بهذا يرتبط مجلد data بمكان ملف main.py نفسه بدل الاعتماد على المجلد الحالي الذي شغلت الأمر منه. إذا أردت شرحًا أوسع للمسارات، راجع شرح pathlib في بايثون للتعامل مع الملفات والمجلدات.

أخطاء شائعة عند بناء برنامج CLI

1. تشغيل الملف من مسار غير صحيح

إذا ظهر أن النظام لا يجد main.py، تأكد أنك داخل مجلد المشروع أو استخدم المسار الصحيح للملف. لا نوسع شرح Terminal هنا لأن هدف الدرس هو بناء الأداة نفسها.

2. نسيان Argument مطلوب

في المثال الأول، هذا الأمر ناقص:

python main.py

لأن البرنامج يحتاج positional argument اسمه name. ستعرض argparse رسالة usage وخطأ مناسبًا تلقائيًا.

3. كتابة اسم خيار غير صحيح

إذا عرّفت --lang فلا تستخدم --language إلا إذا أضفته فعليًا في الكود.

4. الخلط بين input() وArguments

استخدم input() عندما تريد سؤال المستخدم أثناء التنفيذ. واستخدم argparse عندما تريد أن يمرر القيم والأوامر مع أمر التشغيل.

5. عدم اختبار --help

صفحة المساعدة جزء مهم من تجربة CLI. شغّل:

python main.py --help

وتأكد أن أسماء الأوامر ورسائل help مفهومة.

أفضل ممارسات بناء برامج CLI في Python وتنظيم الأوامر والرسائل

أفضل ممارسات للمشروع

  • اجعل أسماء Subcommands واضحة مثل add وlist.
  • اكتب description وhelp قصيرة ومباشرة.
  • قسّم منطق البرنامج إلى دوال بدل وضع كل شيء في كتلة واحدة.
  • تحقق من البيانات قبل تخزينها؛ لذلك رفضنا المهمة الفارغة.
  • استخدم encoding="utf-8" عند حفظ نصوص عربية.
  • تعامل مع الأخطاء المتوقعة عندما يكبر المشروع.
  • اختبر كل أمر، وليس المسار الناجح فقط.

إذا احتجت إلى معالجة Exceptions بتفصيل أكبر، راجع شرح try و except في بايثون. ولتنظيم الدوال المستخدمة هنا يمكنك مراجعة شرح Functions في بايثون.

كيف تطور مشروع CLI بعد ذلك؟

بعد أن تعمل أوامر add وlist وclear، لا تعِد كتابة المشروع من الصفر. أضف ميزة واحدة في كل مرة:

  • أضف أمر count لحساب عدد المهام.
  • أضف أمرًا لحذف مهمة محددة بدل مسح الكل.
  • أضف حالة للمهمة: مكتملة أو غير مكتملة.
  • انقل التخزين من TXT إلى JSON.
  • أضف تأكيدًا قبل clear.
  • اكتب README يحتوي على أمثلة التشغيل.

تدريب عملي

  1. أضف Subcommand باسم count.
  2. اجعل clear يطلب تأكيدًا قبل المسح.
  3. أضف Optional Argument مثل --verbose لاحقًا لعرض تفاصيل أكثر.
  4. جرّب كل الأوامر ثم شغّل python main.py --help.

روابط تساعدك على متابعة المسار

الخلاصة

لبناء برنامج CLI حقيقي في بايثون، استخدم argparse لتعريف Arguments وقراءة القيم من Terminal، ثم قسم منطق البرنامج إلى دوال واستخدم Subcommands عندما تحتوي الأداة على أكثر من عملية. في هذا الدرس طبقنا ذلك على مشروع مهام يدعم add وlist وclear ويحفظ البيانات في ملف.

{alertSuccess} الخطوة التالية الأفضل: أضف Command جديدًا بنفسك، ثم انتقل إلى درس logging في بايثون لتتعلم كيف تسجل أحداث الأدوات والمشاريع بدل الاعتماد على رسائل الطباعة فقط.

إرسال تعليق

أحدث أقدم