[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Python
. . -> [Subject]  MushPy: a Python framework on top of Mushclient's API

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

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page


Posted by Icewolf   (17 posts)  [Biography] bio
Date Sat 15 May 2010 02:41 AM (UTC)
Message
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
[Go to top] top

Posted by Icewolf   (17 posts)  [Biography] bio
Date Reply #1 on Sat 15 May 2010 02:42 AM (UTC)
Message

=============
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!

[Go to top] top

Posted by Icewolf   (17 posts)  [Biography] bio
Date Reply #2 on Sat 15 May 2010 02:43 AM (UTC)
Message

============
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']


[Go to top] top

Posted by Icewolf   (17 posts)  [Biography] bio
Date Reply #3 on Sat 15 May 2010 02:44 AM (UTC)
Message

==============
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, [keyword options...] )
 |      >>> def callback( name ):
 |      ...     pass

[Go to top] top

Posted by Icewolf   (17 posts)  [Biography] bio
Date Reply #4 on Sat 15 May 2010 02:44 AM (UTC)

Amended on Sat 15 May 2010 02:47 AM (UTC) by Icewolf

Message

==============
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

[Go to top] top

Posted by Coderunner   USA  (27 posts)  [Biography] bio
Date Reply #5 on Sat 15 May 2010 03:38 AM (UTC)
Message
Wow, this looks awesome! I think this could turn out to be a really powerful tool.
[Go to top] top

Posted by Icewolf   (17 posts)  [Biography] bio
Date Reply #6 on Sat 15 May 2010 01:36 PM (UTC)
Message
Coderunner said:

Wow, this looks awesome! I think this could turn out to be a really powerful tool.


Thanks. I actually already have something small based on this "framework". It'd be great if ppl join me or at least give me some feedback:)
[Go to top] top

Posted by CJI   Poland  (7 posts)  [Biography] bio
Date Reply #7 on Wed 14 Jul 2010 10:51 AM (UTC)
Message
One little addition I'd suggest - in consts.py you define class to hold return codes. I ran it through simple regexp to obtain this dictionary:


smart_ret = { 0 : "No error",
30001 : "The world is already open",
30002 : "The world is closed, this action cannot be performed",
30003 : "No name has been specified where one is required",
30004 : "The sound file could not be played",
30005 : "The specified trigger name does not exist",
30006 : "Attempt to add a trigger that already exists",
30007 : "The trigger 'match' string cannot be empty",
30008 : "The name of this object is invalid",
30009 : "Script name is not in the script file",
30010 : "The specified alias name does not exist",
30011 : "Attempt to add a alias that already exists",
30012 : "The alias 'match' string cannot be empty",
30013 : "Unable to open requested file",
30014 : "Log file was not open",
30015 : "Log file was already open",
30016 : "Bad write to log file",
30017 : "The specified timer name does not exist",
30018 : "Attempt to add a timer that already exists",
30019 : "Attempt to delete a variable that does not exist",
30020 : "Attempt to use SetCommand with a non-empty command window",
30021 : "Bad regular expression syntax",
30022 : "Time given to AddTimer is invalid",
30023 : "Direction given to AddToMapper is invalid",
30024 : "No items in mapper",
30025 : "Option name not found",
30026 : "New value for option is out of range",
30027 : "Trigger sequence value invalid",
30028 : "Where to send trigger text to is invalid",
30029 : "Trigger label not specified/invalid for 'send to variable'",
30030 : "File name specified for plugin not found",
30031 : "There was a parsing or other problem loading the plugin",
30032 : "Plugin is not allowed to set this option",
30033 : "Plugin is not allowed to get this option",
30034 : "Requested plugin is not installed",
30035 : "Only a plugin can do this",
30036 : "Plugin does not support that subroutine (subroutine not in script)",
30037 : "Plugin does not support saving state",
30037 : "Plugin could not save state (eg. no state directory)",
30039 : "Plugin is currently disabled",
30040 : "Could not call plugin routine",
30041 : "Calls to 'Execute' nested too deeply",
30042 : "Unable to create socket for chat connection",
30043 : "Unable to do DNS (domain name) lookup for chat connection",
30044 : "No chat connections open",
30045 : "Requested chat person not connected",
30046 : "General problem with a parameter to a script call",
30047 : "Already listening for incoming chats",
30048 : "Chat session with that ID not found",
30049 : "Already connected to that server/port",
30050 : "Cannot get (text from the) clipboard",
30051 : "Cannot open the specified file",
30052 : "Already transferring a file",
30053 : "Not transferring a file",
30054 : "There is not a command of that name",
30055 : "That array already exists",
30056 : "That name is not permitted for a key",
30056 : "That array does not exist",
30057 : "Values to be imported into array are not in pairs",
30058 : "Import succeeded, however some values were overwritten",
30059 : "Import/export delimiter must be a single character, other than backslash",
30060 : "Array element set, existing value overwritten",
30061 : "Array key does not exist",
30062 : "Cannot import because cannot find unused temporary character", }


which I find more useful.

There are other things, I'll write about them later.
[Go to top] top

Posted by Drakonik   (20 posts)  [Biography] bio
Date Reply #8 on Mon 25 Jun 2012 02:52 AM (UTC)
Message
On trying to import this package, I get the following traceback: https://gist.github.com/2986151
[Go to top] top

Posted by Flauto   (1 post)  [Biography] bio
Date Reply #9 on Tue 16 Oct 2012 12:25 PM (UTC)
Message
What's wrong with it?

Script error
World: mymud
Execution of line 12 column 0
Immediate execution
Traceback (most recent call last):
File "<Script Block >", line 12, in <module>
from coroutine import coroutine
File "C:\Python27\Lib\coroutine.py", line 2, in <module>
_gbl = ax._scriptEngine_.globalNameSpaceModule
NameError: name 'ax' is not defined

Line in error:
from coroutine import coroutine
Error context in script:
8 :
9 : from common import *
10 : from consts import *
11 :
12*: from coroutine import coroutine
13 :
14 : from terminals import McTerminal
15 :
16 : from objects import Trigger
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


30,138 views.

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at HostDash]