Problem statement
My package relies on matplotlib to use a specific font which may not be installed on the target device.
I'm trying to install ttf font files from the source distribution to the matplotlib fonts/ttf
directory, after building the package.
With setuptools
slowly removing parts of its CLI (python setup.py sdist/bdist_wheel
) and the possibility to use build
(python -m build
), I decided to build my package with the latter.
What I tried
I tried modifying the setup.py
from the outdated https://stackoverflow.com/a/34304823/8797886.
My question differs from this post in that I would like to use python -m build
.
setup.py
import warnings
from functools import partial
from setuptools import setup
from setuptools.command.install import install
def _post_install():
# Try to install custom fonts
try:
import os
import shutil
import matplotlib as mpl
import mypkg
# 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(mypkg.__file__), "ttf")
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.move(old_path, new_path)
print("moving" 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(
"An issue occured while installing the custom fonts for mypkg."
)
raise
# Set up the machinery to install custom fonts. Subclass the setup tools install
# class in order to run custom commands during installation.
class MoveTTF(install):
def run(self):
"""
Performs the usual install process and then copies the True Type fonts
that come with shithappens into matplotlib's True Type font directory,
and deletes the matplotlib fontList.cache.
"""
# Perform the usual install process
install.run(self)
self.execute(_post_install, (), "Moving Custom Font to matplotlib.")
setup_movettf = partial(
setup,
package_data={"": ["ttf/*.ttf"]},
cmdclass={"install": MoveTTF},
)
setup_movettf()
I used a partial
setup
, because I expect build
to fill in all the other stuff from pyproject.toml
.
pyproject.toml
[build-system]
requires = ["setuptools>=61.0", "matplotlib"]
build-backend = "setuptools.build_meta"
[project]
name = "mypkg"
etc...
[tool.setuptools.packages.find]
where = ["src"]
[tool.setuptools.package-data]
mypkg = ["ttf/*.ttf"]
What I get
When I use python -m build
, I get
ModuleNotFoundError: No module named 'mypkg'
When I use python setup.py sdist
and python setup.py bdist_wheel
, the wheel is successfully build.
When installing the wheel with pip install dist/mypkg-[].whl
, the install is successful and the matplotlib ttf library is populated with the custom fonts.
What I expect
I expect python -m build
to work with importing mypkg
post-install, like the setuptools cli does.
CodePudding user response:
You can not do this with Python packaging tools. You need to go beyond that. Some platform specific packaging tools. Think .deb
/apt
on Debian/Ubuntu or full blown executable installers on Windows (or .msi
if it still exists).
This is for operations at "install-time"...
... but you do not need to do this at "install-time", the code of your application or library can contain functions to do this installation of the fonts at run-time.
On the other hand, if you and your users only ever use the setup.py
script, without using pip at all (or any other modern installer), then it will likely still work, because obviously you can put any code you want in setup.py
without restriction.
There might be some more details in these: