File: README.md
IceCream β Never use print() to debug again
Do you ever use print() or log() to debug your code? Of course you
do. IceCream, or ic for short, makes print debugging a little sweeter.
ic() is like print(), but better:
- It prints both variables and expressions along with their values.
- It's 60% faster to type.
- Data structures are formatted and pretty printed.
- Output is syntax highlighted.
- It optionally includes program context: filename, line number, and
parent function.
IceCream is well tested, permissively licensed, and supports Python 3 and PyPy3.
IceCream is maintained by Jakeroid (Ivan Karabadzhak), with support from the confidential computing folks at π₯· Confidential AI.
Inspect Variables
Have you ever printed variables or expressions to debug your program? If
you've ever typed something like
print(foo('123'))or the more thorough
print("foo('123')", foo('123'))then ic() will put a smile on your face. With arguments, ic()
inspects itself and prints both its own arguments and the values of
those arguments.
from icecream import ic
def foo(i):
return i + 333
ic(foo(123))Prints
ic| foo(123): 456Similarly,
d = {'key': {1: 'one'}}
ic(d['key'][1])
class klass():
attr = 'yep'
ic(klass.attr)Prints
ic| d['key'][1]: 'one'
ic| klass.attr: 'yep'Just give ic() a variable or expression and you're done. Easy.
Inspect Execution
Have you ever used print() to determine which parts of your program are
executed, and in which order they're executed? For example, if you've ever added
print statements to debug code like
def foo():
print(0)
first()
if expression:
print(1)
second()
else:
print(2)
third()then ic() helps here, too. Without arguments, ic() inspects itself and
prints the calling filename, line number, and parent function.
from icecream import ic
def foo():
ic()
first()
if expression:
ic()
second()
else:
ic()
third()Prints
ic| example.py:4 in foo()
ic| example.py:11 in foo()Just call ic() and you're done. Simple.
Return Value
ic() returns its argument(s), so ic() can easily be inserted into
pre-existing code.
>>> a = 6
>>> def half(i):
>>> return i / 2
>>> b = half(ic(a))
ic| a: 6
>>> ic(b)
ic| b: 3Miscellaneous
ic.format(*args) is like ic() but the output is returned as a string instead
of written to stderr.
>>> from icecream import ic
>>> s = 'sup'
>>> out = ic.format(s)
>>> print(out)
ic| s: 'sup'Additionally, ic()'s output can be entirely disabled, and later re-enabled, withic.disable() and ic.enable() respectively.
from icecream import ic
ic(1)
ic.disable()
ic(2)
ic.enable()
ic(3)Prints
ic| 1: 1
ic| 3: 3ic() continues to return its arguments when disabled, of course; no existing
code with ic() breaks.
Import Tricks
To make ic() available in every file without needing to be imported in
every file, you can install() it. For example, in a root A.py:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from icecream import install
install()
from B import foo
foo()and then in B.py, which is imported by A.py, just call ic():
# -*- coding: utf-8 -*-
def foo():
x = 3
ic(x)install() adds ic() to the
builtins module,
which is shared amongst all files imported by the interpreter.
Similarly, ic() can later be uninstall()ed, too.
ic() can also be imported in a manner that fails gracefully if
IceCream isn't installed, like in production environments (i.e. not
development). To that end, this fallback import snippet may prove
useful:
try:
from icecream import ic
except ImportError: # Graceful fallback if IceCream isn't installed.
ic = lambda *a: None if not a else (a[0] if len(a) == 1 else a) # noqaConfiguration
ic.configureOutput(prefix, outputFunction, argToStringFunction, includeContext, contextAbsPath) controls ic()'s output.
prefix, if provided, adopts a custom output prefix. prefix can be a
string, like
>>> from icecream import ic
>>> ic.configureOutput(prefix='hello -> ')
>>> ic('world')
hello -> 'world'or a function.
>>> import time
>>> from icecream import ic
>>>
>>> def unixTimestamp():
>>> return '%i |> ' % int(time.time())
>>>
>>> ic.configureOutput(prefix=unixTimestamp)
>>> ic('world')
1519185860 |> 'world': 'world'prefix's default value is ic| .
outputFunction, if provided, is called once for every ic() call withic()'s output, as a string, instead of that string being written to
stderr (the default).
>>> import logging
>>> from icecream import ic
>>>
>>> def warn(s):
>>> logging.warning("%s", s)
>>>
>>> ic.configureOutput(outputFunction=warn)
>>> ic('eep')
WARNING:root:ic| 'eep': 'eep'argToStringFunction, if provided, is called with argument values to be
serialized to displayable strings. The default is PrettyPrint's
pprint.pformat(),
but this can be changed to, for example, handle non-standard datatypes
in a custom fashion.
>>> from icecream import ic
>>>
>>> def toString(obj):
>>> if isinstance(obj, str):
>>> return '[!string %r with length %i!]' % (obj, len(obj))
>>> return repr(obj)
>>>
>>> ic.configureOutput(argToStringFunction=toString)
>>> ic(7, 'hello')
ic| 7: 7, 'hello': [!string 'hello' with length 5!]The default argToStringFunction is icecream.argumentToString, and
has methods to register and unregister functions to be dispatched
for specific classes using functools.singledispatch. It also has aregistry property to view registered functions.
>>> from icecream import ic, argumentToString
>>> import numpy as np
>>>
>>> # Register a function to summarize numpy array
>>> @argumentToString.register(np.ndarray)
>>> def _(obj):
>>> return f"ndarray, shape={obj.shape}, dtype={obj.dtype}"
>>>
>>> x = np.zeros((1, 2))
>>> ic(x)
ic| x: ndarray, shape=(1, 2), dtype=float64
>>>
>>> # View registered functions
>>> argumentToString.registry
mappingproxy({object: <function icecream.icecream.argumentToString(obj)>,
numpy.ndarray: <function __main__._(obj)>})
>>>
>>> # Unregister a function and fallback to the default behavior
>>> argumentToString.unregister(np.ndarray)
>>> ic(x)
ic| x: array([[0., 0.]])includeContext, if provided and True, adds the ic() call's filename,
line number, and parent function to ic()'s output.
>>> from icecream import ic
>>> ic.configureOutput(includeContext=True)
>>>
>>> def foo():
>>> i = 3
>>> ic(i)
>>> foo()
ic| example.py:12 in foo()- i: 3includeContext is False by default.
contextAbsPath, if provided and True, outputs absolute filepaths, like/path/to/foo.py, over just filenames, like foo.py, when ic() is
called with includeContext == True. This is useful when debugging
multiple files that share the same filename(s). Moreover, some editors,
like VSCode, turn absolute filepaths into clickable links that open the
file where ic() was called.
>>> from icecream import ic
>>> ic.configureOutput(includeContext=True, contextAbsPath=True)
>>>
>>> i = 3
>>>
>>> def foo():
>>> ic(i)
>>> foo()
ic| /absolute/path/to/example.py:12 in foo()- i: 3
>>>
>>> ic.configureOutput(includeContext=True, contextAbsPath=False)
>>>
>>> def foo():
>>> ic(i)
>>> foo()
ic| example.py:18 in foo()- i: 3contextAbsPath is False by default.
If you want to use icecream with multiple log levels, like with Pythonβslogging module, you can use ic.format() to integrate icecreamβs
debugging with your logger:
import logging
from icecream import ic
foo = 'bar'
logging.debug(ic.format(foo))β This is a bit clunky. Would you prefer built-in log level support in
icecream? If so, please share your thoughts in
issue.
Installation
Installing IceCream with pip is easy.
$ pip install icecreamRelated Python libraries
ic() uses executing
by @alexmojaki to reliably locateic() calls in Python source. It's magic.
IceCream in Other Languages
Delicious IceCream should be enjoyed in every language.
- Dart: icecream
- Rust: icecream-rs
- Node.js: node-icecream
- C++: IceCream-Cpp
- C99: icecream-c
- PHP: icecream-php
- Go: icecream-go
- Ruby: Ricecream
- Java: icecream-java
- R: icecream
- Lua: icecream-lua
- Clojure(Script): icecream-cljc
- Bash: IceCream-Bash
- SystemVerilog: icecream_sv
- GameMaker Language: GMIceCream
If you'd like a similar ic() function in your favorite language, please open a
pull request! IceCream's goal is to sweeten print debugging with a handy-dandyic() function in every language.
File: changelog.txt
================================================================================ v2.2.0
Added: noColor option for configureOutput, which disables
colored output. It is set to False by default.
================================================================================ v2.1.11
Improved: Fixes Japanese character encoding issues.
Big thanks to the community! This release was made possible by the people
who contributed to the library.
================================================================================ v2.1.10
Improved: This change excludes the test folder from wheels.
Big thanks to the community! This release was made possible by the people
who contributed to the library.
================================================================================ v2.1.9
Removed: Support for Python 3.8.
Fixed: Issues #229 and #60, which means improved lists output.
Big thanks to the community! This release was made possible by the people
who contributed to the library.
================================================================================ v2.1.8
Added: You can pass a pre-configured ic instance to builtins.
Added: You can configure IceCream to output to either stdout or stderr.
Big thanks to the community! This release was made possible by the people
who contributed to the library.
================================================================================ v2.1.7
Added: Configurable line wrap length.
Improved: The package no longer includes tests in the production installation.
================================================================================ v2.1.6
Fixed: Pretty-printing of SymPy (and similar) objects.
Previously, calling ic() on structures containing SymPy objects could raise
a TypeError because pprint.pformat(sort_dicts=True) attempted to sort
unorderable keys. IceCream now keeps sort_dicts=True on the fast path and
falls back to sort_dicts=False when pprint raises, ensuring robust output
without crashes.
================================================================================ v2.1.5
Changed: Improved printing for variables of type str.
Fixed issues that affected the output of multiline strings and strings
containing special characters such as escaped newlines and tabs.
Strings are now printed exactly as they are, faithfully representing their
actual value.
================================================================================ v2.1.4
Changed: Drop support for all Python versions prior to Python 3.8, which
are now long past EOL. Notably: Python 2 is no longer supported.
Changed: Update the 'executing' dependency to >= v2.1.0 to improve
source code analysis and support Python 3.13.
================================================================================ v2.1.3
Added: The contextAbsPath= parameter to ic.configureOutput() which, when
True, outputs absolute paths, like /path/to/foo.py, instead of just
filenames, like foo.py. See https://github.com/gruns/icecream/pull/122.
Huge thank you to @HelinXu!
Changed: Raise TypeError if no arguments are provided to
ic.configureOutput().
================================================================================ v2.1.2
Added: Ability to register and unregister singledispatch argumentToString
functions. See https://github.com/gruns/icecream/pull/115. Huge thank you
to @atusy!
================================================================================ v2.1.1
Added: Support for Python 3.9.
Changed: Use timestamps in the local timezone instead of less helpful
UTC timestamps.
================================================================================ v2.1.0
Added: install() and uninstall() functions that add or remove ic() from
the builtins module.
Changed: Switch to ast.literal_eval() to determine if an argument and
value are the same, and thus only the value should be output. Huge
thank you to Ed Cardinal and Alex Hall.
================================================================================ v2.0.0
Added: Support for Python 3.8.
Removed: Support for Python 3.4.
Changed: Switched core AST parsing engine to Alex Hall's executing
(https://github.com/alexmojaki/executing). Huge thank you to Alex Hall.
Changed: Whitespace in arguments is no longer collapsed. Indentation in
multiline arguments is now preserved.
================================================================================ v1.5.0
Fixed: Support multiline container arguments. e.g.
ic([a,
b])
Fixed: Include LICENSE.txt in source distributions.
Changed: Collapse argument whitespace, e.g. ic([ a, b ]) -> ic| [a, b].
================================================================================ v1.4.0
Added: Colorize output with pygments.
Added: Test Python style with pycodestyle.
Fixed: Parse and print tuple arguments correctly, e.g. ic((a, b)).
Fixed: Fail gracefully when the underlying source code changes during execution.
Changed: Print values (e.g. 1, 'foo', etc) by themselves, nonredundantly. For
example, ic(3) now prints 'ic| 3' instead of 'ic| 3: 3'.
================================================================================ v1.3.1
Removed: Support for Python 3.3, which reached EOL on 2017-09-29.
Fixed: ic() invocations that fail to find or access source code (e.g. eval(),
exec(), python -i, etc) now print an error message instead of throwing an
IOError (Python 2) or OSError (Python 3).
================================================================================ v1.3
First release.
This changelog wasn't maintained prior to v1.3.
File: LICENSE.txt
Copyright 2018 Ansgar Grunseid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
File: .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
File: .github/workflows/ci.yml
name: CI
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- python-version: '3.8'
toxenv: py38
- python-version: '3.9'
toxenv: py39
- python-version: '3.10'
toxenv: py310
- python-version: '3.11'
toxenv: py311
- python-version: '3.12'
toxenv: py312
- python-version: '3.13'
toxenv: py313
- python-version: 'pypy-3.10'
toxenv: pypy3
- python-version: '3.9'
toxenv: mypy
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Install tox
run: pip install tox
- name: Tox
run: tox
env:
TOXENV: ${{ matrix.toxenv }}