- How can I import ICommand for inheritance in the command1.py file?
Your project would have to be inside a proper package. If you are not doing that already, you should.
Once Python understands that "command1" is inside a package, inside it you can do:
from ..ICommand import ICommand
(ICommand must be a .py file defining your ICommand, of course).
- How do I create one instance of every class contained in a .py file
in the commands folder?
For Python, unless you explicitly import a file, a .py file is as good as any data file sitting on the directory. The language allows you to, but does not perform any "auto-discovery" of whatever files you will have under your plug-ins.
You can do that yourself, our you can use a framework that does this kind of thing - zope.configuration
is one, but you have to create xml-like files with the folders it should scan.
Doing it yourself can be easy, it is just a matter of listing the desired folders, and call __import__
for any Python files in there.
TThe object returned by the call to __import__
is the module itself, you can then just check its contents for subclasses (or otherwise implementations of) ICommand
and instantiate then.
module = __import__(...)
plugins = {}
for name, obj in module.__dict__.items():
if isinstance(obj, ICommand):
plugins[name] = obj() # This instatiate the class
I have two answers with explicit examples of how to do that:
Load module to invoke its decorators
Python: import every module from a folder?
- Is there any way to ensure that the plugin file only contains a
definition for a derived ICommand class?
Yes.
But you should not put that restriction there, as you state it.
The snippet above for getting the ICommand subclasses inspect all of a modues top level contents, and you could easily raise an exception on any variable, function or class there that is not an ICommand subclass.
That however is not a rational restriction: it is usual in Python to need small "utility" functions that are not class related, or other variables that will hold constant values - it is not usefull to constrain those to be class members for your plug-in. Likewise, if you are worried about the plugins containing arbitrary code that should not be there: you can't prevent that at all. It is not feasible to securely "sandbox" a Python file in a Python process. Very good people tried for years to have a "Python sandbox", only to be frustrated. (If that is a requirement, use O.S. level process resource restrictions, and run your plug-ins i.e. only import their files, in a process with those restrictions)
Otherwise, you may be meaning that you want "a single subclass of ICommand per file", with no other restrictions: then just insert a check in the above loop to instantiate the plug-in - if it finds a second class in the same file, raise an exception.