[PYTHON] __version__ pièges et bonnes pratiques

Lors de la distribution d'un module Python, vous devez décrire son numéro de version,

Deux descriptions sont requises. Bien sûr, écrire le même numéro de version à deux endroits est gênant et source d'erreurs, je veux donc le faire en un seul endroit.

Décrivez le numéro de version dans __version __. Py et

mylibrary/__version__.py


__version_info__ = (1, 0, 0)
__version__ = '.'.join(map(str, __version_info__))

Je pense que la configuration de ʻimport __version __ from setup.pyet__init __. Py` est un modèle courant.

\ _ \ _ Version \ _ \ _ trap

Il y a un problème avec cette configuration. Dans __init __. Py (ou le module principal importé par __init __. Py), C'est le cas lors de la description de l'importation d'un module non standard.

mylibrary/__init__.py


from __version__ import __version__
from core import MyClass  # mylibrary.Raccourcis à utiliser dans MyClass

mylibrary/core.py


import numpy as np  #Importation de modules externes requis par MyClass

class MyClass(object):
    pas

Si vous exécutez setup.py dans cet état, ...

Erreur d'importation soudaine


> py setup.py install
Traceback (most recent call last):
  File "C:\Users\hoge\git\example\setup.py", line 4, in <module>
    from mylibrary import __version__
  File "C:\Users\hoge\git\example\mylibrary\__init__.py", line 2, in <module>
    from .core import MyClass
  File "C:\Users\hoge\git\example\mylibrary\core.py", line 1, in <module>
    import numpy as np
ImportError: No module named numpy

Une erreur ImportError se produira et le module mylibrary ne pourra pas être installé.

Même si install_requires pour installer numpy est décrit dans setup.py C'est une "clé dans l'état sûr" que le setup.py ne peut pas être exécuté et ne peut pas être installé.

Bonnes pratiques [^ 1]

[^ 1]: J'avais vraiment l'intention d'écrire le calendrier de l'Avent de cette année comme une "meilleure pratique", mais juste avant de trouver un moyen extrêmement facile, c'était totalement merdique. Je suis désolé, alors je vais le laisser tel quel. Veuillez vous référer à ceux qui utilisent un ancien environnement transcendantal où setup.cfg ne peut pas être utilisé.

La cause est que si vous importez __version __. Py, __init __. Py dans le même répertoire sera également importé. La solution est donc de "charger __version __. Py sans importer".

setup.py


#!/usr/bin/python

from setuptools import setup, find_packages
# from __version__ import __version__  #Supprimer, cause de ImportError
import os

packages = find_packages()

ns = dict()
for package in packages:
    version_file = os.path.join(package, '__version__.py')
    if os.path.exists(version_file):
        with open(version_file, mode='rt') as f:
            eval(compile(f.read(), version_file, 'exec'), dict(), ns)
            break

__version__ = ns['__version__']
del ns

setup(
    version=__version__,
)

Je n'entrerai pas dans les détails, mais je cherche __version __. Py, l'évalue et extrait la variable __version__ directement. De cette façon, vous pouvez éviter d'importer __init __. Py qui provoque ʻImportError`.

mais, Je suis réticent à écrire trop de code autre que les métadonnées dans setup.py Il n'est pas réaliste d'importer un module non standard avec __init __. Py.

Il semble que quelque chose comme "une erreur s'est produite lors de la tentative de combiner la description du numéro de version en un seul endroit" peut facilement se produire. Il n'est pas étonnant que l'opinion selon laquelle "\ _ \ _ version \ _ \ _ est un anti-pattern" sort.

meilleur entrainement

Écrivez setup.py comme suit.

setup.py


from setuptools import setup
setup()

Comme vous pouvez le voir, tout ce que vous avez à faire est d'appeler setup () et les paramètres sont vides.

setup () récupérera les paramètres manquants du fichier setup.cfg, le cas échéant, qu'il soit vide ou non. Et il y a une méthode de description dans setup.cfg qui spécifie et fait référence aux fichiers et aux variables.

setup.cfg


[metadata]
version = attr: mylibrary.__version__.__version__

Cela a le même effet que l'application de la variable __version__ du fichier mylibrary / __ version __. Py à la version desetup ().

Au fait, avec cette méthode ainsi que l'importation de __version __. Py,

Cependant, la référence de la variable décrite dans setup.cfg est la même que setup.py dans" Pas la meilleure pratique ", Il semble que le fichier soit directement ʻeval () `sans passer par le mécanisme d'importation, et une erreur ImportError ne se produit pas.

Résumé

En plus de la version, la plupart des choses qui ont été décrites dans setup.py peuvent être décrites intelligemment dans setup.cfg. De plus, non seulement les métadonnées de setup () mais aussi les paramètres tels que flake8, py.test et nosetest peuvent être décrits ensemble. Cela permet également de garder le répertoire propre.

Puisque j'ai mis setup.cfg avec beaucoup d'efforts, je veux en tirer le meilleur parti.

Recommended Posts

__version__ pièges et bonnes pratiques
Bonnes pratiques pour Django views.py et urls.py (?)
Pratiques et algorithmes DBSCAN
Découvrez les bonnes pratiques de cookiecutter-django
Construire et exécuter TOPPERS / ASP (version 10/03/2020)
Développement AWS Lambda Mes meilleures pratiques
Meilleures pratiques pour les fichiers de configuration dans Flask