One place for hosting & domains

      Module

      Comment utiliser le module subprocess pour exécuter des programmes externes en Python 3


      L’auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      Python 3 comprend le module subprocess permettant d’exécuter des programmes externes et de lire leurs sorties dans votre code Python.

      Il se peut que vous trouviez subprocess utile si vous voulez utiliser un autre programme sur votre ordinateur à partir de votre code Python. Par exemple, vous pouvez invoquer git depuis votre code Python pour récupérer les fichiers de votre projet qui sont suivis dans le contrôle de version de git. Comme tout programme auquel vous pouvez accéder sur votre ordinateur par subprocess, les exemples présentés ici s’appliquent à tout programme externe que vous pourriez vouloir invoquer à partir de votre code Python.

      subprocess comprend plusieurs classes et fonctions, mais dans ce tutoriel, nous couvrirons l’une des fonctions les plus utiles de subprocess : subprocess.run. Nous passerons en revue ses différentes utilisations et les principaux arguments des mots-clés.

      Conditions préalables

      Pour tirer le meilleur parti de ce tutoriel, il est recommandé d’être familiarisé avec la  programmation en Python 3. Vous pouvez consulter ces tutoriels pour obtenir les informations de base nécessaires :

      Exécution d’un programme externe

      Vous pouvez utiliser la fonction subprocess.run pour exécuter un programme externe à partir de votre code Python. Mais d’abord, vous devez importer les modules subprocess et sys dans votre programme :

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "print('ocean')"])
      

      Si vous l’exécutez, vous obtiendrez une sortie comme ci-dessous :

      Output

      ocean

      Passons en revue cet exemple :

      • sys.executable est le chemin absolu vers l’exécutable Python avec lequel votre programme a été invoqué à l’origine. Par exemple, sys.executable pourrait être un chemin tel que /usr/local/bin/python.
      • subprocess.run reçoit une liste de chaînes de caractères comprenant les composants de la commande que nous essayons d’exécuter. Comme la première chaîne que nous passons est sys.executable, nous ordonnons à subprocess.run d’exécuter un nouveau programme Python.
      • Le composant -c est une option de ligne de commande python qui vous permet de passer une chaîne avec un programme Python entier à exécuter. Dans notre cas, nous passons un programme qui imprime la chaîne ocean.

      Vous pouvez penser que chaque entrée de la liste que nous passons à subprocess.run est séparée par un espace. Par exemple, [sys.executable, "-c", "print('ocean')"] se traduit approximativement par /usr/local/bin/python -c "print('ocean')". Notez que subprocess cite automatiquement les composants de la commande avant d’essayer de les exécuter sur le système d’exploitation sous-jacent de sorte que, par exemple, vous pouvez passer un nom de fichier qui contient des espaces.

      Warning : ne jamais transmettre une entrée non fiable à subprocess.run. Comme subprocess.run a la capacité d’exécuter des commandes arbitraires sur votre ordinateur, des acteurs malveillants peuvent l’utiliser pour manipuler votre ordinateur de manière inattendue.

      Capturer output d’un programme externe

      Maintenant que nous pouvons invoquer un programme externe en utilisant subprocess.run, voyons comment nous pouvons récupérer la sortie de ce programme. Par exemple, ce processus pourrait être utile si nous voulions utiliser git ls-files pour produire tous vos fichiers actuellement stockés sous contrôle de version.

      Note : Les exemples présentés dans cette section nécessitent Python 3.7 ou version supérieure. En particulier, les arguments capture_output et le mot-clé text ont été ajoutés à Python 3.7 lors de sa sortie en juin 2018.

      Ajoutons à notre exemple précédent :

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      stdout: ocean stderr:

      Cet exemple est en grande partie le même que celui présenté dans la première section : nous sommes toujours en train d’exécuter un sous-processus pour imprimer ocean. Il est toutefois important de noter que nous passons les arguments des mots-clés capture_output=True et text=True à subprocess.run.

      subprocess.run renvoie un objet subprocess.CompletedProcess qui est lié à result. L’objet subprocess.CompletedProcess comprend des détails sur le code de sortie du programme externe et sa sortie. capture_output=True garantit que result.stdout et result.stderr sont remplis avec la sortie correspondante du programme externe. Par défaut, result.stdout et result.stderr sont liés en tant qu’octets, mais l’argument du mot-clé text=True indique à Python de décoder plutôt les octets en chaînes de caractères.

      Dans la section de sortie, stdout est ocean (plus la nouvelle ligne de fin que print ajoute implicitement), et nous n’avons pas de stderr.

      Essayons un exemple qui produit une valeur non vide pour stderr :

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Si nous exécutons ce code, nous obtenons une sortie comme celle qui suit :

      Output

      stdout: stderr: Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops

      Ce code exécute un sous-processus Python qui génère immédiatement une ValueError. Lorsque nous inspectons le result final, nous ne voyons rien dans stdout et un Traceback de notre ValueError dans stderr. C’est parce que par défaut Python écrit le Traceback de l’exception non gérée à stderr .

      Lever une exception sur un code de sortie incorrect

      Il est parfois utile de lever une exception si un programme que nous exécutons sort avec un code de sortie incorrect. Les programmes qui sortent avec un code nul sont considérés comme réussis, mais les programmes qui sortent avec un code non-nul sont considérés comme ayant rencontré une erreur. Par exemple, ce modèle pourrait être utile si nous voulions lever une exception dans le cas où nous exécutons des fichiers git ls-files dans un répertoire qui n’est pas réellement un référentiel git.

      Nous pouvons utiliser l’argument check=True du mot-clé subprocess.run pour qu’une exception soit levée si le programme externe renvoie un code de sortie non-nul :

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
      

      Si nous exécutons ce code, nous obtenons une sortie comme celle qui suit :

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Cette sortie montre que nous avons exécuté un sous-processus qui a généré une erreur imprimée en stderr dans notre terminal. Ensuite, subprocess.run a consciencieusement levé un subprocess.CalledProcessError en notre nom dans notre programme Python principal.

      Alternativement, le module de sous-processus comprend également la méthode subprocess.CompletedProcess.check_returncode que nous pouvons invoquer pour un effet similaire :

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
      result.check_returncode()
      

      Si nous exécutons ce code, nous recevrons :

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Comme nous n’avons pas passé check=True à subprocess.run, nous avons lié avec succès une instance de subprocess.CompletedProcess à result, même si notre programme s’est terminé avec un code non nul. L’appel de result.check_returncode() fait cependant apparaître un sous-processus appelé CalledProcessError parce qu’il détecte le processus terminé sorti avec un code incorrect.

      Utilisation du délai d’attente pour quitter prématurément les programmes

      subprocess.run inclut l’argument timeout pour vous permettre d’arrêter un programme externe si son exécution est trop longue :

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 491, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait return self._wait(timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds

      Le sous-processus que nous avons essayé d’exécuter utilisait la fonction time.sleep pour se mettre en veille pendant 2 secondes. Cependant, nous avons passé l’argument du mot-clé timeout=1 à subprocess.run pour que notre sous-processus soit temporisé après 1 seconde. Cela explique pourquoi notre appel à subprocess.run a finalement soulevé une exception de subprocess.TimeoutExpired.

      Notez que l’argument du mot-clé timeout à subprocess.run est approximatif. Python fera tout son possible pour arrêter le sous-processus après le nombre de secondes stipulé dans timeout, mais ce ne sera pas nécessairement exact.

      Transmission d’Input aux programmes

      Parfois, les programmes s’attendent à ce que les données leur soient transmises via stdin.

      L’argument du mot-clé input à subprocess.run vous permet de passer des données au stdin du sous-processus. Par exemple :

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
      )
      

      Après l’exécution de ce code, nous recevrons une sortie comme celle qui suit :

      Output

      underwater

      Dans ce cas, nous avons passé les octets underwater à input. Notre sous-processus cible a utilisé sys.stdin pour lire le passage dans stdin ( underwater ) et l’a imprimé dans notre sortie.

      L’argument du mot-clé input peut être utile si vous voulez enchaîner plusieurs appels subprocess.run ensemble en passant la sortie d’un programme comme entrée à un autre.

      Conclusion

      Le module subprocess est une partie puissante de la bibliothèque standard Python, qui vous permet d’exécuter des programmes externes et d’inspecter leurs sorties facilement. Dans ce tutoriel, vous avez appris à utiliser subprocess.run pour contrôler des programmes externes, leur transmettre des entrées, analyser leurs sorties et vérifier leurs codes de retour.

      Le module subprocess propose des classes et des utilitaires supplémentaires que nous n’avons pas abordés dans ce tutoriel. Maintenant que vous disposez d’une base de référence, vous pouvez utiliser la documentation du module subprocess pour en savoir plus sur d’autres classes et utilitaires disponibles.



      Source link

      How To Work with Files using the fs Module in Node.js


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Working with files is as common for development purposes as it is for non-development purposes. In daily computer use, a user would likely read and write data to files in various directories in order to accomplish tasks like saving a downloaded file or accessing data to be used in another application. In the same way, a back-end program or command line interface (CLI) tool might need to write downloaded data to a file in order to save it, or a data-intensive application may need to export to JSON, CSV, or Excel formats. These programs would need to communicate with the filesystem of the operating system on which they are running.

      With Node.js, you can programmatically manipulate files with the built-in fs module. The name is short for “file system,” and the module contains all the functions you need to read, write, and delete files on the local machine. This unique aspect of Node.js makes JavaScript a useful language for back-end and CLI tool programming.

      In this article, you will use the fs module to read a file created via the command line, create and write to a new file, delete the file that you created, and move the first file into a different folder. The fs module supports interacting with files synchronously, asynchronously, or via streams; this tutorial will focus on how to use the asynchronous, Promise-based API, the most commonly used method for Node.js developers.

      Prerequisites

      Step 1 — Reading Files with readFile()

      In this step, you’ll write a program to read files in Node.js. To do this, you’ll need to import the fs module, a standard Node.js module for working with files, and then use the module’s readFile() function. Your program will read the file, store its contents in a variable, then log its contents to the console.

      The first step will be to set up the coding environment for this activity and the ones in the later sections.

      Create a folder to store your code. In your terminal, make a folder called node-files:

      Change your working directory to the newly created folder with the cd command:

      In this folder, you’ll create two files. The first file will be a new file with content that your program will read later. The second file will be the Node.js module that reads the file.

      Create the file greetings.txt with the following command:

      • echo "hello, hola, bonjour, hallo" > greetings.txt

      The echo command prints its string argument to the terminal. You use > to redirect echo’s output to a new file, greetings.txt.

      Now, create and open readFile.js in your text editor of choice. This tutorial uses nano, a terminal text editor. You can open this file with nano like this:

      The code for this file can be broken up into three sections. First, you need to import the Node.js module that allows your program to work with files. In your text editor, type this code:

      node-files/readFile.js

      const fs = require('fs').promises;
      

      As mentioned earlier, you use the fs module to interact with the filesystem. Notice, though, that you are importing the .promises part of the module.

      When the fs module was first created, the primary way to write asynchronous code in Node.js was through callbacks. As promises grew in popularity, the Node.js team worked to support them in the fs module out of the box. In Node.js version 10, they created a promises object in the fs module that uses promises, while the main fs module continues to expose functions that use callbacks. In this program, you are importing the promise version of the module.

      Once the module is imported, you can create an asynchronous function to read the file. Asynchronous functions begin with the async keyword. With an asynchronous function, you can resolve promises using the await keyword, instead of chaining the promise with the .then() method.

      Create a new function readFile() that accepts one argument, a string called filePath. Your readFile() function will use the fs module to load the file into a variable using async/await syntax.

      Enter the following highlighted code:

      node-files/readFile.js

      const fs = require('fs').promises;
      
      async function readFile(filePath) {
        try {
          const data = await fs.readFile(filePath);
          console.log(data.toString());
        } catch (error) {
          console.error(`Got an error trying to read the file: ${error.message}`);
        }
      }
      

      You define the function with the async keyword so you can later use the accompanying await keyword. To capture errors in your asynchronous file reading operation, you enclose the call to fs.readFile() with a try...catch block. Within the try section, you load a file to a data variable with the fs.readFile() function. The only required argument for that function is the file path, which is given as a string.

      The fs.readFile() returns a buffer object by default. A buffer object can store any kind of file type. When you log the contents of the file, you convert those bytes into text by using the toString() method of the buffer object.

      If an error is caught, typically if the file is not found or the program does not have permission to read the file, you log the error you received in the console.

      Finally, call the function on the greetings.txt file with the following highlighted line:

      node-files/readFile.js

      const fs = require('fs').promises;
      
      async function readFile(filePath) {
        try {
          const data = await fs.readFile(filePath);
          console.log(data.toString());
        } catch (error) {
          console.error(`Got an error trying to read the file: ${error.message}`);
        }
      }
      
      readFile('greetings.txt');
      

      Be sure to save your contents. With nano, you can save and exit by pressing CTRL+X.

      Your program will now read the greetings.txt file you created earlier and log its contents to the terminal. Confirm this by executing your module with node:

      You will receive the following output:

      Output

      hello, hola, bonjour, hallo

      You’ve now read a file with the fs module’s readFile() function using the async/await syntax.

      Note: In some earlier versions of Node.js, you will receive the following warning when using the fs module:

      (node:13085) ExperimentalWarning: The fs.promises API is experimental
      

      The promises object of the fs module was introduced in Node.js version 10, so some earlier versions still call the module experimental. This warning was removed when the API became stable in version 12.6.

      Now that you’ve read a file with the fs module, you will next create a file and write text to it.

      Step 2 — Writing Files with writeFile()

      In this step, you will write files with the writeFile() function of the fs module. You will create a CSV file in Node.js that keeps track of a grocery bill. The first time you write the file, you will create the file and add the headers. The second time, you will append data to the file.

      Open a new file in your text editor:

      Begin your code by importing the fs module:

      node-files/writeFile.js

      const fs = require('fs').promises;
      

      You will continue to use async/await syntax as you create two functions. The first function will be to make the CSV file. The second function will be to add data to the CSV file.

      In your text editor, enter the following highlighted code:

      node-files/writeFile.js

      const fs = require('fs').promises;
      
      async function openFile() {
        try {
          const csvHeaders="name,quantity,price"
          await fs.writeFile('groceries.csv', csvHeaders);
        } catch (error) {
          console.error(`Got an error trying to write to a file: ${error.message}`);
        }
      }
      

      This asynchronous function first creates a csvHeaders variable that contains the column headings of your CSV file. You then use the writeFile() function of the fs module to create a file and write data to it. The first argument is the file path. As you provided just the file name, Node.js will create the file in the same directory that you’re executing the code in. The second argument is the data you are writing, in this case the csvHeaders variable.

      Next, create a new function to add items to your grocery list. Add the following highlighted function in your text editor:

      node-files/writeFile.js

      const fs = require('fs').promises;
      
      async function openFile() {
        try {
          const csvHeaders="name,quantity,price"
          await fs.writeFile('groceries.csv', csvHeaders);
        } catch (error) {
          console.error(`Got an error trying to write to a file: ${error.message}`);
        }
      }
      
      async function addGroceryItem(name, quantity, price) {
        try {
          const csvLine = `n${name},${quantity},${price}`
          await fs.writeFile('groceries.csv', csvLine, { flag: 'a' });
        } catch (error) {
          console.error(`Got an error trying to write to a file: ${error.message}`);
        }
      }
      

      The asynchronous addGroceryItem() function accepts three arguments: the name of the grocery item, the amount you are buying, and the price per unit. These arguments are used with template literal syntax to form the csvLine variable, which is the data you are writing to the file.

      You then use the writeFile() method as you did in the openFile() function. However, this time you have a third argument: a JavaScript object. This object has a flag key with the value a. Flags tell Node.js how to interact with the file on the system. By using the flag a, you are telling Node.js to append to the file, not overwrite it. If you don’t specify a flag, it defaults to w, which creates a new file if none exists or overwrites a file if it already exists. You can learn more about filesystem flags in the Node.js documentation.

      To complete your script, use these functions. Add the following highlighted lines at the end of the file:

      node-files/writeFile.js

      ...
      async function addGroceryItem(name, quantity, price) {
        try {
          const csvLine = `n${name},${quantity},${price}`
          await fs.writeFile('groceries.csv', csvLine, { flag: 'a' });
        } catch (error) {
          console.error(`Got an error trying to write to a file: ${error.message}`);
        }
      }
      
      (async function () {
        await openFile();
        await addGroceryItem('eggs', 12, 1.50);
        await addGroceryItem('nutella', 1, 4);
      })();
      

      To call the functions, you first create a wrapper function with async function. Since the await keyword can not be used from the global scope as of the writing of this tutorial, you must wrap the asynchronous functions in an async function. Notice that this function is anonymous, meaning it has no name to identify it.

      Your openFile() and addGroceryItem() functions are asynchronous functions. Without enclosing these calls in another function, you cannot guarantee the order of the content. The wrapper you created is defined with the async keyword. Within that function you order the function calls using the await keyword.

      Finally, the async function definition is enclosed in parentheses. These tell JavaScript that the code inside them is a function expression. The parentheses at the end of the function and before the semicolon are used to invoke the function immediately. This is called an Immediately-Invoked Function Expression (IIFE). By using an IIFE with an anonymous function, you can test that your code produces a CSV file with three lines: the column headers, a line for eggs, and the last line for nutella.

      Save and exit nano with CTRL+X.

      Now, run your code with the node command:

      There will be no output. However, a new file will exist in your current directory.

      Use the cat command to display the contents of groceries.csv:

      You will receive the following output:

      node-files/groceries.csv

      name,quantity,price
      eggs,12,1.5
      nutella,1,4
      

      Your call to openFile() created a new file and added the column headings for your CSV. The subsequent calls to addGroceryItem() then added your two lines of data.

      With the writeFile() function, you can create and edit files. Next, you will delete files, a common operation when you have temporary files or need to make space on a hard drive.

      In this step, you will delete files with the unlink() function in the fs module. You will write a Node.js script to delete the groceries.csv file that you created in the last section.

      In your terminal, create a new file for this Node.js module:

      Now you will write code that creates an asynchronous deleteFile() function. That function will accept a file path as an argument, passing it to the unlink() function to remove it from your filesystem.

      In your text editor, write the following code:

      node-files/deleteFile.js

      const fs = require('fs').promises;
      
      async function deleteFile(filePath) {
        try {
          await fs.unlink(filePath);
          console.log(`Deleted ${filePath}`);
        } catch (error) {
          console.error(`Got an error trying to delete the file: ${error.message}`);
        }
      }
      
      deleteFile('groceries.csv');
      

      The unlink() function accepts one argument: the file path of the file you want to be deleted.

      Warning: When you delete the file with the unlink() function, it is not sent to your recycle bin or trash can but permanently removed from your filesystem. This action is not reversible, so please be certain that you want to remove the file before executing your code.

      Exit nano, ensuring that you save the contents of the file by entering CTRL+X.

      Now, execute the program. Run the following command in your terminal:

      You will receive the following output:

      Output

      Deleted groceries.csv

      To confirm that the file no longer exists, use the ls command in your current directory:

      This command will display these files:

      Output

      deleteFile.js greetings.txt readFile.js writeFile.js

      You’ve now confirmed that your file was deleted with the unlink() function.

      So far you’ve learned how to read, write, edit, and delete files. The following section uses a function to move files to different folders. After learning that function, you will be able to do the most critical file management tasks in Node.js.

      Step 4 — Moving Files with rename()

      Folders are used to organize files, so being able to programmatically move files from one folder to another makes file management easier. You can move files in Node.js with the rename() function. In this step, you’ll move a copy of the greetings.txt file into a new folder.

      Before you can code your Node.js module, you need to set a few things up. Begin by creating a folder that you’ll be moving your file into. In your terminal, create a test-data folder in your current directory:

      Now, copy the greetings.txt file that was used in the first step using the cp command:

      • cp greetings.txt greetings-2.txt

      Finish the setup by opening a JavaScript file to contain your code:

      In your Node.js module, you’ll create a function called moveFile() that calls the rename() function. When using the rename() function, you need to provide the file path of the original file and the path of the destination location. For this example, you’ll use a moveFile() function to move the greetings-2.txt file into the test-data folder. You’ll also change its name to salutations.txt.

      Enter the following code in your open text editor:

      node-files/moveFile.js

      const fs = require('fs').promises;
      
      async function moveFile(source, destination) {
        try {
          await fs.rename(source, destination);
          console.log(`Moved file from ${source} to ${destination}`);
        } catch (error) {
          console.error(`Got an error trying to move the file: ${error.message}`);
        }
      }
      
      moveFile('greetings-2.txt', 'test-data/salutations.txt');
      

      As mentioned earlier, the rename() function takes two arguments: the source and destination file paths. This function can move files to other folders, rename a file in its current directory, or move and rename at the same time. In your code, you are moving and renaming your file.

      Save and exit nano by pressing CTRL+X.

      Next, execute this program with node. Enter this command to run the program:

      You will receive this output:

      Output

      Moved file from greetings-2.txt to test-data/salutations.txt

      To confirm that the file no longer exists in your current directory, you can use the ls command:

      This command will display these files and folder:

      Output

      deleteFile.js greetings.txt moveFile.js readFile.js test-data writeFile.js

      You can now use ls to list the files in the test-data subfolder:

      Your moved file will appear in the output:

      Output

      salutations.txt

      You have now used the rename() function to move a file from your current directory into a subfolder. You also renamed the file with the same function call.

      Conclusion

      In this article, you learned various functions to manage files with Node.js. You first loaded the contents of a file with readFile(). You then created new files and appended data to an existing file with the writeFile() function. You permanently removed a file with the unlink() function, and then move and renamed a file with rename().

      Working with files programmatically is an important function of Node.js. Programs might need to output files for a user to use, or may need to store data for an application that is not always running. With the fs module’s functions, developers have control of how files are used in our Node.js programs.

      To learn more about the fs module, you can read the Node.js documentation. If you’d like to continue learning Node.js, you can return to the How To Code in Node.js series, or browse programming projects and setups on our Node topic page.



      Source link

      Comment utiliser le module pathlib pour manipuler les chemins des systèmes de fichiers en Python 3


      L’auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      Python 3 inclut le module pathlib, qui permet de manipuler les chemins des systèmes de fichiers de manière agnostique, quel que soit le système d’exploitation. pathlib est similaire au module os.path, mais pathlib offre un niveau d’interface supérieur — et souvent plus pratique — qu’os.path.

      Nous pouvons identifier des fichiers sur un ordinateur avec des chemin hiérarchiques. Par exemple, nous pourrions identifier le fichier wave.txt sur un ordinateur avec ce chemin : /Users/sammy/ocean/wave.txt. Les systèmes d’exploitation représentent les chemins de manière légèrement différente. Windows peut représenter le chemin d’accès au fichier wave.txt comme ceci, C:Userssammyoceanwave.txt.

      Vous pouvez trouver le module pathlib utile si dans votre programme Python vous créez ou déplacez des fichiers dans le système de fichiers, listez des fichiers sur le système de fichiers qui correspondent tous à une extension ou un modèle donnés, ou créez des chemins de fichiers appropriés du système d’exploitation basés sur des collections de chaînes de caractères. Bien que vous puissiez utiliser d’autres outils (comme le module os.path) pour accomplir plusieurs de ces tâches, le module pathlib vous permet d’effectuer ces opérations avec un degré de lisibilité élevé et une quantité minimale de code.

      Dans ce tutoriel, nous aborderons certaines des façons d’utiliser le module pathlib pour représenter et manipuler les chemins du système de fichiers.

      Conditions préalables

      Pour tirer le meilleur parti de ce tutoriel, il est recommandé d’être familiarisé avec la  programmation en Python 3. Vous pouvez consulter ces tutoriels pour obtenir les informations de base nécessaires :

      Construire des instances Path

      Le module pathlib fournit plusieurs classes, mais l’une des plus importantes est la classe Path. Les instances de la classe Path représentent un chemin d’accès à un fichier ou un répertoire du système de fichiers de notre ordinateur.

      Par exemple, le code suivant instancie une instance Path qui représente une partie du chemin d’accès à un fichier wave.txt :

      from pathlib import Path
      
      wave = Path("ocean", "wave.txt")
      print(wave)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      ocean/wave.txt

      from pathlib import Path rend la classe Path disponible pour notre programme. Ensuite, Path("ocean", "wave.txt") instance une instance nouvelle Path. L’impression de la sortie montre que Python a ajouté le séparateur approprié du système d’exploitation / entre les deux composants de chemin que nous lui avons donné : "ocean"et "wave.txt".

      Remarque : En fonction de votre système d’exploitation, votre résultat peut varier légèrement par rapport aux exemples de sorties présentés dans ce tutoriel. Si vous utilisez Windows, par exemple, votre résultat pour ce premier exemple ressemblera peut-être à oceanwave.txt.

      À présent, l’objet Path assigné à la variable wave contient un chemin relatif. En d’autres termes, ocean/wave.txt pourrait exister à plusieurs emplacements de notre système de fichiers. À titre d’exemple, il peut exister dans /Users/user_1/ocean/wave.txt ou /Users/user_2/research/ocean/wave.txt, mais nous n’avons pas préciséà quel endroit exactement nous faisons référence. Un chemin absolu, en revanche, renvoie sans ambiguïté à un seul emplacement du système de fichiers.

      Vous pouvez utiliser Path.home() pour obtenir le chemin absolu du répertoire d’accueil de l’utilisateur actuel :

      home = Path.home()
      wave_absolute = Path(home, "ocean", "wave.txt")
      print(home)
      print(wave_absolute)
      

      Si nous exécutons ce code, nous obtiendrons en gros le résultat suivant :

      Output

      /Users/sammy /Users/sammy/ocean/wave.txt

      Remarque : Comme mentionné précédemment, votre sortie varie en fonction de votre #système d’exploitation. Votre répertoire d’accueil, bien sûr, sera également différent de /Users/sammy.

      Path.home() renvoie une instance Path avec un chemin absolu vers le répertoire d’accueil de l’utilisateur actuel. Nous passons ensuite dans cette instance Path et les chaînes "ocean" et "wave.txt" dans un autre constructeur Path pour créer un chemin absolu vers le fichier wave.txt. La sortie montre que la première ligne est le répertoire d’accueil, et la deuxième ligne est le répertoire d’accueil plus ocean/wave.txt.

      Cet exemple illustre également une caractéristique importante de la classe Path : le constructeur Path accepte les chaînes et les objets Path préexistants.

      Examinons de plus près le support des chaînes et des objets Path dans le constructeur Path  :

      shark = Path(Path.home(), "ocean", "animals", Path("fish", "shark.txt"))
      print(shark)
      

      Si nous exécutons ce code Python, nous obtiendrons un résultat similaire au suivant :

      Output

      /Users/sammy/ocean/animals/fish/shark.txt

      shark est un Path vers un fichier que nous avons construit en utilisant les objets Path (Path.home() et Path("fish", "shark.txt")) et les chaînes ("ocean" et "animals"). Le constructeur Path traite intelligemment les deux types d’objets et les joint de manière propre en utilisant le séparateur du système d’exploitation approprié, dans ce cas /.

      Accéder aux attributs de fichier

      Maintenant que nous avons appris comment construire des instances Path, examinons comment vous pouvez utiliser ces instances pour accéder aux informations sur un fichier.

      Nous pouvons utiliser les attributs name et suffix pour accéder aux noms de fichier et aux suffixes :

      wave = Path("ocean", "wave.txt")
      print(wave)
      print(wave.name)
      print(wave.suffix)
      

      En exécutant ce code, nous obtiendrons un résultat similaire à ce qui suit :

      Output

      /Users/sammy/ocean/wave.txt wave.txt .txt

      Cette sortie montre que le nom du fichier à la fin de notre chemin est wave.txt et le suffixe de ce fichier est .txt.

      Les instances Path offrent également la fonction with_name, qui permet de créer de manière transparente un nouvel objet Path portant un nom différent :

      wave = Path("ocean", "wave.txt")
      tides = wave.with_name("tides.txt")
      print(wave)
      print(tides)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      ocean/wave.txt
      ocean/tides.txt
      

      Le code construit d’abord une instance Path qui pointe vers un fichier nommé wave.txt. Ensuite, nous appelons la méthode with_name sur wave pour renvoyer une seconde instance Path qui pointe vers un nouveau fichier nommé tides.txt. La partie du chemin correspondant au répertoire ocean/ reste inchangée, ce qui fait que le chemin final devient ocean/tides.txt

      Accéder aux ascendants

      Il est parfois utile d’accéder à des répertoires qui contiennent un chemin d’accès donné. Prenons un exemple :

      shark = Path("ocean", "animals", "fish", "shark.txt")
      print(shark)
      print(shark.parent)
      

      Si nous exécutons ce code, nous obtiendrons un résultat qui ressemble au suivant :

      Output

      ocean/animals/fish/shark.txt ocean/animals/fish

      L’attribut parent d’une instance Path renvoie l’ascendant le plus immédiat d’un chemin de fichier donné. Dans ce cas, il renvoie le répertoire qui contient le fichier shark.txt : ocean/animals/fish.

      Nous pouvons accéder à l’attribut parent plusieurs fois de suite pour remonter l’arbre d’ascendance d’un fichier donné :

      shark = Path("ocean", "animals", "fish", "shark.txt")
      print(shark)
      print(shark.parent.parent)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      ocean/animals/fish/shark.txt ocean/animals

      La sortie est similaire à la sortie précédente, mais maintenant nous avons traversé un autre niveau plus élevé en accédant à .parent une seconde fois. Deux répertoires plus haut que shark.txt nous avons le répertoire ocean/animals.

      Utiliser Glob pour lister les fichiers

      Il est également possible d’utiliser la classe Path pour lister les fichiers à l’aide de la méthode glob.

      Supposons que nous avons une structure de répertoire qui ressemblait à ceci :

      └── ocean
          ├── animals
          │   └── fish
          │       └── shark.txt
          ├── tides.txt
          └── wave.txt
      

      Le répertoire ocean contient les fichiers tides.txt et wave.txt. Nous avons un fichier nommé shark.txt imbriqué sous le répertoire ocean, un répertoire animals et un répertoire fish : ocean/animals/fish.

      Pour lister tous les fichiers .txt du répertoire ocean, nous pourrions dire :

      for txt_path in Path("ocean").glob("*.txt"):
          print(txt_path)
      

      Ce code donnerait un résultat du type :

      Output

      ocean/wave.txt ocean/tides.txt

      Le modèle glob "*.txt" trouve tous les fichiers se terminant par .txt. Comme l’exemple de code exécute ce glob dans le répertoire ocean, il renvoie les deux fichiers .txt du répertoire ocean : wave.txt et tides.txt.

      Remarque : Si vous souhaitez dupliquer les sorties indiquées dans cet exemple, vous devrez imiter la structure de répertoire illustrée ici sur votre ordinateur.

      Nous pouvons également utiliser la méthode glob de manière récursive. Pour lister tous les fichiers .txt du répertoire ocean et tous ses sous-répertoires, nous pourrions dire :

      for txt_path in Path("ocean").glob("**/*.txt"):
          print(txt_path)
      

      Si nous exécutons ce code, nous obtiendrions le résultat suivant :

      Output

      ocean/wave.txt ocean/tides.txt ocean/animals/fish/shark.txt

      La partie ** du modèle glob correspondra à ce répertoire et tous les répertoires en dessous, de manière récursive. Donc, non seulement nous avons les fichiers wave.txt et tides.txt dans la sortie, mais nous recevons également le fichier shark.txt qui a été imbriqué sous ocean/animals/fish.

      Calculer les chemin relatifs

      Nous pouvons utiliser la méthode Path.relative_to pour calculer les chemins par rapport aux autres. La méthode relative_to est utile lorsque, par exemple, vous souhaitez récupérer une partie d’un long chemin de fichier.

      Prenons le cas du code suivant :

      shark = Path("ocean", "animals", "fish", "shark.txt")
      below_ocean = shark.relative_to(Path("ocean"))
      below_animals = shark.relative_to(Path("ocean", "animals"))
      print(shark)
      print(below_ocean)
      print(below_animals)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      ocean/animals/fish/shark.txt animals/fish/shark.txt fish/shark.txt

      La méthode relative_to renvoie un nouvel objet Path relatif à l’argument donné. Dans notre exemple, nous calculons le Path d’accès à shark.txt par rapport au répertoire ocean, puis par rapport aux répertoires ocean et animals.

      Si la fonction relative_to ne peut pas calculer de réponse parce que nous lui fournissons un chemin non relié, elle génère une ValueError :

      shark = Path("ocean", "animals", "fish", "shark.txt")
      shark.relative_to(Path("unrelated", "path"))
      

      Nous obtiendrons une exception ValueError qui a été soulevée à partir de ce code et qui ressemblera à quelque chose comme ceci :

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/Python3.8/pathlib.py", line 899, in relative_to raise ValueError("{!r} does not start with {!r}" ValueError: 'ocean/animals/fish/shark.txt' does not start with 'unrelated/path'

      unrelated/path n’est pas une partie de ocean/animals/fish/shark.txt, Python n’a donc aucun moyen pour de calculer un chemin relatif pour nous.

      Conclusion

      Le module pathlib est une partie puissante de la bibliothèque standard Python qui nous permet de manipuler rapidement les chemins du système de fichiers sur n’importe quel système d’exploitation. Dans ce tutoriel, nous avons appris à utiliser certains des utilitaires clés de pathlib pour accéder aux attributs de fichier, lister les fichiers avec des modèles glob, et parcourir les fichiers et les répertoires parents.

      Le module pathlib propose des classes et des utilitaires supplémentaires que nous n’avons pas abordés dans ce tutoriel. Maintenant que vous disposez d’une base de référence, vous pouvez utiliser la documentation du module pathlib pour en savoir plus sur d’autres classes et utilitaires disponibles.

      Si vous souhaitez utiliser d’autres bibliothèques Python, consultez les tutoriels suivants :



      Source link