简体   繁体   中英

How to avoid having current directory in Python's sys.path while keeping user site packages?

The users can execute my Python app in directories containing their own Python scripts. If any of these scripts has name which clashes with a library module used by my program (or even clashes with the name of my module), everything breaks with an unhelpful error message.

I know that Python (since 3.4) has -I switch, which makes import machinery ignore current directory (ie. "" won't be added to sys.path ). This would almost solve my problem, but it has the side effect of also ignoring user site packages.

I know I can tweak sys.path after my program has loaded, but it won't help if the user (by accident) shadows the main module of my program.

Can I somehow make Python ignore current directory but give me user site packages at the same time?

You can re-enable the user site paths, by calling site.addusersitepackages(None) (the None simply means: check existing sys.path definitions to avoid adding duplicate paths):

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)

Quick demo:

>>> 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

While site.addusersitepackages() is undocumented, it is a key component of site.main() and is also quite simple . If you feel you can't rely on its continued existence, reimplement it like this:

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)

This version omits the known_paths argument entirely, and only uses documented site attributes and functions: site.getusersitepackages() , site.ENABLE_USER_SITE and site.addsitedir() .

Or, fold the above into the code to enable the user site directory, wrapped as a function:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM