Skip to content

Commit

Permalink
Report error information if GDB/LLDB is not found
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyseek committed Dec 14, 2018
1 parent a2f0a45 commit 64bd137
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 5 deletions.
23 changes: 20 additions & 3 deletions pystack.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import functools
import codecs
import locale
import distutils.spawn

import click

Expand Down Expand Up @@ -45,7 +46,7 @@ def make_gdb_args(pid, command):
r'call (void) PyRun_SimpleString("exec(r\"\"\"%s\"\"\")")' % command,
r'call (void) PyGILState_Release((void *) $1)',
]
arguments = ['gdb', '-p', str(pid), '-batch']
arguments = [find_debugger('gdb'), '-p', str(pid), '-batch']
arguments.extend("-eval-command=%s" % s for s in statements)
return arguments

Expand All @@ -56,11 +57,23 @@ def make_lldb_args(pid, command):
r'expr (void) PyRun_SimpleString("exec(r\"\"\"%s\"\"\")")' % command,
r'expr (void) PyGILState_Release($gil)',
]
arguments = ['lldb', '-p', str(pid), '--batch']
arguments = [find_debugger('lldb'), '-p', str(pid), '--batch']
arguments.extend('--one-line=%s' % s for s in statements)
return arguments


def find_debugger(name):
debugger = distutils.spawn.find_executable(name)
if not debugger:
raise DebuggerNotFound(
'Could not find "%s" in your PATH environment variable' % name)
return debugger


class DebuggerNotFound(Exception):
pass


def print_stack(pid, include_greenlet=False, debugger=None, verbose=False):
"""Executes a file in a running Python process."""
# TextIOWrapper of Python 3 is so strange.
Expand Down Expand Up @@ -120,7 +133,11 @@ def cli_main(pid, include_greenlet, debugger, verbose):
$ pystack <pid>
'''
return print_stack(pid, include_greenlet, debugger, verbose)
try:
print_stack(pid, include_greenlet, debugger, verbose)
except DebuggerNotFound as e:
click.echo('DebuggerNotFound: %s' % e.args[0], err=True)
click.get_current_context().exit(1)


def tolerate_missing_locale():
Expand Down
22 changes: 20 additions & 2 deletions test_pystack.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
import platform
import time

from pytest import fixture, mark, param
from pytest import fixture, mark, param, raises
from distutils.spawn import find_executable
from click.testing import CliRunner

from pystack import cli_main, tolerate_missing_locale
from pystack import (
cli_main, tolerate_missing_locale, find_debugger, DebuggerNotFound)


skipif_non_gdb = mark.skipif(
Expand Down Expand Up @@ -43,6 +44,15 @@ def cli():
return CliRunner()


def test_find_debugger():
assert find_debugger('sh') == '/bin/sh'
with raises(DebuggerNotFound) as error:
find_debugger('shhhhhhhhhhhhhhhhhhhhhhhhh')
assert error.value.args[0] == (
'Could not find "shhhhhhhhhhhhhhhhhhhhhhhhh" in your'
' PATH environment variable')


@mark.parametrize(('process', 'debugger'), [
param(STATEMENTS['sleep'], 'gdb', marks=[skipif_non_gdb, skipif_darwin]),
param(STATEMENTS['sleep'], 'lldb', marks=skipif_non_lldb),
Expand All @@ -52,3 +62,11 @@ def test_smoke(cli, process, debugger):
assert not result.exception
assert result.exit_code == 0
assert ' File "<string>", line 1, in <module>\n' in result.output


@mark.parametrize('process', [STATEMENTS['sleep']], indirect=['process'])
def test_smoke_debugger_not_found(cli, mocker, process):
mocker.patch('pystack.find_debugger', side_effect=DebuggerNotFound('oops'))
result = cli.invoke(cli_main, [str(process.pid)])
assert result.exit_code == 1
assert 'DebuggerNotFound: oops' in result.output
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ deps =
pytest
pytest-cov
pytest-pep8
pytest-mock
commands =
py.test --cov=pystack {posargs}

0 comments on commit 64bd137

Please sign in to comment.