<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 El otro día estuvimos hablando de la biblioteca collections, una joya dentro de la librería estándar. Hoy vamos a hablar de una nueva biblioteca que se incluyó en la versión 3.4 de CPython llamada pathlib. 
Solo python 3, actualízate!!!
Esta biblioteca nos da la posibilidad de usar clases para trabajar con las rutas del sistema de ficheros con una serie de métodos muy interesantes.
Algunas utilidades para configurar el problema
Vamos a crear un par de funciones que nos permiten crear y borrar un directorio de pruebas para poder reproducir el ejemplo de forma sencilla
Step1:  Si ahora ejecutamos la función crea_directorio
Step2:  Nos debería quedar una estructura parecida a lo siguiente
Step3:  Nuestra nueva estructura de ficheros debería ser la siguiente
Step4:  Y vuelvo a crear la estructura de ficheros inicial
Step5:  Después de la limpieza vamos a afrontar el problema usando pathlib.
El mismo ejemplo con pathlib
Primero importamos la librería y, como bonus, creamos una función que hace lo mismo que la función borra_directorio pero usando pathlib, que llamaremos borra_directorio_pathlib
Step6:  La anterior función con shutil es un poco más sencilla que con pathlib. Esto es lo único que hecho de menos en pathlib, algunas utilidades de shutil que vendrían muy bien de serie. Algo negativo tenía que tener.
En la anterior función, borra_directorio_pathlib, podemos ver ya algunas cositas de pathlib.
p = Path('.', 'pybonacci_probando_pathlib') nos crea una ruta que ahora es un objeto en lugar de una cadena. Dentro del bucle usamos el método iterdir que nos permite iterar sobre los directorios de la ruta definida en el objeto p. el iterador nos devuelve nuevos objetos que disponen de métodos como is_dir, que nos permite saber si una ruta se refiere a un directorio, o unlink, que nos permite eliminar el fichero o enlace. Por último, una vez que no tenemos ficheros dentro del directorio definido en p podemos usar el método rmdir para eliminar la carpeta.
Ahora veamos cómo realizar lo mismo que antes usando pathlib, es decir, mover los ficheros .py a la carpeta python que hemos de crear.
Step7:  Nuevamente, nuestra estructura de ficheros debería ser la misma que antes
<ASSISTANT_TASK:>
Python Code:
import os
import glob
import shutil
from random import randint, choice, seed
from string import ascii_letters
# función que nos crea un directorio de prueba en
# el mismo directorio del notebook
def crea_directorio():
    seed(1)
    base = os.path.join(os.path.curdir,
                        'pybonacci_probando_pathlib')
    os.makedirs(base, exist_ok = True)
    for i in range(0, randint(3, 5)):
        folder = ''.join([choice(ascii_letters) for _ in range(4)])
        path = os.path.join(base, folder)
        os.makedirs(path, exist_ok = True)
        for j in range(0, randint(2, 5)):
            ext = choice(['.txt', '.py', '.html'])
            name = ''.join([choice(ascii_letters) for _ in range(randint(5, 10))])
            filename = name + ext
            path2 = os.path.join(path, filename)
            open(path2, 'w').close()
# Función que nos permite hacer limpieza            
def borra_directorio():
    base = os.path.join(os.path.curdir,
                        'pybonacci_probando_pathlib')
    shutil.rmtree(base + os.path.sep)
Explanation: El otro día estuvimos hablando de la biblioteca collections, una joya dentro de la librería estándar. Hoy vamos a hablar de una nueva biblioteca que se incluyó en la versión 3.4 de CPython llamada pathlib. 
Solo python 3, actualízate!!!
Esta biblioteca nos da la posibilidad de usar clases para trabajar con las rutas del sistema de ficheros con una serie de métodos muy interesantes.
Algunas utilidades para configurar el problema
Vamos a crear un par de funciones que nos permiten crear y borrar un directorio de pruebas para poder reproducir el ejemplo de forma sencilla:
End of explanation
crea_directorio()
Explanation: Si ahora ejecutamos la función crea_directorio:
End of explanation
# Suponemos que ya has creado los directorios y ficheros
# de prueba usando crea_directorio()
# recolectamos todos los ficheros *.py con sus rutas
base = os.path.join(os.path.curdir,
                    'pybonacci_probando_pathlib')
ficheros_py = glob.glob(os.path.join(base, '**', '*.py'))
# creamos la carpeta 'python' 
# dentro de 'pybonacci_probando_pathlib'
os.makedirs(os.path.join(base, 'python'), exist_ok = True)
# y movemos los ficheros a la nueva carpeta 'python'
for f in ficheros_py:
    fich = f.split(os.path.sep)[-1]
    shutil.move(f, os.path.join(base, 'python'))
Explanation: Nos debería quedar una estructura parecida a lo siguiente:
pybonacci_probando_pathlib/
├── KZWe
│   ├── CrUZoLgubb.txt
│   ├── IayRnBUbHo.txt
│   ├── WCEPyYng.txt
│   └── yBMWX.py
├── WCFJ
│   ├── GBGQmtsLFG.html
│   ├── PglOUshVv.py
│   └── RoWDsb.py
└── zLcE
    ├── AQlxJSXR.html
    ├── fCQGgXk.html
    └── xFUbEctT.html
Ejemplo usando lo disponible hasta hace poco
Pensemos en un problema que consiste en identificar todos los ficheros .py disponibles en determinada ruta y dejarlos en una nueva carpeta, que llamaremos python, todos juntos eliminándolos de la carpeta original en la que se encuentren.
De la forma antigua esto podría ser así:
End of explanation
borra_directorio()
Explanation: Nuestra nueva estructura de ficheros debería ser la siguiente:
pybonacci_probando_pathlib/
├── KZWe
│   ├── CrUZoLgubb.txt
│   ├── IayRnBUbHo.txt
│   └── WCEPyYng.txt
├── python
│   ├── PglOUshVv.py
│   ├── RoWDsb.py
│   └── yBMWX.py
├── WCFJ
│   └── GBGQmtsLFG.html
└── zLcE
    ├── AQlxJSXR.html
    ├── fCQGgXk.html
    └── xFUbEctT.html
En el anterior ejemplo hemos tenido que usar las bibliotecas glob, os y shutil para poder realizar una operación relativamente sencilla. Esto no es del todo deseable porque he de conocer tres librerías diferentes y mi cabeza no da para tanto.
Limpieza
Me cargo la carpeta pybonacci_probando_pathlib para hacer un poco de limpieza:
End of explanation
crea_directorio()
Explanation: Y vuelvo a crear la estructura de ficheros inicial:
End of explanation
from pathlib import Path
def borra_directorio_pathlib(path = None):
    if path is None:
        p = Path('.', 'pybonacci_probando_pathlib')
    else:
        p = path
    for i in p.iterdir():
        if i.is_dir():
            borra_directorio_pathlib(i)
        else:
            i.unlink()
    p.rmdir()
Explanation: Después de la limpieza vamos a afrontar el problema usando pathlib.
El mismo ejemplo con pathlib
Primero importamos la librería y, como bonus, creamos una función que hace lo mismo que la función borra_directorio pero usando pathlib, que llamaremos borra_directorio_pathlib:
End of explanation
# recolectamos todos los ficheros *.py con sus rutas
p = Path('.', 'pybonacci_probando_pathlib')
ficheros_py = p.glob('**/*.py')
# creamos la carpeta 'python' dentro de 'pybonacci_probando_pathlib'
(p / 'python').mkdir(mode = 0o777, exist_ok = True)
# y copiamos los ficheros a la nueva carpeta 'python'
for f in ficheros_py:
    target = p / 'python' / f.name
    f.rename(target)
Explanation: La anterior función con shutil es un poco más sencilla que con pathlib. Esto es lo único que hecho de menos en pathlib, algunas utilidades de shutil que vendrían muy bien de serie. Algo negativo tenía que tener.
En la anterior función, borra_directorio_pathlib, podemos ver ya algunas cositas de pathlib.
p = Path('.', 'pybonacci_probando_pathlib') nos crea una ruta que ahora es un objeto en lugar de una cadena. Dentro del bucle usamos el método iterdir que nos permite iterar sobre los directorios de la ruta definida en el objeto p. el iterador nos devuelve nuevos objetos que disponen de métodos como is_dir, que nos permite saber si una ruta se refiere a un directorio, o unlink, que nos permite eliminar el fichero o enlace. Por último, una vez que no tenemos ficheros dentro del directorio definido en p podemos usar el método rmdir para eliminar la carpeta.
Ahora veamos cómo realizar lo mismo que antes usando pathlib, es decir, mover los ficheros .py a la carpeta python que hemos de crear.
End of explanation
borra_directorio_pathlib()
Explanation: Nuevamente, nuestra estructura de ficheros debería ser la misma que antes:
pybonacci_probando_pathlib/
├── KZWe
│   ├── CrUZoLgubb.txt
│   ├── IayRnBUbHo.txt
│   └── WCEPyYng.txt
├── python
│   ├── PglOUshVv.py
│   ├── RoWDsb.py
│   └── yBMWX.py
├── WCFJ
│   └── GBGQmtsLFG.html
└── zLcE
    ├── AQlxJSXR.html
    ├── fCQGgXk.html
    └── xFUbEctT.html
Repasemos el código anterior:
Hemos creado un objeto ruta p tal como habíamos visto antes en la función borra_directorio_pathlib. Este objeto ahora dispone de un método glob que nos devuelve un iterador con lo que le pidamos, en este caso, todos los ficheros con extensión .py. En la línea (p / 'python').mkdir(mode = 0o777, exist_ok = True) podemos ver el uso de / como operador para instancias de Path. El primer paréntesis nos devuelve una nueva instancia de Path que dispone del método mkdir que hace loque todos esperáis. Como ficheros_py era un iterador podemos usarlo en el bucle obteniendo nuevas instancias de Path con las rutas de los ficheros python que queremos mover. en la línea donde se define target hacemos uso del atributo name,que nos devuelve la última parte de la ruta. Por último, el fichero con extensión .py definido en el Path f lo renombramos a una nueva ruta, definida en target.
Y todo esto usando una única librería!!!
Echadle un ojo a la documentación oficial para descubrir otras cositas interesantes.
Si además de usar una única librería usamos parte de la funcionalidad de shutil tenemos una pareja muy potente, pathlib + shutil.
Limpieza II
Y para terminar, limpiamos nuestra estructura de ficheros pero usando ahora la función borra_directorio_pathlib que habíamos creado pero no usado aún:
End of explanation
<END_TASK>