Global variables shared across modules

By Steven D’Aprano via Discussions on Python.org at 26Jun2022 11:17:

“my X() debug function”

Tell us more!

Well, I’m a lazy typist. And I debug a lot with print(), or more often
my X() function instead. X() has 4 primary features:

  • easy to type (1 letter, and both X and ( hold down the shift key)
  • can output in an ANSI colour - I use yellow in my terminals for it, so
    it stands out amongst the normal green
  • write to stderr by default, but can also write directly to the
    terminal (or to a logger or be discarded, which I pretty much never
    use)
  • be controlled with enviroment variables

Here’s a screengrab of a dev terminal with some X() debug output in
the output:

So, the module I’m debugging will usually have:

from cs.x import X

like this (uncommited code which emits the message in the image above):

CSS[~/hg/css-solar(hg:solar)]fleet2*> diff
+ exec hg -R /Users/cameron/hg/css-solar diff
diff --git a/lib/python/cs/timeseries.py b/lib/python/cs/timeseries.py
--- a/lib/python/cs/timeseries.py
+++ b/lib/python/cs/timeseries.py
@@ -102,6 +102,8 @@ from cs.resources import MultiOpenMixin
 from cs.result import CancellationError
 from cs.upd import Upd, UpdProxy, print  # pylint: disable=redefined-builtin

+from cs.x import X
+
 __version__ = '20220606-post'

 DISTINFO = {
@@ -2730,6 +2732,7 @@ class TimeSeriesMapping(dict, MultiOpenM
           `column_name_map.get(column_name,column_name)`
     '''
     pd = import_extra('pandas', DISTINFO)
+    X("READ_CSV %r\npd_read_csv_kw=%s", csvpath, pformat(pd_read_csv_kw))
     df = pfx_call(pd.read_csv, csvpath, **pd_read_csv_kw)
     # prepare column renames
     renamed = {}

So, easy to type print flavour debugging.

BUT…

One thing I particularly rely on is its “tty” mode, which writes
directly to the current terminal when active. This is particularly handy
when debugging a test suite. For example, pytest intercepts stderr
and … prints it at the end, or drops it on the floor or something. If
I’m running my (failing) tests that way, the X() output still comes up
immediately in bright yellow. Ideally, usefully just before the test
explodes.

So my dev environment (these days, usually configured with direnv)
sets these modes with environment variables. Using direnv, these
.envrc files:

CSS[~/hg/css-solar(hg:solar)]fleet2*> cat .envrc
source_env ..
export SPLINK_DATADIR=$PWD/spd
export SPLINK_FETCH_SOURCE=solar-lan:/cygdrive/c/Users/CSKK/SP-LINK/CSKK
CSS[~/hg/css-solar(hg:solar)]fleet2*> cat ../.envrc
export CS_X_VIA_TTY=1
export CS_X_COLOUR=yellow
export CS_X_BUILTIN=1

so locally there’s some SPLINK* envvars associated with the code I’m
working on, and the parent dir has CS_X_* envvars setting my usual
debug modes, common to all my checkouts. The 3 above:

  • make X() write to /dev/tty (bypassing any stderr interception,
    such as test suites and command line redirections)
  • make X() write bright yellow messages, easy to see in the output
  • stuffs the name X into the builtins namespace! which means I can
    just put X(...) calls in other modules without bothering with an
    import

And that last is the tie in to this namespace discussion :slight_smile:

The cs.x module is available on PyPI if you care. Or source here:
https://hg.sr.ht/~cameron-simpson/css/browse/lib/python/cs/x.py

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like