Skip to main content

A Redis-backed REPL that saves command history, output, & errors

Project description

Install

Install Redis and start server

% sudo apt-get install -y redis-server

or

% brew install redis@3.2
% brew services start redis@3.2

Install with pip

% pip3 install chloop

Usage

The GetCharLoop class is provided by the chloop package. Calling an instance of this class starts a REPL session, which the user can end by pressing Ctrl + d or Ctrl + c.

See the Example section below.

The first character you type at the REPL prompt is significant.

The colon

Hitting the : key at the prompt will allow you to enter a command and any arguments you need to pass to that command.

  • :docstrings to view docstrings of methods defined on the class

  • :errors to view colon commands that raised exceptions

  • :history view colon commands issued

  • :pdb to start a pdb session (debugging/inspection)

  • :ipython to start ipython shell

  • :shortcuts to view hotkey shortcuts

Any methods added to your sub-class of GetCharLoop are callable as colon commands, as long as they do not start with an underscore (_). Methods should only accept ``*args``, if anything.

For any methods/commands that should not be logged to the history, append the method name to the end of the self._DONT_LOG_CMDS list.

The dash

Hitting the - key at the prompt will allow you to type a note.

The question mark

Hitting the ? key at the prompt will display the class docstring(s) and the startup message.

Other keys

Hitting any other key at the prompt will do one of the following:

  • call a registered shortcut function bound to the key (use :shortcuts command to see what is available)

  • display the character and its integer ordinal

A hotkey can be bound to any callable object that accepts no arguments.

Use functools.partial (if necessary) to create a callable accepting no arguments.

Adding hotkeys (simple)

  • call the _add_hotkey method on your instance of GetCharLoop (or sub-class) with the following args

    • ch: character hotkey

    • func: callable object that accepts no arguments

    • help_string: a string containing short help text for hotkey

Adding hotkeys (when using callables on self)

  • call the self._chfunc_dict_update method in the __init__ method of your subclass with a list of tuples or a dict.

    • the keys of the dict (or first items in list of tuples) are the hotkey characters

    • the values of the dict (or second items in list of tuples) are 2-item tuples

      • 1st item is a callable that accepts no arguments

      • 2nd item is a short help string

        Note: when passing a dict, the items will be inserted in the alphabetical order of the help string.

Basic example

% python3 -c 'from chloop import GetCharLoop; GetCharLoop()()'

> :docstrings
======================================================================
Loop forever, receiving character input from user and performing actions

    - ^d or ^c to break the loop
    - ':' to enter a command (and any arguments)
        - the name of the command should be monkeypatched on the GetCharLoop
          instance, or be a defined method on a GetCharLoop sub-class
        - the function bound to `:command` should accept `*args` only
    - '-' to receive an input line from user (a note)
    - '?' to show the class docstring(s) and the startup message

.:: docstrings ::.
Print/return the docstrings of methods defined on this class

.:: errors ::.
Print/return any colon commands that raised exceptions (w/ traceback)

.:: history ::.
Print/return colon commands used

.:: ipython ::.
Start ipython shell. To continue back to the input loop, use 'ctrl + d'

.:: pdb ::.
Start pdb (debugger). To continue back to the input loop, use 'c'

.:: shortcuts ::.
Print/return any hotkey shortcuts defined on this class



> :pdb
[10] > /tmp/ch/venv/lib/python3.5/site-packages/chloop/__init__.py(90)__call__()
-> continue
(Pdb++) l
 85                     cmd = user_input.split()[0]
 86                     args = user_input.split()[1:]
 87
 88                     if cmd == 'pdb':
 89                         import pdb; pdb.set_trace()
 90  ->                     continue
 91
 92                     if cmd == 'ipython':
 93                         from IPython import embed; embed()
 94                         continue
 95
(Pdb++) self._collection
Collection('chloop-log', 'default', index_fields='cmd,status,error_type', json_fields='args,value')
(Pdb++) self._collection.keyspace
[]
(Pdb++) c

> :ipython
Python 3.5.1+ (default, Mar 30 2016, 22:46:26)
Type "copyright", "credits" or "license" for more information.

IPython 5.2.2 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.


In [1]: self._collection
Out[1]: Collection('chloop-log', 'default', index_fields='cmd,status,error_type', json_fields='args,value')

In [2]: self.shortcuts
Out[2]: <bound method GetCharLoop.shortcuts of <chloop.GetCharLoop object at 0x7f9f8ff5f5f8>>

In [3]: self.docstrings
Out[3]: <bound method GetCharLoop.docstrings of <chloop.GetCharLoop object at 0x7f9f8ff5f5f8>>

In [4]:
Do you really want to exit ([y]/n)? y


> :shortcuts


> - there are no shortcuts defined by default

>

Sub-class example

  • Import GetCharLoop and sub-class it

  • Initialize the sub-class and call it

    Save the following to mine.py

from functools import partial
from chloop import GetCharLoop


class Mine(GetCharLoop):
    """A sub-class of GetCharLoop"""
    def __init__(self, *args, **kwargs):
        # Process any extra/custom kwargs here and set some attributes
        self._mything = kwargs.pop('mything', 'some default value')

        super(Mine, self).__init__(*args, **kwargs)

        # Add some single-key shorcuts that call methods on `self`
        self._chfunc_dict_update([
            ('h', (self.history,
                  'display recent command history')),
            ('e', (self.errors,
                  'display recent errors')),
        ])


    def somefunc(self, *args):
        """Joins the args passed to it into a string"""
        args_as_one = ' '.join(args)
        print(repr(args_as_one))
        return args_as_one

    def lame(self):
        """raise exception"""
        return 1/0


if __name__ == '__main__':
    m = Mine(prompt='\nmyprompt> ')
    m._add_hotkey('a', lambda: print('hello'), 'say hello')
    m()

Interact with the REPL

Assuming the above code is in a file called mine.py

% python mine.py

myprompt> :somefunc here are some args
u'here are some args'

myprompt> :shortcuts
'e' -- display recent errors
'h' -- display recent command history
'a' -- say hello

myprompt> a
hello

myprompt> :lame
======================================================================
Traceback (most recent call last):
  File "/home/ken/chloop/chloop/__init__.py", line 232, in __call__
    value = cmd_func()
  File "main.py", line 33, in lame
    return 1/0
ZeroDivisionError: integer division or modulo by zero

cmd: u'lame'
args: []

myprompt> :pdb
...

myprompt> e
(errors output)

myprompt> - here is a note

myprompt> - here is another note

myprompt>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

chloop-0.2.15-py3-none-any.whl (11.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page