chloop


Namechloop JSON
Version 0.2.23 PyPI version JSON
download
home_pagehttps://github.com/kenjyco/chloop
SummaryA Redis-backed REPL that saves command history, output, & errors
upload_time2023-07-10 04:57:59
maintainer
docs_urlNone
authorKen
requires_python
licenseMIT
keywords repl redis cli command-line command history kenjyco
VCS
bugtrack_url
requirements bg-helper click fs-helper redis-helper
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Install
-------

If you don’t have `docker <https://docs.docker.com/get-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>



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/kenjyco/chloop",
    "name": "chloop",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "repl,redis,cli,command-line,command,history,kenjyco",
    "author": "Ken",
    "author_email": "kenjyco@gmail.com",
    "download_url": "https://github.com/kenjyco/chloop/tarball/v0.2.23",
    "platform": null,
    "description": "Install\n-------\n\nIf you don\u2019t have `docker <https://docs.docker.com/get-docker>`__\ninstalled, install Redis and start server\n\n::\n\n   % sudo apt-get install -y redis-server\n\n   or\n\n   % brew install redis\n   % brew services start redis\n\nInstall with ``pip``\n\n::\n\n   % pip3 install chloop\n\n..\n\n   Optionally install ipython with ``pip3 install ipython`` to enable\n   ``:ipython`` colon command on a GetCharLoop instance. Also\n   ``pip3 install pdbpp`` for an improved debug experience when using\n   ``:pdb`` colon command.\n\nUsage\n-----\n\nThe ``GetCharLoop`` class is provided by the ``chloop`` package. Calling\nan **instance** of this class starts a REPL session, which the user can\nend by pressing ``Ctrl`` + ``d`` or ``Ctrl`` + ``c``.\n\n   See the **Example** section below.\n\nThe **first** character you type at the REPL prompt is significant.\n\nThe colon\n^^^^^^^^^\n\nHitting the ``:`` key at the prompt will allow you to enter a command\nand any arguments you need to pass to that command.\n\n-  ``:docstrings`` to view docstrings of methods defined on the class\n-  ``:errors`` to view colon commands that raised exceptions\n-  ``:history`` view colon commands issued\n-  ``:pdb`` to start a pdb session (debugging/inspection)\n-  ``:ipython`` to start ipython shell\n-  ``:shortcuts`` to view hotkey shortcuts\n\nAny methods added to your sub-class of ``GetCharLoop`` are callable as\n**colon commands**, as long as they do not start with an underscore\n(``_``). Methods should **only accept ``*args``**, if anything.\n\nFor any methods/commands that should not be logged to the history,\nappend the method name to the end of the ``self._DONT_LOG_CMDS`` list.\n\nThe dash\n^^^^^^^^\n\nHitting the ``-`` key at the prompt will allow you to type a note.\n\nThe question mark\n^^^^^^^^^^^^^^^^^\n\nHitting the ``?`` key at the prompt will display the class docstring(s)\nand the startup message.\n\nOther keys\n^^^^^^^^^^\n\nHitting any other key at the prompt will do one of the following:\n\n-  call a **registered shortcut function** bound to the key (use\n   ``:shortcuts`` command to see what is available)\n-  display the character and its integer ordinal\n\nA hotkey can be bound to any callable object that accepts no arguments.\n\n   Use ``functools.partial`` (if necessary) to create a callable\n   accepting no arguments.\n\nAdding hotkeys (simple)\n\n-  call the ``_add_hotkey`` method on your instance of ``GetCharLoop``\n   (or sub-class) with the following args\n\n   -  ``ch``: character hotkey\n   -  ``func``: callable object that accepts no arguments\n   -  ``help_string``: a string containing short help text for hotkey\n\nAdding hotkeys (when using callables on ``self``)\n\n-  call the ``self._chfunc_dict_update`` method in the ``__init__``\n   method of your subclass with a list of tuples or a dict.\n\n   -  the keys of the dict (or first items in list of tuples) are the\n      hotkey characters\n   -  the values of the dict (or second items in list of tuples) are\n      2-item tuples\n\n      -  1st item is a **callable** that accepts no arguments\n      -  2nd item is a short help string\n\n      ..\n\n         Note: when passing a dict, the items will be inserted in the\n         alphabetical order of the help string.\n\nBasic example\n-------------\n\n::\n\n   % python3 -c 'from chloop import GetCharLoop; GetCharLoop()()'\n\n   > :docstrings\n   ======================================================================\n   Loop forever, receiving character input from user and performing actions\n\n       - ^d or ^c to break the loop\n       - ':' to enter a command (and any arguments)\n           - the name of the command should be monkeypatched on the GetCharLoop\n             instance, or be a defined method on a GetCharLoop sub-class\n           - the function bound to `:command` should accept `*args` only\n       - '-' to receive an input line from user (a note)\n       - '?' to show the class docstring(s) and the startup message\n\n   .:: docstrings ::.\n   Print/return the docstrings of methods defined on this class\n\n   .:: errors ::.\n   Print/return any colon commands that raised exceptions (w/ traceback)\n\n   .:: history ::.\n   Print/return colon commands used\n\n   .:: ipython ::.\n   Start ipython shell. To continue back to the input loop, use 'ctrl + d'\n\n   .:: pdb ::.\n   Start pdb (debugger). To continue back to the input loop, use 'c'\n\n   .:: shortcuts ::.\n   Print/return any hotkey shortcuts defined on this class\n\n\n\n   > :pdb\n   [10] > /tmp/ch/venv/lib/python3.5/site-packages/chloop/__init__.py(90)__call__()\n   -> continue\n   (Pdb++) l\n    85                     cmd = user_input.split()[0]\n    86                     args = user_input.split()[1:]\n    87\n    88                     if cmd == 'pdb':\n    89                         import pdb; pdb.set_trace()\n    90  ->                     continue\n    91\n    92                     if cmd == 'ipython':\n    93                         from IPython import embed; embed()\n    94                         continue\n    95\n   (Pdb++) self._collection\n   Collection('chloop-log', 'default', index_fields='cmd,status,error_type', json_fields='args,value')\n   (Pdb++) self._collection.keyspace\n   []\n   (Pdb++) c\n\n   > :ipython\n   Python 3.5.1+ (default, Mar 30 2016, 22:46:26)\n   Type \"copyright\", \"credits\" or \"license\" for more information.\n\n   IPython 5.2.2 -- An enhanced Interactive Python.\n   ?         -> Introduction and overview of IPython's features.\n   %quickref -> Quick reference.\n   help      -> Python's own help system.\n   object?   -> Details about 'object', use 'object??' for extra details.\n\n\n   In [1]: self._collection\n   Out[1]: Collection('chloop-log', 'default', index_fields='cmd,status,error_type', json_fields='args,value')\n\n   In [2]: self.shortcuts\n   Out[2]: <bound method GetCharLoop.shortcuts of <chloop.GetCharLoop object at 0x7f9f8ff5f5f8>>\n\n   In [3]: self.docstrings\n   Out[3]: <bound method GetCharLoop.docstrings of <chloop.GetCharLoop object at 0x7f9f8ff5f5f8>>\n\n   In [4]:\n   Do you really want to exit ([y]/n)? y\n\n\n   > :shortcuts\n\n\n   > - there are no shortcuts defined by default\n\n   >\n\nSub-class example\n-----------------\n\n-  Import ``GetCharLoop`` and sub-class it\n-  Initialize the sub-class and call it\n\n..\n\n   Save the following to ``mine.py``\n\n::\n\n   from functools import partial\n   from chloop import GetCharLoop\n\n\n   class Mine(GetCharLoop):\n       \"\"\"A sub-class of GetCharLoop\"\"\"\n       def __init__(self, *args, **kwargs):\n           # Process any extra/custom kwargs here and set some attributes\n           self._mything = kwargs.pop('mything', 'some default value')\n\n           super(Mine, self).__init__(*args, **kwargs)\n\n           # Add some single-key shorcuts that call methods on `self`\n           self._chfunc_dict_update([\n               ('h', (self.history,\n                     'display recent command history')),\n               ('e', (self.errors,\n                     'display recent errors')),\n           ])\n\n\n       def somefunc(self, *args):\n           \"\"\"Joins the args passed to it into a string\"\"\"\n           args_as_one = ' '.join(args)\n           print(repr(args_as_one))\n           return args_as_one\n\n       def lame(self):\n           \"\"\"raise exception\"\"\"\n           return 1/0\n\n\n   if __name__ == '__main__':\n       m = Mine(prompt='\\nmyprompt> ')\n       m._add_hotkey('a', lambda: print('hello'), 'say hello')\n       m()\n\nInteract with the REPL\n^^^^^^^^^^^^^^^^^^^^^^\n\n   Assuming the above code is in a file called ``mine.py``\n\n::\n\n   % python mine.py\n\n   myprompt> :somefunc here are some args\n   u'here are some args'\n\n   myprompt> :shortcuts\n   'e' -- display recent errors\n   'h' -- display recent command history\n   'a' -- say hello\n\n   myprompt> a\n   hello\n\n   myprompt> :lame\n   ======================================================================\n   Traceback (most recent call last):\n     File \"/home/ken/chloop/chloop/__init__.py\", line 232, in __call__\n       value = cmd_func()\n     File \"main.py\", line 33, in lame\n       return 1/0\n   ZeroDivisionError: integer division or modulo by zero\n\n   cmd: u'lame'\n   args: []\n\n   myprompt> :pdb\n   ...\n\n   myprompt> e\n   (errors output)\n\n   myprompt> - here is a note\n\n   myprompt> - here is another note\n\n   myprompt>\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A Redis-backed REPL that saves command history, output, & errors",
    "version": "0.2.23",
    "project_urls": {
        "Download": "https://github.com/kenjyco/chloop/tarball/v0.2.23",
        "Homepage": "https://github.com/kenjyco/chloop"
    },
    "split_keywords": [
        "repl",
        "redis",
        "cli",
        "command-line",
        "command",
        "history",
        "kenjyco"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9b5a130bc593ca18cc365d4a001a750b71da0ef611403e55db229cdb1cc14d54",
                "md5": "afc095455d3451e0647807643c604e43",
                "sha256": "85f4d7e8db5c361550c16d7d7ec5ffe71204c690f9957a51be523512af1e4ec4"
            },
            "downloads": -1,
            "filename": "chloop-0.2.23-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "afc095455d3451e0647807643c604e43",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 8315,
            "upload_time": "2023-07-10T04:57:59",
            "upload_time_iso_8601": "2023-07-10T04:57:59.865361Z",
            "url": "https://files.pythonhosted.org/packages/9b/5a/130bc593ca18cc365d4a001a750b71da0ef611403e55db229cdb1cc14d54/chloop-0.2.23-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-07-10 04:57:59",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "kenjyco",
    "github_project": "chloop",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "bg-helper",
            "specs": []
        },
        {
            "name": "click",
            "specs": [
                [
                    ">=",
                    "6.0"
                ]
            ]
        },
        {
            "name": "fs-helper",
            "specs": []
        },
        {
            "name": "redis-helper",
            "specs": []
        }
    ],
    "lcname": "chloop"
}
        
Ken
Elapsed time: 0.09038s