استخدام بايثون لحوار برمجية تتطلب مدخلات المستخدم pexpect

نحتاج في بعض الأحيان للتعامل مع تطبيقات تتطلب مدخلا من المستخدم وفي عالم البرمجة فإننا كثيرا ما نحول الجهد البشري إلى آلي فبدل انتظار المستخدم لإدخال كلمة سر أو الاجابة بشكل ما فإننا نجعل ذلك آليا عن طريق النص البرمجي وهذا مفيد جدا في الأتمتة والاختبار.

برمجية Expect

في الصدفة أو الطرفية shell هناك أمر expect و autoexpect حيث يستخدمان لأتمتة برمجيات الطرفية فبعد تشغيل autoexpect ووضع نص برمجي ب bash أو sh كمعطى فإنه يسجل كيف يتعامل المستخدم مع هذا النص البرمجي ويسجل إجابات الحوار كاملا في سكربت بصيغة expect

بعدها يستخدم أمر expect لتشغيل النص البرمجي الذي ولدته autoexpect، لكن هذا في الطرفية فماذا عن فعل ذلك باستخدام بايثون بحيث يمكننا التحكم بسهولة أكبر بالعملية؟

برمجية Pexpect

هي برمجية بايثون تمكننا من تقليد عمل expect لكن من داخل بايثون. ولم أعثر فيها على معادل لـ autoexpect لأتمته عملية الكود لكنه يمكن بجهد قليل كتابة تعليماتها.

مثال عملي:

لتثبيت البرمجية وعمل بيئة وهمية للعمل بها داخل دليل مخصص:

mkdir test_pexpect && cd test_pexpect
pipenv shell
pipenv install pexpect

محاكاة برمجية تتطلب مدخلات

الآن لنأخذ مثلا نص بايثون الآتي الذي يتطلب حوارا مع المستخدم:

print('Enter your name:')
x = input()
print(f'Hello {x}')  

حيث نضع مدخلات المحاور في متغير x ثم نطبعها له بعد Hello.

لنحفظ هذا النص في ملف test_enter.py.

كتابة نص المحاورة باستخدام بايثون

لمحاورة هذه البرمجية آليا نكتب النص التالي مستخدمين expect:

import pexpect 
import sys

p = pexpect.spawn("python3 test_enter.py") # تشغيل النص البرمجي باستخدام بايثون#
p.logfile_read = sys.stdout.buffer # جعل المخرجات والمدخلات مرئية وإلا سينفذ التعليمات بصمت #
p.expect("Enter your name:") # توقع النص بين قوسين من النص البرمجي المشغّل #
p.sendline("Zaid") # إرسال نص إلى البرمجية #
p.expect(pexpect.EOF)

لنحفظ الملف بصغية بايثون ونشغله فنرى الآتي:

$ python3 pexpect_test.py 
Enter your name:
Zaid
Hello Zaid

كما نرى أرسل الأسم دون تدخل مننا بحسب قيمة مخزنة مسبقا في النص البرمجي.

ما الهدف من هذه العملية؟

أثناء تعاملي مع محفظة بيتكوين كاش التي أستخدمها في تشغيل عديد من البرمجيات فإني أحتاج لتجاوز طلب كلمة السر أثناء المحفظة، ورغم أن المحفظة لها واجهة سطر أوامر قوية وتدعم الأتمته لكن هذا الأمر فيه علة تتطلب إدخال يدوي من المستخدم.

وكنت قد ولدت لها السكربت التالي باستخدام autoexpect:

set timeout -1
spawn ./electron-cash --dir ""  create
match_max 100000
expect -exact "Password (hit return if you do not wish to encrypt your wallet):"
send -- "\r"
expect eof

وبعد جهد توصلت للسكربت الآتي باستخدام pexpect:

import pexpect 
import sys

python_exec = "/home/user/electron-cash-wallet/venv/bin/python"
ec_exec = "/home/user/electron-cash-wallet/src/Electron-Cash/electron-cash"

def create_wallet(python_exec, ec_exec, network):
    print("Python: ", python_exec)
    print("Electron Cash: ", ec_exec)
    # Execute the command
    p = pexpect.spawn(python_exec, [command, f"--{network}", "create"])
    # Verbose, show messages
    p.logfile_read = sys.stdout.buffer
    p.delaybeforesend = 2
    print("Exceution done")
    # Expect the response
    p.expect("Password \(hit return if you do not wish to encrypt your wallet\):")
    print("Expected input received")
    p.delaybeforesend = 1
    # Send return key
    p.sendline(b'\r')
    print("Sent response")
    p.expect(pexpect.EOF)
    print("Script done")

شُكر

أود أن أشكر مجتمع بيتكوين كاش على تقديمه التمويل اللازم لكتابة هذه المقالات التعليمية ونشر المعرفة البرمجية والتوعية في مجالات العملات الرقمية في العالم العربي وتطويره لبرمجيات حرة تمكن آليات التمويل الجماعي غير المركزي ك Flipstarter و IPFS Flipstarter الذي يمكن أي شخص من عمل حملة تمويل جماعي دون الحاجة لوسيط أو حتى استضافة ودون الحاجة لمحفظة خاصة.

image

3 إعجابات

أتوقع عنوان افضل سيكون
" استخدام بايثون لاتمته برمجية تتطلب مدخلات يدويه من المستخدم pexpect"
كلمه حوار غير واضحة ابدا, استطيع تعديله اذا أعجبك

شكرا لك أخي لكن كلمة حوار هي أقرب ل Dialog وهنا يجري حوار مع البرنامج يطرح أسئلة ويُجاب عنها.