jueves, 30 de julio de 2015

Empaquetado y distribución de proyectos Python (y II)


Introducción


Si hemos desarrollado un módulo/paquete/aplicación Python que creemos puede resultar de utilidad a otras personas, una alternativa para conseguir que llegue a los potenciales interesados consiste en empaquetar el proyecto y en subirlo con posterioridad al repositorio PyPI de la comunidad Python.

Para dar a conocer los nuevos proyectos, PyPI en su página principal, va presentando a sus visitantes los últimos desarrollos que se han publicado con una breve reseña. Además, incorpora un buscador y un navegador de paquetes (browse packages) para facilitar el acceso a los miles de desarrollos que hay registrados.  

Si tenemos el propósito de compartir un proyecto y la fase de codificación, en principio, ha concluido antes de comenzar a empaquetar tendremos que recopilar alguna información importante entre la que se encuentra el nombre del proyecto, su versión (seguir recomendaciones PEP-400), tipo de software, tipo de licencia (GPL V3, MIT, etc), público al que va dirigido, estado del desarrollo (Alfa, Beta, Producción/Estable, etc.), versiones de Python que soporta (2.x/3.x) y las dependencias con otros paquetes, si existen.

Evidentemente, las personas que mantienen PyPI han pensado en todo y ofrecen un índice de clasificación con información normalizada que tendremos que utilizar para registrar con éxito nuestro proyecto. Esto evita que los desarrolladores "inventemos" más de lo debido y ordena con cierto criterio todos los proyectos del repositorio.

Después, antes de proceder al empaquetado tendremos que organizar en una carpeta, siguiendo un orden preestablecido, todos los archivos del proyecto, que básicamente son los que contienen el código fuente y otros que se podrán crear en un editor de textos como el instalador, archivos de configuración, la información que debe aparecer en PyPI, archivos con ejemplos, etcétera.

Para finalizar, tan sólo será necesario registrarse como usuario de PyPI antes de subir el proyecto y ponerlo a disposición de toda la comunidad.


Requerimientos


Una vez que pip y setuptools estén disponibles en nuestra instalación Python, para poder empaquetar y distribuir un proyecto es necesario contar con los módulos wheel y twine.

Wheel se utiliza para empaquetar y twine se utiliza para subir los proyectos a PyPI.

Para instalar wheel y twine (si no estuvieran disponibles):

$ pip3 install wheel
$ pip3 install twine


Caso práctico de empaquetado y distribución de un proyecto


Para explicar, paso a paso, todo el proceso nos vamos a basar en un módulo Python llamado Pysaurio, que hemos desarrollado, que permite buscar y extraer información dispersa en múltiples archivos de texto con la posibilidad de guardar el resultado en un único archivo, por ejemplo, del tipo CSV.

El código fuente se encuentra en un único archivo .py y contiene una clase llamada Pysaurio con varios métodos que podremos utilizar en cualquier programa una vez que importemos el módulo:

from pysaurio import Raptor


Para organizar todos los archivos del proyecto hemos creado una carpeta llamada 'pysaurio' con el siguiente contenido:

Pysaurio/
  • setup.py: script de instalación.
  • setup.cfg: archivo de configuración del script de instalación.
  • README.rst: archivo de texto (ReStructuredText) con una descripción del proyecto.
  • README.md: archivo de texto (Markdown) con una descripción del proyecto.
  • MANIFEST.in: archivo con lista de archivos que se incluyen/excluyen del proyecto.
  • LICENSE.txt: archivo con la licencia elegida para el proyecto.
  • pysaurio (carpeta del paquete): fuentes del módulo.
  • examples (carpeta con ejemplos): ejemplos (.py) y archivos de texto para pruebas.

Otros archivos y directorios que podrían haberse incluido:
  • REQUIREMENTS.txt: Listado de dependencias que deben satisfacerse.
  • CHANGELOG.txt: Cambios incorporados al proyecto ordenados cronológicamente por lanzamientos.
  • ROADMAP.txt: Mejoras previstas en versiones futuras del proyecto.
  • Carpetas para TEST, DATOS complementarios, imágenes, scripts, etc.

Descripción de archivos


setup.py

Este archivo que depende de setuptools se encuentra en el directorio raíz del proyecto. Es el más importante y tiene dos funciones principales:
  • Sirve para describir y configurar diversos aspectos del proyecto. El script contiene una función global llamada setup() cuyos argumentos definen los detalles específicos de un proyecto.: autor, versión, descripción, etc.
  • Se puede ejecutar desde la línea de comandos para realizar tareas relacionadas con la propia gestión del paquete. Para consultar las opciones disponibles: python3 setup.py --help-commands
 
Contenido del archivo setup.py:

from setuptools import setup
from codecs import open
from os import path

here = path.abspath(path.dirname(__file__))

with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
    long_description = f.read()

setup(
    name='pysaurio',
    version='0.2.0',
    description='A tool for searching & extracting information...',
    long_description=long_description,
    url='https://pypi.python.org/pypi/pysaurio',
    author='Antonio',
    author_email='dir@correo.com',
    license='GNU GPLv3',
    classifiers=[
        'Development Status :: 4 - Beta',
        'Intended Audience :: Developers',
        'Intended Audience :: System Administrators',
        'Topic :: Utilities',
        'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
        'Programming Language :: Python :: 3',
    ],
    keywords='pysaurio search extract text csv',
    packages=['pysaurio'],
    package_dir = {'pysaurio':'pysaurio'},
)


Parámetros de la función setup():

  • name: Nombre del paquete. Es recomendable buscar en Pypi que el nombre no está en uso.
  • version: Versión del paquete.
  • description: Descripción breve del proyecto.
  • long_description: Descripción larga del proyecto que se leerá del archivo "README.rst".
  • url: Dirección web del proyecto.
  • author: Nombre o nick del autor.
  • author_email: Dirección de correo electrónico del autor.
  • license: Licencia del proyecto.
  • classifiers: Lista de categorías para clasificar el paquete
  • keywords: Lista de palabras que describen el proyecto. Se pueden usar para encontrarlo.
  • packages: Lista de paquetes Python que se incluirán en el instalable del proyecto.
  • package_dir: Diccionario con el nombre de los paquetes incluidos y sus directorios.

Otros usos y otros parámetros que no se incluyen en el caso práctico pero que podrían utilizarse en otros proyectos.
  • download_url: Página de descargas externa a Pypi.
  • packages: Con la función find_packages() es posible encontrar los paquetes a incluir en el instalable. El argumento 'exclude' puede utilizarse para incluir todos excepto los especificados en la lista: packages=find_packages(exclude=['paquete1']). Requiere importar el módulo find_packages de setuptools.
  • install_requires: Lista de dependencias. Esta lista se puede exportar previamente a un archivo REQUIREMENTS.txt que puede ser leído como el parámetro long_description.
  • package_data: Diccionario con archivos que acompañan al proyecto para instalar dentro del paquete. package_data = {'archivo': ['archivo.dat']}
  • data_files: Lista de archivos que acompañan al proyecto para instalar en otras ubicaciones diferentes a la ubicación del paquete: data_files=[('datos', ['dat/archivo.dat'])] 
  • entry_points: Funciones (de scripts) que pueden ser llamadas directamente por un usuario. entry_points = {'console_scripts': ['Script1 = script1: main',],}.
  • zip_safe: Con el valor 'false' se impide que se instalen los paquetes en formato comprimido.

Más información sobre setuptools.

Ver otro ejemplo de lo que puede contener un archivo setup.py.


setup.cfg

El archivo setup.cfg contiene los valores predeterminados de diferentes opciones que se utilizan con los argumentos de setup.py.
Contenido del archivo setup.cfg en Pysaurio:

[bdist_wheel]
universal=0


La opción universal con el valor '0' establece que el paquete no esta soportado por las dos líneas de Python: 2.x y 3.x. El paquete sólo podrá instalarse en un sistema con Python 3.x.


README.rst

Todos los proyectos deben contener un archivo README.rst en el que se haga una descripción detallada del proyecto.

El formato que se utiliza con más frecuencia para escribir su contenido es reStructuredText aunque no es un requisito indispensable.

Contenido del archivo README.rst:

Pysaurio
-----------

**Raptor** for extracting and displaying information from a set of files of the same type; and creating a single CSV file with all the selected information.
   
The information in the files may be in multiple rows::
   
    PC01.txt:
    User=ms123
    Name=Mayra Sanz
    OS=GNU/Linux
    IP=10.226.140.1
   
But, also, the information may be in several columns. It is possible to read data from multiple fields in a single line::
...
...
...


MANIFEST.in

El archivo MANIFEST.in se utiliza en casos en que se necesiten empaquetar archivos adicionales que setup.py no incluya automáticamente.

Ver archivos que están incluidos por defecto en una distribución.

Contenido del archivo MANIFEST.in:

include README.md
include LICENSE.txt
include examples/*
include examples/txt/*


En MANIFEST.in se incluyen los archivos:

  • README.md: tiene el mismo contenido que README.rst pero el texto está escrito utilizando el lenguaje de marcado MarkDown. 
  • LICENSE.txt: con el texto de la licencia GNU GPL Version 3.
  • También se incluye la carpeta 'examples' que contiene varios programas Python de ejemplos y algunos archivos de texto en el directorio 'txt' necesarios para probar los programas.

Otros instrucciones permitidas: exclude, recursive-include, recursive-exclude, global-include, global-exclude, graft y prune

Ver detalles sobre cómo escribir un archivo MANIFEST.in.


Carpeta 'pysaurio'

Es la carpeta de mayor importancia porque es la que contiene el paquete a distribuir.

La práctica más común consiste en incluir los módulos y paquetes Python bajo un único paquete de nivel superior con el mismo nombre del proyecto (o similar).

En nuestro caso contiene un archivo __init__.py con el código fuente de Pysaurio.

Es imprescindible documentar los fuentes de los paquetes para que cualquier usuario que lo instale pueda consultarla con pydoc3.


Carpeta 'examples'

La carpeta 'examples' contiene varios programas Python con ejemplos y una carpeta llamada 'txt' con algunos archivos de texto necesarios para probar los programas.

También se incluye un archivo con la extensión .rap que es similar a un archivo .INI que es utilizado por unos de los programas de ejemplo.

El módulo Pysaurio utiliza los archivos .rap para salvar información relacionada con una operación de búsqueda y extracción de datos de una serie de archivos de texto. Entre otros Pysaurio tiene un método para guardar un archivo .rap y otro para abrirlo.


Empaquetar el proyecto


Para que un proyecto se pueda instalar desde PyPI es necesario crear al menos un paquete de distribución. En el capítulo anterior se comentaron los dos tipos más usados. A continuación, trataremos sobre la forma de crearlos:

Crear un paquete source o sdist


Para crear un paquete source o sdist (distribución de código fuente):

$ python3 setup.py sdist

Una distribución source requiere el paso de ser generada o construida cuando se instala con pip. Incluso si la distribución es python puro (no contiene extensiones) incluye una fase de construcción para los metadatos de instalación a partir del archivo setup.py.

Durante la generación de la distribución se crean dos carpetas nuevas en la carpeta del proyecto: una llamada "NombrePaquete.egg-info" que contiene archivos de texto con información del paquete o "huevo" (egg) y otra llamada 'dist' con el "huevo" propiamente dicho o el paquete generado: "paquete-version.tar.gz".

Crear un paquete wheel


También es posible crear un paquete wheel que se podrá instalar sin necesidad de pasar por el proceso de construcción. La instalación de paquetes wheel es sustancialmente más rápida para el usuario final que la instalación de una distribución source.

Si el proyecto está basado en Python puro (no contiene extensiones compiladas) y soporta Python 2.x y 3.x, es posible crear un paquete wheel universal

Para construir un paquete wheel universal (Esta opción NO sería la adecuada para Pysaurio porque el proyecto solo está soportado por Python 3.x):

$ python3 setup.py bdist_wheel --universal

También se puede establecer la variable 'universal' con el valor 1 en el archivo setup.cfg con:

[bdist_wheel]
universal=1


Si el proyecto está basado en Python puro, pero no soporta de forma nativa Python 2.x y 3.x, entonces hay que crear el paquete con (Está opción sería la idónea para Pysaurio):

$ python3 setup.py bdist_wheel

bdist_wheel detectará que el código es Python puro y construirá un paquete con un nombre apropiado (según sea la instalación de Python) con la versión adecuada de Python: 2.x o 3.x. (Para más detalles sobre nombres de archivos de paquetes consultar PEP-425).

En la carpeta 'dist' se incluirá el paquete wheel "nombrepaquete-version-py3-none-any.whl" y en el carpeta del proyecto aparecerá una nueva carpeta llamada 'build' con archivos generados durante el proceso de construcción. 

Si se quiere dar soporte tanto a Python 2.x como a 3.x pero con un código fuente distinto se puede ejecutar setup.py bdist_wheel dos veces, una vez con Python 2.x y otra con Python 3.x.

Y si el proyecto contiene extensiones compiladas, entonces será necesario crear lo que se denomina paquete wheel de plataforma:

$ python3 setup.py bdist_wheel

bdist_wheel detectará que el código no es Python puro y construirá un paquete wheel de plataforma con un nombre apropiado.

PyPI actualmente sólo permite paquetes wheel de plataforma para Windows y OS X.

Subir el proyecto a PyPI


Para realizar pruebas es recomendable utilizar el sitio que ha dispuesto PyPI para ellas: PyPI test site

Es recomendable consultar las instrucciones de uso del sitio de pruebas. No hay problema en hacer todas la pruebas que se necesiten porque el sitio se "autolimpiará" cada cierto tiempo.

Crear una cuenta de usuario


Para subir un proyecto a PyPI es necesario tener una cuenta de usuario. Dicha cuenta puede crearse de forma manual utilizando el siguiente formulario o bien en el mismo procedimiento de registro del proyecto.

 

Registrar el proyecto


Hay dos caminos que se pueden seguir para registrar un proyecto:

1) (Recomendado) Utilizar el formulario de registro de PyPI

2) Registrar el proyecto con:

$ python3 setup.py register

Si no disponemos de una cuenta de usuario el asistente nos guiará para crear una.

Si la cuenta se generó de forma manual tendremos que crear el archivo ~/.pypirc con el siguiente contenido:

[distutils]
index-servers=pypi

[pypi]
repository = https://upload.pypi.org/legacy/
username = usuario_PyPI
password = contraseña



Subir el paquete del proyecto a Pypi


Finalmente, para subir la distribución a PyPI, hay dos opciones:

1) (Recomendado) Ejecutar:

$ twine upload dist/*

La principal razón para utilizar twine es que python3 setup.py upload basa la subida en el uso de archivos de texto plano, con el riesgo de seguridad que supone exponer la cuenta del usuario de PyPI y su contraseña.

2) Utilizar setuptools:

$ python3 setup.py sdist bdist_wheel upload

Casi de inmediato, una vez se han subido los archivos a PyPI, la web anunciará en su página inicial la disponibilidad del paquete ofreciendo la fecha de publicación, el nombre del paquete, su versión y la descripción breve que se incluyó en el archivo setup.py.

Y si seleccionamos el enlace del nombre del paquete accederemos a la página del proyecto.

Y lo más importante cualquier usuario, si necesidad de registrarse, podrá instalar Pysaurio en su sistema Python con:

$ pip3 install pysaurio

Herramientas

  • Pyroma es una aplicación que analiza la configuración de setup.py para comprobar si cumple las buenas prácticas recomendadas.

El modo desarrollo


Aunque no es imprescindible, un proyecto se puede instalar en modo "desarrollo" mientras se está trabajando en él:

$ python3 setup.py develop

ó

$ pip3 install -e


Ambos comandos instalarán las dependencias declaradas con "install_requires" y también los scripts declarados en "console_scripts".




martes, 28 de julio de 2015

Empaquetado y distribución de proyectos Python (I)


PyPI, pip y PyPA


PyPI es la web con el repositorio oficial para los proyectos de la comunidad Python mantenida por la Python Software Foundation. PyPI está abierto a todos los desarrolladores de Python que deseen compartir sus proyectos, en forma de paquetes de distribución, con otras personas.

Normalmente, un paquete se puede descargar manualmente desde el repositorio y después instalar (python setup.py install); pero lo habitual es utilizar la herramienta pip que permite desde la consola instalar, desinstalar, actualizar, listar, buscar y realizar otras operaciones relacionadas con los proyectos publicados (en PyPI o en otros repositorios basados en la misma tecnología).

Cuando pip instala un paquete hará lo propio con sus dependencias, es decir, con aquellos paquetes de los que depende su funcionamiento. En la actualidad Pip es la herramienta para gestionar paquetes aconsejada por la PyPA (Python Packaging Authority), la principal autoridad en recomendaciones sobre empaquetado y distribución de aplicaciones Python.

A continuación, se hace un recorrido por los conceptos esenciales para introducirse en este mundo de los paquetes de distribución Python y, también, explicamos el uso de pip. Y en la siguiente entrada recogemos un caso práctico con todos los pasos que hay que seguir para empaquetar y distribuir un proyecto.

Paquete de distribución


Un paquete de distribución es un archivo comprimido, identificado con un nombre y un número de versión, que contiene paquetes y módulos Python y otros archivos que se utilizan para compartir un lanzamiento.

(En este contexto un paquete de distribución o simplemente "paquete" no debe confundirse con un paquete que se importa en un programa Python).

Un paquete de distribución es el archivo, llamado comúnmente huevo (egg), que un usuario final descarga de Internet e instala en un sistema con Python.

En PyPI en la actualidad hay decenas de miles de paquetes y éstos pueden ser, principalmente, de dos tipos:

Paquetes source o sdist


Estos paquetes requieren ser compilados en la parte del usuario final. Este proceso es imprescindible cuando se incluyen extensiones escritas en lenguaje C que deben ser compiladas.


Hay casos en los que es necesario utilizar easy_install para instalar distribuciones construidas siguiendo el formato de los huevos de setuptools. Easy_install es un módulo que se incluyó con las herramientas setuptools, una biblioteca que aporta mejoras a las herramientas de distribución estándar distutils -utilidades de distribución- (de la biblioteca de Python) para construir y distribuir los paquetes con mayor facilidad, especialmente, aquellos con dependencias.

Paquetes wheel


Los paquetes wheel tienen un formato de distribución pre-built (de tipo binario) que ofrecen una instalación más rápida en comparación con el formato del paquete source o sdist (distribución de código fuente).

Wheel es un formato de paquete integrado para Python, que nace a partir de la recomendación PEP-376, con el objetivo de proporcionar una infraestructura estándar para gestionar los paquetes de distribución Python; para que las distintas herramientas que se utilizan actualmente en la instalación y desinstalación de proyectos sean interoperables.

Un archivo wheel es un archivo con el formato ZIP que utiliza un nombre de archivo con una nomenclatura que incluye el nombre del proyecto, su versión y que tiene la extensión .whl.

En este formato muchos paquetes se instalan correctamente en el momento de ser desempaquetados ganándose velocidad en el proceso.

A partir de la versión 1.5 pip prefiere el formato wheel sobre sdist, aunque por razones de compatibilidad gestiona los dos formatos de paquetes sin problemas. En definitiva, el formato wheel pretende con el tiempo sustituir al que fuera precursor de los huevos (Eggs).

Requerimientos para instalar paquetes de distribución


A partir de Python 3.4 se incluye pip como gestor de paquetes por defecto y no es necesario instalar absolutamente nada, excepto en algunos casos muy concretos. También, se incluyen las herramientas setuptools.

Instalar pip y setuptools


- Con Python 3.4 o posterior:

Normalmente, en una instalación Python 3.4 o posterior las herramientas pip y setuptools están listas para su uso. En determinadas circunstancias (porque se haya excluido previamente de la instalación, se haya desinstalado en un momento dado o se trate de un entorno virtual) es posible que no estén disponibles. En ese caso si la instalación cuenta con el paquete ensurepip, instalar con:

$ python3 -m ensurepip --upgrade

El paquete ensurepip proporciona soporte para poner a punto pip en una instalación o en un entorno virtual Python. Es importante tener en cuenta que pip es un proyecto independiente que tiene su propio ciclo de lanzamientos.

Para conocer la ruta de instalación de pip en un sistema con GNU/Linux:

$ which pip3

/usr/bin/pip3

En un sistema Windows pip se instala en el directorio C:\Python*\Scripts\ Esta ruta tendrá que agregarse a la variable de entorno PATH para que pip se pueda invocar desde cualquier ubicación.


- Con versiones anteriores a Python 3.4:

Descargar el archivo get-pip.py y ejecutar con Python:

$ python3 get-pip.py


La ejecución anterior sirve tanto para instalar como para actualizar pip. Además, instalará setuptools si no estuviera instalado.

Una vez instalado pip, si deseamos actualizar setuptools a la última versión disponible:

$ pip3 install -U setuptools


- Pip con soporte para paquetes wheel:


Para asegurar que se tiene instalada una versión reciente de pip con soporte para wheel (permite trabajar con archivos .whl):

$ pip3 install --upgrade pip

También, se puede instalar wheel con:

$ pip3 install wheel

- Otras opciones para instalar pip: 

Para Instalar en un sistema con Debian/Ubuntu:

$ sudo apt-get install python-pip3

Para instalar mediante un archivo .MSI en un sistema con Windows:

Descargar e instalar el paquete .MSI creado por Christoph Gohlke desde el sitio (no oficial) de la Universidad de California:

Desde la misma página es posible descargar setuptools y otros muchos paquetes de distribución Python.

pip en entornos virtuales


Es muy recomendable trabajar con entornos virtuales Python porque permite instalar los paquetes de distribución en un espacio aislado sin poner en riesgo la instalación principal de Python. Además, para hacerlo no es necesario tener privilegios de administración.

Para trabajar con entornos virtuales Python utilizar virtuaenv o pyenv. Si quiere conocer cómo crear y utilizar un entorno virtual: Entornos Virtuales con Python.

Uso de pip


Instalar un paquete


Para instalar paquetes de distribución desde el repositorio PyPI:

$ pip3 install 'paquete'


(Si en el sistema tenemos una instalación Python 2.x y otra 3.x utilizaremos pip para gestionar los paquetes de 2.x y pip3 para los 3.x).

En un sistema GNU/Linux donde se requieran privilegios de administración para realizar instalaciones, utilizar pip con sudo:

$ sudo pip3 install 'paquete'

Si existen varios paquetes se instalará el que tenga la versión más reciente. Las comillas son opcionales:

$ sudo pip3 install paquete

Para instalar en una red con acceso a Internet que utiliza proxy con autenticación:

$ pip3 install paquete --proxy http://usuario:password@servidor:puerto

Para instalar una versión especifica de un paquete:

$ pip3 install 'paquete == version'


Para instalar un paquete descargado previamente desde PyPI:

$ pip3 install paquete.tar.gz

ó si se trata de un paquete wheel:

$ pip3 install paquete.whl

También es posible descomprimir el paquete descargado e instalarlo después con:

$ pip3 setup.py install

Desinstalar un paquete


Para desinstalar un paquete existente en el sistema:

$ pip3 uninstall paquete

Actualizar un paquete


Para actualizar un paquete existente en el sistema:

$ pip3 install paquete --upgrade

 

Listar paquetes instalados


Para listar todos los paquetes instalados en el sistema Python:

$ pip3 list

Mostrar información de un paquete


Para mostrar la versión, localización y dependencias de un paquete instalado:

$ pip3 show paquete


Name: paquete
Version: 0.0.1
Location: /usr/local/lib/python3.4/dist-packages
Requires:

Buscar paquetes en PyPI


Para buscar paquetes por su nombre o por palabras que aparecen en su descripción:

$ pip3 search literal-de-busqueda

Ejemplos:

$ pip3 search 'pimen'

pimento     - Simple CLI Menus

$ pip3 search 'Menus CLI'

Listar paquetes de una instalación en un momento dado (Congelar)


Para listar los paquetes que serían necesarios para replicar la instalación actual en otro sistema:

$ pip3 freeze >requirements.txt

El archivo de requerimientos (requirements.txt) detalla las dependencias que tiene la instalación Python.

Leer paquetes desde archivo e instalar


Para leer una lista de paquetes de un archivo de requerimientos (requirements.txt) e instalarlos en la instalación actual:

$ pip3 install -r requirements.txt

Mostrar la versión de pip


$ pip3 -V

pip 7.1.0 from /usr/local/lib/python3.4/dist-packages (python 3.4)

Actualizar pip a la última versión disponible


$ pip3 install --upgrade pip

Mostrar ayuda de pip


$ pip3 -h

Trabajar con una caché wheel


Para construir una caché de wheel en un directorio local (incluye estructura piramidal y todas las dependencias):

$ pip3 wheel --wheel-dir=/tmp/wh pyramid


Para instalar desde una caché wheel (no se usará el repositorio Pypi):

$ pip3 install --use-wheel --no-index --find-links=/tmp/wh pyramid


Para Instalar desde una caché wheel remotamente

$ pip3 install --use-wheel --no-index --find-links=https://wh.web.com/ pyramid


Siguiente: caso práctico de empaquetado de un proyecto Python y posterior publicación en PyPI para su distribución