.. -*- mode: rst -*-
|GitHubActionTestBadge|_ |ReadTheDocsBadge|_ |GitHubActionPublishBadge|_ |PyPiBadge|_
.. |GitHubActionTestBadge| image:: https://github.com/simai-ml/how-to-opensource/actions/workflows/test.yml/badge.svg
.. _GitHubActionTestBadge: https://github.com/simai-ml/how-to-opensource/actions
.. |ReadTheDocsBadge| image:: https://readthedocs.org/projects/how-to-opensource/badge
.. _ReadTheDocsBadge: https://how-to-opensource.readthedocs.io/en/latest
.. |GitHubActionPublishBadge| image:: https://github.com/simai-ml/how-to-opensource/actions/workflows/publish.yml/badge.svg
.. _GitHubActionPublishBadge: https://github.com/simai-ml/how-to-opensource/actions
.. |PyPiBadge| image:: https://img.shields.io/pypi/v/QM-How-to-Opensource
.. _PyPiBadge: https://pypi.org/project/QM-How-to-Opensource/
BBL - Publier un package en open-source en dix étapes clés
==========================================================
Quelles sont les étapes indispensables pour publier un package Python en open-source ? Depuis l’écriture d’un code propre et la rédaction de la documentation, jusqu’aux tests d’intégration continue et au processus de packaging, nous passerons en revue les dix points clés pour une publication d’un package Python en open-source. Pour ce faire, nous prendrons l’exemple d’un toy model que nous publierons sur github et pypi en moins de deux heures.
Sommaire
========
Voici les 10 bonnes pratiques de développement open-source détaillées ci-après dans ce tutoriel :
1. **Mettre en place un dépôt GitHub,** soit à partir de zéro, soit en forkant un dépôt existant
2. **Encapsuler les fonctions dans un module** facile à importer et renseignant un numéro de version
3. **Documenter les fonctions avec une dosctring et un doctest.** La docstring sera automatiquement publié en ligne et le doctest automatiquement exécuté pendant l'intégration continue.
4. **Ecrire vos fonctions avec déclaration de types.** C'est une habitude facile à prendre qui génère automatiquement des tests unitaires statiques avec MyPy_.
5. **Créer des tests unitaires avec un objectif de couverture de 100%.** La paramétrisation des tests avec ``pytest.xmark.parametrize`` permet de générer des tests très rapidement.
6. **Implémenter une intégration continue du code.** Sur GitHub, le standard est d'utiliser des GitHub Actions. Pensez à toujours tester votre code sur Windows.
7. **Générer une documentation semi-automatique avec Sphinx_.** L'API de votre package est automatiquement documentée si vous avez écrit les docstrings à l'avance. Il ne reste plus qu'à rédiger les parties importantes et les messages à faire passer aux utilisateurs. Les exemples sont un bon moyen d'accompagner la montée en compétences rapide des utilisateurs.
8. **Déployer la documentation de manière continue avec ReadTheDocs_.** Le déploiement continu doit se déclencher a minima à chaque pull request.
9. **Packager votre module avec le fichier setup.py.** Ce fichier est la pierre angulaire de la publication sur PyPi_. Les numéros de version sont plus facile à gérer avec bump2version_.
10. **Déployer votre package de manière continue avec les release GitHub** et les actions correspondantes. Vous pouvez cacher votre mot de passe PyPi_ par un système de tokens.
Pré-requis
==========
1. Avoir un compte GitHub
2. Faire un **Fork** du dépôt (bouton en haut à droite de GitHub)
3. Avoir une installation locale de conda
Si vous n'avez pas de conda installé : téléchargez l'installeur Conda_ ou exécutez les commandes suivantes:
.. code:: shell-session
$ wget https://repo.anaconda.com/miniconda/Miniconda3-py39_4.9.2-MacOSX-x86_64.sh -O miniconda.sh
$ chmod +x miniconda.sh
$ bash miniconda.sh
Attention à bien accepter la demande d'initialisation.
Exercice n°1: Mise en place de l'environnement
==============================================
Clonez votre dépôt forké.
.. code:: shell-session
$ git clone https://github.com/COMPTE/how-to-opensource.git
Installez et activez l'EnvConda_ de développement, environnement qui nous servira à développer le code, la documentation et les tests:
.. code:: shell-session
cd how-to-opensource
conda env create -f environment.dev.yml
conda activate how_to_opensource
Créer une branche de travail et supprimez la correction :
.. code:: shell-session
git checkout -b work
chmod +x start.sh
./start.sh
git add .
git commit -m "start exercises"
git push origin work
Vous pouvez commencer !
Exercice n°2: Création d'un module et d'une fonction
====================================================
Nous allons maintenant créer dans le Module_ ``how_to_opensource`` une nouvelle fonction calculant la somme de deux vecteurs.
Pour cela créez le fichier ``how_to_opensource/core.py`` et créez une nouvelle fonction ``add_two_vectors`` qui va, comme son
nom l'indique, effectuer une addition de deux vecteurs grâce à ``numpy.add``.
Afin de pouvoir importer la fonction, vous devez définir les redirections d'imports dans le fichier ``how_to_opensource/__init__.py``.
.. code:: python
from .core import add_two_vectors
from ._version import __version__
__all__ = ["add_two_vectors", "__version__"]
La première ligne de code vous permet de faire directement
.. code:: python
from how_to_opensource import add_two_vectors
au lieu de
.. code:: python
from how_to_opensource.core import add_two_vectors
La ligne ``__all__ = ...`` permet à la fonction d'être importée avec la syntaxe ``from how_to_opensource import *``.
Enfin, nous anticipons d'ores et déjà le packaging en introduisant un numéro de version dans le fichier ``_version.py`` qui contient une seule ligne de code : ``__version__ = "0.0.0"``.
Il est maintenant possible de tester interactivement la méthode :
.. code:: python
import numpy as np
from how_to_opensource import add_two_vectors
add_two_vectors(np.ones(2), np.ones(2))
ou la version du package :
.. code:: python
import how_to_opensource
print(how_to_opensource.__version__)
Si vous voulez vérifier la syntaxe de votre code, vous pouvez exécuter la commande :
.. code:: shell-session
$ flake8 how_to_opensource
**CORRECTION :**
.. code:: shell-session
git checkout master how_to_opensource/__init__.py how_to_opensource/core.py how_to_opensource/_version.py
Exercice n°3: Typing
====================
Une pratique courante pour rendre plus robuste un package consiste à utiliser le typing pour tout ou une partie du code.
Si l'interpréteur python ne vérifie pas ces types à l'exécution, le langage python propose néanmoins le vocabulaire et la grammaire
nécessaire à la définition de ces types par l'intermédiaire du module Typing_.
Typez maintenant les définitions de ``add_two_vectors`` et de sa fonction de test. Il est aussi possible d'ajouter un test à
l'exécution pour valider que les entrées se conforment au type attendu. Enfin lancez l'analyseur statique de code le second statique utilisant MyPy_.
.. code:: shell-session
$ mypy how_to_opensource --strict
**CORRECTION :**
.. code:: shell-session
git checkout master how_to_opensource/core.py mypy.ini
Exercice n°4: Documentation de la fonction
==========================================
Numpydoc_ propose une méthode de documentation efficace. Ajoutez une documentation à ``add_two_vectors`` spécifiant ses paramètres,
sa sortie et en y incluant une DocTest_. Lancez ensuite la procédure de test en incluant cette fois le test de la documentation.
.. code:: shell-session
$ pytest -vs --doctest-modules --cov-branch --cov=how_to_opensource --pyargs how_to_opensource
**CORRECTION :**
.. code:: shell-session
git checkout master how_to_opensource/core.py
Exercice n°5: Création d'un test unitaire
=========================================
Il convient maintenant de tester cette fonction avec PyTest_. Une méthode standard pour élargir rapidement le domaine testé est
d'utiliser Parameterize_ pour paramétriser les fonctions de test.
Dans ``how_to_opensource/tests/test_core.py`` ajoutez une fonction de test validant le bon fonctionnement de ``add_two_vectors``
en testant différentes dimensions de vecteurs. Lancez maintenant le test en générant les métriques validant que vos tests couvrent bien le code:
.. code:: shell-session
$ pytest -vs --doctest-modules --cov-branch --cov=how_to_opensource --pyargs how_to_opensource
**CORRECTION :** ``git checkout master how_to_opensource/tests/test_core.py``
Exercice n°6: Intégration continue du code
==========================================
Afin d'assurer un niveau de qualité constant, particulièrement dans le cas d'un projet opensource avec de multiples contributeurs, il est
indispensable d'automatiser le processus d'intégration des changements réalisés. C'est à ce point que répond l'intégration continue.
Se basant sur la description d'un pipeline incluant build, test et déploiement, les outils d'integration continue, par exemple
GitHubActions_ ou TravisCI_ en permettent l'automatisation. Cela apporte les valeurs suivantes:
- minimiser la charge de travail pour les concepteurs
- supprimer les erreurs arrivant dans toute action "à la main"
- réduire le temps nécessaire à la détection et l'analyse de problèmes car chaque changement est validé unitairement
- réduire le temps de cycle pour la livraison de nouvelles fonctionnalités tout en en améliorant la qualité
Nous allons utiliser les GitHub actions, pour cela rendez vous sur l'onglet **Actions** de la page GiHub de votre projet.
Pour créer notre workflow d'intégration continue nous allons partir du template **Python Package using Anaconda**, disponible après avoir
cliqué sur **Setup this workflow**. Créez le fichier ``test.yml`` dans le dossier ``.github/workflows``, copiez le template proposé par GitHub
puis modifiez ensuite les étapes du workflow pour coller aux éléments définis précédemment:
- déploiement sur Python 3.9 , Python 3.8, Ubuntu et Windows
- installation de flake8, mypy, numpy, et pytest-cov
- tester le linting, le typing et les tests unitaires
Une fois le fichier créé poussé sur le dépôt, vous pouvez suivre l'execution du pipeline depuis l'interface de GitHub.
Un mail vous sera automatiquement envoyé en fin d'execution pour vous informer des résultats.
**CORRECTION :** ``git checkout master .github/workflows/test.yml``
Exercice n°7: Génération de la documentation
============================================
Avoir une documentation à jour est indispensable autant pour les utilisateurs que pour les contributeurs.
Afin de faciliter la création et la maintenance de celle-ci nous allons utiliser Sphinx_. Le quick start de Sphinx permet l'initialisation rapide des éléments nécessaires.
.. code:: shell-session
$ sphinx-quickstart doc
Note: il n'est pas nécessaire de séparer les répertoires sources et build dans notre cas simple.
Pour générer la documentation il vous suffit maintenant d'exécuter le script nouvellement créé:
.. code:: shell-session
$ cd doc
$ make html
La documentation a été générée dans le repertoire ``doc/_build``, vous pouvez la consulter dans votre navigateur web, elle est belle, mais vide.
En plus de la rédaction que vous ne manquerez pas d'ajouter, il est important de capitaliser sur la documentation écrite à l'exercice n°4.
Pour ce faire, il faut d'abord modifier le fichier **doc/conf.py** pour ajouter ``'sphinx.ext.autodoc'``, ``'sphinx.ext.napoleon'``, et ``'sphinx_autodoc_typehints'``
à la liste des extensions.
Il faut également définir la version du package:
.. code:: python
release = 0.0.0
Enfin, il faut ajouter la documentation automatique du module dans ``doc/index.rst`` qui sera par ailleurs le point d'entrée de toute rédaction additionnelle:
.. code::
.. automodule:: how_to_opensource
:members:
Afin de permettre de trouver le module et d'activer la prise en compte des types, ajoutez les lignes suivantes au fichier ``doc/conf.py``:
.. code:: python
import sys
sys.path.append('../')
napoleon_use_param = True
Une méthode efficace pour enrichir la documentation consiste à ajouter des exemples que l'on met en valeur à l'aide de SphinxGallery_.
Dans ``doc/conf.py``, ajoutez l'extension ``'sphinx_gallery.gen_gallery'``, puis définissez la configuration de la galerie:
.. code:: python
sphinx_gallery_conf = {
'examples_dirs': '../examples', # path to your example scripts
'gallery_dirs': 'auto_examples', # path to where to save gallery generated output
}
Enfin il est nécessaire d'inclure cette galerie à la racine de la documentation, dans ``doc/index.rst`` ajoutez son inclusion:
.. code::
.. toctree::
:maxdepth: 2
auto_examples/index
Pour créer un exemple qui s'affichera dans la doc, vous devez simplement créer un script python dans le répertoire ``examples``. Par exemple :
.. code:: python
"""
===========
Toy Example
===========
L'exemple le plus simple que l'on puisse imaginer.
"""
from how_to_opensource import add_two_vectors
add_two_vectors([12.5, 26.1], [7.5, 3.9])
Le dossier ``examples`` tout juste créé doit s'accompagner d'un fichier ``README.rst`` avec un titre comme:
.. code::
Exemples avancés
================
Vous pouvez alors reconstruire la doc avec `make html` et vérifier que votre documentation est belle !
.. code:: shell-session
open doc/_build/html/index.html
**CORRECTION :** ``git checkout master doc examples``
Exercice n°8: Déploiement continu de la documentation
=====================================================
Pour diffuser cette documentation il est nécessaire de la publier sur un site publique, par exemple en utilisant ReadTheDocs_.
Ce dernier réalisera les tâches définies dans le fichier ``.readthedocs.yml``, ajoutez donc ce fichier au dépôt avec le contenu suivant:
.. code::
version: 2
build:
image: latest
conda:
environment: environment.dev.yml
sphinx:
builder: html
configuration: doc/conf.py
fail_on_warning: false
Ensuite, créez un compte gratuit sur ReadTheDocs_ en utilisant votre login GitHub.
Une fois inscrit et connecté, importez votre projet GitHub (attention à ajouter votre trigramme à l'url du projet par souci d'unicité).
Après avoir soigneusement choisi la branche et la version, lancez la compilation. Suivez son bon déroulement et vérifiez que la documentation produite est conforme à vos attentes.
Pour automatiser la compilation de la doc à chaque pull request, allez ensuite dans Admin > Paramètres avancés et cochez la case "Build pull requests for this project".
Il faut également connecter vos comptes GitHub et ReadTheDocs par un webhook comme suit :
1. sur votre compte ReadTheDocs, allez dans Admin > Integrations > Add integration > GitHub incoming webhook
2. sur votre repo GitHub, allez dans Settings > Webhooks > Add webhook > copier l'URL "payload URL" de readthedocs.
Et voilà ! Votre documentation se reconstruit automatiquement à chaque pull request !
**CORRECTION :** ``git checkout master .readthedocs.yml``
Exercice n°9: Packaging
=======================
De façon à offrir une API claire à l'ensemble des modules de notre projet (certes il n'y en a qu'un en l'état mais cela est voué à changer),
il est utile de créer un package_ qui permet d'avoir un espace de nommage encapsulant les modules et variables, et diffusable directement sur PyPi_.
Pour cela, il est nécessaire d'ajouter un fichier ``setup.py`` à notre projet, et de le définir, vous pouvez pour cela partir de ce tutoriel_.
Voici un exemple de fichier ``setup.py``, ce sont essentiellement des descripteurs qui s'afficheront tels quels sur PyPi_.
**IMPORTANT :** chaque package doit avoir un nom unique sur PyPi_, qui est déduit du paramètre ``name``. Pensez-bien à ajouter votre trigramme dans le ``name`` pour que chacun puisse publier son package sans conflit de noms.
.. code:: python
import os
from setuptools import setup
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
setup(
name="QM How to Opensource by TRIGRAMME",
version="0.0.1",
author="Grégoire Martignon, Vianney Taquet, Damien Hervault",
author_email="gmartignon@quantmetry.com",
description="A Quantmetry tutorial on how to publish an opensource python package.",
license="BSD",
keywords="example opensource tutorial",
url="http://packages.python.org/how_to_opensource",
packages=['how_to_opensource'],
install_requires=["numpy>=1.20"],
extras_require={
"tests": ["flake8", "mypy", "pytest-cov"],
"docs": ["sphinx", "sphinx-gallery", "sphinx_rtd_theme", "numpydoc"]
},
long_description=read('README.rst'),
classifiers=[
"License :: OSI Approved :: BSD License",
"Programming Language :: Python :: 3.9"
],
)
Il ne vous reste plus qu'à construire votre package
.. code:: shell-session
$ python setup.py sdist bdist_wheel
Cela crée trois répertoires : ``dist``, ``build`` et ``QM_How_to_Opensource.egg-info``.
Le ``egg-info`` est une simple collection de fichiers texte purement informatifs, et le ``dist`` est le contenu de ce qui sera hébergé sur PyPi_.
Si vous voulez vérifier que votre `README.rst` est sans erreur, vous pouvez exécuter la commande
.. code:: shell-session
$ twine check dist/*
**N.B.** Cette commande vérifie le contenu du répertoire ``dist``. En conséquence, si vous modifiez le ``README.rst``, il faut exécuter à nouveau la commande ``python setup.py sdist`` pour faire un nouveau check.
Dernier élément d'un package open-source: la license. Elles sont toutes disponibles sur OpenSourceInitiative_, il suffit de la copier-coller dans le fichier `LICENSE` et de remplacer les noms des auteurs et la date !
Pour un projet open-source entièrement libre, la license new BSD-3 est courante en machine learning..
Notre package est maintenant en place, prêt à être publié et ouvert à sa communauté d'utilisateurs et de contributeurs. Il est nécessaire de donner à ses deux populations les outils dont ils ont besoin.
Une accessibilité simple et maîtrisée pour les premiers, de clarté sur les règles de leur engagement pour les seconds.
Dans la mesure où ce nom de version va se retrouver à plusieurs endroits (``setup.py``, ``doc/conf.py``, ...), et pour ne pas risquer d'erreurs dans le maintien en cohérence de cette information à plusieurs endroits, il est possible d'utiliser bump2version_. Pour cela créez un fichier ``.bumpversion.cfg`` à la racine du projet, ce dernier va définir dans quel fichier remplacer automatiquement le numéro de version. Ajoutez-y le contenu ci-dessous et assurez vous que tous les fichiers contiennent initialement les mêmes numéros de version, par la suite ils seront mis à jour automatiquement :
.. code::
[bumpversion]
current_version = 0.0.0
commit = True
tag = True
[bumpversion:file:setup.py]
search = version="{current_version}"
replace = version="{new_version}"
[bumpversion:file:how_to_opensource/_version.py]
search = __version__ = "{current_version}"
replace = __version__ = "{new_version}"
[bumpversion:file:doc/conf.py]
search = release = "{current_version}"
replace = release = "{new_version}"
Vous pouvez désormais incrémenter le numéro de version avec ``bumpversion``.
Trois choix sont possibles pour l'incrémentation du numéro de version: patch, minor, et major. Nous choisissons ici d'incrémenter le "patch":
.. code:: shell-session
$ bumpversion patch
$ git push --tags
Votre publication sur PyPi_ se fait simplement avec la commande :
.. code:: shell-session
$ twine upload dist/*
Attention, cette commande nécessite un identifiant et un mot de passe, il faut donc vous créer un compte au préalable sur PyPi_.
**CORRECTION :** ``git checkout master setup.py LICENSE .bumpversion.cfg``
Exercice n°10: déploiement continu
==================================
Maintenant nous allons mettre en place la publication automatique sur PyPi_ après chaque release officielle de votre package.
Le but est de déclencher automatiquement, à la publication d'une nouvelle release depuis GitHub, la publication de la nouvelle version du package vers PyPi.
Cela signifie donc que le workflow GitHub devra se connecter à votre compte PyPi_.
Pour ne pas avoir à mettre en clair les éléments nécessaires à cette authentification dans votre dépôt, il existe un mécanisme permettant de se connecter à
PyPi sur base d'un token, et de stocker ce token en tant qu'élément secret dans le dépôt GitHub.
Pour cela, une fois connecté sur PyPi:
- Rendez-vous sur la page *Account Settings* et descendez jusqu'à la section *API Tokens*.
- Cliquez sur *Add Token*, donnez lui un nom, par exemple *how-to-opensource* et donnez lui accès au scope complet.
- Copiez le token généré et gardez cette page ouverte au cas où.
- Dans une autre fenêtre, rendez vous sur votre dépôt GitHub à la page *Settings*, section *Secrets*.
Appelez le PYPI_API_TOKEN et collez dans le champ *Value* le token copié depuis PyPi_.
Nous pouvons maintenant mettre en place le workflow de publication automatique, pour cela:
- Rendez vous dans l'onglet *Actions* du projet GitHub et cliquez sur *New workflow*.
- Choisissez le template *Publish Python Package*, renommez le fichier ``publish.yml``, spécifiez la version 3.9 de python et confirmez l'ajout du workflow.
Pour déclencher le workflow, allez sur la page principale du dépôt GitHub, à droite, cliquez sur Releases. Vous devriez voir tous les tags poussés jusqu'à présent. Choisissez le dernier et cliquez sur "Edit tag". Pensez à bien pointer sur la branche ``work``. Cliquez ensuite sur "Publish release". L'action de publication s'est normalement déclenchée dans l'onglet GitHub Actions. Une fois terminée, vous pouvez vérifier que la mise à jour sur PyPi_ s'est bien déroulée.
Enfin il convient d'ajouter de documenter les règles de contribution et d'usage du package. Pour cela rendez vous dans la page **Insights/Community** de GitHub. Cette dernière fournit un moyen simple d'initier les documents nécessaires.
Vous pouvez également naviguer dans l'onglet Insights > Community de github et remplir votre projet avec des template d'issue, pull request ou codes de conduite.
**IMPORTANT :** Vous avez déjà publié une version de votre package à l'étape précédente. Pour republier une nouvelle version, vous être obligé de "bumper" la version à nouveau :
.. code:: shell-session
$ bumpversion patch
$ git push --tags
**CORRECTION :** ``git checkout master .github/workflows/publish.yml``
Récapitulatif
=============
Voici les 10 bonnes pratiques de développement open-source:
1. **Mettre en place un dépôt GitHub,** soit à partir de zéro, soit en forkant un dépôt existant
2. **Encapsuler les fonctions dans un module** facile à importer et renseignant un numéro de version
3. **Documenter les fonctions avec une dosctring et un doctest.** La docstring sera automatiquement publié en ligne et le doctest automatiquement exécuté pendant l'intégration continue.
4. **Ecrire vos fonctions avec déclaration de types.** C'est une habitude facile à prendre qui génère automatiquement des tests unitaires statiques avec MyPy_.
5. **Créer des tests unitaires avec un objectif de couverture de 100%.** La paramétrisation des tests avec ``pytest.xmark.parametrize`` permet de générer des tests très rapidement.
6. **Implémenter une intégration continue du code.** Sur GitHub, le standard est d'utiliser des GitHub Actions. Pensez à toujours tester votre code sur Windows.
7. **Générer une documentation semi-automatique avec Sphinx_.** L'API de votre package est automatiquement documentée si vous avez écrit les docstrings à l'avance. Plus qu'à rédiger les parties importantes et les messages à faire passer aux utilisateurs. Les exemples sont un bon moyen d'accompagner la montée en compétences rapide des utilisateurs.
8. **Déployer la documentation de manière continue avec ReadTheDocs_.** Le déploiement continu doit se déclencher a minima à chaque pull request.
9. **Packager votre module avec le fichier setup.py.** Ce fichier est la pierre angulaire de la publication sur PyPi_. Les numéros de version sont plus facile à gérer avec bump2version_.
10. **Déployer votre package de manière continue avec les release GitHub** et les actions correspondantes. Vous pouvez cacher votre mot de passe PyPi_ par un système de tokens.
BONUS: Gestion du dépôt sur le long terme
=========================================
Quelques bonnes pratiques de gestion du dépôt sur le long terme :
* Tout problème ou amélioration du code doit faire l'objet d'une issue avant une pull request. Les pull request doivent être reliées aux issues qu'elles résolvent.
* Tout incrément de code doit passer par des pull request revue par une personne tierce
* L'onglet GitHub Projects vous permets d'organiser les issues sous formes de cartes simili-Trello, et rend publique votre feuille de route de développement.
* Il est recommandé d'ajouter deux fichiers de documentation à votre repo : un ``CONTRIBUTING.md`` qui renseigne les contributeurs éventuels sur l'art et la manière de faire des pull request pour ce projet, et un ``RELEASE_CHECKLIST.md`` récapitulant toutes les étapes de vérification avant publication sur PyPi_. Vous trouverez un exemple sur MAPIE_.
Bonus: Badges
=============
Notre intégration continue est maintenant en place. Afin de donner une vue de synthèse de son execution et de donner confiance aux utilisateurs potentiels quand à la qualité du package, il est possible d'ajouter des badges qui donneront un status à jour de l'execution de l'intégration continue.
Il faut pour cela, ajoutez dans le README situé à la racine du dépôt les liens suivants:
.. code::
|GitHubActionTestBadge|_ |ReadTheDocsBadge|_ |GitHubActionPublishBadge|_ |PyPiBadge|_
.. |GitHubActionTestBadge| image:: https://github.com/simai-ml/how-to-opensource/actions/workflows/test.yml/badge.svg
.. _GitHubActionTestBadge: https://github.com/simai-ml/how-to-opensource/actions
.. |ReadTheDocsBadge| image:: https://readthedocs.org/projects/how-to-opensource/badge
.. _ReadTheDocsBadge: https://how-to-opensource.readthedocs.io/en/latest
.. |GitHubActionPublishBadge| image:: https://github.com/simai-ml/how-to-opensource/actions/workflows/publish.yml/badge.svg
.. _GitHubActionPublishBadge: https://github.com/simai-ml/how-to-opensource/actions
.. |PyPiBadge| image:: https://img.shields.io/pypi/v/QM-How-to-Opensource
.. _PyPiBadge: https://pypi.org/project/QM-How-to-Opensource/
.. _Conda: https://docs.conda.io/en/latest/miniconda.html
.. _EnvConda: https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html
.. _Module: https://docs.python.org/3/tutorial/modules.html
.. _PyTest: https://docs.pytest.org/en/6.2.x/
.. _Parameterize: https://docs.pytest.org/en/6.2.x/parametrize.html
.. _Numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html
.. _DocTest: https://docs.python.org/3/library/doctest.html
.. _Typing: https://docs.python.org/3/library/typing.html
.. _TravisCI: https://travis-ci.com/
.. _MyPy: http://mypy-lang.org/
.. _Sphinx: https://www.sphinx-doc.org/en/master/index.html
.. _ReadTheDocs: https://readthedocs.org/
.. _SphinxGallery: https://sphinx-gallery.github.io/stable/getting_started.html
.. _GitHubActions: https://github.com/features/actions
.. _package: https://docs.python.org/3/tutorial/modules.html#packages
.. _tutoriel: https://packaging.python.org/guides/distributing-packages-using-setuptools/
.. _OpenSourceInitiative: https://opensource.org/licenses/BSD-3-Clause
.. _bump2version: https://github.com/c4urself/bump2version
.. _PyPi: https://pypi.org/account/register/
.. _MAPIE: https://github.com/simai-ml/MAPIE
Raw data
{
"_id": null,
"home_page": "http://packages.python.org/how_to_opensource",
"name": "QM-How-to-Opensource-CHP",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "example opensource tutorial",
"author": "Gr\u00e9goire Martinon, Vianney Taquet, Damien Hervault",
"author_email": "gmartignon@quantmetry.com",
"download_url": "",
"platform": null,
"description": ".. -*- mode: rst -*-\n\n|GitHubActionTestBadge|_ |ReadTheDocsBadge|_ |GitHubActionPublishBadge|_ |PyPiBadge|_\n\n.. |GitHubActionTestBadge| image:: https://github.com/simai-ml/how-to-opensource/actions/workflows/test.yml/badge.svg\n.. _GitHubActionTestBadge: https://github.com/simai-ml/how-to-opensource/actions\n\n.. |ReadTheDocsBadge| image:: https://readthedocs.org/projects/how-to-opensource/badge\n.. _ReadTheDocsBadge: https://how-to-opensource.readthedocs.io/en/latest\n\n.. |GitHubActionPublishBadge| image:: https://github.com/simai-ml/how-to-opensource/actions/workflows/publish.yml/badge.svg\n.. _GitHubActionPublishBadge: https://github.com/simai-ml/how-to-opensource/actions\n\n.. |PyPiBadge| image:: https://img.shields.io/pypi/v/QM-How-to-Opensource\n.. _PyPiBadge: https://pypi.org/project/QM-How-to-Opensource/\n\nBBL - Publier un package en open-source en dix \u00e9tapes cl\u00e9s\n==========================================================\n\nQuelles sont les \u00e9tapes indispensables pour publier un package Python en open-source ? Depuis l\u2019\u00e9criture d\u2019un code propre et la r\u00e9daction de la documentation, jusqu\u2019aux tests d\u2019int\u00e9gration continue et au processus de packaging, nous passerons en revue les dix points cl\u00e9s pour une publication d\u2019un package Python en open-source. Pour ce faire, nous prendrons l\u2019exemple d\u2019un toy model que nous publierons sur github et pypi en moins de deux heures.\n\nSommaire\n========\n\nVoici les 10 bonnes pratiques de d\u00e9veloppement open-source d\u00e9taill\u00e9es ci-apr\u00e8s dans ce tutoriel : \n\n1. **Mettre en place un d\u00e9p\u00f4t GitHub,** soit \u00e0 partir de z\u00e9ro, soit en forkant un d\u00e9p\u00f4t existant\n2. **Encapsuler les fonctions dans un module** facile \u00e0 importer et renseignant un num\u00e9ro de version\n3. **Documenter les fonctions avec une dosctring et un doctest.** La docstring sera automatiquement publi\u00e9 en ligne et le doctest automatiquement ex\u00e9cut\u00e9 pendant l'int\u00e9gration continue.\n4. **Ecrire vos fonctions avec d\u00e9claration de types.** C'est une habitude facile \u00e0 prendre qui g\u00e9n\u00e8re automatiquement des tests unitaires statiques avec MyPy_.\n5. **Cr\u00e9er des tests unitaires avec un objectif de couverture de 100%.** La param\u00e9trisation des tests avec ``pytest.xmark.parametrize`` permet de g\u00e9n\u00e9rer des tests tr\u00e8s rapidement.\n6. **Impl\u00e9menter une int\u00e9gration continue du code.** Sur GitHub, le standard est d'utiliser des GitHub Actions. Pensez \u00e0 toujours tester votre code sur Windows.\n7. **G\u00e9n\u00e9rer une documentation semi-automatique avec Sphinx_.** L'API de votre package est automatiquement document\u00e9e si vous avez \u00e9crit les docstrings \u00e0 l'avance. Il ne reste plus qu'\u00e0 r\u00e9diger les parties importantes et les messages \u00e0 faire passer aux utilisateurs. Les exemples sont un bon moyen d'accompagner la mont\u00e9e en comp\u00e9tences rapide des utilisateurs.\n8. **D\u00e9ployer la documentation de mani\u00e8re continue avec ReadTheDocs_.** Le d\u00e9ploiement continu doit se d\u00e9clencher a minima \u00e0 chaque pull request.\n9. **Packager votre module avec le fichier setup.py.** Ce fichier est la pierre angulaire de la publication sur PyPi_. Les num\u00e9ros de version sont plus facile \u00e0 g\u00e9rer avec bump2version_.\n10. **D\u00e9ployer votre package de mani\u00e8re continue avec les release GitHub** et les actions correspondantes. Vous pouvez cacher votre mot de passe PyPi_ par un syst\u00e8me de tokens.\n\nPr\u00e9-requis\n==========\n\n1. Avoir un compte GitHub\n2. Faire un **Fork** du d\u00e9p\u00f4t (bouton en haut \u00e0 droite de GitHub)\n3. Avoir une installation locale de conda\n\nSi vous n'avez pas de conda install\u00e9 : t\u00e9l\u00e9chargez l'installeur Conda_ ou ex\u00e9cutez les commandes suivantes:\n\n.. code:: shell-session\n\n $ wget https://repo.anaconda.com/miniconda/Miniconda3-py39_4.9.2-MacOSX-x86_64.sh -O miniconda.sh\n $ chmod +x miniconda.sh\n $ bash miniconda.sh\n\nAttention \u00e0 bien accepter la demande d'initialisation.\n\nExercice n\u00b01: Mise en place de l'environnement\n==============================================\n\nClonez votre d\u00e9p\u00f4t fork\u00e9.\n\n.. code:: shell-session\n\n $ git clone https://github.com/COMPTE/how-to-opensource.git\n\nInstallez et activez l'EnvConda_ de d\u00e9veloppement, environnement qui nous servira \u00e0 d\u00e9velopper le code, la documentation et les tests:\n\n.. code:: shell-session\n\n cd how-to-opensource\n conda env create -f environment.dev.yml\n conda activate how_to_opensource\n\nCr\u00e9er une branche de travail et supprimez la correction :\n\n.. code:: shell-session\n\n git checkout -b work\n chmod +x start.sh\n ./start.sh\n git add .\n git commit -m \"start exercises\"\n git push origin work\n\nVous pouvez commencer !\n\nExercice n\u00b02: Cr\u00e9ation d'un module et d'une fonction\n====================================================\n\nNous allons maintenant cr\u00e9er dans le Module_ ``how_to_opensource`` une nouvelle fonction calculant la somme de deux vecteurs.\nPour cela cr\u00e9ez le fichier ``how_to_opensource/core.py`` et cr\u00e9ez une nouvelle fonction ``add_two_vectors`` qui va, comme son\nnom l'indique, effectuer une addition de deux vecteurs gr\u00e2ce \u00e0 ``numpy.add``.\n\nAfin de pouvoir importer la fonction, vous devez d\u00e9finir les redirections d'imports dans le fichier ``how_to_opensource/__init__.py``.\n\n.. code:: python\n\n from .core import add_two_vectors\n from ._version import __version__\n __all__ = [\"add_two_vectors\", \"__version__\"]\n\nLa premi\u00e8re ligne de code vous permet de faire directement\n\n.. code:: python\n \n from how_to_opensource import add_two_vectors\n \nau lieu de \n\n.. code:: python\n \n from how_to_opensource.core import add_two_vectors\n\nLa ligne ``__all__ = ...`` permet \u00e0 la fonction d'\u00eatre import\u00e9e avec la syntaxe ``from how_to_opensource import *``.\n\nEnfin, nous anticipons d'ores et d\u00e9j\u00e0 le packaging en introduisant un num\u00e9ro de version dans le fichier ``_version.py`` qui contient une seule ligne de code : ``__version__ = \"0.0.0\"``.\n\nIl est maintenant possible de tester interactivement la m\u00e9thode :\n\n.. code:: python\n\n import numpy as np\n from how_to_opensource import add_two_vectors\n add_two_vectors(np.ones(2), np.ones(2))\n\nou la version du package : \n\n.. code:: python\n\n import how_to_opensource\n print(how_to_opensource.__version__)\n\nSi vous voulez v\u00e9rifier la syntaxe de votre code, vous pouvez ex\u00e9cuter la commande :\n\n.. code:: shell-session\n\n $ flake8 how_to_opensource\n\n**CORRECTION :**\n\n.. code:: shell-session\n\n git checkout master how_to_opensource/__init__.py how_to_opensource/core.py how_to_opensource/_version.py\n\n\nExercice n\u00b03: Typing\n====================\n\nUne pratique courante pour rendre plus robuste un package consiste \u00e0 utiliser le typing pour tout ou une partie du code. \nSi l'interpr\u00e9teur python ne v\u00e9rifie pas ces types \u00e0 l'ex\u00e9cution, le langage python propose n\u00e9anmoins le vocabulaire et la grammaire\nn\u00e9cessaire \u00e0 la d\u00e9finition de ces types par l'interm\u00e9diaire du module Typing_.\nTypez maintenant les d\u00e9finitions de ``add_two_vectors`` et de sa fonction de test. Il est aussi possible d'ajouter un test \u00e0\nl'ex\u00e9cution pour valider que les entr\u00e9es se conforment au type attendu. Enfin lancez l'analyseur statique de code le second statique utilisant MyPy_.\n\n.. code:: shell-session\n\n $ mypy how_to_opensource --strict\n\n**CORRECTION :**\n\n.. code:: shell-session\n\n git checkout master how_to_opensource/core.py mypy.ini\n\n\nExercice n\u00b04: Documentation de la fonction\n==========================================\n\nNumpydoc_ propose une m\u00e9thode de documentation efficace. Ajoutez une documentation \u00e0 ``add_two_vectors`` sp\u00e9cifiant ses param\u00e8tres,\nsa sortie et en y incluant une DocTest_. Lancez ensuite la proc\u00e9dure de test en incluant cette fois le test de la documentation.\n\n.. code:: shell-session\n\n $ pytest -vs --doctest-modules --cov-branch --cov=how_to_opensource --pyargs how_to_opensource\n\n**CORRECTION :** \n\n.. code:: shell-session\n\n git checkout master how_to_opensource/core.py\n\n\nExercice n\u00b05: Cr\u00e9ation d'un test unitaire\n=========================================\n\nIl convient maintenant de tester cette fonction avec PyTest_. Une m\u00e9thode standard pour \u00e9largir rapidement le domaine test\u00e9 est\nd'utiliser Parameterize_ pour param\u00e9triser les fonctions de test.\nDans ``how_to_opensource/tests/test_core.py`` ajoutez une fonction de test validant le bon fonctionnement de ``add_two_vectors``\nen testant diff\u00e9rentes dimensions de vecteurs. Lancez maintenant le test en g\u00e9n\u00e9rant les m\u00e9triques validant que vos tests couvrent bien le code:\n\n.. code:: shell-session\n\n $ pytest -vs --doctest-modules --cov-branch --cov=how_to_opensource --pyargs how_to_opensource\n\n**CORRECTION :** ``git checkout master how_to_opensource/tests/test_core.py``\n\n\nExercice n\u00b06: Int\u00e9gration continue du code\n==========================================\n\nAfin d'assurer un niveau de qualit\u00e9 constant, particuli\u00e8rement dans le cas d'un projet opensource avec de multiples contributeurs, il est\nindispensable d'automatiser le processus d'int\u00e9gration des changements r\u00e9alis\u00e9s. C'est \u00e0 ce point que r\u00e9pond l'int\u00e9gration continue.\nSe basant sur la description d'un pipeline incluant build, test et d\u00e9ploiement, les outils d'integration continue, par exemple\nGitHubActions_ ou TravisCI_ en permettent l'automatisation. Cela apporte les valeurs suivantes:\n\n- minimiser la charge de travail pour les concepteurs\n- supprimer les erreurs arrivant dans toute action \"\u00e0 la main\"\n- r\u00e9duire le temps n\u00e9cessaire \u00e0 la d\u00e9tection et l'analyse de probl\u00e8mes car chaque changement est valid\u00e9 unitairement\n- r\u00e9duire le temps de cycle pour la livraison de nouvelles fonctionnalit\u00e9s tout en en am\u00e9liorant la qualit\u00e9\n\nNous allons utiliser les GitHub actions, pour cela rendez vous sur l'onglet **Actions** de la page GiHub de votre projet.\nPour cr\u00e9er notre workflow d'int\u00e9gration continue nous allons partir du template **Python Package using Anaconda**, disponible apr\u00e8s avoir\ncliqu\u00e9 sur **Setup this workflow**. Cr\u00e9ez le fichier ``test.yml`` dans le dossier ``.github/workflows``, copiez le template propos\u00e9 par GitHub\npuis modifiez ensuite les \u00e9tapes du workflow pour coller aux \u00e9l\u00e9ments d\u00e9finis pr\u00e9c\u00e9demment:\n\n- d\u00e9ploiement sur Python 3.9 , Python 3.8, Ubuntu et Windows\n- installation de flake8, mypy, numpy, et pytest-cov\n- tester le linting, le typing et les tests unitaires\n\nUne fois le fichier cr\u00e9\u00e9 pouss\u00e9 sur le d\u00e9p\u00f4t, vous pouvez suivre l'execution du pipeline depuis l'interface de GitHub.\nUn mail vous sera automatiquement envoy\u00e9 en fin d'execution pour vous informer des r\u00e9sultats.\n\n**CORRECTION :** ``git checkout master .github/workflows/test.yml``\n\n\nExercice n\u00b07: G\u00e9n\u00e9ration de la documentation\n============================================\n\nAvoir une documentation \u00e0 jour est indispensable autant pour les utilisateurs que pour les contributeurs.\nAfin de faciliter la cr\u00e9ation et la maintenance de celle-ci nous allons utiliser Sphinx_. Le quick start de Sphinx permet l'initialisation rapide des \u00e9l\u00e9ments n\u00e9cessaires.\n\n.. code:: shell-session\n\n $ sphinx-quickstart doc\n\nNote: il n'est pas n\u00e9cessaire de s\u00e9parer les r\u00e9pertoires sources et build dans notre cas simple.\n\nPour g\u00e9n\u00e9rer la documentation il vous suffit maintenant d'ex\u00e9cuter le script nouvellement cr\u00e9\u00e9:\n\n.. code:: shell-session\n\n $ cd doc\n $ make html\n\nLa documentation a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9e dans le repertoire ``doc/_build``, vous pouvez la consulter dans votre navigateur web, elle est belle, mais vide.\nEn plus de la r\u00e9daction que vous ne manquerez pas d'ajouter, il est important de capitaliser sur la documentation \u00e9crite \u00e0 l'exercice n\u00b04.\nPour ce faire, il faut d'abord modifier le fichier **doc/conf.py** pour ajouter ``'sphinx.ext.autodoc'``, ``'sphinx.ext.napoleon'``, et ``'sphinx_autodoc_typehints'``\n\u00e0 la liste des extensions. \nIl faut \u00e9galement d\u00e9finir la version du package:\n\n.. code:: python \n\n release = 0.0.0\n\nEnfin, il faut ajouter la documentation automatique du module dans ``doc/index.rst`` qui sera par ailleurs le point d'entr\u00e9e de toute r\u00e9daction additionnelle:\n\n.. code::\n\n .. automodule:: how_to_opensource\n :members:\n\nAfin de permettre de trouver le module et d'activer la prise en compte des types, ajoutez les lignes suivantes au fichier ``doc/conf.py``:\n\n.. code:: python\n\n import sys\n sys.path.append('../')\n napoleon_use_param = True\n\nUne m\u00e9thode efficace pour enrichir la documentation consiste \u00e0 ajouter des exemples que l'on met en valeur \u00e0 l'aide de SphinxGallery_.\nDans ``doc/conf.py``, ajoutez l'extension ``'sphinx_gallery.gen_gallery'``, puis d\u00e9finissez la configuration de la galerie:\n\n.. code:: python\n\n sphinx_gallery_conf = {\n 'examples_dirs': '../examples', # path to your example scripts\n 'gallery_dirs': 'auto_examples', # path to where to save gallery generated output\n }\n\nEnfin il est n\u00e9cessaire d'inclure cette galerie \u00e0 la racine de la documentation, dans ``doc/index.rst`` ajoutez son inclusion:\n\n.. code::\n\n .. toctree::\n :maxdepth: 2\n\n auto_examples/index\n\nPour cr\u00e9er un exemple qui s'affichera dans la doc, vous devez simplement cr\u00e9er un script python dans le r\u00e9pertoire ``examples``. Par exemple :\n\n.. code:: python\n\n \"\"\"\n ===========\n Toy Example\n ===========\n L'exemple le plus simple que l'on puisse imaginer.\n \"\"\"\n\n from how_to_opensource import add_two_vectors\n add_two_vectors([12.5, 26.1], [7.5, 3.9])\n\nLe dossier ``examples`` tout juste cr\u00e9\u00e9 doit s'accompagner d'un fichier ``README.rst`` avec un titre comme:\n\n.. code::\n\n Exemples avanc\u00e9s\n ================\n\nVous pouvez alors reconstruire la doc avec `make html` et v\u00e9rifier que votre documentation est belle !\n\n.. code:: shell-session\n\n open doc/_build/html/index.html\n\n**CORRECTION :** ``git checkout master doc examples``\n\n\nExercice n\u00b08: D\u00e9ploiement continu de la documentation\n=====================================================\n\nPour diffuser cette documentation il est n\u00e9cessaire de la publier sur un site publique, par exemple en utilisant ReadTheDocs_.\nCe dernier r\u00e9alisera les t\u00e2ches d\u00e9finies dans le fichier ``.readthedocs.yml``, ajoutez donc ce fichier au d\u00e9p\u00f4t avec le contenu suivant:\n\n.. code::\n\n version: 2\n\n build:\n image: latest\n\n conda:\n environment: environment.dev.yml\n \n sphinx:\n builder: html\n configuration: doc/conf.py\n fail_on_warning: false\n\nEnsuite, cr\u00e9ez un compte gratuit sur ReadTheDocs_ en utilisant votre login GitHub.\n\nUne fois inscrit et connect\u00e9, importez votre projet GitHub (attention \u00e0 ajouter votre trigramme \u00e0 l'url du projet par souci d'unicit\u00e9).\n\nApr\u00e8s avoir soigneusement choisi la branche et la version, lancez la compilation. Suivez son bon d\u00e9roulement et v\u00e9rifiez que la documentation produite est conforme \u00e0 vos attentes.\n\nPour automatiser la compilation de la doc \u00e0 chaque pull request, allez ensuite dans Admin > Param\u00e8tres avanc\u00e9s et cochez la case \"Build pull requests for this project\". \nIl faut \u00e9galement connecter vos comptes GitHub et ReadTheDocs par un webhook comme suit :\n\n1. sur votre compte ReadTheDocs, allez dans Admin > Integrations > Add integration > GitHub incoming webhook\n2. sur votre repo GitHub, allez dans Settings > Webhooks > Add webhook > copier l'URL \"payload URL\" de readthedocs.\n\nEt voil\u00e0 ! Votre documentation se reconstruit automatiquement \u00e0 chaque pull request !\n\n**CORRECTION :** ``git checkout master .readthedocs.yml``\n\n\nExercice n\u00b09: Packaging\n=======================\n\nDe fa\u00e7on \u00e0 offrir une API claire \u00e0 l'ensemble des modules de notre projet (certes il n'y en a qu'un en l'\u00e9tat mais cela est vou\u00e9 \u00e0 changer),\nil est utile de cr\u00e9er un package_ qui permet d'avoir un espace de nommage encapsulant les modules et variables, et diffusable directement sur PyPi_.\nPour cela, il est n\u00e9cessaire d'ajouter un fichier ``setup.py`` \u00e0 notre projet, et de le d\u00e9finir, vous pouvez pour cela partir de ce tutoriel_.\n\nVoici un exemple de fichier ``setup.py``, ce sont essentiellement des descripteurs qui s'afficheront tels quels sur PyPi_.\n\n**IMPORTANT :** chaque package doit avoir un nom unique sur PyPi_, qui est d\u00e9duit du param\u00e8tre ``name``. Pensez-bien \u00e0 ajouter votre trigramme dans le ``name`` pour que chacun puisse publier son package sans conflit de noms.\n\n.. code:: python\n\n import os\n from setuptools import setup\n\n\n def read(fname):\n return open(os.path.join(os.path.dirname(__file__), fname)).read()\n\n\n setup(\n name=\"QM How to Opensource by TRIGRAMME\",\n version=\"0.0.1\",\n author=\"Gr\u00e9goire Martignon, Vianney Taquet, Damien Hervault\",\n author_email=\"gmartignon@quantmetry.com\",\n description=\"A Quantmetry tutorial on how to publish an opensource python package.\",\n license=\"BSD\",\n keywords=\"example opensource tutorial\",\n url=\"http://packages.python.org/how_to_opensource\",\n packages=['how_to_opensource'],\n install_requires=[\"numpy>=1.20\"],\n extras_require={\n \"tests\": [\"flake8\", \"mypy\", \"pytest-cov\"],\n \"docs\": [\"sphinx\", \"sphinx-gallery\", \"sphinx_rtd_theme\", \"numpydoc\"]\n },\n long_description=read('README.rst'),\n classifiers=[\n \"License :: OSI Approved :: BSD License\",\n \"Programming Language :: Python :: 3.9\"\n ],\n )\n\nIl ne vous reste plus qu'\u00e0 construire votre package\n\n.. code:: shell-session\n\n $ python setup.py sdist bdist_wheel\n\nCela cr\u00e9e trois r\u00e9pertoires : ``dist``, ``build`` et ``QM_How_to_Opensource.egg-info``.\n\nLe ``egg-info`` est une simple collection de fichiers texte purement informatifs, et le ``dist`` est le contenu de ce qui sera h\u00e9berg\u00e9 sur PyPi_.\n\nSi vous voulez v\u00e9rifier que votre `README.rst` est sans erreur, vous pouvez ex\u00e9cuter la commande \n\n.. code:: shell-session\n\n $ twine check dist/*\n\n**N.B.** Cette commande v\u00e9rifie le contenu du r\u00e9pertoire ``dist``. En cons\u00e9quence, si vous modifiez le ``README.rst``, il faut ex\u00e9cuter \u00e0 nouveau la commande ``python setup.py sdist`` pour faire un nouveau check.\n\nDernier \u00e9l\u00e9ment d'un package open-source: la license. Elles sont toutes disponibles sur OpenSourceInitiative_, il suffit de la copier-coller dans le fichier `LICENSE` et de remplacer les noms des auteurs et la date !\n\nPour un projet open-source enti\u00e8rement libre, la license new BSD-3 est courante en machine learning..\n\nNotre package est maintenant en place, pr\u00eat \u00e0 \u00eatre publi\u00e9 et ouvert \u00e0 sa communaut\u00e9 d'utilisateurs et de contributeurs. Il est n\u00e9cessaire de donner \u00e0 ses deux populations les outils dont ils ont besoin.\nUne accessibilit\u00e9 simple et ma\u00eetris\u00e9e pour les premiers, de clart\u00e9 sur les r\u00e8gles de leur engagement pour les seconds.\n\nDans la mesure o\u00f9 ce nom de version va se retrouver \u00e0 plusieurs endroits (``setup.py``, ``doc/conf.py``, ...), et pour ne pas risquer d'erreurs dans le maintien en coh\u00e9rence de cette information \u00e0 plusieurs endroits, il est possible d'utiliser bump2version_. Pour cela cr\u00e9ez un fichier ``.bumpversion.cfg`` \u00e0 la racine du projet, ce dernier va d\u00e9finir dans quel fichier remplacer automatiquement le num\u00e9ro de version. Ajoutez-y le contenu ci-dessous et assurez vous que tous les fichiers contiennent initialement les m\u00eames num\u00e9ros de version, par la suite ils seront mis \u00e0 jour automatiquement :\n\n.. code::\n\n [bumpversion]\n current_version = 0.0.0\n commit = True\n tag = True\n\n [bumpversion:file:setup.py]\n search = version=\"{current_version}\"\n replace = version=\"{new_version}\"\n\n [bumpversion:file:how_to_opensource/_version.py]\n search = __version__ = \"{current_version}\"\n replace = __version__ = \"{new_version}\"\n\n [bumpversion:file:doc/conf.py]\n search = release = \"{current_version}\"\n replace = release = \"{new_version}\"\n\nVous pouvez d\u00e9sormais incr\u00e9menter le num\u00e9ro de version avec ``bumpversion``.\nTrois choix sont possibles pour l'incr\u00e9mentation du num\u00e9ro de version: patch, minor, et major. Nous choisissons ici d'incr\u00e9menter le \"patch\":\n\n.. code:: shell-session\n\n $ bumpversion patch\n $ git push --tags\n\nVotre publication sur PyPi_ se fait simplement avec la commande :\n\n.. code:: shell-session\n\n $ twine upload dist/*\n\nAttention, cette commande n\u00e9cessite un identifiant et un mot de passe, il faut donc vous cr\u00e9er un compte au pr\u00e9alable sur PyPi_.\n\n**CORRECTION :** ``git checkout master setup.py LICENSE .bumpversion.cfg``\n\nExercice n\u00b010: d\u00e9ploiement continu\n==================================\n\nMaintenant nous allons mettre en place la publication automatique sur PyPi_ apr\u00e8s chaque release officielle de votre package. \nLe but est de d\u00e9clencher automatiquement, \u00e0 la publication d'une nouvelle release depuis GitHub, la publication de la nouvelle version du package vers PyPi.\nCela signifie donc que le workflow GitHub devra se connecter \u00e0 votre compte PyPi_. \nPour ne pas avoir \u00e0 mettre en clair les \u00e9l\u00e9ments n\u00e9cessaires \u00e0 cette authentification dans votre d\u00e9p\u00f4t, il existe un m\u00e9canisme permettant de se connecter \u00e0\nPyPi sur base d'un token, et de stocker ce token en tant qu'\u00e9l\u00e9ment secret dans le d\u00e9p\u00f4t GitHub.\nPour cela, une fois connect\u00e9 sur PyPi:\n\n- Rendez-vous sur la page *Account Settings* et descendez jusqu'\u00e0 la section *API Tokens*. \n\n- Cliquez sur *Add Token*, donnez lui un nom, par exemple *how-to-opensource* et donnez lui acc\u00e8s au scope complet. \n\n- Copiez le token g\u00e9n\u00e9r\u00e9 et gardez cette page ouverte au cas o\u00f9.\n\n- Dans une autre fen\u00eatre, rendez vous sur votre d\u00e9p\u00f4t GitHub \u00e0 la page *Settings*, section *Secrets*.\n\nAppelez le PYPI_API_TOKEN et collez dans le champ *Value* le token copi\u00e9 depuis PyPi_.\n\nNous pouvons maintenant mettre en place le workflow de publication automatique, pour cela:\n\n- Rendez vous dans l'onglet *Actions* du projet GitHub et cliquez sur *New workflow*.\n\n- Choisissez le template *Publish Python Package*, renommez le fichier ``publish.yml``, sp\u00e9cifiez la version 3.9 de python et confirmez l'ajout du workflow.\n\nPour d\u00e9clencher le workflow, allez sur la page principale du d\u00e9p\u00f4t GitHub, \u00e0 droite, cliquez sur Releases. Vous devriez voir tous les tags pouss\u00e9s jusqu'\u00e0 pr\u00e9sent. Choisissez le dernier et cliquez sur \"Edit tag\". Pensez \u00e0 bien pointer sur la branche ``work``. Cliquez ensuite sur \"Publish release\". L'action de publication s'est normalement d\u00e9clench\u00e9e dans l'onglet GitHub Actions. Une fois termin\u00e9e, vous pouvez v\u00e9rifier que la mise \u00e0 jour sur PyPi_ s'est bien d\u00e9roul\u00e9e.\n\nEnfin il convient d'ajouter de documenter les r\u00e8gles de contribution et d'usage du package. Pour cela rendez vous dans la page **Insights/Community** de GitHub. Cette derni\u00e8re fournit un moyen simple d'initier les documents n\u00e9cessaires.\n\nVous pouvez \u00e9galement naviguer dans l'onglet Insights > Community de github et remplir votre projet avec des template d'issue, pull request ou codes de conduite.\n\n**IMPORTANT :** Vous avez d\u00e9j\u00e0 publi\u00e9 une version de votre package \u00e0 l'\u00e9tape pr\u00e9c\u00e9dente. Pour republier une nouvelle version, vous \u00eatre oblig\u00e9 de \"bumper\" la version \u00e0 nouveau :\n\n.. code:: shell-session\n\n $ bumpversion patch\n $ git push --tags\n\n**CORRECTION :** ``git checkout master .github/workflows/publish.yml``\n\nR\u00e9capitulatif\n=============\n\nVoici les 10 bonnes pratiques de d\u00e9veloppement open-source: \n\n1. **Mettre en place un d\u00e9p\u00f4t GitHub,** soit \u00e0 partir de z\u00e9ro, soit en forkant un d\u00e9p\u00f4t existant\n2. **Encapsuler les fonctions dans un module** facile \u00e0 importer et renseignant un num\u00e9ro de version\n3. **Documenter les fonctions avec une dosctring et un doctest.** La docstring sera automatiquement publi\u00e9 en ligne et le doctest automatiquement ex\u00e9cut\u00e9 pendant l'int\u00e9gration continue.\n4. **Ecrire vos fonctions avec d\u00e9claration de types.** C'est une habitude facile \u00e0 prendre qui g\u00e9n\u00e8re automatiquement des tests unitaires statiques avec MyPy_.\n5. **Cr\u00e9er des tests unitaires avec un objectif de couverture de 100%.** La param\u00e9trisation des tests avec ``pytest.xmark.parametrize`` permet de g\u00e9n\u00e9rer des tests tr\u00e8s rapidement.\n6. **Impl\u00e9menter une int\u00e9gration continue du code.** Sur GitHub, le standard est d'utiliser des GitHub Actions. Pensez \u00e0 toujours tester votre code sur Windows.\n7. **G\u00e9n\u00e9rer une documentation semi-automatique avec Sphinx_.** L'API de votre package est automatiquement document\u00e9e si vous avez \u00e9crit les docstrings \u00e0 l'avance. Plus qu'\u00e0 r\u00e9diger les parties importantes et les messages \u00e0 faire passer aux utilisateurs. Les exemples sont un bon moyen d'accompagner la mont\u00e9e en comp\u00e9tences rapide des utilisateurs.\n8. **D\u00e9ployer la documentation de mani\u00e8re continue avec ReadTheDocs_.** Le d\u00e9ploiement continu doit se d\u00e9clencher a minima \u00e0 chaque pull request.\n9. **Packager votre module avec le fichier setup.py.** Ce fichier est la pierre angulaire de la publication sur PyPi_. Les num\u00e9ros de version sont plus facile \u00e0 g\u00e9rer avec bump2version_.\n10. **D\u00e9ployer votre package de mani\u00e8re continue avec les release GitHub** et les actions correspondantes. Vous pouvez cacher votre mot de passe PyPi_ par un syst\u00e8me de tokens.\n\nBONUS: Gestion du d\u00e9p\u00f4t sur le long terme\n=========================================\n\nQuelques bonnes pratiques de gestion du d\u00e9p\u00f4t sur le long terme :\n\n* Tout probl\u00e8me ou am\u00e9lioration du code doit faire l'objet d'une issue avant une pull request. Les pull request doivent \u00eatre reli\u00e9es aux issues qu'elles r\u00e9solvent.\n* Tout incr\u00e9ment de code doit passer par des pull request revue par une personne tierce\n* L'onglet GitHub Projects vous permets d'organiser les issues sous formes de cartes simili-Trello, et rend publique votre feuille de route de d\u00e9veloppement.\n* Il est recommand\u00e9 d'ajouter deux fichiers de documentation \u00e0 votre repo : un ``CONTRIBUTING.md`` qui renseigne les contributeurs \u00e9ventuels sur l'art et la mani\u00e8re de faire des pull request pour ce projet, et un ``RELEASE_CHECKLIST.md`` r\u00e9capitulant toutes les \u00e9tapes de v\u00e9rification avant publication sur PyPi_. Vous trouverez un exemple sur MAPIE_.\n\nBonus: Badges\n=============\n\nNotre int\u00e9gration continue est maintenant en place. Afin de donner une vue de synth\u00e8se de son execution et de donner confiance aux utilisateurs potentiels quand \u00e0 la qualit\u00e9 du package, il est possible d'ajouter des badges qui donneront un status \u00e0 jour de l'execution de l'int\u00e9gration continue.\nIl faut pour cela, ajoutez dans le README situ\u00e9 \u00e0 la racine du d\u00e9p\u00f4t les liens suivants:\n\n.. code::\n\n |GitHubActionTestBadge|_ |ReadTheDocsBadge|_ |GitHubActionPublishBadge|_ |PyPiBadge|_\n\n .. |GitHubActionTestBadge| image:: https://github.com/simai-ml/how-to-opensource/actions/workflows/test.yml/badge.svg\n .. _GitHubActionTestBadge: https://github.com/simai-ml/how-to-opensource/actions\n \n .. |ReadTheDocsBadge| image:: https://readthedocs.org/projects/how-to-opensource/badge\n .. _ReadTheDocsBadge: https://how-to-opensource.readthedocs.io/en/latest\n \n .. |GitHubActionPublishBadge| image:: https://github.com/simai-ml/how-to-opensource/actions/workflows/publish.yml/badge.svg\n .. _GitHubActionPublishBadge: https://github.com/simai-ml/how-to-opensource/actions\n \n .. |PyPiBadge| image:: https://img.shields.io/pypi/v/QM-How-to-Opensource\n .. _PyPiBadge: https://pypi.org/project/QM-How-to-Opensource/\n \n.. _Conda: https://docs.conda.io/en/latest/miniconda.html\n.. _EnvConda: https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html\n.. _Module: https://docs.python.org/3/tutorial/modules.html\n.. _PyTest: https://docs.pytest.org/en/6.2.x/\n.. _Parameterize: https://docs.pytest.org/en/6.2.x/parametrize.html\n.. _Numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html\n.. _DocTest: https://docs.python.org/3/library/doctest.html\n.. _Typing: https://docs.python.org/3/library/typing.html\n.. _TravisCI: https://travis-ci.com/\n.. _MyPy: http://mypy-lang.org/\n.. _Sphinx: https://www.sphinx-doc.org/en/master/index.html\n.. _ReadTheDocs: https://readthedocs.org/\n.. _SphinxGallery: https://sphinx-gallery.github.io/stable/getting_started.html\n.. _GitHubActions: https://github.com/features/actions\n.. _package: https://docs.python.org/3/tutorial/modules.html#packages\n.. _tutoriel: https://packaging.python.org/guides/distributing-packages-using-setuptools/\n.. _OpenSourceInitiative: https://opensource.org/licenses/BSD-3-Clause\n.. _bump2version: https://github.com/c4urself/bump2version\n.. _PyPi: https://pypi.org/account/register/\n.. _MAPIE: https://github.com/simai-ml/MAPIE\n",
"bugtrack_url": null,
"license": "BSD",
"summary": "A Quantmetry tutorial on how to publish an opensource python package.",
"version": "0.0.0",
"project_urls": {
"Homepage": "http://packages.python.org/how_to_opensource"
},
"split_keywords": [
"example",
"opensource",
"tutorial"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "71618f2da19d58b96e3e4f571668d280aa868e6656a5e73c3f83b51a1ddf960d",
"md5": "29844e2a70428129b8c70036abb1c59b",
"sha256": "8600a928843f2726d08a1b1fa05af40e6a07f0e7bf8e53582da5009e96b3756d"
},
"downloads": -1,
"filename": "QM_How_to_Opensource_CHP-0.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "29844e2a70428129b8c70036abb1c59b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 12422,
"upload_time": "2023-10-11T12:46:37",
"upload_time_iso_8601": "2023-10-11T12:46:37.972699Z",
"url": "https://files.pythonhosted.org/packages/71/61/8f2da19d58b96e3e4f571668d280aa868e6656a5e73c3f83b51a1ddf960d/QM_How_to_Opensource_CHP-0.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-10-11 12:46:37",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "qm-how-to-opensource-chp"
}