Skip to content
Snippets Groups Projects
Commit 1a184198 authored by Thomas Goirand's avatar Thomas Goirand
Browse files

New upstream version 0.1.6

parents
No related branches found
No related tags found
No related merge requests found
LICENSE 0 → 100644
Copyright (c) 2014-2015 Markus Unterwaditzer & contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
global-exclude *.py[cdo] __pycache__ *.so *.pyd
include LICENSE
PKG-INFO 0 → 100644
Metadata-Version: 1.0
Name: click-repl
Version: 0.1.6
Summary: REPL plugin for Click
Home-page: https://github.com/untitaker/click-repl
Author: Markus Unterwaditzer
Author-email: markus@unterwaditzer.net
License: MIT
Description: UNKNOWN
Platform: UNKNOWN
==========
click-repl
==========
.. image:: https://travis-ci.org/click-contrib/click-repl.svg?branch=master
:target: https://travis-ci.org/click-contrib/click-repl
In your click_ app:
.. code:: python
import click
from click_repl import register_repl
@click.group()
def cli():
pass
@cli.command()
def hello():
click.echo("Hello world!")
register_repl(cli)
cli()
In the shell::
$ my_app repl
> hello
Hello world!
> ^C
$ echo hello | my_app repl
Hello world!
Features not shown:
* Tab-completion.
* The parent context is reused, which means ``ctx.obj`` persists between
subcommands. If you're keeping caches on that object (like I do), using the
app's repl instead of the shell is a huge performance win.
* ``!``-prefix executes shell commands.
You can use the internal ``:help`` command to explain usage.
PyPI: `<https://pypi.python.org/pypi/click-repl>`_
.. _click: http://click.pocoo.org/
Advanced Usage
==============
For more flexibility over how your REPL works you can use the ``repl`` function
directly instead of ``register_repl``. For example, in your app:
.. code:: python
import click
from click_repl import repl
from prompt_toolkit.history import FileHistory
@click.group()
def cli():
pass
@cli.command()
def myrepl():
prompt_kwargs = {
'history': FileHistory('/etc/myrepl/myrepl-history'),
}
repl(click.get_current_context(), prompt_kwargs=prompt_kwargs)
cli()
And then your custom ``myrepl`` command will be available on your CLI, which
will start a REPL which has its history stored in
``/etc/myrepl/myrepl-history`` and persist between sessions.
Any arguments that can be passed to the ``python-prompt-toolkit`` Prompt_ class
can be passed in the ``prompt_kwargs`` argument and will be used when
instantiating your ``Prompt``.
.. _Prompt: http://python-prompt-toolkit.readthedocs.io/en/stable/pages/reference.html?prompt_toolkit.shortcuts.Prompt#prompt_toolkit.shortcuts.Prompt
License
=======
Licensed under the MIT, see ``LICENSE``.
Metadata-Version: 1.0
Name: click-repl
Version: 0.1.6
Summary: REPL plugin for Click
Home-page: https://github.com/untitaker/click-repl
Author: Markus Unterwaditzer
Author-email: markus@unterwaditzer.net
License: MIT
Description: UNKNOWN
Platform: UNKNOWN
LICENSE
MANIFEST.in
README.rst
setup.py
click_repl/__init__.py
click_repl/exceptions.py
click_repl.egg-info/PKG-INFO
click_repl.egg-info/SOURCES.txt
click_repl.egg-info/dependency_links.txt
click_repl.egg-info/requires.txt
click_repl.egg-info/top_level.txt
\ No newline at end of file
click
prompt_toolkit
six
click_repl
from collections import defaultdict
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.history import InMemoryHistory
from prompt_toolkit.shortcuts import prompt
import click
import click._bashcomplete
import click.parser
import os
import shlex
import sys
import six
from .exceptions import InternalCommandException, ExitReplException # noqa
# Handle click.exceptions.Exit introduced in Click 7.0
try:
from click.exceptions import Exit as ClickExit
except ImportError:
class ClickExit(RuntimeError):
pass
PY2 = sys.version_info[0] == 2
if PY2:
text_type = unicode # noqa
else:
text_type = str # noqa
__version__ = "0.1.6"
_internal_commands = dict()
def _register_internal_command(names, target, description=None):
if not hasattr(target, "__call__"):
raise ValueError("Internal command must be a callable")
if isinstance(names, six.string_types):
names = [names]
elif not isinstance(names, (list, tuple)):
raise ValueError('"names" must be a string or a list / tuple')
for name in names:
_internal_commands[name] = (target, description)
def _get_registered_target(name, default=None):
target_info = _internal_commands.get(name)
if target_info:
return target_info[0]
return default
def _exit_internal():
raise ExitReplException()
def _help_internal():
formatter = click.HelpFormatter()
formatter.write_heading("REPL help")
formatter.indent()
with formatter.section("External Commands"):
formatter.write_text('prefix external commands with "!"')
with formatter.section("Internal Commands"):
formatter.write_text('prefix internal commands with ":"')
info_table = defaultdict(list)
for mnemonic, target_info in six.iteritems(_internal_commands):
info_table[target_info[1]].append(mnemonic)
formatter.write_dl(
(
", ".join((":{0}".format(mnemonic) for mnemonic in sorted(mnemonics))),
description,
)
for description, mnemonics in six.iteritems(info_table)
)
return formatter.getvalue()
_register_internal_command(["q", "quit", "exit"], _exit_internal, "exits the repl")
_register_internal_command(
["?", "h", "help"], _help_internal, "displays general help information"
)
class ClickCompleter(Completer):
def __init__(self, cli):
self.cli = cli
def get_completions(self, document, complete_event=None):
# Code analogous to click._bashcomplete.do_complete
try:
args = shlex.split(document.text_before_cursor)
except ValueError:
# Invalid command, perhaps caused by missing closing quotation.
return
cursor_within_command = (
document.text_before_cursor.rstrip() == document.text_before_cursor
)
if args and cursor_within_command:
# We've entered some text and no space, give completions for the
# current word.
incomplete = args.pop()
else:
# We've not entered anything, either at all or for the current
# command, so give all relevant completions for this context.
incomplete = ""
ctx = click._bashcomplete.resolve_ctx(self.cli, "", args)
if ctx is None:
return
choices = []
for param in ctx.command.params:
if isinstance(param, click.Option):
for options in (param.opts, param.secondary_opts):
for o in options:
choices.append(
Completion(
text_type(o), -len(incomplete), display_meta=param.help
)
)
elif isinstance(param, click.Argument):
if isinstance(param.type, click.Choice):
for choice in param.type.choices:
choices.append(Completion(text_type(choice), -len(incomplete)))
if isinstance(ctx.command, click.MultiCommand):
for name in ctx.command.list_commands(ctx):
command = ctx.command.get_command(ctx, name)
choices.append(
Completion(
text_type(name),
-len(incomplete),
display_meta=getattr(command, "short_help"),
)
)
for item in choices:
if item.text.startswith(incomplete):
yield item
def bootstrap_prompt(prompt_kwargs, group):
"""
Bootstrap prompt_toolkit kwargs or use user defined values.
:param prompt_kwargs: The user specified prompt kwargs.
"""
prompt_kwargs = prompt_kwargs or {}
defaults = {
"history": InMemoryHistory(),
"completer": ClickCompleter(group),
"message": u"> ",
}
for key in defaults:
default_value = defaults[key]
if key not in prompt_kwargs:
prompt_kwargs[key] = default_value
return prompt_kwargs
def repl( # noqa: C901
old_ctx,
prompt_kwargs=None,
allow_system_commands=True,
allow_internal_commands=True,
):
"""
Start an interactive shell. All subcommands are available in it.
:param old_ctx: The current Click context.
:param prompt_kwargs: Parameters passed to
:py:func:`prompt_toolkit.shortcuts.prompt`.
If stdin is not a TTY, no prompt will be printed, but only commands read
from stdin.
"""
# parent should be available, but we're not going to bother if not
group_ctx = old_ctx.parent or old_ctx
group = group_ctx.command
isatty = sys.stdin.isatty()
# Delete the REPL command from those available, as we don't want to allow
# nesting REPLs (note: pass `None` to `pop` as we don't want to error if
# REPL command already not present for some reason).
repl_command_name = old_ctx.command.name
if isinstance(group_ctx.command, click.CommandCollection):
available_commands = {
cmd_name: cmd_obj
for source in group_ctx.command.sources
for cmd_name, cmd_obj in source.commands.items()
}
else:
available_commands = group_ctx.command.commands
available_commands.pop(repl_command_name, None)
prompt_kwargs = bootstrap_prompt(prompt_kwargs, group)
if isatty:
def get_command():
return prompt(**prompt_kwargs)
else:
get_command = sys.stdin.readline
while True:
try:
command = get_command()
except KeyboardInterrupt:
continue
except EOFError:
break
if not command:
if isatty:
continue
else:
break
if allow_system_commands and dispatch_repl_commands(command):
continue
if allow_internal_commands:
try:
result = handle_internal_commands(command)
if isinstance(result, six.string_types):
click.echo(result)
continue
except ExitReplException:
break
try:
args = shlex.split(command)
except ValueError as e:
click.echo("{}: {}".format(type(e).__name__, e))
continue
try:
with group.make_context(None, args, parent=group_ctx) as ctx:
group.invoke(ctx)
ctx.exit()
except click.ClickException as e:
e.show()
except ClickExit:
pass
except SystemExit:
pass
except ExitReplException:
break
def register_repl(group, name="repl"):
"""Register :func:`repl()` as sub-command *name* of *group*."""
group.command(name=name)(click.pass_context(repl))
def exit():
"""Exit the repl"""
_exit_internal()
def dispatch_repl_commands(command):
"""Execute system commands entered in the repl.
System commands are all commands starting with "!".
"""
if command.startswith("!"):
os.system(command[1:])
return True
return False
def handle_internal_commands(command):
"""Run repl-internal commands.
Repl-internal commands are all commands starting with ":".
"""
if command.startswith(":"):
target = _get_registered_target(command[1:], default=None)
if target:
return target()
class InternalCommandException(Exception):
pass
class ExitReplException(InternalCommandException):
pass
[egg_info]
tag_build =
tag_date = 0
setup.py 0 → 100644
#!/usr/bin/env python
import ast
import re
from setuptools import setup
_version_re = re.compile(r"__version__\s+=\s+(.*)")
with open("click_repl/__init__.py", "rb") as f:
version = str(
ast.literal_eval(_version_re.search(f.read().decode("utf-8")).group(1))
)
setup(
name="click-repl",
version=version,
description="REPL plugin for Click",
author="Markus Unterwaditzer",
author_email="markus@unterwaditzer.net",
url="https://github.com/untitaker/click-repl",
license="MIT",
packages=["click_repl"],
install_requires=["click", "prompt_toolkit", "six"],
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment