zzyb 发表于 2010-5-15 11:00:31

MushPy: a Python framework on top of Mushclient's API

大家好,我最近写了一个Python框架用于开发Mushclient机器人。这个基于mushclient的api,和mushclient api的区别是,这个是一个更“pythonic”的方法,并且更方便使用。例如,用decorator创建一个trigger:@Trigger.make("一个regexp", ...):
def callback_function(name,line,wc):
# ...
pass再例如,直接用print语句打印到mushclient notepad:notepad = McTerminal("Title")
print >> notepad, "hello world!"如果替换sys.stdout:import sys
sys.stdout = McTerminal("standard output")所有的程序,只要print到stdout的,都会被redirect到这个notepad!方便吧!

还有最得意的,python的coroutine,也就是Lua的wait:@coroutine
def a_coroutine():
yield
do_something()
args, kwargs = yeild ('timer', 0,0,10) # 等待10秒

args, kwargs = yield ('regexp', '一个触发器')#触发后继续执行下面的语句!
# ...原帖看这里:http://mushclient.com/forum/?id=10283

下载在这里:http://code.google.com/p/mushpy/downloads/list

This is to announce a Python framework for Mushclient's API. It is a
more "Pythonic" way to develop MUD automations. Currently, there are
several modules available:* terminal.py:
    Construct a Python file-like object for the Mushclient's notepads

* objects.py:
    * Trigger
    * Alias
    * Timer

* coroutine.py:
    * Decorate a callable to use it as a coroutine.The package can be downloaded from here: http://code.google.com/p/mushpy/downloads/list

Package details:

=============
Terminal
=============Help on class McTerminal in module mushpy.terminals:

class McTerminal
|Construct a Python file-like object for the Mushclient's notepads.
|
|This is an abstraction of Mushclient's notepads for the ease of use in
|Python. An example is better than thousand words:
|
|      >>> import sys
|      >>> sys.stdout = McTerminal("Standard Output")
|
|      >>> print "Hello world"
|
|Once sys.stdout is been replace by an McTerminal instance, all codes that
|write to stdout (print, etc.) will be directed to a Mushclient's notepad
|titled "Standard Output". Fancy, heh?
|
|When instantiating, several keyword options can be used:
|
|      * time_stamp: (boolean) prefix a time stamp to each line, default to False
|      * prompt_to_save: (boolean) prompt to save on exit, default to False
|      * read_only: (boolean) if the notepad is readonly. default to True
|
|An example:
|      
|      >>> notepad = McTerminal( "An McTerminal Example", time_stamp=True, read_only=True )
|      >>> print >> notepad, "Hello world!"
|      >>> print >> notepad, "Yeah! It's so easy to use Mushclient!"
|
|The output:
|
|      05/14/10 22:01:26: Initializing...
|      05/14/10 22:03:41: Hello world!
|      05/14/10 22:03:57: Yeah! It's so easy to use Mushclient!============
Trigger
============Help on class Trigger in module mushpy.objects:

class Trigger(McObject)
|The Python wrapper of a trigger representation.
|
|This is a thin layer on top of Mushclient's trigger API.
|
|The Trigger class only can be instantiate by a name (optional):
|
|      >> trig = Trigger("trigger_name")
|
|or without a name:
|
|      >> trig = Trigger()
|
|One can test if a trigger object has a trigger object exists in Mushclient:
|
|      >> trig.exists()
|
|A trigger w/o name will return False. If a trigger does not exists, one can
|create one with:
|
|      >> trig.create( "pattern", group="group_name", one_shot=1, ... )
|
|The options are listed in Mushclient's document under SetTriggerOption().
|
|If the trigger is instantiated without a name specified, a unique one will
|be assigned to be when created in Mushclient.
|
|If the trigger with the specified name exists, many details about it can be
|retreived or set, like a Python dict:
|
|      >> print trig['group']
|      >> print trig['match']
|      >> print trig['enabled']
|      >> print trig['one_shot']
|      >> # ...
|
|      >> trig['group'] = 'new_group_name'
|      >> trig['enabled'] = 0 # disable
|
|Some methods can be used:
|
|      >>> trig.disable()
|      >>> trig.enable()
|      >>> trig.delete()   # this will delete the underlying mushclient trigger
|
|One powerfull feature built beyond Mushclient is the callback function:
|
|      >>> def func(name, line, wc):
|      ...   pass
|
|      >>> trig.callback = func
|
|Once the trigger is matched, func will be called. Callback can be accessed like an attribute:
|
|      >>> print trig.callback
|
|It can also be deleted:
|
|      >>> del trig.callback
|
|Note that the callback, once set, will overwrite the existing "script"
|option. Even it is deleted, the original "script" option will not be
|restored. However, it is more convenient to use callback so that "script"
|option need not to be set explicitly any more.
|
|WARNING: Do not try to modify a trigger's "script" option once a callback
|is used. Because MushPy uses a global dispatcher to dispatch (invoke)
|callbacks for all triggers that has a callback registered. In other words,
|when a callback is set for a trigger, the trigger's "script" option is set
|to the global dispatcher. Once changed, when the trigger fires, dispatcher
|will not be invoked, as a result, the desired call back will not be invoked
|either.
|
|On top of the powerfull callback, the decorator is proudly presented:
|
|      >>> @Trigger.make( "some pattern", group="group_name", one_shot=1, ... )
|      ... def callback( name, line, wc ):
|      ...   pass
|
|Therefore, a trigger will be created. The function "callback" will be
|registered as the trigger's callback.
|
|The trigger object is accessible as the callback's attribute. Since a
|callback function may be used by multiple triggers, multiple aliases, and
|multiple timers, it has a set, "mc_objects", to store all its connected
|triggers/aliases/timers.
|
|      >>> for obj in trig.mc_objects:
|      ...   print obj['name']==============
Alias
==============Help on class Alias in module mushpy.objects:

class Alias(McObject)
|The Python wrapper of Mushclient's Alias
|
|Usage is the same as Trigger.=============
Timer
=============Help on class Timer in module mushpy.objects:

class Timer(McObject)
|Python wrapper of Mushclient's Timer.
|
|Usage is similar to Trigger/Alias, with a few exceptions.
|
|To instantiate:
|      
|      >>> timer = Timer( hour, minute, second, option1=value1, option2=value2, ... )
|
|To use as a decorator
|
|      >>> @Timer.make( hour, minute, second, )
|      >>> def callback( name ):
|      ...   pass==============
Coroutine
==============Help on class coroutine in module mushpy.coroutine:

class coroutine(__builtin__.object)
|Decorate a callable to use it as a coroutine.
|
|Usage:
|      @coroutine()
|      def bla():
|          pass
|
|or
|      def bla(): pass
|      bla = coroutine()(bla)
|
|To write a coroutine, there is a protocol to follow:
|      
|      1. The decorated callable takes the arguments to generate the
|      generator. If you don't know what it is, just ignore it and use no
|      arguments.
|
|      2. On the first line of the coroutine, you must use the following yield
|      statement to receive the arguments from the caller.
|
|          args, kwargs = yield
|
|      3. Likewise, each time you yield, the return value of the yield
|      statement will be (args, kwargs) from the caller.
|
|      4. (Feature) You can use the following yields to specify when to resume
|      running the code below the yields:
|
|          # resume after 5 seconds
|          args, kwargs = yield ('timer', 0,0,5)
|
|          # resume when the pattern matched
|          args, kwargs = yield ('match', r'some regular expression pattern')
|
|      5. When the coroutine returns, the caller will receive the return value
|      StopIteration. Otherwise, the caller will always receive the return
|      value None. Since it's not the attemp of a coroutine to return
|      something to the caller, but resume doing something at times, I
|      currently do not plan to provide a protocol for returning a meaningfull
|      value to the caller.
|
|An example of using coroutines:
|
|@coroutine(arg_to_aCoroutine)
|def aCoroutine(arg_to_aCoroutine):
|      args, kwargs = yield    # Must have this at the first line
|      print 'arguments of the first call', args, kwargs
|
|      args, kwargs = yield ('timer', 0,0,3)
|      print '3 seconds have passed. Arguments:', args, kwargs
|
|      args, kwargs = yield ('match', r'hello world')
|      print 'I see "hello world" from the MUD output. Arguments:', args, kwargs
|
|      # Coroutine returns here. Caller will receive StopIteration
|      return

maper 发表于 2010-5-15 11:08:18

ttk_00 ttk_00 ttk_00

lzkd 发表于 2010-5-15 11:09:48

支持,顶一个.
高手好多.
可惜,我不会Python

ljyinvader 发表于 2010-5-15 11:10:17

膜拜一下大牛

zgbl 发表于 2010-5-15 11:39:02

已转至http://pkuxkx.com/wiki/robot/other

ddid 发表于 2010-5-15 12:11:55

最好放些简单的demo。

bluse 发表于 2010-5-15 18:49:18

后排学习来的

zzyb 发表于 2010-5-15 21:41:08

原帖由 zgbl 于 2010-5-15 11:39 AM 发表 http://pkuxkx.com/forum/images/common/back.gif
已转至http://pkuxkx.com/wiki/robot/other

谢谢加精

zzyb 发表于 2010-5-15 21:48:37

回复 1楼 的帖子

对了。这个package还带有一个测试模块:mushpy.tests

由于时间有限,目前只有测试Trigger的测试程序,希望大家帮我添加更多的测试,完善这个framework。

希望大家能够一起参与进来。

zgbl 发表于 2013-1-12 21:25:42

我去,chrome继续坑爹中,召唤@nol @seagate 来加精
页: [1]
查看完整版本: MushPy: a Python framework on top of Mushclient's API