Mostrando entradas con la etiqueta libreria. Mostrar todas las entradas
Mostrando entradas con la etiqueta libreria. Mostrar todas las entradas

martes, 18 de junio de 2024

Python (V) . Importar módulos de otras carpetas. Entornos virtuales python: Crear, activar, desactivar, listar librerias instaladas. requirememts.txt

 0. Introducción


Para poder hacer referencia a módulos que están en otra carpeta, mirar a ver si dicha referencia está en sys.path

para ver lo que hay en el sys.path 

import sys
print(sys.path)

Para añadir una ruta al syspath 

sys.path.append('/home/ximo/miruta')

Para ver como obtenemos las rutas del fichero hasta la raiz del disco:

from pathlib import Path

for path in Path(__file__).parents:
    print(str(path))

Y obtenemos 

/home/ximo/MyPython/prova03_ref_library/lib02
/home/ximo/MyPython/prova03_ref_library
/home/ximo/MyPython
/home/ximo
/home
/


1. Solución 1: Añadir la carpeta raiz al sys.path. Si funciona por línea de comandos.

Supongamos que la librería raiz es root y esta tiene dos hijas lib01 y lib02

Supongamos que lib01 tiene dos hijas lib01_01 y lib01_02 y cada hija tiene un fichero python

Supongamos que lib02 tiene una hija lib02_01

prova03_ref_library
    lib01
        lib01_01
            proga.py
        lib01_02
            progb.py
    lib02
        lib02_01
            progc.py

desde progc.py queremos llamar a los otros progs, para ello se propone buscar la ruta de la carpeta padre del proyecto (a la carpeta prova03_ref_library)  y a partir de ahí hacer los imports como lib01e.carpeta_hijo.modulo. Por ejemplo lib01.lib01_01.proga

Veamos la ruta absuluta de la carpeta que contien a progc.py

/home/ximo/MyPython/prova03_ref_library/lib02/lb02_01

Observamos que hay 2 saltos a carpetas padres para pasar de la carpeta lib02_01 a la prov03_ref_library por tanto la ruta del padre se obtiene con 

Path(__file__).parents[2]

Por tanto si añadimos la expresión anterior al sys.path, ya podemos referenciar los módulos y carpetas que cuelgan de ella.

# progc.py

from pathlib import Path
import sys

path_root2 = Path(__file__).parents[2]
sys.path.append(str(path_root2))

import lib01.lib01_01.proga as proga
import lib01.lib01_02.progb as progb

# O también
#from lib01.lib01_01 import proga as proga
#from lib01.lib01_02 import progb as progb

Ahora no tenemos ningún problema para hacer estas importaciones

OJO: A veces falla si desde otro módulo importamos un módulo que importa otro. Si importamos desde la misma carpeta hay que hacer el "try-except"

# ------Imprescindible para poder importar de otras carpetas (de basicutils)
import sys
from pathlib import Path
# ------Metemos tres niveles desde la caprta actual (o) hasta el abuelo (2)
for i in range(3):sys.path.append(str(Path(__file__).parents[i])) from basicutils import xmutils, xmexcel, xmpolish, xmsql, xmodoo try: # if in the same folder then needs a try and import directly from castillautils import xmcastilla except Exception as error: import xmcastilla # ------Fin imprescindible

2. Solución 2: Definir la carpeta raiz en el launch.json. NO FUNCIONA POR LINEA DE COMANDOS

Supongamos el ejemplo anterior

El nuevo launch.json será

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"env": {"PYTHONPATH":"${workspaceRoot}"}, // modify PYTHONPATH
}
]
}

Y el fichero se simplificaría

import lib01.lib01_01.proga as proga
import lib01.lib01_02.progb as progb

# O también
#from lib01.lib01_01 import proga as proga
#from lib01.lib01_02 import progb as progb

3. Usar entorno virtual python en la configuración

Se puede crear un entorno virtual de python de varias maneras. Una es de la forma tracicional de situarse mendiante una ventana de comandos dentro de la carpeta del proyecto y ejecutar

#Opcion 1: Crearlo en una ruta relativa
python3 -m venv my-venv
#ACTIVARLO
source my-venv/bin/activate

#ACTIVARLO en WINDOWS
my-venv\Scripts\activate.bat

#---------------SI HAY PROBLEMAS DE POR COPIAR UN PROYECTO ANTERIOR
#---------------SE RECOMIENDA TRABAJAR EN RUTAS ABSOLUTAS 
python3 -m venv ~/MyPython/control-presencia/my-venv
#ACTIVARLO
source ~/MyPython/control-presencia/my-venv/bin/activate

o por contra desde vscode darle a Crtl-Shit-p y seleccionar Python: create environment

Una vez creado se puede crear una configuración (launch.json) dándole al botón triangular y dándole al vínculo "create a launch.json"


Y se copia este fichero, donde se especifica una ruta apython. Ojo en windows hay que indicar el nombre de ejecutable (${workspaceRoot}/.venv/bin/python.exe) 

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Current File",
"type": "debugpy",
"python": "${workspaceRoot}/my-venv/bin/python", //Linux
"python": "${workspaceRoot}/my-venv/Scripts/python.exe", //Windows!!!
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"env": {"PYTHONPATH":"${workspaceRoot}"}, // modify PYTHONPATH
}
]
}

 Para desactivar el virtual environment

deactivate

Para ver que entorno actual tenemos

echo $VIRTUAL_ENV

4. Ver las librerias instaladas en un entorno virtual. "requirements.txt"

Se puede listar sin detalles, con detalles o incluso crear el requirements.txt

#Primeramente hay qie activar el entorno virtual
venv/bin/activate.sh

#listar sin detalles
pip list

#listar con detalles
pip freeze


#crear requirements.txt
peep freeze > requirements.txt







Python (IV). Crear librerías. Ejecutar las pruebas. Guardarlas en pypi

Ver también CodeCamp pero con cuidado pues no hace falta meter los ficheros __init__.py en cada carpeta!!! O ver tambien Medium 

Para crear una librería hay que realizar los siguientes pasos básicos:

1. Crear la carpeta padre del proyecto y crear un entorno virtual en ella

Creamos por ejemplo la carpeta mymodule, y dentro de ella creamos el entorno virtual virtualenv

#Creamos la carpeta padre y nos situamo dentro de ella
mkdir mymodule
cd mymodule

#Si no tenemos instalado para crear el entorno virtual lo instalamos
pip install virtualenv 

# Creamos el entormo virtual y lo activamos
python -m venv myenv
myenv\Scripts\activate.bat

2. Instal·lar en dicho entorno virtual las librerias wheel, setuptools y twine


#Nos situamos dentro de la carpeta padre e instalamos
pip install setuptools wheel twine


3. Creamos la estructura del proyecto: las subcarpetas ximo01, ximo02 y test

#Creamos las subcarpetas ximo01, ximo02 y test 
mkdir ximo01
mkdir ximo02
mkdir test
cd mymodule

#Si no tenemos instalado para crear el entorno virtual lo instalamos
mymodule/
│
├── mi_paquete/
│   ├── __init__.py
│   ├── subcarpeta1/
│   │   ├── __init__.py
│   │   ├── modulo1.py
│   │   └── modulo2.py
│   ├── subcarpeta2/
│   │   ├── __init__.py
│   │   ├── modulo3.py
│   │   └── modulo4.py
│   └── subcarpeta3/
│       ├── __init__.py
│       ├── modulo5.py
│       └── modulo6.py

4. Crear entorno virtual y activarlo


#Si no tenemos instalado para crear el entorno virtual lo instalamos
pip install virtualenv 

# Creamos el entormo virtual y lo activamos
python -m venv myenv
# lo activamos (windows)
myenv\Scripts\activate.bat
# lo activamos (linux)
source myvenv/bin/activate


3. Crear una carpeta dentro de ximolib01parent con el nombre que queramos que tenga la librería por jemplo ximollib01 

4. Entrar en la carpeta ximolib01parent y crear un entorno virtual de python y activarlo

python3 -m venv myvenv

source myvenv/bin/activate


Ojo: para que el entorno virtual se guarde en a configuración de vscode ver el siguiente post


5. Instalar en dicho entorno las librerías: wheel, setuptools y twine

pip install wheel setuptools twine

6. En la carpeta padre ximolib01parent crear estos ficheros

- setup.py (vacío)

- README.md (inicilamentre vacío, pero se puede dar información de la librería)

7. Situarse en ximolib01 (ximolib01parent/ximolib01) y crear estos ficheros:

 - _init__.py (inicilamente vacío)

- Uno o varios ficheros python (.py) de las funcionalidades a crear

 8. Situarse en ximolib01parent/tests y crear estos ficheros:

 - _init__.py (inicilamente vacío)

- Uno o varios ficheros python (.py) que comiencen con test_ de las funcionalidades a testear

 Veamos la estructura del proyecto

ximolib01parent
   └>setup.py
   └>README.md
   └>myvenv
   │   └>bin
   └>ximolib01
   │   └>__init_.py
   │   └>myfunctions01.py
   │   └>myfunctions02.py
   │   └>myfunctionsNN.py
   └>tests
         └>__init_.py
         └>test_myfun01.py    
         └>test_myfun02.py    

9. Ejemplo

Supongamos que solmente tenemos esta estructura simple de proyecto

ximolib01parent
   └>setup.py
   └>myvenv
   │   └>bin
   └>ximolib01
   │   └>__init_.py
    |    └>ximolib0101
   │    |    └>__init_.py
   │    |    └>formulas.py
    |    └>tests
    |           └>__init_.py
    |           └>test_formulas.py    

Veamos el fichero formulas.py

import math

def area_circle(radius):
    return math.pi * radius ** 2

def area_square(side):
    return side ** 2

def area_rectangle(length, width):
    return length * width

Veamos el contenido del fichero test_formulas.py. Para ello debemos observar que para pasar de la carpeta tests a la carpetaximolib01parent  debemos hacer 2 salto2, por tanto en el pathlib incluimos 2 saltos

import unittest
from pathlib import Path

# ------Imprescindible para poder importar de otras carpetas (de basicutils)
import sys
saltos=2  # Solo hay un salto de la carpeta tests a la carpeta ximolib01parent
from pathlib import Path
for i in range(saltos):sys.path.append(str(Path(__file__).parents[i]))
from ximolib01 import formulas
# ------Fin imprescindible


class TestFigures(unittest.TestCase):
    
    def test_circle_area(self):
        self.assertEqual(circle.circle_area(1), 3.1415926,'wrong circle area') 

    def test_rectangle_area(self):
        self.assert rectangle.rectangle_area(1, 2) == 2

#Execute test
if __name__ == '__main__':
	unittest.main()

Observar en el test que importamos así 

import sys
saltos=2  # Solo hay un salto de la carpeta tests a la carpeta ximolib01parent
from pathlib import Path
for i in range(saltos):sys.path.append(str(Path(__file__).parents[i]))
from ximolib01 import formulas


EJECUCIÓN DE LOS TESTS

Podemos ejecutarlos de 3 maneras:

  1. Mediante el triángulo de vs code
  2. En el terminal de vscode( y comprobando que estamos en el entorno virtual) nos situamos dentro de la carpeta ximolib01 (que es el padre inminente de la carpeta tests) y ejecutamos: 
     python -m unittest tests/test_formula.py
    

  3. En el terminal de vscode( y comprobando que estamos en el entorno virtual) nos situamos dentro de la carpeta ximolib01 (que es el padre inminente de la carpeta tests) y ejecutamos:
     python -m unittest discover -s tests
    

En la tercera opción le pedimos al sistema que busquer TODOS los tests y los ejecute

10. Fichero ximolib01parent/setup.py


from setuptools import setup, find_packages

VERSION = '0.0.1'
DESCRIPTION = 'My first python library'
LONG_DESCRIPTION = 'This is my first library and I am very proud of it'

# Setting up
setup(
# the name must match the folder name 'ximolib01'
name="ximolib01",
version=VERSION,
author="Ximo Dante",
author_email="<ximodane@gmail.com>",
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
packages=find_packages(),
install_requires=['xmltodict'], # add any additional packages that
# needs to be installed along with your package. Eg: 'caer'
test_requires=[],
keywords=['python', 'wsdl'],
classifiers= [
"Development Status :: 3 - Alpha",
"Intended Audience :: Education",
"Programming Language :: Python :: 3",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Operating System :: Linux :: Ubuntu",
]
)


Los parámetros son:

install_requires indica la lista de librerías que se requieren previamente 

test_requires indica la lista de librerías que se requieren previamente solo para realizar los tests


11.Construir (build) la librería

Situarse en ximo01libparent y ejecutar en un shell


python setup.py bdist_wheel

y el fichero con extensión .whl (de wheel) se creará en la carpeta dist

12. Instalar la librería localmente


pip install /path/to/wheelfile.whl

13. Instalarla en https://pypi.org

13.1 Obtener una clave API de https://pypi.org/

Todo parece sencillo hasta que aparece un código QR que hay que leer con el authentictor de google del móvil y ya da un token enorme que hay que guardar

12. Ejecutar el builfd y la instalación

Ojo: utilizar setup está deprecado!!!!

python setup.py sdist bdist_wheel  # Ya hecho antes

twine upload dist/*

Y nos pide el token anterior


Y además nos da una url donde ver la librería

https://pypi.org/project/ximolib01/0.0.1/

13. Instalar la librería

Ya la tenemos disponible en el repositorio pypi para instalar

 pip install ximolib01