Live data from Hacker News

Icecream: Never use print() to debug again in Python

github.com

141–150 of 271 posts

Re: Icecream: Never use print() to debug again in Python

#142
post #104

This looks cool and all, but why is it called Icecream? I know naming abstract stuff is hard but it feels like this lends itself to a more descriptive name. "ic()" tells me nothing about what the function does.

I think it's a (confusing) two-layer pun. When read phonetically as letter names, the name "ic" sounds like "I see". "ic" also is an initialism for "ice cream". Everyone loves ice cream, and so another low-meaning cutesy-poo pun-ishment of a name was born. I think. Pure speculation here.

My first thought was "I scream" ...

Re: Icecream: Never use print() to debug again in Python

#143
Friendly reminder the stlib includes the pprint module. pprint.pprint() will give nicely formatted output of data structures and lists.

(Not suggesting it as a replacement for this tool - but if you’re a pyhacker and don’t know about this it’s handy)

Re: Icecream: Never use print() to debug again in Python

#145
post #60

Earlier quoted context omitted.

Absolutely, I don't understand why using print() or its equivalent in other languages is looked down upon. It's quick way to narrow down the "area of search" before bringing in the big guns.

How is changing code simpler than literally clicking on the line number to set a breakpoint?

In the time it takes me to figure out how to connect a debugger to the process I've had a good half-dozen full loops of 1) add print statements 2) compile 3) run already done.

Re: Icecream: Never use print() to debug again in Python

#146
post #76

Earlier quoted context omitted.

In the docs you can look up breakpoint, it has a lot of features amongst other things you can register a custom handler. I use it in selenium tests so I can either debug on error or just print the error message and continue

Could you provide a concrete example? It's still unclear to me why one wants a custom breakpoint() handler.

This is how we use it in my testing repo:

__init__.py

    os.environ.setdefault('PYTHONBREAKPOINT', 'tests.utils.raise_or_debug')

tests.utils.raise_or_debug

    def raise_or_debug(msg=''):
        if settings.BREAKPOINT_ON_ERROR:
            extype, value, tb = sys.exc_info()
            if getattr(sys, 'last_traceback', None):
                pdb.pm()
            elif tb:
                pdb.post_mortem(tb)
            else:
                pdb.set_trace()
        elif msg:
            raise AssertionError(msg)
        else:
            pdb.set_trace()
The reason is so we can leave breakpoints in the tests, and then depending on context run the tests in a context where debug is possible, or simply raise the failure again.

Selenium can be very flaky, so this has really sped up iteration and improvements. Standard functions with retries, and smart assertions and timeouts can then be fixed and resumed in dev - and give a good message on fail (for example headless chrome runner on CI).

Re: Icecream: Never use print() to debug again in Python

#147
post #136

Earlier quoted context omitted.

This is actually really cool. I was going to say that so many people miss the point of print debugging and as a consequence forget to shorten the import line as much as possible. from icecream import ic;ic() is 28 characters import q;q() is 12 characters print() is 7 characters

Why would the amount of characters possibly matter?

I find it important because it lowers the barrier of entry to print debugging. I have found myself using less prints in Java than in Python both because of static typing and having to write the full `System.out.println`.

This is also important to me because I am very cautious of not doing a file-level import (I don't want to commit a file with the dependency). The fewer characters it takes, the easier it is for me to write it all in a single line and remove it afterward.

Re: Icecream: Never use print() to debug again in Python

#148

I am always going to use print to debug in every programming language I can until the day I die.

sometimes it's printf, sometimes it's printk, sometimes it's echo, but yes I agree.

I had an emacs macro that would help. Simplified it was:

  (defun add-printf ()
    (interactive)
    (let ((s (word-near-point)))
      (when s
        (beginning-of-line)
        (insert "printf(\"@@@ %s:%d "
                s 
                ": 0x%x\\n\", __FUNCTION__, __LINE__,"
                s
                ");\n")
        (forward-line -1)
        (indent-for-tab-command)
        (end-of-line)
        (search-backward " \\n" nil t))))

  (global-set-key [f8] 'add-printf)
I had lots of variants (crafted while recompiling) with prompts, or marked regions or lots more throwaway printf silliness

Re: Icecream: Never use print() to debug again in Python

#149

Earlier quoted context omitted.

WHAT... Why ain't anybody talking about this? Brilliant!

In this case, it would seem it took a little reinvention in order to let the wheel's discovery be known.

Not used it, but ic seems to be compatible back to python 2.7 so not really comparable. I can't use the builtin thing in my python code because the host software for my plugins is running python 3.6 embedded and only recently upgraded from 3.3 in the latest release so if I want to maintain backwards compatibility I can never use the new python builtin. I expect lots of other people are in the same position.

Re: Icecream: Never use print() to debug again in Python

#150
post #76

Earlier quoted context omitted.

Could you provide a concrete example? It's still unclear to me why one wants a custom breakpoint() handler.

This is how we use it in my testing repo: __init__.py os.environ.setdefault('PYTHONBREAKPOINT', 'tests.utils.raise_or_debug') tests.utils.raise_or_debug def raise_or_debug(msg=''): if settings.BREAKPOINT_ON_ERROR: extype, value, tb = sys.exc_info() if getattr(sys, 'last_traceback', None): pdb.pm() elif tb: pdb.post_mortem(tb) else: pdb.set_trace() elif msg: raise AssertionError(msg) else: pdb.set_trace() The reason i…

And from our own docs:

    We have manually overwritten the breakpoint handler to a custom handler that in default mode does this:
    
      - `breakpoint()` calls trigger `pdb.set_trace()` as per usual
      - `breakpoint()` calls trigger AssertionError to fail tests
    
    When `BREAKPOINT_ON_ERROR=TRUE` is turned on:
    
      - `breakpoint()` calls trigger `pdb.set_trace()` as per usual
      - `breakpoint()` call `pdb.set_trace()` so you can try to manually work out how the code is functioning
      - if you call `breakpoint()` from an `except` block it will open the debugger at the position of the exception

Usage example:

        try:
            WebDriverWait(self.driver, 10).until(
                EC.element_to_be_clickable((By.ID, 'desktop-apply')))
        except TimeoutException:
            breakpoint('Was not able to click apply button.')
Post reply on HN