PyCon 2013 : Scripting to PyPi to GitHub and More

191
Script to PyPi to Github Script to PyPi to Github @__mharrison__ @__mharrison__ http://hairysun.com http://hairysun.com

description

 

Transcript of PyCon 2013 : Scripting to PyPi to GitHub and More

Page 1: PyCon 2013 : Scripting to PyPi to GitHub and More

Script to PyPi to GithubScript to PyPi to Github

@__mharrison__@__mharrison__http://hairysun.comhttp://hairysun.com

Page 2: PyCon 2013 : Scripting to PyPi to GitHub and More

About MeAbout Me

● 12 years Python12 years Python● Worked in HA, Search, Open Source, BI Worked in HA, Search, Open Source, BI

and Storageand Storage● Author of multiple Python BooksAuthor of multiple Python Books

Page 3: PyCon 2013 : Scripting to PyPi to GitHub and More

ContinuumsContinuums

More like perl-TMTOWTDIMore like perl-TMTOWTDI

Page 4: PyCon 2013 : Scripting to PyPi to GitHub and More

AgendaAgenda

● Project DevelopmentProject Development

– VersioningVersioning

– ConfigurationConfiguration

– LoggingLogging

– File inputFile input

– Shell invocationShell invocation

● Environment Layout * virtualenv * pipEnvironment Layout * virtualenv * pip

● Project layoutProject layout

Page 5: PyCon 2013 : Scripting to PyPi to GitHub and More

Agenda (2)Agenda (2)● DocumentationDocumentation

● Automation/MakefileAutomation/Makefile

● PackagingPackaging

– setup.pysetup.py

– PyPiPyPi

● TestingTesting

● GithubGithub

● Travis CITravis CI

● PoachplatePoachplate

Page 6: PyCon 2013 : Scripting to PyPi to GitHub and More

BeginBegin

Page 7: PyCon 2013 : Scripting to PyPi to GitHub and More

WarningWarning

● Starting from basic Python knowledgeStarting from basic Python knowledge● Hands onHands on

– (short) lecture(short) lecture– (short) code(short) code– repeat until time is gonerepeat until time is gone

Page 8: PyCon 2013 : Scripting to PyPi to GitHub and More

ProjectProject

Create pycat. Pythonic implementation of Create pycat. Pythonic implementation of catcat

Page 9: PyCon 2013 : Scripting to PyPi to GitHub and More

ScriptingScripting

Page 10: PyCon 2013 : Scripting to PyPi to GitHub and More

hello world hello world cat.pycat.py

importimport syssysforfor line line inin sys sys..stdin:stdin: printprint line, line,

Page 11: PyCon 2013 : Scripting to PyPi to GitHub and More

hello world - Python 3hello world - Python 3

importimport syssysforfor line line inin sys sys..stdin:stdin: printprint(line, end(line, end==''''))

Page 12: PyCon 2013 : Scripting to PyPi to GitHub and More

2 or 3?2 or 3?

Page 13: PyCon 2013 : Scripting to PyPi to GitHub and More

2 or 3?2 or 3?

● Better legacy/library support for 2Better legacy/library support for 2● Possible to support bothPossible to support both

Page 14: PyCon 2013 : Scripting to PyPi to GitHub and More

hello worldhello world

importimport syssysforfor line line inin sys sys..stdin:stdin: sys sys..stdoutstdout..write(line)write(line)

Page 15: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

create create cat.pycat.py

Page 16: PyCon 2013 : Scripting to PyPi to GitHub and More

Single File or Project?Single File or Project?

Page 17: PyCon 2013 : Scripting to PyPi to GitHub and More

LayoutLayoutCan depend on distribution mechanism:Can depend on distribution mechanism:● Single fileSingle file● Zip fileZip file

– Python entry pointPython entry point– Splat/runSplat/run

● System packageSystem package● PyPi/Distribute/pip packagePyPi/Distribute/pip package

Page 18: PyCon 2013 : Scripting to PyPi to GitHub and More

Single FileSingle File

● chmodchmod and place in and place in $PATH$PATH● add add #!/usr/bin/env python#!/usr/bin/env python

Page 19: PyCon 2013 : Scripting to PyPi to GitHub and More

Single File (2)Single File (2)

● No reuseNo reuse

Page 20: PyCon 2013 : Scripting to PyPi to GitHub and More

Zip FileZip File

● PYTHONPATH=cat.zip python -m PYTHONPATH=cat.zip python -m __main____main__

● tar -zxvf cat.zip; cd cat; tar -zxvf cat.zip; cd cat; python cat.pypython cat.py

Page 21: PyCon 2013 : Scripting to PyPi to GitHub and More

Zip File (2)Zip File (2)

● No reuseNo reuse● No stacktraceNo stacktrace

Page 22: PyCon 2013 : Scripting to PyPi to GitHub and More

System PackageSystem Package

● emerge -av qtileemerge -av qtile (rpm|apt|brew) (rpm|apt|brew)

Page 23: PyCon 2013 : Scripting to PyPi to GitHub and More

System Package (2)System Package (2)

● Requires rootRequires root● At mercy of packager (maybe worse than At mercy of packager (maybe worse than

PyPi)PyPi)● ReuseReuse● Limited to single versionLimited to single version● python -m modulenamepython -m modulename

Page 24: PyCon 2013 : Scripting to PyPi to GitHub and More

Pip PackagePip Package

““Best practice” is combo of:Best practice” is combo of:● DistributeDistribute● VirtualenvVirtualenv● PipPip

Page 25: PyCon 2013 : Scripting to PyPi to GitHub and More

Pip Package (2)Pip Package (2)

$ virtualenv catenv$ virtualenv catenv$ source catenv/bin/activate$ source catenv/bin/activate$ pip install pycat$ pip install pycat

Page 26: PyCon 2013 : Scripting to PyPi to GitHub and More

Pip Package (3)Pip Package (3)

● Multiple versionsMultiple versions● ReuseReuse● Effort to create Effort to create setup.pysetup.py

Page 27: PyCon 2013 : Scripting to PyPi to GitHub and More

Minimal Example LayoutMinimal Example LayoutProject/Project/ README.txt README.txt project/ project/ __init__.py __init__.py other.py other.py ... ... setup.py setup.py

Page 28: PyCon 2013 : Scripting to PyPi to GitHub and More

Better Example LayoutBetter Example LayoutProject/Project/ .gitignore .gitignore doc/ doc/ Makefile Makefile index.rst index.rst README.txt README.txt Makefile Makefile bin/ bin/ runfoo.py runfoo.py project/ project/ __init__.py __init__.py other.py other.py ... ... setup.py setup.py

Page 29: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

create layout for create layout for cat.pycat.py

Page 30: PyCon 2013 : Scripting to PyPi to GitHub and More

Semantic VersioningSemantic Versioning

Page 31: PyCon 2013 : Scripting to PyPi to GitHub and More

VersioningVersioning

http://semver.orghttp://semver.org

Formal spec for versioning projectsFormal spec for versioning projects

Page 32: PyCon 2013 : Scripting to PyPi to GitHub and More

Python VersioningPython Versioning

PEP 386PEP 386

N.N[.n]+[{a|b|c}N[.N]+][.postN][.devN]N.N[.n]+[{a|b|c}N[.N]+][.postN][.devN]

1.0a1 < 1.0a2 < 1.0b2.post3451.0a1 < 1.0a2 < 1.0b2.post345

Page 33: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py

fromfrom distutils.coredistutils.core importimport setup setup

setup(namesetup(name=='PyCat''PyCat',,........ version version=='1.0''1.0'))

Page 34: PyCon 2013 : Scripting to PyPi to GitHub and More

Where to store version?Where to store version?

In In module.__version__module.__version__ (might cause (might cause importing issues)importing issues)

Page 35: PyCon 2013 : Scripting to PyPi to GitHub and More

VersionVersion

If using Sphinx for docs, be sure to update:If using Sphinx for docs, be sure to update:

docs/docs/ conf.py conf.py

Page 36: PyCon 2013 : Scripting to PyPi to GitHub and More

argparseargparse

ap ap == argparse argparse..ArgumentParser(versionArgumentParser(version=='1.0''1.0'))......apap..print_version()print_version()

Page 37: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

Add version to projectAdd version to project

Page 38: PyCon 2013 : Scripting to PyPi to GitHub and More

ConfigurationConfiguration

Page 39: PyCon 2013 : Scripting to PyPi to GitHub and More

ConfigurationConfiguration● PythonPython

– Django (Django (settings.pysettings.py))

– Python (Python (site.pysite.py, , setup.pysetup.py))

● JSON/YAMLJSON/YAML

– Google App EngineGoogle App Engine

● Environment VariablesEnvironment Variables

– Python (Python (PYTHONPATHPYTHONPATH))

● .ini (.ini (ConfigParserConfigParser, , ConfigObjConfigObj))

– matplotlibmatplotlib

– ipythonipython

● Command line options (Command line options (argparseargparse))

● Sqlite blobSqlite blob

● Shelve/pickle blobShelve/pickle blob

Page 40: PyCon 2013 : Scripting to PyPi to GitHub and More

Configuration (2)Configuration (2)

Are not mutually exclusiveAre not mutually exclusive

Page 41: PyCon 2013 : Scripting to PyPi to GitHub and More

Configuration (3)Configuration (3)(Unix) Hierarchy:(Unix) Hierarchy:

● System rc (run control) (System rc (run control) (/etc/conf.d/etc/conf.d))

● User rc (User rc (~/.config/app/...~/.config/app/...))

● Environment variablesEnvironment variables

● Command line optionsCommand line options

http://www.faqs.org/docs/artu/ch10s02.htmlhttp://www.faqs.org/docs/artu/ch10s02.html

Filesystem Hierarchy Standard: Filesystem Hierarchy Standard: http://www.pathname.com/fhs/http://www.pathname.com/fhs/

Page 42: PyCon 2013 : Scripting to PyPi to GitHub and More

Configuration (4)Configuration (4)

● Plain text config is easily approachablePlain text config is easily approachable● Careful with Python config on process Careful with Python config on process

run by rootrun by root

Page 43: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

Add configuration Add configuration -n-n to to show line numbersshow line numbers

Page 44: PyCon 2013 : Scripting to PyPi to GitHub and More

LoggingLogging

Page 45: PyCon 2013 : Scripting to PyPi to GitHub and More

LoggingLogging

logginglogging module provides feature-rich module provides feature-rich logginglogging

Page 46: PyCon 2013 : Scripting to PyPi to GitHub and More

Logging (2)Logging (2)

importimport logginglogging

logginglogging..basicConfig(levelbasicConfig(level==logginglogging..ERROR,ERROR, filename filename=='.log''.log'))......logginglogging..error(error('Error encountered in...''Error encountered in...'))

Page 47: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

Add configuration Add configuration --verbose--verbose to log file to log file

being “catted”being “catted”

Page 48: PyCon 2013 : Scripting to PyPi to GitHub and More

Dealing with File InputDealing with File Input

Page 49: PyCon 2013 : Scripting to PyPi to GitHub and More

““Files”Files”

Dealing with?Dealing with?● FilenameFilename● file objectfile object● string datastring data

Page 50: PyCon 2013 : Scripting to PyPi to GitHub and More

FilenameFilename

Somewhat analogous to an Somewhat analogous to an IterableIterable..● Can open/iterate many timesCan open/iterate many times● Implementation depends on fileImplementation depends on file● Need to manage closing fileNeed to manage closing file

Page 51: PyCon 2013 : Scripting to PyPi to GitHub and More

File ObjectFile Object

Somewhat analogous to an Somewhat analogous to an IteratorIterator..● Can iterate once (unless Can iterate once (unless seekseeked)ed)

● Can accept Can accept filefile, , StringIOStringIO, , socketsocket, , generator, etcgenerator, etc

● Memory friendly - scalableMemory friendly - scalable

Page 52: PyCon 2013 : Scripting to PyPi to GitHub and More

String DataString Data

No iterator analogy.No iterator analogy.● Memory hog - less scalableMemory hog - less scalable

Page 53: PyCon 2013 : Scripting to PyPi to GitHub and More

Stdlib ExamplesStdlib ExamplesModule String Data File Filename

json loads load

pickle loads load

xml.etree.ElementTree

fromstring parse parse

xml.dom.minidom parseString parse parse

ConfigParser cp.readfp cp.read(filenames)

csv reader DictReader

pyyaml 3rd party load, safe_load load, safe_load

Page 54: PyCon 2013 : Scripting to PyPi to GitHub and More

Stdlib Take-awaysStdlib Take-aways

● mostly functionsmostly functions● file interface is required, others optionalfile interface is required, others optional● parseparse or or loadload

Page 55: PyCon 2013 : Scripting to PyPi to GitHub and More

ExampleExample>>>>>> importimport syssys

>>>>>> defdef parseparse(fin):(fin):...... forfor line line inin upper(fin): upper(fin):...... sys sys..stdoutstdout..write(line)write(line)

>>>>>> defdef upperupper(iterable):(iterable):...... forfor item item inin iterable: iterable:...... yieldyield strstr(item)(item)..upper()upper()

Page 56: PyCon 2013 : Scripting to PyPi to GitHub and More

Create file to parseCreate file to parse

>>> >>> withwith openopen(('/tmp/data''/tmp/data', , 'w''w') ) asas fout: fout:... ... fout fout..write(write('line1'line1\n\n''))... ... fout fout..write(write('line2'line2\n\n''))

Page 57: PyCon 2013 : Scripting to PyPi to GitHub and More

Filename to Filename to filefile

>>> >>> filename filename == '/tmp/data''/tmp/data'>>> >>> withwith openopen(filename) (filename) asas fin: fin:... ... parse(fin) parse(fin)LINE1LINE1LINE2LINE2

Page 58: PyCon 2013 : Scripting to PyPi to GitHub and More

String data to String data to filefile>>> >>> data data == "string"string\n\ndatadata\n\n"">>> >>> importimport StringIOStringIO>>> >>> parse(StringIOparse(StringIO..StringIO(data))StringIO(data))STRINGSTRINGDATADATA

Page 59: PyCon 2013 : Scripting to PyPi to GitHub and More

Parse IterableParse Iterable

>>> >>> data data == [ ['foo'foo\n\n'', , 'bar'bar\n\n'']]>>> >>> parse(data)parse(data)FOOFOOBARBAR

Page 60: PyCon 2013 : Scripting to PyPi to GitHub and More

More More filefile benefits benefits

● Combine with generators to filter, tweakCombine with generators to filter, tweak● Easier to testEasier to test

Page 61: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

Add a Add a parseparse function function

Page 62: PyCon 2013 : Scripting to PyPi to GitHub and More

Invoking Shell Invoking Shell CommandsCommands

Page 63: PyCon 2013 : Scripting to PyPi to GitHub and More

Reading outputReading output

>>> >>> importimport subprocesssubprocess>>> >>> p p == subprocess subprocess..Popen(Popen('id -u''id -u', shell, shell==TrueTrue, , stdoutstdout==subprocesssubprocess..PIPE, stderrPIPE, stderr==subprocesssubprocess..PIPE)PIPE)>>> >>> pp..stdoutstdout..read()read()'1000\n''1000\n'>>> >>> pp..returncode returncode # None means not done# None means not done>>> >>> printprint p p..wait()wait()00

Page 64: PyCon 2013 : Scripting to PyPi to GitHub and More

Feeding Feeding stdinstdinCan use Can use communicatecommunicate or or p2.stdin.writep2.stdin.write w/ w/ flush/closeflush/close..>>> >>> p2 p2 == subprocess subprocess..Popen(Popen('wc -l''wc -l', shell, shell==TrueTrue, , stdoutstdout==subprocesssubprocess..PIPE, stdinPIPE, stdin==subprocesssubprocess..PIPE, PIPE, stderrstderr==subprocesssubprocess..PIPE)PIPE)>>> >>> out, err out, err == p2 p2..communicate(communicate('foo'foo\n\nbarbar\n\n'') ) #p.stdin.flush()#p.stdin.flush()

>>> >>> outout'2\n''2\n'>>> >>> p2p2..returncodereturncode00

Page 65: PyCon 2013 : Scripting to PyPi to GitHub and More

Chaining scriptsChaining scriptsChaining is pretty straightforward make sure to Chaining is pretty straightforward make sure to closeclose stdinstdin. . http://stackoverflow.com/questions/1595492/blocks-send-input-to-python-subprhttp://stackoverflow.com/questions/1595492/blocks-send-input-to-python-subprocess-pipelineocess-pipeline

>>> >>> p3 p3 == subprocess subprocess..Popen(Popen('sort''sort', shell, shell==TrueTrue,,... ... stdout stdout==subprocesssubprocess..PIPE,PIPE,... ... stdin stdin==subprocesssubprocess..PIPE)PIPE)>>> >>> p4 p4 == subprocess subprocess..Popen(Popen('uniq''uniq', shell, shell==TrueTrue,,... ... stdout stdout==subprocesssubprocess..PIPE,PIPE,... ... stdin stdin==p3p3..stdout,stdout,... ... close_fds close_fds==TrueTrue) ) # hangs w/o close_fds# hangs w/o close_fds

>>> >>> p3p3..stdinstdin..write(write('1'1\n\n22\n\n11\n\n''))>>> >>> p3p3..stdinstdin..flush(); p3flush(); p3..stdinstdin..close();close();>>> >>> p4p4..stdoutstdout..read()read()'1\n2\n''1\n2\n'

Page 66: PyCon 2013 : Scripting to PyPi to GitHub and More

Chaining scripts and pythonChaining scripts and python

catcat 0-2, add 10 to them (in python) and 0-2, add 10 to them (in python) and wc wc -l-l results. results.>>> >>> importimport osos>>> >>> p5 p5 == subprocess subprocess..Popen(Popen('cat''cat', shell, shell==TrueTrue, , stdoutstdout==subprocesssubprocess..PIPE, stdinPIPE, stdin==subprocesssubprocess..PIPE, close_fdsPIPE, close_fds==TrueTrue))>>> >>> defdef p6p6((inputinput):):... ... ''' add 10 to line in input '''''' add 10 to line in input '''... ... forfor line line inin inputinput::... ... yieldyield ''%d%s%d%s'' %%((intint(line(line..strip())strip())+10+10, os, os..linesep)linesep)

Page 67: PyCon 2013 : Scripting to PyPi to GitHub and More

Chaining scripts and python Chaining scripts and python (2)(2)

>>> >>> p7 p7 == subprocess subprocess..Popen(Popen('wc -l''wc -l', shell, shell==TrueTrue, , stdoutstdout==subprocesssubprocess..PIPE, stdinPIPE, stdin==subprocesssubprocess..PIPE, close_fdsPIPE, close_fds==TrueTrue))>>> >>> [p5[p5..stdinstdin..write(write(strstr(x)(x)++osos..linesep) linesep) forfor x x inin xrangexrange((33)])]>>> >>> p5p5..stdinstdin..close()close()>>> >>> [p7[p7..stdinstdin..write(x) write(x) forfor x x inin p6(p5 p6(p5..stdoutstdout..xreadlines())]xreadlines())]>>> >>> p7p7..stdinstdin..close()close()>>> >>> p7p7..stdoutstdout..read()read()'3\n''3\n'

Page 68: PyCon 2013 : Scripting to PyPi to GitHub and More

EnvironmentEnvironment

Page 69: PyCon 2013 : Scripting to PyPi to GitHub and More

Python EnvironmentPython Environment

● System Python or “Virtual” PythonSystem Python or “Virtual” Python● Installation methodInstallation method

Page 70: PyCon 2013 : Scripting to PyPi to GitHub and More

Which PythonWhich Python

System PythonSystem Python● Requires rootRequires root● Only one version of libraryOnly one version of library● System packages may be out of dateSystem packages may be out of date

Page 71: PyCon 2013 : Scripting to PyPi to GitHub and More

Which Python (2)Which Python (2)

““Virtual” PythonVirtual” Python● Runs as userRuns as user● Specify versionSpecify version● Sandboxed from systemSandboxed from system● Create multiple sandboxesCreate multiple sandboxes

Page 72: PyCon 2013 : Scripting to PyPi to GitHub and More

Which Python (3)Which Python (3)

Install Install virtualenvvirtualenv

Page 73: PyCon 2013 : Scripting to PyPi to GitHub and More

virtualenvvirtualenvInstallation:Installation:

● System package System package $ sudo apt-get install $ sudo apt-get install python-virtualenvpython-virtualenv

● With pip With pip $ pip install virtualenv$ pip install virtualenv● $ easy_install virtualenv$ easy_install virtualenv● $ wget $ wget https://raw.github.com/pypa/virtualenv/master/https://raw.github.com/pypa/virtualenv/master/virtualenv.py; python virtualenv.pyvirtualenv.py; python virtualenv.py

Page 74: PyCon 2013 : Scripting to PyPi to GitHub and More

virtualenvvirtualenv (2) (2)

Create virtual environment:Create virtual environment:

$ virtualenv env_name$ virtualenv env_name

Page 75: PyCon 2013 : Scripting to PyPi to GitHub and More

Directory StructureDirectory Structure

env_name/env_name/ bin/ bin/ activate activate python python pip pip lib/ lib/ python2.7/ python2.7/ site-packages/ site-packages/

Page 76: PyCon 2013 : Scripting to PyPi to GitHub and More

virtualenvvirtualenv (3) (3)

Activate virtual environment:Activate virtual environment:

$ source env_name/bin/activate$ source env_name/bin/activate

Page 77: PyCon 2013 : Scripting to PyPi to GitHub and More

virtualenvvirtualenv (4) (4)

Windows activate virtual environment:Windows activate virtual environment:

> \path\to\env\Scripts\activate> \path\to\env\Scripts\activate

May require May require PS C:\> PS C:\> Set-ExecutionPolicy AllSignedSet-ExecutionPolicy AllSigned

Page 78: PyCon 2013 : Scripting to PyPi to GitHub and More

virtualenvvirtualenv (5) (5)

Comes with Comes with pippip to install packages: to install packages:

$ pip install sqlalchemy$ pip install sqlalchemy

Page 79: PyCon 2013 : Scripting to PyPi to GitHub and More

virtualenvvirtualenv (6) (6)

$ which python # not /usr/bin/python$ which python # not /usr/bin/python/home/matt/work/courses/script-pypi-github/env/b/home/matt/work/courses/script-pypi-github/env/bin/pythonin/python

Page 80: PyCon 2013 : Scripting to PyPi to GitHub and More

virtualenvvirtualenv (7) (7)

>>> sys.path>>> sys.path['', ..., ['', ..., '/home/matt/work/courses/script-py'/home/matt/work/courses/script-pypi-github/env/lib/python2.7/site-ppi-github/env/lib/python2.7/site-packages']ackages']

Page 81: PyCon 2013 : Scripting to PyPi to GitHub and More

virtualenvvirtualenv (8) (8)

Use Use deactivatedeactivate shell function to reset shell function to reset PATHPATH::

$ deactivate$ deactivate

Page 82: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

create virtualenv create virtualenv envenv

Page 83: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip

Page 84: PyCon 2013 : Scripting to PyPi to GitHub and More

pippipRecursive Acronym - Recursive Acronym - PPip ip IInstalls nstalls PPackagesackages● installinstall● upgradeupgrade● uninstalluninstall● ““pin” versionspin” versions● requirements.txtrequirements.txt

Page 85: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (2) (2)

Install:Install:

$ pip install sqlalchemy$ pip install sqlalchemy

Page 86: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (3) (3)

Upgrade:Upgrade:

$ pip install --upgrade sqlalchemy$ pip install --upgrade sqlalchemy

Page 87: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (4) (4)

Uninstall:Uninstall:

$ pip uninstall sqlalchemy$ pip uninstall sqlalchemy

Page 88: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (5) (5)

““Pin” version:Pin” version:

$ pip install sqlalchemy==0.7$ pip install sqlalchemy==0.7

Page 89: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (6) (6)

Requirements file:Requirements file:

$ pip install -r requirements.txt$ pip install -r requirements.txt

Page 90: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (7) (7)

Requirements file Requirements file $ cat requirements.txt$ cat requirements.txt::

sqlalchemy==0.7sqlalchemy==0.7foobarfoobarbazlib>=1.0bazlib>=1.0

Page 91: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (8) (8)

Create requirement file from env:Create requirement file from env:

$ pip freeze > req.txt$ pip freeze > req.txt

Page 92: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (9) (9)

● pip docs say to install from virtualenvpip docs say to install from virtualenv● virtualenv docs say to install from pipvirtualenv docs say to install from pip

Page 93: PyCon 2013 : Scripting to PyPi to GitHub and More

pippip (10) (10)Install from directory:Install from directory:

pip install --download packages -r pip install --download packages -r requirements.txtrequirements.txtpip install --no-index pip install --no-index --find-links=file://full/path/to/p--find-links=file://full/path/to/packages -r requirements.txtackages -r requirements.txt

Page 94: PyCon 2013 : Scripting to PyPi to GitHub and More

distributedistribute, , setuptoolssetuptools, , distutilsdistutils

● pippip wraps wraps distributedistribute adds uninstall, adds uninstall, req.txtreq.txt

● distributedistribute fork of fork of setuptoolssetuptools● setuptoolssetuptools unmaintained, adds eggs, unmaintained, adds eggs,

dependencies, dependencies, easy_installeasy_install● distutilsdistutils stdlib packaging library stdlib packaging library

Page 95: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

use pip to install use pip to install package from internetpackage from internet

Page 96: PyCon 2013 : Scripting to PyPi to GitHub and More

More LayoutMore Layout

Page 97: PyCon 2013 : Scripting to PyPi to GitHub and More

Better Example LayoutBetter Example LayoutProject/Project/ .gitignore .gitignore doc/ doc/ Makefile Makefile index.rst index.rst README.txt README.txt Makefile Makefile bin/ bin/ runfoo.py runfoo.py project/ project/ __init__.py __init__.py other.py other.py ... ... setup.py setup.py

Page 98: PyCon 2013 : Scripting to PyPi to GitHub and More

.gitignore.gitignore*.py[cod]*.py[cod]

# C extensions# C extensions*.so*.so

# Packages# Packages*.egg*.egg*.egg-info*.egg-infodistdistbuildbuildeggseggspartspartsbinbinvarvarsdistsdist

Page 99: PyCon 2013 : Scripting to PyPi to GitHub and More

.gitignore.gitignoredevelop-eggsdevelop-eggs.installed.cfg.installed.cfglibliblib64lib64__pycache____pycache__

# Installer logs# Installer logspip-log.txtpip-log.txt

# Unit test / coverage reports# Unit test / coverage reports.coverage.coverage.tox.toxnosetests.xmlnosetests.xml

# Translations# Translations*.mo*.mo

https://github.com/github/gitignorehttps://github.com/github/gitignore

Page 100: PyCon 2013 : Scripting to PyPi to GitHub and More

.gitignore.gitignore (2) (2)

See See blaze-coreblaze-core for example of C and for example of C and Docs. Docs. https://github.com/ContinuumIO/blaze-corhttps://github.com/ContinuumIO/blaze-coree

Page 101: PyCon 2013 : Scripting to PyPi to GitHub and More

.gitignore.gitignore (3) (3)From From requestsrequests::

.coverage.coverageMANIFESTMANIFESTcoverage.xmlcoverage.xmlnosetests.xmlnosetests.xmljunit-report.xmljunit-report.xmlpylint.txtpylint.txttoy.pytoy.pyviolations.pyflakes.txtviolations.pyflakes.txtcover/cover/docs/_builddocs/_buildrequests.egg-info/requests.egg-info/*.pyc*.pyc*.swp*.swpenv/env/.workon.workont.pyt.pyt2.pyt2.py

https://github.com/kennethreitz/requestshttps://github.com/kennethreitz/requests

Page 102: PyCon 2013 : Scripting to PyPi to GitHub and More

Other tipsOther tips● localsettings.pylocalsettings.py (for django) (for django)

● *~*~ (emacs) (emacs)

● Run Run git statusgit status and add outliers to and add outliers to .gitignore.gitignore

● Make settings global:Make settings global:git config --global core.excludesfile git config --global core.excludesfile Python.gitignorePython.gitignoregit config --global core.excludesfile git config --global core.excludesfile Python.gitignorePython.gitignore

Page 103: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

add (premptive) add (premptive) .gitignore.gitignore

Page 104: PyCon 2013 : Scripting to PyPi to GitHub and More

DocumentationDocumentation

Page 105: PyCon 2013 : Scripting to PyPi to GitHub and More

DocumentationDocumentation

Two types:Two types:● Developer docs (README, INSTALL, Developer docs (README, INSTALL,

HACKING, etc)HACKING, etc)● End userEnd user

Page 106: PyCon 2013 : Scripting to PyPi to GitHub and More

DeveloperDeveloper

READMEREADME - main entry point for project - main entry point for project● Brief introBrief intro● Links/ContactLinks/Contact● LicenseLicense

Page 107: PyCon 2013 : Scripting to PyPi to GitHub and More

READMEREADME

For github integration name it For github integration name it README.rstREADME.rst or or README.mdREADME.md

Page 108: PyCon 2013 : Scripting to PyPi to GitHub and More

LICENSELICENSE

Include text of license. Templates at Include text of license. Templates at http://opensource.org/licenses/index.htmlhttp://opensource.org/licenses/index.html

Page 109: PyCon 2013 : Scripting to PyPi to GitHub and More

LicensingLicensing

Some include dunder meta in project docstring (Some include dunder meta in project docstring (requestsrequests __init__.py__init__.py):):

:copyright: (c) 2013 by Kenneth Reitz.:copyright: (c) 2013 by Kenneth Reitz.:license: Apache 2.0, see LICENSE for more :license: Apache 2.0, see LICENSE for more details.details.

(note IANAL)(note IANAL)

Page 110: PyCon 2013 : Scripting to PyPi to GitHub and More

Licensing (2)Licensing (2)Some include dunder meta in project (Some include dunder meta in project (requestsrequests __init__.py__init__.py):):

__title__ = 'requests'__title__ = 'requests'__version__ = '1.1.0'__version__ = '1.1.0'__build__ = 0x010100__build__ = 0x010100__author__ = 'Kenneth Reitz'__author__ = 'Kenneth Reitz'__license__ = 'Apache 2.0'__license__ = 'Apache 2.0'__copyright__ = 'Copyright 2013 Kenneth Reitz'__copyright__ = 'Copyright 2013 Kenneth Reitz'

(note IANAL)(note IANAL)

Page 111: PyCon 2013 : Scripting to PyPi to GitHub and More

Other filesOther files

● AUTHORSAUTHORS● HISTORY/CHANGELOGHISTORY/CHANGELOG● TODOTODO

Page 112: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

create simple create simple READMEREADME

Page 113: PyCon 2013 : Scripting to PyPi to GitHub and More

End User DocsEnd User Docs

Sphinx is a tool that makes it easy to create Sphinx is a tool that makes it easy to create intelligent and beautiful documentation, intelligent and beautiful documentation, written by Georg Brandl and licensed written by Georg Brandl and licensed under the BSD license.under the BSD license.

http://sphinx-doc.orghttp://sphinx-doc.org

Page 114: PyCon 2013 : Scripting to PyPi to GitHub and More

Suggested setupSuggested setup

Project/Project/ doc/ doc/ # sphinx stuff # sphinx stuff Makefile Makefile

Page 115: PyCon 2013 : Scripting to PyPi to GitHub and More

Sphinx in 4 LinesSphinx in 4 Lines

$ cd docs$ cd docs$ sphinx-quickstart$ sphinx-quickstart$ $EDITOR index.rst$ $EDITOR index.rst$ make html$ make html

Page 116: PyCon 2013 : Scripting to PyPi to GitHub and More

AssignmentAssignment

write docs at a later write docs at a later time :)time :)

Page 117: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile

Page 118: PyCon 2013 : Scripting to PyPi to GitHub and More

MotivationMotivationRunning commands often:Running commands often:

● nosetestsnosetests (plus options) (plus options)

● create sdistcreate sdist

● upload to PyPiupload to PyPi

● create virtualenvcreate virtualenv

● install dependenciesinstall dependencies

● cleanup cruftcleanup cruft

● create TAGScreate TAGS

● profileprofile

● sdistsdist

● PyPi - register and uploadPyPi - register and upload

● creating pngs from svgscreating pngs from svgs

● docsdocs

● Python 3 testingPython 3 testing

● etc...etc...

Page 119: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile

● Knows about executing (build) Knows about executing (build) commandscommands

● Knows about dependenciesKnows about dependencies

Page 120: PyCon 2013 : Scripting to PyPi to GitHub and More

ExampleExample

To test:To test:● Make virtualenvMake virtualenv● install code dependenciesinstall code dependencies● install nose (+coverage)install nose (+coverage)● run testsrun tests

Page 121: PyCon 2013 : Scripting to PyPi to GitHub and More

Clean checkoutClean checkout$ make test$ make testvsvs

$ virtualenv env$ virtualenv env$ env/bin/activate$ env/bin/activate$ pip install -r deps.txt$ pip install -r deps.txt$ pip install nose coverage.py$ pip install nose coverage.py$ nosestests$ nosestests

Page 122: PyCon 2013 : Scripting to PyPi to GitHub and More

Enough Enough makemake knowledge to be knowledge to be

dangerousdangerous

Page 123: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (1) (1)

Syntax of Syntax of MakefileMakefile::

file: dependentfilefile: dependentfile<TAB>Command1<TAB>Command1......<TAB>CommandN<TAB>CommandN

Page 124: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (2) (2)

Running (runs Running (runs MakefileMakefile by default): by default):

$ make file$ make file# will build dependentfile if # will build dependentfile if necessarynecessary# then build file# then build file

Page 125: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (3) (3)

Example:Example:

foo: foo.c foo.hfoo: foo.c foo.h<TAB>cc -c foo.c<TAB>cc -c foo.c<TAB>cc -o foo foo.o<TAB>cc -o foo foo.o

Page 126: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (4) (4)

Running (echoes commands by default Running (echoes commands by default -s-s for silent):for silent):

$ make$ makecc -c foo.ccc -c foo.ccc -o foo foo.occ -o foo foo.o

Page 127: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (5) (5)

Subsequent runs do nothing:Subsequent runs do nothing:

$ make$ makemake: `foo' is up to date.make: `foo' is up to date.

Page 128: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (6) (6)

Add a Add a cleanclean command: command:

.PHONY: clean.PHONY: clean

clean:clean:<TAB>rm foo.o foo<TAB>rm foo.o foo

Page 129: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (7) (7)

Since Since cleanclean isn't a file, need to use isn't a file, need to use .PHONY.PHONY to indicate that to to indicate that to makemake. (If you had a file . (If you had a file named named cleanclean it wouldn't try to build it). it wouldn't try to build it).

Page 130: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (8) (8)

(Simply Expanded) Variables (expanded when set):(Simply Expanded) Variables (expanded when set):

BIN := env/binBIN := env/binPY := $(BIN)/pythonPY := $(BIN)/pythonNOSE := $(BIN)/nosetestsNOSE := $(BIN)/nosetests

.PHONY: build.PHONY: buildbuild: envbuild: env<TAB>$(PY) setup.py sdist<TAB>$(PY) setup.py sdist

Page 131: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (9) (9)

(Recursively Expanded) Variables (expanded when used):(Recursively Expanded) Variables (expanded when used):

FILE = fooFILE = fooDATA = $(FILE)DATA = $(FILE)

# If DATA expanded would be foo# If DATA expanded would be foo

FILE = barFILE = bar# If DATA expanded would be bar# If DATA expanded would be bar

Page 132: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (10) (10)

Shell functions:Shell functions:

.PHONY: pwd.PHONY: pwdpwd:pwd:<TAB>pushd /etc<TAB>pushd /etc

Page 133: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (11) (11)Invoking:Invoking:

$ make pwd$ make pwdpushd /etcpushd /etcmake: pushd: Command not foundmake: pushd: Command not foundmake: *** [pwd] Error 127make: *** [pwd] Error 127

((pushdpushd is a bash function) is a bash function)

Page 134: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (12) (12)Shell functions:Shell functions:

SHELL := /bin/bashSHELL := /bin/bash

.PHONY: pwd.PHONY: pwdpwd:pwd:<TAB>pushd /etc<TAB>pushd /etc

Page 135: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (13) (13)

Multiple commands:Multiple commands:

SHELL := /bin/bashSHELL := /bin/bash

.PHONY: pwd.PHONY: pwdpwd:pwd:<TAB>pushd /etc<TAB>pushd /etc<TAB>pwd<TAB>pwd<TAB>popd<TAB>popd

Page 136: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (14) (14)

Multiple commands:Multiple commands:

$ make pwd$ make pwdpushd /etcpushd /etc/etc /tmp/foo/etc /tmp/foopwdpwd/tmp/foo/tmp/foopopdpopd/bin/bash: line 0: popd: directory stack empty/bin/bash: line 0: popd: directory stack empty

Page 137: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (15) (15)

Each tab indented command runs in its Each tab indented command runs in its own process. Use own process. Use ;; and put in one line or and put in one line or use use \\ for line continuation for line continuation

Page 138: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (16) (16)

Multiple commands (use line continuation Multiple commands (use line continuation \\):):

SHELL := /bin/bashSHELL := /bin/bash

.PHONY: pwd2.PHONY: pwd2pwd2:pwd2:<TAB>pushd /etc; \<TAB>pushd /etc; \<TAB>pwd; \<TAB>pwd; \<TAB>popd<TAB>popd

Page 139: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (17) (17)

Shell variables:Shell variables:

.PHONY: path.PHONY: pathpath:path:<TAB>echo $PATH<TAB>echo $PATH

Page 140: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (18) (18)

Make thinks they are make variables:Make thinks they are make variables:

$ make path$ make pathecho ATHecho ATHATHATH

Page 141: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (19) (19)

$$ needs to be escaped with needs to be escaped with $$::

.PHONY: path.PHONY: pathpath:path:<TAB>echo $$PATH<TAB>echo $$PATH

Page 142: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile (18) (18)

Now it works:Now it works:

$ make path$ make pathecho $PATHecho $PATH/tmp/maketest/tmp/maketest

Page 143: PyCon 2013 : Scripting to PyPi to GitHub and More

Makefiles for Python Makefiles for Python ProjectsProjects

Page 144: PyCon 2013 : Scripting to PyPi to GitHub and More

Inspired by Rick Harding's Inspired by Rick Harding's TalkTalk

http://pyvideo.org/video/1354/starting-youhttp://pyvideo.org/video/1354/starting-your-project-right-setup-and-automationr-project-right-setup-and-automationhttps://github.com/mitechie/pyohio_2012https://github.com/mitechie/pyohio_2012

Page 145: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile for Python for Python

Make virtualenv:Make virtualenv:

env:env:<TAB>virtualenv env<TAB>virtualenv env

Page 146: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile for Python (2) for Python (2)

Make dependencies:Make dependencies:

.PHONY: deps.PHONY: depsdeps: envdeps: env<TAB>$(PIP) install -r <TAB>$(PIP) install -r requirements.txtrequirements.txt

Page 147: PyCon 2013 : Scripting to PyPi to GitHub and More

MakefileMakefile for Python (3) for Python (3)

Testing with Testing with nosenose::

.PHONY: test.PHONY: testtest: nose depstest: nose deps<TAB>$(NOSE)<TAB>$(NOSE)

# nose depends on the nosetests binary# nose depends on the nosetests binarynose: $(NOSE)nose: $(NOSE)$(NOSE): env$(NOSE): env<TAB>$(PIP) install nose<TAB>$(PIP) install nose

Page 148: PyCon 2013 : Scripting to PyPi to GitHub and More

Contrary OpinionsContrary Opinions

““Dynamic languages don't need anything Dynamic languages don't need anything like like makemake, unless they have some , unless they have some compile-time interface dependencies compile-time interface dependencies between modules”between modules”

http://stackoverflow.com/questions/758093http://stackoverflow.com/questions/7580939/why-are-there-no-makefiles-for-automati9/why-are-there-no-makefiles-for-automation-in-python-projectson-in-python-projects

Page 149: PyCon 2013 : Scripting to PyPi to GitHub and More

Other optionsOther options

● paverpaver● fabricfabric● buildoutbuildout

Page 150: PyCon 2013 : Scripting to PyPi to GitHub and More

PackagingPackaging

Page 151: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py overloaded overloaded

● create sdist (source distribution)create sdist (source distribution)● upload to pypiupload to pypi● install packageinstall package

Page 152: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py wart wart

requirerequire keyword of keyword of distutilsdistutils doesn't doesn't download reqs only download reqs only documentsdocuments them. Use them. Use requirements.txtrequirements.txt in combo with in combo with pippip..

Page 153: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py example exampleFrom From requestsrequests::

setup(setup( name='requests', name='requests', version=requests.__version__, version=requests.__version__, description='Python HTTP for Humans.', description='Python HTTP for Humans.', long_description=open('README.rst').read() + long_description=open('README.rst').read() + '\n\n' +'\n\n' + open('HISTORY.rst').read(), open('HISTORY.rst').read(), author='Kenneth Reitz', author='Kenneth Reitz', author_email='[email protected]', author_email='[email protected]', url='http://python-requests.org', url='http://python-requests.org',

Page 154: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py example (2) example (2)

packages=packages,packages=packages,package_data={'': ['LICENSE', 'NOTICE'], package_data={'': ['LICENSE', 'NOTICE'], 'requests': ['*.pem']},'requests': ['*.pem']},package_dir={'requests': 'requests'},package_dir={'requests': 'requests'},include_package_data=True,include_package_data=True,install_requires=requires,install_requires=requires,license=open('LICENSE').read(),license=open('LICENSE').read(),zip_safe=False,zip_safe=False,

Page 155: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py example (3) example (3) classifiers=(classifiers=( 'Development Status :: 5 - Production/Stable', 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: Developers', 'Natural Language :: English', 'Natural Language :: English', 'License :: OSI Approved :: Apache Software License', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', 'Programming Language :: Python', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3', # 'Programming Language :: Python :: 3.0', # 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.3', ), ),))

Page 156: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py modules modules

If project consists of a few modules this If project consists of a few modules this may be easiestmay be easiest

Page 157: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py packages packages

Need to explicitly list Need to explicitly list allall packages, not just packages, not just rootroot

Page 158: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py scripts scripts

Add executable Python files hereAdd executable Python files here

Page 159: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py non-Python files non-Python files

● add files to add files to MANIFEST.inMANIFEST.in (include in (include in package)package)

● add files to add files to package_datapackage_data in in setup.pysetup.py (include in install) Not recursive(include in install) Not recursive

Page 160: PyCon 2013 : Scripting to PyPi to GitHub and More

MANIFEST.inMANIFEST.in language language

● include|exclude pat1 pat2 ...include|exclude pat1 pat2 ...● recursive-(include|exclude) dir pat1 pat2 ...recursive-(include|exclude) dir pat1 pat2 ...● global-(include|exclude) dir pat1 pat2 ...global-(include|exclude) dir pat1 pat2 ...● prune dirprune dir● graft dirgraft dir

http://docs.python.org/release/1.6/dist/sdist-cmd.html#sdist-chttp://docs.python.org/release/1.6/dist/sdist-cmd.html#sdist-cmdmd

Page 161: PyCon 2013 : Scripting to PyPi to GitHub and More

setup.pysetup.py classifiers classifiers

Almost 600 different classifiers.Almost 600 different classifiers.

Not used by pip to enforce versions. For UI Not used by pip to enforce versions. For UI onlyonly

Page 162: PyCon 2013 : Scripting to PyPi to GitHub and More

Create sdistCreate sdist

$ python setup.py sdist$ python setup.py sdist

Page 163: PyCon 2013 : Scripting to PyPi to GitHub and More

PyPiPyPi

Validate Validate setup.pysetup.py::

$ python setup.py check$ python setup.py check

Page 164: PyCon 2013 : Scripting to PyPi to GitHub and More

PyPi RegisterPyPi Register

Click on “Register” on right hand boxClick on “Register” on right hand box

https://pypi.python.org/pypi?%3Aaction=rehttps://pypi.python.org/pypi?%3Aaction=register_formgister_form

Page 165: PyCon 2013 : Scripting to PyPi to GitHub and More

PyPi UploadPyPi Upload

$ python setup.py sdist register $ python setup.py sdist register uploadupload

Page 166: PyCon 2013 : Scripting to PyPi to GitHub and More

PyPi Upload (2)PyPi Upload (2)$ python setup.py sdist register upload$ python setup.py sdist register upload......Creating tar archiveCreating tar archiveremoving 'rst2odp-0.2.4' (and everything under it)removing 'rst2odp-0.2.4' (and everything under it)running registerrunning registerrunning checkrunning checkWe need to know who you are, so please choose either:We need to know who you are, so please choose either: 1. use your existing login, 1. use your existing login, 2. register as a new user, 2. register as a new user, 3. have the server generate a new password for you (and email it to you), 3. have the server generate a new password for you (and email it to you), oror 4. quit 4. quitYour selection [default 1]:Your selection [default 1]:11

Page 167: PyCon 2013 : Scripting to PyPi to GitHub and More

PyPi Upload (3)PyPi Upload (3)

Username: mharrisonUsername: mharrisonPassword:Password:Registering rst2odp to http://pypi.python.org/pypiRegistering rst2odp to http://pypi.python.org/pypiServer response (200): OKServer response (200): OKI can store your PyPI login so future submissions will be faster.I can store your PyPI login so future submissions will be faster.(the login will be stored in /home/matt/.pypirc)(the login will be stored in /home/matt/.pypirc)Save your login (y/N)?ySave your login (y/N)?yrunning uploadrunning uploadSubmitting dist/rst2odp-0.2.4.tar.gz to http://pypi.python.org/pypiSubmitting dist/rst2odp-0.2.4.tar.gz to http://pypi.python.org/pypiServer response (200): OKServer response (200): OK

Page 168: PyCon 2013 : Scripting to PyPi to GitHub and More

PyPi NotePyPi Note

Though PyPi packages are signed there is Though PyPi packages are signed there is no verification step during package no verification step during package installationinstallation

Page 169: PyCon 2013 : Scripting to PyPi to GitHub and More

Non PyPi URLNon PyPi URL

$ pip install --no-index -f $ pip install --no-index -f http://dist.plone.org/thirdparty/ http://dist.plone.org/thirdparty/ -U PIL-U PIL

Page 170: PyCon 2013 : Scripting to PyPi to GitHub and More

Personal PyPiPersonal PyPi

https://github.com/benliles/djangopypihttps://github.com/benliles/djangopypi

Page 171: PyCon 2013 : Scripting to PyPi to GitHub and More

PyPiPyPiMakefileMakefile integration: integration:

# --------- PyPi ----------# --------- PyPi ----------.PHONY: build.PHONY: buildbuild: envbuild: env<TAB>$(PY) setup.py sdist<TAB>$(PY) setup.py sdist

.PHONY: upload.PHONY: uploadupload: envupload: env<TAB>$(PY) setup.py sdist register upload<TAB>$(PY) setup.py sdist register upload

Page 172: PyCon 2013 : Scripting to PyPi to GitHub and More

TestingTesting

Page 173: PyCon 2013 : Scripting to PyPi to GitHub and More

TestingTesting

Add tests to your projectAdd tests to your project

Page 174: PyCon 2013 : Scripting to PyPi to GitHub and More

Testing (2)Testing (2)

● use use doctestdoctest or or unittestunittest

Page 175: PyCon 2013 : Scripting to PyPi to GitHub and More

Testing (3)Testing (3)Use Use nosenose to run: to run:

$ env/bin/nosetests$ env/bin/nosetests....--------------------------Ran 2 tests in 0.007sRan 2 tests in 0.007s

OKOK

Page 176: PyCon 2013 : Scripting to PyPi to GitHub and More

Testing (4)Testing (4)MakefileMakefile integration: integration:NOSE := env/bin/nosetestsNOSE := env/bin/nosetests# --------- Testing ----------# --------- Testing ----------.PHONY: test.PHONY: testtest: nose depstest: nose deps<TAB>$(NOSE)<TAB>$(NOSE)

# nose depends on the nosetests binary# nose depends on the nosetests binarynose: $(NOSE)nose: $(NOSE)$(NOSE): env$(NOSE): env<TAB>$(PIP) install nose<TAB>$(PIP) install nose

Page 177: PyCon 2013 : Scripting to PyPi to GitHub and More

GithubGithub

Page 178: PyCon 2013 : Scripting to PyPi to GitHub and More

GithubGithub

Just a satisfied userJust a satisfied user

Page 179: PyCon 2013 : Scripting to PyPi to GitHub and More

Why Github?Why Github?

Not bazaar nor mercurialNot bazaar nor mercurial

Page 180: PyCon 2013 : Scripting to PyPi to GitHub and More

Why Github? (2)Why Github? (2)

Code is a first class objectCode is a first class object

Page 181: PyCon 2013 : Scripting to PyPi to GitHub and More

GithubGithub

Don't check in keys/passwords!Don't check in keys/passwords!

http://ejohn.org/blog/keeping-passwords-ihttp://ejohn.org/blog/keeping-passwords-in-source-control/#postcommentn-source-control/#postcomment

Page 182: PyCon 2013 : Scripting to PyPi to GitHub and More

A Branching StrategyA Branching Strategy

http://github.com/nvie/gitflowhttp://github.com/nvie/gitflow

Page 183: PyCon 2013 : Scripting to PyPi to GitHub and More

Travis CITravis CI

Page 184: PyCon 2013 : Scripting to PyPi to GitHub and More

Travis CITravis CI

CI (continuous integration) for GithubCI (continuous integration) for Github

Page 185: PyCon 2013 : Scripting to PyPi to GitHub and More

Travis CI (2)Travis CI (2)

Illustrates power of (web) hooksIllustrates power of (web) hooks

Page 186: PyCon 2013 : Scripting to PyPi to GitHub and More

5 Steps5 Steps

● Sign-in with githubSign-in with github● Sync repos on Profile pageSync repos on Profile page● Enable repoEnable repo● Create a Create a .travis.yml.travis.yml file on github file on github● Push a commit on githubPush a commit on github

Page 187: PyCon 2013 : Scripting to PyPi to GitHub and More

travis.ymltravis.ymllanguage: pythonlanguage: pythonpython:python: - "3.3" - "3.3" - "2.7" - "2.7" - "2.6" - "2.6" - "pypy" - "pypy"# command to run tests# command to run testsscript: make testscript: make test

Page 188: PyCon 2013 : Scripting to PyPi to GitHub and More

More InfoMore Info

http://about.travis-ci.org/http://about.travis-ci.org/

Page 189: PyCon 2013 : Scripting to PyPi to GitHub and More

PoachplatePoachplate

Page 190: PyCon 2013 : Scripting to PyPi to GitHub and More

poachplatepoachplate

Example of most of what we have talked Example of most of what we have talked about todayabout today

https://github.com/mattharrison/poachplathttps://github.com/mattharrison/poachplatee

Page 191: PyCon 2013 : Scripting to PyPi to GitHub and More

That's allThat's all

Questions? Tweet or email meQuestions? Tweet or email [email protected]@gmail.com

@__mharrison__@__mharrison__http://hairysun.comhttp://hairysun.com