Skip to content

Commit

Permalink
Merge pull request #6 from gregoil/feature/more_tests_and_coverage
Browse files Browse the repository at this point in the history
added more tests and coverage process through coveralls
  • Loading branch information
osherdp authored Apr 21, 2018
2 parents 4ff8bc4 + a33bc3b commit 8c17771
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 41 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,4 @@ ENV/

.idea
/.project
.pytest_cache
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
language: python
python:
- '3.6'
install: pip install tox

install: pip install tox coveralls
script: tox
after_success: coveralls

deploy:
provider: pypi
on:
Expand Down
9 changes: 6 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
ipdbugger
---------
.. image:: https://travis-ci.org/gregoil/ipdbugger.svg?branch=master
:target: https://travis-ci.org/gregoil/ipdbugger

.. image:: https://img.shields.io/pypi/v/ipdbugger.svg
:alt: PyPI
:target: https://pypi.python.org/pypi/ipdbugger/
Expand All @@ -11,6 +8,12 @@ ipdbugger
:alt: Python versions
:target: https://pypi.python.org/pypi/ipdbugger/

.. image:: https://travis-ci.org/gregoil/ipdbugger.svg?branch=master
:target: https://travis-ci.org/gregoil/ipdbugger

.. image:: https://coveralls.io/repos/github/gregoil/ipdbugger/badge.svg?branch=master
:target: https://coveralls.io/github/gregoil/ipdbugger

``ipdbugger`` is a code debugging tool based on ``ipdb``.

Use the ``debug`` decorator on functions or classes to debug them.
Expand Down
19 changes: 6 additions & 13 deletions ipdbugger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@


class IPDBugger(Pdb):
"""Deubbger class, adds functionality to the normal pdb."""
"""Debugger class, adds functionality to the normal pdb."""
def do_raise(self, arg):
"""Raise the last exception caught."""
self.do_continue(arg)
Expand Down Expand Up @@ -93,15 +93,8 @@ def start_debugging():


class ErrorsCatchTransformer(ast.NodeTransformer):
"""Surround each statement with a try/except block to catch errors.
Attributes:
IGNORED_EXCEPTION (str): name of the base class of the exceptions
to catch, or None to catch all.
"""
"""Surround each statement with a try/except block to catch errors."""
def __init__(self, ignore_exceptions=(), catch_exception=None):
raise_cmd = ast.Raise()

if sys.version_info > (3, 0):
start_debug_cmd = ast.Expr(
value=ast.Call(
Expand Down Expand Up @@ -133,7 +126,7 @@ def __init__(self, ignore_exceptions=(), catch_exception=None):
0,
ast.ExceptHandler(type=ignore_exception_node,
name=None,
body=[raise_cmd]))
body=[ast.Raise()]))

def generic_visit(self, node):
"""Surround node statement with a try/except block to catch errors.
Expand Down Expand Up @@ -283,6 +276,6 @@ def wrapper(*args, **kw):
return victim

else:
raise RuntimeError("Debugger can only wrap functions and classes")

return victim
raise TypeError(
"Debugger can only wrap functions and classes. "
"Got object {!r} of type {}".format(victim, type(victim).__name__))
10 changes: 8 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
-e .
astroid==1.5.3
attrs==17.4.0
backports.functools-lru-cache==1.4
backports.shutil-get-terminal-size==1.0.0
colorama==0.3.9
configparser==3.5.0
coverage==4.5.1
decorator==4.1.2
enum34==1.1.6
flake8==3.4.1
funcsigs==1.0.2
ipdb==0.10.3
ipython==5.5.0
ipython-genutils==0.2.0
isort==4.2.15
lazy-object-proxy==1.3.1
mccabe==0.6.1
mock==2.0.0
more-itertools==4.1.0
pathlib2==2.3.0
pbr==4.0.2
pexpect==4.2.1
pickleshare==0.7.4
pluggy==0.5.2
prompt-toolkit==1.0.15
ptyprocess==0.5.2
py==1.4.34
py==1.5.3
pycodestyle==2.3.1
pyflakes==1.5.0
Pygments==2.2.0
pylint==1.7.2
pytest==3.5.0
pytest-cov==2.5.1
scandir==1.5
simplegeneric==0.8.1
singledispatch==3.4.0.3
Expand Down
135 changes: 115 additions & 20 deletions tests/unit/test_debug.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,138 @@
"""Unit tests for the debug decorator in ipdbugger module."""
from __future__ import absolute_import
import sys
from unittest import TestCase, main

from IPython.utils.capture import capture_output
import pytest

from ipdbugger import debug


try:
from unittest.mock import patch

except ImportError:
from mock import patch


class DebugCatchesExpcetionsCase(TestCase):
"""Tests that an exception is caught iff one is raised."""
def test_debugging_raising_function():
"""Test debugging a raising function."""
@debug
def should_raise():
raise Exception()

with capture_output(), patch('bdb.Bdb.set_trace') as set_trace:
should_raise()
assert set_trace.called


def test_debugging_raising_method():
"""Test debugging a raising bounded-method."""
class A(object):
def should_raise(self):
raise Exception()

a = A()
a.should_raise = debug(a.should_raise)

with capture_output(), patch('bdb.Bdb.set_trace') as set_trace:
a.should_raise()
assert set_trace.called


def test_debugging_function_twice():
"""Test applying `debug` on a function more than once can be done."""
@debug
@debug
def shouldnt_raise(self):
def should_raise():
raise Exception()

with capture_output(), patch('bdb.Bdb.set_trace') as set_trace:
should_raise()
assert set_trace.called_once


def test_debugging_non_raising_function():
"""Test debugging on a non-raising function."""
@debug
def non_raising_function():
pass

with capture_output(), patch('bdb.Bdb.set_trace') as set_trace:
non_raising_function()
assert not set_trace.called


def test_debugging_class():
"""Test debugging a class with two methods."""
@debug
def should_raise(self):
raise Exception("Something bad happened")
class DebuggedClass(object):
def first_method(self):
raise Exception()

def second_method(self):
raise Exception()

debugged_object = DebuggedClass()

with capture_output(), patch('bdb.Bdb.set_trace') as set_trace:
debugged_object.first_method()
assert set_trace.called

with capture_output(), patch('bdb.Bdb.set_trace') as set_trace:
debugged_object.second_method()
assert set_trace.called


def test_debugging_non_compatible_type():
"""Test raising an indicative error when trying to debug a bad type."""
with pytest.raises(TypeError,
match="Debugger can only wrap functions and classes. "
"Got object 1 of type int"):
debug(1)


def test_debugging_when_source_code_is_missing():
"""Test debugging code that its source code is not available.
Note:
In this kind of code we cannot stop at an error, so we fall-back to
simply running this code without interference.
"""
exec("def function(): 1 / 0", locals(), globals())
func = debug(globals()["function"])

with pytest.raises(ArithmeticError):
func()


def test_ignoring_exceptions():
"""Test ignoring specific exceptions that should be raised."""
def func():
raise ValueError()

func = debug(func, ignore_exceptions=[ValueError])

with pytest.raises(ValueError):
func()


def test_targeting_specific_exception():
"""Test targeting specific exception that we should stop at it."""
def func():
assert False

func = debug(func, catch_exception=AssertionError)

with capture_output(), patch('bdb.Bdb.set_trace') as set_trace:
func()
assert set_trace.called

@patch('bdb.Bdb.set_trace')
def test_should_raise(self, set_trace):
with capture_output():
self.should_raise()
assert set_trace.called

@patch('bdb.Bdb.set_trace')
def test_shouldnt_raise(self, set_trace):
with capture_output():
self.shouldnt_raise()
assert not set_trace.called
def test_non_targeted_exceptions():
"""Test raising exceptions that don't match the targeted exception."""
def func():
raise ValueError()

func = debug(func, catch_exception=AssertionError)

if __name__ == '__main__':
main()
with pytest.raises(ValueError):
func()
13 changes: 11 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ envlist = py27,py36

[testenv]


deps =
-r{toxinidir}/requirements.txt

commands =
flake8 setup.py ipdbugger
pylint setup.py ipdbugger
python tests/unit/test_debug.py
pytest

[pytest]
testpaths = tests/
addopts = --cov-report=html --cov=ipdbugger

[coverage:run]
branch = True

[coverage:report]
exclude_lines = if sys.version_info

0 comments on commit 8c17771

Please sign in to comment.