Python gestion et déploiement de modules externes ************************************************* Il existe un projet qui permet de gérer plus facilement les modules externes Comme beaucoup de projet l'arrivée de Python3 a déclaré la fin de certains projets et la création de nouveau. Installation d'un module externe -------------------------------- Python < 2.8 ~~~~~~~~~~~~ La solution la plus simple est d'utiliser easy_install Pour l'installer il suffit d'aller sur https://pypi.python.org/pypi/setuptools puis de télécharger et de lancer l'executable cela génère dans le dossier **scripts** de python un excecutable nommé easy_install Pour l'utiliser rien de plus simple :: easy_install jinja2 Python > 3.0 ~~~~~~~~~~~~ La il faut changer d'outil pour utiliser **pip** Aller sur http://www.pip-installer.org/en/latest/installing.html et suivre les instructions en lançant get-pip.py Sinon on peut le faire manuellement, il faut tout d'abord télécharger et installer **distribute** sur https://pypi.python.org/pypi/distribute (version 0.6.49) Puis pour lancer l'installation :: python setup.py install faire la même chose avec pip sur https://pypi.python.org/pypi/pip/1.2.1 :: python setup.py install cela génère dans le dossier **scripts** de python un excecutable nommé pip pour l'utilisation rien de plus simple :: pip install simplejson pip install --upgrade simplejson pip uninstall simplejson Il est possible d'utiliser pip à travers un proxy .. code-block:: bash pip install --proxy=myboite\mylogin:mypassword@proxy.myboite.fr:8080 ablog Création d'un module externe ---------------------------- Il existe plusieurs moyens pour fournir à d'autres des outils développés en python. Suivant ce qui a été produit (application ou module) on peut imaginer leurs déploiement par: - un installateur (un msi ou exe pour windows, un deb ou rpm pour linux, ...) - un egg: un fichier zip directement utilisable par python - l'utilisation de pip ou setuptools Nous allons voir comment comment utiliser setuptools (ed donc pip) pour réaliser tout cela. Nous allons imaginer de créer le module **mytools** ayant la structure suivante :: mytools |_ mytools | |_ __init__.py | |_ parser.py | |_ sample | |_ sample1.py |_ setup.py Le fichier __init__.py .. code-block:: python #!/usr/bin/env python # -*- coding: utf-8 -*- """ Module mytools. Tout les outils idispensables pour python """ __version__ = "0.0.1" from parser import OptionParser .. note:: l'import d'OptionParser dans le init permet de faire "from mytools import OptionParser" au lieu de "from mytools.parser import OptionParser". cela est donc plus simple pour importer des classes importantes du module Le fichier parser.py .. code-block:: python #!/usr/bin/env python # -*- coding: utf-8 -*- """ Implémentation de parser avec de la couleur """ import colorconsole, colorconsole.terminal import os, sys import optparse __all__ = ['OptionParser'] import colorconsole, colorconsole.terminal import os, sys import optparse class OptionParser(optparse.OptionParser): def __init__(self, screen=None, **kw): optparse.OptionParser.__init__(self, **kw) if screen == None: screen = colorconsole.terminal.get_terminal() self.screen = screen def exit(self, status=0, msg=None): if msg: sys.stderr.write(msg) self.screen.set_color(colorconsole.terminal.colors["WHITE"], colorconsole.terminal.colors["BLACK"]) sys.exit(status) def error(self, msg): self.screen.set_color(colorconsole.terminal.colors["LRED"], None) optparse.OptionParser.error(self, msg) def print_version(self, file=None): self.screen.set_color(colorconsole.terminal.colors["LGREEN"],None) optparse.OptionParser.print_version(self, file) self.screen.set_color(colorconsole.terminal.colors["WHITE"], colorconsole.terminal.colors["BLACK"]) def print_help(self, file=None): self.screen.set_color(colorconsole.terminal.colors["LGREEN"],None) optparse.OptionParser.print_help(self, file) self.screen.set_color(colorconsole.terminal.colors["WHITE"], colorconsole.terminal.colors["BLACK"]) def print_info(self, msg=""): self.screen.set_color(colorconsole.terminal.colors["LGREEN"],None) print(msg) self.screen.set_color(colorconsole.terminal.colors["WHITE"], colorconsole.terminal.colors["BLACK"]) def print_stdout(self, msg, fg="WHITE", bg="BLACK"): self.screen.set_color(colorconsole.terminal.colors[fg],colorconsole.terminal.colors[bg]) sys.stdout.write(msg) self.screen.set_color(colorconsole.terminal.colors["WHITE"], colorconsole.terminal.colors["BLACK"]) def get_formatwidth(self, default=80): try: width = int(os.environ['COLUMNS']) except (KeyError, ValueError): width = default return "%-"+str(width)+"s" .. note:: Il est important de documenter son module. l'utilisation de __all__ permet de n'autoriser que certains éléments a être importable ... afin de faciliter la gestion du module pour les utilisateurs Le fichier sample1.py .. code-block:: python import sys, traceback from mytools.parser import OptionParser import os VERSION="0.1" PROG="sample1" DESCRIPTION="""description of sample1""" AUTHOR="Frederic Aoustin" if __name__ == '__main__': usage = "usage: %prog [options]" parser = OptionParser(version="%s %s" % (PROG,VERSION), usage=usage) parser.description= DESCRIPTION parser.epilog = AUTHOR parser.add_option("-a","--arg", dest = "myarg", action = "store_true", help = "arg by default False", default = False) try: (options, args) = parser.parse_args() if options.myarg: parser.error("myarg is True, error ;-)") sys.exit() except Exception as e: parser.error(e) sys.exit(1) On peut maintenant tester notre module mytools :: C:\Users\fraoustin\Google Drive\project\mytools>set PYTHONPATH=%PYTHONPATH%;. C:\Users\fraoustin\Google Drive\project\mytools>python mytools\sample\sample1.py -h Usage: sample1.py [options] description of sample1 Options: --version show program's version number and exit -h, --help show this help message and exit -a, --arg arg by default False Frederic Aoustin .. note:: on remarque que nous modifions notre PYTHONPATH afin de pouvoir charger notre module Notre installateur nous permettra d'éviter cette action Le fichier setup.py .. code-block:: python #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup, find_packages import mytools setup( name='mytools', version=mytools.__version__, packages=find_packages(), author="Frederic Aoustin", author_email="fraoustin@gmail.com", description="mes outils pour python", long_description="mes super outils pour python", install_requires= ['colorconsole'], #on peut preciser une version "colorconsole >= 0.1" include_package_data=False, #mettre True si vous avez un fichier manifest.ini url='http://mypage.com', # liste des marqueurs disponible sur:https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ "Programming Language :: Python", "Development Status :: 3 - Alpha", "License :: OSI Approved", "Natural Language :: French", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.0", "Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Communications", "Topic :: Terminals", ], # La syntaxe est "nom-de-commande-a-creer = package.module:fonction". #entry_points = { # 'console_scripts': [ # 'proclame-sm = sm_lib.core:proclamer', # ], #}, ) Nous n'utilisons pas de fichier manifest.ini mais il peut être utile si on ne souhaite pas par exemple exclure le répertoire sample mais inclure des fichiers jpg par exemple :: exclude sample include *.jpg La notion de entry_point permet d'obtenir des scripts qui lance automatiquement la fonction identifiée. Maintenant on peut: * installer notre module :: python setup.py install * créer une source de distribution :: python setup.py sdist --formats=tar,zip * créer un module eegs :: python setup.py bdist_egg * créer un installateur windows :: python setup.py bdist_wininst Pour ajouter notre module sur le site pypi créer un nouveau compte si besoin (option 2) :: python setup.py register ce connecter à son compte (option 1) :: python setup.py register cela permet de créer un fichier .pypirc au niveau de votre home contenant :: [distutils] index-servers = pypi [pypi] username:fraoustin password:V=4/3pir3 puis par la suite créer une source de distribution et la mettre en ligne :: python setup.py sdist upload .. note:: si vous avez une erreur 401 d'authentification il faut mettre à jours le module distribute via un "pip install --upgrade distribute" vous pouvez maintenant l'installer depuis pypi :: pip install mytools La comparaison de version pour l'outil est réalisée ainsi .. code-block:: python >>> from distutils.version import StrictVersion >>> StrictVersion('10.4.10') > StrictVersion('10.4.9') True