I am creating a command line application in Python using the Click library that accepts a name as input but if no name is entered it returns the default value.
Here is the code I have so far.
hello.py
import click
@click.version_option(1.0)
@click.command()
@click.argument('string', default='World')
@click.option('-r', '--repeat', default=1, help='How many times should be greeted.')
def cli(string,repeat):
'''This string greets you.'''
for i in xrange(repeat):
click.echo('Hello %s!' % string)
if __name__ == '__main__':
cli()
When I run it.
$ hello
Hello World!
$ hello Bob
Hello Bob!
$ hello Bob -r 3
Hello Bob!
Hello Bob!
Hello Bob!
This is exactly what I want.
Now, I would like to be able to accept input from stdin like the following examples.
$ echo John | hello
Hello John!
$ echo John | hello -r 3
Hello John!
Hello John!
Hello John!
Python click option names Click derives the name of the option from the long name, if both are used. In the example, we create an option with both short and long names. The name of the variable passed to the function is string , derived from the longer option name. We run the program using both option names.
Click is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It's the “Command Line Interface Creation Kit”. It's highly configurable but comes with sensible defaults out of the box.
Well this is quite an old question but I will try to answer it anyway.
I'm sorta new to Click so, I reckon, my solution can be improved immensely. Anyway it does exactly what you want. Here it is:
import click
def get_name(ctx, param, value):
if not value and not click.get_text_stream('stdin').isatty():
return click.get_text_stream('stdin').read().strip()
else:
return value
@click.command()
@click.argument('name', callback=get_name, required=False)
@click.option('--repeat', '-r', default=1)
def say_hello(name, repeat):
for i in range(repeat):
click.echo('Hello {}'.format(name or 'World'))
if __name__ == "__main__":
say_hello()
The problem is that the command result before piping will be consumed inside your application and not as an argument for it. Since your application doesn't use any input inside itself, everything you pipe to it will be discarded.
If you want you application to be 'pipeable' just insert a raw_input
inside it since this function reads from stdin.
To make your program to looks like cat you can do:
@click.command()
@click.argument('string', required=False)
@click.option('-r', '--repeat', default=1, help='How many times should be greeted.')
def cli(string, repeat):
'''This string greets you.'''
if not string:
string = raw_input()
for i in xrange(repeat):
click.echo('Hello %s!' % string)
Another option is to transform string in an option and set prompt to True:
@click.command()
@click.option('--string', prompt=True)
@click.option('-r', '--repeat', default=1, help='How many times should be greeted.')
def cli(string, repeat):
'''This string greets you.'''
for i in xrange(repeat):
click.echo('Hello %s!' % string)
In this way, if the user does not provide a string he will be prompted for input, which makes your application pipeable too. The only problem is that it will print to stdout STRING:
which sometimes is not acceptable (you can define an empty string to display with prompt=''
, but, since I know, there is no chance to get rid of :
).
By the way, to achieve the same thing, using the your code the way it is, you can do:
python hello.py `echo bob`
echo bob
will be evaluated first and its result will compose the arguments for hello.py
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With