Exemplo n.º 1
0
 def test_plain_text_output_format(self):
     """Inspect the plain text output of coloredlogs."""
     logger = VerboseLogger(random_string(25))
     stream = StringIO()
     install(level=logging.NOTSET, logger=logger, stream=stream)
     # Test that filtering on severity works.
     logger.setLevel(logging.INFO)
     logger.debug("No one should see this message.")
     assert len(stream.getvalue().strip()) == 0
     # Test that the default output format looks okay in plain text.
     logger.setLevel(logging.NOTSET)
     for method, severity in ((logger.debug, 'DEBUG'),
                              (logger.info, 'INFO'),
                              (logger.verbose, 'VERBOSE'),
                              (logger.warning, 'WARNING'),
                              (logger.error, 'ERROR'),
                              (logger.critical, 'CRITICAL')):
         # Prepare the text.
         text = "This is a message with severity %r." % severity.lower()
         # Log the message with the given severity.
         method(text)
         # Get the line of output generated by the handler.
         output = stream.getvalue()
         lines = output.splitlines()
         last_line = lines[-1]
         assert text in last_line
         assert severity in last_line
         assert PLAIN_TEXT_PATTERN.match(last_line)
Exemplo n.º 2
0
 def test_plain_text_output_format(self):
     """Inspect the plain text output of coloredlogs."""
     logger = VerboseLogger(random_string(25))
     stream = StringIO()
     install(level=logging.NOTSET, logger=logger, stream=stream)
     # Test that filtering on severity works.
     logger.setLevel(logging.INFO)
     logger.debug("No one should see this message.")
     assert len(stream.getvalue().strip()) == 0
     # Test that the default output format looks okay in plain text.
     logger.setLevel(logging.NOTSET)
     for method, severity in ((logger.debug, 'DEBUG'), (logger.info,
                                                        'INFO'),
                              (logger.verbose, 'VERBOSE'), (logger.warning,
                                                            'WARN'),
                              (logger.error, 'ERROR'), (logger.critical,
                                                        'CRITICAL')):
         # Prepare the text.
         text = "This is a message with severity %r." % severity.lower()
         # Log the message with the given severity.
         method(text)
         # Get the line of output generated by the handler.
         output = stream.getvalue()
         lines = output.splitlines()
         last_line = lines[-1]
         assert text in last_line
         assert severity in last_line
         assert PLAIN_TEXT_PATTERN.match(last_line)
Exemplo n.º 3
0
 def test_support_for_milliseconds(self):
     """Make sure milliseconds are hidden by default but can be easily enabled."""
     # Check that the default log format doesn't include milliseconds.
     stream = StringIO()
     install(reconfigure=True, stream=stream)
     logging.info("This should not include milliseconds.")
     assert all(map(PLAIN_TEXT_PATTERN.match, stream.getvalue().splitlines()))
     # Check that milliseconds can be enabled via a shortcut.
     stream = StringIO()
     install(milliseconds=True, reconfigure=True, stream=stream)
     logging.info("This should include milliseconds.")
     assert all(map(PATTERN_INCLUDING_MILLISECONDS.match, stream.getvalue().splitlines()))
Exemplo n.º 4
0
 def test_support_for_milliseconds(self):
     """Make sure milliseconds are hidden by default but can be easily enabled."""
     # Check that the default log format doesn't include milliseconds.
     stream = StringIO()
     install(reconfigure=True, stream=stream)
     logging.info("This should not include milliseconds.")
     assert all(map(PLAIN_TEXT_PATTERN.match, stream.getvalue().splitlines()))
     # Check that milliseconds can be enabled via a shortcut.
     stream = StringIO()
     install(milliseconds=True, reconfigure=True, stream=stream)
     logging.info("This should include milliseconds.")
     assert all(map(PATTERN_INCLUDING_MILLISECONDS.match, stream.getvalue().splitlines()))
Exemplo n.º 5
0
 def test_dynamic_stderr_lookup(self):
     """Make sure coloredlogs.install() uses StandardErrorHandler when possible."""
     coloredlogs.install()
     # Redirect sys.stderr to a temporary buffer.
     initial_stream = StringIO()
     initial_text = "Which stream will receive this text?"
     with PatchedAttribute(sys, 'stderr', initial_stream):
         logging.info(initial_text)
     assert initial_text in initial_stream.getvalue()
     # Redirect sys.stderr again, to a different destination.
     subsequent_stream = StringIO()
     subsequent_text = "And which stream will receive this other text?"
     with PatchedAttribute(sys, 'stderr', subsequent_stream):
         logging.info(subsequent_text)
     assert subsequent_text in subsequent_stream.getvalue()
Exemplo n.º 6
0
def render_usage(text):
    """
    Reformat a command line program's usage message to reStructuredText_.

    :param text: The plain text usage message (a string).
    :returns: The usage message rendered to reStructuredText_ (a string).
    """
    meta_variables = find_meta_variables(text)
    introduction, options = parse_usage(text)
    output = [render_paragraph(p, meta_variables) for p in introduction]
    if options:
        output.append('\n'.join([
            '.. csv-table::',
            '   :header: Option, Description',
            '   :widths: 30, 70',
            '',
        ]))
        csv_buffer = StringIO()
        csv_writer = csv.writer(csv_buffer)
        while options:
            variants = options.pop(0)
            description = options.pop(0)
            csv_writer.writerow([
                render_paragraph(variants, meta_variables),
                ('\n\n'.join(
                    render_paragraph(p, meta_variables)
                    for p in split_paragraphs(description))).rstrip(),
            ])
        csv_lines = csv_buffer.getvalue().splitlines()
        output.append('\n'.join('   %s' % l for l in csv_lines))
    logger.debug("Rendered output: %s", output)
    return '\n\n'.join(trim_empty_lines(o) for o in output)
Exemplo n.º 7
0
def render_usage(text):
    """
    Reformat a command line program's usage message to reStructuredText_.

    :param text: The plain text usage message (a string).
    :returns: The usage message rendered to reStructuredText_ (a string).
    """
    meta_variables = find_meta_variables(text)
    introduction, options = parse_usage(text)
    output = [render_paragraph(p, meta_variables) for p in introduction]
    if options:
        output.append('\n'.join([
            '.. csv-table::',
            '   :header: Option, Description',
            '   :widths: 30, 70',
            '',
        ]))
        csv_buffer = StringIO()
        csv_writer = csv.writer(csv_buffer)
        while options:
            variants = options.pop(0)
            description = options.pop(0)
            csv_writer.writerow([
                render_paragraph(variants, meta_variables),
                '\n\n'.join(render_paragraph(p, meta_variables) for p in split_paragraphs(description)),
            ])
        csv_lines = csv_buffer.getvalue().splitlines()
        output.append('\n'.join('   %s' % l for l in csv_lines))
    logger.debug("Rendered output: %s", output)
    return '\n\n'.join(trim_empty_lines(o) for o in output)
Exemplo n.º 8
0
 def test_support_for_milliseconds_directive(self):
     """Make sure milliseconds using the ``%f`` directive are supported."""
     stream = StringIO()
     install(reconfigure=True,
             stream=stream,
             datefmt='%Y-%m-%dT%H:%M:%S.%f%z')
     logging.info("This should be timestamped according to #45.")
     assert re.match(
         r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[+-]\d{4}\s',
         stream.getvalue())
Exemplo n.º 9
0
 def test_plain_text_output_format(self):
     """Inspect the plain text output of coloredlogs."""
     logger = VerboseLogger(random_string(25))
     stream = StringIO()
     install(level=logging.NOTSET, logger=logger, stream=stream)
     # Test that filtering on severity works.
     logger.setLevel(logging.INFO)
     logger.debug("No one should see this message.")
     assert len(stream.getvalue().strip()) == 0
     # Test that the default output format looks okay in plain text.
     logger.setLevel(logging.NOTSET)
     for method, severity in ((logger.debug, 'DEBUG'),
                              (logger.info, 'INFO'),
                              (logger.verbose, 'VERBOSE'),
                              (logger.warning, 'WARNING'),
                              (logger.error, 'ERROR'),
                              (logger.critical, 'CRITICAL')):
         # XXX Workaround for a regression in Python 3.7 caused by the
         # Logger.isEnabledFor() method using stale cache entries. If we
         # don't clear the cache then logger.isEnabledFor(logging.DEBUG)
         # returns False and no DEBUG message is emitted.
         try:
             logger._cache.clear()
         except AttributeError:
             pass
         # Prepare the text.
         text = "This is a message with severity %r." % severity.lower()
         # Log the message with the given severity.
         method(text)
         # Get the line of output generated by the handler.
         output = stream.getvalue()
         lines = output.splitlines()
         last_line = lines[-1]
         assert text in last_line
         assert severity in last_line
         assert PLAIN_TEXT_PATTERN.match(last_line)
Exemplo n.º 10
0
 def test_spinner(self):
     """Test :func:`humanfriendly.Spinner`."""
     stream = StringIO()
     spinner = humanfriendly.Spinner('test spinner', total=4, stream=stream, interactive=True)
     for progress in [1, 2, 3, 4]:
         spinner.step(progress=progress)
         time.sleep(0.2)
     spinner.clear()
     output = stream.getvalue()
     output = (output.replace(humanfriendly.show_cursor_code, '')
                     .replace(humanfriendly.hide_cursor_code, ''))
     lines = [line for line in output.split(humanfriendly.erase_line_code) if line]
     self.assertTrue(len(lines) > 0)
     self.assertTrue(all('test spinner' in l for l in lines))
     self.assertTrue(all('%' in l for l in lines))
     self.assertEqual(sorted(set(lines)), sorted(lines))
Exemplo n.º 11
0
 def test_spinner(self):
     """Test :func:`humanfriendly.Spinner`."""
     stream = StringIO()
     spinner = humanfriendly.Spinner('test spinner', total=4, stream=stream, interactive=True)
     for progress in [1, 2, 3, 4]:
         spinner.step(progress=progress)
         time.sleep(0.2)
     spinner.clear()
     output = stream.getvalue()
     output = (output.replace(humanfriendly.show_cursor_code, '')
                     .replace(humanfriendly.hide_cursor_code, ''))
     lines = [line for line in output.split(humanfriendly.erase_line_code) if line]
     self.assertTrue(len(lines) > 0)
     self.assertTrue(all('test spinner' in l for l in lines))
     self.assertTrue(all('%' in l for l in lines))
     self.assertEqual(sorted(set(lines)), sorted(lines))
Exemplo n.º 12
0
class CaptureOutput(ContextManager):

    """Context manager that captures what's written to :data:`sys.stdout` and :data:`sys.stderr`."""

    def __init__(self, merged=False, input=''):
        """
        Initialize a :class:`CaptureOutput` object.

        :param merged: :data:`True` to merge the streams,
                       :data:`False` to capture them separately.
        :param input: The data that reads from :data:`sys.stdin`
                      should return (a string).
        """
        self.stdin = StringIO(input)
        self.stdout = StringIO()
        self.stderr = self.stdout if merged else StringIO()
        self.patched_attributes = [
            PatchedAttribute(sys, name, getattr(self, name))
            for name in ('stdin', 'stdout', 'stderr')
        ]

    stdin = None
    """The :class:`~humanfriendly.compat.StringIO` object used to feed the standard input stream."""

    stdout = None
    """The :class:`~humanfriendly.compat.StringIO` object used to capture the standard output stream."""

    stderr = None
    """The :class:`~humanfriendly.compat.StringIO` object used to capture the standard error stream."""

    def __enter__(self):
        """Start capturing what's written to :data:`sys.stdout` and :data:`sys.stderr`."""
        super(CaptureOutput, self).__enter__()
        for context in self.patched_attributes:
            context.__enter__()
        return self

    def __exit__(self, exc_type=None, exc_value=None, traceback=None):
        """Stop capturing what's written to :data:`sys.stdout` and :data:`sys.stderr`."""
        super(CaptureOutput, self).__exit__(exc_type, exc_value, traceback)
        for context in self.patched_attributes:
            context.__exit__(exc_type, exc_value, traceback)

    def getvalue(self):
        """Get the text written to :data:`sys.stdout`."""
        return self.stdout.getvalue()
Exemplo n.º 13
0
def main(*args, **kw):
    """Utility function to test the command line interface without invoking a subprocess."""
    returncode = 0
    input_buffer = StringIO(kw.get('input', ''))
    output_buffer = StringIO()
    saved_argv = sys.argv
    saved_stdin = sys.stdin
    saved_stdout = sys.stdout
    try:
        sys.argv = [sys.argv[0]] + list(args)
        sys.stdin = input_buffer
        sys.stdout = output_buffer
        cli.main()
    except SystemExit as e:
        returncode = e.code or 1
    finally:
        sys.argv = saved_argv
        sys.stdin = saved_stdin
        sys.stdout = saved_stdout
    return returncode, output_buffer.getvalue()
Exemplo n.º 14
0
def main(*args, **kw):
    """Utility function to test the command line interface without invoking a subprocess."""
    returncode = 0
    input_buffer = StringIO(kw.get('input', ''))
    output_buffer = StringIO()
    saved_argv = sys.argv
    saved_stdin = sys.stdin
    saved_stdout = sys.stdout
    try:
        sys.argv = [sys.argv[0]] + list(args)
        sys.stdin = input_buffer
        sys.stdout = output_buffer
        cli.main()
    except SystemExit as e:
        returncode = e.code or 1
    finally:
        sys.argv = saved_argv
        sys.stdin = saved_stdin
        sys.stdout = saved_stdout
    return returncode, output_buffer.getvalue()
Exemplo n.º 15
0
 def test_support_for_milliseconds_directive(self):
     """Make sure milliseconds using the ``%f`` directive are supported."""
     stream = StringIO()
     install(reconfigure=True, stream=stream, datefmt='%Y-%m-%dT%H:%M:%S.%f%z')
     logging.info("This should be timestamped according to #45.")
     assert re.match(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{4}\s', stream.getvalue())