Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debugging in Python: Show last N executed lines

I would love to see the last 10 lines which were executed by the python interpreter before this exception occured:

test_has_perm_in_foobar.py F
Traceback (most recent call last):
  File "/.../test_has_perm_in_foobar.py", line 50, in test_has_perm
    self.assertFalse(check_perm(request, some_object))
  File "/usr/lib/python2.7/unittest/case.py", line 416, in assertFalse
    raise self.failureException(msg)
AssertionError: True is not false

I want to see where check_perm() returned True.

I know that I could use interactive debugging to find the matching line, but I am lazy and want to find a easier way to the line where check_perm() returned the return value.

I use pyCharm, but a text based tool, would solve my need, too.

BTW: Please don't tell me how to use the debugger with step-over and step-into. I know this.

Here is some code to illustrate it.

def check_perm(request, some_object):
    if condition_1:
        return True
    if condition_2:
        return sub_check(some_object)
    if condition_3:
        return sub_check2(some_object)
    ...

There are several ways where check_perm() could return True. If True was returned because of condition_1, then I want to see something like this

+         if condition_1:
+            return True

The output I have in mind is like set -x on the shell.

Update

cgitb, pytest and other tools can show the lines before the line where the assertion failed. BUT, they only show the lines of the current python file. This question is about the lines which were executed before the assertion happens, but covering all files. In my case I want to know where the return value of check_perm() was created. The tools pytest, cgitb, ... don't show this.

What I am searching is like set -x on the shell:

help set

-x Print commands and their arguments as they are executed.

like image 835
guettli Avatar asked Dec 19 '16 11:12

guettli


People also ask

What does pdb Set_trace () do?

set_trace() function. Wherever you put this line in your code, the Python interpreter will stop and present an interactive debugger command prompt. From here, you can run any arbitrary Python code, or issue pdb commands to step through or even into the code by using next and step, respectively.

How is debugging done in Python?

Debugging in Python is facilitated by pdb module(python debugger) which comes built-in to the Python standard library. It is actually defined as the class Pdb which internally makes use of bdb(basic debugger functions) and cmd(support for line-oriented command interpreters) modules.


1 Answers

For this reason I've switched testing to pytest.

It can show local variables and traceback with different detalization level. Line where call was done is marked with >.

For example in my django project:

$ py.test --showlocals --tb=long
=============================== test session starts ===============================
platform darwin -- Python 3.5.1, pytest-3.0.3, py-1.4.31, pluggy-0.4.0
Django settings: dj_tg_bot.settings (from ini file)
rootdir: /Users/el/Projects/dj-tg-alpha-bot, inifile: tox.ini
plugins: django-3.0.0, cov-2.4.0
collected 8 items

tests/test_commands.py ....F
tests/test_logger.py .
tests/test_simple.py ..

==================================== FAILURES =====================================
__________________________ TestSimpleCommands.test_start __________________________

self = <tests.test_commands.TestSimpleCommands testMethod=test_start>

    def test_start(self,):
        """
            Test bot accept normally command /start and replies as it should.
            """
>       self._test_message_ok(self.start)

self       = <tests.test_commands.TestSimpleCommands testMethod=test_start>

tests/test_commands.py:56:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tests.test_commands.TestSimpleCommands testMethod=test_start>
action = {'in': ' /start', 'out': {'parse_mode': 'Markdown', 'reply_markup': '', 'text': 'Welcome'}}
update = <telegram.update.Update object at 0x113e16cf8>, number = 1

    def _test_message_ok(self, action, update=None, number=1):
        if not update:
            update = self.update
        with mock.patch("telegram.bot.Bot.sendMessage", callable=mock.MagicMock()) as mock_send:
            if 'in' in action:
                update.message.text = action['in']
            response = self.client.post(self.webhook_url, update.to_json(), **self.kwargs)
            #  Check response 200 OK
            self.assertEqual(response.status_code, status.HTTP_200_OK)
            #  Check
>           self.assertBotResponse(mock_send, action)

action     = {'in': ' /start', 'out': {'parse_mode': 'Markdown', 'reply_markup': '', 'text': 'Welcome'}}
mock_send  = <MagicMock name='sendMessage' id='4619939344'>
number     = 1
response   = <Response status_code=200, "application/json">
self       = <tests.test_commands.TestSimpleCommands testMethod=test_start>
update     = <telegram.update.Update object at 0x113e16cf8>

../../.pyenv/versions/3.5.1/lib/python3.5/site-packages/telegrambot/test/testcases.py:83:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <tests.test_commands.TestSimpleCommands testMethod=test_start>
mock_send = <MagicMock name='sendMessage' id='4619939344'>
command = {'in': ' /start', 'out': {'parse_mode': 'Markdown', 'reply_markup': '', 'text': 'Welcome'}}

    def assertBotResponse(self, mock_send, command):
>       args, kwargs = mock_send.call_args
E       TypeError: 'NoneType' object is not iterable

command    = {'in': ' /start', 'out': {'parse_mode': 'Markdown', 'reply_markup': '', 'text': 'Welcome'}}
mock_send  = <MagicMock name='sendMessage' id='4619939344'>
self       = <tests.test_commands.TestSimpleCommands testMethod=test_start>

../../.pyenv/versions/3.5.1/lib/python3.5/site-packages/telegrambot/test/testcases.py:61: TypeError
------------------------------ Captured stderr call -------------------------------
Handler not found for {'message': {'from': {'username': 'username_4', 'last_name': 'last_name_4', 'id': 5, 'first_name': 'first_name_4'}, 'chat': {'username': 'username_4', 'last_name': 'last_name_4', 'first_name': 'first_name_4', 'title': 'title_4', 'type': 'private', 'id': 5}, 'text': ' /start', 'message_id': 5, 'date': 1482500826}, 'update_id': 5}
======================= 1 failed, 7 passed in 2.29 seconds ========================
(.env) ✘-1 ~/Projects/dj-tg-alpha-bot [master|✚ 1…8⚑ 12]
16:47 $
like image 179
Eugene Lisitsky Avatar answered Oct 08 '22 11:10

Eugene Lisitsky