Casos de uso para:
Compatibilidad poetry vs buildpacks, gracias!
https://github.com/heroku/heroku-buildpack-python/issues/796
¿Por qué todavía seguimos diferenciando entre librería y aplicación? ¿Cuándo estará disponible para su uso general lo especificado en el PEP631? ¿Qué es un Platypus?
Cómo referenciar paquetes privados para que puedan instalarse con pip en distintos entornos de CI/CD
Integración y despliegue continuo, cómo organizarlo en grandes empresas, artefactory, Jenkins, etc. convivencia con otros proyectos, puesta en producción.
Instalación para Alpine linux mini root fs para containers!
Como instalar una libreria de manera agnostica con el host?, me refiero a instalar una libreria en windows pero con arquitectura x86 linux.
Ya que tuve un proyecto y la unica solucion fue descargar una ISO de un ubuntu server x86 y ahi hacer el pip install (en ese caso fue PARAMIKO) ya que donde yo ejecutaba mi Script tenian ese SO y yo desarrollaba en una MAC y me marcaba error por los HEADERS del OS.
Sígueme! https://github.com/astrojuanlu/
✨✨✨ Instale el paquete deseado en dos sencillos pasos: ✨✨✨
$ source .venv/bin/activate
(.venv) $ python -m pip install ipython
«¿Y no había otra cosa que se llamaba
easy
...?»
Hagamos como que nunca existió 😇
«Sí, pero... ¡es que yo lo quiero en uno!»
Mal menor: pip nuevo ⚠️⚠️⚠️
$ pip install ipython # Hmmm...
Por defecto se instala en ${HOME}/.local/lib
(a escondidas se ha usado --user
). ¿Queremos eso?
In [1]: import sys
In [2]: sys.prefix
Out[2]: '/usr'
In [3]: import urllib3
In [4]: urllib3.__file__
Out[4]: '/usr/lib/python3/dist-packages/urllib3/__init__.py'
In [3]: import IPython
In [4]: IPython.__file__
Out[4]: '/home/juanlu/.local/lib/python3.8/site-packages/IPython/__init__.py'
Ya tenemos dos localizaciones distintas 😨
«Sí, pero... ¡es que yo lo quiero en uno!»
Catástrofe en ciernes: pip viejo 🚨🚨🚨
$ pip install urllib3 # Hmmm...
[Errno 13] Permission denied: '/usr/lib/python3.8'
$ sudo pip install urllib3 # NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
sudo pip install
🚫 puede desestabilizar dependencias críticas de tu sistemaOpciones:
venv
https://docs.python.org/3/library/venv.html ¡en la biblioteca estándar desde Python 3.3 (2012)!virtualenv
https://pypi.org/project/virtualenv/, más rápido y flexible (recientemente resucitado por Bernát Gábor)Otras opciones:
virtualenvwrapper
no tiene actividad desde febrero de 2019 😓 (¡aunque aún funciona!)pyenv
rompe el $PATH
y algunos scripts 😓 https://github.com/pyenv/pyenv/issues/1112Pipenv
trata de hacer demasiadas cosas, avanza con mucho esfuerzo, y tiene ciertos problemasPoetry
nunca lo usé 🤔¿¿Y qué pasa con Alpine??
$ docker run -it --rm --name pip-wheel python:3.8-alpine sh
/ # python -m pip install numpy
Collecting numpy
Downloading numpy-1.20.1.zip (7.8 MB)
|████████████████████████████████| 7.8 MB 10.8 MB/s
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing wheel metadata ... error
ERROR: Command errored out with exit status 1:
command: /usr/local/bin/python /usr/local/lib/python3.8/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmpzz6m5yah
cwd: /tmp/pip-install-9mlwuba9/numpy
Complete output (226 lines):
...
File "numpy/core/setup.py", line 676, in get_mathlib_info
raise RuntimeError("Broken toolchain: cannot link a simple C program")
RuntimeError: Broken toolchain: cannot link a simple C program
🤯
wheel
que resuelve este problema ofreciendo un Built DistributionEl formato del nombre del archivo indica la compatibilidad:
{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
Es decir:
distribution
: Nombre del paquete (Django
, numpy
)version
: Versión (compatible con el PEP 440)python tag
y abi tag
: Implementación de Python (cp38
, pp372-pypy3_72
)platform
: PlataformaPor ejemplo:
numpy-1.20.1-cp38-cp38-manylinux1_x86_64.whl
..."many what"???
For Linux, the situation is much more delicate.
PEP 513 -- A Platform Tag for Portable Linux Built Distributions
glibc
manylinux1
manylinux2010
(CentOS 6), manylinux2014
(CentOS 7), y vendrán másglibc
, sino musl
! 😭😭😭musl
, pero de momento hay que usar métodos alternativosEn resumen:
python -m pip install
+ venv
= ❤️✨✨✨ Especifique las dependencias deseadas en dos sencillos pasos: ✨✨✨
(.venv) $ echo "django<3" > requirements.in
(.venv) $ python -m pip install pip-tools && pip-compile
pip-compile toma como entrada un archivo requirements.in
y produce un requirements.txt
con todas las versiones fijadas:
(.venv) $ cat requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile
#
django==2.2.19
# via -r requirements.in
pytz==2021.1
# via django
sqlparse==0.4.1
# via django
Perfecto para tener un entorno reproducible 💯
Una vez fijadas, ¡por defecto no se actualizan!
(.venv) $ echo "django" > requirements.in
(.venv) $ pip-compile
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile
#
django==2.2.19
# via -r requirements.in
pytz==2021.1
# via django
sqlparse==0.4.1
# via django
Se acabaron los pipelines rotos por nuevas versiones ✨
Solo se actualizan si lo pedimos:
(.venv) $ pip-compile -P django
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile
#
asgiref==3.3.1
# via django
django==3.1.7
# via -r requirements.in
pytz==2021.1
# via django
sqlparse==0.4.1
# via django
Y, para poner nuestro entorno al día:
(.venv) $ pip-sync
Collecting asgiref==3.3.1
Using cached asgiref-3.3.1-py3-none-any.whl (19 kB)
Collecting django==3.1.7
Using cached Django-3.1.7-py3-none-any.whl (7.8 MB)
Collecting pytz==2021.1
Using cached pytz-2021.1-py2.py3-none-any.whl (510 kB)
Collecting sqlparse==0.4.1
Using cached sqlparse-0.4.1-py3-none-any.whl (42 kB)
Installing collected packages: sqlparse, pytz, asgiref, django
Successfully installed asgiref-3.3.1 django-3.1.7 pytz-2021.1 sqlparse-0.4.1
...que es casi lo mismo que hacer:
(.venv) $ python -m pip install -r requirements.txt
Requirement already satisfied: asgiref==3.3.1 in ./.venv/lib/python3.8/site-packages (from -r requirements.txt (line 7)) (3.3.1)
Requirement already satisfied: django==3.1.7 in ./.venv/lib/python3.8/site-packages (from -r requirements.txt (line 9)) (3.1.7)
Requirement already satisfied: pytz==2021.1 in ./.venv/lib/python3.8/site-packages (from -r requirements.txt (line 11)) (2021.1)
Requirement already satisfied: sqlparse==0.4.1 in ./.venv/lib/python3.8/site-packages (from -r requirements.txt (line 13)) (0.4.1)
😍😍😍
Otras alternativas:
Pipenv
Poetry
setup.py
~ ¡Calma! No hemos llegado aún, y además no es exactamente para estoEn resumen:
pip-compile
+ pip-sync
(o simplemente pip
) = ❤️requirements.txt
, ¡usémoslo!✨✨✨ Distribuya su código en tres sencillos pasos: ✨✨✨
(.venv) $ cat saludo.py # Este no cuenta ;)
"""
Un saludo
"""
__version__ = "0.1.0"
print("¡Hola, mundo!")
(.venv) $ python -m pip install flit && flit init
(.venv) $ python -m pip install build && python -m build
(.venv) $ python -m pip install twine && twine upload dist/*
Pero, ¿qué es flit, y qué está pasando aquí?
(.venv) $ ls
dist LICENSE pyproject.toml saludo.py
¡No hay setup.py
! 😮 Rebobinemos por un momento...
setup.py
para especificar los metadatos del proyectofrom setuptools import setup
setup(
...
setuptools
tiene ejem algunos detractoressetuptools
) y el frontend (pip
)«¿No había otra cosa que se llamaba...?»
Elevemos una oración por su alma 😇
pyproject.toml
[build-system]
requires = ["setuptools", "wheel"] # PEP 518
build-backend = "setuptools.build_meta" # PEP 517
(Para más información, Brett Cannon lo explica muy bien)
Por tanto, en lugar de hacer el antiguo:
(.venv) $ python setup.py install # Buuuuuuuuuuuuuu 👎
¡Ahora podemos hacer esto!
(.venv) $ python -m pip install .
Y pip
ya sabe hacer el resto 🎉
De paso, ¡python -m pip uninstall
funciona! ✨
Insisto: dejad de ejecutar setup.py
. Haced caso a Paul, es muy majete.
Equivalencias:
python setup.py install
-> python -m pip install .
python setup.py develop
-> python -m pip install -e .
("instalaciones editables", ¡muy útiles!)python setup.py sdist bdist_wheel
-> python -m build
(en seguida lo explicamos)setup.py
son endiablados 😵 (por ejemplo el de SciPy) - por suerte, setuptools
permite todo esto y mássetuptools
, es recomendable usar metadatos estáticos en setup.cfg
:[metadata]
name = mypackage
version = 0.0.1
[options]
packages = mypackage
install_requires =
requests
importlib; python_version == "2.6"
Y para eso tenemos flit
:
(.venv) $ flit init
Module name [saludo]:
Author [Juan Luis Cano Rodríguez]:
Author email [hello@juanlu.space]:
Home page [https://github.com/astrojuanlu/python-saludo]:
Choose a license (see http://choosealicense.com/ for more info)
1. MIT - simple and permissive
2. Apache - explicitly grants patent rights
3. GPL - ensures that code based on this is shared with the same terms
4. Skip - choose a license later
Enter 1-4 [1]:
Written pyproject.toml; edit that file to add optional extra info.
(.venv) $ cat pyproject.toml
[build-system]
requires = ["flit_core >=2,<4"]
build-backend = "flit_core.buildapi"
[tool.flit.metadata]
module = "saludo"
author = "Juan Luis Cano Rodríguez"
author-email = "hello@juanlu.space"
home-page = "https://github.com/astrojuanlu/python-saludo"
classifiers = [ "License :: OSI Approved :: MIT License",]
¡Y nada más! ✨
Y ha llegado el momento de la verdad: generamos nuestras Source Distribution y Built Distribution usando build
:
(.venv) $ python -m build
(.venv) $ ls dist/
saludo-0.1.0-py2.py3-none-any.whl saludo-0.1.0.tar.gz
(¡o al PyPI interno de tu empresa!)
«¿Significa eso que, dependiendo de si elijo
setuptools
,flit
, opoetry
, tengo que especificar los metadatos de una manera totalmente distinta?»
Sí 😓
...¡pero no por mucho tiempo!
pyproject.toml
setuptools
, flit
, y poetry
en mente!flit
hace pocos días 😍Alternativas:
Poetry
!enscons
(poca actividad en GitHub)scikit-build
o mesonpep517
para código con extensiones en C, C++, FORTRAN u otrosEn resumen:
flit
+ build
+ twine
= ❤️setuptools
pyproject.toml
será parecido en todos✨ Resumen del resumen: https://github.com/astrojuanlu/cookiecutter-pylib ✨
pip
! 🎉 Y nunca jamás nombrar a easy_install
🚫venv
! 🎉 Y nunca jamás hacer sudo pip install
🚫flit
! 🎉 Y, si lo necesitas, puedes seguir usando setuptools
✔️<hello@juanlu.space>