如何使用python包分发字体?

2024-04-20 14:04:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经创建了一个名为clearplot的包,它环绕matplotlib。我还想用我的字体分发我的包。我查阅了Python打包用户指南中的this section,决定使用data_files关键字。我选择了data_files而不是{},因为我需要将字体安装在包的外部的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有两个问题:

  1. 我试图在setup()有机会安装matplotlib之前导入它。这是一个明显的错误,但是在我运行setup()之前,我需要知道mpl_ttf_dir在哪里。在
  2. 正如前面提到的here,轮子分布不支持data_files的绝对路径。我不认为这会是一个问题,因为我想我只会使用一个sdist分布。(sdist允许绝对路径)然后我发现pip7.0(及更高版本)将所有包转换为wheel发行版,即使发行版最初是作为sdist创建的。在

我对问题2很恼火,但从那以后,我发现绝对路径是不好的,因为它们不适用于virtualenv。因此,我现在愿意改变我的方法,但是我该怎么做呢?在

我唯一的想法是首先将字体作为package_data分发,然后使用os模块将字体移动到适当的位置。这是一种洁净的方法吗?在


Tags: pathpyimportcachedatamatplotlibosdir
2条回答

多亏了@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(它使用wheels)。在

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包可能只安装到用户可写的位置。因此,在您第一次运行程序时复制字体并检测到正确的位置,可能会提示您以比通过更有效的方式执行操作设置.py,比如:在需要时通过密码提示提升权限,如果检测不到,请求另一个位置,如果您正在重写现有的系统文件等,请提示

我曾经试图论证Python包应该能够在/etc中放置内容,但是我意识到与仅仅为目标操作系统创建一个合适的本机包(即debian的debian包或Windows的.exe安装程序)相比,它的好处是很小的。在

底线是wheel和setuptools不是整个操作系统的包管理器,而是一些本地site-packages/中的包管理器。在

我希望这个答案能给你足够的背景知识来避免data_files。最后一个好的理由是:让它在distutil、setuptools和wheel上工作是不可能的。在

相关问题 更多 >