the top-level functions in this module (`define`, `parse_command_line`, etc)
simply call methods on it. You may create additional `OptionParser`
instances to define isolated sets of options, such as for subcommands.
+
+.. note::
+
+ By default, several options are defined that will configure the
+ standard `logging` module when `parse_command_line` or `parse_config_file`
+ are called. If you want Tornado to leave the logging configuration
+ alone so you can manage it yourself, either pass ``--logging=none``
+ on the command line or do the following to disable it in code::
+
+ from tornado.options import options, parse_command_line
+ options.logging = None
+ parse_command_line()
"""
from __future__ import absolute_import, division, print_function, with_statement
class _Option(object):
+ UNSET = object()
+
def __init__(self, name, default=None, type=basestring_type, help=None,
metavar=None, multiple=False, file_name=None, group_name=None,
callback=None):
self.group_name = group_name
self.callback = callback
self.default = default
- self._value = None
+ self._value = _Option.UNSET
def value(self):
- return self.default if self._value is None else self._value
+ return self.default if self._value is _Option.UNSET else self._value
def parse(self, value):
_parse = {
import logging
import os
import re
+import subprocess
+import sys
import tempfile
import warnings
for filename in glob.glob(tmpdir + '/test_log*'):
os.unlink(filename)
os.rmdir(tmpdir)
+
+
+class LoggingOptionTest(unittest.TestCase):
+ """Test the ability to enable and disable Tornado's logging hooks."""
+ def logs_present(self, statement, args=None):
+ # Each test may manipulate and/or parse the options and then logs
+ # a line at the 'info' level. This level is ignored in the
+ # logging module by default, but Tornado turns it on by default
+ # so it is the easiest way to tell whether tornado's logging hooks
+ # ran.
+ IMPORT = 'from tornado.options import options, parse_command_line'
+ LOG_INFO = 'import logging; logging.info("hello")'
+ program = ';'.join([IMPORT, statement, LOG_INFO])
+ proc = subprocess.Popen(
+ [sys.executable, '-c', program] + (args or []),
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ stdout, stderr = proc.communicate()
+ self.assertEqual(proc.returncode, 0, 'process failed: %r' % stdout)
+ return b'hello' in stdout
+
+ def test_default(self):
+ self.assertFalse(self.logs_present('pass'))
+
+ def test_tornado_default(self):
+ self.assertTrue(self.logs_present('parse_command_line()'))
+
+ def test_disable_command_line(self):
+ self.assertFalse(self.logs_present('parse_command_line()',
+ ['--logging=none']))
+
+ def test_disable_command_line_case_insensitive(self):
+ self.assertFalse(self.logs_present('parse_command_line()',
+ ['--logging=None']))
+
+ def test_disable_code_string(self):
+ self.assertFalse(self.logs_present(
+ 'options.logging = "none"; parse_command_line()'))
+
+ def test_disable_code_none(self):
+ self.assertFalse(self.logs_present(
+ 'options.logging = None; parse_command_line()'))
+
+ def test_disable_override(self):
+ # command line trumps code defaults
+ self.assertTrue(self.logs_present(
+ 'options.logging = None; parse_command_line()',
+ ['--logging=info']))