Tag: Python

Comprobar permisos de Administrador en una ejecuci贸n (estilo 馃悕 Python)

Habitualmente nos encontramos con la situaci贸n en la que debemos ejecutar ciertos programas o flujos de ejecuci贸n y necesitamos permisos de Administrador. Estas situaciones se nos presentan cuando tenemos que manejar carpetas y ficheros en acciones que impliquen lectura, escritura o ejecuci贸n en directorios protegidos del sistema. Para ello se requiere una elevaci贸n de permisos que deberemos comprobar si existe antes de lanzar nuestra ejecuci贸n.

Aprovechando que seguramente tengamos que hacer esto varias veces, creo que la mejor opci贸n de hacerlo es con el mejor lenguaje pegamento que existe hasta la fecha, que no es ni m谩s ni menos que Python. Por ello la soluci贸n final que vamos a plantear es excelente tanto para administradores de sistemas como para desarrolladores, siendo adem谩s multiplataforma GNU/Linux y Windows.

Tenemos que tener en cuenta que GNU/Linux y Windows no funcionan igual para la gesti贸n de permisos. En Windows preguntaremos desde la API disponible si el usuario es administrador, mientras que en GNU/Linux preguntaremos por si el usuario tiene permisos root.

import ctypes, os
from sys import exit


def is_admin():
    is_admin = False
    try:
        is_admin = os.getuid() == 0
    except AttributeError:
        is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0

    print ("Admin privileges: {}".format(is_admin))
    return is_admin

Para mirar los permisos en Windows usaremos la librer铆a ctypes y para los permisos en GNU/Linux usaremos la librer铆a os. Ambas est谩n incluida en Python. Por una raz贸n arbitrar铆a se ha elegido comprobar primero GNU/Linux y despu茅s Windows.

Cuando se comprueba en GNU/Linux invocamos a la funci贸n os.getuid que nos devolver谩 0 en el caso de ser root. Si llamamos a la funci贸n desde Windows con Python nos elevar谩 una excepci贸n del tipo AttributeError, que aprovecharemos a capturar para hacer la comprobaci贸n en Windows invocando a la funci贸n ctypes.windll.shell32.IsUserAnAdmin. En ambos casos guardaremos el booleano de la evaluaci贸n y lo devolveremos al final de la funci贸n.

Hasta aqu铆 sencillo, pero esto es c贸digo Python y es necesario tener el interprete de Python, con el que obliga al sistema a tener instalado el int茅rprete de Python. Para solucionarlo, deber铆amos convertir nuestro c贸digo en un programa a帽adiendo un punto de entrada y devolviendo un c贸digo de retorno tras la ejecuci贸n.

import ctypes, os
from sys import exit


def is_admin():
    is_admin = False
    is_win = False
    try:
        is_admin = os.getuid() == 0
    except AttributeError:
        is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
        is_win = True

    print ("Admin privileges: {}".format(is_admin))
    return is_admin, is_win

Antes modificaremos un poco la funci贸n is_admin()a帽adiendo un valor is_win que usaremos para saber que estamos comprobando en GNU/Linux o Windows los permisos de administrador, devolviendo el valor como un segundo valor en el retorno de la funci贸n.

Recordad que Python es posible recoger m煤ltiples valores de retorno en una variable como una tupla, en variables separadas o incluso tirar los valores que no nos interesen.

def my_function():
    a = 2
    b = 3
    return a, b

a = my_function()
print(a)  # out: (2, 3)

a, b = my_function()
print(a)  # out: 2
print(b)  # out: 3

a, _ = my_function()  #  b es ignorado
print(a)  # out: 2

Adem谩s a帽adimos un punto de entrada debajo de la funci贸n is_admin().

if __name__ == "__main__":
    is_admin, is_win = is_admin()
    # Converting boolean to integer 
    ret = int(is_admin == False)
    if is_win:
        exit(ret)
    else:
        exit(ret * -1)

Comprobar si __name__ es __main__, es una excelente forma de hacer que cada unidad de fichero Python sea ejecutable si se quiere. El nombre de __main__ s贸lo es dado al fichero Python que es dado al int茅rprete para ser ejecutado y en caso de no serlo, siempre puede ser importado en otro fichero Python, sin que el punto de entrada afecte.

Como vemos, ahora estamos recogiendo en el retorno is_admin e is_win. Necesitamos el segundo valor para decidir el valor de retorno, ya que los c贸digos de error en Windows son enteros positivos y en GNU/Linux son enteros negativos. El 煤nico punto en com煤n es que devolver un 0 es se帽al de que la ejecuci贸n fue correcta. Sabiendo esto debemos adaptar el retorno de los errores dependiendo el sistema.

馃捑 Binarizando nuestra aplicaci贸n Python

Para convertirlo en un ejecutable usaremos PyInstaller, el cual pod茅is instalar con un simple pip install pyinstaller. Para binarizar nuestra aplicaci贸n en un ejecutable autocontenido con el interprete de Python ejecutaremos:

pyinstaller -F is_admin.py

De esta forma resultar谩, mucho mas sencilla la distribuci贸n de nuestra aplicaci贸n.

馃憯 Puesta en Producci贸n

Ahora vamos a plantear los dos casos de uso para Windows y GNU/Linux. Como aclaraci贸n, decir que los ejemplos expuestos se pueden usar tanto con la versi贸n binarizada o con la de c贸digo invocando al int茅rprete de Python.

Windows

@echo off

cd
cd /D "%~dp0"
cd

#REM python is_admin.py
is_admin.exe

if errorlevel 1 (
   echo Exit Code is %errorlevel%
   echo.
   echo Admin privileges required
   echo Run it again as Administrator
   echo.
   pause
   exit /b %errorlevel%
)

#REM [your_executable].exe

pause

馃憖 Puedes descargar la versi贸n binarizada de is_admin.exe

GNU/Linux

#!/bin/bash

pwd
cd `dirname $0`
SCRIPTDIR=`pwd`
pwd

#python is_admin.py
is_admin


if [ $? -eq 0 ]
then
  # [your_executable]
else
  echo Exit Code is $?
  echo.
  echo Admin privileges required
  echo Run it again as Administrator
  echo.
  read -rsp $'Press any key to continue...\n' -n 1 key
  exit $?
fi

read -rsp $'Press any key to continue...\n' -n 1 key

Si no est谩s tan familiarizado con el Bash te invito a que visites el proyecto ExplainShell para que puedas obtener la explicaci贸n de los diferentes comandos y argumentos.

馃 Conclusiones

La soluci贸n presentada, sin ser seguramente perfecta, asegura tanto a administradores de sistemas como desarrolladores, comprobar si existen los permisos de administrador necesarios de manera sencilla; pudiendo hacerlo con una versi贸n binarizada autocontenida que incluya el int茅rpretete Python, ejecut谩ndolo usando el int茅rprete de Python del sistema gracias a ser todo dependencias internas, o llamando directamente a la funci贸n is_admin() si se quiere integrar en un desarrollo.

El c贸digo completo puedes encontrarlo en el siguiente gist de GitHub:

Espero que esta forma de trabajar te resulte 煤til y puedas extrapolarla y usar para otros casos Python como tu lenguaje pegamento generando c贸digo y aplicaciones altamente reutilizables.

Gesti贸n de dependencias y versionado en Python

Cuando programas una de las cosas m谩s importantes para asegurar la compatibilidad y el soporte de una librer铆a, herramienta o programa, es el versionado del mismo.

El versionado sirve para que a nivel interno, el equipo de desarrolladores pueda llevar un control de hitos dentro del desarrollo y a su vez sirve para que otros desarrolladores o usuarios, que usan estas librer铆as, herramientas o programas, puedan tener un control a la hora de integrarlas o actualizarlas.

Ahora bien, el problema viene a la hora de establecer la significaci贸n de dicho n煤mero de versi贸n. En Python es normal usar el sistema SemVer, el cual establece tres grupos de n煤meros separados por puntos de la forma MAJOR.MINOR.PATCH

  • MAJOR: Se incrementa cuando cuando se realizan cambios incompatibles a nivel de API.
  • MINOR: Se incrementa cuando se a帽aden funcionalidad de manera retrocompatible.
  • PATCH: Se incrementa cuando se corrigen 馃悰 fallos de manera retrocompotible

Es posible que estuvieras familiarizado con este sistema de versionado, pero a煤n as铆 te recomiendo su lectura completa en https://semver.org.

Teniendo esto claro, vamos a pasar a ver la aplicaci贸n pr谩ctica que que tiene esto en la gesti贸n de dependencias, donde la generaci贸n de paquetes para su distribuci贸n en Pipy es donde se marca la diferencia. Podemos ajustar que nuestro paquete maneje las dependencias de acuerdo a criterios de versi贸n de Python, debido a casos como que una librer铆a espec铆fica deje de dar soporte a ciertas versiones de Python a partir de cierta versi贸n.

En el caso citado, hay dos opciones directas que son, o retirar soporte a ciertas versiones de Python propagando la restricci贸n de alguna de nuestras dependencias, o controlar las versiones de las dependencias dependiendo de la versi贸n de Python a utilizar. Veamos c贸mo:

colorama==0.3.7; python_version < '3.4.*'
colorama>=0.3.7; python_version >= '3.4.*'

En este caso definimos en nuestro requirements.txt la condici贸n de que para versiones de Python menores a 3.4.* es necesario usar la versi贸n de colorama 0.3.7, ya que dicha dependencia retira el soporte a versiones inferiores desde esa versi贸n. Para versiones iguales o mayores a 3.4.*, simplemente se exige una versi贸n mayor o igual a 0.3.7. Atenci贸n a que siempre se citan los tres grupos de n煤meros.

Otras veces puede pasar que cierta versi贸n de una dependencia nos d茅 problemas y queramos convertirla en una excepci贸n al requerimiento

fake_library>1.6.2,!=1.7.2

En este caso de la librer铆a inventada fake_library exigir铆a una versi贸n superior a 1.6.2, pero que no sea 1.7.2.

Por 煤ltimo es posible instalar dependencias que sean necesarias para ciertos sistemas operativos. Veamos un ejemplo:

pywin32 >=1.0.*; sys_platform == 'win32'
SistemaValor platform
AIX'aix'
GNU/Linux'linux'
Windows'win32'
Windows/Cygwin'cygwin'
macOS'darwin'

https://docs.python.org/3/library/sys.html#sys.platform

Para el ejemplo se especifica una versi贸n superior o igual a 1.0.* de pywin32 en el caso de encontrarnos en un sistema Windows.

Finalmente es posible que en el setup.py de una librer铆a, herramienta o aplicaci贸n, se obligue a contar con unas versi贸n especificas de Python y/o evitar otras:

from setuptools import setup
 
setup(
    name='mypackage',
    packages=['mypackage'],
    version='0.1',
    license='LGPL v3',
    description='A random test lib',
    author='RDCH106',
    author_email='contact@rdch106.hol.es',
    url='https://github.com/RDCH106/mypackage',
    download_url='https://github.com/RDCH106/parallel_foreach_submodule/archive/v0.1.tar.gz',
    keywords='test example develop', 
    python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', # requerimientos de versi贸n de Python
    classifiers = ['Programming Language :: Python',
                   'Programming Language :: Python :: 2.7',
                   'Programming Language :: Python :: 3.4',
                   'Programming Language :: Python :: 3.5',
                   'Programming Language :: Python :: 3.6',
                   'Programming Language :: Python :: 3.7',
                   'Programming Language :: Python :: 3.8'],
)

En la l铆nea 14 se puede ver que se especifica que se requiere versiones de Python mayores a 2.7, pero que no sean ni 3.0.*, 3.1.*, 3.2.* o 3.3.*.

Todas estas reglas condicionales para la gesti贸n de dependencias quedan reflejadas en las PEP (Python Enhancement Proposal) 345, 440, 496 y 508 principalmente.

Espero que todo esto sirva para evitar caer en el llamado 鈥infierno de las dependencias鈥, mientras crece tu librer铆a, herramienta o aplicaci贸n.

Aprende a programar en Python – Introducci贸n – 0

Llevaba tiempo mascando esta serie de entradas para aprender a programar en Python, para las cuales no quise quedarme en algo del tipo mira, aprende y copia. El curso tiene un enfoque pr谩ctico con su parte de teor铆a y ejercicios donde corresponda. Atendiendo a las actuales necesidades formativas he decidido que el curso y su material podr谩 ser trabajado de manera online utilizando 煤nicamente un navegador web.

Para ello he creado un repositorio en GitHub con dos herramientas que podr茅is elegir usar de manera online:

Ambos proyectos usan como base el int茅rprete de Brython, un proyecto que intenta emular el interprete de Python que puedes instalarte en tu equipo. Este proyecto permite saltarse el problema de no poder instalar el interprete de Python debido a restricciones en el equipo que uses, por ejemplo si dependes del departamento de Sistemas para instalarlo, o simplemente si quieres retomar el curso en cualquier instante sin necesidad de instalar nada.

El proyecto de la Consola Python Online es una consola que se comporta de manera similar a la que puedes tener cuando lanzas Python desde una consola de comandos. El proyecto IDE Python Online es un entorno de desarrollo integrado donde podr谩s en su parte izquierda realizar la programaci贸n con realce de sintaxis y ayuda de autocompletado predictivo de c贸digo; y en su parte derecha podr谩s ver el resultado del c贸digo escrito a la izquierda tras darle al bot贸n "鈻 Run" de la parte superior. Con estas dos herramientas tendr谩s lo que te hace falta para seguir el curso.

Este proyecto es de car谩cter Open Source, siendo posible contribuir en el propio repositorio a la mejora de los fragmentos de c贸digo, ejercicios y herramientas.

Antes de empezar quisiera explicarte qu茅 es Python y ofrecerte una peque帽a aproximaci贸n de su historia. Python es un lenguaje de programaci贸n interpretado, lo que significa que no necesita compilarse y generar un binario para funcionar, se interpreta el c贸digo y el encargado de hacerlo (el int茅rprete), lo traducen a lenguaje m谩quina. Esto quiere decir tambi茅n que con vuestro c贸digo en Python s贸lo necesit谩is que un int茅rprete de Python est茅 instalado en la m谩quina para ejecutar el c贸digo, o usar las herramientas que anteriormente presentaba 馃槈 .

Python es un excelente lenguaje de programaci贸n si quieres aprender una herramienta que potencie o complemente tu trabajo, como es el caso del cl谩sico Excel. O simplemente como tu primer lenguaje de programaci贸n, debido a que su curva de aprendizaje es mucho m谩s baja a diferencia de otros lenguajes, haciendo hincapi茅 en una sintaxis que favorece la legibilidad del c贸digo. Adem谩s Python es multiparadigma, lo que significa que puede acomodarse a distintos enfoques y necesidades de programaci贸n, incluyendo el buen dise帽o por defecto en la propia sintaxis y evoluci贸n del lenguaje.

Actualmente Python se encuentra en un proceso de migraci贸n de Python 2 a Python 3, debido a que el soporte de Python 2 acaba el 1 de enero de 2020, terminando con un estado de segmentaci贸n del lenguaje que llevaba varios a帽os produci茅ndose. El salto de Python 2 a Python 3 supone el cambio del dise帽o de cierta parte de la sintaxis que rompe la compatibilidad y evitaba a Python avanzar hacia el Python que hoy conocemos y que tanta penetraci贸n tiene en los sectores t茅cnicos y no tan t茅cnicos. No obstante existen herramientas como 2to3 que realizan la adaptaci贸n autom谩tica de la sintaxis de Python 2 a Python3. Obviamente no es perfecto y queda en manos del programador el terminar de pulir la migraci贸n. La versi贸n del lenguaje que aprender谩s aqu铆, por supuesto es Python 3 馃槈 .

Para ir abriendo boca voy a mostrarte el cl谩sico programa de inicio "Hello World!" o "Hola Mundo!" en espa帽ol:

Si le das al bot贸n "鈻 Run" leer谩s en la derecha "Hello World" seguido del tiempo que ha tardado en ejecutarse nuestro programa (lo que hay en el panel izquierdo).

Ahora te propongo un simple ejercicio hasta la pr贸xima entrada. Partiendo del siguiente c贸digo:

Intenta que imprima en el lado derecho "Hello World". Es f谩cil y seguro que lo consigues 馃槈 .

Con esto cerramos el cap铆tulo de introducci贸n donde hemos conocido las herramientas que vamos a usar para el curso, hemos presentado Python y hemos ejecutado nuestro primer programa.

C贸mo subir un paquete a PyPI

Recientemente un compa帽ero m铆o quer铆a distribuir una peque帽a librer铆a en Python que hab铆a escrito. En lugar de forzar a los desarrolladores a clonar su repositorio, quer铆a que pudieran instalarse la librer铆a con un s贸lo comando "pip install". Planteamiento muy interesante que se formaliza con el concepto de gestor de paquetes.

Un gestor permite un uso m谩s inteligente, 谩gil y seguro de las dependencias y ayuda tanto al que distribuye el paquete como al que lo usa, resolviendo problemas como el versionado, la cadena de dependencias dentro del paquete, la instalaci贸n...

Quisiera a fin de fomentar el uso del gestor de paquetes de Python llamado pip, que usa como repositorio oficial PyPI (Python Package Index), generar una gu铆a lo m谩s completa posible. 鈿狅笍 Me gustar铆a remarcar que con ello no quiero ni pretendo incentivar que cualquiera se dedique a subir de cualquier forma lo primero que se lo ocurra. Aludo a la responsabilidad de cada uno, para no convertir PyPI en un vertedero de paquetes de dudosa calidad. 鈿狅笍

驴Qu茅 es PyPI?

Desde la web oficial:

PyPI 鈥 脥ndice de Paquetes Python

El 脥ndice de Paquetes Python es un repositorio de software para el lenguaje de programaci贸n de Python.

驴Has programado algo genial? 驴Quieres que otros puedan instalarlo con easy_install o pip? Pon tu c贸digo en PyPI. Es una gran lista de paquetes de Python donde debes enviar tu paquete para que pueda instalarse f谩cilmente con uno s贸lo comando.

La buena noticia es que enviar un paquete a PyPI en la teor铆a es muy simple: registrarte y cargar tu c贸digo, todo de manera gratuita. La mala noticia es que en la pr谩ctica es un poco m谩s complicado que eso 馃槄. La otra buena noticia es que he escrito esta gu铆a 馃榿 y que, si est谩s atascado, siempre puedes consultar la documentaci贸n oficial 馃槈.

He escrito esta gu铆a con los siguientes supuestos:

  •      El m贸dulo / biblioteca / paquete que est谩 enviando se llama mypackage.
  •      mypackage est谩 alojado en GitHub.

Crear tu cuenta

Crea una cuenta en PyPI Live y tambi茅n en PyPI Test. Debes crear una cuenta para poder cargar tu c贸digo. Te recomiendo usar el mismo correo electr贸nico y contrase帽a para ambas cuentas, s贸lo para hacerte la vida m谩s f谩cil cuando llegue el momento de subir tu c贸digo. Ambas plataformas son id茅nticas, siendo la de test una r茅plica de la oficial para que pruebes a subir tus paquetes.

Crear un archivo de configuraci贸n .pypirc

Este archivo contiene su informaci贸n para la autenticaci贸n con PyPI, tanto la versi贸n en vivo como la versi贸n de prueba.

[distutils]
index-servers =
  pypi
  pypitest

[pypi]
repository=https://upload.pypi.org/legacy/
username=your_username
password=your_password

[pypitest]
repository=https://test.pypi.org/legacy/
username=your_username
password=your_password

Esto es s贸lo para hacer tu vida m谩s f谩cil, para que cuando llegue el momento de subir el c贸digo de de tu paquete no tengas que recordar/escribir tu nombre de usuario y contrase帽a. Aseg煤rate de poner este archivo en tu carpeta de inicio de tu sistema GNU/Linux; tu ruta debe ser:

~/.pypirc

Debido a que este archivo contiene tu nombre de usuario y contrase帽a, es posible que desees cambiar sus permisos para que s贸lo t煤 puedas leerlos y escribirlos. Desde la terminal, ejecuta:

chmod 600 ~/.pypirc

Si por el contrario te encuentras en un sistema Windows genera el archivo .pypirc en la carpeta de tu usuario en C:\Users\usuario con el siguiente comando:

type nul > your_file.txt
馃憗锔 Notas sobre usernames / passwords

En Python 3, si tu contrase帽a incluye un % sin procesar, debes generar una secuencia de escape duplic谩ndolo. El analizador de configuraci贸n de .pypirc interpola las cadenas de texto. Por ejemplo, si tu contrase帽a es hello%world:

[pypi]
repository=https://pypi.python.org/pypi
username=myusername
password=hello%%world

Nunca me he encontrado con este problema, pero si te ocurre, esto podr铆a ayudar. 馃槈

Este comportamiento de escape ha sido parcheado y ya no es necesario hacerlo, pero si ves un error con un c贸digo de respuesta de:

 403: Invalid or non-existent authentication information 

Intenta eliminar la secuencia de escape de los signos de porcentaje en tu contrase帽a.

Si tu contrase帽a incluye espacios, aseg煤rese de no entrecomillarla. Por ejemplo, si tu contrase帽a es me encanta Mascando Bits:

[pypi]
repository=https://pypi.python.org/pypi
username=myusername
password=me encanta MascandoBits

Preparar el paquete

Cada paquete en PyPI necesita tener un archivo llamado setup.py en la ra铆z del directorio. Si est谩s utilizando un archivo README en formato markdown, tambi茅n necesitar谩 un archivo MANIFEST.in. Adem谩s, es recomendable elegir una licencia para tu paquete reflejada en un archivo LICENSE que describa lo que se puede hacer con tu c贸digo. Entonces, si por ejemplo he estado trabajando en una biblioteca llamada mypackage, la estructura de mi directorio se ver铆a tal que as铆:

root-dir/   # nombre de directorio de trabajo aleatorio
  setup.py
  MANIFEST.in
  LICENSE.txt
  README.md
  mypackage/
    __init__.py
    foo.py
    bar.py
    baz.py

A continuaci贸n un desglose de lo que va en cada archivo:

setup.py

Son los metadatos de la librer铆a necesarios para generar el paquete.

from setuptools import setup

setup(
    name='mypackage',
    packages=['mypackage'], # Mismo nombre que en la estructura de carpetas de arriba
    version='0.1',
    license='LGPL v3', # La licencia que tenga tu paquete
    description='A random test lib',
    author='RDCH106',
    author_email='contact@rdch106.hol.es',
    url='https://github.com/RDCH106/mypackage', # Usa la URL del repositorio de GitHub
    download_url='https://github.com/RDCH106/parallel_foreach_submodule/archive/v0.1.tar.gz', # Te lo explico a continuaci贸n
    keywords='test example develop', # Palabras que definan tu paquete
    classifiers=['Programming Language :: Python',  # Clasificadores de compatibilidad con versiones de Python para tu paquete
                 'Programming Language :: Python :: 2.7',
                 'Programming Language :: Python :: 3.3',
                 'Programming Language :: Python :: 3.4',
                 'Programming Language :: Python :: 3.5',
                 'Programming Language :: Python :: 3.6',
                 'Programming Language :: Python :: 3.7'],
)

El par谩metro download_url es un enlace a un archivo alojado con el c贸digo de tu repositorio. Github alojar谩 esto para ti, pero solo si creas una etiqueta git tag. En tu repositorio, escribe en la l铆nea de comandos:

git tag v0.1 -m "Agrega una etiqueta para que podamos poner esto en PyPI"

Luego, escribe el siguiente comando para mostrar la lista de etiquetas:

git tag

Deber铆as ver v0.1 en la lista.

Por 煤ltimo escribe el siguiente comando para actualizar tu c贸digo en Github con la informaci贸n de etiqueta m谩s reciente:

git push --tags origin master

Github crear谩 archivos comprimidos para descargar en https://github.com/{username}/{package_name}/archive/v{tag}.tar.gz.

MANIFEST.in

Incluye archivos que se empaquetar谩n en al distribuci贸n del paquete.

include LICENSE.txt README.md

LICENSE.txt ser谩 el archivo que contiene la licencia y README.md ser谩 el fichero que contenga la informaci贸n b谩sica (instalaci贸n, uso...) que quieras distribuir con tu paquete.

Subir tu paquete a PyPI Test

Ejecuta:

python setup.py sdist upload -r pypitest

No deber铆a recibir ning煤n error si seguiste los pasos hasta este punto, y ahora tambi茅n deber铆as poder ver tu paquete en el repositorio PyPI de prueba. Si hay algo que no te gusta este es el momento de hacer los cambios que quieras. Eso s铆, para subir el paquete de nuevo tendr谩s que editar el n煤mero de versi贸n para que sea distinto al de la anterior vez.

鈿狅笍 PyPI te permite borrar las versiones del paquete y subir todos las versiones que quieras, pero no editar una versi贸n de tu paquete subida. Esto es para mantener la estabilidad de las dependencias. Es posible retirar una versi贸n, creando la consecuente ruptura de dependencias, pero no se deja modificar para una versi贸n de un paquete por no desvirtuar el sentido mismo del versionado.

Es posible que en algunas gu铆a o documentaci贸n hayas visto que tambi茅n se hace previo al upload un comando register:

python setup.py register -r pypitest

Ya no es necesario y no est谩 soportado:

https://packaging.python.org/guides/migrating-to-pypi-org/#registering-package-names-metadata


Subir tu paquete a PyPI Live

Ejecuta:

python setup.py sdist upload -r pypi

Y ya, !lo has hecho! 馃帀馃帀馃帀 Has publicado tu primer paquete en PyPI y podr谩 ser instalado con el gestor de paquetes pip o cualquier otro como conda.