Python packaging
-
Upload
axel-haustant -
Category
Technology
-
view
85 -
download
2
description
Transcript of Python packaging
Packaging PythonPar Axel Haustant
Packaging ?
Pourquoi ?• pour distribuer
• pour déployer
• pour archiver
Être réutilisable
“
3
Comment ?• standard
• multiplateformes
• documenté
• à moindre coût
La solution: setuptools !
“
4
Les bases
setup.pyfrom setuptools import setup
setup( name='my-project', version='0.1.0', # ...)
C'est du Python donc tout est permis !
6
Identification• name
• version
• description
• long_description
• url
• classifiers
• ...
7
Versionning• respect des normes (PEP 386, semver...)
• release: {major}.{minor}.{patch}
• dev/master/...: {major}.{minor}.{patch}.dev
• Automatisez la release !
• script shell
• outil dédié (ex: Zest.releaser, Bump'R, ...)
8
Gestion des dépendances• install_requires
• tests_require
• extras_require
extras_require = { 'tests': ['factory-boy']}
$ pip install my-project[tests]
9
Gestion des resources• include_package_data/package_data
• MANIFEST.in
• pkg_resouces
10
READMEDoit permettre de démarrer rapidement.
• Présentation fonctionnelle rapide
• Procédure d'installation
• Documentation (ou lien)
• Complété par un changelog
11
Commandes
DéveloppezPour être prêt à développer:
$ python setup.py develop# ou$ pip install -e .
A refaire dès que les dépendances et les entrypoints changent.
13
PrévisualisezContrôlez ce que vous allez publier
$ python setup.py --long-description | rst2html$ python setup.py sdist
14
Publiez# Enregistrer le module sur PyPI$ python setup.py register# Publier sur PyPI$ python setup.py sdist upload# Créer un version avec un suffix$ python setup.py -q egg_info -b ".1234" sdist
15
Réutilisez !
Réutiliser les metadonnées du moduleSelon la PEP 396, le module doit contenir un attribut __version__
from project import __version__, __description__setup( name='project' version=__version__ description=__description__)
17
Réutiliser les requirements de pipRE_REQUIREMENT = re.compile(r'̂\s*-r\s*(?P<filename>.*)$')
def pip(filename): requirements = [] for line in open(join('requirements', filename)).readlines(): match = RE_REQUIREMENT.match(line) if match: requirements.extend(pip(match.group('filename'))) else: requirements.append(line) return requirements
setup( # ... install_requires=pip('install.pip'), tests_require=pip('test.pip'), extras_require = { 'tests': pip('test.pip'), },)
18
Réutiliser les fichiers rstPYPI_RST_FILTERS = ( (r'\.\.\s? code-block::\s*(\w|\+)+', '::'), # (r'.*travis-ci\.org/.*', ''), (r'.*pypip\.in/.*', ''), (r'.*crate\.io/.*', ''), (r'.*coveralls\.io/.*', ''),)
def rst(filename): content = open(filename).read() for regex, replacement in PYPI_RST_FILTERS: content = re.sub(regex, replacement, content) return content
long_description = '\n'.join(( rst('README.rst'), rst('CHANGELOG.rst'), ''))
19
Réutilisez la versiontry: from pkg_resources import get_distribution VERSION = get_distribution('project').versionexcept: VERSION = __import__('project').__version__
Prend en compte la version "installée" (ex: 0.1.0.dev1234)
20
Entry Points
Console scriptsPas besoin de répertoire bin
entry_points={ 'console_scripts': [ 'myexec = project.commands:main', ]}
$ myexec
22
Créer ses propres commandesentry_points = { 'distutils.commands': 'do_it = project.commands:DoSomething',},
from setuptools import Command
class DoSomething(Command): description = "Do something" user_options = []
def initialize_options(self): pass
def finalize_options(self): pass
def run(self): do_something()
23
Chargement d'extensionsUn project qui exporte
entry_points = { 'myproject.plugins': [ 'someplugin = other_project.plugins:SomePlugin', ],},
Un autre qui importe
import pkg_resources
for entrypoint in pkg_resources.iter_entry_points('myproject.plugins'): plugin = entrypoint.load()
24
Un peu de lecture• Documentation officielle de setuptools
• The Hitchhiker's Guide to Packaging
• PEP 386 (numéro de version)
• PEP 396 (version d'un module)
• PEP 345 (métadonnées)
• PEP 426 (métadonnées 2.0)
• semver
25
Questions
A suivre...• présentation:
• http://noirbizarre.github.io/slides/paris.py/
• http://slides.noirbizarre.info/paris.py/
• blog: http://noirbizarre.info
• twitter: @noirbizarre
• google+: noirbizarre
27
Extras
Layoutfi── docfi── myproject│ fi─ __init__.py│ └─ ..fi── requirements│ fi─ develop.pip│ fi─ install.pip│ fi─ tools.pip│ └─ test.pipfi─ .gitignorefi─ Makefile/Fabfilefi─ bumpr.rcfi─ CHANGELOG.rstfi─ pep8.rcfi─ pylint.rcfi─ MANIFEST.infi─ README.rst└─ setup.py
29