Los usuarios pueden ejecutar mi aplicación Python en directorios que contienen sus propios scripts de Python. Si alguno de estos scripts tiene un nombre que choca con un módulo de biblioteca utilizado por mi programa (o incluso choca con el nombre de mi módulo), todo se rompe con un mensaje de error inútil.

Sé que Python (desde 3.4) tiene el interruptor -I, lo que hace que la maquinaria de importación ignore el directorio actual (es decir, "" no se agregará a sys.path). Esto casi resolvería mi problema, pero tiene el efecto secundario de ignorar también los paquetes del sitio del usuario.

Sé que puedo modificar sys.path después de que mi programa se haya cargado, pero no ayudará si el usuario (por accidente) oculta el módulo principal de mi programa.

¿Puedo de alguna manera hacer que Python ignore el directorio actual pero me dé paquetes de sitios de usuario al mismo tiempo?

0
Aivar 3 mar. 2021 a las 15:11

1 respuesta

La mejor respuesta

Puede volver a habilitar las rutas del sitio del usuario llamando a site.addusersitepackages(None) (None simplemente significa: verifique las definiciones de sys.path existentes para evitar agregar rutas duplicadas):

import site
import sys

if sys.flags.no_user_site and sys.prefix == sys.base_prefix:
    # python -s or python -I has disabled user sites, and this is not a virtualenv
    site.ENABLE_USER_SITE = True
    site.addusersitepackages(None)

Demostración rápida:

>>> import site, sys, os.path
>>> user_site = os.path.expanduser(f"~/.local/lib/python{sys.version_info.major}.{sys.version_info.minor}/site-packages")
>>> user_site in sys.path
False
>>> sys.flags.no_user_site
1
>>> site.ENABLE_USER_SITE = True
>>> site.addusersitepackages(None)
>>> user_site in sys.path
True

Si bien site.addusersitepackages() no está documentado, es un componente clave de site.main() y es también bastante simple. Si siente que no puede confiar en su existencia continua, vuelva a implementarlo así:

import os.path
import site

def addusersitepackages():
    user_site = site.getusersitepackages()

    if site.ENABLE_USER_SITE and os.path.isdir(user_site):
        site.addsitedir(user_site)

Esta versión omite el argumento known_paths por completo y solo usa atributos y funciones site documentados: site.getusersitepackages(), site.ENABLE_USER_SITE y {{X4 }}.

O bien, doble lo anterior en el código para habilitar el directorio del sitio del usuario, envuelto como una función:

import os.path
import site
import sys

def ensure_usersitepackages():
    if sys.flags.no_user_site and sys.prefix == sys.base_prefix:
        # if python -s or python -I has disabled user sites, and this 
        # is not a virtualenv, explicitly enable user sites anyway.
        site.ENABLE_USER_SITE = True
        user_site = site.getusersitepackages()
        if os.path.isdir(user_site):
            site.addsitedir(user_site)

1
Martijn Pieters 4 mar. 2021 a las 00:17