How can I split my python file into multiple plugins?

So, the first thing I want to say: I studied modules and the like, I just donโ€™t know how I would rewrite this to fit this.

Project: I have a Skype Bot using the Skype4Py module. I have about 11 commands, I noticed that one script is getting a little big.

I'm trying to think about how to link a single main.py file with a plugin folder that contains each bot function in its own respectable Python file. Everything just sounds, except when it comes to a function.

Here is just a basic look at my Skype bot, skipping some of the larger features.

import Skype4Py, random class SkypeBot(): def __init__(self): self.skype = Skype4Py.Skype() if self.skype.Client.IsRunning == False: self.skype.Client.Start() self.skype.Attach() self.results = ['Yes', 'No', 'Maybe', 'Never'] def main(self): print ' Skype Bot currently running on user: %s' % self.skype.CurrentUserHandle print "\n\nCommands Called:\n" while True: self.skype.OnMessageStatus = self.RunFunction def RunFunction(self, Message, Status): if Status == 'SENT' or Status == 'RECEIVED': cmd = Message.Body.split(' ')[0] if cmd in self.functions.keys(): self.context = Message self.caller = self.context.FromHandle self.functions[cmd](self) def ping(self): print " %s : Ping" % self.caller self.context.Chat.SendMessage('Pong') def say(self): try: response = self.context.Body.split(' ', 1) if response[1] == "-info": print " %s : say -info" % self.caller self.context.Chat.SendMessage("Resends the message entered. \n" "Usage: !say Hello. \n" "Example: Bot: Hello.") else: say = response[1] print " %s : Say [%s]" % (self.caller, say) self.context.Chat.SendMessage(say) except: self.context.Chat.SendMessage("Please use -info to properly use the !say command") def eightball(self): try: question = self.context.Body.split(' ', 1) if question[1] == "-info": print " %s : 8Ball -info" % self.caller self.context.Chat.SendMessage("Responds with an answer.\n" "Usage: !8ball 'Do I have swag?'\n" "Example: !8Ball Response: 'Yes'") else: random.shuffle(self.results) answer = self.results[3] print " %s : 8Ball [%s]" % (self.caller, question[1]) self.context.Chat.SendMessage("!8Ball Response: %s" % answer) except: self.context.Chat.SendMessage("Please use -info to properly use the !8ball command") #FUNCTIONS LIST #******************** functions = { "!ping": ping, "!say": say, "!8ball": eightball, } if __name__ == "__main__": snayer = SkypeBot() snayer.main() 

So basically, what interests me is how I can change

 self.skype.OnMessageStatus = self.RunFunction 

so that it runs functions from another file?

+2
function python module class skype4py
Oct 28 '14 at 2:07
source share
1 answer

For a program of this size, you really don't need to put your command functions in separate files, but I think this is a good organization. And good practice when you write a program with thousands of lines of code. :)

One way to do this is to create a SkypeBot base class without any command methods, and then import the command methods from your plugins directory and add them to the class. It is easy to add new attributes to an existing class, and it does not matter if the new attributes are properties or methods, the syntax for adding them is identical. (With a bit of work, you can even add new attributes to an instance, so you can have several instances, each of which has its own set of commands. But I think that is not necessary here, since a program using the SkypeBot class will usually only create one instance).

So, we can break your question into two parts:

  • How to add methods to an existing class.
  • How to import these methods from other source files.

As I said, 1) easy. 2) also quite simple, but I have never done this before, so I had to do a little research and testing, and I canโ€™t promise that what I did is the best practice, but it works. :)

I don't know much about Skype, and I donโ€™t have this Skype4Py module, and, as you said, the code above is not a complete program, so I wrote a fairly simple code to illustrate the process of adding plug-in methods from separate files to an existing class.

The name of the main program is "plugin_demo.py". To keep something neat, he lives in his own "plugintest /" directory, which you must create somewhere in your Python path (for example, where you usually keep your Python programs). This path must be specified in the PYTHONPATH environment variable.

"plugintest /" has the following structure:

 plugintest/ __init__.py plugin_demo.py plugins/ __init__.py add.py multiply.py 

The __init__.py files are used by the Python import machine to report that the directory contains a Python package, see 6.4. Packages in Python docs for more details.

Here are the contents of these files. First, the files that go into "plugintest /":

__ __ INIT. RU

 __all__ = ['plugin_demo', 'plugins'] from plugintest import * 

plugin_demo.py

 #! /usr/bin/env python #A simple class that will get methods added later from plugins directory class Test(object): def __init__(self, data): self.data = data def add_plugins(cls): import plugins print "Adding plugin methods to %s class" % cls.__name__ for name in plugins.__all__: print name plug = getattr(plugins, name) print plug method = getattr(plug, name) print method setattr(cls, name, method) print print "Done\n" add_plugins(Test) def main(): #Now test it! t = Test([1, 2, 3]); print t.data t.multiply(10); print t.data t.add(5); print t.data if __name__ == '__main__': main() 

And now the contents of the "plugintest / plugins /" directory:

__ __ INIT. RU

 __all__ = ['add', 'multiply'] from plugintest.plugins import * 

add.py

 #A method for the Test class of plugin_demo.py def add(self, m): self.data = [m + i for i in self.data] 

multiply.py

 #A method for the Test class of plugin_demo.py def multiply(self, m): self.data = [m * i for i in self.data] 

If you cd to a directory containing the "plugintest /" folder, you can start it using

python plugintest/plugin_demo.py

and if you cd on "plugintest /"

python plugin_demo.py

Also, in the interpreter (or other Python program) you should be able to do

import plugintest

and then run main() function "plugin_demo.py" with

plugintest.plugin_demo.main()

Other common options are from ... import ... etc. should also work as expected.

The function in plugin_demo.py that does the magic of adding imported methods to the Test class is add_plugins() . When it starts, it prints the name of the method, its module and its function. This may be useful during development, but you are likely to comment on some of these print statements after the program runs correctly.

I hope this helps, and if you have any questions, please feel free to ask.

+2
Oct 29 '14 at 5:46
source share



All Articles