Double Click - Continue Building Better CLIs

C65d18a43152b199ee94aad2b79b70c4?s=47 Seb
November 18, 2017

Double Click - Continue Building Better CLIs

C65d18a43152b199ee94aad2b79b70c4?s=128

Seb

November 18, 2017
Tweet

Transcript

  1. 2.

    Check Out Click - Part I Click - A Pleasure

    To Write, A Pleasure To Use (PyCon US 2016)
  2. 3.

    Seb • @elbaschid • Freelance Coder at Roadside Software •

    Outdoor Tour Guide • Vancouver ➡ Rocky Mountains
  3. 8.

    Option • Optional parameter • Name and value required •

    Flags as special options What It Looks Like: $ heroku --help $ heroku logs --app my-heroku-app
  4. 9.

    (Sub-)Command • Nested commands allowed • Groups sub-commands • Has

    options & arguments What It Looks Like: $ pip install django
  5. 14.

    Basic Example # cli.py import click @click.command() @click.option('--times', '-t', type=int)

    @click.argument('symbol') def main(times, symbol): print(f'I {symbol * times} Click!') if __name__ == '__main__': main()
  6. 16.

    Breaking It $ python test.py -t five ❤ Usage: test.py

    [OPTIONS] SYMBOL Error: Invalid value for "--times" / "-t": five is not a valid integer
  7. 21.

    weather config $ weather config Please enter your API key

    []: mysecretapikey $ cat ~/.weather.cfg mysecretapikey
  8. 22.

    weather forecast $ weather forecast Montreal Time Description Min Temp

    Max Temp ============================================================ Tue, Nov 14 @ 00h clear sky -2.3 2.1 Tue, Nov 14 @ 03h clear sky -2.8 0.1 Tue, Nov 14 @ 06h few clouds -2.7 -1.2 Tue, Nov 14 @ 09h few clouds -2.9 -2.9 ... ... ... ...
  9. 30.

    Running It $ weather config Please enter your API key

    []: mysecretapikey $ cat ~/.weather.cfg mysecretapikey
  10. 35.

    Save The Key def config(config_file, api_key): api_key = click.prompt( 'Please

    enter your API key', default=api_key ) with open(config_file, 'w') as cfg: cfg.write(api_key)
  11. 37.

    weather forecast <name> $ weather forecast Montreal Time Description Min

    Temp Max Temp ============================================================ Tue, Nov 14 @ 00h clear sky -2.3 2.1 Tue, Nov 14 @ 03h clear sky -2.8 0.1 Tue, Nov 14 @ 06h few clouds -2.7 -1.2 Tue, Nov 14 @ 09h few clouds -2.9 -2.9 ... ... ... ... API Call https://api.openweathermap.org/data/2.5/forecast?q=Montreal
  12. 38.

    weather forecast <city ID> $ weather forecast 6077243 Time Description

    Min Temp Max Temp ============================================================ Tue, Nov 14 @ 00h clear sky -2.3 2.1 Tue, Nov 14 @ 03h clear sky -2.8 0.1 Tue, Nov 14 @ 06h few clouds -2.7 -1.2 Tue, Nov 14 @ 09h few clouds -2.9 -2.9 ... ... ... ... API Call https://api.openweathermap.org/data/2.5/forecast?id=6077243
  13. 41.

    Our Location Type class LocationType(click.ParamType): name = 'location' def convert(self,

    value, param, ctx): try: value = int(value) except ValueError: query = 'q' else: query = 'id' return Location(query, value)
  14. 42.

    Use It @main.command() @click.argument('location', type=LocationType()) def forecast(location): ... url =

    'https://api.openweathermap.org/data/2.5/forecast' params = { location.query: location.value, } response = session.get(url, params=params) ...
  15. 43.

    weather forecast $ weather forecast Montreal Time Description Min Temp

    Max Temp ============================================================ Tue, Nov 14 @ 00h clear sky -2.3 2.1 Tue, Nov 14 @ 03h clear sky -2.8 0.1 Tue, Nov 14 @ 06h few clouds -2.7 -1.2 Tue, Nov 14 @ 09h few clouds -2.9 -2.9 ... ... ... ...
  16. 45.

    The Test Runner from click.testing import CliRunner def test_writing_config_file(): runner

    = CliRunner() runner.invoke( main, ['config'], input='mysecretapikey', ) ...
  17. 46.

    Filesystem Tests with runner.isolated_filesystem() as env: api_key = '00ee52f44f3350c73f2684a0f23f2805' filename

    = f'{env}/weather.cfg' result = runner.invoke( main, ['--config-file', filename, 'config'], input=api_key, )
  18. 47.

    The Result assert result.exit_code == 0 assert api_key in result.output

    with open(filename) as cfg_file: assert cfg_file.read() == api_key
  19. 49.

    Learn More • PyPA Packaging User Guide • Grug make

    fire! Grug make wheel! - Russell Keith-Magee • Shipping Software To Users With Python - Glyph
  20. 50.

    Choose A License It's a minefield, people. All I'm saying

    is this: the next time you release code into the wild, do your fellow developers a favor and pick a license – any license. — Coding Horror
  21. 55.

    Generated Code #!${VENV}/bin/python3 # EASY-INSTALL-ENTRY-SCRIPT: 'double-click-weather','console_scripts','weather' __requires__ = 'double-click-weather' import

    re import sys from pkg_resources import load_entry_point if __name__ == '__main__': sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) sys.exit( load_entry_point('double-click-weather', 'console_scripts', 'weather')() )
  22. 57.

    PyCascades 2018 Vancouver, BC ! 22-23 January, 2018 ! Get

    Your Ticket ! http://www.pycascades.com
  23. 58.
  24. 59.

    Need Help Building Cool Let's Talk seb@roadsi.de | www.roadsi.de Slides:

    bit.ly/pyconca-double-click Code: bit.ly/double-click-example
  25. 61.

    Unix-style Pipeline $ weather find Montreal | weather forecast Time

    Description Min Temp Max Temp ============================================================ Tue, Nov 14 @ 00h clear sky -2.3 2.1 Tue, Nov 14 @ 03h clear sky -2.8 0.1 Tue, Nov 14 @ 06h few clouds -2.7 -1.2 ... ... ... ...