如何使用我的 python 包分发字体?
How do I distribute fonts with my python package?
我在 Python 打包用户指南中创建了一个名为 clearplot that wraps around matplotlib. I have also created a nice font that I want to distribute with my package. I consulted this section 的包,并确定我应该使用 data_files
关键字。我选择 data_files
而不是 package_data
,因为我需要将字体安装在包 外部 的 matplotlib 目录中。
这是我对 setup.py
文件的第一个有缺陷的尝试:
from distutils.core import setup
import os, sys
import matplotlib as mpl
#Find where matplotlib stores its True Type fonts
mpl_data_dir = os.path.dirname(mpl.matplotlib_fname())
mpl_ttf_dir = os.path.join(mpl_data_dir, 'fonts', 'ttf')
setup(
...(edited for brevity)...
install_requires = ['matplotlib >= 1.4.0, !=1.4.3', 'numpy >= 1.6'],
data_files = [
(mpl_ttf_dir, ['./font_files/TeXGyreHeros-txfonts/TeXGyreHerosTXfonts-Regular.ttf']),
(mpl_ttf_dir, ['./font_files/TeXGyreHeros-txfonts/TeXGyreHerosTXfonts-Italic.ttf'])]
)
#Try to delete matplotlib's fontList cache
mpl_cache_dir = mpl.get_cachedir()
mpl_cache_dir_ls = os.listdir(mpl_cache_dir)
if 'fontList.cache' in mpl_cache_dir_ls:
fontList_path = os.path.join(mpl_cache_dir, 'fontList.cache')
os.remove(fontList_path)
这个 setup.py
有两个问题:
- 我尝试在
setup()
有机会安装之前导入 matplotlib。这是一个明显的错误,但在 运行 setup()
. 之前我需要知道 mpl_ttf_dir
在哪里
- 如前所述 here,车轮分布不支持
data_files
的绝对路径。我不认为这会是个问题,因为我认为我只会使用 sdist 发行版。 (sdists 确实允许绝对路径。)然后我发现 pip 7.0(及更高版本)将所有包转换为 wheel 分布,即使该分布最初是作为 sdist 创建的。
我对问题 #2 非常恼火,但是从那时起,我发现绝对路径是错误的,因为它们不适用于 virtualenv。因此,我现在愿意改变我的做法,但我该怎么办?
我唯一的想法是首先将字体分发为 package_data
,然后使用 os
模块将字体移动到正确的位置。这是犹太洁食方法吗?
The only idea I have is to distribute the font as package_data first and then move the font to the proper location afterwards using the os module. Is that a kosher method?
我会考虑这样做。我知道你的包可能不是 virtualenvs 的明显候选者,但考虑到 python 包可能只安装到用户可写的位置。因此,当您第一次 运行 您的程序并检测到正确的位置时复制字体,可能会提示您以比通过 setup.py 更好的方式做事,例如:通过密码提示提升权限如果需要它,要求一个不同的位置,以防您无法检测到它,提示您是否正在覆盖现有的系统文件等。
我曾经试图争论 Python 包应该能够在 /etc
中放置东西,但我意识到与为目标 [=26 创建适当的本机包相比,好处很小=],即 Debian 的 debian 软件包或 Windows.
的 .exe 安装程序
最重要的是,wheel 和 setuptools 不是整个 OS 的包管理器,而只是某些本地 site-packages/
.
中的包管理器
我希望这个答案能为您提供足够的背景知识以避免 data_files
。最后一个很好的理由:让它跨 distutils、setuptools 和 wheel 工作是不行的。
感谢@benjaoming 的回答和 this blog post,这是我想出的:
from setuptools import setup
from setuptools.command.install import install
import warnings
#Set up the machinery to install custom fonts. Subclass the setup tools install
#class in order to run custom commands during installation.
class move_ttf(install):
def run(self):
"""
Performs the usual install process and then copies the True Type fonts
that come with clearplot into matplotlib's True Type font directory,
and deletes the matplotlib fontList.cache
"""
#Perform the usual install process
install.run(self)
#Try to install custom fonts
try:
import os, shutil
import matplotlib as mpl
import clearplot as cp
#Find where matplotlib stores its True Type fonts
mpl_data_dir = os.path.dirname(mpl.matplotlib_fname())
mpl_ttf_dir = os.path.join(mpl_data_dir, 'fonts', 'ttf')
#Copy the font files to matplotlib's True Type font directory
#(I originally tried to move the font files instead of copy them,
#but it did not seem to work, so I gave up.)
cp_ttf_dir = os.path.join(os.path.dirname(cp.__file__), 'true_type_fonts')
for file_name in os.listdir(cp_ttf_dir):
if file_name[-4:] == '.ttf':
old_path = os.path.join(cp_ttf_dir, file_name)
new_path = os.path.join(mpl_ttf_dir, file_name)
shutil.copyfile(old_path, new_path)
print "Copying " + old_path + " -> " + new_path
#Try to delete matplotlib's fontList cache
mpl_cache_dir = mpl.get_cachedir()
mpl_cache_dir_ls = os.listdir(mpl_cache_dir)
if 'fontList.cache' in mpl_cache_dir_ls:
fontList_path = os.path.join(mpl_cache_dir, 'fontList.cache')
os.remove(fontList_path)
print "Deleted the matplotlib fontList.cache"
except:
warnings.warn("WARNING: An issue occured while installing the custom fonts for clearplot.")
setup(...
#Specify the dependencies and versions
install_requires = ['matplotlib >= 1.4.0, !=1.4.3', 'numpy >= 1.6'],
#Specify any non-python files to be distributed with the package
package_data = {'' : ['color_maps/*.csv', 'true_type_fonts/*.ttf']},
#Specify the custom install class
cmdclass={'install' : move_ttf}
)
这解决了问题 #1(它在导入之前安装 matplotlib)和问题 #2(它适用于轮子)。
我在 Python 打包用户指南中创建了一个名为 clearplot that wraps around matplotlib. I have also created a nice font that I want to distribute with my package. I consulted this section 的包,并确定我应该使用 data_files
关键字。我选择 data_files
而不是 package_data
,因为我需要将字体安装在包 外部 的 matplotlib 目录中。
这是我对 setup.py
文件的第一个有缺陷的尝试:
from distutils.core import setup
import os, sys
import matplotlib as mpl
#Find where matplotlib stores its True Type fonts
mpl_data_dir = os.path.dirname(mpl.matplotlib_fname())
mpl_ttf_dir = os.path.join(mpl_data_dir, 'fonts', 'ttf')
setup(
...(edited for brevity)...
install_requires = ['matplotlib >= 1.4.0, !=1.4.3', 'numpy >= 1.6'],
data_files = [
(mpl_ttf_dir, ['./font_files/TeXGyreHeros-txfonts/TeXGyreHerosTXfonts-Regular.ttf']),
(mpl_ttf_dir, ['./font_files/TeXGyreHeros-txfonts/TeXGyreHerosTXfonts-Italic.ttf'])]
)
#Try to delete matplotlib's fontList cache
mpl_cache_dir = mpl.get_cachedir()
mpl_cache_dir_ls = os.listdir(mpl_cache_dir)
if 'fontList.cache' in mpl_cache_dir_ls:
fontList_path = os.path.join(mpl_cache_dir, 'fontList.cache')
os.remove(fontList_path)
这个 setup.py
有两个问题:
- 我尝试在
setup()
有机会安装之前导入 matplotlib。这是一个明显的错误,但在 运行setup()
. 之前我需要知道 - 如前所述 here,车轮分布不支持
data_files
的绝对路径。我不认为这会是个问题,因为我认为我只会使用 sdist 发行版。 (sdists 确实允许绝对路径。)然后我发现 pip 7.0(及更高版本)将所有包转换为 wheel 分布,即使该分布最初是作为 sdist 创建的。
mpl_ttf_dir
在哪里
我对问题 #2 非常恼火,但是从那时起,我发现绝对路径是错误的,因为它们不适用于 virtualenv。因此,我现在愿意改变我的做法,但我该怎么办?
我唯一的想法是首先将字体分发为 package_data
,然后使用 os
模块将字体移动到正确的位置。这是犹太洁食方法吗?
The only idea I have is to distribute the font as package_data first and then move the font to the proper location afterwards using the os module. Is that a kosher method?
我会考虑这样做。我知道你的包可能不是 virtualenvs 的明显候选者,但考虑到 python 包可能只安装到用户可写的位置。因此,当您第一次 运行 您的程序并检测到正确的位置时复制字体,可能会提示您以比通过 setup.py 更好的方式做事,例如:通过密码提示提升权限如果需要它,要求一个不同的位置,以防您无法检测到它,提示您是否正在覆盖现有的系统文件等。
我曾经试图争论 Python 包应该能够在 /etc
中放置东西,但我意识到与为目标 [=26 创建适当的本机包相比,好处很小=],即 Debian 的 debian 软件包或 Windows.
最重要的是,wheel 和 setuptools 不是整个 OS 的包管理器,而只是某些本地 site-packages/
.
我希望这个答案能为您提供足够的背景知识以避免 data_files
。最后一个很好的理由:让它跨 distutils、setuptools 和 wheel 工作是不行的。
感谢@benjaoming 的回答和 this blog post,这是我想出的:
from setuptools import setup
from setuptools.command.install import install
import warnings
#Set up the machinery to install custom fonts. Subclass the setup tools install
#class in order to run custom commands during installation.
class move_ttf(install):
def run(self):
"""
Performs the usual install process and then copies the True Type fonts
that come with clearplot into matplotlib's True Type font directory,
and deletes the matplotlib fontList.cache
"""
#Perform the usual install process
install.run(self)
#Try to install custom fonts
try:
import os, shutil
import matplotlib as mpl
import clearplot as cp
#Find where matplotlib stores its True Type fonts
mpl_data_dir = os.path.dirname(mpl.matplotlib_fname())
mpl_ttf_dir = os.path.join(mpl_data_dir, 'fonts', 'ttf')
#Copy the font files to matplotlib's True Type font directory
#(I originally tried to move the font files instead of copy them,
#but it did not seem to work, so I gave up.)
cp_ttf_dir = os.path.join(os.path.dirname(cp.__file__), 'true_type_fonts')
for file_name in os.listdir(cp_ttf_dir):
if file_name[-4:] == '.ttf':
old_path = os.path.join(cp_ttf_dir, file_name)
new_path = os.path.join(mpl_ttf_dir, file_name)
shutil.copyfile(old_path, new_path)
print "Copying " + old_path + " -> " + new_path
#Try to delete matplotlib's fontList cache
mpl_cache_dir = mpl.get_cachedir()
mpl_cache_dir_ls = os.listdir(mpl_cache_dir)
if 'fontList.cache' in mpl_cache_dir_ls:
fontList_path = os.path.join(mpl_cache_dir, 'fontList.cache')
os.remove(fontList_path)
print "Deleted the matplotlib fontList.cache"
except:
warnings.warn("WARNING: An issue occured while installing the custom fonts for clearplot.")
setup(...
#Specify the dependencies and versions
install_requires = ['matplotlib >= 1.4.0, !=1.4.3', 'numpy >= 1.6'],
#Specify any non-python files to be distributed with the package
package_data = {'' : ['color_maps/*.csv', 'true_type_fonts/*.ttf']},
#Specify the custom install class
cmdclass={'install' : move_ttf}
)
这解决了问题 #1(它在导入之前安装 matplotlib)和问题 #2(它适用于轮子)。