Slide 1

Slide 1 text

Share Your Code! Python Packaging without Complication daveops.com/pycon2017 [email protected] @tylerdave

Slide 2

Slide 2 text

def beautiful_code(): """This code is so beautiful."""   print('Hello, PyCon!')

Slide 3

Slide 3 text

“I want to share my code! What do I need to do?”

Slide 4

Slide 4 text

Package

Slide 5

Slide 5 text

Documentation

Slide 6

Slide 6 text

Source Hosting

Slide 7

Slide 7 text

Tests

Slide 8

Slide 8 text

CI

Slide 9

Slide 9 text

License

Slide 10

Slide 10 text

Contributing

Slide 11

Slide 11 text

we need Code Package Documentation Source Hosting Tests CI License Contributing

Slide 12

Slide 12 text

“But I just wanted to share my code!”

Slide 13

Slide 13 text

TL;DR

Slide 14

Slide 14 text

TL;DR

Slide 15

Slide 15 text

Terminology

Slide 16

Slide 16 text

Module Saved Python code

Slide 17

Slide 17 text

Import Package namespace / directory

Slide 18

Slide 18 text

Distribution Package Shareable / installable

Slide 19

Slide 19 text

Source Distribution sdist

Slide 20

Slide 20 text

Built Distribution Wheel

Slide 21

Slide 21 text

Wheel

Slide 22

Slide 22 text

Wheel Universal

Slide 23

Slide 23 text

Wheel Universal Pure Python

Slide 24

Slide 24 text

Wheel Universal Pure Python Platform

Slide 25

Slide 25 text

History

Slide 26

Slide 26 text

History Copy / Replace

Slide 27

Slide 27 text

History Copy / Replace PyPA

Slide 28

Slide 28 text

History Copy / Replace PyPA PyPUG https://packaging.python.org/

Slide 29

Slide 29 text

“Let's make a package!”

Slide 30

Slide 30 text

Using cookiecutter $ cookiecutter cookiecutter-python-package … full_name (default is "Dave Forgac")? email (default is "[email protected]")? github_username (default is "tylerdave")? project_name (default is "Example")? Example Package repo_name (default is "boilerplate")? Example-Package project_short_description (default is "A short description")? Example package for PyCon talk. release_date (default is "2017-05-21")? year (default is "2017")? version (default is "0.1.0")?

Slide 31

Slide 31 text

Layout . ├── data │ └── data_file ├── DESCRIPTION.rst ├── MANIFEST.in ├── README.rst ├── sample │ ├── __init__.py │ └── package_data.dat ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── test_sample.py

Slide 32

Slide 32 text

Code . ├── data │ └── data_file ├── DESCRIPTION.rst ├── MANIFEST.in ├── README.rst ├── sample │ ├── __init__.py │ └── package_data.dat ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── test_sample.py

Slide 33

Slide 33 text

setup.py . ├── data │ └── data_file ├── DESCRIPTION.rst ├── MANIFEST.in ├── README.rst ├── sample │ ├── __init__.py │ └── package_data.dat ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── test_sample.py

Slide 34

Slide 34 text

setup.cfg . ├── data │ └── data_file ├── DESCRIPTION.rst ├── MANIFEST.in ├── README.rst ├── sample │ ├── __init__.py │ └── package_data.dat ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── test_sample.py

Slide 35

Slide 35 text

MANIFEST.in . ├── data │ └── data_file ├── DESCRIPTION.rst ├── MANIFEST.in ├── README.rst ├── sample │ ├── __init__.py │ └── package_data.dat ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── test_sample.py

Slide 36

Slide 36 text

README.rst . ├── data │ └── data_file ├── DESCRIPTION.rst ├── MANIFEST.in ├── README.rst ├── sample │ ├── __init__.py │ └── package_data.dat ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── test_sample.py

Slide 37

Slide 37 text

setup.py (1/2) from setuptools import setup, find_packages   setup( name='Example Package', version='0.1.0', # PEP440-compliant version description='Example package for PyCon talk.', long_description='Displayed on PyPI project page.', url='https://github.com/tylerdave/Example-Package', author='Dave Forgac', author_email='[email protected]', packages=find_packages(exclude=['docs', 'tests']) install_requires=['requests'], package_data={ 'sample': ['package_data.dat'] }

Slide 38

Slide 38 text

setup.py (1/2) from setuptools import setup, find_packages   setup( name='Example Package', version='0.1.0', # PEP440-compliant version description='Example package for PyCon talk.', long_description='Displayed on PyPI project page.', url='https://github.com/tylerdave/Example-Package', author='Dave Forgac', author_email='[email protected]', packages=find_packages(exclude=['docs', 'tests']) install_requires=['requests'], package_data={ 'sample': ['package_data.dat'] }

Slide 39

Slide 39 text

setup.py (1/2) from setuptools import setup, find_packages   setup( name='Example Package', version='0.1.0', # PEP440-compliant version description='Example package for PyCon talk.', long_description='Displayed on PyPI project page.', url='https://github.com/tylerdave/Example-Package', author='Dave Forgac', author_email='[email protected]', packages=find_packages(exclude=['docs', 'tests']) install_requires=['requests'], package_data={ 'sample': ['package_data.dat'] }

Slide 40

Slide 40 text

setup.py (1/2) from setuptools import setup, find_packages   setup( name='Example Package', version='0.1.0', # PEP440-compliant version description='Example package for PyCon talk.', long_description='Displayed on PyPI project page.', url='https://github.com/tylerdave/Example-Package', author='Dave Forgac', author_email='[email protected]', packages=find_packages(exclude=['docs', 'tests']) install_requires=['requests'], package_data={ 'sample': ['package_data.dat'] }

Slide 41

Slide 41 text

setup.py (1/2) from setuptools import setup, find_packages   setup( name='Example Package', version='0.1.0', # PEP440-compliant version description='Example package for PyCon talk.', long_description='Displayed on PyPI project page.', url='https://github.com/tylerdave/Example-Package', author='Dave Forgac', author_email='[email protected]', packages=find_packages(exclude=['docs', 'tests']) install_requires=['requests'], package_data={ 'sample': ['package_data.dat'] }

Slide 42

Slide 42 text

setup.py (2/2) … entry_points={ 'console_scripts': [ 'hello=example_package.cli:say_hello', ], } license='MIT', classifiers=[ 'Development Status :: 3 - Alpha', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5',

Slide 43

Slide 43 text

setup.py (2/2) … entry_points={ 'console_scripts': [ 'hello=example_package.cli:say_hello', ], } license='MIT', classifiers=[ 'Development Status :: 3 - Alpha', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5',

Slide 44

Slide 44 text

setup.py (2/2) … entry_points={ 'console_scripts': [ 'hello=example_package.cli:say_hello', ], } license='MIT', classifiers=[ 'Development Status :: 3 - Alpha', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5',

Slide 45

Slide 45 text

setup.cfg [bdist_wheel] universal = 1           [flake8] exclude = docs

Slide 46

Slide 46 text

MANIFEST.in include LICENSE include README.rst   recursive-include tests * recursive-exclude * __pycache__ recursive-exclude * *.py[co]

Slide 47

Slide 47 text

README.rst =============================== Example Package ===============================   License: MIT   Documentation: https://example.com   Usage -----   ``sample --help``

Slide 48

Slide 48 text

LICENSE

Slide 49

Slide 49 text

Tests ./tests tox.ini

Slide 50

Slide 50 text

Docs ./docs

Slide 51

Slide 51 text

CI .travis.yml

Slide 52

Slide 52 text

requirements.txt

Slide 53

Slide 53 text

Also Common (rst | md | txt) HISTORY or CHANGES or CHANGELOG CONTRIBUTING AUTHORS

Slide 54

Slide 54 text

“Now let's share our code!”

Slide 55

Slide 55 text

Git init cd Example-Package git init git add . git commit -m 'initial commit'

Slide 56

Slide 56 text

Run tests tox … OK ___________________________ summary __________________________ py27: commands succeeded py34: commands succeeded py35: commands succeeded py36: commands succeeded

Slide 57

Slide 57 text

Commit git add . git commit -m "add hello pycon functionality"

Slide 58

Slide 58 text

Services

Slide 59

Slide 59 text

GitHub

Slide 60

Slide 60 text

Travis CI https://travis-ci.org/ or travis enable

Slide 61

Slide 61 text

Git push To [email protected]:tylerdave/Example-Package.git * [new branch] master -> master Branch master set up to track remote branch master from origin.

Slide 62

Slide 62 text

See builds succeeding!

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

PyPI https://pypi.python.org/

Slide 65

Slide 65 text

PyPI https://pypi.python.org/ Test PyPI https://testpypi.python.org/

Slide 66

Slide 66 text

Save PyPI Settings $HOME/.pypirc [distutils] index-servers=pypi [pypi] repository = https://pypi.python.org/pypi username = password =

Slide 67

Slide 67 text

Virtualenv pew virtualenvwrapper

Slide 68

Slide 68 text

Packaging Tools pip install wheel pip install twine

Slide 69

Slide 69 text

Build dist. files ./setup.py sdist ./setup.py bdist_wheel or make dist

Slide 70

Slide 70 text

Upload twine upload dist/*

Slide 71

Slide 71 text

Install pip install example-package

Slide 72

Slide 72 text

Develop Mode ./setup.py develop or pip install -e .

Slide 73

Slide 73 text

Rinse, Repeat

Slide 74

Slide 74 text

Versions bumpversion versioneer

Slide 75

Slide 75 text

Recap

Slide 76

Slide 76 text

Recap DIY

Slide 77

Slide 77 text

Recap DIY Use the tools

Slide 78

Slide 78 text

Recap DIY Use the tools Share your code!

Slide 79

Slide 79 text

Thank you! Please leave feedback daveops.com/pycon2017 [email protected] @tylerdave