Haibo Huang | 5406a6a | 2020-02-26 16:36:20 -0800 | [diff] [blame] | 1 | #! /usr/bin/env python3 |
jvr | 3285b4b | 2001-08-09 18:47:22 +0000 | [diff] [blame] | 2 | |
Denis Jacquerye | db08ee2 | 2013-11-29 14:11:19 +0100 | [diff] [blame] | 3 | from __future__ import print_function |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 4 | import io |
| 5 | import sys |
| 6 | import os |
| 7 | from os.path import isfile, join as pjoin |
| 8 | from glob import glob |
Haibo Huang | d123eeb | 2020-04-03 12:18:18 -0700 | [diff] [blame] | 9 | from setuptools import setup, find_packages, Command, Extension |
| 10 | from setuptools.command.build_ext import build_ext as _build_ext |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 11 | from distutils import log |
| 12 | from distutils.util import convert_path |
| 13 | import subprocess as sp |
| 14 | import contextlib |
| 15 | import re |
jvr | 3285b4b | 2001-08-09 18:47:22 +0000 | [diff] [blame] | 16 | |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 17 | # Force distutils to use py_compile.compile() function with 'doraise' argument |
| 18 | # set to True, in order to raise an exception on compilation errors |
| 19 | import py_compile |
| 20 | orig_py_compile = py_compile.compile |
jvr | 3285b4b | 2001-08-09 18:47:22 +0000 | [diff] [blame] | 21 | |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 22 | def doraise_py_compile(file, cfile=None, dfile=None, doraise=False): |
| 23 | orig_py_compile(file, cfile=cfile, dfile=dfile, doraise=True) |
| 24 | |
| 25 | py_compile.compile = doraise_py_compile |
| 26 | |
Haibo Huang | d123eeb | 2020-04-03 12:18:18 -0700 | [diff] [blame] | 27 | setup_requires = [] |
| 28 | |
| 29 | if {'bdist_wheel'}.intersection(sys.argv): |
| 30 | setup_requires.append('wheel') |
| 31 | |
| 32 | if {'release'}.intersection(sys.argv): |
| 33 | setup_requires.append('bump2version') |
| 34 | |
| 35 | try: |
| 36 | __import__("cython") |
| 37 | except ImportError: |
| 38 | has_cython = False |
| 39 | else: |
| 40 | has_cython = True |
| 41 | |
| 42 | env_with_cython = os.environ.get("FONTTOOLS_WITH_CYTHON") |
| 43 | with_cython = ( |
| 44 | True if env_with_cython in {"1", "true", "yes"} |
| 45 | else False if env_with_cython in {"0", "false", "no"} |
| 46 | else None |
| 47 | ) |
| 48 | # --with-cython/--without-cython options override environment variables |
| 49 | opt_with_cython = {'--with-cython'}.intersection(sys.argv) |
| 50 | opt_without_cython = {'--without-cython'}.intersection(sys.argv) |
| 51 | if opt_with_cython and opt_without_cython: |
| 52 | sys.exit( |
| 53 | "error: the options '--with-cython' and '--without-cython' are " |
| 54 | "mutually exclusive" |
| 55 | ) |
| 56 | elif opt_with_cython: |
| 57 | sys.argv.remove("--with-cython") |
| 58 | with_cython = True |
| 59 | elif opt_without_cython: |
| 60 | sys.argv.remove("--without-cython") |
| 61 | with_cython = False |
| 62 | |
| 63 | if with_cython and not has_cython: |
| 64 | setup_requires.append("cython") |
| 65 | |
| 66 | ext_modules = [] |
| 67 | if with_cython is True or (with_cython is None and has_cython): |
| 68 | ext_modules.append( |
| 69 | Extension("fontTools.cu2qu.cu2qu", ["Lib/fontTools/cu2qu/cu2qu.py"]), |
| 70 | ) |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 71 | |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 72 | extras_require = { |
| 73 | # for fontTools.ufoLib: to read/write UFO fonts |
| 74 | "ufo": [ |
Haibo Huang | f08648c | 2019-02-01 17:02:23 -0800 | [diff] [blame] | 75 | "fs >= 2.2.0, < 3", |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 76 | ], |
| 77 | # for fontTools.misc.etree and fontTools.misc.plistlib: use lxml to |
| 78 | # read/write XML files (faster/safer than built-in ElementTree) |
| 79 | "lxml": [ |
| 80 | "lxml >= 4.0, < 5", |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 81 | ], |
| 82 | # for fontTools.sfnt and fontTools.woff2: to compress/uncompress |
| 83 | # WOFF 1.0 and WOFF 2.0 webfonts. |
| 84 | "woff": [ |
Haibo Huang | 7de6799 | 2020-12-04 18:55:08 -0800 | [diff] [blame] | 85 | "brotli >= 1.0.1; platform_python_implementation == 'CPython'", |
| 86 | "brotlicffi >= 0.8.0; platform_python_implementation != 'CPython'", |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 87 | "zopfli >= 0.1.4", |
| 88 | ], |
| 89 | # for fontTools.unicode and fontTools.unicodedata: to use the latest version |
| 90 | # of the Unicode Character Database instead of the built-in unicodedata |
| 91 | # which varies between python versions and may be outdated. |
| 92 | "unicode": [ |
Rod S | 0b59a54 | 2022-03-25 12:41:45 -0700 | [diff] [blame] | 93 | # Python 3.11 already has Unicode 14.0, so the backport is not needed. |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 94 | ( |
Rod S | 0b59a54 | 2022-03-25 12:41:45 -0700 | [diff] [blame] | 95 | "unicodedata2 >= 14.0.0; python_version < '3.11'" |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 96 | ), |
| 97 | ], |
Haibo Huang | 79019a0 | 2019-01-08 14:14:22 -0800 | [diff] [blame] | 98 | # for graphite type tables in ttLib/tables (Silf, Glat, Gloc) |
| 99 | "graphite": [ |
| 100 | "lz4 >= 1.7.4.2" |
| 101 | ], |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 102 | # for fontTools.interpolatable: to solve the "minimum weight perfect |
| 103 | # matching problem in bipartite graphs" (aka Assignment problem) |
| 104 | "interpolatable": [ |
| 105 | # use pure-python alternative on pypy |
| 106 | "scipy; platform_python_implementation != 'PyPy'", |
| 107 | "munkres; platform_python_implementation == 'PyPy'", |
| 108 | ], |
Haibo Huang | 79019a0 | 2019-01-08 14:14:22 -0800 | [diff] [blame] | 109 | # for fontTools.varLib.plot, to visualize DesignSpaceDocument and resulting |
| 110 | # VariationModel |
| 111 | "plot": [ |
| 112 | # TODO: figure out the minimum version of matplotlib that we need |
| 113 | "matplotlib", |
| 114 | ], |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 115 | # for fontTools.misc.symfont, module for symbolic font statistics analysis |
| 116 | "symfont": [ |
| 117 | "sympy", |
| 118 | ], |
| 119 | # To get file creator and type of Macintosh PostScript Type 1 fonts (macOS only) |
| 120 | "type1": [ |
| 121 | "xattr; sys_platform == 'darwin'", |
| 122 | ], |
Haibo Huang | 672f694 | 2020-10-28 22:20:03 -0700 | [diff] [blame] | 123 | # for fontTools.ttLib.removeOverlaps, to remove overlaps in TTF fonts |
| 124 | "pathops": [ |
| 125 | "skia-pathops >= 0.5.0", |
| 126 | ], |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 127 | } |
| 128 | # use a special 'all' key as shorthand to includes all the extra dependencies |
| 129 | extras_require["all"] = sum(extras_require.values(), []) |
| 130 | |
| 131 | |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 132 | # Trove classifiers for PyPI |
| 133 | classifiers = {"classifiers": [ |
| 134 | "Development Status :: 5 - Production/Stable", |
| 135 | "Environment :: Console", |
| 136 | "Environment :: Other Environment", |
| 137 | "Intended Audience :: Developers", |
| 138 | "Intended Audience :: End Users/Desktop", |
| 139 | "License :: OSI Approved :: MIT License", |
| 140 | "Natural Language :: English", |
| 141 | "Operating System :: OS Independent", |
| 142 | "Programming Language :: Python", |
| 143 | "Programming Language :: Python :: 2", |
| 144 | "Programming Language :: Python :: 3", |
| 145 | "Topic :: Text Processing :: Fonts", |
| 146 | "Topic :: Multimedia :: Graphics", |
| 147 | "Topic :: Multimedia :: Graphics :: Graphics Conversion", |
| 148 | ]} |
jvr | 5808f3f | 2001-08-09 23:03:47 +0000 | [diff] [blame] | 149 | |
| 150 | |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 151 | # concatenate README.rst and NEWS.rest into long_description so they are |
| 152 | # displayed on the FontTols project page on PyPI |
| 153 | with io.open("README.rst", "r", encoding="utf-8") as readme: |
| 154 | long_description = readme.read() |
| 155 | long_description += "\nChangelog\n~~~~~~~~~\n\n" |
| 156 | with io.open("NEWS.rst", "r", encoding="utf-8") as changelog: |
| 157 | long_description += changelog.read() |
jvr | 059cbe3 | 2002-07-01 09:11:01 +0000 | [diff] [blame] | 158 | |
| 159 | |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 160 | @contextlib.contextmanager |
| 161 | def capture_logger(name): |
| 162 | """ Context manager to capture a logger output with a StringIO stream. |
| 163 | """ |
| 164 | import logging |
jvr | 91bde17 | 2003-01-03 21:01:07 +0000 | [diff] [blame] | 165 | |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 166 | logger = logging.getLogger(name) |
| 167 | try: |
| 168 | import StringIO |
| 169 | stream = StringIO.StringIO() |
| 170 | except ImportError: |
| 171 | stream = io.StringIO() |
| 172 | handler = logging.StreamHandler(stream) |
| 173 | logger.addHandler(handler) |
| 174 | try: |
| 175 | yield stream |
| 176 | finally: |
| 177 | logger.removeHandler(handler) |
| 178 | |
| 179 | |
| 180 | class release(Command): |
| 181 | """ |
| 182 | Tag a new release with a single command, using the 'bumpversion' tool |
| 183 | to update all the version strings in the source code. |
| 184 | The version scheme conforms to 'SemVer' and PEP 440 specifications. |
| 185 | |
| 186 | Firstly, the pre-release '.devN' suffix is dropped to signal that this is |
| 187 | a stable release. If '--major' or '--minor' options are passed, the |
| 188 | the first or second 'semver' digit is also incremented. Major is usually |
| 189 | for backward-incompatible API changes, while minor is used when adding |
| 190 | new backward-compatible functionalities. No options imply 'patch' or bug-fix |
| 191 | release. |
| 192 | |
| 193 | A new header is also added to the changelog file ("NEWS.rst"), containing |
| 194 | the new version string and the current 'YYYY-MM-DD' date. |
| 195 | |
| 196 | All changes are committed, and an annotated git tag is generated. With the |
| 197 | --sign option, the tag is GPG-signed with the user's default key. |
| 198 | |
| 199 | Finally, the 'patch' part of the version string is bumped again, and a |
| 200 | pre-release suffix '.dev0' is appended to mark the opening of a new |
| 201 | development cycle. |
| 202 | |
| 203 | Links: |
| 204 | - http://semver.org/ |
| 205 | - https://www.python.org/dev/peps/pep-0440/ |
| 206 | - https://github.com/c4urself/bump2version |
| 207 | """ |
| 208 | |
| 209 | description = "update version strings for release" |
| 210 | |
| 211 | user_options = [ |
| 212 | ("major", None, "bump the first digit (incompatible API changes)"), |
| 213 | ("minor", None, "bump the second digit (new backward-compatible features)"), |
| 214 | ("sign", "s", "make a GPG-signed tag, using the default key"), |
| 215 | ("allow-dirty", None, "don't abort if working directory is dirty"), |
| 216 | ] |
| 217 | |
| 218 | changelog_name = "NEWS.rst" |
| 219 | version_RE = re.compile("^[0-9]+\.[0-9]+") |
| 220 | date_fmt = u"%Y-%m-%d" |
| 221 | header_fmt = u"%s (released %s)" |
| 222 | commit_message = "Release {new_version}" |
| 223 | tag_name = "{new_version}" |
| 224 | version_files = [ |
| 225 | "setup.cfg", |
| 226 | "setup.py", |
| 227 | "Lib/fontTools/__init__.py", |
| 228 | ] |
| 229 | |
| 230 | def initialize_options(self): |
| 231 | self.minor = False |
| 232 | self.major = False |
| 233 | self.sign = False |
| 234 | self.allow_dirty = False |
| 235 | |
| 236 | def finalize_options(self): |
| 237 | if all([self.major, self.minor]): |
| 238 | from distutils.errors import DistutilsOptionError |
| 239 | raise DistutilsOptionError("--major/--minor are mutually exclusive") |
| 240 | self.part = "major" if self.major else "minor" if self.minor else None |
| 241 | |
| 242 | def run(self): |
| 243 | if self.part is not None: |
| 244 | log.info("bumping '%s' version" % self.part) |
| 245 | self.bumpversion(self.part, commit=False) |
| 246 | release_version = self.bumpversion( |
| 247 | "release", commit=False, allow_dirty=True) |
| 248 | else: |
| 249 | log.info("stripping pre-release suffix") |
| 250 | release_version = self.bumpversion("release") |
| 251 | log.info(" version = %s" % release_version) |
| 252 | |
| 253 | changes = self.format_changelog(release_version) |
| 254 | |
| 255 | self.git_commit(release_version) |
| 256 | self.git_tag(release_version, changes, self.sign) |
| 257 | |
| 258 | log.info("bumping 'patch' version and pre-release suffix") |
| 259 | next_dev_version = self.bumpversion('patch', commit=True) |
| 260 | log.info(" version = %s" % next_dev_version) |
| 261 | |
| 262 | def git_commit(self, version): |
| 263 | """ Stage and commit all relevant version files, and format the commit |
| 264 | message with specified 'version' string. |
| 265 | """ |
| 266 | files = self.version_files + [self.changelog_name] |
| 267 | |
| 268 | log.info("committing changes") |
| 269 | for f in files: |
| 270 | log.info(" %s" % f) |
| 271 | if self.dry_run: |
| 272 | return |
| 273 | sp.check_call(["git", "add"] + files) |
| 274 | msg = self.commit_message.format(new_version=version) |
| 275 | sp.check_call(["git", "commit", "-m", msg], stdout=sp.PIPE) |
| 276 | |
| 277 | def git_tag(self, version, message, sign=False): |
| 278 | """ Create annotated git tag with given 'version' and 'message'. |
| 279 | Optionally 'sign' the tag with the user's GPG key. |
| 280 | """ |
| 281 | log.info("creating %s git tag '%s'" % ( |
| 282 | "signed" if sign else "annotated", version)) |
| 283 | if self.dry_run: |
| 284 | return |
| 285 | # create an annotated (or signed) tag from the new version |
| 286 | tag_opt = "-s" if sign else "-a" |
| 287 | tag_name = self.tag_name.format(new_version=version) |
| 288 | proc = sp.Popen( |
| 289 | ["git", "tag", tag_opt, "-F", "-", tag_name], stdin=sp.PIPE) |
| 290 | # use the latest changes from the changelog file as the tag message |
| 291 | tag_message = u"%s\n\n%s" % (tag_name, message) |
| 292 | proc.communicate(tag_message.encode('utf-8')) |
| 293 | if proc.returncode != 0: |
| 294 | sys.exit(proc.returncode) |
| 295 | |
| 296 | def bumpversion(self, part, commit=False, message=None, allow_dirty=None): |
| 297 | """ Run bumpversion.main() with the specified arguments, and return the |
| 298 | new computed version string (cf. 'bumpversion --help' for more info) |
| 299 | """ |
Haibo Huang | 5406a6a | 2020-02-26 16:36:20 -0800 | [diff] [blame] | 300 | import bumpversion.cli |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 301 | |
| 302 | args = ( |
| 303 | (['--verbose'] if self.verbose > 1 else []) + |
| 304 | (['--dry-run'] if self.dry_run else []) + |
| 305 | (['--allow-dirty'] if (allow_dirty or self.allow_dirty) else []) + |
| 306 | (['--commit'] if commit else ['--no-commit']) + |
| 307 | (['--message', message] if message is not None else []) + |
| 308 | ['--list', part] |
| 309 | ) |
| 310 | log.debug("$ bumpversion %s" % " ".join(a.replace(" ", "\\ ") for a in args)) |
| 311 | |
| 312 | with capture_logger("bumpversion.list") as out: |
Haibo Huang | 5406a6a | 2020-02-26 16:36:20 -0800 | [diff] [blame] | 313 | bumpversion.cli.main(args) |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 314 | |
| 315 | last_line = out.getvalue().splitlines()[-1] |
| 316 | new_version = last_line.replace("new_version=", "") |
| 317 | return new_version |
| 318 | |
| 319 | def format_changelog(self, version): |
| 320 | """ Write new header at beginning of changelog file with the specified |
| 321 | 'version' and the current date. |
| 322 | Return the changelog content for the current release. |
| 323 | """ |
| 324 | from datetime import datetime |
| 325 | |
| 326 | log.info("formatting changelog") |
| 327 | |
| 328 | changes = [] |
| 329 | with io.open(self.changelog_name, "r+", encoding="utf-8") as f: |
| 330 | for ln in f: |
| 331 | if self.version_RE.match(ln): |
| 332 | break |
| 333 | else: |
| 334 | changes.append(ln) |
| 335 | if not self.dry_run: |
| 336 | f.seek(0) |
| 337 | content = f.read() |
| 338 | date = datetime.today().strftime(self.date_fmt) |
| 339 | f.seek(0) |
| 340 | header = self.header_fmt % (version, date) |
| 341 | f.write(header + u"\n" + u"-"*len(header) + u"\n\n" + content) |
| 342 | |
| 343 | return u"".join(changes) |
| 344 | |
| 345 | |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 346 | def find_data_files(manpath="share/man"): |
| 347 | """ Find FontTools's data_files (just man pages at this point). |
| 348 | |
| 349 | By default, we install man pages to "share/man" directory relative to the |
| 350 | base installation directory for data_files. The latter can be changed with |
| 351 | the --install-data option of 'setup.py install' sub-command. |
| 352 | |
| 353 | E.g., if the data files installation directory is "/usr", the default man |
| 354 | page installation directory will be "/usr/share/man". |
| 355 | |
| 356 | You can override this via the $FONTTOOLS_MANPATH environment variable. |
| 357 | |
| 358 | E.g., on some BSD systems man pages are installed to 'man' instead of |
| 359 | 'share/man'; you can export $FONTTOOLS_MANPATH variable just before |
| 360 | installing: |
| 361 | |
| 362 | $ FONTTOOLS_MANPATH="man" pip install -v . |
| 363 | [...] |
| 364 | running install_data |
| 365 | copying Doc/man/ttx.1 -> /usr/man/man1 |
| 366 | |
| 367 | When installing from PyPI, for this variable to have effect you need to |
| 368 | force pip to install from the source distribution instead of the wheel |
| 369 | package (otherwise setup.py is not run), by using the --no-binary option: |
| 370 | |
| 371 | $ FONTTOOLS_MANPATH="man" pip install --no-binary=fonttools fonttools |
| 372 | |
| 373 | Note that you can only override the base man path, i.e. without the |
| 374 | section number (man1, man3, etc.). The latter is always implied to be 1, |
| 375 | for "general commands". |
| 376 | """ |
| 377 | |
| 378 | # get base installation directory for man pages |
| 379 | manpagebase = os.environ.get('FONTTOOLS_MANPATH', convert_path(manpath)) |
| 380 | # all our man pages go to section 1 |
| 381 | manpagedir = pjoin(manpagebase, 'man1') |
| 382 | |
| 383 | manpages = [f for f in glob(pjoin('Doc', 'man', 'man1', '*.1')) if isfile(f)] |
| 384 | |
| 385 | data_files = [(manpagedir, manpages)] |
| 386 | return data_files |
| 387 | |
jvr | 91bde17 | 2003-01-03 21:01:07 +0000 | [diff] [blame] | 388 | |
Haibo Huang | d123eeb | 2020-04-03 12:18:18 -0700 | [diff] [blame] | 389 | class cython_build_ext(_build_ext): |
| 390 | """Compile *.pyx source files to *.c using cythonize if Cython is |
| 391 | installed and there is a working C compiler, else fall back to pure python dist. |
| 392 | """ |
| 393 | |
| 394 | def finalize_options(self): |
| 395 | from Cython.Build import cythonize |
| 396 | |
| 397 | # optionally enable line tracing for test coverage support |
| 398 | linetrace = os.environ.get("CYTHON_TRACE") == "1" |
| 399 | |
| 400 | self.distribution.ext_modules[:] = cythonize( |
| 401 | self.distribution.ext_modules, |
| 402 | force=linetrace or self.force, |
| 403 | annotate=os.environ.get("CYTHON_ANNOTATE") == "1", |
| 404 | quiet=not self.verbose, |
| 405 | compiler_directives={ |
| 406 | "linetrace": linetrace, |
| 407 | "language_level": 3, |
| 408 | "embedsignature": True, |
| 409 | }, |
| 410 | ) |
| 411 | |
| 412 | _build_ext.finalize_options(self) |
| 413 | |
| 414 | def build_extensions(self): |
| 415 | try: |
| 416 | _build_ext.build_extensions(self) |
| 417 | except Exception as e: |
| 418 | if with_cython: |
| 419 | raise |
| 420 | from distutils.errors import DistutilsModuleError |
| 421 | |
| 422 | # optional compilation failed: we delete 'ext_modules' and make sure |
| 423 | # the generated wheel is 'pure' |
| 424 | del self.distribution.ext_modules[:] |
| 425 | try: |
| 426 | bdist_wheel = self.get_finalized_command("bdist_wheel") |
| 427 | except DistutilsModuleError: |
| 428 | # 'bdist_wheel' command not available as wheel is not installed |
| 429 | pass |
| 430 | else: |
| 431 | bdist_wheel.root_is_pure = True |
| 432 | log.error('error: building extensions failed: %s' % e) |
| 433 | |
| 434 | cmdclass = {"release": release} |
| 435 | |
| 436 | if ext_modules: |
| 437 | cmdclass["build_ext"] = cython_build_ext |
| 438 | |
| 439 | |
| 440 | setup_params = dict( |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 441 | name="fonttools", |
Rod S | 0b59a54 | 2022-03-25 12:41:45 -0700 | [diff] [blame] | 442 | version="4.31.2", |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 443 | description="Tools to manipulate font files", |
| 444 | author="Just van Rossum", |
| 445 | author_email="just@letterror.com", |
| 446 | maintainer="Behdad Esfahbod", |
| 447 | maintainer_email="behdad@behdad.org", |
| 448 | url="http://github.com/fonttools/fonttools", |
| 449 | license="MIT", |
| 450 | platforms=["Any"], |
Rod S | 0b59a54 | 2022-03-25 12:41:45 -0700 | [diff] [blame] | 451 | python_requires=">=3.7", |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 452 | long_description=long_description, |
| 453 | package_dir={'': 'Lib'}, |
| 454 | packages=find_packages("Lib"), |
| 455 | include_package_data=True, |
| 456 | data_files=find_data_files(), |
Haibo Huang | d123eeb | 2020-04-03 12:18:18 -0700 | [diff] [blame] | 457 | ext_modules=ext_modules, |
| 458 | setup_requires=setup_requires, |
Elliott Hughes | 69c9aca | 2018-10-30 14:11:58 -0700 | [diff] [blame] | 459 | extras_require=extras_require, |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 460 | entry_points={ |
| 461 | 'console_scripts': [ |
| 462 | "fonttools = fontTools.__main__:main", |
| 463 | "ttx = fontTools.ttx:main", |
| 464 | "pyftsubset = fontTools.subset:main", |
| 465 | "pyftmerge = fontTools.merge:main", |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 466 | ] |
| 467 | }, |
Haibo Huang | d123eeb | 2020-04-03 12:18:18 -0700 | [diff] [blame] | 468 | cmdclass=cmdclass, |
Haibo Huang | 8b3c57b | 2018-07-03 17:43:11 -0700 | [diff] [blame] | 469 | **classifiers |
| 470 | ) |
Haibo Huang | d123eeb | 2020-04-03 12:18:18 -0700 | [diff] [blame] | 471 | |
| 472 | |
| 473 | if __name__ == "__main__": |
| 474 | setup(**setup_params) |