A Redis-backed REPL that saves command history, output, & errors
Project description
Install
If you don’t have docker installed, install Redis and start server
% sudo apt-get install -y redis-server or % brew install redis % brew services start redis
Install with pip
% pip3 install chloop
Optionally install ipython with pip3 install ipython to enable :ipython colon command on a GetCharLoop instance. Also pip3 install pdbpp for an improved debug experience when using :pdb colon command.
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file chloop-0.2.23-py3-none-any.whl
.
File metadata
- Download URL: chloop-0.2.23-py3-none-any.whl
- Upload date:
- Size: 8.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 85f4d7e8db5c361550c16d7d7ec5ffe71204c690f9957a51be523512af1e4ec4 |
|
MD5 | afc095455d3451e0647807643c604e43 |
|
BLAKE2b-256 | 9b5a130bc593ca18cc365d4a001a750b71da0ef611403e55db229cdb1cc14d54 |