def __call__(self, *args):
try:
# Re-encode the cap, because tparm() takes a bytestring in Python
# 3. However, appear to be a plain Unicode string otherwise so
# concats work.
#
# We use *latin1* encoding so that bytes emitted by tparm are
# encoded to their native value: some terminal kinds, such as
# 'avatar' or 'kermit', emit 8-bit bytes in range 0x7f to 0xff.
# latin1 leaves these values unmodified in their conversion to
# unicode byte values. The terminal emulator will "catch" and
# handle these values, even if emitting utf8-encoded text, where
# these bytes would otherwise be illegal utf8 start bytes.
parametrized = tparm(self.encode('latin1'), *args).decode('latin1')
return (parametrized if self._normal is None else
FormattingString(parametrized, self._normal))
except curses.error:
# Catch "must call (at least) setupterm() first" errors, as when
# running simply `nosetests` (without progressive) on nose-
# progressive. Perhaps the terminal has gone away between calling
# tigetstr and calling tparm.
return u''
except TypeError:
# If the first non-int (i.e. incorrect) arg was a string, suggest
# something intelligent:
if len(args) == 1 and isinstance(args[0], basestring):
raise TypeError(
'A native or nonexistent capability template received '
'%r when it was expecting ints. You probably misspelled a '
'formatting call like bright_red_on_white(...).' % args)
else:
# Somebody passed a non-string; I don't feel confident
# guessing what they were trying to do.
raise
python类tparm()的实例源码
def __call__(self, *args):
"""Return a Unicode or whatever you passed in as the first arg
(hopefully a string of some kind).
When called with an int as the first arg, return an empty Unicode. An
int is a good hint that I am a ``ParametrizingString``, as there are
only about half a dozen string-returning capabilities on OS X's
terminfo man page which take any param that's not an int, and those are
seldom if ever used on modern terminal emulators. (Most have to do with
programming function keys. Blessings' story for supporting
non-string-returning caps is undeveloped.) And any parametrized
capability in a situation where all capabilities themselves are taken
to be blank are, of course, themselves blank.
When called with a non-int as the first arg (no no args at all), return
the first arg. I am acting as a ``FormattingString``.
"""
if len(args) != 1 or isinstance(args[0], int):
# I am acting as a ParametrizingString.
# tparm can take not only ints but also (at least) strings as its
# second...nth args. But we don't support callably parametrizing
# caps that take non-ints yet, so we can cheap out here. TODO: Go
# through enough of the motions in the capability resolvers to
# determine which of 2 special-purpose classes,
# NullParametrizableString or NullFormattingString, to return, and
# retire this one.
return u''
return args[0] # Should we force even strs in Python 2.x to be
# unicodes? No. How would I know what encoding to use
# to convert it?
def __init__(self, color=True, fmt=DEFAULT_FORMAT,
datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS):
r"""
:arg bool color: Enables color support.
:arg string fmt: Log message format.
It will be applied to the attributes dict of log records. The
text between ``%(color)s`` and ``%(end_color)s`` will be colored
depending on the level if color support is on.
:arg dict colors: color mappings from logging level to terminal color
code
:arg string datefmt: Datetime format.
Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.
.. versionchanged:: 3.2
Added ``fmt`` and ``datefmt`` arguments.
"""
logging.Formatter.__init__(self, datefmt=datefmt)
self._fmt = fmt
self._colors = {}
if color and _stderr_supports_color():
# The curses module has some str/bytes confusion in
# python3. Until version 3.2.3, most methods return
# bytes, but only accept strings. In addition, we want to
# output these strings with the logging module, which
# works with unicode strings. The explicit calls to
# unicode() below are harmless in python2 but will do the
# right conversion in python 3.
fg_color = (curses.tigetstr("setaf") or
curses.tigetstr("setf") or "")
if (3, 0) < sys.version_info < (3, 2, 3):
fg_color = unicode_type(fg_color, "ascii")
for levelno, code in colors.items():
self._colors[levelno] = unicode_type(curses.tparm(fg_color, code), "ascii")
self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii")
else:
self._normal = ''
def __new__(cls, *args):
"""
Class constructor accepting 3 positional arguments.
:arg cap: parameterized string suitable for curses.tparm()
:arg normal: terminating sequence for this capability (optional).
:arg name: name of this terminal capability (optional).
"""
assert len(args) and len(args) < 4, args
new = six.text_type.__new__(cls, args[0])
new._normal = len(args) > 1 and args[1] or u''
new._name = len(args) > 2 and args[2] or u'<not specified>'
return new
def __call__(self, *args):
"""
Returning :class:`FormattingString` instance for given parameters.
Return evaluated terminal capability (self), receiving arguments
``*args``, followed by the terminating sequence (self.normal) into
a :class:`FormattingString` capable of being called.
:rtype: :class:`FormattingString` or :class:`NullCallableString`
"""
try:
# Re-encode the cap, because tparm() takes a bytestring in Python
# 3. However, appear to be a plain Unicode string otherwise so
# concats work.
attr = curses.tparm(self.encode('latin1'), *args).decode('latin1')
return FormattingString(attr, self._normal)
except TypeError as err:
# If the first non-int (i.e. incorrect) arg was a string, suggest
# something intelligent:
if len(args) and isinstance(args[0], six.string_types):
raise TypeError(
"A native or nonexistent capability template, %r received"
" invalid argument %r: %s. You probably misspelled a"
" formatting call like `bright_red'" % (
self._name, args, err))
# Somebody passed a non-string; I don't feel confident
# guessing what they were trying to do.
raise
except curses.error as err:
# ignore 'tparm() returned NULL', you won't get any styling,
# even if does_styling is True. This happens on win32 platforms
# with http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses installed
if "tparm() returned NULL" not in six.text_type(err):
raise
return NullCallableString()
def tparm(self, capabilities, *args):
"""A simplified version of tigetstr without terminal delays."""
for capability in capabilities:
term_string = curses.tigetstr(capability)
if term_string is not None:
term_string = re.sub(r"\$\<[^>]+>", "", term_string)
break
try:
return curses.tparm(term_string, *args)
except Exception as e:
self.logging.debug("Unable to set tparm: %s" % e)
return ""
def __init__(self, color=True, fmt=DEFAULT_FORMAT,
datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS):
r"""
:arg bool color: Enables color support.
:arg string fmt: Log message format.
It will be applied to the attributes dict of log records. The
text between ``%(color)s`` and ``%(end_color)s`` will be colored
depending on the level if color support is on.
:arg dict colors: color mappings from logging level to terminal color
code
:arg string datefmt: Datetime format.
Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.
.. versionchanged:: 3.2
Added ``fmt`` and ``datefmt`` arguments.
"""
logging.Formatter.__init__(self, datefmt=datefmt)
self._fmt = fmt
self._colors = {}
if color and _stderr_supports_color():
# The curses module has some str/bytes confusion in
# python3. Until version 3.2.3, most methods return
# bytes, but only accept strings. In addition, we want to
# output these strings with the logging module, which
# works with unicode strings. The explicit calls to
# unicode() below are harmless in python2 but will do the
# right conversion in python 3.
fg_color = (curses.tigetstr("setaf") or
curses.tigetstr("setf") or "")
if (3, 0) < sys.version_info < (3, 2, 3):
fg_color = unicode_type(fg_color, "ascii")
for levelno, code in colors.items():
self._colors[levelno] = unicode_type(curses.tparm(fg_color, code), "ascii")
self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii")
else:
self._normal = ''
def _bleed_row(line, row, col_start):
counter = col_start
for fragment in re.split('( +)', line):
if not fragment:
continue
if fragment[0] != ' ':
start = tparm(tigetstr("cup"), row, counter).decode('ascii')
# print up to the maximum amount of cols.
chars = max(0, get_width() - counter)
sys.stdout.write(start + fragment[:chars])
counter += len(fragment)
def get(cap, *args, **kwargs):
default = kwargs.pop('default', '')
if 'PWNLIB_NOTERM' in os.environ:
return ''
if kwargs != {}:
raise TypeError("get(): No such argument %r" % kwargs.popitem()[0])
if cache == None:
init()
s = cache.get(cap)
if not s:
s = curses.tigetstr(cap)
if s == None:
s = curses.tigetnum(cap)
if s == -2:
s = curses.tigetflag(cap)
if s == -1:
# default to empty string so tparm doesn't fail
s = ''
else:
s = bool(s)
cache[cap] = s
# if `s' is not set `curses.tparm' will throw an error if given arguments
if args and s:
return curses.tparm(s, *args)
else:
return s
def _tparm(self, arg, index):
import curses
return curses.tparm(to_bytes(arg), index).decode('ascii') or ''
def __call__(self, *args):
try:
# Re-encode the cap, because tparm() takes a bytestring in Python
# 3. However, appear to be a plain Unicode string otherwise so
# concats work.
#
# We use *latin1* encoding so that bytes emitted by tparm are
# encoded to their native value: some terminal kinds, such as
# 'avatar' or 'kermit', emit 8-bit bytes in range 0x7f to 0xff.
# latin1 leaves these values unmodified in their conversion to
# unicode byte values. The terminal emulator will "catch" and
# handle these values, even if emitting utf8-encoded text, where
# these bytes would otherwise be illegal utf8 start bytes.
parametrized = tparm(self.encode('latin1'), *args).decode('latin1')
return (parametrized if self._normal is None else
FormattingString(parametrized, self._normal))
except curses.error:
# Catch "must call (at least) setupterm() first" errors, as when
# running simply `nosetests` (without progressive) on nose-
# progressive. Perhaps the terminal has gone away between calling
# tigetstr and calling tparm.
return u''
except TypeError:
# If the first non-int (i.e. incorrect) arg was a string, suggest
# something intelligent:
if len(args) == 1 and isinstance(args[0], basestring):
raise TypeError(
'A native or nonexistent capability template received '
'%r when it was expecting ints. You probably misspelled a '
'formatting call like bright_red_on_white(...).' % args)
else:
# Somebody passed a non-string; I don't feel confident
# guessing what they were trying to do.
raise
def __call__(self, *args):
"""Return a Unicode or whatever you passed in as the first arg
(hopefully a string of some kind).
When called with an int as the first arg, return an empty Unicode. An
int is a good hint that I am a ``ParametrizingString``, as there are
only about half a dozen string-returning capabilities on OS X's
terminfo man page which take any param that's not an int, and those are
seldom if ever used on modern terminal emulators. (Most have to do with
programming function keys. Blessings' story for supporting
non-string-returning caps is undeveloped.) And any parametrized
capability in a situation where all capabilities themselves are taken
to be blank are, of course, themselves blank.
When called with a non-int as the first arg (no no args at all), return
the first arg. I am acting as a ``FormattingString``.
"""
if len(args) != 1 or isinstance(args[0], int):
# I am acting as a ParametrizingString.
# tparm can take not only ints but also (at least) strings as its
# second...nth args. But we don't support callably parametrizing
# caps that take non-ints yet, so we can cheap out here. TODO: Go
# through enough of the motions in the capability resolvers to
# determine which of 2 special-purpose classes,
# NullParametrizableString or NullFormattingString, to return, and
# retire this one.
return u''
return args[0] # Should we force even strs in Python 2.x to be
# unicodes? No. How would I know what encoding to use
# to convert it?
def __init__(self, term_stream=sys.stdout):
"""
Create a `TerminalController` and initialize its attributes
with appropriate values for the current terminal.
`term_stream` is the stream that will be used for terminal
output; if this stream is not a tty, then the terminal is
assumed to be a dumb terminal (i.e., have no capabilities).
"""
# Curses isn't available on all platforms
try: import curses
except: return
# If the stream isn't a tty, then assume it has no capabilities.
if not term_stream.isatty(): return
# Check the terminal type. If we fail, then assume that the
# terminal has no capabilities.
try: curses.setupterm()
except: return
# Look up numeric capabilities.
self.COLS = curses.tigetnum('cols')
self.LINES = curses.tigetnum('lines')
# Look up string capabilities.
for capability in self._STRING_CAPABILITIES:
(attrib, cap_name) = capability.split('=')
setattr(self, attrib, self._tigetstr(cap_name) or '')
# Colors
set_fg = self._tigetstr('setf')
if set_fg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
setattr(self, color, curses.tparm(set_fg, i) or '')
set_fg_ansi = self._tigetstr('setaf')
if set_fg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
set_bg = self._tigetstr('setb')
if set_bg:
for i,color in zip(range(len(self._COLORS)), self._COLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
set_bg_ansi = self._tigetstr('setab')
if set_bg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
def __init__(self):
""" Initialization """
dict.__init__(self, {
'NORMAL': '',
'BOLD': '',
'ERASE': '\n',
'RED': '',
'YELLOW': '',
'GREEN': '',
})
try:
import curses as _curses
except ImportError:
# fixup if a submodule of curses failed.
if 'curses' in _sys.modules:
del _sys.modules['curses']
else:
try:
_curses.setupterm()
except (TypeError, _curses.error):
pass
else:
try:
_curses.tigetstr('sgr0')
except TypeError: # pypy3
# pylint: disable = invalid-name
bc = lambda val: val.encode('ascii')
else:
bc = lambda val: val # pylint: disable = invalid-name
def make_color(color):
""" Make color control string """
seq = _curses.tigetstr(bc('setaf'))
if seq is not None:
seq = _curses.tparm(seq, color).decode('ascii')
return seq
self['NORMAL'] = _curses.tigetstr(bc('sgr0')).decode('ascii')
self['BOLD'] = _curses.tigetstr(bc('bold')).decode('ascii')
erase = _curses.tigetstr(bc('el1')).decode('ascii')
if erase is not None:
self['ERASE'] = erase + \
_curses.tigetstr(bc('cr')).decode('ascii')
self['RED'] = make_color(_curses.COLOR_RED)
self['YELLOW'] = make_color(_curses.COLOR_YELLOW)
self['GREEN'] = make_color(_curses.COLOR_GREEN)
def __init__(self):
""" Initialization """
dict.__init__(self, {
'NORMAL': '',
'BOLD': '',
'ERASE': '\n',
'RED': '',
'YELLOW': '',
'GREEN': '',
})
try:
import curses as _curses
except ImportError:
# fixup if a submodule of curses failed.
if 'curses' in _sys.modules:
del _sys.modules['curses']
else:
try:
_curses.setupterm()
except (TypeError, _curses.error):
pass
else:
try:
_curses.tigetstr('sgr0')
except TypeError: # pypy3
# pylint: disable = invalid-name
bc = lambda val: val.encode('ascii')
else:
bc = lambda val: val # pylint: disable = invalid-name
def make_color(color):
""" Make color control string """
seq = _curses.tigetstr(bc('setaf'))
if seq is not None:
seq = _curses.tparm(seq, color).decode('ascii')
return seq
self['NORMAL'] = _curses.tigetstr(bc('sgr0')).decode('ascii')
self['BOLD'] = _curses.tigetstr(bc('bold')).decode('ascii')
erase = _curses.tigetstr(bc('el1')).decode('ascii')
if erase is not None:
self['ERASE'] = erase + \
_curses.tigetstr(bc('cr')).decode('ascii')
self['RED'] = make_color(_curses.COLOR_RED)
self['YELLOW'] = make_color(_curses.COLOR_YELLOW)
self['GREEN'] = make_color(_curses.COLOR_GREEN)
def highlight_line(self, line, offset, last_highlight):
if not self.colorizer.terminal_capable:
return line
if last_highlight:
line = last_highlight + line
limit = offset + len(line)
adjust = 0
for rule in self.highlights:
start = rule.get("start")
end = rule.get("end")
fg = rule.get("fg")
bg = rule.get("bg")
bold = rule.get("bold")
if offset <= start <= limit + adjust:
escape_seq = ""
if fg is not None:
if isinstance(fg, basestring):
fg = self.colorizer.COLOR_MAP[fg]
escape_seq += self.colorizer.tparm(
["setaf", "setf"], fg)
if bg is not None:
if isinstance(bg, basestring):
bg = self.colorizer.COLOR_MAP[bg]
escape_seq += self.colorizer.tparm(
["setab", "setb"], bg)
if bold:
escape_seq += self.colorizer.tparm(["bold"])
insert_at = start - offset + adjust
line = line[:insert_at] + escape_seq + line[insert_at:]
adjust += len(escape_seq)
last_highlight = escape_seq
if offset <= end <= limit + adjust:
escape_seq = self.colorizer.tparm(["sgr0"])
insert_at = end - offset + adjust
line = line[:insert_at] + escape_seq + line[insert_at:]
adjust += len(escape_seq)
last_highlight = None
# Always terminate active highlight at the linebreak because we don't
# know what's being rendered to our right. We will resume
# last_highlight on next line.
if last_highlight:
line += self.colorizer.tparm(["sgr0"])
return line, last_highlight