PyCon 2017 (Part 2!)
Talk: “Double Click: Continue Building Better CLIs”
Summarized by Kévin Barralon
This PyCon Canada talk was a presentation of Click, a Python package that allows you to create CLIs (Command-Line Interfaces) with only a few lines of code.
Click is simple and easy to use, in that the configuration of commands happens almost entirely using decorators around your Python functions. For example, here is a simple function that can be used to repeat the word you pass it as an argument:
# hello.py
import click<span style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" data-mce-type="bookmark" class="mce_SELRES_start"></span>
@click.command()
@click.option('--count', default=1, type=int, help='Number of greetings.')
@click.option('--name', prompt='Your name',
help='The person to greet.')
def hello(count, name):
for _ in range(count):
click.echo(f'Hello {name}!') # Syntaxe de Python 3.6 !
if __name__ == '__main__':
hello()
In just a few lines of code, you’ve created a command that can:
- take an option
--count
with a default value of 1 and that is type-cast to an integer. - take an option
--name
which allows the user to state their name, thanks to the ‘prompt’ argument passed in the decorator
These values are passed directly as the count
and name
parameters of the decorated function.
To run this command in your terminal:
python3 test.py --count=3
Your name: Casimir
Hello Casimir!
Hello Casimir!
Hello Casimir!
The other interesting (and practical!) point here is that if you pass the option --help
when you call the command, you can see the docstring for your function, as well as information on each option that your comamnd supports thanks to the argument help
passed in your decorators:
python3 hello.py --help
Usage: test.py [OPTIONS]
Simple program that greets NAME for a total of COUNT times.
Options:
Count INTEGER Number of greetings
Name TEXT The person to greet
Help Show this message and exit.
Rather than simply passing options to your command, you can also specify arguments. For example:
@click.command()
@click.argument('filename')
def touch(filename):
click.echo(filename)
Then:
python3 touch.py foo.txt
foo.txt # Résultat
As you can see, the possibilities with Click are endless. Here are a few additional ones for fun:
- Add the argument
multiple=True
in your decorator @click.option
which will give you a tuple of all options passed to your command. - Add a callback as an argument to
@click.option
which will change the behaviour of your command (to define custom validation rules, for example). - Pass environment variables to your decorator (like so:
envar="USERNAME"
).
Define a limited or unlimited number of arguments that will return a tuple. - Add a File method as a type in your decorator (example:
@click.argument('input', type=click.File('rb'))
) which will automatically open a specified file and close it when necessary.
A list of all possibilities offered by this Python package is available in the documentation, which is indeed very well done.
Bonus!
The closing keynote on f-strings really seemed to motivate our team! Here’s an article by Maxime which adds to the one by Sébastien from last week:
What in the World Are F-Strings?
By Maxime Dupuis
The mechanism of Literal String Interpolation, known as f-strings, is a new arrival in the latest version of Python, 3.6. They are recognizable by the f
(or F
) at the beginning of a declaration of a string: f'My f-string!'
. They are very similar in behaviour to template strings in JavaScript, which are defined using the `
character.
F-strings are useful because they can reference variables that will be automatically interpolated with the values of the local variables defined under the same name.
>>> age = 42
>>> first_name = 'Maxime'
>>> f"My name is {first_name} and I'm {age} years old"
"My name is Maxime and I'm 42 years old"
>>> # The use of an undefined variable will give us a NameError:
>>> f"{notdefined}"
Traceback (most recent call last):
File "<stdin>;", line 1, in <module>
NameError: name 'notdefined' is not defined
They become very interesting when you consider their impact on performance. If we compare them to other ways to create strings in Python, we have the following:
python3.6 -m timeit -c 'age=42; first_name="Maxime"; f"My name is {first_name} and I'm {age} years old"'
10000000 loops, best of 3: 0.172 usec per loop
python3.6 -m timeit -c 'age=42; first_name="Maxime"; "My name is {first_name} and I'm {age} years old".format(first_name=first_name, age=age)'
1000000 loops, best of 3: 0.714 usec per loop
python3.6 -m timeit -c 'age=42; first_name="Maxime"; "My name is %s and I'm %s years old" % (prenom, age)'
1000000 loops, best of 3: 0.283 usec per loop
python3.6 -m timeit -c 'age=42; first_name="Maxime"; "My name is " + prenom + " and I'm " + str(age) + " years old"'
1000000 loops, best of 3: 0.449 usec per loop
python3.6 -m timeit -c 'from string import Template; age=42; first_name="Maxime"; Template("My name is $first_name and I'm $age years old").substitute(first_name=first_name, age=age)'
100000 loops, best of 3: 8.75 usec per loop
But it’s not only useful for its performance benefits. We can use f-strings to call functions, modify substrings, and many other things:
>>> total = 10.0
>>> taxes = 1.15
>>> f'Total: {total + taxes}'
'Total: 11.15'
>>> first_name = 'Maxime'
>>> f'My name is {first_name.upper()}'
'My name is MAXIME'
If f-strings interest you or you haven’t yet discovered all of the new things that Python 3.6 has to offer, check out the release notes.
Mobility
SwiftGen
By Thibault Wittemberg
When we develop an iOS app, we regularly need to access resources. The traditional way to use them in the code is to instantiate them with their identifiers (strings):
let avatar = UIImage(named: ‘darthVader’) // gets the ‘darthVader’ image from the assets folder
let name = NSLocalizedString (‘darthVader’, comment: ‘’) // gets the localized string with the key ‘darthVader’ from the Localizable.strings file
The same goes for fonts, storyboards and colors.
Swift is a strict language about type management and promotes the detection of errors at compile time rather than at run time.
That being said, what happens if one of the resources we want to instantiate is not found at run time? Since this instantiation is based on a string, it is subject to errors (typo errors). Therefore, we can use the SwiftGen tool which allows to secure this kind of manipulation:
- It avoids typo errors
- It allows auto completion
- It ensures that the resources exist at compile time.
It operates as follows:
- The “SwiftGen” executable is installed on the development workstation (either via Homebrew or via CocoaPods)
- A custom build phase launches this executable for each compilation
- SwiftGen scans the project’s resources and generates the Swift code representing them in a “type safe” manner
The resource identifiers will be transformed into enums that are much more secure and easy to use. Consider the following example:
let avatar = Asset.darthVader.image
let name = L10n.darthVader
It is even possible to customize the templates that will be used to generate the code if you want to apply a different coding style.
When combined with the “Reusable” framework (from the same author), we have tools that are almost mandatory (and we use them a lot at Savoir-faire Linux).
SwiftGen is made to be integrated with your continuous integration environment (the executable can be embedded in a CocoaPods dependency, it avoids installing it on the build machine). Read more on GitHub!
Contributions
New Release of num2words v0.5.6 with Support for New Languages!
By Ernesto Ortiz
It has been five months since the previous release of num2words v0.5.5, and these have been five really active months. A lot of new contributors have made some great improvements and have added support for new languages! Here are some of the latest changes, with “special thanks” to the contributors!
- ‘Num2words’ has changed its coding conventions to follow PEP8. Code coverage has increased a lot, and we need your help to continue improving this, so check out the issues related to num2words
- Now we can use other converters like
to_currency
, to_year
, to_ordinal_num
- Thanks to Tufan Kaynak for adding support for the Turkish localization
- Thanks to Jesús Leganés-Combarro for adding support for Algerian French localization
- Thanks to Armin Oliya for adding support for the Dutch localization
- Thanks to Sergio Zholudov for adding support for the Ukrainian localization
- Thanks to Blaž Bregar for adding support for the Slovenian localization
- Thanks to Mārtiņš Šulcs for making a lot of improvements to the base code,
to_currency
functionalities and more!
Special thanks to everyone that has taken the time to report new issues, to make pull requests and to share their time and effort with this project!
You can check the new release at the following links: