Merge pull request #1290 from ZyX-I/pdb

Add support for Python debugger
This commit is contained in:
Nikolai Aleksandrovich Pavlov 2015-02-07 04:27:43 +03:00
commit 43a9a2552a
30 changed files with 1258 additions and 28 deletions

View File

@ -23,3 +23,9 @@ Vim listers
.. automodule:: powerline.listers.vim
:members:
Pdb listers
-----------
.. automodule:: powerline.listers.pdb
:members:

View File

@ -239,3 +239,9 @@ In order to keep shell prompt, but avoid launching Python twice to get unused
In order to remove additional space from the end of the right prompt in fish
that was added in order to support multiline prompt ``$POWERLINE_NO_FISH_ABOVE``
or ``$POWERLINE_NO_SHELL_ABOVE`` variable should be set.
PDB overrides
=============
Like shell bindings :ref:`PDB bindings <pdb-prompt>` take overrides from
:ref:`environment variables <local-configuration-overrides-env>`.

View File

@ -0,0 +1,7 @@
************
PDB segments
************
.. automodule:: powerline.segments.pdb
:members:

View File

@ -469,6 +469,21 @@ Ipython
Attribute ``prompt_count`` contains the so-called “history count”
(equivalent to ``\N`` in ``in_template``).
Pdb
---
``pdb``
Currently active :py:class:`pdb.Pdb` instance.
``curframe``
Frame which will be run next. Note: due to the existence of
:py:func:`powerline.listers.pdb.frame_lister` one must not use
``segment_info['pdb'].curframe``.
``initial_stack_length``
Equal to the length of :py:attr:`pdb.Pdb.stack` at the first invocation of
the prompt decremented by one.
Segment class
=============

View File

@ -124,3 +124,41 @@ the used profile:
IPython=0.11* is not supported and does not work. IPython<0.10 was not
tested (not installable by pip).
.. _pdb-prompt:
PDB prompt
==========
To use Powerline with PDB prompt you need to use custom class. Inherit your
class from :py:class:`pdb.Pdb` and decorate it with
:py:func:`powerline.bindings.pdb.use_powerline_prompt`:
.. code-block:: Python
import pdb
from powerline.bindings.pdb import use_powerline_prompt
@use_powerline_prompt
class MyPdb(pdb.Pdb):
pass
MyPdb.run('some.code.to.debug()')
. Alternatively you may use
.. code-block:: bash
python -mpowerline.bindings.pdb path/to/script.py
just like you used ``python -m pdb``.
.. note:
If you are using Python-2.6 you need to use ``python
-mpowerline.bindings.pdb.__main__``, not what is shown above.
.. warning:
Using PyPy (not PyPy3) forces ASCII-only prompts. In other cases unicode
characters are allowed, even if you use `pdbpp
<https://pypi.python.org/pypi/pdbpp>`_.

View File

@ -0,0 +1,183 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import sys
import pdb
from powerline.pdb import PDBPowerline
from powerline.lib.encoding import get_preferred_output_encoding
from powerline.lib.unicode import unicode
if sys.version_info < (3,):
# XXX The below classes make code compatible with PDBpp which uses pyrepl
# which does not expect unicode or something above ASCII. They are
# completely not needed if pdbpp is not used, but thats not always the
# case.
class PowerlineRenderBytesResult(bytes):
def __new__(cls, s, encoding=None):
encoding = encoding or s.encoding
if isinstance(s, PowerlineRenderResult):
return s.encode(encoding)
self = bytes.__new__(cls, s.encode(encoding) if isinstance(s, unicode) else s)
self.encoding = encoding
return self
for meth in (
'__contains__',
'partition', 'rpartition',
'split', 'rsplit',
'count', 'join',
):
exec((
'def {0}(self, *args):\n'
' if any((isinstance(arg, unicode) for arg in args)):\n'
' return self.__unicode__().{0}(*args)\n'
' else:\n'
' return bytes.{0}(self, *args)'
).format(meth))
for meth in (
'find', 'rfind',
'index', 'rindex',
):
exec((
'def {0}(self, *args):\n'
' if any((isinstance(arg, unicode) for arg in args)):\n'
' args = [arg.encode(self.encoding) if isinstance(arg, unicode) else arg for arg in args]\n'
' return bytes.{0}(self, *args)'
).format(meth))
def __len__(self):
return len(self.decode(self.encoding))
def __getitem__(self, *args):
return PowerlineRenderBytesResult(bytes.__getitem__(self, *args), encoding=self.encoding)
def __getslice__(self, *args):
return PowerlineRenderBytesResult(bytes.__getslice__(self, *args), encoding=self.encoding)
@staticmethod
def add(encoding, *args):
if any((isinstance(arg, unicode) for arg in args)):
return PowerlineRenderResult(''.join((
arg
if isinstance(arg, unicode)
else arg.decode(encoding)
for arg in args
)), encoding)
else:
return PowerlineRenderBytesResult(b''.join(args), encoding=encoding)
def __add__(self, other):
return self.add(self.encoding, self, other)
def __radd__(self, other):
return self.add(self.encoding, other, self)
def __unicode__(self):
return PowerlineRenderResult(self)
class PowerlineRenderResult(unicode):
def __new__(cls, s, encoding=None):
encoding = (
encoding
or getattr(s, 'encoding', None)
or get_preferred_output_encoding()
)
if isinstance(s, unicode):
self = unicode.__new__(cls, s)
else:
self = unicode.__new__(cls, s, encoding, 'replace')
self.encoding = encoding
return self
def __str__(self):
return PowerlineRenderBytesResult(self)
def __getitem__(self, *args):
return PowerlineRenderResult(unicode.__getitem__(self, *args))
def __getslice__(self, *args):
return PowerlineRenderResult(unicode.__getslice__(self, *args))
@staticmethod
def add(encoding, *args):
return PowerlineRenderResult(''.join((
arg
if isinstance(arg, unicode)
else arg.decode(encoding)
for arg in args
)), encoding)
def __add__(self, other):
return self.add(self.encoding, self, other)
def __radd__(self, other):
return self.add(self.encoding, other, self)
def encode(self, *args, **kwargs):
return PowerlineRenderBytesResult(unicode.encode(self, *args, **kwargs), args[0])
else:
PowerlineRenderResult = str
def use_powerline_prompt(cls):
'''Decorator that installs powerline prompt to the class
:param pdb.Pdb cls:
Class that should be decorated.
:return:
``cls`` argument or a class derived from it. Latter is used to turn
old-style classes into new-style classes.
'''
@property
def prompt(self):
try:
powerline = self.powerline
except AttributeError:
powerline = PDBPowerline()
powerline.setup(self)
self.powerline = powerline
return PowerlineRenderResult(powerline.render(side='left'))
@prompt.setter
def prompt(self, _):
pass
@prompt.deleter
def prompt(self):
pass
if not hasattr(cls, '__class__'):
# Old-style class: make it new-style or @property will not work.
old_cls = cls
class cls(cls, object):
__module__ = cls.__module__
__doc__ = cls.__doc__
cls.__name__ = old_cls.__name__
cls.prompt = prompt
return cls
def main():
'''Run module as a script
Uses :py:func:`pdb.main` function directly, but prior to that it mocks
:py:class:`pdb.Pdb` class with powerline-specific class instance.
'''
orig_pdb = pdb.Pdb
@use_powerline_prompt
class Pdb(pdb.Pdb, object):
def __init__(self):
orig_pdb.__init__(self)
pdb.Pdb = Pdb
return pdb.main()

View File

@ -0,0 +1,9 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
from powerline.bindings.pdb import main
if __name__ == '__main__':
main()

View File

@ -15,7 +15,7 @@ fn _powerline_continuation_prompt {
_powerline_prompt --renderer-arg 'local_theme=continuation' $*
}
fn _powerline_prompt {
$POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS shell aboveleft -r.rcsh --last-pipe-status $^_POWERLINE_STATUS --last-exit-code $_POWERLINE_STATUS($#_POWERLINE_STATUS) --jobnum $_POWERLINE_JOBNUM --renderer-arg 'client_id='$pid $*
$POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS shell aboveleft -r.readline --last-pipe-status $^_POWERLINE_STATUS --last-exit-code $_POWERLINE_STATUS($#_POWERLINE_STATUS) --jobnum $_POWERLINE_JOBNUM --renderer-arg 'client_id='$pid $*
}
fn _powerline_set_prompt {
_POWERLINE_STATUS = ( $status )

View File

@ -0,0 +1,8 @@
{
"groups": {
"current_code_name": "information:additional",
"current_context": "current_code_name",
"current_line": "information:regular",
"current_file": "information:regular"
}
}

View File

@ -0,0 +1,5 @@
{
"groups": {
"stack_depth": { "fg": "gray1", "bg": "gray10", "attrs": ["bold"] }
}
}

View File

@ -0,0 +1,5 @@
{
"groups": {
"stack_depth": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] }
}
}

View File

@ -12,6 +12,10 @@
"in2": "in2"
}
},
"pdb": {
"colorscheme": "default",
"theme": "default"
},
"shell": {
"colorscheme": "default",
"theme": "default",

View File

@ -0,0 +1,27 @@
{
"default_module": "powerline.segments.pdb",
"segments": {
"left": [
{
"function": "stack_depth"
},
{
"type": "segment_list",
"function": "powerline.listers.pdb.frame_lister",
"segments": [
{
"function": "current_file",
"after": ":"
},
{
"function": "current_line",
"after": " "
},
{
"function": "current_code_name"
}
]
}
]
}
}

37
powerline/listers/pdb.py Normal file
View File

@ -0,0 +1,37 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
from powerline.theme import requires_segment_info
@requires_segment_info
def frame_lister(pl, segment_info, full_stack=False, maxframes=3):
'''List all frames in segment_info format
:param bool full_stack:
If true, then all frames in the stack are listed. Normally N first
frames are discarded where N is a number of frames present at the first
invocation of the prompt minus one.
:param int maxframes:
Maximum number of frames to display.
'''
if full_stack:
initial_stack_length = 0
frames = segment_info['pdb'].stack
else:
initial_stack_length = segment_info['initial_stack_length']
frames = segment_info['pdb'].stack[initial_stack_length:]
if len(frames) > maxframes:
frames = frames[-maxframes:]
return (
(
{
'curframe': frame[0],
'initial_stack_length': initial_stack_length,
},
{}
)
for frame in frames
)

48
powerline/pdb.py Normal file
View File

@ -0,0 +1,48 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import sys
import platform
import os
from powerline import Powerline
from powerline.lib.overrides import parse_override_var
from powerline.lib.dict import mergeargs, mergedicts
class PDBPowerline(Powerline):
'''PDB-specific powerline bindings
'''
def init(self, **kwargs):
return super(PDBPowerline, self).init(
ext='pdb',
renderer_module='pdb',
**kwargs
)
def do_setup(self, pdb):
self.update_renderer()
self.renderer.set_pdb(pdb)
def load_main_config(self):
r = super(PDBPowerline, self).load_main_config()
config_overrides = os.environ.get('POWERLINE_CONFIG_OVERRIDES')
if config_overrides:
mergedicts(r, mergeargs(parse_override_var(config_overrides)))
return r
def load_theme_config(self, name):
r = super(PDBPowerline, self).load_theme_config(name)
theme_overrides = os.environ.get('POWERLINE_THEME_OVERRIDES')
if theme_overrides:
theme_overrides_dict = mergeargs(parse_override_var(theme_overrides))
if name in theme_overrides_dict:
mergedicts(r, theme_overrides_dict[name])
return r
def get_config_paths(self):
paths = [path for path in os.environ.get('POWERLINE_CONFIG_PATHS', '').split(':') if path]
return paths or super(PDBPowerline, self).get_config_paths()
if sys.version_info < (3,) and platform.python_implementation() == 'PyPy':
get_encoding = staticmethod(lambda: 'ascii')

View File

@ -124,8 +124,10 @@ class Renderer(object):
'getcwd': getattr(os, 'getcwdu', os.getcwd),
'home': os.environ.get('HOME'),
}
'''Basic segment info. Is merged with local segment information by
``.get_segment_info()`` method. Keys:
'''Basic segment info
Is merged with local segment information by :py:meth:`get_segment_info`
method. Keys:
``environ``
Object containing environment variables. Must define at least the
@ -279,9 +281,10 @@ class Renderer(object):
string_width)``. Returns a three-tuple if ``output_raw`` is also
``True``: ``(colored_string, colorless_string, string_width)``.
:param dict segment_info:
Segment information. See also ``.get_segment_info()`` method.
Segment information. See also :py:meth:`get_segment_info` method.
:param matcher_info:
Matcher information. Is processed in ``.get_theme()`` method.
Matcher information. Is processed in :py:meth:`get_segment_info`
method.
'''
theme = self.get_theme(matcher_info)
return self.do_render(
@ -504,7 +507,7 @@ class Renderer(object):
def hl(self, contents, fg=None, bg=None, attrs=None):
'''Output highlighted chunk.
This implementation just outputs ``.hlstyle()`` joined with
This implementation just outputs :py:meth:`hlstyle` joined with
``contents``.
'''
return self.hlstyle(fg, bg, attrs) + (contents or '')

View File

@ -2,6 +2,7 @@
from __future__ import (unicode_literals, division, absolute_import, print_function)
from powerline.renderers.shell import ShellRenderer
from powerline.renderers.shell.readline import ReadlineRenderer
from powerline.theme import Theme
@ -45,10 +46,9 @@ class IPythonRenderer(ShellRenderer):
)
class IPythonPromptRenderer(IPythonRenderer):
class IPythonPromptRenderer(IPythonRenderer, ReadlineRenderer):
'''Powerline ipython prompt (in and in2) renderer'''
escape_hl_start = '\x01'
escape_hl_end = '\x02'
pass
class IPythonNonPromptRenderer(IPythonRenderer):

View File

@ -0,0 +1,50 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import sys
import platform
from powerline.renderers.shell.readline import ReadlineRenderer
from powerline.renderer import Renderer
class PDBRenderer(ReadlineRenderer):
'''PDB-specific powerline renderer
'''
pdb = None
initial_stack_length = None
def get_segment_info(self, segment_info, mode):
r = self.segment_info.copy()
r['pdb'] = self.pdb
r['initial_stack_length'] = self.initial_stack_length
r['curframe'] = self.pdb.curframe
return r
def set_pdb(self, pdb):
'''Record currently used :py:class:`pdb.Pdb` instance
Must be called before first calling :py:meth:`render` method.
:param pdb.Pdb pdb:
Used :py:class:`pdb.Pdb` instance. This instance will later be used
by :py:meth:`get_segment_info` for patching :ref:`segment_info
<dev-segments-info>` dictionary.
'''
self.pdb = pdb
def render(self, **kwargs):
if self.initial_stack_length is None:
self.initial_stack_length = len(self.pdb.stack) - 1
return Renderer.render(self, **kwargs)
if sys.version_info < (3,) and platform.python_implementation() == 'PyPy':
def do_render(self, **kwargs):
# Make sure that only ASCII characters survive
ret = super(PDBRenderer, self).do_render(**kwargs)
ret = ret.encode('ascii', 'replace')
ret = ret.decode('ascii')
return ret
renderer = PDBRenderer

View File

@ -1,12 +1,7 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
from powerline.renderers.shell import ShellRenderer
from powerline.renderers.shell.readline import ReadlineRenderer
class RcshRenderer(ShellRenderer):
'''Powerline rcsh prompt renderer'''
escape_hl_start = '\x01'
escape_hl_end = '\x02'
renderer = RcshRenderer
renderer = ReadlineRenderer

View File

@ -0,0 +1,14 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
from powerline.renderers.shell import ShellRenderer
class ReadlineRenderer(ShellRenderer):
'''Renderer useful for some applications that use readline
'''
escape_hl_start = '\x01'
escape_hl_end = '\x02'
renderer = ReadlineRenderer

61
powerline/segments/pdb.py Normal file
View File

@ -0,0 +1,61 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import os
from powerline.theme import requires_segment_info
@requires_segment_info
def current_line(pl, segment_info):
'''Displays line number that is next to be run
'''
return str(segment_info['curframe'].f_lineno)
@requires_segment_info
def current_file(pl, segment_info, basename=True):
'''Displays current file name
:param bool basename:
If true only basename is displayed.
'''
filename = segment_info['curframe'].f_code.co_filename
if basename:
filename = os.path.basename(filename)
return filename
@requires_segment_info
def current_code_name(pl, segment_info):
'''Displays name of the code object of the current frame
'''
return segment_info['curframe'].f_code.co_name
@requires_segment_info
def current_context(pl, segment_info):
'''Displays currently executed context name
This is similar to :py:func:`current_code_name`, but gives more details.
Currently it only gives module file name if code_name happens to be
``<module>``.
'''
name = segment_info['curframe'].f_code.co_name
if name == '<module>':
name = os.path.basename(segment_info['curframe'].f_code.co_filename)
return name
@requires_segment_info
def stack_depth(pl, segment_info, full_stack=False):
'''Displays current stack depth
Result is relative to the stack depth at the time prompt was first run.
:param bool full_stack:
If true then absolute depth is used.
'''
return str(len(segment_info['pdb'].stack) - (
0 if full_stack else segment_info['initial_stack_length']))

View File

@ -217,10 +217,6 @@ class VimPowerline(Powerline):
for args in _local_themes:
self.add_local_theme(*args)
@staticmethod
def get_segment_info():
return {}
def reset_highlight(self):
try:
self.renderer.reset_highlight()

View File

@ -7,7 +7,7 @@ import os
from functools import partial
from collections import namedtuple
from powerline.segments import shell, tmux
from powerline.segments import shell, tmux, pdb
from powerline.lib.vcs import get_fallback_create_watcher
from powerline.lib.unicode import out_u
@ -1308,6 +1308,52 @@ class TestVim(TestCase):
sys.path.pop(0)
class TestPDB(TestCase):
def test_current_line(self):
pl = Pl()
self.assertEqual(pdb.current_line(pl=pl, segment_info={'curframe': Args(f_lineno=10)}), '10')
def test_current_file(self):
pl = Pl()
cf = lambda **kwargs: pdb.current_file(
pl=pl,
segment_info={'curframe': Args(f_code=Args(co_filename='/tmp/abc.py'))},
**kwargs
)
self.assertEqual(cf(), 'abc.py')
self.assertEqual(cf(basename=True), 'abc.py')
self.assertEqual(cf(basename=False), '/tmp/abc.py')
def test_current_code_name(self):
pl = Pl()
ccn = lambda **kwargs: pdb.current_code_name(
pl=pl,
segment_info={'curframe': Args(f_code=Args(co_name='<module>'))},
**kwargs
)
self.assertEqual(ccn(), '<module>')
def test_current_context(self):
pl = Pl()
cc = lambda **kwargs: pdb.current_context(
pl=pl,
segment_info={'curframe': Args(f_code=Args(co_name='<module>', co_filename='/tmp/abc.py'))},
**kwargs
)
self.assertEqual(cc(), 'abc.py')
def test_stack_depth(self):
pl = Pl()
sd = lambda **kwargs: pdb.stack_depth(
pl=pl,
segment_info={'pdb': Args(stack=[1, 2, 3]), 'initial_stack_length': 1},
**kwargs
)
self.assertEqual(sd(), '2')
self.assertEqual(sd(full_stack=False), '2')
self.assertEqual(sd(full_stack=True), '3')
old_cwd = None

View File

@ -0,0 +1,89 @@
s


View File

@ -0,0 +1,24 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import pdb
import os
import sys
from powerline.bindings.pdb import use_powerline_prompt
@use_powerline_prompt
class Pdb(pdb.Pdb):
pass
p = Pdb()
script = os.path.join(os.path.dirname(__file__), 'pdb-script.py')
with open(script, 'r') as fd:
code = compile(fd.read(), script, 'exec')
p.run('exec(code)', globals={'code': code})

View File

@ -0,0 +1,38 @@
# vim:fileencoding=utf-8:noet
def nop(_):
pass
class Foo(object):
def __init__(self):
nop('__init__')
self.bar()
self.baz()
self.bra()
@classmethod
def bar(cls):
nop(cls.__name__)
@staticmethod
def baz():
nop(1)
def bra(self):
nop(self.__class__.__name__)
def brah():
nop('brah')
f = Foo()
Foo.bar()
Foo.baz()
Foo.bra(f)
f.bar()
f.baz()
f.bra()
brah()

View File

@ -0,0 +1,222 @@
 1  pdb-script.py:6 <module>  
--Call--
-> class Foo(object):
 2  pdb-script.py:6 <module>  pdb-script.py:6 Foo  
-> class Foo(object):
 2  pdb-script.py:6 <module>  pdb-script.py:6 Foo  
-> def __init__(self):
 2  pdb-script.py:6 <module>  pdb-script.py:7 Foo  
-> @classmethod
 2  pdb-script.py:6 <module>  pdb-script.py:13 Foo  
-> @staticmethod
 2  pdb-script.py:6 <module>  pdb-script.py:17 Foo  
-> def bra(self):
 2  pdb-script.py:6 <module>  pdb-script.py:21 Foo  
--Return--
-> def bra(self):
 2  pdb-script.py:6 <module>  pdb-script.py:21 Foo  
-> def brah():
 1  pdb-script.py:25 <module>  
-> f = Foo()
 1  pdb-script.py:29 <module>  
--Call--
-> def __init__(self):
 2  pdb-script.py:29 <module>  pdb-script.py:7 __init__  
-> nop('__init__')
 2  pdb-script.py:29 <module>  pdb-script.py:8 __init__  
--Call--
-> def nop(_):
 3  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:2 nop  
-> pass
 3  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:3 nop  
--Return--
-> pass
 3  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:3 nop  
-> self.bar()
 2  pdb-script.py:29 <module>  pdb-script.py:9 __init__  
--Call--
-> @classmethod
 3  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:13 bar  
-> nop(cls.__name__)
 3  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:15 bar  
--Call--
-> def nop(_):
 4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> nop(cls.__name__)
 3  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:15 bar  
-> self.baz()
 2  pdb-script.py:29 <module>  pdb-script.py:10 __init__  
--Call--
-> @staticmethod
 3  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:17 baz  
-> nop(1)
 3  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:19 baz  
--Call--
-> def nop(_):
 4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> nop(1)
 3  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:19 baz  
-> self.bra()
 2  pdb-script.py:29 <module>  pdb-script.py:11 __init__  
--Call--
-> def bra(self):
 3  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:21 bra  
-> nop(self.__class__.__name__)
 3  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:22 bra  
--Call--
-> def nop(_):
 4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> nop(self.__class__.__name__)
 3  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:22 bra  
--Return--
-> self.bra()
 2  pdb-script.py:29 <module>  pdb-script.py:11 __init__  
-> Foo.bar()
 1  pdb-script.py:30 <module>  
--Call--
-> @classmethod
 2  pdb-script.py:30 <module>  pdb-script.py:13 bar  
-> nop(cls.__name__)
 2  pdb-script.py:30 <module>  pdb-script.py:15 bar  
--Call--
-> def nop(_):
 3  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:2 nop  
-> pass
 3  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> pass
 3  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> nop(cls.__name__)
 2  pdb-script.py:30 <module>  pdb-script.py:15 bar  
-> Foo.baz()
 1  pdb-script.py:31 <module>  
--Call--
-> @staticmethod
 2  pdb-script.py:31 <module>  pdb-script.py:17 baz  
-> nop(1)
 2  pdb-script.py:31 <module>  pdb-script.py:19 baz  
--Call--
-> def nop(_):
 3  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:2 nop  
-> pass
 3  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> pass
 3  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> nop(1)
 2  pdb-script.py:31 <module>  pdb-script.py:19 baz  
-> Foo.bra(f)
 1  pdb-script.py:32 <module>  
--Call--
-> def bra(self):
 2  pdb-script.py:32 <module>  pdb-script.py:21 bra  
-> nop(self.__class__.__name__)
 2  pdb-script.py:32 <module>  pdb-script.py:22 bra  
--Call--
-> def nop(_):
 3  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:2 nop  
-> pass
 3  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> pass
 3  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> nop(self.__class__.__name__)
 2  pdb-script.py:32 <module>  pdb-script.py:22 bra  
-> f.bar()
 1  pdb-script.py:34 <module>  
--Call--
-> @classmethod
 2  pdb-script.py:34 <module>  pdb-script.py:13 bar  
-> nop(cls.__name__)
 2  pdb-script.py:34 <module>  pdb-script.py:15 bar  
--Call--
-> def nop(_):
 3  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:2 nop  
-> pass
 3  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> pass
 3  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> nop(cls.__name__)
 2  pdb-script.py:34 <module>  pdb-script.py:15 bar  
-> f.baz()
 1  pdb-script.py:35 <module>  
--Call--
-> @staticmethod
 2  pdb-script.py:35 <module>  pdb-script.py:17 baz  
-> nop(1)
 2  pdb-script.py:35 <module>  pdb-script.py:19 baz  
--Call--
-> def nop(_):
 3  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:2 nop  
-> pass
 3  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> pass
 3  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> nop(1)
 2  pdb-script.py:35 <module>  pdb-script.py:19 baz  
-> f.bra()
 1  pdb-script.py:36 <module>  
--Call--
-> def bra(self):
 2  pdb-script.py:36 <module>  pdb-script.py:21 bra  
-> nop(self.__class__.__name__)
 2  pdb-script.py:36 <module>  pdb-script.py:22 bra  
--Call--
-> def nop(_):
 3  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:2 nop  
-> pass
 3  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> pass
 3  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> nop(self.__class__.__name__)
 2  pdb-script.py:36 <module>  pdb-script.py:22 bra  
-> brah()
 1  pdb-script.py:38 <module>  
--Call--
-> def brah():
 2  pdb-script.py:38 <module>  pdb-script.py:25 brah  
-> nop('brah')
 2  pdb-script.py:38 <module>  pdb-script.py:26 brah  
--Call--
-> def nop(_):
 3  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:2 nop  
-> pass
 3  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:3 nop  
--Return--
-> pass
 3  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:3 nop  
--Return--
-> nop('brah')
 2  pdb-script.py:38 <module>  pdb-script.py:26 brah  
--Return--
-> brah()
 1  pdb-script.py:38 <module>  
--Return--
 0  

View File

@ -0,0 +1,217 @@
 2  <string>:1 <module>  pdb-script.py:6 <module>  
--Call--
-> class Foo(object):
 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:6 Foo  
-> class Foo(object):
 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:6 Foo  
-> def __init__(self):
 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:7 Foo  
-> @classmethod
 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:13 Foo  
-> @staticmethod
 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:17 Foo  
-> def bra(self):
 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:21 Foo  
--Return--
-> def bra(self):
 3  <string>:1 <module>  pdb-script.py:6 <module>  pdb-script.py:21 Foo  
-> def brah():
 2  <string>:1 <module>  pdb-script.py:25 <module>  
-> f = Foo()
 2  <string>:1 <module>  pdb-script.py:29 <module>  
--Call--
-> def __init__(self):
 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:7 __init__  
-> nop('__init__')
 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:8 __init__  
--Call--
-> def nop(_):
 4  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:29 <module>  pdb-script.py:8 __init__  pdb-script.py:3 nop  
-> self.bar()
 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:9 __init__  
--Call--
-> @classmethod
 4  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:13 bar  
-> nop(cls.__name__)
 4  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:15 bar  
--Call--
-> def nop(_):
 5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:2 nop  
-> pass
 5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> pass
 5  pdb-script.py:9 __init__  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> nop(cls.__name__)
 4  pdb-script.py:29 <module>  pdb-script.py:9 __init__  pdb-script.py:15 bar  
-> self.baz()
 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:10 __init__  
--Call--
-> @staticmethod
 4  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:17 baz  
-> nop(1)
 4  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:19 baz  
--Call--
-> def nop(_):
 5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:2 nop  
-> pass
 5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> pass
 5  pdb-script.py:10 __init__  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> nop(1)
 4  pdb-script.py:29 <module>  pdb-script.py:10 __init__  pdb-script.py:19 baz  
-> self.bra()
 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:11 __init__  
--Call--
-> def bra(self):
 4  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:21 bra  
-> nop(self.__class__.__name__)
 4  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:22 bra  
--Call--
-> def nop(_):
 5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:2 nop  
-> pass
 5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> pass
 5  pdb-script.py:11 __init__  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> nop(self.__class__.__name__)
 4  pdb-script.py:29 <module>  pdb-script.py:11 __init__  pdb-script.py:22 bra  
--Return--
-> self.bra()
 3  <string>:1 <module>  pdb-script.py:29 <module>  pdb-script.py:11 __init__  
-> Foo.bar()
 2  <string>:1 <module>  pdb-script.py:30 <module>  
--Call--
-> @classmethod
 3  <string>:1 <module>  pdb-script.py:30 <module>  pdb-script.py:13 bar  
-> nop(cls.__name__)
 3  <string>:1 <module>  pdb-script.py:30 <module>  pdb-script.py:15 bar  
--Call--
-> def nop(_):
 4  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:30 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> nop(cls.__name__)
 3  <string>:1 <module>  pdb-script.py:30 <module>  pdb-script.py:15 bar  
-> Foo.baz()
 2  <string>:1 <module>  pdb-script.py:31 <module>  
--Call--
-> @staticmethod
 3  <string>:1 <module>  pdb-script.py:31 <module>  pdb-script.py:17 baz  
-> nop(1)
 3  <string>:1 <module>  pdb-script.py:31 <module>  pdb-script.py:19 baz  
--Call--
-> def nop(_):
 4  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:31 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> nop(1)
 3  <string>:1 <module>  pdb-script.py:31 <module>  pdb-script.py:19 baz  
-> Foo.bra(f)
 2  <string>:1 <module>  pdb-script.py:32 <module>  
--Call--
-> def bra(self):
 3  <string>:1 <module>  pdb-script.py:32 <module>  pdb-script.py:21 bra  
-> nop(self.__class__.__name__)
 3  <string>:1 <module>  pdb-script.py:32 <module>  pdb-script.py:22 bra  
--Call--
-> def nop(_):
 4  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:32 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> nop(self.__class__.__name__)
 3  <string>:1 <module>  pdb-script.py:32 <module>  pdb-script.py:22 bra  
-> f.bar()
 2  <string>:1 <module>  pdb-script.py:34 <module>  
--Call--
-> @classmethod
 3  <string>:1 <module>  pdb-script.py:34 <module>  pdb-script.py:13 bar  
-> nop(cls.__name__)
 3  <string>:1 <module>  pdb-script.py:34 <module>  pdb-script.py:15 bar  
--Call--
-> def nop(_):
 4  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:34 <module>  pdb-script.py:15 bar  pdb-script.py:3 nop  
--Return--
-> nop(cls.__name__)
 3  <string>:1 <module>  pdb-script.py:34 <module>  pdb-script.py:15 bar  
-> f.baz()
 2  <string>:1 <module>  pdb-script.py:35 <module>  
--Call--
-> @staticmethod
 3  <string>:1 <module>  pdb-script.py:35 <module>  pdb-script.py:17 baz  
-> nop(1)
 3  <string>:1 <module>  pdb-script.py:35 <module>  pdb-script.py:19 baz  
--Call--
-> def nop(_):
 4  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:35 <module>  pdb-script.py:19 baz  pdb-script.py:3 nop  
--Return--
-> nop(1)
 3  <string>:1 <module>  pdb-script.py:35 <module>  pdb-script.py:19 baz  
-> f.bra()
 2  <string>:1 <module>  pdb-script.py:36 <module>  
--Call--
-> def bra(self):
 3  <string>:1 <module>  pdb-script.py:36 <module>  pdb-script.py:21 bra  
-> nop(self.__class__.__name__)
 3  <string>:1 <module>  pdb-script.py:36 <module>  pdb-script.py:22 bra  
--Call--
-> def nop(_):
 4  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:36 <module>  pdb-script.py:22 bra  pdb-script.py:3 nop  
--Return--
-> nop(self.__class__.__name__)
 3  <string>:1 <module>  pdb-script.py:36 <module>  pdb-script.py:22 bra  
-> brah()
 2  <string>:1 <module>  pdb-script.py:38 <module>  
--Call--
-> def brah():
 3  <string>:1 <module>  pdb-script.py:38 <module>  pdb-script.py:25 brah  
-> nop('brah')
 3  <string>:1 <module>  pdb-script.py:38 <module>  pdb-script.py:26 brah  
--Call--
-> def nop(_):
 4  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:2 nop  
-> pass
 4  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:3 nop  
--Return--
-> pass
 4  pdb-script.py:38 <module>  pdb-script.py:26 brah  pdb-script.py:3 nop  
--Return--
-> nop('brah')
 3  <string>:1 <module>  pdb-script.py:38 <module>  pdb-script.py:26 brah  

View File

@ -34,9 +34,15 @@ IPYPY_DEANSI_RE = re.compile(r'\033(?:\[(?:\?\d+[lh]|[^a-zA-Z]+[a-ln-zA-Z])|[=>]
with codecs.open(fname, 'r', encoding='utf-8') as R:
with codecs.open(new_fname, 'w', encoding='utf-8') as W:
found_cd = False
i = -1
for line in (R if shell != 'fish' else R.read().split('\n')):
i += 1
if not found_cd:
found_cd = ('cd tests/shell/3rd' in line)
found_cd = (
'class Foo(object):' in line
if shell == 'pdb' else
'cd tests/shell/3rd' in line
)
continue
if 'true is the last line' in line:
break
@ -101,4 +107,15 @@ with codecs.open(fname, 'r', encoding='utf-8') as R:
elif shell == 'rc':
if line == 'read() failed: Connection reset by peer\n':
line = ''
elif shell == 'pdb':
if is_pypy:
if line == '\033[?1h\033=\033[?25l\033[1A\n':
line = ''
line = IPYPY_DEANSI_RE.subn('', line)[0]
if line == '\n':
line = ''
if line.startswith(('>',)):
line = ''
elif line == '-> self.quitting = 1\n':
line = '-> self.quitting = True\n'
W.write(line)

View File

@ -1,5 +1,7 @@
#!/bin/sh
set -e
. tests/bot-ci/scripts/common/main.sh
set +x
: ${PYTHON:=python}
FAIL_SUMMARY=""
FAILED=0
@ -109,14 +111,41 @@ do_run_test() {
done
# Wait for screen to initialize
sleep 1
while ! screen -S "$SESNAME" -p 0 -X width 300 1 ; do
local attempts=100
while ! screen -S "$SESNAME" -p 0 -X width 300 1 >/dev/null ; do
sleep 0.1s
attempts=$(( attempts - 1 ))
if test $attempts -eq 0 ; then
echo "Waiting for too long: assuming test failed"
echo "Failed ${SH}. Full output:"
echo '============================================================'
cat tests/shell/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log
echo '____________________________________________________________'
if test "x$POWERLINE_TEST_NO_CAT_V" != "x1" ; then
echo "Full output (cat -v):"
echo '============================================================'
cat -v tests/shell/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log
echo '____________________________________________________________'
fi
return 1
fi
done
if ( \
test "x${SH}" = "xdash" ||
( \
test "x${SH}" = "xdash" \
|| ( \
test "x${SH}" = "xipython" \
&& ${PYTHON} -c 'import platform, sys; sys.exit(1 - (platform.python_implementation() == "PyPy"))' \
&& test "$PYTHON_IMPLEMENTATION" = "PyPy" \
) \
|| ( \
test "x${SH}" = "xpdb" \
&& ( \
( \
test "$PYTHON_VERSION_MAJOR" -eq 3 \
&& test "$PYTHON_VERSION_MINOR" -eq 2 \
&& test "$PYTHON_IMPLEMENTATION" = "CPython" \
) \
|| test "$PYTHON_IMPLEMENTATION" = "PyPy" \
) \
) \
) ; then
# If I do not use this hack for dash then output will look like
@ -126,7 +155,9 @@ do_run_test() {
# …
# prompt1> prompt2> …
while read -r line ; do
screen -S "$SESNAME" -p 0 -X stuff "$line$NL"
if test "$(screen -S "$SESNAME" -p 0 -X stuff "$line$NL")" = "No screen session found." ; then
break
fi
sleep 1
done < tests/test_shells/input.$SH
else
@ -185,6 +216,9 @@ run_test() {
TEST_CLIENT="$2"
SH="$3"
local attempts=3
if test -n "$ONLY_SHELL$ONLY_TEST_TYPE$ONLY_TEST_CLIENT" ; then
attempts=1
fi
while test $attempts -gt 0 ; do
rm -f tests/shell/${SH}.${TEST_TYPE}.${TEST_CLIENT}.log
rm -f tests/shell/${SH}.${TEST_TYPE}.${TEST_CLIENT}.full.log
@ -256,6 +290,9 @@ for pexe in powerline powerline-config ; do
fi
done
ln -s python tests/shell/path/pdb
PDB_PYTHON=pdb
if test -z "$POWERLINE_RC_EXE" ; then
if which rc-status >/dev/null ; then
# On Gentoo `rc` executable is from OpenRC. Thus app-shells/rc instals
@ -418,6 +455,29 @@ if ( test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xzsh" ) \
fi
fi
if test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xpdb" ; then
if ! ( test "$PYTHON_IMPLEMENTATION" = "PyPy" && test "$PYTHON_VERSION_MAJOR" = 2 ) ; then
if test "x${ONLY_TEST_TYPE}" = "x" || test "x${ONLY_TEST_TYPE}" = "xsubclass" ; then
echo "> pdb subclass"
if ! run_test subclass python $PDB_PYTHON "$PWD/tests/test_shells/pdb-main.py" ; then
FAILED=1
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T pdb $PDB_PYTHON $PWD/tests/test_shells/pdb-main.py"
fi
fi
if test "x${ONLY_TEST_TYPE}" = "x" || test "x${ONLY_TEST_TYPE}" = "xmodule" ; then
echo "> pdb module"
MODULE="powerline.bindings.pdb"
if test "$PYTHON_MM" = "2.6" ; then
MODULE="powerline.bindings.pdb.__main__"
fi
if ! run_test module python $PDB_PYTHON -m$MODULE "$PWD/tests/test_shells/pdb-script.py" ; then
FAILED=1
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T pdb $PDB_PYTHON -m$MODULE $PWD/tests/test_shells/pdb-script"
fi
fi
fi
fi
if test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xipython" ; then
if which ipython >/dev/null ; then
# Define some overrides which should be ignored by IPython.