La raison pour laquelle j'écris cet article est de partager quelques idées sur la façon de garder un projet propre, même avec de nombreux contributeurs. Ceci est particulièrement important pour les ingénieurs de données, étant donné la nature en constante évolution des données et les demandes de traitement dans les bibliothèques et applications Python.
Le titre peut paraître un peu clickbaity, mais si vous suivez ces étapes, votre code Python deviendra beaucoup plus facile à gérer. Si vous êtes un développeur senior, vous ne trouverez probablement rien de nouveau ici. Ne vous inquiétez pas, j'ai un mème amusant pour vous.
Cela peut sembler trivial, mais j'ai connu des personnes qui stockaient leur code uniquement sur leur ordinateur local – et qui l'ont malheureusement perdu parce qu'elles ne l'avaient sauvegardé nulle part ailleurs. Il existe plusieurs systèmes de contrôle de version, comme Git, qui fonctionne avec des plateformes telles que GitHub, GitLab et Bitbucket. Bien que Git soit le choix incontournable pour beaucoup, d'autres systèmes de contrôle de version comme SVN (Subversion) et Mercurial jouent toujours un rôle important dans la gestion du code.
Pour ce guide, je souhaite créer une petite bibliothèque de démonstration Python avec une seule fonction pour illustrer la gestion des données de base. Il ne s'agit pas d'une boîte à outils complète, mais sert d'exemple simple pour démontrer les meilleures pratiques telles que la qualité du code, la gestion de l'environnement et les flux de travail CI/CD.
Pour commencer, j'ai créé un référentiel pour notre bibliothèque de démonstration Python, l'appelant blog_de_toolkit. Il est public, alors n'hésitez pas à le créer et à utiliser le code existant comme point de départ pour vos propres projets. Puisqu’une bonne documentation est essentielle, j’ai inclus une suggestion de fichier README vide. Et pour garder le dépôt bien rangé, j'ai ajouté un modèle Python .gitignore par défaut pour empêcher le téléchargement de fichiers inutiles.
Maintenant que nous avons le dépôt, nous pouvons le cloner.
Je ne vais pas plonger ici dans les commandes Git – vous pouvez trouver de nombreux tutoriels en ligne. Si vous n'aimez pas utiliser la CLI du terminal simple, vous pouvez également gérer des référentiels avec des outils tels que GitHub Desktop ou SourceTree, qui fournissent une interface plus visuelle et intuitive.
Personnellement, j'aime vraiment utiliser GitHub Desktop. Alors, clonons notre dépôt sur l'ordinateur local et ouvrons-le dans votre IDE préféré.
Voyons ce que nous avons jusqu'à présent :
Pas mal pour un début !
Pour l'étape 2, nous organiserons notre projet de_toolkit. Une bonne structure permet de trouver facilement les choses et de garder tout bien rangé. Nous allons créer des dossiers pour notre code, nos tests et notre documentation, en mettant en place un cadre simple et propre sur lequel s'appuyer.
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
Nous avons un dossier principal pour tout le code utile que nous allons ajouter, un dossier tests pour nos futurs tests unitaires et un .gitignore pour garder les fichiers inutiles hors de notre référentiel. Il existe également un fichier setup.py, qui est une configuration de base pour rendre le projet installable. Je n'entrerai pas dans les détails maintenant puisque nous y reviendrons plus tard dans l'Étape 8 : Créer un package de distribution.
Lors de la mise en place de la structure de votre projet, garder les choses cohérentes fait une énorme différence. Au fur et à mesure que votre projet se développe, c'est une bonne idée de diviser les éléments en modules plus petits, comme diviser data_tools.py en csv_tools.py et json_tools.py. De cette façon, il est plus facile de gérer et de trouver ce dont vous avez besoin sans fouiller dans de longs fichiers.
Ajouter un dossier docs/ est également une démarche judicieuse, même si cela ne commence que par quelques notes. Cela vous aidera (ainsi que les autres) à suivre le fonctionnement des choses à mesure que le projet évolue. Si vous travaillez avec des configurations telles que YAML ou JSON, un dossier configs/ peut vous aider à garder les choses en ordre. Et si vous envisagez d'écrire des scripts pour l'automatisation ou les tests, un dossier scripts/ les gardera organisés.
À ce stade, nous devons installer quelques bibliothèques supplémentaires pour continuer à développer le projet.
Bien sûr, nous pourrions simplement exécuter pip install à partir de la ligne de commande pour installer les dépendances dont nous avons besoin. Mais que se passe-t-il si nous jonglons avec plusieurs projets, chacun nécessitant des versions différentes de Python et des bibliothèques ? C'est là qu'interviennent les environnements virtuels : ils isolent les dépendances de chaque projet, y compris les versions spécifiques de Python, afin que tout reste autonome et indépendant.
Heureusement, il existe de nombreux outils pour créer des environnements virtuels, vous pouvez donc choisir ce qui vous convient le mieux :
virtualenv
venv
conda
pyenv
pipenv
poésie
Personnellement, je suis un grand fan de pyenv, c'est donc ce que je vais utiliser ici. Je l'ai déjà installé sur mon ordinateur portable car c'est mon outil de prédilection pour le travail et les projets personnels.
Commençons par installer Python :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
Si pyenv ne reconnaît pas cette version de Python, essayez d'abord de la mettre à jour. Par exemple, si vous êtes sur Mac et que vous avez installé pyenv avec Homebrew, exécutez :
pyenv install 3.12.2
Si vous rencontrez l'erreur ModuleNotFoundError : Aucun module nommé '_lzma', essayez :
brew update && brew upgrade pyenv
Ensuite, dans notre dossier de projet, créons un nouvel environnement virtuel :
brew install readline xz
Maintenant, définissez la version locale de Python sur l'environnement virtuel que vous venez de créer :
pyenv virtualenv 3.12.2 de_toolkit
Si l’environnement ne change pas après avoir exécuté la commande sur MacOS, il existe un fil de discussion utile en ligne proposant une solution. Une fois que tout est correctement configuré, vous devriez voir de_toolkit au début de votre ligne de commande, comme ceci :
Maintenant, installons nos dépendances :
pyenv local de_toolkit
Ensuite, nous enregistrerons tous les packages installés, ainsi que leurs versions, dans un fichier exigences.txt. Cela permet de partager facilement les dépendances du projet ou de recréer le même environnement ailleurs :
pip install setuptools wheel twine pandas
Voici la liste des packages installés que nous avons :
Bien entendu, vous pouvez éditer le fichier exigences.txt pour ne conserver que les bibliothèques principales et leurs versions, si vous préférez.
Cette étape est cruciale – probablement l’une des plus importantes. Vous avez probablement entendu des histoires d’horreur sur des informations d’identification exposées dans les référentiels GitHub ou sur des jetons sensibles partagés accidentellement en public. Pour éviter cela, il est essentiel de garder les informations sensibles hors de votre code dès le départ. Sinon, il est facile d'oublier que vous avez codé en dur un mot de passe de base de données, d'appliquer vos modifications et boum : vos informations d'identification sont désormais publiques.
Le codage en dur des mots de passe, des clés API ou des informations d'identification de base de données constitue un risque de sécurité majeur. Si ceux-ci deviennent un dépôt public, ils pourraient compromettre l’ensemble de votre système. Le moyen le plus sûr de gérer les secrets est de les stocker dans des variables d'environnement ou dans un fichier .env. Pour vous aider à charger ces variables dans votre projet Python, nous utiliserons la bibliothèque python-dotenv. Il lit les paires clé-valeur à partir d'un fichier .env et les rend disponibles en tant que variables d'environnement dans votre code.
Tout d'abord, installez la bibliothèque avec :
pip freeze > requirements.txt
Créez un fichier .env dans votre dossier de projet avec le contenu suivant :
pip install python-dotenv
Maintenant, modifions data_tools.py pour charger ces secrets en utilisant python-dotenv :
Lorsque vous appelez load_dotenv(), il recherche un fichier .env dans le répertoire courant et charge son contenu dans l'environnement. L'utilisation de os.getenv() vous permet d'accéder à ces variables en toute sécurité dans votre code, en gardant les informations d'identification isolées du code source et en réduisant le risque d'exposition accidentelle.
Un conseil clé est d'éviter de soumettre votre fichier .env au contrôle de version. Ajoutez-le à .gitignore pour éviter qu'il ne soit accidentellement poussé :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
Si vous utilisez VSCode, il existe une extension dotenv utile qui reconnaît automatiquement vos fichiers .env *. Et si vous préférez travailler depuis le terminal, vous pouvez exporter le fichier *.env comme ceci :
pyenv install 3.12.2
Lorsque vous travaillez sur votre projet, essayez d'écrire de petites fonctions réutilisables, faciles à comprendre et à gérer. Une bonne règle de base est la suivante : « Si vous l'utilisez plus de deux fois, transformez-le en fonction. »
Dans notre data_tools.py, créons une fonction qui démontre la logique typique de l'ingénierie des données, comme charger des données à partir d'un CSV et les nettoyer :
Conseil de pro : respectez snake_case
pour les noms de fonctions et de variables en Python : cela permet de garder votre code cohérent et facile à lire. Évitez les noms énigmatiques comme x ou df2 ; des noms clairs et descriptifs facilitent l'utilisation de votre code.Nous utilisons ici des docstrings pour décrire ce que fait la fonction, ses paramètres et le type de retour. Cela permet aux autres développeurs (et à vous-même) de comprendre facilement comment utiliser la fonction. Il existe plusieurs conventions de docstring populaires, mais les plus courantes incluent PEP 257, Google Style et NumPy Style :
Pour les petites fonctions, PEP 257 suffit souvent, mais pour les projets plus complexes, les styles Google ou NumPy offrent plus de clarté et de structure.
Tapez des astuces en Python, comme file_path: str dans notre exemple, affichez les types de données attendus pour les entrées et sorties de fonction. Ils améliorent la lisibilité, aident à détecter les bugs et facilitent la collaboration en définissant des attentes claires.
Voici un exemple de la façon dont les astuces de type améliorent la signature de fonction :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
Dans cet exemple, le type soupçon file_path: str montre que l'argument doit être une chaîne, tandis que -> pd.DataFrame indique que la fonction renvoie un Pandas DataFrame. Cela rend le comportement de la fonction facile à comprendre en un coup d’œil. Les indices de type fonctionnent également bien avec les IDE et les linters, comme PyCharm, VSCode ou mypy, offrant une saisie semi-automatique et des avertissements précoces si des types incompatibles sont transmis.
Si une fonction peut renvoyer plusieurs types ou Aucun, vous pouvez utiliser Facultatif depuis le module de saisie :
pyenv install 3.12.2
Cela indique que la fonction peut renvoyer soit une chaîne, soit Aucun. Pour des structures de données plus complexes, vous pouvez utiliser List, Dict ou Tuple à partir du module de saisie pour spécifier les types attendus.
Écrire des tests unitaires est un moyen simple de vous assurer que votre code fait ce qu'il est censé faire, sans surprises inattendues. Ils vous aident à détecter rapidement les bogues et à apporter des modifications en toute confiance, sachant que tout fonctionne toujours comme prévu. En Python, il existe plusieurs bibliothèques disponibles pour les tests unitaires, chacune avec ses atouts et son écosystème :
test unitaire
pytest
nez2
hypothèse
Pour ce guide, nous utiliserons pytest car il est simple, flexible et facile à utiliser. Vous pouvez l'installer avec :
brew update && brew upgrade pyenv
Ensuite, créez un fichier nommé test_data_tools.py dans le dossier tests/. Écrivons quelques tests pour le code que nous avons implémenté précédemment. Voici un exemple de test pour notre fonction load_and_clean_data() et notre logique de récupération de variables d'environnement :
Dans test_load_and_clean_data(), nous utilisons StringIO pour simuler un fichier CSV en entrée. Cela nous permet de tester sans avoir besoin d'un fichier réel. Le test vérifie que la fonction supprime correctement les doublons et les valeurs NaN, vérifie que le DataFrame ne contient aucune donnée manquante et confirme que les entrées uniques dans la colonne « nom » sont correctes.
Dans test_get_database_url() et test_get_api_key(), nous utilisons monkeypatch, un utilitaire fourni par pytest, pour définir temporairement des variables d'environnement pendant le test. Cela garantit que les fonctions renvoient les valeurs attendues sans avoir besoin de variables d'environnement réelles.
Pour exécuter tous les tests, exécutez simplement la commande suivante :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
L'une des raisons pour lesquelles j'aime pytest est sa flexibilité. Il va au-delà des tests unitaires de base en offrant des fonctionnalités puissantes telles que des appareils, des tests paramétrés et des plugins. Les appareils vous permettent de configurer des données de test ou des configurations que plusieurs tests peuvent réutiliser, ce qui garde votre code SEC (Ne vous répétez pas). Les tests paramétrés vous permettent d'exécuter le même test avec différentes entrées, ce qui permet de gagner du temps et de réduire la duplication. Et si vous avez besoin d'étendre les fonctionnalités de pytest, il existe un large écosystème de plugins pour des choses comme tester les applications Django, mesurer la couverture de code ou se moquer des requêtes HTTP.
Le maintien d'une qualité élevée du code garantit que votre code est facile à lire, à maintenir et exempt de bogues courants. Plusieurs outils peuvent aider à appliquer des normes de codage cohérentes, à formater automatiquement le code et à détecter rapidement les problèmes potentiels. Certaines options populaires incluent pylint, flake8, noir et détecter les secrets.
pylint applique les normes de codage et détecte les erreurs courantes.
flake8 combine des outils pour détecter les violations de style et les erreurs logiques.
black est un formateur avisé qui garantit que votre code respecte les normes PEP8.
detect-secrets analyse votre code pour empêcher que les secrets codés en dur ne soient exposés.
Vous pouvez installer ces outils avec :
pyenv install 3.12.2
Par exemple, exécutez pylint sur un fichier ou un répertoire spécifique :
brew update && brew upgrade pyenv
Vous recevrez un rapport avec des avertissements et des suggestions pour améliorer votre code. Pour ignorer des avertissements spécifiques, vous pouvez utiliser :
brew install readline xz
Vous pouvez également utiliser flake8 pour rechercher des problèmes de style et des erreurs logiques :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
Pour formater automatiquement votre code, exécutez black :
pyenv install 3.12.2
Au lieu d'exécuter ces outils manuellement à chaque fois que vous apportez des modifications, vous pouvez automatiser le processus avec des hooks de pré-validation. Les hooks de pré-commit s'exécutent automatiquement avant chaque validation, bloquant la validation en cas d'échec d'un outil.
Tout d'abord, installez le package pre-commit :
brew update && brew upgrade pyenv
Ensuite, créez un fichier .pre-commit-config.yaml dans le répertoire de votre projet avec le contenu suivant (ici j'ai utilisé tous mes pré-commits de base préférés) :
Activez les hooks de pré-commit dans votre référentiel local :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
Désormais, chaque fois que vous essayez de vous engager, ces outils s'exécuteront automatiquement. Si un outil échoue, la validation sera bloquée jusqu'à ce que le problème soit résolu. Vous pouvez également exécuter tous les hooks manuellement dans votre base de code :
pyenv install 3.12.2
Maintenant que nous avons construit notre projet, écrit du code, ajouté des tests et configuré des hooks de pré-validation, la prochaine étape consiste à déterminer comment d'autres (ou même nous-mêmes) pouvons facilement l'utiliser. L'emballage du projet rend cela possible. Cela nous permet de tout regrouper soigneusement afin qu'il puisse être installé et utilisé sans copier les fichiers manuellement.
Pour partager votre projet, vous devez structurer correctement le package, écrire un README significatif, créer un script de démarrage et générer le package de distribution. Un bon README comprend généralement le nom du projet et une brève description de ce qu'il fait, des instructions d'installation, des exemples d'utilisation, des instructions de développement pour configurer l'environnement et des directives pour contribuer. Vous pouvez trouver un simple exemple README.md pour notre projet blog_de_toolkit dans le référentiel.
Au cœur de tout package Python se trouve le fichier setup.py. Ce fichier est l'endroit où nous définissons les métadonnées et la configuration nécessaires pour empaqueter et installer notre projet. Il comprend le nom, la version et la description du projet, qui le rendent identifiable. La long_description lit le fichier README pour donner aux utilisateurs plus de contexte sur le projet lorsqu'ils le voient sur PyPI. Nous spécifions les dépendances dans la liste install_requires afin qu'elles soient automatiquement installées avec le package. La section entry_points définit une entrée d'interface de ligne de commande (CLI), afin que les utilisateurs puissent exécuter l'outil depuis leur terminal. Nous utilisons find_packages() pour inclure tous les sous-modules du package, et la section classifiers fournit des métadonnées, comme la version Python et la licence utilisées par le projet. Enfin, le champ python_requires garantit que le package s'installe uniquement sur les versions Python compatibles. Voici la configuration setup.py pour notre projet blog_de_toolkit :
Une fois le setup.py configuré, vous pouvez créer le package de distribution. Commencez par installer les outils nécessaires avec :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
Ensuite, construisez le package :
pyenv install 3.12.2
Cette commande crée deux fichiers de distribution :
sdist : Une archive source (par exemple, .tar.gz)
bdist_wheel : Un package construit (par exemple, .whl)
Ces fichiers seront situés dans le répertoire dist/. Pour tester le package, installez-le localement avec :
brew update && brew upgrade pyenv
Vous pouvez également tester la commande CLI en exécutant :
brew install readline xz
cela devrait imprimer l'URL de la base de données, la clé API et les données nettoyées de sample_data.csv.
Si vous souhaitez partager le package publiquement, vous pouvez le télécharger sur PyPI. Tout d’abord, installez Twine :
pyenv virtualenv 3.12.2 de_toolkit
Ensuite, téléchargez le package :
pyenv local de_toolkit
Vous serez invité à saisir vos informations d’identification PyPI. Une fois téléchargé, d'autres peuvent installer votre package directement depuis PyPI avec :
pip install setuptools wheel twine pandas
À mesure que votre projet grandit, davantage de personnes travailleront sur la même base de code, souvent en même temps. Sans mesures de protection appropriées, il est facile que des erreurs, du code non testé ou des fusions accidentelles se faufilent et gâchent les choses. Pour assurer le bon fonctionnement et maintenir un niveau d’exigence élevé, la protection de la branche principale devient essentielle. Dans cette étape, nous verrons comment configurer des règles de protection des branches et partagerons quelques conseils pour effectuer des révisions de code fluides sur les demandes d'extraction.
Les règles de protection des branches garantissent que personne ne peut accéder directement à la branche principale sans réussir les tests ou obtenir une révision du code. Cela empêche les fonctionnalités inachevées, les bogues ou le mauvais code de s'infiltrer et d'interrompre le projet. Il favorise également le travail d'équipe en exigeant des demandes d'extraction, donnant ainsi aux autres la possibilité de donner leur avis. De plus, des vérifications automatisées, comme les tests et les linters, garantissent la solidité du code avant la fusion.
La configuration des règles de protection des branches sur GitHub est assez simple. Rendez-vous dans les Paramètres de votre référentiel et cliquez sur Branches dans la section « Code et automatisation ». Recherchez Règles de protection de branche et cliquez sur Ajouter une règle de protection de branche. Entrez main dans le champ du nom de la branche, et il est maintenant temps de modifier quelques paramètres.
Vous pouvez définir des règles de protection des branches pour exiger des examens des demandes d'extraction, garantissant ainsi que quelqu'un vérifie le code avant sa fusion. Les vérifications de statut garantissent la réussite des tests et le bon fonctionnement des linters, et maintenir les branches à jour avec les dernières modifications permet d'éviter les conflits. Si nécessaire, vous pouvez restreindre le nombre de personnes autorisées à effectuer des push vers la branche ou même exiger des validations signées pour plus de sécurité. Une fois que tout est défini, cliquez sur Créer, et juste comme ça : plus de poussées directes ou de tests ignorés.
Lorsque votre pull request est en cours d'examen, c'est une bonne idée de faciliter les choses pour vos réviseurs. Commencez par une description claire de l’effet de vos modifications et de la raison pour laquelle elles sont nécessaires. Utilisez des messages de validation significatifs qui reflètent ce qui a été mis à jour. Si les changements sont mineurs et ciblés, le processus de révision devient plus fluide et plus rapide. N'oubliez pas de répondre poliment aux commentaires et de donner suite aux modifications demandées : cela montre que vous appréciez les commentaires et contribue à maintenir la collaboration positive.
Si c'est vous qui examinez une pull request, votre travail va au-delà de la simple recherche d'erreurs : il s'agit d'améliorer le code et de soutenir votre coéquipier. Commencez par lire la description de la pull request pour comprendre ce que les modifications tentent d'accomplir. Concentrez-vous sur les commentaires constructifs : suggérez des alternatives si nécessaire et expliquez pourquoi elles pourraient mieux fonctionner. Reconnaître le bon travail avec un simple « Joli refactor ? » contribue également à créer une expérience d’évaluation positive. Gardez un œil sur les tests pour vous assurer qu’ils sont présents, pertinents et réussis. Et si quelque chose n’est pas clair, posez des questions au lieu de faire des hypothèses. En fin de compte, les évaluations concernent le travail d'équipe : collaborer pour améliorer le projet ensemble.
L'utilisation de modèles d'évaluation peut contribuer à rendre le processus plus fluide en gardant tout le monde concentré sur ce qui compte. Voici un exemple de modèle d'examen de demande de tirage :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
L'ajout d'un modèle comme celui-ci à vos directives de contribution ou le lien dans le référentiel permet aux réviseurs de rester facilement sur la bonne voie. Cela garantit également la cohérence des éléments entre les révisions, aidant ainsi l'équipe à maintenir une base de code propre et organisée.
En s'appuyant sur l'importance de protéger votre branche principale, il est également crucial de s'assurer que chaque modification de code est correctement testée, examinée et validée avant de la fusionner ou de la déployer. C'est là que l'Intégration continue (CI) et la Livraison/Déploiement continu (CD) entrent en jeu. CI/CD automatise le processus d'exécution des tests, de vérification du code et de déploiement des modifications, fournissant ainsi un retour rapide aux développeurs et réduisant les risques que des bogues se retrouvent en production.
GitHub Actions est un outil d'automatisation intégré directement à GitHub. Il vous permet de créer des flux de travail qui répondent aux événements de votre référentiel, tels que des demandes push ou pull. Dans GitHub Actions, nous pouvons automatiser plusieurs tâches clés pour maintenir une base de code saine. Par exemple :
Exécuter des tests chaque fois que du code est poussé ou qu'une pull request est créée, en s'assurant que les nouvelles modifications ne cassent rien.
Vérification du style de code et du peluchage pour appliquer des normes de codage cohérentes.
Application de hooks de pré-validation pour formater le code et détecter les petits problèmes comme les espaces de fin.
Générer la documentation ou même déployer le code lorsque toutes les vérifications sont réussies.
Configurons un workflow GitHub Actions qui exécute nos tests unitaires et applique des linters de pré-validation (comme le noir) chaque fois qu'une demande push ou pull se produit sur la branche principale.
Tout d'abord, créez le fichier de workflow :
blog_de_toolkit/ │ ├── de_toolkit/ │ ├── __init__.py │ └── data_tools.py │ ├── tests/ │ ├── __init__.py │ └── test_data_tools.py │ ├── .gitignore ├── setup.py └── README.md
Voici le contenu de ci.yml :
Ce workflow automatise les tests et le peluchage chaque fois que du code est poussé ou qu'une pull request est ouverte sur la branche principale. Il garantit que tous les contrôles de qualité sont réussis avant la fusion du code. L'action actions/checkout clone le référentiel dans le runner et nous utilisons actions/setup-python pour configurer Python 3.12 pour le flux de travail. Les dépendances sont installées à partir de Requirements.txt à l'aide de pip. Après cela, tous les tests sont exécutés avec pytest et les hooks de pré-validation garantissent que le code respecte les directives de formatage et de style. Si un test ou une vérification échoue, le flux de travail s'arrête pour empêcher la fusion du code défectueux.
Testons-le. Tout d’abord, créez une nouvelle branche à partir de main et apportez quelques modifications.
Dans mon cas, j'ai mis à jour le fichier README. Validez vos modifications et ouvrez une pull request dans la branche principale.
Vous verrez maintenant que la révision est requise et que GitHub Actions (GA) effectue toutes ses vérifications. Même si la fusion est bloquée par les règles de protection des branches, je peux toujours « Fusionner sans attendre que les conditions soient remplies » car mes autorisations permettent de contourner les protections.
Vous pouvez suivre les résultats de votre workflow GitHub Actions dans l'onglet Actions.
Voici un exemple de ce à quoi ressemble l'étape pytest lors d'une exécution :
Suivre manuellement la version de votre projet peut s'avérer compliqué, surtout à mesure qu'il grandit. C'est là qu'intervient le versionnement sémantique (SemVer) : il suit le modèle MAJOR.MINOR.PATCH pour communiquer ce qui a changé dans chaque version. L'automatisation du contrôle de version avec python-semantic-release rend cela encore plus facile. Il analyse vos messages de validation, modifie la version en fonction du type de modifications, marque les versions et peut même publier votre package sur PyPI si vous le souhaitez. Cela simplifie la gestion des versions et garantit la cohérence.
Pour une gestion des versions transparente, vous pouvez intégrer python-semantic-release directement dans GitHub Actions. La documentation officielle fournit des flux de travail qui automatisent les changements de version et les versions chaque fois que vous accédez à la branche principale. Avec cette configuration, le processus de publication devient fluide et sans intervention, vous pouvez donc vous concentrer sur l'écriture du code sans vous soucier de la gestion manuelle des versions.
Exemple de flux de travail courant — python-semantic-release
Pour que cela fonctionne, vos messages de validation doivent suivre les normes de validation conventionnelles. Chaque type de validation détermine si la version augmentera le niveau PATCH, MINEUR ou MAJOR :
correctif : Déclenche un changement de version du PATCH (par exemple, 1.0.0 → 1.0.1).
exploit : Déclenche un changement de version MINEURE (par exemple, 1.0.0 → 1.1.0).
CHANGEMENT RUPTURE : ou ! dans le message de validation déclenche un changement de version MAJEUR (par exemple, 1.0.0 → 2.0.0).
En suivant ces conventions simples, vous saurez toujours à quoi vous attendre à chaque nouvelle version.
Nous avons tout couvert, depuis l'organisation de votre projet et la gestion des secrets jusqu'à l'écriture de tests, l'automatisation des flux de travail et la gestion des versions avec le versionnage sémantique. Avec les bons outils et processus, construire un projet fiable et maintenable devient beaucoup plus fluide et même amusant.
La clé est de rester cohérent, d'automatiser là où vous le pouvez et de continuer à vous améliorer au fur et à mesure. Chaque petit pas fait une grande différence au fil du temps. C'est maintenant votre tour : allez construire, expérimenter et profiter du processus ! Essayez d'appliquer ces étapes à votre prochain projet — et n'hésitez pas à partager votre expérience dans les commentaires !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!