I’m creating a small Python script to manage different classes of servers (FTP, HTTP, SSH, etc.)
On each type of server, we can perform different types of actions (deploy, configure, check, etc.)
I have a base Server class, then a separate class for each type of server that inherits from this:
class Server:
...
def check():
...
class HTTPServer(Server):
def check():
super(HTTPServer, self).check()
...
class FTPServer(Server):
def check():
super(FTPServer, self).check()
...
A sample command line might be:
my_program deploy http
From the command-line, the two mandatory arguments I need are:
- Operation to perform
- Type of server to create/manage
Previously, I was using argparse and the store operation, and using a dict to match the command-line option to the actual class and function name. For example:
types_of_servers = {
'http': 'HTTPServer',
'ftp': 'FTPServer',
...
}
valid_operations = {
'check': 'check',
'build': 'build',
'deploy': 'deploy',
'configure': 'configure',
'verify': 'verify',
}
(In my actual code, valid_operations wasn’t quite a naive 1:1 mapping.)
And then using rather horrible code to create the right type of object, and call the right class.
Then I thought I’d use argparse’s subparsers feature to do it instead. So I’ve made each operation (check, build, deploy, etc.) a subparser.
Normally, I could link each sub-command to a particular function, and have it call it. However, I don’t want to just call a generic check() function – I need to create the correct type of object first, and then call the appropriate function within that object.
Is there a good, or pythonic way to do this? Preferably one that doesn’t involve a lot of hardcoding, or badly designed if/else loops?
If you are set on using a subparser for each command I would do something like this. Use argparse’s type support to call a function that lookups the class you want to instantiate and returns it.
Then call the method on that instance dynamically with getattr()
Output looks something like this: