Skip to content

Commit

Permalink
Merge pull request #9 from gregoil/feature/more_tests
Browse files Browse the repository at this point in the history
Adding tests and fixing behaviour on Python 3
  • Loading branch information
osherdp committed Jun 21, 2018
2 parents 8c17771 + 9f40b74 commit c1f3a0f
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 18 deletions.
33 changes: 22 additions & 11 deletions ipdbugger/__init__.py
Expand Up @@ -16,7 +16,7 @@
"""
from __future__ import print_function
from __future__ import absolute_import
# pylint: disable=misplaced-bare-raise,protected-access,bare-except
# pylint: disable=protected-access,bare-except
# pylint: disable=missing-docstring,too-many-locals,too-many-branches
import re
import ast
Expand All @@ -28,6 +28,7 @@

import colorama
from termcolor import colored
from future.utils import raise_
from IPython.core.debugger import Pdb

# Enable color printing on screen.
Expand All @@ -36,12 +37,19 @@

class IPDBugger(Pdb):
"""Debugger class, adds functionality to the normal pdb."""
def __init__(self, exc_info, *args, **kwargs):
Pdb.__init__(self, *args, **kwargs)
self.exc_info = exc_info

def do_raise(self, arg):
"""Raise the last exception caught."""
self.do_continue(arg)
_, exc_value, _ = sys.exc_info()

# Annotating the exception for a continual re-raise
_, exc_value, _ = self.exc_info
exc_value._ipdbugger_let_raise = True
raise

raise_(*self.exc_info)

def do_retry(self, arg):
"""Rerun the previous command."""
Expand All @@ -52,7 +60,7 @@ def do_retry(self, arg):
self.curframe.f_lineno = prev_line
break

except:
except ValueError:
prev_line -= 1

self.do_jump(prev_line)
Expand All @@ -77,8 +85,9 @@ def start_debugging():
"""
exc_type, exc_value, exc_tb = sys.exc_info()

# If the exception has been annotated to be re-raised, raise the exception
if hasattr(exc_value, '_ipdbugger_let_raise'):
raise
raise_(*sys.exc_info())

print()
for line in traceback.format_exception(exc_type, exc_value, exc_tb):
Expand All @@ -89,13 +98,14 @@ def start_debugging():

from ipdb.__main__ import wrap_sys_excepthook, def_colors
wrap_sys_excepthook()
IPDBugger(def_colors).set_trace(test_frame)
IPDBugger(exc_info=sys.exc_info(),
color_scheme=def_colors).set_trace(test_frame)


class ErrorsCatchTransformer(ast.NodeTransformer):
"""Surround each statement with a try/except block to catch errors."""
def __init__(self, ignore_exceptions=(), catch_exception=None):
if sys.version_info > (3, 0):
if sys.version_info > (3, 0): # pragma: no cover
start_debug_cmd = ast.Expr(
value=ast.Call(
ast.Name("start_debugging", ast.Load()),
Expand All @@ -104,7 +114,7 @@ def __init__(self, ignore_exceptions=(), catch_exception=None):
)
)

else:
else: # pragma: no cover
start_debug_cmd = ast.Expr(
value=ast.Call(ast.Name("start_debugging", ast.Load()),
[], [], None, None))
Expand Down Expand Up @@ -142,14 +152,14 @@ def generic_visit(self, node):
if (isinstance(node, ast.stmt) and
not isinstance(node, ast.FunctionDef)):

if sys.version_info > (3, 0):
if sys.version_info > (3, 0): # pragma: no cover
new_node = ast.Try( # pylint: disable=no-member
orelse=[],
body=[node],
finalbody=[],
handlers=self.exception_handlers)

else:
else: # pragma: no cover
new_node = ast.TryExcept( # pylint: disable=no-member
orelse=[],
body=[node],
Expand All @@ -164,7 +174,8 @@ def debug(victim, ignore_exceptions=(), catch_exception=None):
"""A decorator function to catch exceptions and enter debug mode.
Args:
victim (object): either a class or function to wrap and debug.
victim (typing.Union(type, function)): either a class or function to
wrap and debug.
ignore_exceptions (list): list of classes of exceptions not to catch.
catch_exception (type): class of exception to catch and debug.
default is None, meaning catch all exceptions.
Expand Down
5 changes: 3 additions & 2 deletions requirements.txt
@@ -1,4 +1,4 @@
astroid==1.5.3
astroid==1.6.5
attrs==17.4.0
backports.functools-lru-cache==1.4
backports.shutil-get-terminal-size==1.0.0
Expand All @@ -8,6 +8,7 @@ coverage==4.5.1
decorator==4.1.2
enum34==1.1.6
flake8==3.4.1
future==0.16.0
funcsigs==1.0.2
ipdb==0.10.3
ipython==5.5.0
Expand All @@ -28,7 +29,7 @@ py==1.5.3
pycodestyle==2.3.1
pyflakes==1.5.0
Pygments==2.2.0
pylint==1.7.2
pylint==1.9.2
pytest==3.5.0
pytest-cov==2.5.1
scandir==1.5
Expand Down
3 changes: 2 additions & 1 deletion setup.py
@@ -1,7 +1,7 @@
"""Setup file for handling packaging and distribution."""
from setuptools import setup

__version__ = "2.0.0"
__version__ = "2.0.1"

setup(
name="ipdbugger",
Expand All @@ -14,6 +14,7 @@
url="https://github.com/gregoil/ipdbugger",
keywords="ipdb debug debugger exception",
install_requires=["ipdb",
"future",
"colorama",
"termcolor"],
packages=["ipdbugger"],
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_debug.py → tests/test_debug.py
@@ -1,8 +1,8 @@
"""Unit tests for the debug decorator in ipdbugger module."""
from __future__ import absolute_import

from IPython.utils.capture import capture_output
import pytest
from IPython.utils.capture import capture_output

from ipdbugger import debug

Expand Down
74 changes: 74 additions & 0 deletions tests/test_shell.py
@@ -0,0 +1,74 @@
from __future__ import print_function

import bdb
import pytest
from IPython.utils.capture import capture_output

from ipdbugger import debug

try:
from unittest import mock
except ImportError:
import mock


@mock.patch("sys.stdin")
def test_help(stdin):
"""Test that both raise and retry actions are mentioned on help message."""
@debug
def some_func():
raise ValueError("some error")

stdin.readline.side_effect = ["help", "exit"]
with capture_output() as out, pytest.raises(bdb.BdbQuit):
some_func()

assert "raise" in out.stdout
assert "retry" in out.stdout


@mock.patch("sys.stdin")
def test_raise(stdin):
"""Test that exceptions can be raised back to the main program."""
@debug
def some_func():
raise ValueError("some error")

with pytest.raises(ValueError,
match="some error"):
stdin.readline.return_value = "raise"
some_func()


@mock.patch("sys.stdin")
def test_continue(stdin):
"""Test that program execution can continue after an error occurred."""
@debug
def some_func():
raise ValueError("some error")

stdin.readline.return_value = "continue"
some_func()


@mock.patch("sys.stdin")
def test_retry(stdin):
"""Test retrying buggy actions."""
class A:
def __init__(self):
self.count = 0

@debug
def func(self):
self.sometimes_buggy()

def sometimes_buggy(self):
if self.count <= 1:
self.count += 1
raise ValueError("some error")

stdin.readline.side_effect = ["retry", "continue"]
a = A()
a.func()

assert a.count == 2
Empty file removed tests/unit/__init__.py
Empty file.
3 changes: 0 additions & 3 deletions tox.ini
Expand Up @@ -17,6 +17,3 @@ addopts = --cov-report=html --cov=ipdbugger

[coverage:run]
branch = True

[coverage:report]
exclude_lines = if sys.version_info

0 comments on commit c1f3a0f

Please sign in to comment.