Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ANSI rendering of rst markup. #24

Merged
merged 1 commit into from
Mar 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions defopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from __future__ import (
absolute_import, division, unicode_literals, print_function)

import contextlib
import inspect
import logging
import re
Expand All @@ -25,9 +26,19 @@
except ImportError: # pragma: no cover
from funcsigs import signature as _inspect_signature

try:
from colorama import colorama_text as _colorama_text
except ImportError:
@contextlib.contextmanager
def _colorama_text(*args):
yield

if sys.version_info.major == 2: # pragma: no cover
def _get_type_hints(*args, **kwargs):
return {}
_basestring = basestring
else:
_basestring = str

__version__ = '3.0.0'

Expand Down Expand Up @@ -85,7 +96,8 @@ def run(*funcs, **kwargs):
func.__name__, formatter_class=_Formatter)
_populate_parser(func, subparser, parsers, short)
subparser.set_defaults(_func=func)
args = parser.parse_args(argv)
with _colorama_text():
args = parser.parse_args(argv)
# Workaround for http://bugs.python.org/issue9253#msg186387
if not main and not hasattr(args, '_func'):
parser.error('too few arguments')
Expand Down Expand Up @@ -312,8 +324,28 @@ def _parse_doc(func):
return _Doc(doctext, tuples)


def _itertext_ansi(node):
# Implementation modified from `ElementTree.Element.itertext`.
tag = node.tag
if not isinstance(tag, _basestring) and tag is not None:
return
ansi_code = {"strong": "\033[1m", "emphasis": "\033[3m"}.get(tag, "")
t = node.text
if t:
yield ansi_code
yield t
if ansi_code:
yield "\033[0m" # Reset.
for e in node:
for t in _itertext_ansi(e):
yield t
t = e.tail
if t:
yield t


def _get_text(node):
return ''.join(node.itertext())
return ''.join(_itertext_ansi(node))


def _indent(text):
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ universal=1
source=defopt

[coverage:report]
fail_under=98
fail_under=97
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you need to change this? I don't think your changes reduced coverage.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return in

    if not isinstance(tag, str) and tag is not None:
        return

doesn't get exercised (and I don't think it's worth writing a test to specifically test it -- it comes straight from the upstream implementation). That's enough for dropping the coverage.

5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
install_requires=[
'docutils',
'sphinxcontrib-napoleon>=0.5.1',
'funcsigs;python_version<"3"',
'funcsigs;python_version<"3.3"',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, I don't intend to support 3.0-3.2, but I don't have a problem with changing this.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't plan to use them either, but that's just a more convenient way to say "function signatures were introduced in 3.3"

'enum34;python_version<"3.4"',
'typing;python_version<"3.5"',
'colorama>=0.3.4;sys.platform=="win32"',
],
tests_require=[
'mock;python_version<"3"',
'mock;python_version<"3.3"',
],
classifiers=[
'Programming Language :: Python',
Expand Down
7 changes: 7 additions & 0 deletions test_defopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,13 @@ def foo(bar):
self.assertIn('%(prog)s', self._get_help(foo))
self.assertNotIn('%%', self._get_help(foo))

def test_rst_ansi(self):
def foo():
"""*italic* **bold**"""
return bar
self.assertIn('\033[3mitalic\033[0m \033[1mbold\033[0m',
self._get_help(foo))

def _get_help(self, func):
parser = ArgumentParser(formatter_class=defopt._Formatter)
defopt._populate_parser(func, parser, {}, {})
Expand Down