import inspect
import io
import itertools
import sys
import typing as t
from gettext import gettext as _
from . _compat import isatty
from . _compat import strip_ansi
from . exceptions import Abort
from . exceptions import UsageError
from . globals import resolve_color_default
from . types import Choice
from . types import convert_type
from . types import ParamType
from . utils import echo
from . utils import LazyFile
if t . TYPE_CHECKING :
from . _termui_impl import ProgressBar
V = t . TypeVar ( " V " )
# The prompt functions to use. The doc tools currently override these
# functions to customize how they work.
visible_prompt_func : t . Callable [ [ str ] , str ] = input
_ansi_colors = {
" black " : 30 ,
" red " : 31 ,
" green " : 32 ,
" yellow " : 33 ,
" blue " : 34 ,
" magenta " : 35 ,
" cyan " : 36 ,
" white " : 37 ,
" reset " : 39 ,
" bright_black " : 90 ,
" bright_red " : 91 ,
" bright_green " : 92 ,
" bright_yellow " : 93 ,
" bright_blue " : 94 ,
" bright_magenta " : 95 ,
" bright_cyan " : 96 ,
" bright_white " : 97 ,
}
_ansi_reset_all = " \033 [0m "
def hidden_prompt_func ( prompt : str ) - > str :
import getpass
return getpass . getpass ( prompt )
def _build_prompt (
text : str ,
suffix : str ,
show_default : bool = False ,
default : t . Optional [ t . Any ] = None ,
show_choices : bool = True ,
type : t . Optional [ ParamType ] = None ,
) - > str :
prompt = text
if type is not None and show_choices and isinstance ( type , Choice ) :
prompt + = f " ( { ' , ' . join ( map ( str , type . choices ) ) } ) "
if default is not None and show_default :
prompt = f " { prompt } [ { _format_default ( default ) } ] "
return f " { prompt } { suffix } "
def _format_default ( default : t . Any ) - > t . Any :
if isinstance ( default , ( io . IOBase , LazyFile ) ) and hasattr ( default , " name " ) :
return default . name
return default
def prompt (
text : str ,
default : t . Optional [ t . Any ] = None ,
hide_input : bool = False ,
confirmation_prompt : t . Union [ bool , str ] = False ,
type : t . Optional [ t . Union [ ParamType , t . Any ] ] = None ,
value_proc : t . Optional [ t . Callable [ [ str ] , t . Any ] ] = None ,
prompt_suffix : str = " : " ,
show_default : bool = True ,
err : bool = False ,
show_choices : bool = True ,
) - > t . Any :
""" Prompts a user for input. This is a convenience function that can
be used to prompt a user for input later .
If the user aborts the input by sending an interrupt signal , this
function will catch it and raise a : exc : ` Abort ` exception .
: param text : the text to show for the prompt .
: param default : the default value to use if no input happens . If this
is not given it will prompt until it ' s aborted.
: param hide_input : if this is set to true then the input value will
be hidden .
: param confirmation_prompt : Prompt a second time to confirm the
value . Can be set to a string instead of ` ` True ` ` to customize
the message .
: param type : the type to use to check the value against .
: param value_proc : if this parameter is provided it ' s a function that
is invoked instead of the type conversion to
convert a value .
: param prompt_suffix : a suffix that should be added to the prompt .
: param show_default : shows or hides the default value in the prompt .
: param err : if set to true the file defaults to ` ` stderr ` ` instead of
` ` stdout ` ` , the same as with echo .
: param show_choices : Show or hide choices if the passed type is a Choice .
For example if type is a Choice of either day or week ,
show_choices is true and text is " Group by " then the
prompt will be " Group by (day, week): " .
. . versionadded : : 8.0
` ` confirmation_prompt ` ` can be a custom string .
. . versionadded : : 7.0
Added the ` ` show_choices ` ` parameter .
. . versionadded : : 6.0
Added unicode support for cmd . exe on Windows .
. . versionadded : : 4.0
Added the ` err ` parameter .
"""
def prompt_func ( text : str ) - > str :
f = hidden_prompt_func if hide_input else visible_prompt_func
try :
# Write the prompt separately so that we get nice
# coloring through colorama on Windows
echo ( text . rstrip ( " " ) , nl = False , err = err )
# Echo a space to stdout to work around an issue where
# readline causes backspace to clear the whole line.
return f ( " " )
except ( KeyboardInterrupt , EOFError ) :
# getpass doesn't print a newline if the user aborts input with ^C.
# Allegedly this behavior is inherited from getpass(3).
# A doc bug has been filed at https://bugs.python.org/issue24711
if hide_input :
echo ( None , err = err )
raise Abort ( ) from None
if value_proc is None :
value_proc = convert_type ( type , default )
prompt = _build_prompt (
text , prompt_suffix , show_default , default , show_choices , type
)
if confirmation_prompt :
if confirmation_prompt is True :
confirmation_prompt = _ ( " Repeat for confirmation " )
confirmation_prompt = _build_prompt ( confirmation_prompt , prompt_suffix )
while True :
while True :
value = prompt_func ( prompt )
if value :
break
elif default is not None :
value = default
break
try :
result = value_proc ( value )
except UsageError as e :
if hide_input :
echo ( _ ( " Error: The value you entered was invalid. " ) , err = err )
else :
echo ( _ ( " Error: {e.message} " ) . format ( e = e ) , err = err ) # noqa: B306
continue
if not confirmation_prompt :
return result
while True :
value2 = prompt_func ( confirmation_prompt )
is_empty = not value and not value2
if value2 or is_empty :
break
if value == value2 :
return result
echo ( _ ( " Error: The two entered values do not match. " ) , err = err )
def confirm (
text : str ,
default : t . Optional [ bool ] = False ,
abort : bool = False ,
prompt_suffix : str = " : " ,
show_default : bool = True ,
err : bool = False ,
) - > bool :
""" Prompts for confirmation (yes/no question).
If the user aborts the input by sending a interrupt signal this
function will catch it and raise a : exc : ` Abort ` exception .
: param text : the question to ask .
: param default : The default value to use when no input is given . If
` ` None ` ` , repeat until input is given .
: param abort : if this is set to ` True ` a negative answer aborts the
exception by raising : exc : ` Abort ` .
: param prompt_suffix : a suffix that should be added to the prompt .
: param show_default : shows or hides the default value in the prompt .
: param err : if set to true the file defaults to ` ` stderr ` ` instead of
` ` stdout ` ` , the same as with echo .
. . versionchanged : : 8.0
Repeat until input is given if ` ` default ` ` is ` ` None ` ` .
. . versionadded : : 4.0
Added the ` ` err ` ` parameter .
"""
prompt = _build_prompt (
text ,
prompt_suffix ,
show_default ,
" y/n " if default is None else ( " Y/n " if default else " y/N " ) ,
)
while True :
try :
# Write the prompt separately so that we get nice
# coloring through colorama on Windows
echo ( prompt . rstrip ( " " ) , nl = False , err = err )
# Echo a space to stdout to work around an issue where
# readline causes backspace to clear the whole line.
value = visible_prompt_func ( " " ) . lower ( ) . strip ( )
except ( KeyboardInterrupt , EOFError ) :
raise Abort ( ) from None
if value in ( " y " , " yes " ) :
rv = True
elif value in ( " n " , " no " ) :
rv = False
elif default is not None and value == " " :
rv = default
else :
echo ( _ ( " Error: invalid input " ) , err = err )
continue
break
if abort and not rv :
raise Abort ( )
return rv
def echo_via_pager (
text_or_generator : t . Union [ t . Iterable [ str ] , t . Callable [ [ ] , t . Iterable [ str ] ] , str ] ,
color : t . Optional [ bool ] = None ,
) - > None :
""" This function takes a text and shows it via an environment specific
pager on stdout .
. . versionchanged : : 3.0
Added the ` color ` flag .
: param text_or_generator : the text to page , or alternatively , a
generator emitting the text to page .
: param color : controls if the pager supports ANSI colors or not . The
default is autodetection .
"""
color = resolve_color_default ( color )
if inspect . isgeneratorfunction ( text_or_generator ) :
i = t . cast ( t . Callable [ [ ] , t . Iterable [ str ] ] , text_or_generator ) ( )
elif isinstance ( text_or_generator , str ) :
i = [ text_or_generator ]
else :
i = iter ( t . cast ( t . Iterable [ str ] , text_or_generator ) )
# convert every element of i to a text type if necessary
text_generator = ( el if isinstance ( el , str ) else str ( el ) for el in i )
from . _termui_impl import pager
return pager ( itertools . chain ( text_generator , " \n " ) , color )
def progressbar (
iterable : t . Optional [ t . Iterable [ V ] ] = None ,
length : t . Optional [ int ] = None ,
label : t . Optional [ str ] = None ,
show_eta : bool = True ,
show_percent : t . Optional [ bool ] = None ,
show_pos : bool = False ,
item_show_func : t . Optional [ t . Callable [ [ t . Optional [ V ] ] , t . Optional [ str ] ] ] = None ,
fill_char : str = " # " ,
empty_char : str = " - " ,
bar_template : str = " %(label)s [ %(bar)s ] %(info)s " ,
info_sep : str = " " ,
width : int = 36 ,
file : t . Optional [ t . TextIO ] = None ,
color : t . Optional [ bool ] = None ,
update_min_steps : int = 1 ,
) - > " ProgressBar[V] " :
""" This function creates an iterable context manager that can be used
to iterate over something while showing a progress bar . It will
either iterate over the ` iterable ` or ` length ` items ( that are counted
up ) . While iteration happens , this function will print a rendered
progress bar to the given ` file ` ( defaults to stdout ) and will attempt
to calculate remaining time and more . By default , this progress bar
will not be rendered if the file is not a terminal .
The context manager creates the progress bar . When the context
manager is entered the progress bar is already created . With every
iteration over the progress bar , the iterable passed to the bar is
advanced and the bar is updated . When the context manager exits ,
a newline is printed and the progress bar is finalized on screen .
Note : The progress bar is currently designed for use cases where the
total progress can be expected to take at least several seconds .
Because of this , the ProgressBar class object won ' t display
progress that is considered too fast , and progress where the time
between steps is less than a second .
No printing must happen or the progress bar will be unintentionally
destroyed .
Example usage : :
with progressbar ( items ) as bar :
for item in bar :
do_something_with ( item )
Alternatively , if no iterable is specified , one can manually update the
progress bar through the ` update ( ) ` method instead of directly
iterating over the progress bar . The update method accepts the number
of steps to increment the bar with : :
with progressbar ( length = chunks . total_bytes ) as bar :
for chunk in chunks :
process_chunk ( chunk )
bar . update ( chunks . bytes )
The ` ` update ( ) ` ` method also takes an optional value specifying the
` ` current_item ` ` at the new position . This is useful when used
together with ` ` item_show_func ` ` to customize the output for each
manual step : :
with click . progressbar (
length = total_size ,
label = ' Unzipping archive ' ,
item_show_func = lambda a : a . filename
) as bar :
for archive in zip_file :
archive . extract ( )
bar . update ( archive . size , archive )
: param iterable : an iterable to iterate over . If not provided the length
is required .
: param length : the number of items to iterate over . By default the
progressbar will attempt to ask the iterator about its
length , which might or might not work . If an iterable is
also provided this parameter can be used to override the
length . If an iterable is not provided the progress bar
will iterate over a range of that length .
: param label : the label to show next to the progress bar .
: param show_eta : enables or disables the estimated time display . This is
automatically disabled if the length cannot be
determined .
: param show_percent : enables or disables the percentage display . The
default is ` True ` if the iterable has a length or
` False ` if not .
: param show_pos : enables or disables the absolute position display . The
default is ` False ` .
: param item_show_func : A function called with the current item which
can return a string to show next to the progress bar . If the
function returns ` ` None ` ` nothing is shown . The current item can
be ` ` None ` ` , such as when entering and exiting the bar .
: param fill_char : the character to use to show the filled part of the
progress bar .
: param empty_char : the character to use to show the non - filled part of
the progress bar .
: param bar_template : the format string to use as template for the bar .
The parameters in it are ` ` label ` ` for the label ,
` ` bar ` ` for the progress bar and ` ` info ` ` for the
info section .
: param info_sep : the separator between multiple info items ( eta etc . )
: param width : the width of the progress bar in characters , 0 means full
terminal width
: param file : The file to write to . If this is not a terminal then
only the label is printed .
: param color : controls if the terminal supports ANSI colors or not . The
default is autodetection . This is only needed if ANSI
codes are included anywhere in the progress bar output
which is not the case by default .
: param update_min_steps : Render only when this many updates have
completed . This allows tuning for very fast iterators .
. . versionchanged : : 8.0
Output is shown even if execution time is less than 0.5 seconds .
. . versionchanged : : 8.0
` ` item_show_func ` ` shows the current item , not the previous one .
. . versionchanged : : 8.0
Labels are echoed if the output is not a TTY . Reverts a change
in 7.0 that removed all output .
. . versionadded : : 8.0
Added the ` ` update_min_steps ` ` parameter .
. . versionchanged : : 4.0
Added the ` ` color ` ` parameter . Added the ` ` update ` ` method to
the object .
. . versionadded : : 2.0
"""
from . _termui_impl import ProgressBar
color = resolve_color_default ( color )
return ProgressBar (
iterable = iterable ,
length = length ,
show_eta = show_eta ,
show_percent = show_percent ,
show_pos = show_pos ,
item_show_func = item_show_func ,
fill_char = fill_char ,
empty_char = empty_char ,
bar_template = bar_template ,
info_sep = info_sep ,
file = file ,
label = label ,
width = width ,
color = color ,
update_min_steps = update_min_steps ,
)
def clear ( ) - > None :
""" Clears the terminal screen. This will have the effect of clearing
the whole visible space of the terminal and moving the cursor to the
top left . This does not do anything if not connected to a terminal .
. . versionadded : : 2.0
"""
if not isatty ( sys . stdout ) :
return
# ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor
echo ( " \033 [2J \033 [1;1H " , nl = False )
def _interpret_color (
color : t . Union [ int , t . Tuple [ int , int , int ] , str ] , offset : int = 0
) - > str :
if isinstance ( color , int ) :
return f " { 38 + offset } ;5; { color : d } "
if isinstance ( color , ( tuple , list ) ) :
r , g , b = color
return f " { 38 + offset } ;2; { r : d } ; { g : d } ; { b : d } "
return str ( _ansi_colors [ color ] + offset )
def style (
text : t . Any ,
fg : t . Optional [ t . Union [ int , t . Tuple [ int , int , int ] , str ] ] = None ,
bg : t . Optional [ t . Union [ int , t . Tuple [ int , int , int ] , str ] ] = None ,
bold : t . Optional [ bool ] = None ,
dim : t . Optional [ bool ] = None ,
underline : t . Optional [ bool ] = None ,
overline : t . Optional [ bool ] = None ,
italic : t . Optional [ bool ] = None ,
blink : t . Optional [ bool ] = None ,
reverse : t . Optional [ bool ] = None ,
strikethrough : t . Optional [ bool ] = None ,
reset : bool = True ,
) - > str :
""" Styles a text with ANSI styles and returns the new string. By
default the styling is self contained which means that at the end
of the string a reset code is issued . This can be prevented by
passing ` ` reset = False ` ` .
Examples : :
click . echo ( click . style ( ' Hello World! ' , fg = ' green ' ) )
click . echo ( click . style ( ' ATTENTION! ' , blink = True ) )
click . echo ( click . style ( ' Some things ' , reverse = True , fg = ' cyan ' ) )
click . echo ( click . style ( ' More colors ' , fg = ( 255 , 12 , 128 ) , bg = 117 ) )
Supported color names :
* ` ` black ` ` ( might be a gray )
* ` ` red ` `
* ` ` green ` `
* ` ` yellow ` ` ( might be an orange )
* ` ` blue ` `
* ` ` magenta ` `
* ` ` cyan ` `
* ` ` white ` ` ( might be light gray )
* ` ` bright_black ` `
* ` ` bright_red ` `
* ` ` bright_green ` `
* ` ` bright_yellow ` `
* ` ` bright_blue ` `
* ` ` bright_magenta ` `
* ` ` bright_cyan ` `
* ` ` bright_white ` `
* ` ` reset ` ` ( reset the color code only )
If the terminal supports it , color may also be specified as :
- An integer in the interval [ 0 , 255 ] . The terminal must support
8 - bit / 256 - color mode .
- An RGB tuple of three integers in [ 0 , 255 ] . The terminal must
support 24 - bit / true - color mode .
See https : / / en . wikipedia . org / wiki / ANSI_color and
https : / / gist . github . com / XVilka / 8346728 for more information .
: param text : the string to style with ansi codes .
: param fg : if provided this will become the foreground color .
: param bg : if provided this will become the background color .
: param bold : if provided this will enable or disable bold mode .
: param dim : if provided this will enable or disable dim mode . This is
badly supported .
: param underline : if provided this will enable or disable underline .
: param overline : if provided this will enable or disable overline .
: param italic : if provided this will enable or disable italic .
: param blink : if provided this will enable or disable blinking .
: param reverse : if provided this will enable or disable inverse
rendering ( foreground becomes background and the
other way round ) .
: param strikethrough : if provided this will enable or disable
striking through text .
: param reset : by default a reset - all code is added at the end of the
string which means that styles do not carry over . This
can be disabled to compose styles .
. . versionchanged : : 8.0
A non - string ` ` message ` ` is converted to a string .
. . versionchanged : : 8.0
Added support for 256 and RGB color codes .
. . versionchanged : : 8.0
Added the ` ` strikethrough ` ` , ` ` italic ` ` , and ` ` overline ` `
parameters .
. . versionchanged : : 7.0
Added support for bright colors .
. . versionadded : : 2.0
"""
if not isinstance ( text , str ) :
text = str ( text )
bits = [ ]
if fg :
try :
bits . append ( f " \033 [ { _interpret_color ( fg ) } m " )
except KeyError :
raise TypeError ( f " Unknown color { fg !r} " ) from None
if bg :
try :
bits . append ( f " \033 [ { _interpret_color ( bg , 10 ) } m " )
except KeyError :
raise TypeError ( f " Unknown color { bg !r} " ) from None
if bold is not None :
bits . append ( f " \033 [ { 1 if bold else 22 } m " )
if dim is not None :
bits . append ( f " \033 [ { 2 if dim else 22 } m " )
if underline is not None :
bits . append ( f " \033 [ { 4 if underline else 24 } m " )
if overline is not None :
bits . append ( f " \033 [ { 53 if overline else 55 } m " )
if italic is not None :
bits . append ( f " \033 [ { 3 if italic else 23 } m " )
if blink is not None :
bits . append ( f " \033 [ { 5 if blink else 25 } m " )
if reverse is not None :
bits . append ( f " \033 [ { 7 if reverse else 27 } m " )
if strikethrough is not None :
bits . append ( f " \033 [ { 9 if strikethrough else 29 } m " )
bits . append ( text )
if reset :
bits . append ( _ansi_reset_all )
return " " . join ( bits )
def unstyle ( text : str ) - > str :
""" Removes ANSI styling information from a string. Usually it ' s not
necessary to use this function as Click ' s echo function will
automatically remove styling if necessary .
. . versionadded : : 2.0
: param text : the text to remove style information from .
"""
return strip_ansi ( text )
def secho (
message : t . Optional [ t . Any ] = None ,
file : t . Optional [ t . IO [ t . AnyStr ] ] = None ,
nl : bool = True ,
err : bool = False ,
color : t . Optional [ bool ] = None ,
* * styles : t . Any ,
) - > None :
""" This function combines :func:`echo` and :func:`style` into one
call . As such the following two calls are the same : :
click . secho ( ' Hello World! ' , fg = ' green ' )
click . echo ( click . style ( ' Hello World! ' , fg = ' green ' ) )
All keyword arguments are forwarded to the underlying functions
depending on which one they go with .
Non - string types will be converted to : class : ` str ` . However ,
: class : ` bytes ` are passed directly to : meth : ` echo ` without applying
style . If you want to style bytes that represent text , call
: meth : ` bytes . decode ` first .
. . versionchanged : : 8.0
A non - string ` ` message ` ` is converted to a string . Bytes are
passed through without style applied .
. . versionadded : : 2.0
"""
if message is not None and not isinstance ( message , ( bytes , bytearray ) ) :
message = style ( message , * * styles )
return echo ( message , file = file , nl = nl , err = err , color = color )
def edit (
text : t . Optional [ t . AnyStr ] = None ,
editor : t . Optional [ str ] = None ,
env : t . Optional [ t . Mapping [ str , str ] ] = None ,
require_save : bool = True ,
extension : str = " .txt " ,
filename : t . Optional [ str ] = None ,
) - > t . Optional [ t . AnyStr ] :
r """ Edits the given text in the defined editor. If an editor is given
( should be the full path to the executable but the regular operating
system search path is used for finding the executable ) it overrides
the detected editor . Optionally , some environment variables can be
used . If the editor is closed without changes , ` None ` is returned . In
case a file is edited directly the return value is always ` None ` and
` require_save ` and ` extension ` are ignored .
If the editor cannot be opened a : exc : ` UsageError ` is raised .
Note for Windows : to simplify cross - platform usage , the newlines are
automatically converted from POSIX to Windows and vice versa . As such ,
the message here will have ` ` \n ` ` as newline markers .
: param text : the text to edit .
: param editor : optionally the editor to use . Defaults to automatic
detection .
: param env : environment variables to forward to the editor .
: param require_save : if this is true , then not saving in the editor
will make the return value become ` None ` .
: param extension : the extension to tell the editor about . This defaults
to ` . txt ` but changing this might change syntax
highlighting .
: param filename : if provided it will edit this file instead of the
provided text contents . It will not use a temporary
file as an indirection in that case .
"""
from . _termui_impl import Editor
ed = Editor ( editor = editor , env = env , require_save = require_save , extension = extension )
if filename is None :
return ed . edit ( text )
ed . edit_file ( filename )
return None
def launch ( url : str , wait : bool = False , locate : bool = False ) - > int :
""" This function launches the given URL (or filename) in the default
viewer application for this file type . If this is an executable , it
might launch the executable in a new session . The return value is
the exit code of the launched application . Usually , ` ` 0 ` ` indicates
success .
Examples : :
click . launch ( ' https://click.palletsprojects.com/ ' )
click . launch ( ' /my/downloaded/file ' , locate = True )
. . versionadded : : 2.0
: param url : URL or filename of the thing to launch .
: param wait : Wait for the program to exit before returning . This
only works if the launched program blocks . In particular ,
` ` xdg - open ` ` on Linux does not block .
: param locate : if this is set to ` True ` then instead of launching the
application associated with the URL it will attempt to
launch a file manager with the file located . This
might have weird effects if the URL does not point to
the filesystem .
"""
from . _termui_impl import open_url
return open_url ( url , wait = wait , locate = locate )
# If this is provided, getchar() calls into this instead. This is used
# for unittesting purposes.
_getchar : t . Optional [ t . Callable [ [ bool ] , str ] ] = None
def getchar ( echo : bool = False ) - > str :
""" Fetches a single character from the terminal and returns it. This
will always return a unicode character and under certain rare
circumstances this might return more than one character . The
situations which more than one character is returned is when for
whatever reason multiple characters end up in the terminal buffer or
standard input was not actually a terminal .
Note that this will always read from the terminal , even if something
is piped into the standard input .
Note for Windows : in rare cases when typing non - ASCII characters , this
function might wait for a second character and then return both at once .
This is because certain Unicode characters look like special - key markers .
. . versionadded : : 2.0
: param echo : if set to ` True ` , the character read will also show up on
the terminal . The default is to not show it .
"""
global _getchar
if _getchar is None :
from . _termui_impl import getchar as f
_getchar = f
return _getchar ( echo )
def raw_terminal ( ) - > t . ContextManager [ int ] :
from . _termui_impl import raw_terminal as f
return f ( )
def pause ( info : t . Optional [ str ] = None , err : bool = False ) - > None :
""" This command stops execution and waits for the user to press any
key to continue . This is similar to the Windows batch " pause "
command . If the program is not run through a terminal , this command
will instead do nothing .
. . versionadded : : 2.0
. . versionadded : : 4.0
Added the ` err ` parameter .
: param info : The message to print before pausing . Defaults to
` ` " Press any key to continue... " ` ` .
: param err : if set to message goes to ` ` stderr ` ` instead of
` ` stdout ` ` , the same as with echo .
"""
if not isatty ( sys . stdin ) or not isatty ( sys . stdout ) :
return
if info is None :
info = _ ( " Press any key to continue... " )
try :
if info :
echo ( info , nl = False , err = err )
try :
getchar ( )
except ( KeyboardInterrupt , EOFError ) :
pass
finally :
if info :
echo ( err = err )