Skip to content

Instantly share code, notes, and snippets.

@geoangelotti
Created September 22, 2023 15:02
Show Gist options
  • Save geoangelotti/00cce9fef27db23e5a1ca3c8c0db2f9e to your computer and use it in GitHub Desktop.
Save geoangelotti/00cce9fef27db23e5a1ca3c8c0db2f9e to your computer and use it in GitHub Desktop.
Click tutorial
import pprint
import click
import json
'''
@click.group(<name>) creates a command that instantiates a group class
a group is intended to be a set of related commands
@click.argument(<argument name>) tells us that we will be passing an argument
and referring to that argument in the function by the name we pass it
@click.pass_context tells the group command that we're going to be using
the context, the context is not visible to the command unless we pass this
In our example we'll name our group "cli"
'''
@click.group("cli")
@click.pass_context
@click.argument("document")
def cli(ctx, document):
"""An example CLI for interfacing with a document"""
_stream = open(document)
_dict = json.load(_stream)
_stream.close()
ctx.obj = _dict
'''
@click.command(<name>) creates a command that can be called with
the name that we pass through
Here we'll create an example command that prints out our context object,
which we expect to be a json looking dictionary
'''
@cli.command("check_context_object")
@click.pass_context
def check_context(ctx):
pprint.pprint(type(ctx.obj))
'''
Here we'll make a pass decorator, which we can use to pass
the last object stored of a type of our choosing in the context
by using click.make_pass_decorator(<type>)
'''
pass_dict = click.make_pass_decorator(dict)
'''
click.echo is click's version of the echo command
click.style lets us style our output
click.secho is a command that takes a message, and a style command,
is a combination of click.echo and click.style
This command returns the keys to our dictionary object and
demonstrates how to use click.echo, click.style, and click.secho
'''
@cli.command("get_keys")
@pass_dict
def get_keys(_dict):
keys = list(_dict.keys())
click.secho("The keys in our dictionary are", fg="green")
click.echo(click.style(keys, fg="blue"))
'''
This command gets a specific key from the context object
'''
@cli.command("get_key")
@click.argument("key")
@click.pass_context
def get_key(ctx, key):
pprint.pprint(ctx.obj[key])
'''
click.invoke(<command>, <args>) is click's way of letting us
arbitrarily nest commands. NOTE: this command can only be used
when both the command being invoked AND the the command
doing the invoking use @click.pass_context
Since we already have a get_key command, we can just call that
to print out a summary
'''
@cli.command("get_summary")
@click.pass_context
def get_summary(ctx):
ctx.invoke(get_key, key="summary")
'''
@click.option(<one dash usage>, <two dash usage>, is_flag (optional), help = <help>)
is how we can pass options to our command
We'll create a function that gets the "results" of our dictionary
and we will pass it two optional arguments, one to specify that
we want a specific key from the results, and a flag to indicate
whether or not we want to save our results to a json file
'''
@cli.command("get_results")
@click.option("-d", "--download", is_flag=True, help="Pass to download the result to a json file")
@click.option("-k", "--key", help="Pass a key to specify that key from the results")
@click.pass_context
def get_results(ctx, download: bool, key: str):
results = ctx.obj['results']
if key is not None:
result = {}
for entry in results:
if key in entry:
if key in result:
result[key] += entry[key]
else:
result[key] = entry[key]
results = result
if download:
if key is not None:
filename = key+'.json'
else:
filename = "results.json"
with open(filename, 'w') as w:
w.write(json.dumps(results))
print("File saved to", filename)
else:
pprint.pprint(results)
'''
@click.pass_obj is similar to @click.pass_context, instead
of passing the whole context, it only passes context.obj
We'll do something fun with our text extractor, we'll include
options to extract as either paragraphs or sentences, and
default to returning one big block of text
'''
@cli.command("get_text")
@click.option("-s", "--sentences", is_flag=True, help="Pass to return sentences")
@click.option("-p", "--paragraphs", is_flag=True, help="Pass to return paragraphs")
@click.option("-d", "--download", is_flag=True, help="Download as a json file")
@click.pass_obj
def get_text(_dict, sentences, paragraphs, download):
"""Returns the text as sentences, paragraphs, or one block by default"""
results = _dict['results']
text = {}
for idx, entry in enumerate(results):
if paragraphs:
text[idx] = entry['text']
else:
if 'text' in text:
text['text'] += entry['text']
else:
text['text'] = entry['text']
if sentences:
sentences = text['text'].split('.')
for i in range(len(sentences)):
if sentences[i] != '':
text[i] = sentences[i]
del text['text']
pprint.pprint(text)
if download:
if paragraphs:
filename = "paragraphs.json"
elif sentences:
filename = "sentences.json"
else:
filename = "text.json"
with open(filename, 'w') as w:
w.write(json.dumps(results))
print("File saved to", filename)
def main():
cli(prog_name="cli")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment