I'm using Tornado options
to define command-line arguments. However, I would like to be able to throw arbitrary configuration options, not defined in code, to my program. These will differ, depending on what the program is supposed to do. For instance, connect to a bluetooth device using a MAC address or connect to a serial device using a TTY.
If I define a set of "mandatory" options in code and then add an additional when calling the program, I get an exception thrown by parse_command_line()
.
It would be very handy to get e.g. a dictionary with the remaining (undefined) options. That is, much in the same way as **kwargs
works in functions.
Can this be done?
(A work-around is to define a string option named e.g. configuration and throw everything in there, possibly encoded in some clever way. As the program is being called by another program I can e.g. base64-encode a serialized dict.)
Update: I've noticed that if you add command-line args without leading dashes, Tornado will ignore them and return a list with remaining (undefined) options.
You can create subclass of OptionParser
singleton and modify parsing method. Example:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import OptionParser
import sys
class MyOptionParser(OptionParser):
def parse_command_line(self, args=None, final=True):
if args is None:
args = sys.argv
remaining = []
for i in range(1, len(args)):
# All things after the last option are command line arguments
if not args[i].startswith("-"):
remaining = args[i:]
break
if args[i] == "--":
remaining = args[i + 1:]
break
arg = args[i].lstrip("-")
name, equals, value = arg.partition("=")
name = name.replace('-', '_')
if not name in self._options:
# modified line self.print_help()
# modified line raise Error('Unrecognized command line option: %r' % name)
self.define(name, help="Arbitrary option") # new line
option = self._options[name]
if not equals:
if option.type == bool:
value = "true"
else:
raise Error('Option %r requires a value' % name)
option.parse(value)
if final:
self.run_parse_callbacks()
return remaining
options = MyOptionParser()
options.define("port", default=8000, help="run on the given port", type=int)
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.write(options.myoption)
if __name__ == "__main__":
options.parse_command_line()
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
The only difference from source is I'm defining passed option instead of throwing an Exception. Running:
python test.py --myoption="test"