Formation Python
- L'opérateur Modulo Python et la gestion des données avec SQLite et SQLAlchemy – Le véritable podcast Python
- 10 nouveaux plugins pour les blogueurs débutants et expérimentés
- Comprendre le traçage Python – Real Python
- Épisode 40: Les 10 plus grandes histoires de data science de 2015
- Les meilleurs plugins d'avis pour WordPress
La création d'applications avec une interface de ligne de commande (CLI) conviviale est une compétence utile pour un développeur Python. Avec cette compétence, vous pouvez créer des outils pour automatiser et accélérer les tâches dans votre environnement de travail. Dans ce didacticiel, vous allez créer un outil de génération d'arborescence de répertoires Python pour votre ligne de commande.
L'application prendra un chemin de répertoire comme argument sur la ligne de commande et affichera un diagramme d'arborescence de répertoires sur votre écran. Il fournira également d'autres options pour peaufiner la sortie.
Dans ce didacticiel, vous apprendrez à:
- Créer un Application CLI avec Python
argparse
- Récursivement traverser une structure de répertoires utilisant
pathlib
- Générer, formater et afficher un diagramme d'arborescence de répertoires
- Enregistrez l'arborescence de répertoires dans un fichier de sortie
Vous pouvez télécharger le code et d'autres ressources nécessaires pour créer ce projet de générateur d'arborescence de répertoires en cliquant sur le lien ci-dessous:
Démo: un outil générateur d'arborescence de répertoires en Python
Dans ce didacticiel, vous allez créer un outil de ligne de commande pour répertorier le contenu d’un répertoire ou d’un dossier dans un diagramme arborescent. Il existe déjà plusieurs solutions matures qui effectuent cette tâche. Vous trouverez des outils comme le arbre
command, qui est disponible sur la plupart des systèmes d'exploitation, ainsi que sur d'autres outils, tels que treelib, dirtriex, etc. Cependant, trouver votre propre solution à ce problème serait un bon exercice d'apprentissage.
Ce tutoriel fait référence au type d'outil décrit ci-dessus comme un générateur d'arborescence de répertoires. L’outil que vous allez créer ici vous permettra de générer et d’afficher un diagramme en forme d’arbre répertoriant la structure interne d’un répertoire donné dans votre système de fichiers. Vous trouverez également ce diagramme appelé diagramme d'arborescence de répertoires tout au long du didacticiel.
Votre générateur d'arborescence de répertoires aura une interface de ligne de commande conviviale. Il fournira également des fonctionnalités intéressantes, telles que l'affichage d'un diagramme arborescent avec le contenu d'un répertoire sur la fenêtre de votre terminal et l'enregistrement du diagramme dans un fichier externe.
Voici à quoi ressemblera l'application et fonctionnera une fois que vous aurez atteint la fin de ce didacticiel:
Votre générateur d'arborescence de répertoires fournira une CLI entièrement fonctionnelle mais minimale avec quelques options qui vous permettent de générer et d'afficher un diagramme en arbre répertoriant tous les fichiers et répertoires d'un répertoire racine donné.
Aperçu du projet
Le projet que vous allez créer dans ce didacticiel consiste en une application de ligne de commande qui prend un chemin de répertoire comme argument, parcourt sa structure interne et génère un diagramme arborescent répertoriant le contenu du répertoire en question. Dans cette section, vous allez jeter un premier regard sur le problème et une solution possible. Vous déciderez également de la présentation du projet.
Présentation du projet
Pour créer votre générateur d'arborescence de répertoires, vous allez créer quelques modules et un package. Ensuite, vous donnerez au projet une mise en page d'application Python cohérente. À la fin de ce didacticiel, le répertoire racine de votre projet aura la structure de répertoires suivante:
./rptree_project/
│
├── rptree /
│ ├── rptree.py
│ ├── __init__.py
│ └── cli.py
│
├── LISEZMOI.md
└── tree.py
le rptree_project /
directory est le répertoire racine du projet. Là, vous placerez les fichiers suivants:
-
LISEZMOI.md
fournit la description du projet et des instructions sur l'installation et l'exécution de l'application. L'ajout d'un fichier README descriptif et détaillé à vos projets est considéré comme une bonne pratique en matière de programmation, en particulier si vous prévoyez de publier le projet en tant que solution open source. -
tree.py
fournit un script de point d'entrée pour vous permettre d'exécuter l'application.
Ensuite, vous avez le rptree /
répertoire qui contient un package Python avec trois modules:
rptree.py
fournit les principales fonctionnalités de l’application.__init__.py
permetrptree /
en tant que package Python.cli.py
fournit l'interface de ligne de commande pour l'application.
Votre outil générateur d'arborescence de répertoires s'exécutera sur la ligne de commande. Il prendra des arguments, les traitera et affichera une arborescence de répertoires dans la fenêtre du terminal. Il peut également enregistrer le diagramme de sortie dans un fichier au format markdown.
Présentation de la solution
Traverser un répertoire dans votre système de fichiers et générer un diagramme arborescent convivial qui reflète son contenu peut ne pas sembler une tâche difficile à première vue. Cependant, lorsque vous commencez à y penser, vous vous rendez compte que cela cache beaucoup de complexité.
Tout d’abord, c’est un problème qui implique la récursivité. Supposons que votre gestionnaire de fichiers soit ouvert dans votre répertoire de base et que vous recherchez un fichier spécifique. Ensuite, vous double-cliquez sur le Documents /
sous-répertoire et affichez son contenu sur votre écran. Si le fichier est là, vous l'ouvrez. Sinon, vous ouvrez un autre sous-répertoire et continuez à chercher. Vous pouvez décrire ce processus avec les étapes suivantes:
- Ouvrez un répertoire.
- Inspectez le contenu du répertoire.
- Si le fichier est trouvé, ouvrez-le. Sinon, revenez à la première étape.
La conclusion est que travailler avec des répertoires et leur contenu est un problème que vous aborderez généralement en utilisant la récursivité. C’est le chemin que vous suivrez dans ce didacticiel. En général, vous exécuterez les étapes suivantes:
- Obtenez le chemin vers un répertoire sur votre système de fichiers.
- Ouvrez le répertoire.
- Obtenez une liste de toutes ses entrées (répertoires et fichiers).
- Si le répertoire contient des sous-répertoires, répétez le processus à partir de la deuxième étape.
Pour exécuter la première étape, vous devez fournir un moyen pour votre application d'emprunter un chemin de répertoire sur la ligne de commande. Pour ce faire, vous utiliserez Python argparse
module de la bibliothèque standard.
Pour effectuer les deuxième et troisième étapes, vous utiliserez pathlib
. Ce module fournit plusieurs outils pour gérer et représenter les chemins du système de fichiers. Enfin, vous utiliserez une liste Python standard pour stocker la liste des entrées dans la structure de répertoires.
Un deuxième point à prendre en compte est de savoir comment façonner un bel arbre qui reflète la structure des répertoires de manière précise et conviviale. Dans ce didacticiel, vous allez mettre en forme vos diagrammes d'arbre à l'aide d'une stratégie qui imite ce que le arbre
commande le fait, donc vos diagrammes ressembleront à celui que vous avez vu dans la section ci-dessus.
Organisation du code
En termes de conception, si vous pensez au problème actuel et appliquez le principe de responsabilité unique, vous pouvez organiser le code de votre application de générateur d'arborescence de répertoires selon trois responsabilités principales:
- Fournir la CLI
- Parcourez le répertoire racine et construisez l'arborescence
- Afficher l'arborescence
Le code lié à la CLI vivra dans cli.py
. Dans rptree.py
, vous placerez le code lié aux deuxième et troisième responsabilités.
Dans cet exemple, vous allez écrire un DirectoryTree
classe pour générer et afficher l'arborescence. Vous utiliserez cette classe dans votre code client ou votre fonction principale. La classe fournira une méthode appelée .produire()
pour générer et afficher l'arborescence de répertoires.
Ensuite, vous coderez un bas niveau _TreeGenerator
classe pour parcourir la structure de répertoires et créer la liste contenant les entrées qui forment l'arborescence. Cette classe fournira une méthode appelée .build_tree ()
pour effectuer cette opération.
L'arborescence aura deux composants principaux:
- Diriger fournira la représentation du répertoire racine.
- Corps fournira la représentation du contenu de l'annuaire.
La représentation de la tête de l'arborescence comprendra le nom du répertoire racine et un tube supplémentaire (│
) pour relier la tête et le corps de l'arbre.
La représentation du corps de l'arborescence se composera de chaînes comprenant les composants suivants:
- Une chaîne de préfixe qui fournit l'espacement requis pour refléter la position d'une entrée dans la structure du répertoire
- Un caractère qui connecte le sous-répertoire ou le fichier actuel à son répertoire parent
- Le nom du sous-répertoire ou du fichier actuel
Voici comment combiner ces éléments pour créer une arborescence de répertoires:
Votre générateur d'arbres .build_tree ()
renvoie une liste avec toutes les entrées qui forment l'arborescence de répertoires. Pour afficher le diagramme, vous devez appeler .produire()
sur votre objet d'arborescence de répertoires.
Conditions préalables
Pour terminer ce didacticiel et en tirer le meilleur parti, vous devez être à l'aise avec les concepts suivants:
- Création d'interfaces de ligne de commande (CLI) avec Python
argparse
module - Traverser le système de fichiers avec
pathlib
- Utilisation de la récursivité et création de fonctions récursives en Python
- Travailler avec des fichiers utilisant
ouvert()
et leavec
déclaration - Utilisant
imprimer()
pour imprimer du texte à l'écran et également pour écrire dans des fichiers physiques de votre système de fichiers - Utilisation de la programmation orientée objet en Python
Si vous ne possédez pas toutes les connaissances requises avant de commencer ce didacticiel, c'est pas grave! Vous pouvez toujours arrêter et consulter les ressources suivantes:
En termes de dépendances logicielles, votre projet de générateur d'arborescence de répertoires n'a pas besoin de bibliothèques externes. Toutes ses dépendances sont disponibles sous forme de fonctions intégrées Python ou de modules dans la bibliothèque standard.
Cela dit, il est temps de se salir les mains avec du vrai code et de créer votre propre outil de génération d’arborescence de répertoires!
Étape 1: Configuration de la structure du projet
Tout d'abord, vous devez créer une mise en page d'application cohérente pour votre projet de générateur d'arborescence de répertoires. Allez-y et créez un nouveau répertoire sur votre système de fichiers avec le nom rptree_project /
. Dans ce répertoire, vous avez besoin de deux fichiers vides:
LISEZMOI.md
tree.py
Ensuite, vous devez créer un sous-répertoire appelé rptree /
contenant les fichiers vides suivants: rptree.py
, __init__.py
, et – cli.py
. Avec cet ajout, le répertoire racine de votre projet devrait ressembler à ceci:
./rptree_project/
│
├── rptree /
│ ├── rptree.py
│ ├── __init__.py
│ └── cli.py
│
├── LISEZMOI.md
└── tree.py
Pour télécharger ces fichiers et le code que vous y ajouterez dans cette section, cliquez sur le lien ci-dessous:
À ce stade, vous avez besoin d'une étape de configuration supplémentaire. Lancez votre éditeur de code ou IDE préféré dans le répertoire de votre projet, ouvrez __init__.py
et ajoutez le contenu suivant:
# __init__.py
"" "Package de premier niveau pour RP Tree." ""
__version__ = «0,1,0»
Python utilise __init__.py
fichiers pour transformer un répertoire normal en un package. Les packages contiennent des modules, tels que rptree.py
et cli.py
Dans ce projet. Les packages et les modules sont les mécanismes qui vous permettent d'organiser et de structurer votre code Python.
Dans ce cas, __init__.py
contient la chaîne de documentation du module, communément appelée docstring. Il définit également une constante globale appelée __version__
, qui contient le numéro de version de l'application.
Enfin, vous avez besoin d'un exemple de répertoire pour tester l'application et vous assurer qu'elle fonctionne correctement. Laissez le répertoire racine de votre projet et créez la structure de répertoires suivante dans votre système de fichiers, côte à côte avec le dossier de votre projet:
../Bonjour/
│
├── bonjour /
│ ├── __init__.py
│ └── bonjour.py
│
├── tests /
│ └── test_hello.py
│
├── requirements.txt
├── setup.py
├── LISEZMOI.md
└── LICENCE
Cette structure de répertoires imite la présentation générale d'un projet Python. Vous utiliserez cet exemple de structure de répertoires pour tester l'outil de génération d'arborescence de répertoires tout au long des étapes de ce didacticiel. De cette façon, vous pouvez comparer votre résultat avec le résultat attendu à n'importe quelle étape donnée du didacticiel.
Étape 2: Génération d'un diagramme d'arborescence de répertoires en Python
Maintenant que vous connaissez les exigences du projet et que vous avez configuré la mise en page du projet et le répertoire d'exemples, vous pouvez commencer à travailler sur le code réel. Alors préparez votre éditeur à se lancer dans le codage.
Dans cette section, vous coderez la fonctionnalité principale du projet. En d'autres termes, vous allez écrire le code pour générer un diagramme d'arborescence de répertoires complet à partir d'un chemin de répertoire d'entrée. Pour télécharger ce code, cliquez sur le lien ci-dessous:
Revenez maintenant à votre éditeur de code et ouvrez rptree.py
. Ajoutez ensuite le code suivant au fichier:
# rptree.py
"" "Ce module fournit le module principal RP Tree." ""
importer os
importer pathlib
TUYAU = "│"
COUDE = "└──"
TEE = "├──"
TUYAU_PREFIX = "│"
SPACE_PREFIX = ""
Dans ce morceau de code, vous importez d'abord os
et pathlib
à partir de la bibliothèque standard Python. Ensuite, vous définissez plusieurs constantes au niveau du module pour contenir les caractères du connecteur et les chaînes de préfixe que vous utiliserez pour dessiner l’arborescence dans la fenêtre du terminal. Les symboles que vous utiliserez pour dessiner l'arborescence sont les mêmes que ceux que vous avez vus dans les diagrammes précédents de ce didacticiel. L'outil de ligne de commande arbre
utilise ces mêmes symboles pour dessiner des diagrammes en arbre.
Codage du haut niveau DirectoryTree
Classer
Ensuite, vous allez définir une classe de haut niveau pour créer l'arborescence de répertoires et l'afficher sur votre écran. Nommez la classe DirectoryTree
et ajoutez-y le code suivant:
# rptree.py
# Snip ...
classer DirectoryTree:
def __init__(soi, root_dir):
soi._Générateur = _TreeGenerator(root_dir)
def produire(soi):
arbre = soi._Générateur.build_tree()
pour entrée dans arbre:
imprimer(entrée)
Dans l'initialiseur de classe, vous prenez un répertoire racine comme argument et créez un attribut d'instance appelé ._Générateur
. Pour créer cet attribut, vous utilisez une technique POO appelée composition qui définit un "A une" relation. Cela signifie que chaque DirectoryTree
objet a un _TreeGenerator
objet attaché.
Noter: Le caractère de soulignement principal (_
) dans le nom _TreeGenerator
est une convention Python couramment utilisée. Cela implique que la classe est non public, ce qui signifie que vous ne vous attendez pas à ce que cette classe soit utilisée en dehors de son module contenant, rptree.py
.
Cette même convention s'applique aux méthodes et attributs non publics, que vous ne souhaitez pas utiliser en dehors de la classe conteneur. En règle générale, vous commencez à définir les attributs comme non publics et à les rendre Publique si nécessaire. Voir PEP 8 pour plus de détails sur cette convention.
Vous verrez comment créer ceci _TreeGenerator
cours dans une minute. Pour l'instant, jetez un œil à .produire()
. Cette méthode crée une variable locale appelée arbre
qui détient le résultat de l'appel .build_tree ()
sur l'objet générateur d'arbres. Ensuite, vous utilisez un pour
boucle pour imprimer chacun entrée
dans l'arborescence à votre écran.
Codage du bas niveau _TreeGenerator
Classer
Maintenant que vous avez terminé le codage DirectoryTree
, il est temps de coder la classe qui traverse le système de fichiers et génère l’arborescence des répertoires:
1# rptree.py
2# Snip ...
3
4classer _TreeGenerator:
5 def __init__(soi, root_dir):
6 soi._root_dir = pathlib.Chemin(root_dir)
7 soi._arbre = []
8
9 def build_tree(soi):
dix soi._tête_arbre()
11 soi._tree_body(soi._root_dir)
12 revenir soi._arbre
13
14 def _tête_arbre(soi):
15 soi._arbre.ajouter(F"soi._root_dir os.SEP")
16 soi._arbre.ajouter(TUYAU)
Voici comment ce code fonctionne:
-
Ligne 4 définit une nouvelle classe,
_TreeGenerator
. -
Ligne 5 définit l'initialiseur de classe. Dans ce cas,
.__ init __ ()
prendroot_dir
comme argument. Il contient le chemin du répertoire racine de l’arborescence. Notez que vous tournezroot_dir
dans unepathlib.Path
objet et affectez-le à l'attribut d'instance non publique._root_dir
. -
Ligne 7 définit une liste vide pour stocker les entrées qui forment l'arborescence des répertoires.
-
Lignes 9 à 12 définir
.build_tree ()
. Cette méthode publique génère et retourne le diagramme de l'arborescence de répertoires. À l'intérieur.build_tree ()
, vous appelez en premier._tree_head ()
pour construire la tête de l'arbre. Alors tu appelles._tree_body ()
avec._root_dir
comme argument pour générer le reste du diagramme. -
Lignes 14 à 16 définir
._tree_head ()
. Cette méthode ajoute le nom du répertoire racine à._arbre
. Ensuite, vous ajoutez unTUYAU
pour connecter le répertoire racine au reste de l'arborescence.
Jusque-là, vous n’avez codé que la première partie du cours. La prochaine étape consiste à écrire ._tree_body ()
, qui prendra plusieurs lignes de code.
Noter: Les numéros de ligne dans le code ci-dessus et dans le reste des exemples de code de ce didacticiel sont destinés à faciliter l'explication. Ils ne correspondent pas à l’ordre des lignes du module ou du script final.
Le code dans ._tree_body ()
fournit les fonctionnalités de bas niveau de la classe. Il prend un chemin de répertoire comme argument, parcourt le système de fichiers sous ce répertoire et génère l'arborescence de répertoires correspondante. Voici sa mise en œuvre:
1# rptree.py
2# Snip ...
3
4classer _TreeGenerator:
5 # Snip ...
6
7 def _tree_body(soi, annuaire, préfixe=""):
8 entrées = annuaire.iterdir()
9 entrées = trié(entrées, clé=lambda entrée: entrée.is_file())
dix entry_count = len(entrées)
11 pour indice, entrée dans énumérer(entrées):
12 connecteur = COUDE si indice == entry_count - 1 autre TEE
13 si entrée.is_dir():
14 soi._add_directory(
15 entrée, indice, entry_count, préfixe, connecteur
16 )
17 autre:
18 soi._ajouter le fichier(entrée, préfixe, connecteur)
Beaucoup de choses se passent dans ce code. Voici ce qu'il fait, ligne par ligne:
-
Ligne 7 définit
._tree_body ()
. Cette méthode prend deux arguments:-
annuaire
contient le chemin du répertoire que vous souhaitez parcourir. Noter queannuaire
devrait être unpathlib.Path
objet. -
préfixe
contient une chaîne de préfixe que vous utilisez pour dessiner l'arborescence sur la fenêtre du terminal. Cette chaîne permet d'afficher la position du répertoire ou du fichier dans le système de fichiers.
-
-
Ligne 8 appels
.iterdir ()
auannuaire
et attribuez le résultat àentrées
. Cet appel à.iterdir ()
renvoie un itérateur sur les fichiers et sous-répertoires contenus dansannuaire
. -
Ligne 9 trie les entrées dans
annuaire
utilisanttrié ()
. Pour ce faire, vous créez unlambda
fonction qui vérifie sientrée
est un fichier et retourneVrai
ou alorsFaux
par conséquent. En Python,Vrai
etFaux
sont représentés en interne sous forme de nombres entiers,1
et0
, respectivement. L'effet net est quetrié ()
place les répertoires en premier carentry.is_file () == Faux == 0
et les fichiers après eux parce queentry.is_file () == Vrai == 1
. -
Ligne 10 appels
len ()
pour obtenir le nombre d'entrées dans leannuaire
à portée de main. -
Lignes 11 commence un
pour
boucle qui itère sur les entrées dansannuaire
. La boucle utiliseénumérer()
pour associer un index à chaque entrée. -
Ligne 12 définit le symbole de connecteur que vous utiliserez pour dessiner l’arborescence dans la fenêtre du terminal. Par exemple, si l'entrée actuelle est la dernière du répertoire (
index == nombre_entrées - 1
), alors vous utilisez un coude (└──
) comme unconnecteur
. Sinon, vous utilisez un tee (├──
). -
Lignes 13 à 18 définir une instruction conditionnelle qui vérifie si l'entrée actuelle est un répertoire. Si tel est le cas, le
si
appels de bloc de code._add_directory ()
pour ajouter une nouvelle entrée de répertoire. Sinon, leautre
appels de clause._ajouter le fichier()
pour ajouter une nouvelle entrée de fichier.
Pour terminer le codage _TreeGenerator
, tu dois écrire ._add_directory ()
et ._ajouter le fichier()
. Voici le code de ces méthodes non publiques:
1# rptree.py
2# Snip ...
3
4classer _TreeGenerator:
5 # Snip ...
6
7 def _add_directory(
8 soi, annuaire, indice, entry_count, préfixe, connecteur
9 ):
dix soi._arbre.ajouter(F"préfixe connecteur annuaire.Nom os.SEP")
11 si indice ! = entry_count - 1:
12 préfixe + = TUYAU_PREFIX
13 autre:
14 préfixe + = SPACE_PREFIX
15 soi._tree_body(
16 annuaire=annuaire,
17 préfixe=préfixe,
18 )
19 soi._arbre.ajouter(préfixe.bande())
20
21 def _ajouter le fichier(soi, déposer, préfixe, connecteur):
22 soi._arbre.ajouter(F"préfixe connecteur déposer.Nom")
Voici ce que fait ce code, ligne par ligne:
-
Ligne 7 définit
._add_directory ()
. C'est une méthode d'assistance qui prend cinq arguments, sans comptersoi
. Vous savez déjà ce que chacun de ces arguments représente, il n'est donc pas nécessaire de les couvrir à nouveau. -
Ligne 10 ajoute un nouveau répertoire à
._arbre
. Chaque répertoire dans._arbre
est représenté par une chaîne contenant unpréfixe
, uneconnecteur
, le nom du répertoire (nom.entrée
) et un séparateur final (os.sep
). Notez que le séparateur dépend de la plate-forme, ce qui signifie que votre générateur d'arborescence utilise le séparateur qui correspond à votre système d'exploitation actuel. -
Lignes 11 à 14 exécuter une instruction conditionnelle qui met à jour
préfixe
selon leindice
de l'entrée actuelle. -
Lignes 15 à 18 appel
._tree_body ()
avec un nouvel ensemble d'arguments. -
Ligne 19 ajoute un nouveau
préfixe
pour séparer le contenu du répertoire courant du contenu du suivant.
Il y a un détail important discuté dans l'appel à ._tree_body ()
à la ligne 15. Ceci est un appel récursif indirect. Autrement dit, ._tree_body ()
s'appelle au moyen de ._add_directory ()
jusqu'à ce qu'il traverse toute la structure de répertoires.
Enfin, aux lignes 21 et 22, vous définissez ._ajouter le fichier()
. Cette méthode ajoute une entrée de fichier à la liste de l'arborescence des répertoires.
Exécution du code du générateur d'arborescence de répertoires
Wow! C'etait beaucoup de travail! Votre générateur d'arborescence de répertoires fournit désormais ses principales fonctionnalités. Il est temps d’essayer. Ouvrez une session interactive Python sur le répertoire racine du projet et saisissez le code suivant:
>>> de rptree.rptree importer DirectoryTree
>>> arbre = DirectoryTree("../Bonjour")
>>> arbre.produire()
../Bonjour/
│
├── bonjour /
│ ├── __init__.py
│ └── bonjour.py
│
├── tests /
│ └── test_hello.py
│
├── requirements.txt
├── setup.py
├── LISEZMOI.md
└── LICENCE
Ici, vous importez d'abord DirectoryTree
de rptree.py
. Ensuite, vous créez un objet d'arborescence de répertoires, en passant le chemin vers le fichier précédemment créé Bonjour/
exemple de répertoire. Quand vous appelez .produire()
sur l'objet de l'arborescence de répertoires, vous obtenez le diagramme complet de l'arborescence de répertoires imprimé sur votre écran.
Frais! Vous avez déjà codé la fonctionnalité principale de votre générateur d’arborescence de répertoires. Dans la section suivante, vous allez donner à votre projet une interface de ligne de commande agréable et conviviale et un script exécutable.
Étape 3: création de l'interface de ligne de commande du générateur d'arborescence de répertoires
Il existe plusieurs outils pour créer des applications CLI. Certains des plus populaires sont Click, docopt
, Typer, et aussi argparse
, qui est disponible dans la bibliothèque standard. Dans votre projet de générateur d'arborescence de répertoires, vous utiliserez argparse
pour fournir l'interface de ligne de commande. De cette façon, vous éviterez d’avoir une dépendance externe.
Python argparse
vous permet de définir les arguments que votre application prendra en ligne de commande et de valider l'entrée de l'utilisateur. Le module génère également des messages d'aide et d'utilisation pour vos scripts.
Pour télécharger les fichiers et le code que vous allez ajouter ou modifier dans cette section, cliquez sur le lien ci-dessous:
Pour implémenter l'interface de ligne de commande du générateur d'arborescence de répertoires, revenez au répertoire du projet et ouvrez le cli.py
fichier du rptree
paquet. Tapez ensuite le code suivant:
"" "Ce module fournit la CLI RP Tree." ""
# cli.py
importer argparse
importer pathlib
importer sys
de . importer __version__
de .rptree importer DirectoryTree
def principale():
args = parse_cmd_line_arguments()
root_dir = pathlib.Chemin(args.root_dir)
si ne pas root_dir.is_dir():
imprimer("Le répertoire racine spécifié n'existe pas")
sys.sortir()
arbre = DirectoryTree(root_dir)
arbre.produire()
Dans ce morceau de code, vous importez d'abord les modules requis à partir de la bibliothèque standard. Ensuite, vous importez __version__
et aussi DirectoryTree
à partir du paquet contenant, rptree
.
Dans principale()
, vous appelez en premier parse_cmd_line_arguments ()
et regroupez les arguments de ligne de commande dans args
. Vous verrez ce que fait cette fonction dans une minute. Ensuite, vous transformez le répertoire racine en un pathlib.Path
objet. L'instruction conditionnelle effectue une validation rapide pour garantir que l'utilisateur fournit un chemin de répertoire valide et quitte autrement l'application.
Enfin, vous créez un DirectoryTree
objet utilisant root_dir
comme argument et appel .produire()
dessus pour générer et afficher l'arborescence de répertoires correspondante sur la fenêtre de votre terminal.
Vous pouvez maintenant plonger dans le code de parse_cmd_line_arguments ()
. Cette fonction fournit toutes les fonctionnalités liées à la CLI:
1# cli.py
2# Snip ...
3
4def parse_cmd_line_arguments():
5 analyseur = argparse.ArgumentParser(
6 programme="arbre",
7 la description="RP Tree, un générateur d'arborescence de répertoires",
8 épilogue="Merci d'utiliser RP Tree!",
9 )
dix analyseur.version = F"RP Tree v__version__"
11 analyseur.add_argument("-v", "--version", action="version")
12 analyseur.add_argument(
13 "root_dir",
14 métavar="ROOT_DIR",
15 nargs="?",
16 défaut=".",
17 aider="Générer une arborescence de répertoires complète à partir de ROOT_DIR",
18 )
19 revenir analyseur.parse_args()
Voici ce que fait cette fonction:
-
Ligne 5 instancie
argparse.ArgumentParser
, en fournissant le nom de la commande de l'application (programme
), un courtla description
du programme, et unépilogue
phrase à afficher une fois que l’utilisateur a exécuté l’option d’aide de l’application. Cette classe fournit un analyseur pour tous les arguments que l'utilisateur tape sur la ligne de commande. -
Ligne 10 définit l'analyseur
version
attribut à une chaîne contenant le nom de l'application avec sa version actuelle,__version__
. -
Ligne 11 ajoute le premier argument optionnel à la CLI de votre application. le
-v
ou alors--version
flag est requis pour fournir cet argument, qui a l'action par défaut d'afficher la chaîne de version de l'application sur la fenêtre de votre terminal. -
Lignes 12 à 18 ajoutez un deuxième argument à la CLI. Ici,
root_dir
est un argument de position qui contient le chemin du répertoire que vous utiliserez comme point de départ pour générer l’arborescence de répertoires. Dans ce cas, il y a quatre arguments pour.add_argument ()
:-
métavar
contient le nom de l'argument dans les messages d'utilisation. -
nargs
définit le nombre de valeurs que votre programme peut prendre sous l'argument en question. Par exemple, votre générateur d'arborescence de répertoires ne peut prendre qu'un seul chemin de répertoire sur la ligne de commande, donc la valeur appropriée pournargs
est"?"
. -
défaut
fournit une valeur par défaut pour l'argument en question. Dans ce cas, vous utilisez un point ("."
) pour définir le répertoire actuel comme répertoire racine par défaut. -
aider
fournit un bref message d'aide décrivant ce que fait l'argument.
-
-
Ligne 19 analyse les arguments fournis en utilisant
.parse_args ()
. Cette méthode renvoie unEspace de noms
object avec tous les arguments fournis. Vous pouvez accéder à ces arguments en utilisant la notation par points sur l'objet d'espace de noms. Notez que vous avez stocké cet espace de noms dansargs
à l'époque où tu as écritprincipale()
.
La dernière action pour terminer cette étape de votre voyage consiste à fournir un script de point d'entrée. Revenez à votre éditeur de code et ouvrez tree.py
, puis ajoutez-y le code suivant:
#! / usr / bin / env python3
# tree.py
"" "Ce module fournit un script de point d'entrée RP Tree." ""
de rptree.cli importer principale
si __Nom__ == "__principale__":
principale()
Ce fichier est court et simple. Vous importez d'abord principale()
de cli.py
puis enroulez son appel dans le traditionnel si __name__ == "__main__":
conditionnel pour que Python appelle principale()
uniquement si vous exécutez le fichier en tant que programme plutôt que de l'importer en tant que module.
Avec ce script en place, vous pouvez commencer à utiliser votre tout nouveau générateur d'arborescence de répertoires en ligne de commande. Ouvrez une fenêtre de ligne de commande, accédez au répertoire du projet et exécutez les commandes suivantes:
$ python tree.py ../hello
../Bonjour/
│
├── bonjour /
│ ├── __init__.py
│ └── bonjour.py
│
├── tests /
│ └── test_hello.py
│
├── requirements.txt
├── setup.py
├── LISEZMOI.md
└── LICENCE
$ python tree.py -v
RP Tree v0.1.0
$ python tree.py --help
utilisation: arbre [-h] [-v] [ROOT_DIR]
RP Tree, un générateur d'arborescence de répertoires
arguments de position:
ROOT_DIR Génère une arborescence de répertoires complète à partir de ROOT_DIR
arguments optionnels:
-h, --help affiche ce message d'aide et quitte
-v, --version affiche le numéro de version du programme et quitte
Merci d'utiliser RP Tree!
C'est ça! Votre outil générateur d'arborescence de répertoires fonctionne. Il génère et affiche un diagramme arborescent convivial à l'écran. Il fournit également des informations sur la version et l'utilisation. C’est plutôt cool pour une centaine de lignes de code! Dans les sections suivantes, vous allez ajouter quelques fonctionnalités supplémentaires à l'application.
Étape 4: implémentation d'une option d'annuaire uniquement
Une fonctionnalité intéressante à ajouter à votre générateur d'arborescence de répertoires est la possibilité de générer et d'afficher des diagrammes d'arborescence de répertoires uniquement. En d'autres termes, un diagramme qui n'affiche que les répertoires. Dans ce projet, vous ajouterez -ré
et --dir uniquement
drapeaux pour y parvenir, mais avant cela, vous devez mettre à jour _TreeGenerator
afin qu'il puisse prendre en charge cette nouvelle fonctionnalité.
Vous pouvez télécharger les fichiers et le code que vous ajouterez ou modifierez dans cette section en cliquant sur le lien ci-dessous:
Ouvrez maintenant le rptree.py
module et mettez à jour son code comme ceci:
# rptree.py
# Snip ...
classer _TreeGenerator:
def __init__(soi, root_dir, dir_only=Faux):
soi._root_dir = pathlib.Chemin(root_dir)
soi._dir_only = dir_only
soi._arbre = []
# Snip ...
def _tree_body(soi, annuaire, préfixe=""):
entrées = soi._prepare_entries(annuaire)
entry_count = len(entrées)
pour indice, entrée in enumerate(entries):
connector = ELBOW if index == entries_count - 1 else TEE
if entry.is_dir():
self._add_directory(
entry, index, entries_count, prefix, connector
)
else:
self._add_file(entry, prefix, connector)
def _prepare_entries(self, directory):
entries = directory.iterdir()
if self._dir_only:
entries = [[[[entry pour entry in entries if entry.is_dir()]
return entries
entries = sorted(entries, key=lambda entry: entry.is_file())
return entries
# Snip...
First, you add dir_only
as an argument to the class initializer. This is a Boolean argument that allows you to generate a full tree or a directory-only tree depending on the user’s input at the command line. This argument defaults to False
because generating a full tree is the most common use case.
In the second highlighted line, you create an instance attribute called ._dir_only
to hold the newly added argument.
In the third highlighted line, you replace two lines of the original code with a call to ._prepare_entries()
. As its name suggests, this function prepares the directory entries to generate either a full tree or a directory-only tree.
In ._prepare_entries()
, you first get the entries
generator. le if
statement checks if ._dir_only
est True
. If so, then you filter out the files with a list comprehension and return a liste
of directories. Si ._dir_only
est False
, then you sort the entries, reusing the same code you saw before. Finally, you return the complete list of entries in directory
.
Now you need to make sure that you pass this new argument to the instance of _TreeGenerator
back in DirectoryTree
:
# rptree.py
# Snip...
class DirectoryTree:
def __init__(self, root_dir, dir_only=False):
self._generator = _TreeGenerator(root_dir, dir_only)
# Snip...
In the first highlighted line, you add a new argument called dir_only
to the class initializer. In the second highlighted line, you make sure to pass the new argument to the constructor of _TreeGenerator
.
With these changes in place, you can update the cli.py
file so that the application can take and process the -ré
et --dir-only
flags at the command line. First, you need to update main()
:
# cli.py
# Snip...
def main():
# Snip...
tree = DirectoryTree(root_dir, dir_only=args.dir_only)
tree.generate()
In the highlighted line, you pass args.dir_only
to the dir_only
argument of DirectoryTree
. This attribute of the args
namespace holds a Boolean value that depends on the user’s input. If the user provides the -ré
ou alors --dir-only
option at the command line, then args.dir_only
est True
. Otherwise, it’s False
.
Next, go and add those -ré
et --dir-only
flags to the command-line interface. To do that, you need to update parse_cmd_line_arguments()
like this:
# cli.py
# Snip...
def parse_cmd_line_arguments():
# Snip...
parser.add_argument(
"-d",
"--dir-only",
action="store_true",
help="Generate a directory-only tree",
)
return parser.parse_args()
le action
argument in the call to .add_argument()
holds the value "store_true"
, which means that this argument automatically stores True
ou alors False
according to the user’s input. In this case, if the user provides the -ré
ou alors --dir-only
flag at the command line, then the argument stores True
. Otherwise, it stores False
.
With this update in place, it’s time to run and test the application. Get back to your terminal window and execute the following command:
$ python tree.py ../hello -d
../hello/
│
├── hello/
│
└── tests/
From this point on, if you provide the -ré
ou alors -dir-only
flag at the command line, then the tree diagram only displays the subdirectories in your sample hello/
directory.
Step 5: Saving the Directory Tree Diagram to a File
In this section, you’ll add a final feature to your directory tree generator tool. You’ll provide the app with the capability to save the generated directory tree diagram to an external file. To do that, you’ll add a new argument to the CLI with the flags -o
et --output-file
.
As usual, to download the code that you’ll add or modify in this section, click the link below:
Now go back to rptree.py
and update DirectoryTree
like this:
# rptree.py
# Snip...
import sys
# Snip...
class DirectoryTree:
def __init__(self, root_dir, dir_only=False, output_file=sys.stdout):
self._output_file = output_file
self._generator = _TreeGenerator(root_dir, dir_only)
def generate(self):
tree = self._generator.build_tree()
if self._output_file != sys.stdout:
# Wrap the tree in a markdown code block
tree.insert(0, "```")
tree.append("```")
self._output_file = open(
self._output_file, mode="w", encoding="UTF-8"
)
avec self._output_file as stream:
pour entry in tree:
imprimer(entry, file=stream)
This update is almost a full reimplementation of DirectoryTree
. First, you add a new argument to the class initializer called output_file
. This argument defaults to sys.stdout
, which is the standard output (your screen). Then you store the newly added argument in an instance attribute called ._output_file
.
In .generate()
, you first build the directory tree diagram and store it in tree
. The conditional statement checks if the user has provided an output file different from sys.stdout
. If so, then the if
code block wraps the tree diagram in a markdown code block using backticks ("```"
).
Next, you open the provided output file using open()
so you can process it using the avec
statement.
Noter: Calling .insert(0, x)
on a list object might be an expensive operation in terms of execution time. That’s because Python needs to move all the items one position to the right and then insert the new item at the first position.
An efficient alternative to .insert()
would be to use collections.deque
and append the item at the first position of the data structure using .appendleft()
. This data structure is optimized for this kind of operation.
Dans le avec
block, you start a pour
loop to print the directory tree diagram to the provided output file. Note that print()
can also write to regular files on your file system. To do this, you just need to provide a custom file
argument. To dive deeper into the features of print()
, check out Your Guide to the Python print() Function.
Once you’ve finished with DirectoryTree
, you can update the command-line interface to enable the output file option. Get back to cli.py
and modify it like this:
# cli.py
# Snip...
def main():
# Snip...
tree = DirectoryTree(
root_dir, dir_only=args.dir_only, output_file=args.output_file
)
tree.generate()
def parse_cmd_line_arguments():
# Snip...
parser.add_argument(
"-o",
"--output-file",
metavar="OUTPUT_FILE",
nargs="?",
défaut=sys.stdout,
help="Generate a full directory tree and save it to a file",
)
return parser.parse_args()
The first step is to take the output file as an argument in the DirectoryTree
constructor. The output file, if any, will be stored in args.output_file
.
Next, you add a new argument to parser
. This argument has two flags: -o
et --output-file
. To provide an alternative output file, the user has to use one of these flags and provide the path to the files at the command line. Note that the output file defaults to sys.stdout
. This way, if the user doesn’t provide an output file, then the application automatically uses the standard output, the screen.
You can test the newly added option by running the following command on your terminal:
$ python tree.py ../hello -o output_file.md
This command generates a full directory tree diagram and saves it into the output_file.md
file in your current directory. If you open the file, then you’ll see the directory tree diagram saved there in markdown format.
That’s it! Your directory tree generator project is complete. Besides the default option that generates and displays a full directory tree diagram, the application provides the following options:
-v
,--version
show the current version information and exit the application.-h
,--help
show help and usage messages.-ré
,--dir-only
generate a directory-only tree and print it into the screen.-o
,--output-to-markdown
generate a tree and save it to a file in markdown format.
You now have a fully functional command-line tool that generates user-friendly directory tree diagrams. Great job!
Conclusion
You can automate and speed up several processes and tasks in your working environment by creating CLI tools and applications. In Python, you can quickly create this kind of tool using argparse
or other third-party libraries. In this tutorial, you wrote a full project to build a Python directory tree generator tool for your command line.
The application takes a directory path at the command line, generates a directory tree diagram, and displays it on your terminal window or saves it to an external file on your file system. It also provides a few more options to tweak the resulting tree diagram.
In this tutorial, you learned how to:
- Create a CLI application with Python’s
argparse
- Recursively traverse a directory structure using
pathlib
- Generate, format, and print a directory tree diagram
- Save the directory tree diagram to an output file
The final source code for the directory tree generator project is available for you to download. To get it, click the link below:
Next Steps
Up to this point, you’ve built a fully functional directory tree generator tool. Even though the application provides a minimal set of features, it’s a good starting point for you to continue adding features and learning in the process. This will help you take your skills with Python and CLI applications to the next level.
Here are a few ideas you can implement to continue improving your directory tree generator tool:
-
Add support for sorting files and directories: The ability to sort files and directories is a great feature to have. For example, you can add
-s
et--sort-tree
Boolean flags to allow the user to tweak the order of files and directories in the final tree diagram. -
Add icons and colors to the tree diagram: Adding icons, font colors, or both is also a nice feature to implement. For example, you can use custom folder icons for the directories and file type–based icons for the files.
-
Set up the application to publish it as an open source project: Preparing the application to publish to PyPI as an open source project might be an interesting challenge for you to take. Doing so will allow you to share your work with your friends and colleagues. To get started with publishing packages to PyPI, check out How to Publish an Open-Source Python Package to PyPI.
These are just a few ideas of how you can continue adding features to your directory tree generator. Take the challenge and build something amazing on top of this!
[ad_2]