Python Forum
Thread Rating:
  • 2 Vote(s) - 3 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Click Click
#1
So this is about Click,getting stuff from command line into Python.
There are many existing solution for this,i would say that Click is the best of the bunch Thumbs Up

All code testes om Win-10(Python 36) and Linux Mint 18.1(Python 35).
Shell cmder Win-10 and default shell Mint

One of the most powerful feature of Click is click.echo()
It solve Unicode from command line on all OS,also Windows console which is just impressive.


So first example gone put it trough a hard Unicode test.
# click_unicode.py
import click

@click.command()
@click.option('--count', default=3, help='Number of greetings.')
@click.option('--name', prompt='Your name',
              help='Test of difficult Unicode')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo(f'Hello {name} {"☂"}') #36
        #click.echo('Hello {} {}'.format(name, "☂")) #35

if __name__ == '__main__':
    hello()
From command line:
Output:
λ python click_unicode.py Your name: chess☺ king♟♜♞ Hello chess☺ king♟♜♞ ☂ Hello chess☺ king♟♜♞ ☂ Hello chess☺ king♟♜♞ ☂ λ python click_unicode.py --help Usage: click_unicode.py [OPTIONS]  Simple program that greets NAME for a total of COUNT times. Options:  --count INTEGER  Number of greetings.  --name TEXT      Test of difficult Unicode  --help           Show this message and exit.
So it work the same on Win and Linux.
Setting prompt it work like Python's input()
Setting count will repeat prompt 3 times.


A look getting different types form command line.
Here a look at float type:
# float_test.py
import click

@click.command()
@click.option('--pos', nargs=2, type=float)
def get_float(pos):
   n1,n2 = pos
   total = n1 / n2
   click.echo(f'{n1} / {n2} = {total:.2f}') #36
   #click.echo('{} / {} = {:.2f}'.format(n1,n2,total)) #35

if __name__ == '__main__':
   get_float()
From command line:
Output:
λ python float_test.py --pos 14 3 14.0 / 3.0 = 4.67 λ python float_test.py --pos 14 3 100 Usage: float_test.py [OPTIONS] Error: Got unexpected extra argument (100)
So nargs how many argumet that is wanted an that type is float.
Getting a tuple(pos) back unpack and use it to calculate.


Mix types in this example string("str"which is Unicode python 3) and integer.
# str_int.py
import click

@click.command()
@click.option('--item', type=(str, int))
def mix(item):
    #name,number = item
    click.echo('Name is <{}> and number is: <{}>'.format(*item)) #35
    #click.echo(f'Name is <{name}> and number is: <{number}>') #36

if __name__ == '__main__':
    mix()
From command line:
Output:
λ python str_int.py --item †øღ 12345 Name is <†øღ> and number is: <12345> λ python str_int.py --item †øღ 12345 world Usage: str_int.py [OPTIONS] Error: Got unexpected extra argument (world)


Prompt same as input() python.
import click

@click.command()
@click.option('--name', prompt=True) # prompt='Your name please'
def hello(name):
    click.echo(f'Hello {name}') #36
    #click.echo('Hello {}'.format(name)) #35

if __name__ == '__main__':
    hello()
From command line:
Output:
λ python prompt.py Name: Ħαηṧ Hello Ħαηṧ


Getting a file.
# file_arg.py
import click

@click.command()
@click.argument('f', type=click.Path(exists=True))
def touch(f):
    file_name = click.format_filename(f)
    with open(file_name) as f:
        print(f'Content of {file_name} is:\n{f.read()}') #36
        #print('Content of {} is:\n{}'.format(file_name, f.read())) #35

if __name__ == '__main__':
    touch()
Output:
λ python file_arg.py aaa.txt Usage: file_arg.py [OPTIONS] F Error: Invalid value for "f": Path "aaa.txt" does not exist. E:\1py_div\click λ python file_arg.py hello.txt Content of hello.txt is: hello world
So click.Path(exists=True) dos error cheeking.
When okay use with open() and read the file.

I may add more to this demo Cool
Reply
#2
This is very nice resume. Useful too. I've tried click before but just to see how it works. Nothing more. Which modules have you tried?
Have you seen prompt_toolkit? Perhaps it's too powerful for little projects. I don't know it handle Unicode.
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#3
Quote:Which modules have you tried?
I have tested some from standard library(getopt, optparse and argparse) where argparse is the best of theme.
sys.argv(simple list of arguments) which many has a first encounter with this topic.
Tested Docopt,not prompt_toolkit.
I use ptpython as REPL,where prompt_toolkit had and important part in making of ptpython.

I someone has tested something cool on this topic feel free to post here.
Python Fire is a new one,this is something that Google has used internal which is now open source.
Reply
#4
A quick look at Python Fire.
It's kind of cool,it simplify it down bye using some magic.

I want to start with the class and use it in a normal way.
class Calculator:
   """A simple calculator class."""

   def double(self, number):
       return 2 * number

if __name__ == '__main__':
     obj = Calculator()
     print(obj.double(5))
     print(obj.double(4.6))
     print(obj.double('hello'))
Output:
10 9.2 hellohello
So the normal way,instance of the class and assigns to variable obj.
Use method object "obj" and call method double.

Now the same using fire.
# fire_class.py
import fire

class Calculator:
    """A simple calculator class."""

    def double(self, number):
        return 2 * number

if __name__ == '__main__':
    fire.Fire(Calculator)
From command line:
Output:
λ python fire_class.py double 5 10 λ python fire_class.py double 4.6 9.2 λ python fire_class.py double hello hellohello λ python fire_class.py -- --help Type:        type String form: <class '__main__.Calculator'> File:        c:\python36\web_scrape\fire_class.py Line:        4 Docstring:   A simple calculator class. Usage:       fire_class.py
So file name fire_class.py is acting like the method object "obj".
So we can use the class in same way as in first example.


Using a function.
# fire_func.py
import fire

def hello(name):
   return f'Hello {name}!☂'   

if __name__ == '__main__':
   fire.Fire(hello)
From command line:
Output:
λ python fire_func.py outside Hello outside!☂
So will *args work so we can give many argument in Think
# fire_arg.py
import fire

def hello(*args):
    return f'Hello {args}!☂'

if __name__ == '__main__':
    fire.Fire(hello)
From command line:
Output:
λ python fire_arg.py i am from outside and want in Hello ('i', 'am', 'from', 'outside', 'and', 'want', 'in')!☂

Other stuff eg --interactive
From command line:
Output:
λ python fire_class.py -- --interactive Fire is starting a Python REPL with the following objects: Modules: fire Objects: Calculator, component, fire_class.py, result, trace Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] Type "copyright", "credits" or "license" for more information. IPython 5.3.0 -- 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]:
So it start a IPython interactive shell.
Reply
#5
cool!
Reply
#6
I know Fire. Good idea [Image: smile.png]

However, I want to know, how to get positional arguments with Click?
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#7
(Apr-16-2017, 07:28 AM)wavic Wrote: However, I want to know, how to get positional arguments with Click?
Something like this.
If nargs is set -1,then an unlimited number of arguments is accepted.
#numb_input.py
import click

@click.command()
@click.argument('n', nargs=-1)
def numbers(n):
    click.echo(n)
    click.echo(sum(int(i) for i in n))

if __name__ == '__main__':
    numbers()
Output:
(click) C:\Python36\click λ python numb_input.py 1 2 3 4 5 ('1', '2', '3', '4', '5') 15 (click) C:\Python36\click λ python numb_input.py 100 458 96878 ('100', '458', '96878') 97436
As a example sum first numbers,then make a dict of last argument.
#numb_input_1.py
import click

@click.command()
@click.argument('n', nargs=-1)
@click.argument('d', nargs=1)
def numbers(n, d):
    click.echo(sum(float(i) for i in n))
    to_dict = dict([d.split('=')])
    click.echo(to_dict)

if __name__ == '__main__':
    numbers()
Output:
(click) C:\Python36\click λ python numb_input_1.py 100 458 96878 my_number=666 97436.0 {'my_number': '666'}
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  wxpython single click/double click recognition Larz60+ 1 6,163 Jul-23-2017, 06:49 PM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020