Package: ycecream
IntroductionDo you ever useprint()orlog()to debug your code? If so,  ycecream, oryfor short, will make printing debug information a lot sweeter.
And on top of that, you get some basic benchmarking functionality.InstallationInstalling ycecream with pip is easy.$ pip install ycecreamor when you want to upgrade,$ pip install ycecream --upgradeAlternatively, ycecream.py can be juist copied into you current work directory from GitHub (https://github.com/salabim/ycecream).No dependencies!Inspect variables and expressionsHave you ever printed variables or expressions to debug your program? If you've
ever typed something likeprint(add2(1000))or the more thoroughprint("add2(1000)", add2(1000)))or (for Python >= 3.8 only):print(f"{add2(1000) =}")theny()is here to help. With arguments,y()inspects itself and prints
both its own arguments and the values of those arguments.from ycecream import y

def add2(i):
    return i + 2

y(add2(1000))printsy| add2(1000): 1002Similarly,from ycecream import y
class X:
    a = 3
world = {"EN": "world", "NL": "wereld", "FR": "monde", "DE": "Welt"}

y(world, X.a)printsy| world: {"EN": "world", "NL": "wereld", "FR": "monde", "DE": "Welt"}, X.a: 3Just givey()a variable or expression and you're done. Sweet, isn't it?Inspect executionHave you ever usedprint()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 likedef add2(i):
    print("enter")
    result = i + 2
    print("exit")
    return resulttheny()helps here, too. Without arguments,y()inspects itself and
prints the calling line number and -if applicable- the file name and parent function.from ycecream import y
def add2(i):
    y()
    result = i + 2
    y()
    return result
y(add2(1000))prints something likey| #3 in add2()
y| #5 in add2()
y| add2(1000): 1002Just cally()and you're done. Isn't that sweet?Return Valuey()returns its argument(s), soy()can easily be inserted into
pre-existing code.from ycecream import y
def add2(i):
    return i + 2
b = y(add2(1000))
y(b)printsy| add2(1000): 1002
y| b: 1002Debug entry and exit of function callsWhen you applyy()as a decorator to a function or method, both the entry and exit can be tracked.
The (keyword) arguments passed will be shown and upon return, the return value.from ycecream import y
@y()
def mul(x, y):
    return x * y
    
print(mul(5, 7))printsy| called mul(5, 7)
y| returned 35 from mul(5, 7) in 0.000006 seconds
35It is possible to suppress the print-out of either the enter or the exit information with
the show_enter and show_exit parameters, like:from ycecream import y
@y(show_exit=False)
def mul(x, y):
    return x * y
    
print(mul(5, 7))printsy| called mul(5, 7)
35Note that it is possible to useyas a decorator without the parentheses, like@y
def diode(x):
    return 0 if x<0 else x, but this might not work correctly when the def/class definition spawns more than one line. So, always usey()ory(<parameters>)when used as a decorator.Benchmarking with ycecreamIf you decorate a function or method with y, you will be offered the duration between entry and exit (in seconds) as a bonus.That opens the door to simple benchmarking, like:from ycecream import y
import time

@y(show_enter=False,show_line_number=True)
def do_sort(i):
    n = 10 ** i
    x = sorted(list(range(n)))
    return f"{n:9d}"  
    
for i in range(8):
    do_sort(i)the ouput will show the effects of the population size on the sort speed:y| #5 ==> returned '        1' from do_sort(0) in 0.000027 seconds
y| #5 ==> returned '       10' from do_sort(1) in 0.000060 seconds
y| #5 ==> returned '      100' from do_sort(2) in 0.000748 seconds
y| #5 ==> returned '     1000' from do_sort(3) in 0.001897 seconds
y| #5 ==> returned '    10000' from do_sort(4) in 0.002231 seconds
y| #5 ==> returned '   100000' from do_sort(5) in 0.024014 seconds
y| #5 ==> returned '  1000000' from do_sort(6) in 0.257504 seconds
y| #5 ==> returned ' 10000000' from do_sort(7) in 1.553495 secondsIt is also possible to time any code by using y as a context manager, e.g.with y():
    time.sleep(1)wil print something likey| enter
y| exit in 1.000900 secondsYou can include parameters here as well:with y(show_context=True, show_time=True):
    time.sleep(1)will print somethink like:y| #8 @ 13:20:32.605903 ==> enter
y| #8 @ 13:20:33.609519 ==> exit in 1.003358 secondsFinally, to help with timing code, you can request the current delta withy().deltaor (re)set it  withy().delta = 0So, e.g. to time a section of code:y.delta = 0
time.sleep(1)
duration = y.delta
y(duration)might print:y| duration: 1.0001721999999997ConfigurationFor the configuration, it is important to realize thatyis an instance of theycecream._Yclass, which has
a number of configuration attributes:------------------------------------------------------
attribute               alternative     default
------------------------------------------------------
prefix                  p               "y| "
output                  o               "stderr"
serialize                               pprint.pformat
show_line_number        sln             False
show_time               st              False
show_delta              sd              False
show_enter              se              True
show_exit               sx              True
show_traceback          stb             False
sort_dicts *)           sdi             False
enabled                 e               True
line_length             ll              80
compact *)              c               False
indent                  i               1
depth                   de              1000000
wrap_indent             wi              "     "   
separator               sep             ", "
context_separator       cs              " ==> "
equals_separator        es              ": "
values_only             vo              False
value_only_for_fstrings voff            False 
return_none             rn              False
enforce_line_length     ell             False
decorator               d               False
context_manager         cm              False
delta                   dl              0
------------------------------------------------------
*) ignored under Python 2.7It is perfectly ok to set/get any of these attributes directly, likey.prefix = "==> "
print(y.prefix)But, it is also possible to apply configuration directly in the call toy:
So, it is possible to sayfrom ycecream import y
y(12, prefix="==> "), which will print==> 12It is also possible to configure y permanently with the configure method.y.configure(prefix="==> ")
y(12)will print==> 12It is arguably easier to say:y.prefix = "==> "
y(12)or eveny.p = "==> "
y(12)to print==> 12Yet another way to configure y is to get a new instance of y with y.new() and the required configuration:z = y.new(prefix="==> ")
z(12)will print==> 12Or, yet another possibility is to clone y (optionally with modified attributes):yd1 = y.clone(show_date=True)
yd2 = y.clone()
yd2.configure(show_date=True)After thisyd1andyd2will behave similarly (but they are not the same!)prefix / pfrom ycecream import y
y('world', prefix='hello -> ')printshello -> 'world'prefixcan be a function, too.import time
from ycecream import y
def unix_timestamp():
    return f"{int(time.time())} "
hello = "world"
y.configure(prefix=unix_timestamp)
y(hello)prints1613635601 hello: 'world'output / oThis will allow the output to be handled by something else than the default (output being written to stderr).Theoutputattribute can bea callable that accepts at least one parameter (the text to be printed)a string or Path object that will be used as the filenamea text file that is open for writing/appendingIn the example below,from ycecream import y
import sys
y(1, output=print)
y(2, output=sys.stdout
with open("test", "a+") as f:
    y(3, output=f)
y(4, output="")y| 1will be printed to stdouty| 2will be printed to stdouty| 3will be appended to the file testy| 4willdisappearAsoutputmay be any callable, you can even use this to automatically log anyyoutput:from ycecream import y
import logging
logging.basicConfig(level="INFO")
log = logging.getLogger("demo")
y.configure(output=log.info)
a = {1, 2, 3, 4, 5}
y(a)
a.remove(4)
y(a)will print to stderr:INFO:demo:y| a: {1, 2, 3, 4, 5}
INFO:demo:y| a: {1, 2, 3, 5}Finally, you can specify the following strings:"stderr"           to print to stderr
"stdout"           to print to stdout
"null" or ""       to completely ignore (dummy) output 
"logging.debug"    to use logging.debug
"logging.info"     to use logging.info
"logging.warning"  to use logging.warning
"logging.error"    to use logging.error
"logging.critical" to use logging.criticalE.g.from ycecream import y
import sys
y.configure(output="stdout")to print to stdout.serializeThis will allow to specify how argument values are to be
serialized to displayable strings. The default is pformat (from pprint), but this can be changed to,
for example, to handle non-standard datatypes in a custom fashion.
The serialize function should accept at least one parameter.
The function can optionally accept the keyword argumentswidthandsort_dicts,compact,indentanddepth.from ycecream import y
def add_len(obj):
    if hasattr(obj, "__len__"):
        add = f" [len={len(obj)}]"
    else:
        add = ""
    return f"{repr(obj)}{add}"

l = list(range(7))
hello = "world"
y(7, hello, l, serialize=add_len)printsy| 7, hello: 'world' [len=5], l: [0, 1, 2, 3, 4, 5, 6] [len=7]show_line_number / slnIf True, adds they()call's line number and possible the filename and parent function toy()'s output.from ycecream import y
y.configure(show_line_number=True)
def shout():
    hello="world"
    y(hello)
shout()prints something likey| #5 in shout() ==> hello: 'world'If "no parent" or "n", the parent function will not be shown.from ycecream import y
y.configure(show_line_number="n")
def shout():
    hello="world"
    y(hello)
shout()prints something likey| #5 ==> hello: 'world'Note that if you callywithout any arguments, the line number is always shown, regardless of the statusshow_line_number.See below for an explanation of the information provided.show_time / stIf True, adds the current time toy()'s output.from ycecream import y
y.configure(show_time=True)
hello="world"
y(hello)prints something likey| @ 13:01:47.588125 ==> hello: 'world'show_delta / sdIf True, adds the number of seconds since the start of the program toy()'s output.from ycecream import y
import time
y.configure(show_delta=True)
french = "bonjour le monde"
english = "hallo world"
y(english)
time.sleep(1)
y(french)prints something likey| delta=0.088 ==> english: 'hallo world'
y| delta=1.091 ==> french: 'bonjour le monde'show_enter / seWhen used as a decorator or context manager, by default, ycecream ouputs a line when the decorated the
function is called  or the context manager is entered.Withshow_enter=Falsethis line can be suppressed.show_exit / sxWhen used as a decorator or context manager, by default, ycecream ouputs a line when the decorated the
function returned or the context manager is exited.Withshow_exit=Falsethis line can be suppressed.show_traceback / stbWhen show_traceback is True, the ordinary output of y() will be followed by a printout of the
traceback, similar to an error traceback.from ycecream import y
y.show_traceback=True
def x():
    y()

x()
x()printsy| #4 in x()
    Traceback (most recent call last)
      File "c:\Users\Ruud\Dropbox (Personal)\Apps\Python Ruud\ycecream\x.py", line 6, in <module>
        x()
      File "c:\Users\Ruud\Dropbox (Personal)\Apps\Python Ruud\ycecream\x.py", line 4, in x
        y()
y| #4 in x()
    Traceback (most recent call last)
      File "c:\Users\Ruud\Dropbox (Personal)\Apps\Python Ruud\ycecream\x.py", line 7, in <module>
        x()
      File "c:\Users\Ruud\Dropbox (Personal)\Apps\Python Ruud\ycecream\x.py", line 4, in x
        y()Theshow_tracebackfunctionality is also available when y is used as a decorator or context manager.line_length / llThis attribute is used to specify the line length (for wrapping). The default is 80.
Ycecream always tries to keep all output on one line, but if it can't it will wrap:d = dict(a1=1,a2=dict(a=1,b=1,c=3),a3=list(range(10)))
y(d)
y(d, line_length=120)printsy|
    d:
        {'a1': 1,
         'a2': {'a': 1, 'b': 1, 'c': 3},
         'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
y| d: {'a1': 1, 'a2': {'a': 1, 'b': 1, 'c': 3}, 'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}compact / cThis attribute is used to specify the compact parameter forpformat(see the pprint documentation
for details).compactis False by default.a = 9 * ["0123456789"]
y(a)
y(a, compact=True)printsy|
    a:
        ['0123456789',
         '0123456789',
         '0123456789',
         '0123456789',
         '0123456789',
         '0123456789',
         '0123456789',
         '0123456789',
         '0123456789']
y|
    a:
        ['0123456789', '0123456789', '0123456789', '0123456789', '0123456789',
         '0123456789', '0123456789', '0123456789', '0123456789']Note thatcompactis ignored under Python 2.7.indent / iThis attribute is used to specify the indent parameter forpformat(see the pprint documentation
for details).indentis 1 by default.s = "01234567890012345678900123456789001234567890"
y( [s, [s]])
y( [s, [s]], indent=4)printsy|
    [s, [s]]:
        ['01234567890012345678900123456789001234567890',
         ['01234567890012345678900123456789001234567890']]
y|
    [s, [s]]:
        [   '01234567890012345678900123456789001234567890',
            ['01234567890012345678900123456789001234567890']]depth / deThis attribute is used to specify the depth parameter forpformat(see the pprint documentation
for details).depthis1000000by default.s = "01234567890012345678900123456789001234567890"
y([s,[s,[s,[s,s]]]])
y([s,[s,[s,[s,s]]]], depth=3)printsy|
    [s,[s,[s,[s,s]]]]:
        ['01234567890012345678900123456789001234567890',
         ['01234567890012345678900123456789001234567890',
          ['01234567890012345678900123456789001234567890',
           ['01234567890012345678900123456789001234567890',
            '01234567890012345678900123456789001234567890']]]]
y|
    [s,[s,[s,[s,s]]]]:
        ['01234567890012345678900123456789001234567890',
         ['01234567890012345678900123456789001234567890',
          ['01234567890012345678900123456789001234567890', [...]]]]wrap_indent / wiThis specifies the indent string if the output does not fit in the line_length (has to be wrapped).
Rather than a string, wrap_indent can be also be an integer, in which case the wrap_indent will be that amount of blanks.
The default is 4 blanks.E.g.d = dict(a1=1,a2=dict(a=1,b=1,c=3),a3=list(range(10)))
y(d, wrap_indent="  ")
y(d, wrap_indent="....")
y(d, wrap_indent=2)printsy|
  d:
    {'a1': 1,
     'a2': {'a': 1, 'b': 1, 'c': 3},
     'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
y|
....d:
........{'a1': 1,
........ 'a2': {'a': 1, 'b': 1, 'c': 3},
........ 'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
y|
  d:
    {'a1': 1,
     'a2': {'a': 1, 'b': 1, 'c': 3},
     'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}enabled / eCan be used to disable the output:from ycecream import y

y.configure(enabled=False)
s = 'the world is '
y(s + 'perfect.')
y.configure(enabled=True)
y(s + 'on fire.')printsy| s + 'on fire.': 'the world is on fire.'and nothing about a perfect world.sort_dicts / sdiBy default, ycecream does not sort dicts (printed by pprint). However, it is possible to get the
default pprint behaviour (i.e. sorting dicts) with the sorted_dicts attribute:world = {"EN": "world", "NL": "wereld", "FR": "monde", "DE": "Welt"}
y(world))
s1 = y(world, sort_dicts=False)
s2 = y(world, sort_dicts=True)printsy| world: {'EN': 'world', 'NL': 'wereld', 'FR': 'monde', 'DE': 'Welt'}
y| world: {'EN': 'world', 'NL': 'wereld', 'FR': 'monde', 'DE': 'Welt'}
y| world: {'DE': 'Welt', 'EN': 'world', 'FR': 'monde', 'NL': 'wereld'}Note thatsort_dictsis ignored under Python 2.7, i.e. dicts are always sorted.separator / sepBy default, pairs (on one line) are separated by,.
It is possible to change this with the attributeseparator:a="abcd"
b=1
c=1000
d=list("ycecream")
y(a,(b,c),d)
y(a,(b,c),d, separator=" | ")printsy| a: 'abcd', (b,c): (1, 1000), d: ['y', 'c', 'e', 'c', 'r', 'e', 'a', 'm']
y| a: 'abcd' | (b,c): (1, 1000) | d: ['y', 'c', 'e', 'c', 'r', 'e', 'a', 'm']context_separator / csBy default the line_number, time and/or delta are followed by==>.
It is possible to change this with the attributecontext_separator:a="abcd"
y(a)
y(a, show_time=True, context_separator = ' \u279c ')prints:y| @ 12:56:11.341650 ==> a: 'abcd'
y| @ 12:56:11.485567 ➜ a: 'abcd'equals_separator / esBy default name of a variable and its value are separated by:.
It is possible to change this with the attributeequals_separator:a="abcd"
y(a)
y(a, equals_separator = ' == ")prints:y| a: 'abcd'
y| a == 'abcd'values_only / voIf False (the default), both the left-hand side (if possible) and the
value will be printed. If True, the left_hand side will be suppressed:hello = "world"
y(hello, 2 * hello)
y(hello, 2 * hello, values_only=True)printsy| hello: 'world', 2 * hello = 'worldworld'
y| 'world', 'worldworld'The values=True version of y can be seen as a supercharged print/pprint.values_only_for_fstrings / voffIf False (the default), both the original f-string and the
value will be printed for f-strings.
If True, the left_hand side will be suppressed in case of an f-string:x = 12.3
y(f"{x:0.3e}")
y.values_only_for_fstrings = True
y(f"{x:0.3e}")printsy| f"{x:0.3e}": '1.230e+01'
y| '1.230e+01'Note that ifvalues_onlyis True, f-string will be suppressed, regardless ofvalues_only_for_fstrings.return_none / rnNormally,y()returns the values passed directly, which is usually fine. However, when used in a notebook
or REPL, that value will be shown, and that can be annoying. Therefore, ifreturn_noneis True,y()will
return None and thus not show anything.a = 3
print(y(a, a + 1))
y.configure(return_none=True)
print(y(a, a + 1))printsy| (3, 4)
(3, 4)
y| (3, 4)
Noneenforce_line_length / ellIf enforce_line_length is True, all output lines are explicitely truncated to the given
line_length, even those that are not truncated by pformat.delta / dlThe delta attribute can be used to (re)set the current delta, e.g.y.configure(dl=0)
print(y.delta)prints a value that slightly more than 0.decorator / dNormally, an ycecream instance can be used as to show values, as a decorator and as a
context manager.However, when used from a REPL the usage as a decorator can't be detected properly and in that case,
specifydecorator=True. E.g.>>>@y(decorator=True)
>>>def add2(x):
>>>    return x + 2
>>>print(add2(10))
y| called add2(10)
y| returned 12 from add2(10) in 0.000548 seconds
12Thedecoratorattribute is also required when usingy()as a decorator
witbfast disabling(see below).y.enabled([])
@y()
def add2(x):
    return x + 2would fail withTypeError: 'NoneType' object is not callable, buty.enabled([])
@y(decorator=True)
def add2(x):
    return x + 2will run correctly.context_manager / cmNormally, an ycecream instance can be used as to show values, as a decorator and as a
context manager.However, when used from a REPL the usage as a context manager can't be detected properly and in that case,
specifycontext_manager=True. E.g.>>>with y(context_manager=True)
>>>    pass
y| enter
y| exit in 0.008644 secondsThecontext_managerattribute is also required when usingy():as a context manager
withfast disabling(see below).y.enabled([])
with y:
    passwould fail withAttributeError: __enter__, buty.enabled([])
with y(context_manager=True):
    passwill run correctly.provided / prIf provided is False, all output for this call will be suppressed.
If provided is True, output will be generated as usual (obeying the enabled attribute).x = 1
y("should print", provided=x > 0)
y("should not print", provided=x < 0)This will printshould printReturn a string instead of sending to outputy(*args, as_str=True)is likey(*args)but the output is returned as a string instead
of written to output.from ycecream import y
hello = "world"
s = y(hello, as_str=True)
print(s, end="")printsy| hello: 'world'Note that if enabled=False, the call will return the null string ("").Disabling ycecream's outputfrom ycecream import y
yd = y.fork(show_delta=True)
y(1)
yd(2)
y.enabled = False
y(3)
yd(4)
y.enabled = True
y(5)
yd(6)
print(y.enabled)printsy| 1
y| delta=0.011826 ==> 2
y| 5
y| delta=0.044893 ==> 6
TrueOf coursey()continues to return its arguments when disabled, of course.It is also possible to suppress output with the provided attribute (see above).Speeding up disabled ycecreamWhen output is disabled, either viay.configure(enbabled=False)orycecream.enable = False,
ycecream still has to check for usage as a decorator or context manager, which can be rather time
consuming.In order to speed up a program with disabled ycecream calls, it is possible to specifyy.configure(enabled=[]), in which caseywill always just return
the given arguments. If ycecream is disabled this way, usage as a@y()decorator  or as awith y():context manager will raise a runtime error, though. The@ydecorator without parentheses will
not raise any exception, though.To useyas a decorator and still havefast disabling:y.configure(enabled=[])
@y(decorator=True):
def add2(x):
     return x + 2
x34 = add2(30)And, similarly, to useyas a context manager  combined withfast disabling:y.configure(enabled=[])
with @y(context_manager=True):
    passThe table below shows it all.-------------------------------------------------------------------------------
                         enabled=True   enabled=False                enabled=[]
-------------------------------------------------------------------------------
execution speed                normal          normal                      fast     
y()                            normal       no output                 no output
@y                             normal       no output                 no output
y(decorator=True)              normal       no output                 no output
y(context_manager=True)        normal       no output                 no output
@y()                           normal       no output                 TypeError
with y():                      normal       no output  AttributeError/TypeError
y(as_str=True)                 normal             ""                         ""
-------------------------------------------------------------------------------Using ycecream as a substitute forassertYcecream has a methodassert_that works likeassert, but can be enabled or disabled with the enabled flag.temperature = -1
y.assert_(temperature > 0)This will raise an AttributeError.Buty.enabled = False
temperature = -1
y.assert_(temperature > 0)will not.Note that with the attribute propagation method, you can in effect have a layered assert system.Interpreting the line number informationWhenshow_line_numberis True or y() is used without any parameters, the output will contain the line number like:y| #3 ==> a: 'abcd'If the line resides in another file than the main file, the filename (without the path) will be shown as well:y| #30[foo.py] ==> foo: 'Foo'And finally when used in a function or method, that function/method will be shown as well:y| #456[foo.py] in square_root ==> x: 123The parent function can be suppressed by settingshow_line_numberorslnto"n"or"no parent".Configuring at import timeIt can be useful to configure ycecream at import time. This can be done by providing aycecream.jsonfile which
can contain any attribute configuration overriding the standard settings.
E.g. if there is anycecream.jsonfile with the following contents{
    "o": "stdout",
    "show_time": true,
    "line_length": 120`
    'compact' : true
}in the same folder as the application, this program:from ycecream import y
hello = "world"
y(hello)will print to stdout (rather than stderr):y| @ 14:53:41.392190 ==> hello: 'world'At import time the sys.path will be searched for, in that order, to find anycecream.jsonfile and use that. This mean that
you can place anycecream.jsonfile in the site-packages folder whereycecreamis installed to always use
these modified settings.Please observe that json values are slightly different from their Python equivalents:-------------------------------
Python     json
-------------------------------
True       true
False      false
None       none
strings    always double quoted
-------------------------------Note that not-specified attributes will remain the default settings.For obvious reasons, it is not possible to specifyserializein an ycecream.json file.Working with multiple instances of yNormally, only they()object is used.It can be useful to have multiple instances, e.g. when some of the debugging has to be done with context information
and others requires an alternative prefix.THere are several ways to obtain a new instance of ycecream:by usingy.new()With this a new ycecream object is created with the default attributes
and possibly ycecream.json overrides.by usingy.new(ignore_json=True)With this a new ycecreamobject is created with the default attibutes. Any ycecream.json files asre ignored.by usingy.fork()With this a new ycecream object is created with the same attributes as the object it is created ('the parent') from. Note that any non set attributes are copied (propagated) from the parent.by usingy.clone(), which copies all attributes from y()With this a new ycecream object is created with the same attributes as the object it is created ('the parent') from. Note that the attributes are not propagated from the parent, in this case.withy()used as a context managerIn either case, attributes can be added to override the default ones.Examplefrom ycecream import y
y_with_line_number = y.fork(show_line_number=True)
y_with_new_prefix = y.new(prefix="==> ")
y_with_new_prefix_and_time = y_with_new_prefix.clone(show_time=True)
hello="world"
y_with_line_number(hello)
y_with_new_prefix(hello)
y_with_new_prefix_and_time(hello)
y.equals_separator = " == "  # this affects only the forked objects
y_with_line_number(hello)
y_with_new_prefix(hello)
y_with_new_prefix_and_time(hello)
with y(prefix="ycm ") as ycm:
    ycm(hello)
    y(hello)printsy| #6 ==> hello: 'world'
==> hello: 'world'
==> @ 09:55:10.883732 ==> hello: 'world'
y| #10 ==> hello == 'world'
==> hello: 'world'
==> @ 09:55:10.910717 ==> hello: 'world'
ycm enter
ycm hello == 'world'
y| hello == 'world'
ycm exit in 0.017686 secondsignore_jsonWithy.new(ignore_json=True)an instance of y without having applied any json configuration file will be returned. That can be useful when guaranteeing the same output in several setups.ExampleSuppose we have anycecream.jsonfile in the current directory with the contents{prefix="==>"}Theny_post_json = y.new()
y_ignore_json = y.new(ignore_json=True)
hello = "world"
y(hello)
y_post_json(hello)
y_ignore_json(hello)prints==>hello: 'world'
==>hello: 'world'
y| hello: 'world'Test scriptOn GitHub is a filetest_ycecream.pythat tests (and thus also demonstrates) most of the functionality
of ycecream.It is very useful to have a look at the tests to see the features (some may be not covered (yet) in this readme).Using ycecream in a REPLYcecream may be used in a REPL, but with limited functionality:all arguments are just presented as such, i.e. no left-hand side, e.g.>> hello = "world"
>>> y(hello, hello * 2)
y| 'hello', 'hellohello'
('hello', 'hellohello')line numbers are never shownuse as a decorator is only supported when you used asy(decorator=True)ory(d=1)use as a context manager is only supported when used asy(context_manager=True)ory(cm=1)Alternative toySometimes, it is not suitable to use the name y in a program, e.g. when
dealing with coordinates x, y and z.In that case, it is possible to use yc insteadfrom ycecream import ycTheycobject is aforkof y with the prefix"yc| ". That means that attributes ofyare propagated toyc, unless overridden.Of course, it is also possible to usefrom ycecream import y as yyoryy = y.new()oryy = y.new(prefix="yy| ")Alternative installationWithinstall ycecream from github.py, you can install the ycecream.py directly from GitHub to the site packages (as if it was a pip install).Withinstall ycecream.py, you can install the ycecream.py in your current directory to the site packages (as if it was a pip install).Both files can be found in the GitHub repository (https://github.com/salabim/ycecream).LimitationsIt is not possible to use ycecream:from a frozen application (e.g. packaged with PyInstaller)when the underlying source code has changed during executionImplementation detailsAlthough not important for using the package, here are some implementation details:ycecream.py contains the complete source of the asttokens and executing packages, in
order to offer the required source lookups, without any dependenciesycecream.py contains the complete source of pprint as of Python 3.8 in order to support the sort_dicts parameter, Under Python 2.7 this is ignored and the pprint module
from the standard library is used.in order to support using y() as a decorator and a context manager, ycecream caches the complete source of
any source file that uses y()AcknowledgementTheycecreampacakage is inspired by theIceCreampackage, but is a
nearly complete rewrite. Seehttps://github.com/gruns/icecreamMany thanks to the author Ansgar Grunseid / grunseid.com /grunseid@gmail.com.Differences with IceCreamThe ycecream module was originally a fork of IceCream, but has many differences:----------------------------------------------------------------------------------------
characteristic                    ycecream                 IceCream
----------------------------------------------------------------------------------------
platform                          Python 2.7, >=3.6, PyPy  Python 2.7, >=3.5, PyPy
default name                      y (or yc)                ic
dependencies                      none                     many
number of files                   1                        several
usable without installation       yes                      no
can be used as a decorator        yes                      no
can be used as a context manager  yes                      no
can show traceback                yes                      no
PEP8 (Pythonic) API               yes                      no
sorts dicts                       no by default, optional  yes
supports compact, indent and
depth parameters of pprint        yes                      no
use from a REPL                   limited functionality    no
external configuration            via json file            no
observes line_length correctly    yes                      no
benchmarking functionality        yes                      no
suppress f-strings at left hand   optional                 no
indentation                       4 blanks (overridable)   dependent on length of prefix
forking and cloning               yes                      no
test script                       pytest                   unittest
colourize                         no                       yes (can be disabled)
----------------------------------------------------------------------------------------
*) sort_dicts and compact are ignored under Python 2.7