Créer un générateur d'arborescence de répertoires Python pour la ligne de commande – Real Python

By | avril 14, 2021

Formation Python

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:

Démo de Directory Tree Generator

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:

  1. rptree.py fournit les principales fonctionnalités de l’application.
  2. __init__.py permet rptree / en tant que package Python.
  3. 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:

  1. Ouvrez un répertoire.
  2. Inspectez le contenu du répertoire.
  3. 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:

  1. Obtenez le chemin vers un répertoire sur votre système de fichiers.
  2. Ouvrez le répertoire.
  3. Obtenez une liste de toutes ses entrées (répertoires et fichiers).
  4. 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:

  1. Fournir la CLI
  2. Parcourez le répertoire racine et construisez l'arborescence
  3. 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:

  1. Diriger fournira la représentation du répertoire racine.
  2. 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:

Diagramme de l'arborescence des 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 le avec 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:

  1. LISEZMOI.md
  2. 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__.pyet 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é.

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 __ () prend root_dir comme argument. Il contient le chemin du répertoire racine de l’arborescence. Notez que vous tournez root_dir dans une pathlib.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 un TUYAU 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.

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:

    1. annuaire contient le chemin du répertoire que vous souhaitez parcourir. Noter que annuaire devrait être un pathlib.Path objet.

    2. 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 () au annuaire et attribuez le résultat à entrées. Cet appel à .iterdir () renvoie un itérateur sur les fichiers et sous-répertoires contenus dans annuaire.

  • Ligne 9 trie les entrées dans annuaire utilisant trié (). Pour ce faire, vous créez un lambda fonction qui vérifie si entrée est un fichier et retourne Vrai ou alors Faux par conséquent. En Python, Vrai et Faux sont représentés en interne sous forme de nombres entiers, 1 et 0, respectivement. L'effet net est que trié () place les répertoires en premier car entry.is_file () == Faux == 0 et les fichiers après eux parce que entry.is_file () == Vrai == 1.

  • Ligne 10 appels len () pour obtenir le nombre d'entrées dans le annuaire à portée de main.

  • Lignes 11 commence un pour boucle qui itère sur les entrées dans annuaire. 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 un connecteur. 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, le autre 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 compter soi. 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 un préfixe, une connecteur, 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 le indice 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 court la 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 ():

    1. métavar contient le nom de l'argument dans les messages d'utilisation.

    2. 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 pour nargs est "?".

    3. 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.

    4. 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 un Espace 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 dans args à l'époque où tu as écrit principale().

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.

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]