How do I distribute fonts with my python package?
Question: I have created a package called
[clearplot](http://clearplot.readthedocs.org/en/latest/index.html) that wraps
around matplotlib. I have also created a nice font that I want to distribute
with my package. I consulted [this section](https://python-packaging-user-
guide.readthedocs.org/en/latest/distributing/#data-files) of the Python
Packaging User guide, and determined that I should use the `data_files`
keyword. I chose `data_files` instead of `package_data` since I need to
install the font in a matplotlib directory that is _outside_ of my package.

Here is my first, flawed, attempt at a `setup.py` file:

    
    
    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)
    

There are two issues with this `setup.py`:

  1. I attempt to import matplotlib before `setup()` has a chance to install it. This is an obvious booboo, but I needed to know where `mpl_ttf_dir` was before I ran `setup()`.
  2. As mentioned [here](https://python-packaging-user-guide.readthedocs.org/en/latest/distributing/#data-files), wheel distributions do not support absolute paths for `data_files`. I didn't think this would be a problem because I thought I would just use a sdist distribution. (sdists do allow absolute paths.) Then I came to find out that pip 7.0 (and later) converts all packages to wheel distributions, even if the distribution was originally created as a sdist.

I was quite annoyed by issue #2, but, since then, I found out that absolute
paths are bad because they do not work with virtualenv. Thus, I am now willing
to change my approach, but what do I do?

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?


Answer: > 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?

I would consider doing exactly this. I know your package may not be an obvious
candidate for virtualenvs, but consider that python packages may be installed
only to a user-writable location. Thus, copying the font when you first run
your programme and detecting the correct location, might prompt you to do
stuff in a better manner than possible through setup.py, stuff like: Elevate
privileges through a password prompt in case it's needed, ask for a different
location in case you fail to detect it, prompt if you are over-writing
existing system files etc.

I once tried arguing that Python packages should be able to place stuff in
`/etc`, but I realized the benefits were small compared to just creating a
proper native package for the target OS, i.e. a debian package for Debian or a
.exe installer for Windows.

The bottom line is that wheel and setuptools are not package managers for your
entire OS, but just for what's in some local `site-packages/`.

I hope this answer gives you enough background to avoid `data_files`. One last
good reason: Making it work across distutils, setuptools, and wheel is a no-
go.

