في هذا الدرس سنبني برنامج 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 تبقى نفسها.
ما الفرق بين 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 خطوة بخطوة
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 أو الملف يدويًا؛ الكود سينشئهما عند الحاجة.
الكود الكامل لمشروع المهام 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 مفهومة.
أفضل ممارسات للمشروع
- اجعل أسماء Subcommands واضحة مثل
addوlist. - اكتب
descriptionوhelpقصيرة ومباشرة. - قسّم منطق البرنامج إلى دوال بدل وضع كل شيء في كتلة واحدة.
- تحقق من البيانات قبل تخزينها؛ لذلك رفضنا المهمة الفارغة.
- استخدم
encoding="utf-8"عند حفظ نصوص عربية. - تعامل مع الأخطاء المتوقعة عندما يكبر المشروع.
- اختبر كل أمر، وليس المسار الناجح فقط.
إذا احتجت إلى معالجة Exceptions بتفصيل أكبر، راجع شرح try و except في بايثون. ولتنظيم الدوال المستخدمة هنا يمكنك مراجعة شرح Functions في بايثون.
كيف تطور مشروع CLI بعد ذلك؟
بعد أن تعمل أوامر add وlist وclear، لا تعِد كتابة المشروع من الصفر. أضف ميزة واحدة في كل مرة:
- أضف أمر
countلحساب عدد المهام. - أضف أمرًا لحذف مهمة محددة بدل مسح الكل.
- أضف حالة للمهمة: مكتملة أو غير مكتملة.
- انقل التخزين من TXT إلى JSON.
- أضف تأكيدًا قبل
clear. - اكتب README يحتوي على أمثلة التشغيل.
تدريب عملي
- أضف Subcommand باسم
count. - اجعل
clearيطلب تأكيدًا قبل المسح. - أضف Optional Argument مثل
--verboseلاحقًا لعرض تفاصيل أكثر. - جرّب كل الأوامر ثم شغّل
python main.py --help.
روابط تساعدك على متابعة المسار
- كورس بايثون بعد الأساسيات
- الدرس السابق: قراءة وكتابة ملفات CSV داخل مشروع بايثون
- الدرس التالي: شرح logging في بايثون
الخلاصة
لبناء برنامج CLI حقيقي في بايثون، استخدم argparse لتعريف Arguments وقراءة القيم من Terminal، ثم قسم منطق البرنامج إلى دوال واستخدم Subcommands عندما تحتوي الأداة على أكثر من عملية. في هذا الدرس طبقنا ذلك على مشروع مهام يدعم add وlist وclear ويحفظ البيانات في ملف.
{alertSuccess} الخطوة التالية الأفضل: أضف Command جديدًا بنفسك، ثم انتقل إلى درس logging في بايثون لتتعلم كيف تسجل أحداث الأدوات والمشاريع بدل الاعتماد على رسائل الطباعة فقط.



