{"id":27195585,"url":"https://github.com/salabim/ycecream","last_synced_at":"2025-04-09T19:47:08.219Z","repository":{"id":52641376,"uuid":"339435834","full_name":"salabim/ycecream","owner":"salabim","description":"Sweeter debugging and benchmarking Python programs.","archived":false,"fork":false,"pushed_at":"2024-11-07T10:15:49.000Z","size":1169,"stargazers_count":55,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-11-29T10:15:25.806Z","etag":null,"topics":["benchmarking","debugging","python","timing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salabim.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-16T15:05:20.000Z","updated_at":"2024-11-07T10:15:52.000Z","dependencies_parsed_at":"2024-10-19T07:24:54.821Z","dependency_job_id":null,"html_url":"https://github.com/salabim/ycecream","commit_stats":{"total_commits":180,"total_committers":1,"mean_commits":180.0,"dds":0.0,"last_synced_commit":"bfbea6d67da61f5f0ee0fefcb3b6a8154bad80ec"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salabim%2Fycecream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salabim%2Fycecream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salabim%2Fycecream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salabim%2Fycecream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salabim","download_url":"https://codeload.github.com/salabim/ycecream/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248102694,"owners_count":21048231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["benchmarking","debugging","python","timing"],"created_at":"2025-04-09T19:47:05.678Z","updated_at":"2025-04-09T19:47:08.211Z","avatar_url":"https://github.com/salabim.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"This package is not maintained anymore.\n\nIt is now called (with slightly different functionality) **peek** and can be found here:\n\nhttps://pypi.org/project/peek-python/\n\nhttps://github.com/salabim/peek\n\nhttps://salabim.org/peek/\n\n\u003cimg src=\"https://www.salabim.org/peek/peek_logo1.png\"\u003e \n\n\n\n------\n\n\n\n# \u003cimg src=\"https://www.salabim.org/ycecream/ycecream_logo.png\"\u003e\n\n# Introduction\n\nDo you ever use `print()` or `log()` to debug your code? If so,  ycecream, or `y` for short, will make printing debug information a lot sweeter.\nAnd on top of that, you get some basic benchmarking functionality.\n\n# Table of contents\n\n* [Installation](#installation)\n\n* [Inspect variables and expressions](#inspect-variables-and-expressions)\n\n* [Inspect execution](#inspect-execution)\n\n* [Return value](#return-value)\n\n* [Debug entry and exit of function calls](#debug-entry-and-exit-of-function-calls)\n\n* [Benchmarking with ycecream](#benchmarking-with-ycecream)\n\n* [Configuration](#configuration)\n\n* [Return a string instead of sending to output](#return-a-string-instead-of-sending-to-output)\n\n* [Disabling ycecream's output](#disabling-ycecreams-output)\n\n* [Speeding up disabled ycecream](#speeding-up-disabled-ycecream)\n\n* [Using ycecream as a substitute for `assert`](#using-ycecream-as-a-substitute-for-assert)\n\n* [Interpreting the line number information](#interpreting-the-line-number-information)\n\n* [Configuring at import time](#configuring-at-import-time)\n\n* [Working with multiple instances of y](#working-with-multiple-instances-of-y)\n\n* [Test script](#test-script)\n\n* [Using ycecream in a REPL](#using-ycecream-in-a-repl)\n\n* [Alternative to `y`](#alternative-to-y)\n\n* [Alternative installation](#alternative-installation)\n\n* [Limitations](#limitations)\n\n* [Implementation details](#implementation-details)\n\n* [Acknowledgement](#acknowledgement)\n\n* [Differences with IceCream](#differences-with-icecream)\n\n\n# Installation\n\nInstalling ycecream with pip is easy.\n```\n$ pip install ycecream\n```\nor when you want to upgrade,\n```\n$ pip install ycecream --upgrade\n```\n\nAlternatively, ycecream.py can be juist copied into you current work directory from GitHub (https://github.com/salabim/ycecream).\n\nNo dependencies!\n\n\n# Inspect variables and expressions\n\nHave you ever printed variables or expressions to debug your program? If you've\never typed something like\n\n```\nprint(add2(1000))\n```\n\nor the more thorough\n\n```\nprint(\"add2(1000)\", add2(1000)))\n```\nor (for Python \u003e= 3.8 only):\n```\nprint(f\"{add2(1000) =}\")\n```\n\nthen `y()` is here to help. With arguments, `y()` inspects itself and prints\nboth its own arguments and the values of those arguments.\n\n```\nfrom ycecream import y\n\ndef add2(i):\n    return i + 2\n\ny(add2(1000))\n```\n\nprints\n```\ny| add2(1000): 1002\n```\n\nSimilarly,\n\n```\nfrom ycecream import y\nclass X:\n    a = 3\nworld = {\"EN\": \"world\", \"NL\": \"wereld\", \"FR\": \"monde\", \"DE\": \"Welt\"}\n\ny(world, X.a)\n```\n\nprints\n```\ny| world: {\"EN\": \"world\", \"NL\": \"wereld\", \"FR\": \"monde\", \"DE\": \"Welt\"}, X.a: 3\n```\nJust give `y()` a variable or expression and you're done. Sweet, isn't it?\n\n\n# Inspect execution\n\nHave you ever used `print()` to determine which parts of your program are\nexecuted, and in which order they're executed? For example, if you've ever added\nprint statements to debug code like\n\n```\ndef add2(i):\n    print(\"enter\")\n    result = i + 2\n    print(\"exit\")\n    return result\n```\nthen `y()` helps here, too. Without arguments, `y()` inspects itself and\nprints the calling line number and -if applicable- the file name and parent function.\n\n```\nfrom ycecream import y\ndef add2(i):\n    y()\n    result = i + 2\n    y()\n    return result\ny(add2(1000))\n```\n\nprints something like\n```\ny| #3 in add2()\ny| #5 in add2()\ny| add2(1000): 1002\n```\nJust call `y()` and you're done. Isn't that sweet?\n\n\n# Return Value\n\n`y()` returns its argument(s), so `y()` can easily be inserted into\npre-existing code.\n\n```\nfrom ycecream import y\ndef add2(i):\n    return i + 2\nb = y(add2(1000))\ny(b)\n```\nprints\n```\ny| add2(1000): 1002\ny| b: 1002\n```\n# Debug entry and exit of function calls\n\nWhen you apply `y()` as a decorator to a function or method, both the entry and exit can be tracked.\nThe (keyword) arguments passed will be shown and upon return, the return value.\n\n```\nfrom ycecream import y\n@y()\ndef mul(x, y):\n    return x * y\n    \nprint(mul(5, 7))\n```\nprints\n```\ny| called mul(5, 7)\ny| returned 35 from mul(5, 7) in 0.000006 seconds\n35\n```\nIt is possible to suppress the print-out of either the enter or the exit information with\nthe show_enter and show_exit parameters, like:\n\n```\nfrom ycecream import y\n@y(show_exit=False)\ndef mul(x, y):\n    return x * y\n    \nprint(mul(5, 7))\n```\nprints\n```\ny| called mul(5, 7)\n35\n```\nNote that it is possible to use `y` as a decorator without the parentheses, like\n```\n@y\ndef diode(x):\n    return 0 if x\u003c0 else x\n```\n, but this might not work correctly when the def/class definition spawns more than one line. So, always use `y()` or\n`y(\u003cparameters\u003e)` when used as a decorator.  \n\n# Benchmarking with ycecream\n\nIf you decorate a function or method with y, you will be offered the duration between entry and exit (in seconds) as a bonus.\n\nThat opens the door to simple benchmarking, like:\n```\nfrom ycecream import y\nimport time\n\n@y(show_enter=False,show_line_number=True)\ndef do_sort(i):\n    n = 10 ** i\n    x = sorted(list(range(n)))\n    return f\"{n:9d}\"  \n    \nfor i in range(8):\n    do_sort(i)\n```\nthe ouput will show the effects of the population size on the sort speed:\n```\ny| #5 ==\u003e returned '        1' from do_sort(0) in 0.000027 seconds\ny| #5 ==\u003e returned '       10' from do_sort(1) in 0.000060 seconds\ny| #5 ==\u003e returned '      100' from do_sort(2) in 0.000748 seconds\ny| #5 ==\u003e returned '     1000' from do_sort(3) in 0.001897 seconds\ny| #5 ==\u003e returned '    10000' from do_sort(4) in 0.002231 seconds\ny| #5 ==\u003e returned '   100000' from do_sort(5) in 0.024014 seconds\ny| #5 ==\u003e returned '  1000000' from do_sort(6) in 0.257504 seconds\ny| #5 ==\u003e returned ' 10000000' from do_sort(7) in 1.553495 seconds\n```\n\nIt is also possible to time any code by using y as a context manager, e.g.\n```\nwith y():\n    time.sleep(1)\n```\nwil print something like\n```\ny| enter\ny| exit in 1.000900 seconds\n```\nYou can include parameters here as well:\n```\nwith y(show_context=True, show_time=True):\n    time.sleep(1)\n```\nwill print somethink like:\n```\ny| #8 @ 13:20:32.605903 ==\u003e enter\ny| #8 @ 13:20:33.609519 ==\u003e exit in 1.003358 seconds\n```\n\nFinally, to help with timing code, you can request the current delta with\n```\ny().delta\n```\nor (re)set it  with\n```\ny().delta = 0\n```\nSo, e.g. to time a section of code:\n```\ny.delta = 0\ntime.sleep(1)\nduration = y.delta\ny(duration)\n```\nmight print:\n```\ny| duration: 1.0001721999999997\n```\n\n# Configuration\n\nFor the configuration, it is important to realize that `y` is an instance of the `ycecream._Y` class, which has\na number of configuration attributes:\n```\n------------------------------------------------------\nattribute               alternative     default\n------------------------------------------------------\nprefix                  p               \"y| \"\noutput                  o               \"stderr\"\nserialize                               pprint.pformat\nshow_line_number        sln             False\nshow_time               st              False\nshow_delta              sd              False\nshow_enter              se              True\nshow_exit               sx              True\nshow_traceback          stb             False\nsort_dicts              sdi             False\nunderscore_numbers      un              False\nenabled                 e               True\nline_length             ll              80\ncompact                 c               False\nindent                  i               1\ndepth                   de              1000000\nwrap_indent             wi              \"     \"   \nseparator               sep             \", \"\ncontext_separator       cs              \" ==\u003e \"\nequals_separator        es              \": \"\nvalues_only             vo              False\nvalue_only_for_fstrings voff            False \nreturn_none             rn              False\nenforce_line_length     ell             False\ndecorator               d               False\ncontext_manager         cm              False\ndelta                   dl              0\n------------------------------------------------------\n```\nIt is perfectly ok to set/get any of these attributes directly, like\n```\ny.prefix = \"==\u003e \"\nprint(y.prefix)\n```\n\nBut, it is also possible to apply configuration directly in the call to `y`:\nSo, it is possible to say\n```\nfrom ycecream import y\ny(12, prefix=\"==\u003e \")\n```\n, which will print\n```\n==\u003e 12\n```\nIt is also possible to configure y permanently with the configure method. \n```\ny.configure(prefix=\"==\u003e \")\ny(12)\n```\nwill print\n```\n==\u003e 12\n```\nIt is arguably easier to say:\n```\ny.prefix = \"==\u003e \"\ny(12)\n```\nor even\n```\ny.p = \"==\u003e \"\ny(12)\n```\nto print\n```\n==\u003e 12\n```\nYet another way to configure y is to get a new instance of y with y.new() and the required configuration:\n```\nz = y.new(prefix=\"==\u003e \")\nz(12)\n```\nwill print\n```\n==\u003e 12\n```\n\nOr, yet another possibility is to clone y (optionally with modified attributes):\n```\nyd1 = y.clone(show_date=True)\nyd2 = y.clone()\nyd2.configure(show_date=True)\n```\nAfter this `yd1` and `yd2` will behave similarly (but they are not the same!)\n\n## prefix / p\n```\nfrom ycecream import y\ny('world', prefix='hello -\u003e ')\n```\nprints\n```\nhello -\u003e 'world'\n```\n\n`prefix` can be a function, too.\n\n```\nimport time\nfrom ycecream import y\ndef unix_timestamp():\n    return f\"{int(time.time())} \"\nhello = \"world\"\ny.configure(prefix=unix_timestamp)\ny(hello) \n```\nprints\n```\n1613635601 hello: 'world'\n```\n\n## output / o\nThis will allow the output to be handled by something else than the default (output being written to stderr).\n\nThe `output` attribute can be\n\n* a callable that accepts at least one parameter (the text to be printed)\n* a string or Path object that will be used as the filename\n* a text file that is open for writing/appending\n\nIn the example below, \n```\nfrom ycecream import y\nimport sys\ny(1, output=print)\ny(2, output=sys.stdout\nwith open(\"test\", \"a+\") as f:\n    y(3, output=f)\ny(4, output=\"\")\n```\n* `y| 1` will be printed to stdout\n* `y| 2` will be printed to stdout\n* `y| 3` will be appended to the file test\n* `y| 4` will *disappear*\n\nAs `output` may be any callable, you can even use this to automatically log any `y` output:\n```\nfrom ycecream import y\nimport logging\nlogging.basicConfig(level=\"INFO\")\nlog = logging.getLogger(\"demo\")\ny.configure(output=log.info)\na = {1, 2, 3, 4, 5}\ny(a)\na.remove(4)\ny(a)\n```\nwill print to stderr:\n```\nINFO:demo:y| a: {1, 2, 3, 4, 5}\nINFO:demo:y| a: {1, 2, 3, 5}\n```\nFinally, you can specify the following strings:\n```\n\"stderr\"           to print to stderr\n\"stdout\"           to print to stdout\n\"null\" or \"\"       to completely ignore (dummy) output \n\"logging.debug\"    to use logging.debug\n\"logging.info\"     to use logging.info\n\"logging.warning\"  to use logging.warning\n\"logging.error\"    to use logging.error\n\"logging.critical\" to use logging.critical\n```\nE.g.\n```\nfrom ycecream import y\nimport sys\ny.configure(output=\"stdout\")\n```\nto print to stdout.\n\n## serialize\nThis will allow to specify how argument values are to be\nserialized to displayable strings. The default is pformat (from pprint), but this can be changed to,\nfor example, to handle non-standard datatypes in a custom fashion.\nThe serialize function should accept at least one parameter.\nThe function can optionally accept the keyword arguments `width` and `sort_dicts`, `compact`, `indent`, `underscore_numbers` and `depth`.\n```\nfrom ycecream import y\ndef add_len(obj):\n    if hasattr(obj, \"__len__\"):\n        add = f\" [len={len(obj)}]\"\n    else:\n        add = \"\"\n    return f\"{repr(obj)}{add}\"\n\nl = list(range(7))\nhello = \"world\"\ny(7, hello, l, serialize=add_len)\n```\nprints\n```\ny| 7, hello: 'world' [len=5], l: [0, 1, 2, 3, 4, 5, 6] [len=7]\n```\n\n## show_line_number / sln\nIf True, adds the `y()` call's line number and possible the filename and parent function to `y()`'s output.\n\n```\nfrom ycecream import y\ny.configure(show_line_number=True)\ndef shout():\n    hello=\"world\"\n    y(hello)\nshout()\n```\nprints something like\n```\ny| #5 in shout() ==\u003e hello: 'world'\n```\n\nIf \"no parent\" or \"n\", the parent function will not be shown.\n```\nfrom ycecream import y\ny.configure(show_line_number=\"n\")\ndef shout():\n    hello=\"world\"\n    y(hello)\nshout()\n```\nprints something like\n```\ny| #5 ==\u003e hello: 'world'\n```\nNote that if you call `y` without any arguments, the line number is always shown, regardless of the status `show_line_number`.\n\nSee below for an explanation of the information provided.\n\n## show_time / st\nIf True, adds the current time to `y()`'s output.\n\n```\nfrom ycecream import y\ny.configure(show_time=True)\nhello=\"world\"\ny(hello)\n```\nprints something like\n```\ny| @ 13:01:47.588125 ==\u003e hello: 'world'\n```\n\n## show_delta / sd\nIf True, adds the number of seconds since the start of the program to `y()`'s output.\n```\nfrom ycecream import y\nimport time\ny.configure(show_delta=True)\nfrench = \"bonjour le monde\"\nenglish = \"hallo world\"\ny(english)\ntime.sleep(1)\ny(french)\n```\nprints something like\n```\ny| delta=0.088 ==\u003e english: 'hallo world'\ny| delta=1.091 ==\u003e french: 'bonjour le monde'\n```\n\n## show_enter / se\nWhen used as a decorator or context manager, by default, ycecream ouputs a line when the decorated the\nfunction is called  or the context manager is entered.\n\nWith `show_enter=False` this line can be suppressed.\n\n## show_exit / sx\nWhen used as a decorator or context manager, by default, ycecream ouputs a line when the decorated the\nfunction returned or the context manager is exited.\n\nWith `show_exit=False` this line can be suppressed.\n\n\n## show_traceback / stb\nWhen show_traceback is True, the ordinary output of y() will be followed by a printout of the\ntraceback, similar to an error traceback.\n```\nfrom ycecream import y\ny.show_traceback=True\ndef x():\n    y()\n\nx()\nx()\n```\nprints\n```\ny| #4 in x()\n    Traceback (most recent call last)\n      File \"c:\\Users\\Ruud\\Dropbox (Personal)\\Apps\\Python Ruud\\ycecream\\x.py\", line 6, in \u003cmodule\u003e\n        x()\n      File \"c:\\Users\\Ruud\\Dropbox (Personal)\\Apps\\Python Ruud\\ycecream\\x.py\", line 4, in x\n        y()\ny| #4 in x()\n    Traceback (most recent call last)\n      File \"c:\\Users\\Ruud\\Dropbox (Personal)\\Apps\\Python Ruud\\ycecream\\x.py\", line 7, in \u003cmodule\u003e\n        x()\n      File \"c:\\Users\\Ruud\\Dropbox (Personal)\\Apps\\Python Ruud\\ycecream\\x.py\", line 4, in x\n        y()\n```\nThe `show_traceback` functionality is also available when y is used as a decorator or context manager. \n\n## line_length / ll\nThis attribute is used to specify the line length (for wrapping). The default is 80.\nYcecream always tries to keep all output on one line, but if it can't it will wrap:\n```\nd = dict(a1=1,a2=dict(a=1,b=1,c=3),a3=list(range(10)))\ny(d)\ny(d, line_length=120)\n```\nprints\n```\ny|\n    d:\n        {'a1': 1,\n         'a2': {'a': 1, 'b': 1, 'c': 3},\n         'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}\ny| d: {'a1': 1, 'a2': {'a': 1, 'b': 1, 'c': 3}, 'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}\n```\n\n## compact / c\nThis attribute is used to specify the compact parameter for `pformat` (see the pprint documentation\nfor details). `compact` is False by default.\n```\na = 9 * [\"0123456789\"]\ny(a)\ny(a, compact=True)\n```\nprints\n```\ny|\n    a:\n        ['0123456789',\n         '0123456789',\n         '0123456789',\n         '0123456789',\n         '0123456789',\n         '0123456789',\n         '0123456789',\n         '0123456789',\n         '0123456789']\ny|\n    a:\n        ['0123456789', '0123456789', '0123456789', '0123456789', '0123456789',\n         '0123456789', '0123456789', '0123456789', '0123456789']\n```\n\n## indent / i\nThis attribute is used to specify the indent parameter for `pformat` (see the pprint documentation\nfor details). `indent` is 1 by default.\n```\ns = \"01234567890012345678900123456789001234567890\"\ny( [s, [s]])\ny( [s, [s]], indent=4)\n```\nprints\n```\ny|\n    [s, [s]]:\n        ['01234567890012345678900123456789001234567890',\n         ['01234567890012345678900123456789001234567890']]\ny|\n    [s, [s]]:\n        [   '01234567890012345678900123456789001234567890',\n            ['01234567890012345678900123456789001234567890']]\n```\n\n## depth / de\nThis attribute is used to specify the depth parameter for `pformat` (see the pprint documentation\nfor details). `depth` is `1000000` by default. \n```\ns = \"01234567890012345678900123456789001234567890\"\ny([s,[s,[s,[s,s]]]])\ny([s,[s,[s,[s,s]]]], depth=3)\n```\nprints\n```\ny|\n    [s,[s,[s,[s,s]]]]:\n        ['01234567890012345678900123456789001234567890',\n         ['01234567890012345678900123456789001234567890',\n          ['01234567890012345678900123456789001234567890',\n           ['01234567890012345678900123456789001234567890',\n            '01234567890012345678900123456789001234567890']]]]\ny|\n    [s,[s,[s,[s,s]]]]:\n        ['01234567890012345678900123456789001234567890',\n         ['01234567890012345678900123456789001234567890',\n          ['01234567890012345678900123456789001234567890', [...]]]]\n```\n\n## wrap_indent / wi\nThis specifies the indent string if the output does not fit in the line_length (has to be wrapped).\nRather than a string, wrap_indent can be also be an integer, in which case the wrap_indent will be that amount of blanks.\nThe default is 4 blanks.\n\nE.g.\n```\nd = dict(a1=1,a2=dict(a=1,b=1,c=3),a3=list(range(10)))\ny(d, wrap_indent=\"  \")\ny(d, wrap_indent=\"....\")\ny(d, wrap_indent=2)\n```\nprints\n```\ny|\n  d:\n    {'a1': 1,\n     'a2': {'a': 1, 'b': 1, 'c': 3},\n     'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}\ny|\n....d:\n........{'a1': 1,\n........ 'a2': {'a': 1, 'b': 1, 'c': 3},\n........ 'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}\ny|\n  d:\n    {'a1': 1,\n     'a2': {'a': 1, 'b': 1, 'c': 3},\n     'a3': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}\n```\n\n## enabled / e\nCan be used to disable the output:\n```\nfrom ycecream import y\n\ny.configure(enabled=False)\ns = 'the world is '\ny(s + 'perfect.')\ny.configure(enabled=True)\ny(s + 'on fire.')\n```\nprints\n```\ny| s + 'on fire.': 'the world is on fire.'\n```\nand nothing about a perfect world.\n\n## sort_dicts / sdi\nBy default, ycecream does not sort dicts (printed by pprint). However, it is possible to get the\ndefault pprint behaviour (i.e. sorting dicts) with the sorted_dicts attribute:\n\n```\nworld = {\"EN\": \"world\", \"NL\": \"wereld\", \"FR\": \"monde\", \"DE\": \"Welt\"}\ny(world))\ny(world, sort_dicts=False)\ny(world, sort_dicts=True)\n```\nprints\n```\ny| world: {'EN': 'world', 'NL': 'wereld', 'FR': 'monde', 'DE': 'Welt'}\ny| world: {'EN': 'world', 'NL': 'wereld', 'FR': 'monde', 'DE': 'Welt'}\ny| world: {'DE': 'Welt', 'EN': 'world', 'FR': 'monde', 'NL': 'wereld'}\n```\n\n## underscore_numbers / un\nBy default, ycecream does not add underscores in big numberss (printed by pprint). However, it is possible to get the\ndefault pprint behaviour with the underscore_numbers attribute:\n\n```\nnumbers = dict(one= 1, thousand= 1000, million=1000000, x1234567890= 1234567890)\ny(numbers)\ny(numbers, underscore_numbers=True)\ny(numbers, un=False)\n```\nprints\n```\ny| numbers: {'one': 1, 'thousand': 1000, 'million': 1000000, 'x1234567890': 1234567890}\ny| numbers: {'one': 1, 'thousand': 1_000, 'million': 1_000_000, 'x1234567890': 1_234_567_890}\ny| numbers: {'one': 1, 'thousand': 1000, 'million': 1000000, 'x1234567890': 1234567890}\n```\n\n## separator / sep\nBy default, pairs (on one line) are separated by `, `.\nIt is possible to change this with the attribute ` separator`:\n```\na=\"abcd\"\nb=1\nc=1000\nd=list(\"ycecream\")\ny(a,(b,c),d)\ny(a,(b,c),d, separator=\" | \")\n```\nprints\n```\ny| a: 'abcd', (b,c): (1, 1000), d: ['y', 'c', 'e', 'c', 'r', 'e', 'a', 'm']\ny| a: 'abcd' | (b,c): (1, 1000) | d: ['y', 'c', 'e', 'c', 'r', 'e', 'a', 'm']\n```\n## context_separator / cs\nBy default the line_number, time and/or delta are followed by ` ==\u003e `.\nIt is possible to change this with the attribute `context_separator`:\n```\na=\"abcd\"\ny(a)\ny(a, show_time=True, context_separator = ' \\u279c ')\n```\nprints:\n```\ny| @ 12:56:11.341650 ==\u003e a: 'abcd'\ny| @ 12:56:11.485567 ➜ a: 'abcd'\n```\n## equals_separator / es\nBy default name of a variable and its value are separated by `: `.\nIt is possible to change this with the attribute `equals_separator`:\n```\na=\"abcd\"\ny(a)\ny(a, equals_separator = ' == \")\n```\nprints:\n```\ny| a: 'abcd'\ny| a == 'abcd'\n```\n\n## values_only / vo\nIf False (the default), both the left-hand side (if possible) and the\nvalue will be printed. If True, the left_hand side will be suppressed:\n```\nhello = \"world\"\ny(hello, 2 * hello)\ny(hello, 2 * hello, values_only=True)\n```\nprints\n```\ny| hello: 'world', 2 * hello = 'worldworld'\ny| 'world', 'worldworld'\n```\nThe values=True version of y can be seen as a supercharged print/pprint.\n\n\n## values_only_for_fstrings / voff\nIf False (the default), both the original f-string and the\nvalue will be printed for f-strings.\nIf True, the left_hand side will be suppressed in case of an f-string:\n```\nx = 12.3\ny(f\"{x:0.3e}\")\ny.values_only_for_fstrings = True\ny(f\"{x:0.3e}\")\n```\nprints\n```\ny| f\"{x:0.3e}\": '1.230e+01'\ny| '1.230e+01'\n```\nNote that if `values_only` is True, f-string will be suppressed, regardless of `values_only_for_fstrings`.\n\n## return_none / rn\nNormally, `y()`returns the values passed directly, which is usually fine. However, when used in a notebook\nor REPL, that value will be shown, and that can be annoying. Therefore, if `return_none`is True, `y()`will\nreturn None and thus not show anything.\n```\na = 3\nprint(y(a, a + 1))\ny.configure(return_none=True)\nprint(y(a, a + 1))\n```\nprints\n```\ny| (3, 4)\n(3, 4)\ny| (3, 4)\nNone\n```\n\n## enforce_line_length / ell\nIf enforce_line_length is True, all output lines are explicitely truncated to the given\nline_length, even those that are not truncated by pformat.\n\n## delta / dl\nThe delta attribute can be used to (re)set the current delta, e.g.\n```\ny.configure(dl=0)\nprint(y.delta)\n```\nprints a value that slightly more than 0.\n\n\n## decorator / d\nNormally, an ycecream instance can be used as to show values, as a decorator and as a\ncontext manager.\n\nHowever, when used from a REPL the usage as a decorator can't be detected properly and in that case,\nspecify `decorator=True`. E.g. \n```\n\u003e\u003e\u003e@y(decorator=True)\n\u003e\u003e\u003edef add2(x):\n\u003e\u003e\u003e    return x + 2\n\u003e\u003e\u003eprint(add2(10))\ny| called add2(10)\ny| returned 12 from add2(10) in 0.000548 seconds\n12\n```\n\nThe `decorator` attribute is also required when using `y()` as a decorator\nwitb *fast disabling* (see below).\n```\ny.enabled([])\n@y()\ndef add2(x):\n    return x + 2\n```\nwould fail with`TypeError: 'NoneType' object is not callable`, but\n```\ny.enabled([])\n@y(decorator=True)\ndef add2(x):\n    return x + 2\n```\nwill run correctly.\n\n\n## context_manager / cm\nNormally, an ycecream instance can be used as to show values, as a decorator and as a\ncontext manager.\n\nHowever, when used from a REPL the usage as a context manager can't be detected properly and in that case,\nspecify `context_manager=True`. E.g. \n```\n\u003e\u003e\u003ewith y(context_manager=True)\n\u003e\u003e\u003e    pass\ny| enter\ny| exit in 0.008644 seconds\n```\n\nThe `context_manager` attribute is also required when using `y():` as a context manager\nwith *fast disabling* (see below).\n```\ny.enabled([])\nwith y:\n    pass\n```\nwould fail with `AttributeError: __enter__`, but\n```\ny.enabled([])\nwith y(context_manager=True):\n    pass\n```\nwill run correctly.\n\n## provided / pr\nIf provided is False, all output for this call will be suppressed.\nIf provided is True, output will be generated as usual (obeying the enabled attribute).\n\n```\nx = 1\ny(\"should print\", provided=x \u003e 0)\ny(\"should not print\", provided=x \u003c 0)\n```\nThis will print\n```\nshould print\n```\n\n# Return a string instead of sending to output\n\n`y(*args, as_str=True)` is like `y(*args)` but the output is returned as a string instead\nof written to output.\n\n```\nfrom ycecream import y\nhello = \"world\"\ns = y(hello, as_str=True)\nprint(s, end=\"\")\n```\nprints\n```\ny| hello: 'world'\n```\n\nNote that if enabled=False, the call will return the null string (`\"\"`).\n\n# Disabling ycecream's output\n\n```\nfrom ycecream import y\nyd = y.fork(show_delta=True)\ny(1)\nyd(2)\ny.enabled = False\ny(3)\nyd(4)\ny.enabled = True\ny(5)\nyd(6)\nprint(y.enabled)\n```\nprints\n```\ny| 1\ny| delta=0.011826 ==\u003e 2\ny| 5\ny| delta=0.044893 ==\u003e 6\nTrue\n```\nOf course `y()` continues to return its arguments when disabled, of course.\n\nIt is also possible to suppress output with the provided attribute (see above).\n\n## Speeding up disabled ycecream\nWhen output is disabled, either via `y.configure(enbabled=False)` or `ycecream.enable = False`,\nycecream still has to check for usage as a decorator or context manager, which can be rather time\nconsuming.\n\nIn order to speed up a program with disabled ycecream calls, it is possible to specify\n`y.configure(enabled=[])`, in which case `y` will always just return\nthe given arguments. If ycecream is disabled this way, usage as a `@y()` decorator  or as a `with y():`\ncontext manager will raise a runtime error, though. The `@y` decorator without parentheses will\nnot raise any exception, though.\n\nTo use `y` as a decorator and still have *fast disabling*:\n```\ny.configure(enabled=[])\n@y(decorator=True):\ndef add2(x):\n     return x + 2\nx34 = add2(30)\n```\nAnd, similarly, to use `y` as a context manager  combined with *fast disabling*:\n```\ny.configure(enabled=[])\nwith @y(context_manager=True):\n    pass\n```\n\nThe table below shows it all.\n```  \n-------------------------------------------------------------------------------\n                         enabled=True   enabled=False                enabled=[]\n-------------------------------------------------------------------------------\nexecution speed                normal          normal                      fast     \ny()                            normal       no output                 no output\n@y                             normal       no output                 no output\ny(decorator=True)              normal       no output                 no output\ny(context_manager=True)        normal       no output                 no output\n@y()                           normal       no output                 TypeError\nwith y():                      normal       no output  AttributeError/TypeError\ny(as_str=True)                 normal             \"\"                         \"\"\n-------------------------------------------------------------------------------\n```\n\n# Using ycecream as a substitute for `assert`\n\nYcecream has a method `assert_` that works like `assert`, but can be enabled or disabled with the enabled flag.\n\n```\ntemperature = -1\ny.assert_(temperature \u003e 0)\n```\nThis will raise an AttributeError.\n\nBut\n```\ny.enabled = False\ntemperature = -1\ny.assert_(temperature \u003e 0)\n```\nwill not.\n\nNote that with the attribute propagation method, you can in effect have a layered assert system.\n\n# Interpreting the line number information\n\nWhen `show_line_number` is True or y() is used without any parameters, the output will contain the line number like:\n```\ny| #3 ==\u003e a: 'abcd'\n```\nIf the line resides in another file than the main file, the filename (without the path) will be shown as well:\n```\ny| #30[foo.py] ==\u003e foo: 'Foo'\n```\nAnd finally when used in a function or method, that function/method will be shown as well:\n```\ny| #456[foo.py] in square_root ==\u003e x: 123\n```\nThe parent function can be suppressed by setting `show_line_number` or `sln` to `\"n\"` or `\"no parent\"`.\n\n# Configuring at import time\n\nIt can be useful to configure ycecream at import time. This can be done by providing a `ycecream.json` file which\ncan contain any attribute configuration overriding the standard settings.\nE.g. if there is an `ycecream.json` file with the following contents\n```\n{\n    \"o\": \"stdout\",\n    \"show_time\": true,\n    \"line_length\": 120`\n    'compact' : true\n}\n```\nin the same folder as the application, this program:\n```\nfrom ycecream import y\nhello = \"world\"\ny(hello)\n```\nwill print to stdout (rather than stderr):\n```\ny| @ 14:53:41.392190 ==\u003e hello: 'world'\n```\nAt import time the sys.path will be searched for, in that order, to find an `ycecream.json` file and use that. This mean that \nyou can place an `ycecream.json` file in the site-packages folder where `ycecream` is installed to always use\nthese modified settings.\n\nPlease observe that json values are slightly different from their Python equivalents:\n```\n-------------------------------\nPython     json\n-------------------------------\nTrue       true\nFalse      false\nNone       none\nstrings    always double quoted\n-------------------------------\n```\nNote that not-specified attributes will remain the default settings.\n\nFor obvious reasons, it is not possible to specify `serialize` in an ycecream.json file.\n\n# Working with multiple instances of y\n\nNormally, only the `y()` object is used.\n\nIt can be useful to have multiple instances, e.g. when some of the debugging has to be done with context information\nand others requires an alternative prefix.\n\nTHere are several ways to obtain a new instance of ycecream:\n\n*    by using `y.new()`\n     \n     With this a new ycecream object is created with the default attributes\n     and possibly ycecream.json overrides.\n*    by using `y.new(ignore_json=True)`\n\n     With this a new ycecreamobject is created with the default attibutes. Any ycecream.json files asre ignored.\n*    by using `y.fork()`\n     \n     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.\n*    by using `y.clone()`, which copies all attributes from y()\n\n     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.\n\n*    with `y()` used as a context manager\n\nIn either case, attributes can be added to override the default ones.\n\n### Example\n```\nfrom ycecream import y\ny_with_line_number = y.fork(show_line_number=True)\ny_with_new_prefix = y.new(prefix=\"==\u003e \")\ny_with_new_prefix_and_time = y_with_new_prefix.clone(show_time=True)\nhello=\"world\"\ny_with_line_number(hello)\ny_with_new_prefix(hello)\ny_with_new_prefix_and_time(hello)\ny.equals_separator = \" == \"  # this affects only the forked objects\ny_with_line_number(hello)\ny_with_new_prefix(hello)\ny_with_new_prefix_and_time(hello)\nwith y(prefix=\"ycm \") as ycm:\n    ycm(hello)\n    y(hello)\n```\nprints\n```\ny| #6 ==\u003e hello: 'world'\n==\u003e hello: 'world'\n==\u003e @ 09:55:10.883732 ==\u003e hello: 'world'\ny| #10 ==\u003e hello == 'world'\n==\u003e hello: 'world'\n==\u003e @ 09:55:10.910717 ==\u003e hello: 'world'\nycm enter\nycm hello == 'world'\ny| hello == 'world'\nycm exit in 0.017686 seconds\n```\n\n## ignore_json\nWith `y.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.\n\n### Example\nSuppose we have an `ycecream.json` file in the current directory with the contents\n```\n{prefix=\"==\u003e\"}\n```\nThen\n```\ny_post_json = y.new()\ny_ignore_json = y.new(ignore_json=True)\nhello = \"world\"\ny(hello)\ny_post_json(hello)\ny_ignore_json(hello)\n```\nprints\n```\n==\u003ehello: 'world'\n==\u003ehello: 'world'\ny| hello: 'world'\n```\n\n# Test script\n\nOn GitHub is a file `test_ycecream.py` that tests (and thus also demonstrates) most of the functionality\nof ycecream.\n\nIt is very useful to have a look at the tests to see the features (some may be not covered (yet) in this readme).\n\n# Using ycecream in a REPL\n\nYcecream may be used in a REPL, but with limited functionality:\n* all arguments are just presented as such, i.e. no left-hand side, e.g.\n  ```\n  \u003e\u003e hello = \"world\"\n  \u003e\u003e\u003e y(hello, hello * 2)\n  y| 'hello', 'hellohello'\n  ('hello', 'hellohello')\n  ```\n* line numbers are never shown  \n* use as a decorator is only supported when you used as `y(decorator=True)` or `y(d=1)`\n* use as a context manager is only supported when used as `y(context_manager=True)`or `y(cm=1)`\n\n# Alternative to `y`\n\nSometimes, it is not suitable to use the name y in a program, e.g. when\ndealing with coordinates x, y and z.\n\nIn that case, it is possible to use yc instead\n```\nfrom ycecream import yc\n```\nThe `yc` object is a *fork* of y with the prefix `\"yc| \"`. That means that attributes of `y` are propagated to `yc`, unless overridden.\n\nOf course, it is also possible to use\n```\nfrom ycecream import y as yy\n```\nor\n```\nyy = y.new()\n```\nor\n```\nyy = y.new(prefix=\"yy| \")\n```\n\n# Alternative installation\n\nWith `install ycecream from github.py`, you can install the ycecream.py directly from GitHub to the site packages (as if it was a pip install).\n\nWith `install ycecream.py`, you can install the ycecream.py in your current directory to the site packages (as if it was a pip install).\n\nBoth files can be found in the GitHub repository (https://github.com/salabim/ycecream).\n\n\n# Limitations\n\nIt is not possible to use ycecream:\n* from a frozen application (e.g. packaged with PyInstaller)\n* when the underlying source code has changed during execution\n\n# Implementation details\n\nAlthough not important for using the package, here are some implementation details:\n* ycecream.py contains the complete source of the asttokens and executing packages, in\n   order to offer the required source lookups, without any dependencies\n* ycecream.py contains the complete source of pprint as of Python 3.13 in order to support the sort_dicts and underscore_numbers parameter\n* in order to support using y() as a decorator and a context manager, ycecream caches the complete source of\nany source file that uses y()\n\n\n# Acknowledgement\n\nThe **ycecream** pacakage is inspired by the **IceCream** package, but is a \nnearly complete rewrite. See https://github.com/gruns/icecream\n\nMany thanks to the author Ansgar Grunseid / grunseid.com / grunseid@gmail.com .\n\n# Differences with IceCream\n\nThe ycecream module was originally a fork of IceCream, but has many differences:\n\n```\n----------------------------------------------------------------------------------------\ncharacteristic                    ycecream                 IceCream\n----------------------------------------------------------------------------------------\ndefault name                      y (or yc)                ic\ndependencies                      none                     many\nnumber of files                   1                        several\nusable without installation       yes                      no\ncan be used as a decorator        yes                      no\ncan be used as a context manager  yes                      no\ncan show traceback                yes                      no\nPEP8 (Pythonic) API               yes                      no\nsorts dicts                       no by default, optional  yes\nsupports compact, indent,\nand underscore_numbers\nparameters of pprint              yes                      no\nuse from a REPL                   limited functionality    no\nexternal configuration            via json file            no\nobserves line_length correctly    yes                      no\nbenchmarking functionality        yes                      no\nsuppress f-strings at left hand   optional                 no\nindentation                       4 blanks (overridable)   dependent on length of prefix\nforking and cloning               yes                      no\ntest script                       pytest                   unittest\ncolourize                         no                       yes (can be disabled)\n----------------------------------------------------------------------------------------\n```\n![PyPI](https://img.shields.io/pypi/v/ycecream) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ycecream) ![PyPI - Implementation](https://img.shields.io/pypi/implementation/ycecream)\n\n![PyPI - License](https://img.shields.io/pypi/l/ycecream) ![Black](https://img.shields.io/badge/code%20style-black-000000.svg) \n![GitHub last commit](https://img.shields.io/github/last-commit/salabim/ycecream)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalabim%2Fycecream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalabim%2Fycecream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalabim%2Fycecream/lists"}