MacOS修改Python默认配置

环境信息

1
2
3
4
5
6
7
macOS Monterey 12.2.1,Apple M1 Pro版本

$ python --version
Python 3.8.9

$ pip --version
pip 22.0.4 from /Users/gavin/Library/Python/3.8/lib/python/site-packages/pip (python 3.8)

问题

最近在安装 EasyNLP 依赖的时候,报错 如下:

1
2
    raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.VersionConflict: (setuptools 49.2.1 (/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages), Requirement.parse('setuptools>=58.0'))

OK,setuptools 版本太低,升级:

1
2
3
4
5
6
7
$ pip install --upgrade setuptools
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: setuptools in /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages (49.2.1)
Collecting setuptools
Using cached setuptools-62.1.0-py3-none-any.whl (1.1 MB)
Installing collected packages: setuptools
Successfully installed setuptools-62.1.0

升级成功,But,重新安装依赖,还是报同样的错。就离谱。

仔细看了下 setuptools 信息:

1
2
3
4
5
6
7
8
9
10
11
$ pip show setuptools
Name: setuptools
Version: 62.1.0
Summary: Easily download, build, install, upgrade, and uninstall Python packages
Home-page: https://github.com/pypa/setuptools
Author: Python Packaging Authority
Author-email: distutils-sig@python.org
License: UNKNOWN
Location: /Users/gavin/Library/Python/3.8/lib/python/site-packages
Requires:
Required-by:

找到原因了:

pip 升级 setuptools 后的路径:/Users/gavin/Library/Python/3.8/lib/python/site-packages

报错的路径:Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages

也就是说,安装依赖时查找的 site-package,并非默认的路径(site-package 是下载第三方库时在电脑中的存放路径,也就是仓库)。

排查

先查看下 Python 对应的 site 信息:

1
2
3
4
5
6
7
8
9
10
11
12
$ python -m site
sys.path = [
'/usr/bin',
'/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python38.zip',
'/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8',
'/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/lib-dynload',
'/Users/gavin/Library/Python/3.8/lib/python/site-packages',
'/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site-packages',
]
USER_BASE: '/Users/gavin/Library/Python/3.8' (exists)
USER_SITE: '/Users/gavin/Library/Python/3.8/lib/python/site-packages' (exists)
ENABLE_USER_SITE: True

可以看到 sys.path 中两个路径都有,而且两个 site-package 中都有 setuptools,安装依赖时没有读取我们期望的 site-packages。

到这我们有 2 个解决方案,要么把系统自带的 setuptools 也升级,要么在 sys.path 中把系统的 site-packages删掉。

方案一不是长久之计,采用方案二。接下来就是看怎么修改 sys.path 了。

解决

​ 网上查了半天,如果对 sys.path 进行修改,最好是能把系统默认的 site-packages 去掉,只保留我们自己的 site-packages。如果去不掉的话,至少保证我们自己的 site-packages 优先级高于系统默认。

修改 sys.path 的方案一般有这些:

  1. 调用 sys 自带函数,比如 sys.remove() 函数,可以直接删。(该方案一般适用于代码中,临时有效,不适合我们的场景);
  2. python 在生成 sys.path 时,是通过检测.pth 文件所在的目录,以及其中的内容。所以如果想在某个路径加入到 sys.path,可以通过加.pth,或者修改.pth(该方案适合添加内容,也不适合);
  3. 定义 PYTHONPATH = /xxx/xxx,不定义这个变量也可以,直接在 PATH 中添加。这个方案大家应该都知道。根据 bash 类型编辑.bash_profile,或者.zshrc(该方案也只能添加,也不适合);
  4. 通过调整 python 的 site.py,自定义 USER_BASE、USER_SITE;

最终用第四种方案解决了我们的问题,具体方法如下(奇怪的是,我明明没配置,但是 python -m site 命令返回的结果里却显示有):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 1. 查看 site.py所在位置
python -m site -help

# 得到输出
/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/site.py [--user-base] [--user-site]

Without arguments print some useful information
With arguments print the value of USER_BASE and/or USER_SITE separated
by ':'.

Exit codes with --user-base or --user-site:
0 - user site directory is enabled
1 - user site directory is disabled by user
2 - uses site directory is disabled by super user
or for security reasons
>2 - unknown error

# 2. 进入路径,备份文件、编辑文件
cd /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8
cp site.py site_bak.py
sudo vim site.py

# 3. 修改配置,如下,然后保存退出
# Enable per user site-packages directory
# set it to False to disable the feature or True to force the feature
ENABLE_USER_SITE = True

# for distutils.commands.install
# These values are initialized by the getuserbase() and getusersitepackages()
# functions, through the main() function when Python starts.
USER_SITE = "/Users/gavin/Library/Python/3.8/lib/python/site-packages"
USER_BASE = "/Users/gavin/Library/Python/3.8"

然后执行安装依赖命令,可正常执行。