Python: crear un directorio anidado de forma segura

    Introducci贸n

    La manipulaci贸n de archivos es una de las habilidades m谩s importantes para dominar en cualquier lenguaje de programaci贸n, y hacerlo correctamente es de suma importancia. Cometer un error podr铆a causar un problema en su programa, otros programas que se ejecutan en el mismo sistema e incluso en el propio sistema.

    Los posibles errores pueden ocurrir debido a que el directorio principal no existe, o porque otros programas cambian archivos en el sistema de archivos al mismo tiempo, creando algo que se llama condici贸n de carrera.

    Una condici贸n de carrera (en este caso llamada carrera de datos) ocurre cuando dos o m谩s programas quieren crear un archivo con el mismo nombre en el mismo lugar. Si se produce este tipo de error, es muy dif铆cil de encontrar y corregir, ya que no es determinista, o simplemente, pueden suceder cosas diferentes dependiendo del momento exacto en que los dos corredores compiten por los datos.

    En este art铆culo, veremos c贸mo crear un subdirectorio en Python de forma segura, paso a paso. A partir de ahora, todo funcionar谩 en Mac, Linux y Windows.

    Creaci贸n segura de un directorio anidado con pathlib

    Hay muchas formas de crear un subdirectorio, pero quiz谩s la m谩s simple sea usar el pathlib m贸dulo. los pathlib El m贸dulo est谩 dise帽ado principalmente para ayudar a abstraer diferentes sistemas de archivos del sistema operativo y proporcionar una interfaz uniforme para trabajar con la mayor铆a de ellos.

    Gracias a 茅l, su c贸digo deber铆a ser independiente de la plataforma. Tenga en cuenta que esto solo funciona en versiones m谩s recientes de Python (3.5 y posteriores).

    Digamos que tenemos una ruta absoluta de un directorio que se nos ha dado como una cadena y deseamos crear un subdirectorio con un nombre dado. Creemos un directorio llamado OuterDirectory, y lugar InnerDirectory dentro de eso.

    Importaremos Path desde el pathlib m贸dulo, cree un Path objeto con la ruta deseada para nuestro nuevo archivo, y use el mkdir() m茅todo que tiene la siguiente firma:

    Path.mkdir(mode=0o777, parents=False, exist_ok=False)
    

    El siguiente fragmento de c贸digo hace lo que describimos anteriormente:

    from pathlib import Path # Import the module
    path = Path("/home/kristina/OuterDirectory/InnerDirectory") # Create Path object
    path.mkdir() # Cake the directory
    

    Si mkdir() no tiene 茅xito, no se crear谩 ning煤n directorio y se generar谩 un error.

    Opciones y errores de mkdir ()

    Si ejecuta el c贸digo sin crear el OuterDirectory, ver谩 el siguiente error:

    Traceback (most recent call last):
      File "makesubdir.py", line 3, in <module>
        path.mkdir()
      File "/home/kristina/anaconda3/lib/python3.7/pathlib.py", line 1230, in mkdir
        self._accessor.mkdir(self, mode)
    FileNotFoundError: [Errno 2] No such file or directory: '/home/kristina/OuterDirectory/InnerDirectory'
    

    O si InnerDirectory ya existe:

    Traceback (most recent call last):
      File "/home/kristina/Desktop/UNM/makesubdir.py", line 3, in <module>
        path.mkdir()
      File "/home/kristina/anaconda3/lib/python3.7/pathlib.py", line 1230, in mkdir
        self._accessor.mkdir(self, mode)
    FileExistsError: [Errno 17] File exists: '/home/kristina/OuterDirectory/InnerDirectory'
    

    Si ya existe un directorio, el error generado ser谩 FileExistsError, y si el padre no existe, el FileNotFoundError se levantar谩.

    Como no queremos que nuestro programa se rompa cada vez que encuentre un error como este, colocaremos este c贸digo en un bloque de prueba:

    from pathlib import Path 
    path = Path("/home/kristina/OuterDirectory/InnerDir") 
    try:
        path.mkdir() 
    except OSError:
        print("Failed to make nested directory")
    else:
        print("Nested directory made")
    

    Cuando se ejecuta, si el directorio se crea correctamente, la salida ser谩:

    Nested directory made
    

    Si nos encontramos con errores, se generar谩 lo siguiente:

    Failed to make a nested directory
    

    los mkdir() El m茅todo toma tres par谩metros: mode, parentsy exit_ok.

    • los mode par谩metro, si se da, combinado con umask indica qu茅 usuarios tienen privilegios de lectura, escritura y ejecuci贸n. De forma predeterminada, todos los usuarios tienen todos los privilegios que pueden no ser los que queremos si la seguridad es un problema. Tocaremos m谩s sobre esto m谩s adelante.
    • parents indica, en el caso de que falte el directorio principal, si el m茅todo:
    • Cree el directorio principal que falta en s铆 mismo (true)
    • O para generar un error, como en nuestro segundo ejemplo (false)
    • exist_ok especifica si el FileExistsError deber铆a aparecer si ya existe un directorio con el mismo nombre. Tenga en cuenta que este error seguir谩 apareciendo si el archivo del mismo nombre no es un directorio.

    Asignar privilegios de acceso

    Hagamos un directorio llamado SecondInnerDirectory donde solo el propietario tiene todos los privilegios de lectura, escritura y ejecuci贸n, dentro del inexistente SecondOuterDirectory:

    from pathlib import Path
    path = Path("/home/kristina/SecondOuterDirectory/SecondInnerDirectory")
    path.mkdir(mode = 0o007, parents= True, exist_ok= True)
    

    Esto deber铆a ejecutarse sin errores. Si navegamos al SecondOuterDirectory y verifique su contenido desde la consola as铆:

    $ ls -al
    

    Deber铆amos obtener la salida:

    total 12
    drwxrwxr-x  3 kristina kristina 4096 dec 10 01:26 .
    drwxr-xr-x 77 kristina kristina 4096 dec 10 01:26 ..
    d------r-x  2 kristina kristina 4096 dec 10 01:26 SecondInnerDirectory
    

    Bien, podemos ver que el directorio principal se cre贸 correctamente, pero los privilegios no son los esperados. El propietario carece de privilegios de escritura.

    El problema que tenemos aqu铆 es que umask no nos permite crear los privilegios deseados. Para evitar esto, ahorraremos umaskvalor original, c谩mbielo temporalmente y, finalmente, devu茅lvalo a su valor original utilizando el umask() m茅todo desde el m贸dulo OS. umask() devuelve el antiguo valor de umask.

    Reescribamos nuestro c贸digo para probar esto:

    from pathlib import Path
    import os 
    
    old_mask = os.umask(0) # Saving the old umask value and setting umask to 0
    
    path = Path("/home/kristina/SecondOuterDirectory/SecondInnerDirectory")
    path.mkdir(mode = 0o007, parents= True, exist_ok= True)
    
    os.umask(old_mask) # Reverting umask value
    

    Ejecutando este c贸digo y usando el ls -al comando nuevamente dar谩 como resultado la siguiente salida:

    total 12
    drwxrwxrwx  3 kristina kristina 4096 dec 10 01:45 . 
    drwxr-xr-x 77 kristina kristina 4096 dec 10 01:45 ..
    d------rwx  2 kristina kristina 4096 dec 10 01:45 SecondInnerDirectory
    

    Conclusi贸n

    Para manipular archivos de forma segura en muchos sistemas diferentes, necesitamos una forma s贸lida de manejar errores como las carreras de datos. Python ofrece un gran soporte para esto a trav茅s del pathlib m贸dulo.

    Los errores siempre pueden ocurrir cuando se trabaja con sistemas de archivos, y la mejor manera de lidiar con esto es configurando cuidadosamente los sistemas para detectar todos los errores que potencialmente pueden bloquear nuestro programa o causar otros problemas. Escribir c贸digo limpio hace que los programas sean duraderos.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *