python: 7 patterns for scripting - scale 16x | 16x · python: 7 patterns for scripting matt...

65
Python: 7 Patterns for scripting Matt Harrison [email protected] http://panela.blog-city.com/ SCALE 2009 (C)2008, licensed under a CC (BY-SA) license.

Upload: phamngoc

Post on 17-Jun-2018

242 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Python: 7 Patterns for scripting

Matt [email protected]

http://panela.blog-city.com/

SCALE 2009

(C)2008, licensed under a CC (BY-SA) license.

Page 2: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Beginner level

Page 3: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Cliff's Notes

See handout and poachplate.

Page 4: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Python Continuum

Page 5: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Focus on stdlib and pure python

Page 6: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Why Python?

Page 7: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Advantages of Python

● Clean code● 3rd party libs● Cross platform● Threading● Datastructures (lists, dicts)● Performance● ...

Page 8: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Cons of Python

● Not as 'high level' as bash● gluing scripts together is more tedious

Page 9: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

>>> import this The Zen of Python, by Tim Peters There should be one-- and preferably only one --obvious way to do it.

Page 10: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Scripting patterns in python

Page 11: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

1 Compromise Layout

Page 12: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Scrapage/Packript

Page 13: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

.py (module/package) vs script

Page 14: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

PATH vs PYTHONPATH

PATH

● executable● not (usually) importable

Page 15: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

PATH vs PYTHONPATH

PYTHONPATH

● not (usually) executable● importable

Page 16: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Compromise layout

Layout:Project/ bin/ script(.py) (thin wrapper) scriptlib/ __init__.py scriptimpl.py setup.py

Page 17: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

2 Conditional main

Page 18: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Bad

>>> lines = open(sys.argv[1]).readlines()>>> for line in lines:... ..>>> # More stuff>>> # Other stuff>>> # No functions>>> sys.exit()

Page 19: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Good practices

● Don't want behavior to change during import● Globals are 'bad'● Limit side effects● move logic into grokable chunks (ie functions)

Page 20: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Conditional main

>>> # imports>>> # classes/functions>>> def main(prog_args):... # process args... # execute functions... # return exit code>>> if __name__ == '__main__':... sys.exit(main(sys.argv))

Page 21: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

sys.exit

Limit use

● 0 - Sucess● Non-Zero - Error

Page 22: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Results

● Modular code● Testable chunks● Code can be imported/reused● Easier to modify

Page 23: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Summarize

ok to have bad code for run once or if no one else is using it

Page 24: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

3 - 3 Layers of I/O

Page 25: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

What interface?

● main - filename● file-like● generator

Page 26: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

main

● accepts filenames (defaults to sdtin/stdout)● Do file exception handling here● Do close of files

Page 27: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

file-like

Can take open(), sys.stdin, StringIO...

● Testing is easier

Page 28: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Generator

● Efficient(Also use when dealing with dbs)

Page 29: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Generators 101>>> def num_list(count):... results = []... i = 0... while i < count:... results.append(i)... i += 1... return resultsGenerator:>>> def num_gen(count):... i = 0... while i < count:... yield i... i += 1

Page 30: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Generators 101 (2)

>>> for num in num_list(3):... print numGenerator:>>> for num in num_gen(3):... print num

Page 31: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Generators 101 (2)

>>> num_list(3)[0,1,2]>>> gen = num_gen(3)>>> gen<generator object at 0x7f78e133dcf8>>>> gen.next()0>>> gen.next()1

Page 32: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

3 layers

>>> def gen_cat(line_iter):... for line in line_iter:... # business logic... yield line>>> def file_cat(fin, fout):... for line in gen_cat(fin):... fout.write(line)

Page 33: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

3 layers (cont)

>>> def main(pargs):... # optparse blah blah...... fin = sys.stdin... if opt.fin:... fin = open(opt.fin)... fout = sys.stdout... file_cat(fin, fout)

Page 34: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Testing generator

>>> list(gen_cat(['foo\n','bar\n'])) ['foo\n', 'bar\n']

Page 35: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Testing file

>>> import StringIO>>> fout = StringIO.StringIO()>>> file_cat(StringIO.StringIO('foo\nbar\n'), fout)>>> fout.getvalue() foo bar

Page 36: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Testing filename

>>> main(['--fin', '/tmp/foo', '--fout', '/tmp/out'])>>> open('/tmp/out/').read() foo bar

Page 37: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

4 Use optparse

Page 38: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Commandline parsing options

● manual● getopt● optparse

Page 39: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

optparse benefits

● Nice usage (--help)● Provides --version

Page 40: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

5 Composite scripts

Page 41: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Composite scripts

SVN style "script command --options">>> def main(pargs): # pargs = ['script.py', 'status', '--some-option']... if pargs[1] == 'status':... status.main(pargs[2:])

Page 42: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Bonus

If you want to have scripts support this, you get it for free from complying with Executable main and Use optparse

Page 43: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

6 Leave no trace

Page 44: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

No print

Page 45: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

How will I debug?

Page 46: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Use logging

Page 47: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

logging boilerplate>>> LOGFILE = os.path.expanduser('~/.script.log')>>> logger = logging.getLogger('ScriptLogger')>>> logger.setLevel(logging.DEBUG)>>> handler = handlers.RotatingFileHandler(LOGFILE, maxBytes=500, backupCount=2)>>> log_format = Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")>>> handler.setFormatter(log_format)>>> logger.addHandler(handler)

Page 48: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

atexit is also your cleaning friend

Page 49: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Benefits

● Using 3 layers● You'll have (proper) logging

Page 50: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

7 Great artists steal

Page 51: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

setup.py

Page 52: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Bonus pattern: Bad

>>> from sys import *

Page 53: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Better

>>> import sys as s

Page 54: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Non-pattern: Testing

Page 55: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Side note

Code reviews are usually more effective than testing

Page 56: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Figure out how to test

● None● Manually● Automated

– unittest style– doctest– input/output checking

Page 57: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Testing is easier with well structured code

Page 58: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Globals make testing hard

Page 59: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

No testing makes refactoring hard

Page 60: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

No testing/refactoring ->

● crappy code● harder to add features

Page 61: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

crappy code -> unhappy co-workers

Page 62: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

poachplate

Page 63: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

poachplate

● Compromise Layout● Executable main● Theft Packaging

Page 64: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

handout

● Verbose file organization● support for Unix configuration hierarchy● tempfile● Script chaining● pid file● logging

Page 65: Python: 7 Patterns for scripting - SCALE 16x | 16x · Python: 7 Patterns for scripting Matt Harrison matthewharrison@gmail.com SCALE 2009 (C)2008, licensed under a CC (BY-SA) license

Thanks:

● docutils● OOo● inkscape● pygmentsHandout at http://panela.blog-city.com/