Search code examples
pythonkeywordbareword

Bare words / new keywords in Python


I wanted to see if it was possible to define new keywords or, as they're called in Destroy All Software's "WAT" talk when discussing Ruby, bare words, in Python.

I came up with an answer that I couldn't find elsewhere, so I decided to share it Q&A style on StackOverflow.


Solution

  • I've only tried this in the REPL, outside any block, so far. It may be possible to make it work elsewhere, too.

    I put this in my python startup file:

    import sys, traceback
    
    def bareWordsHandler(type_, value, traceback_):
        if isinstance(value, SyntaxError):
            import traceback
    
            # You can probably modify this next line so that it'll work within blocks, as well as outside them:
            bareWords = traceback.format_exception(type_, value, traceback_)[1].split()
    
            # At this point we have the raw string that was entered.
            # Use whatever logic you want on it to decide what to do.
            if bareWords[0] == 'Awesome':
                print(' '.join(bareWords[1:]).upper() + '!')
                return
        bareWordsHandler.originalExceptHookFunction(type_, value, traceback_)
    
    bareWordsHandler.originalExceptHookFunction = sys.excepthook
    sys.excepthook = bareWordsHandler
    

    Quick REPL session demonstration afterwords:

    >>> Awesome bare words
    BARE WORDS!
    

    Use responsibly.

    Edit: Here's a more useful example. I added in a run keyword.

    if bareWords[0] == 'from' and bareWords[2] == 'run':
            atPrompt.autoRun = ['from ' + bareWords[1] + ' import ' + bareWords[3].split('(')[0],
                                ' '.join(bareWords[3:])]
            return
    

    atPrompt.autoRun is a list of variables that, when my prompt is displayed, will automatically be checked and fed back. So, for example, I can do this:

    >>> from loadBalanceTester run loadBalancerTest(runJar = False)
    

    And this gets interpreted as:

    from loadBalancerTest import loadBalancerTest
    loadBalancerTest(runJar = False)
    

    It's kind of like a macro - it's common for me to want to do this kind of thing, so I decided to add in a keyword that lets me do it in fewer keystrokes.