Jonathan Eunice  committed 59ab8d5

added caller_fmt()

  • Participants
  • Parent commits 1ffa82b

Comments (0)

Files changed (4)

 import print_function`` hassle.
 ``say`` attempts to mask some of the quirky compexities of the 2-to-3 divide,
-such as string encodings and codec use. 
+such as string encodings and codec use.
+Your Own Iterpolators
+If you want to write your own functions that take strings and interpolate ``{}``
+format tempaltes in them, you can look at ``say`` souce code and see how to
+do it (see e.g. ``say.text.Text``). But there's an easier way:
+    from say import caller_fmt
+    def ucfmt(s):
+        return caller_fmt(s).upper()
+If ``ucfmt()`` had used ``fmt()``, it would not have worked. ``fmt()`` would
+look for interpolating values within the context of ``ucfmt()`` and, not finding
+any, probably raised an exception. But using ``caller_fmt()`` it looks into the
+context of the caller of ``ucfmt()``, which is exactly where those values would
+reside. *Voila!*
 fmt = Say(encoding=None, retvalue=True, silent=True)
+# TODO: fmt() is such a core feature - maybe a subclas not just an instance configuration?
+def caller_fmt(*args, **kwargs):
+    """
+    Like fmt(), but iterpolating strings not from the caller's context, but the caller's caller's
+    context.  It sounds uber meta, but it helps easily make other routines be able to do what
+    fmt() can do.
+    """
+    kwargs['_callframe'] = inspect.currentframe().f_back.f_back
+    return fmt(*args, **kwargs)
-    version=verno("0.875"),
+    version=verno("0.877"),
     author='Jonathan Eunice',
     description='Super-simple templated printing. E.g.: say("Hello, {whoever}!", indent=1)',

File test/

 import six, os
-from say import Say, fmt, stdout
+from say import Say, fmt, stdout, caller_fmt
 globalvar = 99
     assert say('abc\ndef\nghi', wrap=79) == 'abc def ghi'
     assert say("abcde abcde abcde", wrap=6) == 'abcde\nabcde\nabcde'
-    assert say("abcde abcde abcde", wrap=10, indent=1) == '    abcde\n    abcde\n    abcde'
+    assert say("abcde abcde abcde", wrap=10, indent=1) == '    abcde\n    abcde\n    abcde'
+def test_caller_fmt():
+    def ucfmt(s):
+        return caller_fmt(s).upper()
+    x = 12
+    y = 'x'
+    assert ucfmt("{y!r} is {x}") == "'X' IS 12"