cmd --- پشتیبانی از مفسرهای فرمان خطمحور¶
کد منبع: Lib/cmd.py
کلاس Cmd یک چارچوب ساده برای نوشتن مفسرهای فرمان خطمحور فراهم میکند. این مفسرها اغلب برای مهارهای آزمون، ابزارهای مدیریتی و پیشنمونههایی مفید هستند که بعداً در یک رابط پیشرفتهتر قرار خواهند گرفت.
- class cmd.Cmd(completekey='tab', stdin=None, stdout=None)¶
یک نمونه از
Cmdیا نمونهای از یک زیرکلاس، یک چارچوب مفسر خطمحور است. دلیل موجهی برای نمونهسازی خودCmdوجود ندارد؛ در عوض، این کلاس بهعنوان ابرکلاسِ کلاس مفسری که خودتان تعریف میکنید مفید است، تا متدهایCmdرا به ارث ببرید و متدهای عملیاتی را کپسوله کنید.آرگومان اختیاری completekey نام کلید تکمیل در
readlineاست؛ پیشفرض آن Tab است. اگر completekey برابرNoneنباشد وreadlineدر دسترس باشد، تکمیل فرمان بهطور خودکار انجام میشود.مقدار پیشفرض،
'tab'، بهطور ویژهای رفتار میشود، بهطوریکه به کلید Tab در هرreadline.backendاشاره میکند. بهطور مشخص، اگرreadline.backendبرابرeditlineباشد،Cmdبهجای'tab'از'^I'استفاده میکند. توجه داشته باشید که سایر مقادیر اینگونه رفتار نمیشوند و ممکن است فقط با یک بکاند خاص کار کنند.آرگومانهای اختیاری stdin و stdout اشیای پرونده ورودی و خروجی را مشخص میکنند که نمونه Cmd یا نمونه زیرکلاس برای ورودی و خروجی از آنها استفاده خواهد کرد. اگر مشخص نشده باشند، مقادیر پیشفرض آنها
sys.stdinوsys.stdoutخواهند بود.اگر میخواهید از یک stdin دادهشده استفاده شود، حتماً ویژگی
use_rawinputنمونه را رویFalseتنظیم کنید، در غیر این صورت از stdin صرفنظر میشود.تغییر یافته در نسخهی 3.13:
completekey='tab'برایeditlineبا'^I'جایگزین میشود.
اشیای Cmd¶
نمونهای از Cmd دارای متدهای زیر است:
- Cmd.cmdloop(intro=None)¶
بهطور مکرر یک اعلان صادر میکند، ورودی را میپذیرد، یک پیشوند آغازین را از ورودی دریافتشده تجزیه میکند و متدهای عملیاتی را فراخوانی میکند و باقیماندهی خط را بهعنوان آرگومان به آنها میفرستد.
آرگومان اختیاری یک رشته بنر یا مقدمه است که پیش از اولین اعلان نمایش داده میشود (این مورد، ویژگی کلاس
introرا نادیده میگیرد).اگر ماژول
readlineبارگذاری شده باشد، ورودی بهطور خودکار ویرایش فهرست تاریخچهی مشابه bash را به ارث میبرد (برای مثال Control-P به آخرین فرمان بازمیگردد، Control-N به فرمان بعدی میرود، Control-F مکاننما را به سمت راست بهصورت غیرمخرب حرکت میدهد، Control-B مکاننما را به سمت چپ بهصورت غیرمخرب حرکت میدهد، و غیره).پایان پرونده در ورودی بهعنوان رشته
'EOF'برگردانده میشود.نمونهای از مفسر، نام فرمان
fooرا اگر و تنها اگر متدdo_foo()را داشته باشد، میشناسد. در حالتی خاص، سطری که با نویسه'?'آغاز میشود، به متدdo_help()ارجاع داده میشود. در حالت خاص دیگر، سطری که با نویسه'!'آغاز میشود، به متدdo_shell()ارجاع داده میشود (اگر چنین متدی تعریف شده باشد).این متد زمانی برمیگردد که متد
postcmd()مقدار درستی را برگرداند. آرگومان stop برایpostcmd()، مقدار بازگشتی از متدdo_*()متناظر با فرمان است.اگر تکمیل فعال باشد، تکمیل دستورها بهصورت خودکار انجام میشود و تکمیل آرگومانهای دستورها با فراخوانی
complete_foo()با آرگومانهای text، line، begidx و endidx انجام میشود. text پیشوند رشتهای است که سعی در تطبیق آن داریم: همه موارد منطبق برگرداندهشده باید با آن آغاز شوند. line خط ورودی جاری با حذف فضای سفید ابتدایی است، begidx و endidx اندیسهای آغاز و پایان متن پیشوند هستند که میتوان از آنها برای ارائه تکمیل متفاوت بسته به موقعیت آرگومان استفاده کرد.
- Cmd.do_help(arg)¶
همهی زیرکلاسهای
Cmdیک متدdo_help()از پیش تعریفشده را به ارث میبرند. وقتی این متد با آرگومان'bar'فراخوانی شود، متد متناظرhelp_bar()را فراخوانی میکند، و اگر آن متد موجود نباشد، رشته مستند مربوط بهdo_bar()را در صورت موجود بودن چاپ میکند. بدون آرگومان،do_help()همهی موضوعات راهنمای در دسترس را فهرست میکند (یعنی همهی فرمانهایی که متدهای متناظرhelp_*()دارند یا فرمانهایی که رشته مستندات دارند)، و همچنین فرمانهای بدون مستند را نیز فهرست میکند.
- Cmd.onecmd(str)¶
آرگومان را چنان تفسیر میکند که گویی در پاسخ به اعلان تایپ شده است. این را میتوان بازنویسی کرد، اما معمولاً نیازی به این کار نیست؛ برای قلابهای اجرای مفید، متدهای
precmd()وpostcmd()را ببینید. مقدار بازگشتی، پرچمی است که نشان میدهد آیا تفسیر دستورات توسط مفسر باید متوقف شود یا خیر. اگر برای دستور str یک متدdo_*()وجود داشته باشد، مقدار بازگشتی آن متد برگردانده میشود، در غیر این صورت مقدار بازگشتی از متدdefault()برگردانده میشود.
- Cmd.emptyline()¶
متدی که هنگام وارد شدن یک خط خالی در پاسخ به اعلان فراخوانی میشود. اگر این متد بازنویسی نشده باشد، آخرین فرمان غیرخالی واردشده را تکرار میکند.
- Cmd.default(line)¶
متدی که وقتی پیشوند فرمان شناسایی نشود، بر روی یک خط ورودی فراخوانی میشود. اگر این متد بازنویسی نشود، یک پیام خطا چاپ میکند و بازمیگردد.
- Cmd.completedefault(text, line, begidx, endidx)¶
متدی که برای تکمیل یک خط ورودی فراخوانی میشود، هنگامی که هیچ متد مخصوص دستور
complete_*()در دسترس نباشد. بهطور پیشفرض، یک فهرست خالی برمیگرداند.
- Cmd.columnize(list, displaywidth=80)¶
متدی که فراخوانی میشود تا فهرستی از رشتهها را بهصورت مجموعهای فشرده از ستونها نمایش دهد. هر ستون تنها به اندازهی ضرورت عرض دارد. ستونها برای خوانایی با دو فاصله از هم جدا میشوند.
- Cmd.precmd(line)¶
متد قلابکه درست پیش از تفسیر خط فرمان line، اما پس از تولید و صدور اعلان ورودی اجرا میشود. این متد در
Cmdیک stub است؛ وجود دارد تا در زیرکلاسها بازنویسی شود. مقدار بازگشتی بهعنوان فرمانی استفاده میشود که متدonecmd()آن را اجرا خواهد کرد؛ پیادهسازیprecmd()ممکن است فرمان را بازنویسی کند یا صرفاً line را بدون تغییر بازگرداند.
- Cmd.postcmd(stop, line)¶
متد قلابی که درست پس از پایان توزیع یک فرمان اجرا میشود. این متد یک stub در
Cmdاست و برای بازنویسی توسط زیرکلاسها وجود دارد. line خط فرمانی است که اجرا شده است و stop پرچمی است که نشان میدهد آیا اجرا پس از فراخوانیpostcmd()خاتمه خواهد یافت یا خیر؛ این، مقدار بازگشتی متدonecmd()خواهد بود. مقدار بازگشتی این متد بهعنوان مقدار جدید برای پرچم داخلی متناظر با stop استفاده خواهد شد؛ بازگرداندن false باعث ادامهی تفسیر خواهد شد.
- Cmd.preloop()¶
متد قلابکه یک بار هنگام فراخوانی
cmdloop()اجرا میشود. این متد درCmdیک متد stub است؛ وجود دارد تا توسط زیرکلاسها بازنویسی شود.
- Cmd.postloop()¶
متد قلابکه یک بار اجرا میشود، هنگامی که
cmdloop()در آستانهی بازگشت است. این متد درCmdیک stub است؛ این متد وجود دارد تا توسط زیرکلاسها بازنویسی شود.
نمونههای زیرکلاسهای Cmd دارای چند متغیر نمونه عمومی هستند:
- Cmd.prompt¶
اعلان صادرشده برای درخواست ورودی.
- Cmd.identchars¶
رشتهای از نویسهها که برای پیشوند فرمان پذیرفته میشود.
- Cmd.lastcmd¶
آخرین پیشوند غیرخالی دستور مشاهدهشده.
- Cmd.cmdqueue¶
فهرستی از سطرهای ورودی صفشده. فهرست cmdqueue در
cmdloop()هنگامی که به ورودی جدیدی نیاز باشد بررسی میشود؛ اگر خالی نباشد، عناصر آن به ترتیب پردازش میشوند، گویی در اعلان وارد شدهاند.
- Cmd.intro¶
رشتهای که بهعنوان مقدمه یا بنر صادر میشود. ممکن است با دادن یک آرگومان به متد
cmdloop()بازنویسی شود.
- Cmd.doc_header¶
سرآیندی که اگر خروجی راهنما دارای بخشی برای دستورهای مستندشده باشد، نمایش داده میشود.
- Cmd.misc_header¶
سرآیندی که اگر خروجی راهنما دارای بخشی برای موضوعات متفرقهی راهنما باشد، صادر میشود (یعنی متدهای
help_*()بدون متدهای متناظرdo_*()وجود داشته باشند).
- Cmd.undoc_header¶
سرآیندای که در صورت وجود داشتن بخشی برای فرمانهای مستندنشده در خروجی help، نمایش داده میشود (یعنی متدهای
do_*()بدون متدهایhelp_*()متناظر وجود دارند).
- Cmd.ruler¶
نویسهای که برای رسم سطرهای جداکننده زیر سرآیندهای پیام راهنما استفاده میشود. اگر خالی باشد، هیچ خط جداکنندهای رسم نمیشود. مقدار پیشفرض آن
'='است.
- Cmd.use_rawinput¶
پرچمی که مقدار پیشفرض آن true است. اگر true باشد،
cmdloop()ازinput()برای نمایش یک اعلان و خواندن فرمان بعدی استفاده میکند؛ اگر false باشد، ازsys.stdout.write()وsys.stdin.readline()استفاده میشود. (این بدان معناست که با ایمپورت کردنreadline، در سامانههایی که از آن پشتیبانی میکنند، مفسر بهطور خودکار از ویرایش خط مشابه Emacs و کلیدهای تاریخچهی فرمان پشتیبانی میکند.)
مثال Cmd¶
ماژول cmd عمدتاً برای ساخت پوستههای سفارشی مفید است که به کاربر امکان میدهند با یک برنامه بهصورت تعاملی کار کند.
این بخش یک مثال ساده از چگونگی ساختن پوستهای حول چند مورد از دستورات ماژول turtle ارائه میدهد.
دستورات پایه turtle مانند forward() به یک زیرکلاس از Cmd با متدی به نام do_forward() اضافه میشوند. آرگومان به یک عدد تبدیل میشود و به ماژول turtle فرستاده میشود. رشته مستند در ابزار راهنمای ارائهشده توسط پوسته استفاده میشود.
این مثال همچنین شامل یک امکان ضبط و بازپخش ساده است که با متد precmd() پیادهسازی شده است؛ این متد مسئول تبدیل ورودی به حروف کوچک و نوشتن دستورات در یک پرونده است. متد do_playback() پرونده را میخواند و دستورات ضبطشده را برای بازپخش فوری به cmdqueue اضافه میکند:
import cmd, sys
from turtle import *
class TurtleShell(cmd.Cmd):
intro = 'Welcome to the turtle shell. Type help or ? to list commands.\n'
prompt = '(turtle) '
file = None
# ----- basic turtle commands -----
def do_forward(self, arg):
'Move the turtle forward by the specified distance: FORWARD 10'
forward(*parse(arg))
def do_right(self, arg):
'Turn turtle right by given number of degrees: RIGHT 20'
right(*parse(arg))
def do_left(self, arg):
'Turn turtle left by given number of degrees: LEFT 90'
left(*parse(arg))
def do_goto(self, arg):
'Move turtle to an absolute position with changing orientation. GOTO 100 200'
goto(*parse(arg))
def do_home(self, arg):
'Return turtle to the home position: HOME'
home()
def do_circle(self, arg):
'Draw circle with given radius an options extent and steps: CIRCLE 50'
circle(*parse(arg))
def do_position(self, arg):
'Print the current turtle position: POSITION'
print('Current position is %d %d\n' % position())
def do_heading(self, arg):
'Print the current turtle heading in degrees: HEADING'
print('Current heading is %d\n' % (heading(),))
def do_color(self, arg):
'Set the color: COLOR BLUE'
color(arg.lower())
def do_undo(self, arg):
'Undo (repeatedly) the last turtle action(s): UNDO'
def do_reset(self, arg):
'Clear the screen and return turtle to center: RESET'
reset()
def do_bye(self, arg):
'Stop recording, close the turtle window, and exit: BYE'
print('Thank you for using Turtle')
self.close()
bye()
return True
# ----- record and playback -----
def do_record(self, arg):
'Save future commands to filename: RECORD rose.cmd'
self.file = open(arg, 'w')
def do_playback(self, arg):
'Playback commands from a file: PLAYBACK rose.cmd'
self.close()
with open(arg) as f:
self.cmdqueue.extend(f.read().splitlines())
def precmd(self, line):
line = line.lower()
if self.file and 'playback' not in line:
print(line, file=self.file)
return line
def close(self):
if self.file:
self.file.close()
self.file = None
def parse(arg):
'Convert a series of zero or more numbers to an argument tuple'
return tuple(map(int, arg.split()))
if __name__ == '__main__':
TurtleShell().cmdloop()
در اینجا یک نشست نمونه با پوسته turtle آمده است که توابع راهنما، استفاده از سطرهای خالی برای تکرار دستورها و قابلیت ساده ضبط و پخش را نشان میدهد:
به پوسته turtle خوش آمدید. برای فهرست کردن دستورها، help یا ? را وارد کنید.
(turtle) ?
دستورهای مستندشده (help <topic> را وارد کنید):
========================================
bye color goto home playback record right
circle forward heading left position reset undo
(turtle) help forward
لاکپشت را به اندازه فاصله مشخصشده به جلو حرکت دهید: FORWARD 10
(turtle) record spiral.cmd
(turtle) position
موقعیت فعلی ۰ ۰ است
(turtle) heading
جهت فعلی ۰ است
(turtle) reset
(turtle) circle 20
(turtle) right 30
(turtle) circle 40
(turtle) right 30
(turtle) circle 60
(turtle) right 30
(turtle) circle 80
(turtle) right 30
(turtle) circle 100
(turtle) right 30
(turtle) circle 120
(turtle) right 30
(turtle) circle 120
(turtle) heading
جهت فعلی ۱۸۰ است
(turtle) forward 100
(turtle)
(turtle) right 90
(turtle) forward 100
(turtle)
(turtle) right 90
(turtle) forward 400
(turtle) right 90
(turtle) forward 500
(turtle) right 90
(turtle) forward 400
(turtle) right 90
(turtle) forward 300
(turtle) playback spiral.cmd
موقعیت فعلی ۰ ۰ است
جهت فعلی ۰ است
جهت فعلی ۱۸۰ است
(turtle) bye
از شما برای استفاده از Turtle سپاسگزاریم