diff options
Diffstat (limited to 'third_party/python/Click/examples')
39 files changed, 1282 insertions, 0 deletions
diff --git a/third_party/python/Click/examples/README b/third_party/python/Click/examples/README new file mode 100644 index 0000000000..6be32961f4 --- /dev/null +++ b/third_party/python/Click/examples/README @@ -0,0 +1,12 @@ +Click Examples + + This folder contains various Click examples. Note that + all of these are not runnable by themselves but should be + installed into a virtualenv. + + This is done this way so that scripts also properly work + on Windows and in virtualenvs without accidentally executing + through the wrong interpreter. + + For more information about this see the documentation: + https://click.palletsprojects.com/en/7.x/setuptools/ diff --git a/third_party/python/Click/examples/aliases/README b/third_party/python/Click/examples/aliases/README new file mode 100644 index 0000000000..5a4a066566 --- /dev/null +++ b/third_party/python/Click/examples/aliases/README @@ -0,0 +1,17 @@ +$ aliases_ + + aliases is a fairly advanced example that shows how + to implement command aliases with Click. It uses a + subclass of the default group to customize how commands + are located. + + It supports both aliases read from a config file as well + as automatic abbreviations. + + The aliases from the config are read from the aliases.ini + file. Try `aliases st` and `aliases ci`! + +Usage: + + $ pip install --editable . + $ aliases --help diff --git a/third_party/python/Click/examples/aliases/aliases.ini b/third_party/python/Click/examples/aliases/aliases.ini new file mode 100644 index 0000000000..4f1d54cd6b --- /dev/null +++ b/third_party/python/Click/examples/aliases/aliases.ini @@ -0,0 +1,2 @@ +[aliases] +ci=commit diff --git a/third_party/python/Click/examples/aliases/aliases.py b/third_party/python/Click/examples/aliases/aliases.py new file mode 100644 index 0000000000..38ef72c5c4 --- /dev/null +++ b/third_party/python/Click/examples/aliases/aliases.py @@ -0,0 +1,111 @@ +import os +import click + +try: + import ConfigParser as configparser +except ImportError: + import configparser + + +class Config(object): + """The config in this example only holds aliases.""" + + def __init__(self): + self.path = os.getcwd() + self.aliases = {} + + def read_config(self, filename): + parser = configparser.RawConfigParser() + parser.read([filename]) + try: + self.aliases.update(parser.items('aliases')) + except configparser.NoSectionError: + pass + + +pass_config = click.make_pass_decorator(Config, ensure=True) + + +class AliasedGroup(click.Group): + """This subclass of a group supports looking up aliases in a config + file and with a bit of magic. + """ + + def get_command(self, ctx, cmd_name): + # Step one: bulitin commands as normal + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + + # Step two: find the config object and ensure it's there. This + # will create the config object is missing. + cfg = ctx.ensure_object(Config) + + # Step three: lookup an explicit command aliase in the config + if cmd_name in cfg.aliases: + actual_cmd = cfg.aliases[cmd_name] + return click.Group.get_command(self, ctx, actual_cmd) + + # Alternative option: if we did not find an explicit alias we + # allow automatic abbreviation of the command. "status" for + # instance will match "st". We only allow that however if + # there is only one command. + matches = [x for x in self.list_commands(ctx) + if x.lower().startswith(cmd_name.lower())] + if not matches: + return None + elif len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + + +def read_config(ctx, param, value): + """Callback that is used whenever --config is passed. We use this to + always load the correct config. This means that the config is loaded + even if the group itself never executes so our aliases stay always + available. + """ + cfg = ctx.ensure_object(Config) + if value is None: + value = os.path.join(os.path.dirname(__file__), 'aliases.ini') + cfg.read_config(value) + return value + + +@click.command(cls=AliasedGroup) +@click.option('--config', type=click.Path(exists=True, dir_okay=False), + callback=read_config, expose_value=False, + help='The config file to use instead of the default.') +def cli(): + """An example application that supports aliases.""" + + +@cli.command() +def push(): + """Pushes changes.""" + click.echo('Push') + + +@cli.command() +def pull(): + """Pulls changes.""" + click.echo('Pull') + + +@cli.command() +def clone(): + """Clones a repository.""" + click.echo('Clone') + + +@cli.command() +def commit(): + """Commits pending changes.""" + click.echo('Commit') + + +@cli.command() +@pass_config +def status(config): + """Shows the status.""" + click.echo('Status for %s' % config.path) diff --git a/third_party/python/Click/examples/aliases/setup.py b/third_party/python/Click/examples/aliases/setup.py new file mode 100644 index 0000000000..8d1d6a4068 --- /dev/null +++ b/third_party/python/Click/examples/aliases/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup + +setup( + name='click-example-aliases', + version='1.0', + py_modules=['aliases'], + include_package_data=True, + install_requires=[ + 'click', + ], + entry_points=''' + [console_scripts] + aliases=aliases:cli + ''', +) diff --git a/third_party/python/Click/examples/bashcompletion/README b/third_party/python/Click/examples/bashcompletion/README new file mode 100644 index 0000000000..f8a0d51ef9 --- /dev/null +++ b/third_party/python/Click/examples/bashcompletion/README @@ -0,0 +1,12 @@ +$ bashcompletion + + bashcompletion is a simple example of an application that + tries to autocomplete commands, arguments and options. + + This example requires Click 2.0 or higher. + +Usage: + + $ pip install --editable . + $ eval "$(_BASHCOMPLETION_COMPLETE=source bashcompletion)" + $ bashcompletion --help diff --git a/third_party/python/Click/examples/bashcompletion/bashcompletion.py b/third_party/python/Click/examples/bashcompletion/bashcompletion.py new file mode 100644 index 0000000000..1072840035 --- /dev/null +++ b/third_party/python/Click/examples/bashcompletion/bashcompletion.py @@ -0,0 +1,45 @@ +import click +import os + + +@click.group() +def cli(): + pass + + +def get_env_vars(ctx, args, incomplete): + # Completions returned as strings do not have a description displayed. + for key in os.environ.keys(): + if incomplete in key: + yield key + + +@cli.command(help='A command to print environment variables') +@click.argument("envvar", type=click.STRING, autocompletion=get_env_vars) +def cmd1(envvar): + click.echo('Environment variable: %s' % envvar) + click.echo('Value: %s' % os.environ[envvar]) + + +@click.group(help='A group that holds a subcommand') +def group(): + pass + + +def list_users(ctx, args, incomplete): + # You can generate completions with descriptions by returning + # tuples in the form (completion, description). + users = [('bob', 'butcher'), + ('alice', 'baker'), + ('jerry', 'candlestick maker')] + # Ths will allow completion matches based on matches within the description string too! + return [user for user in users if incomplete in user[0] or incomplete in user[1]] + + +@group.command(help='Choose a user') +@click.argument("user", type=click.STRING, autocompletion=list_users) +def subcmd(user): + click.echo('Chosen user is %s' % user) + + +cli.add_command(group) diff --git a/third_party/python/Click/examples/bashcompletion/setup.py b/third_party/python/Click/examples/bashcompletion/setup.py new file mode 100644 index 0000000000..ad200818cd --- /dev/null +++ b/third_party/python/Click/examples/bashcompletion/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup + +setup( + name='click-example-bashcompletion', + version='1.0', + py_modules=['bashcompletion'], + include_package_data=True, + install_requires=[ + 'click', + ], + entry_points=''' + [console_scripts] + bashcompletion=bashcompletion:cli + ''', +) diff --git a/third_party/python/Click/examples/colors/README b/third_party/python/Click/examples/colors/README new file mode 100644 index 0000000000..4b5b44f696 --- /dev/null +++ b/third_party/python/Click/examples/colors/README @@ -0,0 +1,11 @@ +$ colors_ + + colors is a simple example that shows how you can + colorize text. + + For this to work on Windows, colorama is required. + +Usage: + + $ pip install --editable . + $ colors diff --git a/third_party/python/Click/examples/colors/colors.py b/third_party/python/Click/examples/colors/colors.py new file mode 100644 index 0000000000..193b927121 --- /dev/null +++ b/third_party/python/Click/examples/colors/colors.py @@ -0,0 +1,28 @@ +import click + + +all_colors = 'black', 'red', 'green', 'yellow', 'blue', 'magenta', \ + 'cyan', 'white', 'bright_black', 'bright_red', \ + 'bright_green', 'bright_yellow', 'bright_blue', \ + 'bright_magenta', 'bright_cyan', 'bright_white' + + +@click.command() +def cli(): + """This script prints some colors. If colorama is installed this will + also work on Windows. It will also automatically remove all ANSI + styles if data is piped into a file. + + Give it a try! + """ + for color in all_colors: + click.echo(click.style('I am colored %s' % color, fg=color)) + for color in all_colors: + click.echo(click.style('I am colored %s and bold' % color, + fg=color, bold=True)) + for color in all_colors: + click.echo(click.style('I am reverse colored %s' % color, fg=color, + reverse=True)) + + click.echo(click.style('I am blinking', blink=True)) + click.echo(click.style('I am underlined', underline=True)) diff --git a/third_party/python/Click/examples/colors/setup.py b/third_party/python/Click/examples/colors/setup.py new file mode 100644 index 0000000000..3f8e105fab --- /dev/null +++ b/third_party/python/Click/examples/colors/setup.py @@ -0,0 +1,17 @@ +from setuptools import setup + +setup( + name='click-example-colors', + version='1.0', + py_modules=['colors'], + include_package_data=True, + install_requires=[ + 'click', + # Colorama is only required for Windows. + 'colorama', + ], + entry_points=''' + [console_scripts] + colors=colors:cli + ''', +) diff --git a/third_party/python/Click/examples/complex/README b/third_party/python/Click/examples/complex/README new file mode 100644 index 0000000000..7eaac90372 --- /dev/null +++ b/third_party/python/Click/examples/complex/README @@ -0,0 +1,16 @@ +$ complex_ + + complex is an example of building very complex cli + applications that load subcommands dynamically from + a plugin folder and other things. + + All the commands are implemented as plugins in the + `complex.commands` package. If a python module is + placed named "cmd_foo" it will show up as "foo" + command and the `cli` object within it will be + loaded as nested Click command. + +Usage: + + $ pip install --editable . + $ complex --help diff --git a/third_party/python/Click/examples/complex/complex/__init__.py b/third_party/python/Click/examples/complex/complex/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/third_party/python/Click/examples/complex/complex/__init__.py diff --git a/third_party/python/Click/examples/complex/complex/cli.py b/third_party/python/Click/examples/complex/complex/cli.py new file mode 100644 index 0000000000..bcfd14a132 --- /dev/null +++ b/third_party/python/Click/examples/complex/complex/cli.py @@ -0,0 +1,65 @@ +import os +import sys +import click + + +CONTEXT_SETTINGS = dict(auto_envvar_prefix='COMPLEX') + + +class Context(object): + + def __init__(self): + self.verbose = False + self.home = os.getcwd() + + def log(self, msg, *args): + """Logs a message to stderr.""" + if args: + msg %= args + click.echo(msg, file=sys.stderr) + + def vlog(self, msg, *args): + """Logs a message to stderr only if verbose is enabled.""" + if self.verbose: + self.log(msg, *args) + + +pass_context = click.make_pass_decorator(Context, ensure=True) +cmd_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), + 'commands')) + + +class ComplexCLI(click.MultiCommand): + + def list_commands(self, ctx): + rv = [] + for filename in os.listdir(cmd_folder): + if filename.endswith('.py') and \ + filename.startswith('cmd_'): + rv.append(filename[4:-3]) + rv.sort() + return rv + + def get_command(self, ctx, name): + try: + if sys.version_info[0] == 2: + name = name.encode('ascii', 'replace') + mod = __import__('complex.commands.cmd_' + name, + None, None, ['cli']) + except ImportError: + return + return mod.cli + + +@click.command(cls=ComplexCLI, context_settings=CONTEXT_SETTINGS) +@click.option('--home', type=click.Path(exists=True, file_okay=False, + resolve_path=True), + help='Changes the folder to operate on.') +@click.option('-v', '--verbose', is_flag=True, + help='Enables verbose mode.') +@pass_context +def cli(ctx, verbose, home): + """A complex command line interface.""" + ctx.verbose = verbose + if home is not None: + ctx.home = home diff --git a/third_party/python/Click/examples/complex/complex/commands/__init__.py b/third_party/python/Click/examples/complex/complex/commands/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/third_party/python/Click/examples/complex/complex/commands/__init__.py diff --git a/third_party/python/Click/examples/complex/complex/commands/cmd_init.py b/third_party/python/Click/examples/complex/complex/commands/cmd_init.py new file mode 100644 index 0000000000..8c30186c3e --- /dev/null +++ b/third_party/python/Click/examples/complex/complex/commands/cmd_init.py @@ -0,0 +1,13 @@ +import click +from complex.cli import pass_context + + +@click.command('init', short_help='Initializes a repo.') +@click.argument('path', required=False, type=click.Path(resolve_path=True)) +@pass_context +def cli(ctx, path): + """Initializes a repository.""" + if path is None: + path = ctx.home + ctx.log('Initialized the repository in %s', + click.format_filename(path)) diff --git a/third_party/python/Click/examples/complex/complex/commands/cmd_status.py b/third_party/python/Click/examples/complex/complex/commands/cmd_status.py new file mode 100644 index 0000000000..99e736eee6 --- /dev/null +++ b/third_party/python/Click/examples/complex/complex/commands/cmd_status.py @@ -0,0 +1,10 @@ +import click +from complex.cli import pass_context + + +@click.command('status', short_help='Shows file changes.') +@pass_context +def cli(ctx): + """Shows file changes in the current working directory.""" + ctx.log('Changed files: none') + ctx.vlog('bla bla bla, debug info') diff --git a/third_party/python/Click/examples/complex/setup.py b/third_party/python/Click/examples/complex/setup.py new file mode 100644 index 0000000000..dee002c135 --- /dev/null +++ b/third_party/python/Click/examples/complex/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup + +setup( + name='click-example-complex', + version='1.0', + packages=['complex', 'complex.commands'], + include_package_data=True, + install_requires=[ + 'click', + ], + entry_points=''' + [console_scripts] + complex=complex.cli:cli + ''', +) diff --git a/third_party/python/Click/examples/imagepipe/.gitignore b/third_party/python/Click/examples/imagepipe/.gitignore new file mode 100644 index 0000000000..63280895b1 --- /dev/null +++ b/third_party/python/Click/examples/imagepipe/.gitignore @@ -0,0 +1 @@ +processed-* diff --git a/third_party/python/Click/examples/imagepipe/README b/third_party/python/Click/examples/imagepipe/README new file mode 100644 index 0000000000..91ec0cd26f --- /dev/null +++ b/third_party/python/Click/examples/imagepipe/README @@ -0,0 +1,13 @@ +$ imagepipe_ + + imagepipe is an example application that implements some + multi commands that chain image processing instructions + together. + + This requires pillow. + +Usage: + + $ pip install --editable . + $ imagepipe open -i example01.jpg resize -w 128 display + $ imagepipe open -i example02.jpg blur save diff --git a/third_party/python/Click/examples/imagepipe/example01.jpg b/third_party/python/Click/examples/imagepipe/example01.jpg Binary files differnew file mode 100644 index 0000000000..f2d9397755 --- /dev/null +++ b/third_party/python/Click/examples/imagepipe/example01.jpg diff --git a/third_party/python/Click/examples/imagepipe/example02.jpg b/third_party/python/Click/examples/imagepipe/example02.jpg Binary files differnew file mode 100644 index 0000000000..b1f802ed85 --- /dev/null +++ b/third_party/python/Click/examples/imagepipe/example02.jpg diff --git a/third_party/python/Click/examples/imagepipe/imagepipe.py b/third_party/python/Click/examples/imagepipe/imagepipe.py new file mode 100644 index 0000000000..37a1521133 --- /dev/null +++ b/third_party/python/Click/examples/imagepipe/imagepipe.py @@ -0,0 +1,266 @@ +import click +from functools import update_wrapper +from PIL import Image, ImageFilter, ImageEnhance + + +@click.group(chain=True) +def cli(): + """This script processes a bunch of images through pillow in a unix + pipe. One commands feeds into the next. + + Example: + + \b + imagepipe open -i example01.jpg resize -w 128 display + imagepipe open -i example02.jpg blur save + """ + + +@cli.resultcallback() +def process_commands(processors): + """This result callback is invoked with an iterable of all the chained + subcommands. As in this example each subcommand returns a function + we can chain them together to feed one into the other, similar to how + a pipe on unix works. + """ + # Start with an empty iterable. + stream = () + + # Pipe it through all stream processors. + for processor in processors: + stream = processor(stream) + + # Evaluate the stream and throw away the items. + for _ in stream: + pass + + +def processor(f): + """Helper decorator to rewrite a function so that it returns another + function from it. + """ + def new_func(*args, **kwargs): + def processor(stream): + return f(stream, *args, **kwargs) + return processor + return update_wrapper(new_func, f) + + +def generator(f): + """Similar to the :func:`processor` but passes through old values + unchanged and does not pass through the values as parameter. + """ + @processor + def new_func(stream, *args, **kwargs): + for item in stream: + yield item + for item in f(*args, **kwargs): + yield item + return update_wrapper(new_func, f) + + +def copy_filename(new, old): + new.filename = old.filename + return new + + +@cli.command('open') +@click.option('-i', '--image', 'images', type=click.Path(), + multiple=True, help='The image file to open.') +@generator +def open_cmd(images): + """Loads one or multiple images for processing. The input parameter + can be specified multiple times to load more than one image. + """ + for image in images: + try: + click.echo('Opening "%s"' % image) + if image == '-': + img = Image.open(click.get_binary_stdin()) + img.filename = '-' + else: + img = Image.open(image) + yield img + except Exception as e: + click.echo('Could not open image "%s": %s' % (image, e), err=True) + + +@cli.command('save') +@click.option('--filename', default='processed-%04d.png', type=click.Path(), + help='The format for the filename.', + show_default=True) +@processor +def save_cmd(images, filename): + """Saves all processed images to a series of files.""" + for idx, image in enumerate(images): + try: + fn = filename % (idx + 1) + click.echo('Saving "%s" as "%s"' % (image.filename, fn)) + yield image.save(fn) + except Exception as e: + click.echo('Could not save image "%s": %s' % + (image.filename, e), err=True) + + +@cli.command('display') +@processor +def display_cmd(images): + """Opens all images in an image viewer.""" + for image in images: + click.echo('Displaying "%s"' % image.filename) + image.show() + yield image + + +@cli.command('resize') +@click.option('-w', '--width', type=int, help='The new width of the image.') +@click.option('-h', '--height', type=int, help='The new height of the image.') +@processor +def resize_cmd(images, width, height): + """Resizes an image by fitting it into the box without changing + the aspect ratio. + """ + for image in images: + w, h = (width or image.size[0], height or image.size[1]) + click.echo('Resizing "%s" to %dx%d' % (image.filename, w, h)) + image.thumbnail((w, h)) + yield image + + +@cli.command('crop') +@click.option('-b', '--border', type=int, help='Crop the image from all ' + 'sides by this amount.') +@processor +def crop_cmd(images, border): + """Crops an image from all edges.""" + for image in images: + box = [0, 0, image.size[0], image.size[1]] + + if border is not None: + for idx, val in enumerate(box): + box[idx] = max(0, val - border) + click.echo('Cropping "%s" by %dpx' % (image.filename, border)) + yield copy_filename(image.crop(box), image) + else: + yield image + + +def convert_rotation(ctx, param, value): + if value is None: + return + value = value.lower() + if value in ('90', 'r', 'right'): + return (Image.ROTATE_90, 90) + if value in ('180', '-180'): + return (Image.ROTATE_180, 180) + if value in ('-90', '270', 'l', 'left'): + return (Image.ROTATE_270, 270) + raise click.BadParameter('invalid rotation "%s"' % value) + + +def convert_flip(ctx, param, value): + if value is None: + return + value = value.lower() + if value in ('lr', 'leftright'): + return (Image.FLIP_LEFT_RIGHT, 'left to right') + if value in ('tb', 'topbottom', 'upsidedown', 'ud'): + return (Image.FLIP_LEFT_RIGHT, 'top to bottom') + raise click.BadParameter('invalid flip "%s"' % value) + + +@cli.command('transpose') +@click.option('-r', '--rotate', callback=convert_rotation, + help='Rotates the image (in degrees)') +@click.option('-f', '--flip', callback=convert_flip, + help='Flips the image [LR / TB]') +@processor +def transpose_cmd(images, rotate, flip): + """Transposes an image by either rotating or flipping it.""" + for image in images: + if rotate is not None: + mode, degrees = rotate + click.echo('Rotate "%s" by %ddeg' % (image.filename, degrees)) + image = copy_filename(image.transpose(mode), image) + if flip is not None: + mode, direction = flip + click.echo('Flip "%s" %s' % (image.filename, direction)) + image = copy_filename(image.transpose(mode), image) + yield image + + +@cli.command('blur') +@click.option('-r', '--radius', default=2, show_default=True, + help='The blur radius.') +@processor +def blur_cmd(images, radius): + """Applies gaussian blur.""" + blur = ImageFilter.GaussianBlur(radius) + for image in images: + click.echo('Blurring "%s" by %dpx' % (image.filename, radius)) + yield copy_filename(image.filter(blur), image) + + +@cli.command('smoothen') +@click.option('-i', '--iterations', default=1, show_default=True, + help='How many iterations of the smoothen filter to run.') +@processor +def smoothen_cmd(images, iterations): + """Applies a smoothening filter.""" + for image in images: + click.echo('Smoothening "%s" %d time%s' % + (image.filename, iterations, iterations != 1 and 's' or '',)) + for x in xrange(iterations): + image = copy_filename(image.filter(ImageFilter.BLUR), image) + yield image + + +@cli.command('emboss') +@processor +def emboss_cmd(images): + """Embosses an image.""" + for image in images: + click.echo('Embossing "%s"' % image.filename) + yield copy_filename(image.filter(ImageFilter.EMBOSS), image) + + +@cli.command('sharpen') +@click.option('-f', '--factor', default=2.0, + help='Sharpens the image.', show_default=True) +@processor +def sharpen_cmd(images, factor): + """Sharpens an image.""" + for image in images: + click.echo('Sharpen "%s" by %f' % (image.filename, factor)) + enhancer = ImageEnhance.Sharpness(image) + yield copy_filename(enhancer.enhance(max(1.0, factor)), image) + + +@cli.command('paste') +@click.option('-l', '--left', default=0, help='Offset from left.') +@click.option('-r', '--right', default=0, help='Offset from right.') +@processor +def paste_cmd(images, left, right): + """Pastes the second image on the first image and leaves the rest + unchanged. + """ + imageiter = iter(images) + image = next(imageiter, None) + to_paste = next(imageiter, None) + + if to_paste is None: + if image is not None: + yield image + return + + click.echo('Paste "%s" on "%s"' % + (to_paste.filename, image.filename)) + mask = None + if to_paste.mode == 'RGBA' or 'transparency' in to_paste.info: + mask = to_paste + image.paste(to_paste, (left, right), mask) + image.filename += '+' + to_paste.filename + yield image + + for image in imageiter: + yield image diff --git a/third_party/python/Click/examples/imagepipe/setup.py b/third_party/python/Click/examples/imagepipe/setup.py new file mode 100644 index 0000000000..d2d8d9911a --- /dev/null +++ b/third_party/python/Click/examples/imagepipe/setup.py @@ -0,0 +1,16 @@ +from setuptools import setup + +setup( + name='click-example-imagepipe', + version='1.0', + py_modules=['imagepipe'], + include_package_data=True, + install_requires=[ + 'click', + 'pillow', + ], + entry_points=''' + [console_scripts] + imagepipe=imagepipe:cli + ''', +) diff --git a/third_party/python/Click/examples/inout/README b/third_party/python/Click/examples/inout/README new file mode 100644 index 0000000000..6309bc873e --- /dev/null +++ b/third_party/python/Click/examples/inout/README @@ -0,0 +1,10 @@ +$ inout_ + + inout is a simple example of an application that + can read from files and write to files but also + accept input from stdin or write to stdout. + +Usage: + + $ pip install --editable . + $ inout input_file.txt output_file.txt diff --git a/third_party/python/Click/examples/inout/inout.py b/third_party/python/Click/examples/inout/inout.py new file mode 100644 index 0000000000..b93f306629 --- /dev/null +++ b/third_party/python/Click/examples/inout/inout.py @@ -0,0 +1,30 @@ +import click + + +@click.command() +@click.argument('input', type=click.File('rb'), nargs=-1) +@click.argument('output', type=click.File('wb')) +def cli(input, output): + """This script works similar to the Unix `cat` command but it writes + into a specific file (which could be the standard output as denoted by + the ``-`` sign). + + \b + Copy stdin to stdout: + inout - - + + \b + Copy foo.txt and bar.txt to stdout: + inout foo.txt bar.txt - + + \b + Write stdin into the file foo.txt + inout - foo.txt + """ + for f in input: + while True: + chunk = f.read(1024) + if not chunk: + break + output.write(chunk) + output.flush() diff --git a/third_party/python/Click/examples/inout/setup.py b/third_party/python/Click/examples/inout/setup.py new file mode 100644 index 0000000000..5c613646e2 --- /dev/null +++ b/third_party/python/Click/examples/inout/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup + +setup( + name='click-example-inout', + version='0.1', + py_modules=['inout'], + include_package_data=True, + install_requires=[ + 'click', + ], + entry_points=''' + [console_scripts] + inout=inout:cli + ''', +) diff --git a/third_party/python/Click/examples/naval/README b/third_party/python/Click/examples/naval/README new file mode 100644 index 0000000000..aa289a28e7 --- /dev/null +++ b/third_party/python/Click/examples/naval/README @@ -0,0 +1,14 @@ +$ naval_ + + naval is a simple example of an application that + is ported from the docopt example of the same name. + + Unlike the original this one also runs some code and + prints messages and it's command line interface was + changed slightly to make more sense with established + POSIX semantics. + +Usage: + + $ pip install --editable . + $ naval --help diff --git a/third_party/python/Click/examples/naval/naval.py b/third_party/python/Click/examples/naval/naval.py new file mode 100644 index 0000000000..2d173d84bd --- /dev/null +++ b/third_party/python/Click/examples/naval/naval.py @@ -0,0 +1,70 @@ +import click + + +@click.group() +@click.version_option() +def cli(): + """Naval Fate. + + This is the docopt example adopted to Click but with some actual + commands implemented and not just the empty parsing which really + is not all that interesting. + """ + + +@cli.group() +def ship(): + """Manages ships.""" + + +@ship.command('new') +@click.argument('name') +def ship_new(name): + """Creates a new ship.""" + click.echo('Created ship %s' % name) + + +@ship.command('move') +@click.argument('ship') +@click.argument('x', type=float) +@click.argument('y', type=float) +@click.option('--speed', metavar='KN', default=10, + help='Speed in knots.') +def ship_move(ship, x, y, speed): + """Moves SHIP to the new location X,Y.""" + click.echo('Moving ship %s to %s,%s with speed %s' % (ship, x, y, speed)) + + +@ship.command('shoot') +@click.argument('ship') +@click.argument('x', type=float) +@click.argument('y', type=float) +def ship_shoot(ship, x, y): + """Makes SHIP fire to X,Y.""" + click.echo('Ship %s fires to %s,%s' % (ship, x, y)) + + +@cli.group('mine') +def mine(): + """Manages mines.""" + + +@mine.command('set') +@click.argument('x', type=float) +@click.argument('y', type=float) +@click.option('ty', '--moored', flag_value='moored', + default=True, + help='Moored (anchored) mine. Default.') +@click.option('ty', '--drifting', flag_value='drifting', + help='Drifting mine.') +def mine_set(x, y, ty): + """Sets a mine at a specific coordinate.""" + click.echo('Set %s mine at %s,%s' % (ty, x, y)) + + +@mine.command('remove') +@click.argument('x', type=float) +@click.argument('y', type=float) +def mine_remove(x, y): + """Removes a mine at a specific coordinate.""" + click.echo('Removed mine at %s,%s' % (x, y)) diff --git a/third_party/python/Click/examples/naval/setup.py b/third_party/python/Click/examples/naval/setup.py new file mode 100644 index 0000000000..124addf430 --- /dev/null +++ b/third_party/python/Click/examples/naval/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup + +setup( + name='click-example-naval', + version='2.0', + py_modules=['naval'], + include_package_data=True, + install_requires=[ + 'click', + ], + entry_points=''' + [console_scripts] + naval=naval:cli + ''', +) diff --git a/third_party/python/Click/examples/repo/README b/third_party/python/Click/examples/repo/README new file mode 100644 index 0000000000..52d1fa7d0b --- /dev/null +++ b/third_party/python/Click/examples/repo/README @@ -0,0 +1,9 @@ +$ repo_ + + repo is a simple example of an application that looks + and works similar to hg or git. + +Usage: + + $ pip install --editable . + $ repo --help diff --git a/third_party/python/Click/examples/repo/repo.py b/third_party/python/Click/examples/repo/repo.py new file mode 100644 index 0000000000..2b1992d3e8 --- /dev/null +++ b/third_party/python/Click/examples/repo/repo.py @@ -0,0 +1,151 @@ +import os +import sys +import posixpath + +import click + + +class Repo(object): + + def __init__(self, home): + self.home = home + self.config = {} + self.verbose = False + + def set_config(self, key, value): + self.config[key] = value + if self.verbose: + click.echo(' config[%s] = %s' % (key, value), file=sys.stderr) + + def __repr__(self): + return '<Repo %r>' % self.home + + +pass_repo = click.make_pass_decorator(Repo) + + +@click.group() +@click.option('--repo-home', envvar='REPO_HOME', default='.repo', + metavar='PATH', help='Changes the repository folder location.') +@click.option('--config', nargs=2, multiple=True, + metavar='KEY VALUE', help='Overrides a config key/value pair.') +@click.option('--verbose', '-v', is_flag=True, + help='Enables verbose mode.') +@click.version_option('1.0') +@click.pass_context +def cli(ctx, repo_home, config, verbose): + """Repo is a command line tool that showcases how to build complex + command line interfaces with Click. + + This tool is supposed to look like a distributed version control + system to show how something like this can be structured. + """ + # Create a repo object and remember it as as the context object. From + # this point onwards other commands can refer to it by using the + # @pass_repo decorator. + ctx.obj = Repo(os.path.abspath(repo_home)) + ctx.obj.verbose = verbose + for key, value in config: + ctx.obj.set_config(key, value) + + +@cli.command() +@click.argument('src') +@click.argument('dest', required=False) +@click.option('--shallow/--deep', default=False, + help='Makes a checkout shallow or deep. Deep by default.') +@click.option('--rev', '-r', default='HEAD', + help='Clone a specific revision instead of HEAD.') +@pass_repo +def clone(repo, src, dest, shallow, rev): + """Clones a repository. + + This will clone the repository at SRC into the folder DEST. If DEST + is not provided this will automatically use the last path component + of SRC and create that folder. + """ + if dest is None: + dest = posixpath.split(src)[-1] or '.' + click.echo('Cloning repo %s to %s' % (src, os.path.abspath(dest))) + repo.home = dest + if shallow: + click.echo('Making shallow checkout') + click.echo('Checking out revision %s' % rev) + + +@cli.command() +@click.confirmation_option() +@pass_repo +def delete(repo): + """Deletes a repository. + + This will throw away the current repository. + """ + click.echo('Destroying repo %s' % repo.home) + click.echo('Deleted!') + + +@cli.command() +@click.option('--username', prompt=True, + help='The developer\'s shown username.') +@click.option('--email', prompt='E-Mail', + help='The developer\'s email address') +@click.password_option(help='The login password.') +@pass_repo +def setuser(repo, username, email, password): + """Sets the user credentials. + + This will override the current user config. + """ + repo.set_config('username', username) + repo.set_config('email', email) + repo.set_config('password', '*' * len(password)) + click.echo('Changed credentials.') + + +@cli.command() +@click.option('--message', '-m', multiple=True, + help='The commit message. If provided multiple times each ' + 'argument gets converted into a new line.') +@click.argument('files', nargs=-1, type=click.Path()) +@pass_repo +def commit(repo, files, message): + """Commits outstanding changes. + + Commit changes to the given files into the repository. You will need to + "repo push" to push up your changes to other repositories. + + If a list of files is omitted, all changes reported by "repo status" + will be committed. + """ + if not message: + marker = '# Files to be committed:' + hint = ['', '', marker, '#'] + for file in files: + hint.append('# U %s' % file) + message = click.edit('\n'.join(hint)) + if message is None: + click.echo('Aborted!') + return + msg = message.split(marker)[0].rstrip() + if not msg: + click.echo('Aborted! Empty commit message') + return + else: + msg = '\n'.join(message) + click.echo('Files to be committed: %s' % (files,)) + click.echo('Commit message:\n' + msg) + + +@cli.command(short_help='Copies files.') +@click.option('--force', is_flag=True, + help='forcibly copy over an existing managed file') +@click.argument('src', nargs=-1, type=click.Path()) +@click.argument('dst', type=click.Path()) +@pass_repo +def copy(repo, src, dst, force): + """Copies one or multiple files to a new location. This copies all + files from SRC to DST. + """ + for fn in src: + click.echo('Copy from %s -> %s' % (fn, dst)) diff --git a/third_party/python/Click/examples/repo/setup.py b/third_party/python/Click/examples/repo/setup.py new file mode 100644 index 0000000000..19aab7087a --- /dev/null +++ b/third_party/python/Click/examples/repo/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup + +setup( + name='click-example-repo', + version='0.1', + py_modules=['repo'], + include_package_data=True, + install_requires=[ + 'click', + ], + entry_points=''' + [console_scripts] + repo=repo:cli + ''', +) diff --git a/third_party/python/Click/examples/termui/README b/third_party/python/Click/examples/termui/README new file mode 100644 index 0000000000..2c9d9dd045 --- /dev/null +++ b/third_party/python/Click/examples/termui/README @@ -0,0 +1,9 @@ +$ termui_ + + termui showcases the different terminal UI helpers that + Click provides. + +Usage: + + $ pip install --editable . + $ termui --help diff --git a/third_party/python/Click/examples/termui/setup.py b/third_party/python/Click/examples/termui/setup.py new file mode 100644 index 0000000000..14558e85c1 --- /dev/null +++ b/third_party/python/Click/examples/termui/setup.py @@ -0,0 +1,17 @@ +from setuptools import setup + +setup( + name='click-example-termui', + version='1.0', + py_modules=['termui'], + include_package_data=True, + install_requires=[ + 'click', + # Colorama is only required for Windows. + 'colorama', + ], + entry_points=''' + [console_scripts] + termui=termui:cli + ''', +) diff --git a/third_party/python/Click/examples/termui/termui.py b/third_party/python/Click/examples/termui/termui.py new file mode 100644 index 0000000000..793afa419b --- /dev/null +++ b/third_party/python/Click/examples/termui/termui.py @@ -0,0 +1,156 @@ +# coding: utf-8 +import click +import math +import time +import random + +try: + range_type = xrange +except NameError: + range_type = range + + +@click.group() +def cli(): + """This script showcases different terminal UI helpers in Click.""" + pass + + +@cli.command() +def colordemo(): + """Demonstrates ANSI color support.""" + for color in 'red', 'green', 'blue': + click.echo(click.style('I am colored %s' % color, fg=color)) + click.echo(click.style('I am background colored %s' % color, bg=color)) + + +@cli.command() +def pager(): + """Demonstrates using the pager.""" + lines = [] + for x in range_type(200): + lines.append('%s. Hello World!' % click.style(str(x), fg='green')) + click.echo_via_pager('\n'.join(lines)) + + +@cli.command() +@click.option('--count', default=8000, type=click.IntRange(1, 100000), + help='The number of items to process.') +def progress(count): + """Demonstrates the progress bar.""" + items = range_type(count) + + def process_slowly(item): + time.sleep(0.002 * random.random()) + + def filter(items): + for item in items: + if random.random() > 0.3: + yield item + + with click.progressbar(items, label='Processing accounts', + fill_char=click.style('#', fg='green')) as bar: + for item in bar: + process_slowly(item) + + def show_item(item): + if item is not None: + return 'Item #%d' % item + + with click.progressbar(filter(items), label='Committing transaction', + fill_char=click.style('#', fg='yellow'), + item_show_func=show_item) as bar: + for item in bar: + process_slowly(item) + + with click.progressbar(length=count, label='Counting', + bar_template='%(label)s %(bar)s | %(info)s', + fill_char=click.style(u'█', fg='cyan'), + empty_char=' ') as bar: + for item in bar: + process_slowly(item) + + with click.progressbar(length=count, width=0, show_percent=False, + show_eta=False, + fill_char=click.style('#', fg='magenta')) as bar: + for item in bar: + process_slowly(item) + + # 'Non-linear progress bar' + steps = [math.exp( x * 1. / 20) - 1 for x in range(20)] + count = int(sum(steps)) + with click.progressbar(length=count, show_percent=False, + label='Slowing progress bar', + fill_char=click.style(u'█', fg='green')) as bar: + for item in steps: + time.sleep(item) + bar.update(item) + + +@cli.command() +@click.argument('url') +def open(url): + """Opens a file or URL In the default application.""" + click.launch(url) + + +@cli.command() +@click.argument('url') +def locate(url): + """Opens a file or URL In the default application.""" + click.launch(url, locate=True) + + +@cli.command() +def edit(): + """Opens an editor with some text in it.""" + MARKER = '# Everything below is ignored\n' + message = click.edit('\n\n' + MARKER) + if message is not None: + msg = message.split(MARKER, 1)[0].rstrip('\n') + if not msg: + click.echo('Empty message!') + else: + click.echo('Message:\n' + msg) + else: + click.echo('You did not enter anything!') + + +@cli.command() +def clear(): + """Clears the entire screen.""" + click.clear() + + +@cli.command() +def pause(): + """Waits for the user to press a button.""" + click.pause() + + +@cli.command() +def menu(): + """Shows a simple menu.""" + menu = 'main' + while 1: + if menu == 'main': + click.echo('Main menu:') + click.echo(' d: debug menu') + click.echo(' q: quit') + char = click.getchar() + if char == 'd': + menu = 'debug' + elif char == 'q': + menu = 'quit' + else: + click.echo('Invalid input') + elif menu == 'debug': + click.echo('Debug menu') + click.echo(' b: back') + char = click.getchar() + if char == 'b': + menu = 'main' + else: + click.echo('Invalid input') + elif menu == 'quit': + return diff --git a/third_party/python/Click/examples/validation/README b/third_party/python/Click/examples/validation/README new file mode 100644 index 0000000000..a69e3f4276 --- /dev/null +++ b/third_party/python/Click/examples/validation/README @@ -0,0 +1,12 @@ +$ validation_ + + validation is a simple example of an application that + performs custom validation of parameters in different + ways. + + This example requires Click 2.0 or higher. + +Usage: + + $ pip install --editable . + $ validation --help diff --git a/third_party/python/Click/examples/validation/setup.py b/third_party/python/Click/examples/validation/setup.py new file mode 100644 index 0000000000..9491f709c7 --- /dev/null +++ b/third_party/python/Click/examples/validation/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup + +setup( + name='click-example-validation', + version='1.0', + py_modules=['validation'], + include_package_data=True, + install_requires=[ + 'click', + ], + entry_points=''' + [console_scripts] + validation=validation:cli + ''', +) diff --git a/third_party/python/Click/examples/validation/validation.py b/third_party/python/Click/examples/validation/validation.py new file mode 100644 index 0000000000..00fa0a6001 --- /dev/null +++ b/third_party/python/Click/examples/validation/validation.py @@ -0,0 +1,44 @@ +import click +try: + from urllib import parse as urlparse +except ImportError: + import urlparse + + +def validate_count(ctx, param, value): + if value < 0 or value % 2 != 0: + raise click.BadParameter('Should be a positive, even integer.') + return value + + +class URL(click.ParamType): + name = 'url' + + def convert(self, value, param, ctx): + if not isinstance(value, tuple): + value = urlparse.urlparse(value) + if value.scheme not in ('http', 'https'): + self.fail('invalid URL scheme (%s). Only HTTP URLs are ' + 'allowed' % value.scheme, param, ctx) + return value + + +@click.command() +@click.option('--count', default=2, callback=validate_count, + help='A positive even number.') +@click.option('--foo', help='A mysterious parameter.') +@click.option('--url', help='A URL', type=URL()) +@click.version_option() +def cli(count, foo, url): + """Validation. + + This example validates parameters in different ways. It does it + through callbacks, through a custom type as well as by validating + manually in the function. + """ + if foo is not None and foo != 'wat': + raise click.BadParameter('If a value is provided it needs to be the ' + 'value "wat".', param_hint=['--foo']) + click.echo('count: %s' % count) + click.echo('foo: %s' % foo) + click.echo('url: %s' % repr(url)) |