From 261fc3c5611a255d4c68829713ccc009e1dfd81f Mon Sep 17 00:00:00 2001 From: "G. Queiroz" Date: Sat, 18 Dec 2021 08:28:59 -0300 Subject: [PATCH 1/3] Working on better support for Jupyter --- icecream/icecream.py | 49 ++++++++++++++++++++++++++++++++++++------ tests/test_icecream.py | 8 ++++--- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/icecream/icecream.py b/icecream/icecream.py index 5a7ae4c..f308e3b 100644 --- a/icecream/icecream.py +++ b/icecream/icecream.py @@ -11,8 +11,10 @@ # License: MIT # + from __future__ import print_function +import os import ast import inspect import pprint @@ -63,9 +65,25 @@ def supportTerminalColorsInWindows(): yield colorama.deinit() - -def stderrPrint(*args): - print(*args, file=sys.stderr) +def getOutputFile(): + global DEFAULT_OUTPUT_FILE + if hasattr(DEFAULT_OUTPUT_FILE, 'write'): + return DEFAULT_OUTPUT_FILE + if DEFAULT_OUTPUT_FILE == 'stderr': + return sys.stderr + if DEFAULT_OUTPUT_FILE == 'stdout': + return sys.stdout + if type(DEFAULT_OUTPUT_FILE): + is_new = os.path.isfile(DEFAULT_OUTPUT_FILE) + DEFAULT_OUTPUT_FILE = open(DEFAULT_OUTPUT_FILE, mode='a') + # If the file already exists, add a \n so it becomes easier to read + if not is_new: + print('', file=DEFAULT_OUTPUT_FILE) + return DEFAULT_OUTPUT_FILE + raise ValueError(f"Cannot understand DEFAULT_OUTPUT_FILE = {DEFAULT_OUTPUT_FILE!r} means") + +def ICFilePrint(*args): + print(*args, file=getOutputFile()) def isLiteral(s): @@ -76,18 +94,24 @@ def isLiteral(s): return True -def colorizedStderrPrint(s): +def colorizedICFilePrint(s): colored = colorize(s) with supportTerminalColorsInWindows(): - stderrPrint(colored) + ICFilePrint(colored) DEFAULT_PREFIX = 'ic| ' DEFAULT_LINE_WRAP_WIDTH = 70 # Characters. DEFAULT_CONTEXT_DELIMITER = '- ' -DEFAULT_OUTPUT_FUNCTION = colorizedStderrPrint +DEFAULT_OUTPUT_FILE = 'stderr' +DEFAULT_OUTPUT_FUNCTION = colorizedICFilePrint DEFAULT_ARG_TO_STRING_FUNCTION = pprint.pformat +def str2bool(v): + return str(v).lower() in ["yes", "true", "t", "1", "y"] + +def is_in_jupyter(): + hasattr(__builtins__,'__IPYTHON__') class NoSourceAvailableError(OSError): """ @@ -330,4 +354,15 @@ def configureOutput(self, prefix=_absent, outputFunction=_absent, self.includeContext = includeContext -ic = IceCreamDebugger() +def init(): + global ic + + if is_in_jupyter() or str2bool(os.environ.get('PYTHON_ICECREAM_USE_STDOUT')): + DEFAULT_OUTPUT_FILE = sys.stdout + + # Will create the file if it does not exist + getOutputFile() + + ic = IceCreamDebugger() + +init() diff --git a/tests/test_icecream.py b/tests/test_icecream.py index 8c695ee..9d515bb 100644 --- a/tests/test_icecream.py +++ b/tests/test_icecream.py @@ -20,8 +20,10 @@ from os.path import basename, splitext import icecream -from icecream import ic, stderrPrint, NoSourceAvailableError +from icecream import ic, ICFilePrint, NoSourceAvailableError +# Ensure our tests don't fail because of a misocnfigured environment +icecream.DEFAULT_OUTPUT_FILE = sys.stderr TEST_PAIR_DELIMITER = '| ' MYFILENAME = basename(__file__) @@ -54,7 +56,7 @@ def isatty(self): def disableColoring(): originalOutputFunction = ic.outputFunction - ic.configureOutput(outputFunction=stderrPrint) + ic.configureOutput(outputFunction=ICFilePrint) yield ic.configureOutput(outputFunction=originalOutputFunction) @@ -302,7 +304,7 @@ def testDifferentName(self): def testPrefixConfiguration(self): prefix = 'lolsup ' - with configureIcecreamOutput(prefix, stderrPrint): + with configureIcecreamOutput(prefix, ICFilePrint): with disableColoring(), captureStandardStreams() as (out, err): ic(a) pair = parseOutputIntoPairs(out, err, 1, prefix=prefix)[0][0] From 91ec0ea5d1279788cad88208195f3973ce9fee3c Mon Sep 17 00:00:00 2001 From: "G. Queiroz" Date: Sat, 18 Dec 2021 09:04:11 -0300 Subject: [PATCH 2/3] Improved code and docs. --- README.md | 2 ++ icecream/icecream.py | 32 ++++++-------------------------- tests/test_icecream.py | 7 +++++-- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index d553dd3..eef07cd 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,8 @@ except ImportError: # Graceful fallback if IceCream isn't installed. ### Configuration +By default, icecream will output to stderr unless the environment variable `PYTHON_ICECREAM_USE_STDOUT ` is true (i.e. if it case insensitively matches `1`, `y`, `yes`, `t` or `true`). It will also switch to the stdout if running inside Jupyter. + `ic.configureOutput(prefix, outputFunction, argToStringFunction, includeContext)` can be used to adopt a custom output prefix (the default is `ic| `), change the output function (default is to write to stderr), customize diff --git a/icecream/icecream.py b/icecream/icecream.py index f308e3b..77b3f42 100644 --- a/icecream/icecream.py +++ b/icecream/icecream.py @@ -65,25 +65,8 @@ def supportTerminalColorsInWindows(): yield colorama.deinit() -def getOutputFile(): - global DEFAULT_OUTPUT_FILE - if hasattr(DEFAULT_OUTPUT_FILE, 'write'): - return DEFAULT_OUTPUT_FILE - if DEFAULT_OUTPUT_FILE == 'stderr': - return sys.stderr - if DEFAULT_OUTPUT_FILE == 'stdout': - return sys.stdout - if type(DEFAULT_OUTPUT_FILE): - is_new = os.path.isfile(DEFAULT_OUTPUT_FILE) - DEFAULT_OUTPUT_FILE = open(DEFAULT_OUTPUT_FILE, mode='a') - # If the file already exists, add a \n so it becomes easier to read - if not is_new: - print('', file=DEFAULT_OUTPUT_FILE) - return DEFAULT_OUTPUT_FILE - raise ValueError(f"Cannot understand DEFAULT_OUTPUT_FILE = {DEFAULT_OUTPUT_FILE!r} means") - def ICFilePrint(*args): - print(*args, file=getOutputFile()) + print(*args, file=DEFAULT_OUTPUT_FILE) def isLiteral(s): @@ -103,7 +86,6 @@ def colorizedICFilePrint(s): DEFAULT_PREFIX = 'ic| ' DEFAULT_LINE_WRAP_WIDTH = 70 # Characters. DEFAULT_CONTEXT_DELIMITER = '- ' -DEFAULT_OUTPUT_FILE = 'stderr' DEFAULT_OUTPUT_FUNCTION = colorizedICFilePrint DEFAULT_ARG_TO_STRING_FUNCTION = pprint.pformat @@ -353,16 +335,14 @@ def configureOutput(self, prefix=_absent, outputFunction=_absent, if includeContext is not _absent: self.includeContext = includeContext - -def init(): - global ic +def reload(): + global ic, DEFAULT_OUTPUT_FILE if is_in_jupyter() or str2bool(os.environ.get('PYTHON_ICECREAM_USE_STDOUT')): DEFAULT_OUTPUT_FILE = sys.stdout - - # Will create the file if it does not exist - getOutputFile() + else: + DEFAULT_OUTPUT_FILE = sys.stderr ic = IceCreamDebugger() -init() +reload() diff --git a/tests/test_icecream.py b/tests/test_icecream.py index 9d515bb..c602cf6 100644 --- a/tests/test_icecream.py +++ b/tests/test_icecream.py @@ -19,11 +19,12 @@ from contextlib import contextmanager from os.path import basename, splitext +import os import icecream from icecream import ic, ICFilePrint, NoSourceAvailableError -# Ensure our tests don't fail because of a misocnfigured environment -icecream.DEFAULT_OUTPUT_FILE = sys.stderr +# Ensure our tests don't fail because of a misconfigured environment +os.environ['PYTHON_ICECREAM_USE_STDOUT'] = 'False' TEST_PAIR_DELIMITER = '| ' MYFILENAME = basename(__file__) @@ -94,8 +95,10 @@ def captureStandardStreams(): try: sys.stdout = newStdout sys.stderr = newStderr + icecream.reload() yield newStdout, newStderr finally: + icecream.reload() sys.stdout = realStdout sys.stderr = realStderr From b7455489f0bbc087151dcb96f7ef0d471993cea0 Mon Sep 17 00:00:00 2001 From: "G. Queiroz" Date: Sat, 18 Dec 2021 09:08:44 -0300 Subject: [PATCH 3/3] Fixed is_in_jupyter() --- icecream/icecream.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/icecream/icecream.py b/icecream/icecream.py index 77b3f42..051b3b4 100644 --- a/icecream/icecream.py +++ b/icecream/icecream.py @@ -93,7 +93,11 @@ def str2bool(v): return str(v).lower() in ["yes", "true", "t", "1", "y"] def is_in_jupyter(): - hasattr(__builtins__,'__IPYTHON__') + try: + from IPython import get_ipython + return get_ipython() is not None + except ModuleNotFoundError: + return False class NoSourceAvailableError(OSError): """