52
+ FIVE PYTHON PACKAGES YOU NEED TO KNOW

Five

Embed Size (px)

Citation preview

Page 1: Five

+

FIVE

PYTHON

PACKAGES YOU

NEED TO KNOW

Page 2: Five

+

Łukasz Langa

ambv #python-dev

@llanga Twitter

[email protected]

Page 3: Five

+

pip install first

1

Page 4: Five

+pip install first

>>> quiet = False

>>> if not quiet:

... print("O HAI PYCON!")

...

O HAI PYCON!

Page 5: Five

+pip install first

>>> error_count = 2

>>> if error_count:

... sys.exit(1)

...

ambv@host $

Page 6: Five

+pip install first

>>> leftovers = ['foo', 'bar']

>>> if leftovers:

... print('{} things left.'

... ''.format(len(leftovers)))

...

2 things left.

Page 7: Five

+pip install first

>>> leftovers = [0, None]

>>> if leftovers:

... print('{} things left.'

... ''.format(len(leftovers)))

...

2 things left.

Page 8: Five

+pip install first

>>> leftovers = [0, None]

>>> if any(leftovers):

... print('{} things left.'

... ''.format(len(leftovers)))

...

>>>

Page 9: Five

+pip install first

>>> any([0, 1, 2])

True

Page 10: Five

+pip install first

>>> any([0, 1, 2])

True

>>> first([0, 1, 2])

1

Page 11: Five

+pip install first

s = 'abc'm = re1.match(s)if m:

print('re1', m.group(1))else:

m = re2.match(s)if m:

print('re2', m.group(1))else:

m = re3.match(s)if m:

print('re3', m.group(1))else:

print('no match!')

Page 12: Five

+pip install first

s = 'abc'm = first(r.match(s)

for r in [re1, re2, re3])

if not m:print('no match!’)

elif m.re is re1:print('re1', m.group(1))

elif m.re is re2:print('re2', m.group(1))

elif m.re is re3:print('re2', m.group(1))

Page 13: Five

+

pip install parse

2{ }

Page 14: Five

+pip install parse

>>> old_fmt = "Number %f and something else: %s">>> old_fmt % (1.23456, '\u0141ukasz')'Number 1.234560 and something else: Łukasz'

Old and busted

Page 15: Five

+pip install parse

>>> fmt = "Number {:f} and something else: {}">>> fmt.format(1.23456, '\u0141ukasz')'Number 1.234560 and something else: Łukasz'

New hotness

Page 16: Five

+pip install parse

>>> fmt = "Number {:f} and something else: {}">>> fmt.format(1.23456, '\u0141ukasz')'Number 1.234560 and something else: Łukasz'>>> concrete_string = _>>> parse(fmt, concrete_string)<Result (1.23456, 'Łukasz') {}>>>> r = _>>> r[0]1.23456>>> r[1]'Łukasz'

New hotness

Page 17: Five

+

filecmp

3

Page 18: Five

+filecmp

$ tree /tmp/dir1

.├── dirdir1│ ├── fileA│ └── fileB├── file1├── file2└── file3

Page 19: Five

+filecmp

>>> import filecmp>>> filecmp.cmp('/tmp/dir1/file1',... '/tmp/dir1/file2')False

>>> filecmp.cmp('/tmp/dir1/file1',... '/tmp/dir1/file3')True

Page 20: Five

+filecmp

>>> import filecmp>>> filecmp.cmp('/tmp/dir1/file1',... '/tmp/dir1/file2')False

>>> filecmp.cmp('/tmp/dir1/file1',... '/tmp/dir1/file3')True

Page 21: Five

+filecmp

>>> import filecmp>>> filecmp.cmp('/tmp/dir1/file1',... '/tmp/dir1/file2')False

>>> filecmp.cmp('/tmp/dir1/file1',... '/tmp/dir1/file3')True

Page 22: Five

+filecmp

>>> result = filecmp.dircmp('/tmp/dir1', '/tmp/dir2')

>>> result.report()diff /tmp/dir1 /tmp/dir2Identical files : ['file1', 'file3']Differing files : ['file2']Common subdirectories : ['dirdir1']

>>> result.report_full_closure()diff /tmp/dir1 /tmp/dir2Identical files : ['file1', 'file3']Differing files : ['file2']Common subdirectories : ['dirdir1']

diff /tmp/dir1/dirdir1 /tmp/dir2/dirdir1Only in /tmp/dir1/dirdir1 : ['fileB']Identical files : ['fileA']

Page 23: Five

+filecmp

>>> result = filecmp.dircmp('/tmp/dir1', '/tmp/dir3')

>>> result.report()diff /tmp/dir1 /tmp/dir3Identical files : ['file1', 'file2', 'file3']Common subdirectories : ['dirdir1']

>>> result.report_full_closure()diff /tmp/dir1 /tmp/dir3Identical files : ['file1', 'file2', 'file3']Common subdirectories : ['dirdir1']

diff /tmp/dir1/dirdir1 /tmp/dir3/dirdir1Identical files : ['fileA', 'fileB']

Page 24: Five

+

pip install bitrot

4

Page 25: Five

+pip install bitrot

$ cd /tmp/dir1$ bitrot

Finished. 0.00 MiB of data read. 0 errors found.

5 entries in the database, 5 new, 0 updated,0 renamed, 0 missing.

Page 26: Five

+pip install bitrot

$ sqlite3 .bitrot.dbsqlite> select * from sqlite_master where name='bitrot';

table|bitrot|bitrot|2|CREATE TABLE bitrot(path TEXT PRIMARY KEY, mtime INTEGER, hash TEXT, timestamp TEXT)

sqlite> select * from bitrot limit 1;

./dirdir1/fileA|1363385094|5183b6e4557a39428eb00d4a14437e45c448ccc6|2013-03-15 22:29:46

Page 27: Five

+pip install bitrot

$ bitrot

Finished. 0.00 MiB of data read. 0 errors found.

5 entries in the database, 0 new, 0 updated,0 renamed, 0 missing.

Page 28: Five

+pip install bitrot

$ mv file2 file4$ rm file3$ echo "Another line." >>file1

$ bitrot

Finished. 0.00 MiB of data read. 0 errors found.

4 entries in the database, 0 new, 1 updated,1 renamed, 1 missing.

Page 29: Five

+pip install bitrot

$ bitrot

error: SHA1 mismatch for ./file4:expected cd3be7e3d60016ce01a835c562e2748cf2cbe596,got 3875db357b18eb06fae627d1dc0320efa89c2006. Original info from 2013-03-15 23:29:46.

Finished. 0.00 MiB of data read. 1 error found.

4 entries in the database, 0 new, 0 updated,0 renamed, 0 missing.

Page 30: Five

+

pip install docopt

5

Page 31: Five

+pip install docopt

$ rename --helpusage: rename [-h] [-c] [-I] [-l] [-q] [-U] [-v EXCEPT_REGEX] [-t]

[--index-first INDEX_FIRST] [--index-step INDEX_STEP][--index-digits INDEX_DIGITS] [--index-pad-with INDEX_PAD_WITH][-s] [--selftest [use_directory]]regex target

positional arguments:regex regular expression to match files withtarget target pattern using references to groups in the

regular expressionoptional arguments:-h, --help show this help message and exit-c, --copy copy files instead of renaming-I, --case-insensitive

treat the regular expression as case-insensitive-l, --lower translate all letters to lower-case-q, --quiet don't print anything, just return status codes-U, --upper translate all letters to upper-case-v EXCEPT_REGEX, --except EXCEPT_REGEX

exclude files matching the following regularexpression

-t, --test test only, don't actually rename anything-s, --simple invokes the simple mode. For more help on its

positional arguments: rename -s –help--selftest [use_directory]

run internal unit tests

Page 32: Five

+pip install docopt

stparser = argparse.ArgumentParser(prog='rename', add_help=False)classic = argparse.ArgumentParser(prog='rename')simple = argparse.ArgumentParser(prog='rename')invocator = Proxy(classic, stparser)simple.add_argument('-s', '--simple', action='store_true', help='invokes '

'the simple mode', required=True)common = Proxy(classic, simple)common.add_argument('-c', '--copy', action='store_true',

help='copy files instead of renaming')common.add_argument('-I', '--case-insensitive', action='store_true',

help='treat the regular expression as case-insensitive')common.add_argument('-l', '--lower', action='store_const', dest='xform',

const='lower', help='translate all letters to lower-case')common.add_argument('-q', '--quiet', action='store_true',

help='don\'t print anything, just return status codes')common.add_argument('-U', '--upper', action='store_const', dest='xform',

const='upper', help='translate all letters to upper-case')common.add_argument('-v', '--except', dest='except_regex', action='store',

default="", help='exclude files matching the following ''regular expression')

common.add_argument('-t', '--test', action='store_true', help='test only, ''don\'t actually rename anything')

group = classic.add_argument_group('Configuration for the special ''\\(index) reference')

group.add_argument('--index-first', default=1, help='specifies ''what number will the first \\(index) substitution contain. Default: 1')

group.add_argument('--index-step', default=1, help='specifies ''what number will be added with each step to the first value. Negative ''numbers allowed. Default: 1')

group.add_argument('--index-digits', default='auto',help='specifies how many digits will be used in each \\(index) ''substitution. If a number has fewer digits, they will be prefixed by ''leading zeroes (or another character, see --index-pad-with). Default: ''auto (e.g. path enough digits so that each number uses the same amount'' of characters)')

group.add_argument('--index-pad-with', default='0',help='specifies what character will be used for padding. Default: "0"')

invocator.add_argument('-s', '--simple', action='store_true', help='invokes ''the simple mode. For more help on its positional arguments: ''rename -s --help')

invocator.add_argument('--selftest', nargs='?', const=True,metavar='use_directory', help='run internal unit tests')

classic.add_argument('regex', help='regular expression to match ''files with')

classic.add_argument('target', help='target pattern using ''references to groups in the regular expression')

simple.add_argument('substring_from', help='simple (raw) substring that ''should be found within the filename')

simple.add_argument('substring_to', help='the replacement string')simple.add_argument('regex', help='regular expression to match '

'files with')args = stparser.parse_known_args()if args[0].selftest:

selftest(args[0].selftest)elif args[0].simple:

args = simple.parse_args()args.regex = "".join(args.regex)args.substring_from = "".join(args.substring_from)args.substring_to = "".join(args.substring_to)sys.exit(Renamer(**args.__dict__).rename_simple(**args.__dict__))

else:args = classic.parse_args()args.regex = "".join(args.regex)args.except_regex = "".join(args.except_regex)args.target = "".join(args.target)

Page 33: Five

+pip install docopt

$ httproxy --helpTiny HTTP Proxy.

This module implements GET, HEAD, POST, PUT, DELETE and CONNECTmethods on BaseHTTPServer.

Usage:httproxy [options]httproxy [options] <allowed-client> ...

Options:-h, --help Show this screen.--version Show version and exit.-H, --host HOST Host to bind to [default: 127.0.0.1].-p, --port PORT Port to bind to [default: 8000].-l, --logfile PATH Path to the logfile [default: STDOUT].-i, --pidfile PIDFILE Path to the pidfile [default: httproxy.pid].-d, --daemon Daemonize (run in the background). The

default logfile path is httproxy.log inthis case.

-c, --configfile CONFIGFILE Path to a configuration file.-v, --verbose Log headers.

Page 34: Five

+pip install docopt

"""Tiny HTTP Proxy.

This module implements GET, HEAD, POST, PUT, DELETE and CONNECTmethods on BaseHTTPServer.

Usage:httproxy [options]httproxy [options] <allowed-client> ...

Options:-h, --help Show this screen.--version Show version and exit.-H, --host HOST Host to bind to [default: 127.0.0.1].-p, --port PORT Port to bind to [default: 8000].-l, --logfile PATH Path to the logfile [default: STDOUT].-i, --pidfile PIDFILE Path to the pidfile [default: httproxy.pid].-d, --daemon Daemonize (run in the background). The

default logfile path is httproxy.log inthis case.

-c, --configfile CONFIGFILE Path to a configuration file.-v, --verbose Log headers.

"""

Page 35: Five

+pip install docopt

cmdline_args = docopt(__doc__, version=__version__,

)

Page 36: Five

+

pip install six

6

Page 37: Five

+pip install six

Have a Python 2.x project?

1. Write those tests, seriously.

2. Target 2.7 with __futures__:

division

print_function

unicode_literals

3. Run tests on 3.3. Use six to fix leftovers.

4. There is no step 4! *

Page 38: Five

+pip install six

* Well, to have all bases covered, read:

http://docs.python.org/3/

howto/pyporting.html

Page 39: Five

+pip install six

Have a Python 2.x project?

1. Tests.

2. 2.7 + three futures.

3. Run tests on both 2.7 and 3.3.

Fix whatever doesn’t work using six.

Page 40: Five

+pip install six

six.text_type / six.binary_type

Page 41: Five

+pip install six

six.text_type / six.binary_type

six.iterkeys / six.iteritems / six.itervalues

Page 42: Five

+pip install six

six.text_type / six.binary_type

six.iterkeys / six.iteritems / six.itervalues

six.next

Page 43: Five

+pip install six

six.text_type / six.binary_type

six.iterkeys / six.iteritems / six.itervalues

six.next

six.with_metaclass

Page 44: Five

+pip install six

six.text_type / six.binary_type

six.iterkeys / six.iteritems / six.itervalues

six.next

six.with_metaclass

from six.moves import xrange

Page 45: Five

+pip install six

six.text_type / six.binary_type

six.iterkeys / six.iteritems / six.itervalues

six.next

six.with_metaclass

from six.moves import xrange

if six.PY3:

Page 46: Five

+

pip install tox

7

Page 47: Five

+pip install tox

[tox]envlist = py27,py32,py33

[testenv]changedir = testcommands =

{envbindir}/python run_tests.py

[testenv:py27]basepython = python2.7deps =

configparser

tox.ini

Page 48: Five

+pip install tox

$ tox..._________________ summary _________________

py26: commands succeeded

py27: commands succeeded

py32: commands succeeded

py33: commands succeeded

congratulations :)

Page 49: Five

+

Travis-CI

BONUS

Page 50: Five

+Travis-CI

language: python

before_install:- pip install tox

script: tox

.travis.yml

Page 51: Five

+Travis-CI

Page 52: Five

+

Łukasz Langa

ambv #python-dev

@llanga Twitter

[email protected]