diff --git a/docs/source/configuration/listers.rst b/docs/source/configuration/listers.rst index dc544b91..04e5371e 100644 --- a/docs/source/configuration/listers.rst +++ b/docs/source/configuration/listers.rst @@ -23,3 +23,9 @@ Vim listers .. automodule:: powerline.listers.vim :members: + +Pdb listers +----------- + +.. automodule:: powerline.listers.pdb + :members: diff --git a/docs/source/configuration/local.rst b/docs/source/configuration/local.rst index 3eec3ee0..5ea233f4 100644 --- a/docs/source/configuration/local.rst +++ b/docs/source/configuration/local.rst @@ -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 ` take overrides from +:ref:`environment variables `. diff --git a/docs/source/configuration/segments/pdb.rst b/docs/source/configuration/segments/pdb.rst new file mode 100644 index 00000000..b9a104b2 --- /dev/null +++ b/docs/source/configuration/segments/pdb.rst @@ -0,0 +1,7 @@ +************ +PDB segments +************ + +.. automodule:: powerline.segments.pdb + :members: + diff --git a/docs/source/develop/segments.rst b/docs/source/develop/segments.rst index 509eb7f7..3fea00a2 100644 --- a/docs/source/develop/segments.rst +++ b/docs/source/develop/segments.rst @@ -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 ============= diff --git a/docs/source/usage/other.rst b/docs/source/usage/other.rst index cbdab712..c160339f 100644 --- a/docs/source/usage/other.rst +++ b/docs/source/usage/other.rst @@ -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 + `_. diff --git a/powerline/bindings/pdb/__init__.py b/powerline/bindings/pdb/__init__.py new file mode 100644 index 00000000..4033e611 --- /dev/null +++ b/powerline/bindings/pdb/__init__.py @@ -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 that’s 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() diff --git a/powerline/bindings/pdb/__main__.py b/powerline/bindings/pdb/__main__.py new file mode 100755 index 00000000..768b2f29 --- /dev/null +++ b/powerline/bindings/pdb/__main__.py @@ -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() diff --git a/powerline/bindings/rc/powerline.rc b/powerline/bindings/rc/powerline.rc index 732d40c8..15b313a9 100644 --- a/powerline/bindings/rc/powerline.rc +++ b/powerline/bindings/rc/powerline.rc @@ -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 ) diff --git a/powerline/config_files/colorschemes/pdb/__main__.json b/powerline/config_files/colorschemes/pdb/__main__.json new file mode 100644 index 00000000..01a51fe5 --- /dev/null +++ b/powerline/config_files/colorschemes/pdb/__main__.json @@ -0,0 +1,8 @@ +{ + "groups": { + "current_code_name": "information:additional", + "current_context": "current_code_name", + "current_line": "information:regular", + "current_file": "information:regular" + } +} diff --git a/powerline/config_files/colorschemes/pdb/default.json b/powerline/config_files/colorschemes/pdb/default.json new file mode 100644 index 00000000..b97acf7f --- /dev/null +++ b/powerline/config_files/colorschemes/pdb/default.json @@ -0,0 +1,5 @@ +{ + "groups": { + "stack_depth": { "fg": "gray1", "bg": "gray10", "attrs": ["bold"] } + } +} diff --git a/powerline/config_files/colorschemes/pdb/solarized.json b/powerline/config_files/colorschemes/pdb/solarized.json new file mode 100644 index 00000000..2e1c787c --- /dev/null +++ b/powerline/config_files/colorschemes/pdb/solarized.json @@ -0,0 +1,5 @@ +{ + "groups": { + "stack_depth": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] } + } +} diff --git a/powerline/config_files/config.json b/powerline/config_files/config.json index 9502129a..bd2cf2bb 100644 --- a/powerline/config_files/config.json +++ b/powerline/config_files/config.json @@ -12,6 +12,10 @@ "in2": "in2" } }, + "pdb": { + "colorscheme": "default", + "theme": "default" + }, "shell": { "colorscheme": "default", "theme": "default", diff --git a/powerline/config_files/themes/pdb/default.json b/powerline/config_files/themes/pdb/default.json new file mode 100644 index 00000000..dcae1080 --- /dev/null +++ b/powerline/config_files/themes/pdb/default.json @@ -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" + } + ] + } + ] + } +} diff --git a/powerline/listers/pdb.py b/powerline/listers/pdb.py new file mode 100644 index 00000000..24e11eaf --- /dev/null +++ b/powerline/listers/pdb.py @@ -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 + ) diff --git a/powerline/pdb.py b/powerline/pdb.py new file mode 100644 index 00000000..b1e13cea --- /dev/null +++ b/powerline/pdb.py @@ -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') diff --git a/powerline/renderer.py b/powerline/renderer.py index 6d9b56a7..c03c42e8 100644 --- a/powerline/renderer.py +++ b/powerline/renderer.py @@ -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 '') diff --git a/powerline/renderers/ipython/__init__.py b/powerline/renderers/ipython/__init__.py index 3547fd2e..a84418f1 100644 --- a/powerline/renderers/ipython/__init__.py +++ b/powerline/renderers/ipython/__init__.py @@ -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): diff --git a/powerline/renderers/pdb.py b/powerline/renderers/pdb.py new file mode 100644 index 00000000..040f0e1a --- /dev/null +++ b/powerline/renderers/pdb.py @@ -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 + ` 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 diff --git a/powerline/renderers/shell/rcsh.py b/powerline/renderers/shell/rcsh.py index 4bc01412..75ccb223 100644 --- a/powerline/renderers/shell/rcsh.py +++ b/powerline/renderers/shell/rcsh.py @@ -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 diff --git a/powerline/renderers/shell/readline.py b/powerline/renderers/shell/readline.py new file mode 100644 index 00000000..a72dff05 --- /dev/null +++ b/powerline/renderers/shell/readline.py @@ -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 diff --git a/powerline/segments/pdb.py b/powerline/segments/pdb.py new file mode 100644 index 00000000..bd6a38b7 --- /dev/null +++ b/powerline/segments/pdb.py @@ -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 + ````. + ''' + name = segment_info['curframe'].f_code.co_name + if name == '': + 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'])) diff --git a/powerline/vim.py b/powerline/vim.py index b93788a8..d4f5c2d6 100644 --- a/powerline/vim.py +++ b/powerline/vim.py @@ -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() diff --git a/tests/test_segments.py b/tests/test_segments.py index 73e4bb91..08fc520b 100644 --- a/tests/test_segments.py +++ b/tests/test_segments.py @@ -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=''))}, + **kwargs + ) + self.assertEqual(ccn(), '') + + def test_current_context(self): + pl = Pl() + cc = lambda **kwargs: pdb.current_context( + pl=pl, + segment_info={'curframe': Args(f_code=Args(co_name='', 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 diff --git a/tests/test_shells/input.pdb b/tests/test_shells/input.pdb new file mode 100644 index 00000000..e9ac498c --- /dev/null +++ b/tests/test_shells/input.pdb @@ -0,0 +1,89 @@ +s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_shells/pdb-main.py b/tests/test_shells/pdb-main.py new file mode 100644 index 00000000..37af785f --- /dev/null +++ b/tests/test_shells/pdb-main.py @@ -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}) diff --git a/tests/test_shells/pdb-script.py b/tests/test_shells/pdb-script.py new file mode 100644 index 00000000..40db5e8d --- /dev/null +++ b/tests/test_shells/pdb-script.py @@ -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() diff --git a/tests/test_shells/pdb.module.ok b/tests/test_shells/pdb.module.ok new file mode 100644 index 00000000..7554dd6c --- /dev/null +++ b/tests/test_shells/pdb.module.ok @@ -0,0 +1,222 @@ + 1  pdb-script.py:6    +--Call-- +-> class Foo(object): + 2  pdb-script.py:6   pdb-script.py:6 Foo   +-> class Foo(object): + 2  pdb-script.py:6   pdb-script.py:6 Foo   +-> def __init__(self): + 2  pdb-script.py:6   pdb-script.py:7 Foo   +-> @classmethod + 2  pdb-script.py:6   pdb-script.py:13 Foo   +-> @staticmethod + 2  pdb-script.py:6   pdb-script.py:17 Foo   +-> def bra(self): + 2  pdb-script.py:6   pdb-script.py:21 Foo   +--Return-- +-> def bra(self): + 2  pdb-script.py:6   pdb-script.py:21 Foo   +-> def brah(): + 1  pdb-script.py:25    +-> f = Foo() + 1  pdb-script.py:29    +--Call-- +-> def __init__(self): + 2  pdb-script.py:29   pdb-script.py:7 __init__   +-> nop('__init__') + 2  pdb-script.py:29   pdb-script.py:8 __init__   +--Call-- +-> def nop(_): + 3  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:2 nop   +-> pass + 3  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:3 nop   +--Return-- +-> pass + 3  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:3 nop   +-> self.bar() + 2  pdb-script.py:29   pdb-script.py:9 __init__   +--Call-- +-> @classmethod + 3  pdb-script.py:29   pdb-script.py:9 __init__  pdb-script.py:13 bar   +-> nop(cls.__name__) + 3  pdb-script.py:29   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   pdb-script.py:9 __init__  pdb-script.py:15 bar   +-> self.baz() + 2  pdb-script.py:29   pdb-script.py:10 __init__   +--Call-- +-> @staticmethod + 3  pdb-script.py:29   pdb-script.py:10 __init__  pdb-script.py:17 baz   +-> nop(1) + 3  pdb-script.py:29   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   pdb-script.py:10 __init__  pdb-script.py:19 baz   +-> self.bra() + 2  pdb-script.py:29   pdb-script.py:11 __init__   +--Call-- +-> def bra(self): + 3  pdb-script.py:29   pdb-script.py:11 __init__  pdb-script.py:21 bra   +-> nop(self.__class__.__name__) + 3  pdb-script.py:29   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   pdb-script.py:11 __init__  pdb-script.py:22 bra   +--Return-- +-> self.bra() + 2  pdb-script.py:29   pdb-script.py:11 __init__   +-> Foo.bar() + 1  pdb-script.py:30    +--Call-- +-> @classmethod + 2  pdb-script.py:30   pdb-script.py:13 bar   +-> nop(cls.__name__) + 2  pdb-script.py:30   pdb-script.py:15 bar   +--Call-- +-> def nop(_): + 3  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:2 nop   +-> pass + 3  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:3 nop   +--Return-- +-> pass + 3  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:3 nop   +--Return-- +-> nop(cls.__name__) + 2  pdb-script.py:30   pdb-script.py:15 bar   +-> Foo.baz() + 1  pdb-script.py:31    +--Call-- +-> @staticmethod + 2  pdb-script.py:31   pdb-script.py:17 baz   +-> nop(1) + 2  pdb-script.py:31   pdb-script.py:19 baz   +--Call-- +-> def nop(_): + 3  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:2 nop   +-> pass + 3  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:3 nop   +--Return-- +-> pass + 3  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:3 nop   +--Return-- +-> nop(1) + 2  pdb-script.py:31   pdb-script.py:19 baz   +-> Foo.bra(f) + 1  pdb-script.py:32    +--Call-- +-> def bra(self): + 2  pdb-script.py:32   pdb-script.py:21 bra   +-> nop(self.__class__.__name__) + 2  pdb-script.py:32   pdb-script.py:22 bra   +--Call-- +-> def nop(_): + 3  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:2 nop   +-> pass + 3  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:3 nop   +--Return-- +-> pass + 3  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:3 nop   +--Return-- +-> nop(self.__class__.__name__) + 2  pdb-script.py:32   pdb-script.py:22 bra   +-> f.bar() + 1  pdb-script.py:34    +--Call-- +-> @classmethod + 2  pdb-script.py:34   pdb-script.py:13 bar   +-> nop(cls.__name__) + 2  pdb-script.py:34   pdb-script.py:15 bar   +--Call-- +-> def nop(_): + 3  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:2 nop   +-> pass + 3  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:3 nop   +--Return-- +-> pass + 3  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:3 nop   +--Return-- +-> nop(cls.__name__) + 2  pdb-script.py:34   pdb-script.py:15 bar   +-> f.baz() + 1  pdb-script.py:35    +--Call-- +-> @staticmethod + 2  pdb-script.py:35   pdb-script.py:17 baz   +-> nop(1) + 2  pdb-script.py:35   pdb-script.py:19 baz   +--Call-- +-> def nop(_): + 3  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:2 nop   +-> pass + 3  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:3 nop   +--Return-- +-> pass + 3  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:3 nop   +--Return-- +-> nop(1) + 2  pdb-script.py:35   pdb-script.py:19 baz   +-> f.bra() + 1  pdb-script.py:36    +--Call-- +-> def bra(self): + 2  pdb-script.py:36   pdb-script.py:21 bra   +-> nop(self.__class__.__name__) + 2  pdb-script.py:36   pdb-script.py:22 bra   +--Call-- +-> def nop(_): + 3  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:2 nop   +-> pass + 3  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:3 nop   +--Return-- +-> pass + 3  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:3 nop   +--Return-- +-> nop(self.__class__.__name__) + 2  pdb-script.py:36   pdb-script.py:22 bra   +-> brah() + 1  pdb-script.py:38    +--Call-- +-> def brah(): + 2  pdb-script.py:38   pdb-script.py:25 brah   +-> nop('brah') + 2  pdb-script.py:38   pdb-script.py:26 brah   +--Call-- +-> def nop(_): + 3  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:2 nop   +-> pass + 3  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:3 nop   +--Return-- +-> pass + 3  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:3 nop   +--Return-- +-> nop('brah') + 2  pdb-script.py:38   pdb-script.py:26 brah   +--Return-- +-> brah() + 1  pdb-script.py:38    +--Return-- + 0   diff --git a/tests/test_shells/pdb.subclass.ok b/tests/test_shells/pdb.subclass.ok new file mode 100644 index 00000000..d8eba5ef --- /dev/null +++ b/tests/test_shells/pdb.subclass.ok @@ -0,0 +1,217 @@ + 2  :1   pdb-script.py:6    +--Call-- +-> class Foo(object): + 3  :1   pdb-script.py:6   pdb-script.py:6 Foo   +-> class Foo(object): + 3  :1   pdb-script.py:6   pdb-script.py:6 Foo   +-> def __init__(self): + 3  :1   pdb-script.py:6   pdb-script.py:7 Foo   +-> @classmethod + 3  :1   pdb-script.py:6   pdb-script.py:13 Foo   +-> @staticmethod + 3  :1   pdb-script.py:6   pdb-script.py:17 Foo   +-> def bra(self): + 3  :1   pdb-script.py:6   pdb-script.py:21 Foo   +--Return-- +-> def bra(self): + 3  :1   pdb-script.py:6   pdb-script.py:21 Foo   +-> def brah(): + 2  :1   pdb-script.py:25    +-> f = Foo() + 2  :1   pdb-script.py:29    +--Call-- +-> def __init__(self): + 3  :1   pdb-script.py:29   pdb-script.py:7 __init__   +-> nop('__init__') + 3  :1   pdb-script.py:29   pdb-script.py:8 __init__   +--Call-- +-> def nop(_): + 4  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:2 nop   +-> pass + 4  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:3 nop   +--Return-- +-> pass + 4  pdb-script.py:29   pdb-script.py:8 __init__  pdb-script.py:3 nop   +-> self.bar() + 3  :1   pdb-script.py:29   pdb-script.py:9 __init__   +--Call-- +-> @classmethod + 4  pdb-script.py:29   pdb-script.py:9 __init__  pdb-script.py:13 bar   +-> nop(cls.__name__) + 4  pdb-script.py:29   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   pdb-script.py:9 __init__  pdb-script.py:15 bar   +-> self.baz() + 3  :1   pdb-script.py:29   pdb-script.py:10 __init__   +--Call-- +-> @staticmethod + 4  pdb-script.py:29   pdb-script.py:10 __init__  pdb-script.py:17 baz   +-> nop(1) + 4  pdb-script.py:29   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   pdb-script.py:10 __init__  pdb-script.py:19 baz   +-> self.bra() + 3  :1   pdb-script.py:29   pdb-script.py:11 __init__   +--Call-- +-> def bra(self): + 4  pdb-script.py:29   pdb-script.py:11 __init__  pdb-script.py:21 bra   +-> nop(self.__class__.__name__) + 4  pdb-script.py:29   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   pdb-script.py:11 __init__  pdb-script.py:22 bra   +--Return-- +-> self.bra() + 3  :1   pdb-script.py:29   pdb-script.py:11 __init__   +-> Foo.bar() + 2  :1   pdb-script.py:30    +--Call-- +-> @classmethod + 3  :1   pdb-script.py:30   pdb-script.py:13 bar   +-> nop(cls.__name__) + 3  :1   pdb-script.py:30   pdb-script.py:15 bar   +--Call-- +-> def nop(_): + 4  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:2 nop   +-> pass + 4  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:3 nop   +--Return-- +-> pass + 4  pdb-script.py:30   pdb-script.py:15 bar  pdb-script.py:3 nop   +--Return-- +-> nop(cls.__name__) + 3  :1   pdb-script.py:30   pdb-script.py:15 bar   +-> Foo.baz() + 2  :1   pdb-script.py:31    +--Call-- +-> @staticmethod + 3  :1   pdb-script.py:31   pdb-script.py:17 baz   +-> nop(1) + 3  :1   pdb-script.py:31   pdb-script.py:19 baz   +--Call-- +-> def nop(_): + 4  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:2 nop   +-> pass + 4  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:3 nop   +--Return-- +-> pass + 4  pdb-script.py:31   pdb-script.py:19 baz  pdb-script.py:3 nop   +--Return-- +-> nop(1) + 3  :1   pdb-script.py:31   pdb-script.py:19 baz   +-> Foo.bra(f) + 2  :1   pdb-script.py:32    +--Call-- +-> def bra(self): + 3  :1   pdb-script.py:32   pdb-script.py:21 bra   +-> nop(self.__class__.__name__) + 3  :1   pdb-script.py:32   pdb-script.py:22 bra   +--Call-- +-> def nop(_): + 4  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:2 nop   +-> pass + 4  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:3 nop   +--Return-- +-> pass + 4  pdb-script.py:32   pdb-script.py:22 bra  pdb-script.py:3 nop   +--Return-- +-> nop(self.__class__.__name__) + 3  :1   pdb-script.py:32   pdb-script.py:22 bra   +-> f.bar() + 2  :1   pdb-script.py:34    +--Call-- +-> @classmethod + 3  :1   pdb-script.py:34   pdb-script.py:13 bar   +-> nop(cls.__name__) + 3  :1   pdb-script.py:34   pdb-script.py:15 bar   +--Call-- +-> def nop(_): + 4  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:2 nop   +-> pass + 4  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:3 nop   +--Return-- +-> pass + 4  pdb-script.py:34   pdb-script.py:15 bar  pdb-script.py:3 nop   +--Return-- +-> nop(cls.__name__) + 3  :1   pdb-script.py:34   pdb-script.py:15 bar   +-> f.baz() + 2  :1   pdb-script.py:35    +--Call-- +-> @staticmethod + 3  :1   pdb-script.py:35   pdb-script.py:17 baz   +-> nop(1) + 3  :1   pdb-script.py:35   pdb-script.py:19 baz   +--Call-- +-> def nop(_): + 4  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:2 nop   +-> pass + 4  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:3 nop   +--Return-- +-> pass + 4  pdb-script.py:35   pdb-script.py:19 baz  pdb-script.py:3 nop   +--Return-- +-> nop(1) + 3  :1   pdb-script.py:35   pdb-script.py:19 baz   +-> f.bra() + 2  :1   pdb-script.py:36    +--Call-- +-> def bra(self): + 3  :1   pdb-script.py:36   pdb-script.py:21 bra   +-> nop(self.__class__.__name__) + 3  :1   pdb-script.py:36   pdb-script.py:22 bra   +--Call-- +-> def nop(_): + 4  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:2 nop   +-> pass + 4  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:3 nop   +--Return-- +-> pass + 4  pdb-script.py:36   pdb-script.py:22 bra  pdb-script.py:3 nop   +--Return-- +-> nop(self.__class__.__name__) + 3  :1   pdb-script.py:36   pdb-script.py:22 bra   +-> brah() + 2  :1   pdb-script.py:38    +--Call-- +-> def brah(): + 3  :1   pdb-script.py:38   pdb-script.py:25 brah   +-> nop('brah') + 3  :1   pdb-script.py:38   pdb-script.py:26 brah   +--Call-- +-> def nop(_): + 4  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:2 nop   +-> pass + 4  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:3 nop   +--Return-- +-> pass + 4  pdb-script.py:38   pdb-script.py:26 brah  pdb-script.py:3 nop   +--Return-- +-> nop('brah') + 3  :1   pdb-script.py:38   pdb-script.py:26 brah   diff --git a/tests/test_shells/postproc.py b/tests/test_shells/postproc.py index ff9c5748..d544bf83 100755 --- a/tests/test_shells/postproc.py +++ b/tests/test_shells/postproc.py @@ -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) diff --git a/tests/test_shells/test.sh b/tests/test_shells/test.sh index 81b5edb2..fdce0d3e 100755 --- a/tests/test_shells/test.sh +++ b/tests/test_shells/test.sh @@ -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.