Skip to content

Commit

Permalink
Move to pyproject.toml; CI python 3.12.
Browse files Browse the repository at this point in the history
  • Loading branch information
anntzer committed Oct 19, 2023
1 parent e771c74 commit 38641b7
Show file tree
Hide file tree
Showing 33 changed files with 183 additions and 189 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-11, windows-2019]
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
Expand All @@ -21,7 +21,7 @@ jobs:
set -x &&
export DISTUTILS_DEBUG=1 &&
python -mpip install --upgrade pip setuptools &&
python -mpip install --upgrade pip &&
case "$(python -c 'import sys; print(sys.platform)')" in
linux)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 0 additions & 2 deletions lib/mplcairo/.gitignore

This file was deleted.

44 changes: 44 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[build-system]
requires = [
"setuptools>=62",
"setuptools_scm[toml]>=6.2",
"pybind11>=2.8.0",
"pycairo>=1.16.0; os_name == 'posix'", # Removed for manylinux build.
]
build-backend = "setuptools.build_meta"

[project]
name = "mplcairo"
description = "A (new) cairo backend for Matplotlib."
readme = "README.rst"
authors = [{name = "Antony Lee"}]
license = {text = "MIT"}
classifiers = [
"Development Status :: 4 - Beta",
"Framework :: Matplotlib",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
]
requires-python = ">=3.8"
dependencies = [
"matplotlib>=2.2",
"pillow", # Already a dependency of mpl>=3.3.
"pycairo>=1.16.0; os_name == 'posix'",
]
dynamic = ["version"]

[tool.setuptools_scm]
version_scheme = "post-release"
local_scheme = "node-and-date"
fallback_version = "0+unknown"

[tool.coverage.run]
branch = true
source_pkgs = ["mplcairo"]

[tool.pytest.ini_options]
filterwarnings = [
"error",
"ignore::DeprecationWarning",
"error::DeprecationWarning:mplcairo",
]
218 changes: 106 additions & 112 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Environment variables:
MPLCAIRO_MANYLINUX
If set, build a manylinux wheel: pycairo is not declared as setup_requires.
If set, build a manylinux wheel: pycairo is not a build requirement.
MPLCAIRO_NO_UNITY_BUILD
If set, compile the various cpp files separately, instead of as a single
Expand All @@ -23,22 +23,21 @@
import subprocess
from subprocess import CalledProcessError
import sys
from tempfile import TemporaryDirectory
import tokenize
import urllib.request

if sys.platform == "darwin":
os.environ.setdefault("CC", "clang")
# Funnily enough, distutils uses $CC to compile c++ extensions but
# $CXX to *link* such extensions... (Moreover, it does some funky
# changes to $CXX if either $CC or $CXX has multiple words -- see e.g.
# https://bugs.python.org/issue6863.)
os.environ.setdefault("CXX", "clang")

from setupext import Extension, build_ext, find_packages, setup
import setuptools
from setuptools import Distribution
from pybind11.setup_helpers import Pybind11Extension
if os.environ.get("MPLCAIRO_MANYLINUX", ""):
cairo = None
else:
import cairo


MIN_CAIRO_VERSION = "1.13.1" # Also in _feature_tests.cpp.
MIN_RAQM_VERSION = "0.7.0"
MANYLINUX = bool(os.environ.get("MPLCAIRO_MANYLINUX", ""))
UNITY_BUILD = not bool(os.environ.get("MPLCAIRO_NO_UNITY_BUILD"))


Expand All @@ -47,6 +46,63 @@ def get_pkgconfig(*args):
universal_newlines=True))


def gen_extension(tmpdir):
ext = Pybind11Extension(
"mplcairo._mplcairo",
sources=(
["ext/_unity_build.cpp"] if UNITY_BUILD else
sorted({*map(str, Path("ext").glob("*.cpp"))}
- {"ext/_unity_build.cpp"})),
depends=[
"setup.py",
*map(str, Path("ext").glob("*.h")),
*map(str, Path("ext").glob("*.cpp")),
],
cxx_std=17,
include_dirs=[cairo.get_include()] if cairo else [],
)

# NOTE: Versions <= 8.2 of Arch Linux's python-pillow package included
# *into a non-overridable distutils header directory* a ``raqm.h`` that
# is both invalid (https://bugs.archlinux.org/task/57492) and outdated
# (missing a declaration for `raqm_version_string`). It is thus not
# possible to build mplcairo with such an old distro package installed.
try:
get_pkgconfig(f"raqm >= {MIN_RAQM_VERSION}")
except (FileNotFoundError, CalledProcessError):
tmpdir.mkdir(parents=True, exist_ok=True)
(tmpdir / "raqm-version.h").write_text("") # Touch it.
with urllib.request.urlopen(
f"https://raw.githubusercontent.com/HOST-Oman/libraqm/"
f"v{MIN_RAQM_VERSION}/ext/raqm.h") as request, \
(tmpdir / "raqm.h").open("wb") as file:
file.write(request.read())
ext.include_dirs += [tmpdir]
else:
ext.extra_compile_args += get_pkgconfig("--cflags", "raqm")

if os.name == "posix":
get_pkgconfig(f"cairo >= {MIN_CAIRO_VERSION}")
ext.extra_compile_args += [
"-flto", "-Wall", "-Wextra", "-Wpedantic",
*get_pkgconfig("--cflags", "cairo"),
]
ext.extra_link_args += ["-flto"]

elif os.name == "nt":
# Windows conda path for FreeType.
ext.include_dirs += [Path(sys.prefix, "Library/include")]
ext.extra_compile_args += [
"/experimental:preprocessor",
"/wd4244", "/wd4267", # cf. gcc -Wconversion.
]
ext.libraries += ["psapi", "cairo", "freetype"]
# Windows conda path for FreeType -- needs to be str, not Path.
ext.library_dirs += [str(Path(sys.prefix, "Library/lib"))]

return ext


@functools.lru_cache(1)
def paths_from_link_libpaths():
# "Easy" way to call CommandLineToArgvW...
Expand All @@ -61,69 +117,7 @@ def paths_from_link_libpaths():
return paths


class build_ext(build_ext):

def finalize_options(self):
import cairo
from pybind11.setup_helpers import Pybind11Extension

self.distribution.ext_modules[:] = ext, = [Pybind11Extension(
"mplcairo._mplcairo",
sources=(
["src/_unity_build.cpp"] if UNITY_BUILD else
sorted({*map(str, Path("src").glob("*.cpp"))}
- {"src/_unity_build.cpp"})),
depends=[
"setup.py",
*map(str, Path("src").glob("*.h")),
*map(str, Path("src").glob("*.cpp")),
],
cxx_std=17,
include_dirs=[cairo.get_include()],
)]

# NOTE: Versions <= 8.2 of Arch Linux's python-pillow package included
# *into a non-overridable distutils header directory* a ``raqm.h`` that
# is both invalid (https://bugs.archlinux.org/task/57492) and outdated
# (missing a declaration for `raqm_version_string`). It is thus not
# possible to build mplcairo with such an old distro package installed.
try:
get_pkgconfig(f"raqm >= {MIN_RAQM_VERSION}")
except (FileNotFoundError, CalledProcessError):
tmp_include_dir = Path(
self.get_finalized_command("build").build_base, "include")
tmp_include_dir.mkdir(parents=True, exist_ok=True)
(tmp_include_dir / "raqm-version.h").write_text("") # Touch it.
with urllib.request.urlopen(
f"https://raw.githubusercontent.com/HOST-Oman/libraqm/"
f"v{MIN_RAQM_VERSION}/src/raqm.h") as request, \
(tmp_include_dir / "raqm.h").open("wb") as file:
file.write(request.read())
ext.include_dirs += [tmp_include_dir]
else:
ext.extra_compile_args += get_pkgconfig("--cflags", "raqm")

if os.name == "posix":
get_pkgconfig(f"cairo >= {MIN_CAIRO_VERSION}")
ext.extra_compile_args += [
"-flto", "-Wall", "-Wextra", "-Wpedantic",
*get_pkgconfig("--cflags", "cairo"),
]
ext.extra_link_args += ["-flto"]

elif os.name == "nt":
# Windows conda path for FreeType.
ext.include_dirs += [Path(sys.prefix, "Library/include")]
ext.extra_compile_args += [
"/experimental:preprocessor",
"/wd4244", "/wd4267", # cf. gcc -Wconversion.
]
ext.libraries += ["psapi", "cairo", "freetype"]
# Windows conda path for FreeType -- needs to be str, not Path.
ext.library_dirs += [str(Path(sys.prefix, "Library/lib"))]

super().finalize_options()

class build_ext(setuptools.command.build_ext.build_ext):
def _copy_dlls_to(self, dest):
if os.name == "nt":
for dll in ["cairo.dll", "freetype.dll"]:
Expand All @@ -142,41 +136,41 @@ def copy_extensions_to_source(self):
self.get_finalized_command("build_py").get_package_dir("mplcairo"))


setup.register_pth_hook("setup_mplcairo_pth.py", "mplcairo.pth")


setup(
name="mplcairo",
description="A (new) cairo backend for Matplotlib.",
long_description=open("README.rst", encoding="utf-8").read(),
author="Antony Lee",
url="https://github.com/matplotlib/mplcairo",
license="MIT",
classifiers=[
"Development Status :: 4 - Beta",
"Framework :: Matplotlib",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
],
cmdclass={"build_ext": build_ext},
packages=find_packages("lib"),
package_dir={"": "lib"},
ext_modules=[Extension("", [])],
python_requires=">=3.8",
setup_requires=[
"setuptools>=36.7", # setup_requires early install.
"setuptools_scm",
"pybind11>=2.8.0",
*(["pycairo>=1.16.0; os_name == 'posix'"] if not MANYLINUX else []),
],
use_scm_version={ # xref __init__.py
"version_scheme": "post-release",
"local_scheme": "node-and-date",
"write_to": "lib/mplcairo/_version.py",
},
install_requires=[
"matplotlib>=2.2",
"pillow", # Already a dependency of mpl>=3.3.
"pycairo>=1.16.0; os_name == 'posix'",
],
)
def register_pth_hook(source_path, pth_name):
"""
::
setup.register_pth_hook("hook_source.py", "hook_name.pth") # Add hook.
"""
with tokenize.open(source_path) as file:
source = file.read()
_pth_hook_mixin._pth_hooks.append((pth_name, source))


class _pth_hook_mixin:
_pth_hooks = []

def run(self):
super().run()
for pth_name, source in self._pth_hooks:
with Path(self.install_dir, pth_name).open("w") as file:
file.write(f"import os; exec({source!r})")

def get_outputs(self):
return (super().get_outputs()
+ [str(Path(self.install_dir, pth_name))
for pth_name, _ in self._pth_hooks])


def setup(**kwargs):
cmdclass = kwargs.setdefault("cmdclass", {})
get = Distribution({"cmdclass": cmdclass}).get_command_class
cmdclass["develop"] = type(
"develop_with_pth_hook", (_pth_hook_mixin, get("develop")), {})
cmdclass["install_lib"] = type(
"install_lib_with_pth_hook", (_pth_hook_mixin, get("install_lib")), {})
setuptools.setup(**kwargs)


register_pth_hook("setup_mplcairo_pth.py", "mplcairo.pth")
with TemporaryDirectory() as tmpdir:
setup(ext_modules=[gen_extension(tmpdir=Path(tmpdir))])
60 changes: 0 additions & 60 deletions setupext.py

This file was deleted.

1 change: 1 addition & 0 deletions src/mplcairo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.dll
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 38641b7

Please sign in to comment.