fonttools 4.58.5__cp310-cp310-win32.whl → 4.59.0__cp310-cp310-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fonttools might be problematic. Click here for more details.

Files changed (52) hide show
  1. fontTools/__init__.py +1 -1
  2. fontTools/cu2qu/cu2qu.cp310-win32.pyd +0 -0
  3. fontTools/feaLib/lexer.cp310-win32.pyd +0 -0
  4. fontTools/merge/__init__.py +1 -1
  5. fontTools/misc/bezierTools.cp310-win32.pyd +0 -0
  6. fontTools/misc/filesystem/__init__.py +68 -0
  7. fontTools/misc/filesystem/_base.py +134 -0
  8. fontTools/misc/filesystem/_copy.py +45 -0
  9. fontTools/misc/filesystem/_errors.py +54 -0
  10. fontTools/misc/filesystem/_info.py +75 -0
  11. fontTools/misc/filesystem/_osfs.py +164 -0
  12. fontTools/misc/filesystem/_path.py +67 -0
  13. fontTools/misc/filesystem/_subfs.py +92 -0
  14. fontTools/misc/filesystem/_tempfs.py +34 -0
  15. fontTools/misc/filesystem/_tools.py +34 -0
  16. fontTools/misc/filesystem/_walk.py +55 -0
  17. fontTools/misc/filesystem/_zipfs.py +204 -0
  18. fontTools/misc/sstruct.py +2 -6
  19. fontTools/misc/xmlWriter.py +28 -1
  20. fontTools/pens/momentsPen.cp310-win32.pyd +0 -0
  21. fontTools/pens/roundingPen.py +2 -2
  22. fontTools/qu2cu/qu2cu.cp310-win32.pyd +0 -0
  23. fontTools/subset/__init__.py +11 -11
  24. fontTools/ttLib/sfnt.py +2 -3
  25. fontTools/ttLib/tables/S__i_l_f.py +2 -2
  26. fontTools/ttLib/tables/T_S_I__1.py +2 -5
  27. fontTools/ttLib/tables/T_S_I__5.py +2 -2
  28. fontTools/ttLib/tables/_c_m_a_p.py +1 -1
  29. fontTools/ttLib/tables/_c_v_t.py +1 -2
  30. fontTools/ttLib/tables/_g_l_y_f.py +9 -10
  31. fontTools/ttLib/tables/_h_d_m_x.py +4 -4
  32. fontTools/ttLib/tables/_l_o_c_a.py +2 -2
  33. fontTools/ttLib/tables/_p_o_s_t.py +3 -4
  34. fontTools/ttLib/tables/otBase.py +2 -4
  35. fontTools/ttLib/tables/otTables.py +7 -12
  36. fontTools/ttLib/tables/sbixStrike.py +3 -3
  37. fontTools/ttLib/ttFont.py +7 -16
  38. fontTools/ttLib/woff2.py +10 -13
  39. fontTools/ufoLib/__init__.py +20 -25
  40. fontTools/ufoLib/glifLib.py +12 -17
  41. fontTools/ufoLib/validators.py +2 -4
  42. fontTools/unicodedata/__init__.py +2 -0
  43. fontTools/varLib/hvar.py +1 -1
  44. fontTools/varLib/iup.cp310-win32.pyd +0 -0
  45. {fonttools-4.58.5.dist-info → fonttools-4.59.0.dist-info}/METADATA +19 -3
  46. {fonttools-4.58.5.dist-info → fonttools-4.59.0.dist-info}/RECORD +52 -40
  47. {fonttools-4.58.5.dist-info → fonttools-4.59.0.dist-info}/licenses/LICENSE.external +29 -0
  48. {fonttools-4.58.5.data → fonttools-4.59.0.data}/data/share/man/man1/ttx.1 +0 -0
  49. {fonttools-4.58.5.dist-info → fonttools-4.59.0.dist-info}/WHEEL +0 -0
  50. {fonttools-4.58.5.dist-info → fonttools-4.59.0.dist-info}/entry_points.txt +0 -0
  51. {fonttools-4.58.5.dist-info → fonttools-4.59.0.dist-info}/licenses/LICENSE +0 -0
  52. {fonttools-4.58.5.dist-info → fonttools-4.59.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+ from pathlib import PurePosixPath
5
+
6
+ from ._base import FS
7
+ from ._errors import DirectoryExpected, ResourceNotFound
8
+
9
+ if typing.TYPE_CHECKING:
10
+ from collections.abc import Collection
11
+ from typing import IO, Any
12
+
13
+ from ._info import Info
14
+
15
+
16
+ class SubFS(FS):
17
+ """Maps a sub-directory of another filesystem."""
18
+
19
+ def __init__(self, parent: FS, sub_path: str):
20
+ super().__init__()
21
+ self._parent = parent
22
+ self._prefix = PurePosixPath(sub_path).as_posix().rstrip("/")
23
+ if not parent.exists(self._prefix):
24
+ raise ResourceNotFound(f"No such file or directory: {sub_path!r}")
25
+ elif not parent.isdir(self._prefix):
26
+ raise DirectoryExpected(f"{sub_path!r} is not a directory")
27
+
28
+ def delegate_fs(self):
29
+ return self._parent
30
+
31
+ def _full(self, rel: str) -> str:
32
+ self.check()
33
+ return f"{self._prefix}/{PurePosixPath(rel).as_posix()}".lstrip("/")
34
+
35
+ def open(self, path: str, mode: str = "rb", **kwargs) -> IO[Any]:
36
+ return self._parent.open(self._full(path), mode, **kwargs)
37
+
38
+ def exists(self, path: str) -> bool:
39
+ return self._parent.exists(self._full(path))
40
+
41
+ def isdir(self, path: str) -> bool:
42
+ return self._parent.isdir(self._full(path))
43
+
44
+ def isfile(self, path: str) -> bool:
45
+ return self._parent.isfile(self._full(path))
46
+
47
+ def listdir(self, path: str) -> list[str]:
48
+ return self._parent.listdir(self._full(path))
49
+
50
+ def makedir(self, path: str, recreate: bool = False):
51
+ return self._parent.makedir(self._full(path), recreate=recreate)
52
+
53
+ def makedirs(self, path: str, recreate: bool = False):
54
+ return self._parent.makedirs(self._full(path), recreate=recreate)
55
+
56
+ def getinfo(self, path: str, namespaces: Collection[str] | None = None) -> Info:
57
+ return self._parent.getinfo(self._full(path), namespaces=namespaces)
58
+
59
+ def remove(self, path: str):
60
+ return self._parent.remove(self._full(path))
61
+
62
+ def removedir(self, path: str):
63
+ return self._parent.removedir(self._full(path))
64
+
65
+ def removetree(self, path: str):
66
+ return self._parent.removetree(self._full(path))
67
+
68
+ def movedir(self, src: str, dst: str, create: bool = False):
69
+ self._parent.movedir(self._full(src), self._full(dst), create=create)
70
+
71
+ def getsyspath(self, path: str) -> str:
72
+ return self._parent.getsyspath(self._full(path))
73
+
74
+ def readbytes(self, path: str) -> bytes:
75
+ return self._parent.readbytes(self._full(path))
76
+
77
+ def writebytes(self, path: str, data: bytes):
78
+ self._parent.writebytes(self._full(path), data)
79
+
80
+ def __repr__(self) -> str:
81
+ return f"{self.__class__.__name__}({self._parent!r}, {self._prefix!r})"
82
+
83
+ def __str__(self) -> str:
84
+ return f"{self._parent}/{self._prefix}"
85
+
86
+
87
+ class ClosingSubFS(SubFS):
88
+ """Like SubFS, but auto-closes the parent filesystem when closed."""
89
+
90
+ def close(self):
91
+ super().close()
92
+ self._parent.close()
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import tempfile
5
+
6
+ from ._errors import OperationFailed
7
+ from ._osfs import OSFS
8
+
9
+
10
+ class TempFS(OSFS):
11
+ def __init__(self, auto_clean: bool = True, ignore_clean_errors: bool = True):
12
+ self.auto_clean = auto_clean
13
+ self.ignore_clean_errors = ignore_clean_errors
14
+ self._temp_dir = tempfile.mkdtemp("__temp_fs__")
15
+ self._cleaned = False
16
+ super().__init__(self._temp_dir)
17
+
18
+ def close(self):
19
+ if self.auto_clean:
20
+ self.clean()
21
+ super().close()
22
+
23
+ def clean(self):
24
+ if self._cleaned:
25
+ return
26
+
27
+ try:
28
+ shutil.rmtree(self._temp_dir)
29
+ except Exception as e:
30
+ if not self.ignore_clean_errors:
31
+ raise OperationFailed(
32
+ f"failed to remove temporary directory: {self._temp_dir!r}"
33
+ ) from e
34
+ self._cleaned = True
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+ from pathlib import PurePosixPath
5
+
6
+ from ._errors import DirectoryNotEmpty
7
+
8
+ if typing.TYPE_CHECKING:
9
+ from typing import IO
10
+
11
+ from ._base import FS
12
+
13
+
14
+ def remove_empty(fs: FS, path: str):
15
+ """Remove all empty parents."""
16
+ path = PurePosixPath(path)
17
+ root = PurePosixPath("/")
18
+ try:
19
+ while path != root:
20
+ fs.removedir(path.as_posix())
21
+ path = path.parent
22
+ except DirectoryNotEmpty:
23
+ pass
24
+
25
+
26
+ def copy_file_data(src_file: IO, dst_file: IO, chunk_size: int | None = None):
27
+ """Copy data from one file object to another."""
28
+ _chunk_size = 1024 * 1024 if chunk_size is None else chunk_size
29
+ read = src_file.read
30
+ write = dst_file.write
31
+ # in iter(callable, sentilel), callable is called until it returns the sentinel;
32
+ # this allows to copy `chunk_size` bytes at a time.
33
+ for chunk in iter(lambda: read(_chunk_size) or None, None):
34
+ write(chunk)
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+ from collections import deque
5
+ from collections.abc import Collection, Iterator
6
+
7
+ from ._path import combine
8
+
9
+ if typing.TYPE_CHECKING:
10
+ from typing import Callable
11
+
12
+ from ._base import FS
13
+ from ._info import Info
14
+
15
+
16
+ class BoundWalker:
17
+ def __init__(self, fs: FS):
18
+ self._fs = fs
19
+
20
+ def _iter_walk(
21
+ self, path: str, namespaces: Collection[str] | None = None
22
+ ) -> Iterator[tuple[str, Info | None]]:
23
+ """Walk files using a *breadth first* search."""
24
+ queue = deque([path])
25
+ push = queue.appendleft
26
+ pop = queue.pop
27
+ _scan = self._fs.scandir
28
+ _combine = combine
29
+
30
+ while queue:
31
+ dir_path = pop()
32
+ for info in _scan(dir_path, namespaces=namespaces):
33
+ if info.is_dir:
34
+ yield dir_path, info
35
+ push(_combine(dir_path, info.name))
36
+ else:
37
+ yield dir_path, info
38
+ yield path, None
39
+
40
+ def _filter(
41
+ self,
42
+ include: Callable[[str, Info], bool] = lambda path, info: True,
43
+ path: str = "/",
44
+ namespaces: Collection[str] | None = None,
45
+ ) -> Iterator[str]:
46
+ _combine = combine
47
+ for path, info in self._iter_walk(path, namespaces):
48
+ if info is not None and include(path, info):
49
+ yield _combine(path, info.name)
50
+
51
+ def files(self, path: str = "/") -> Iterator[str]:
52
+ yield from self._filter(lambda _, info: info.is_file, path)
53
+
54
+ def dirs(self, path: str = "/") -> Iterator[str]:
55
+ yield from self._filter(lambda _, info: info.is_dir, path)
@@ -0,0 +1,204 @@
1
+ from __future__ import annotations
2
+
3
+ import io
4
+ import os
5
+ import shutil
6
+ import stat
7
+ import typing
8
+ import zipfile
9
+ from datetime import datetime
10
+
11
+ from ._base import FS
12
+ from ._errors import FileExpected, ResourceNotFound, ResourceReadOnly
13
+ from ._info import Info
14
+ from ._path import dirname, forcedir, normpath, relpath
15
+ from ._tempfs import TempFS
16
+
17
+ if typing.TYPE_CHECKING:
18
+ from collections.abc import Collection
19
+ from typing import IO, Any
20
+
21
+ from ._subfs import SubFS
22
+
23
+
24
+ class ZipFS(FS):
25
+ """Read and write zip files."""
26
+
27
+ def __new__(
28
+ cls, file: str | os.PathLike, write: bool = False, encoding: str = "utf-8"
29
+ ):
30
+ if write:
31
+ return WriteZipFS(file, encoding)
32
+ else:
33
+ return ReadZipFS(file, encoding)
34
+
35
+ if typing.TYPE_CHECKING:
36
+
37
+ def __init__(
38
+ self, file: str | os.PathLike, write: bool = False, encoding: str = "utf-8"
39
+ ):
40
+ pass
41
+
42
+
43
+ class ReadZipFS(FS):
44
+ """A readable zip file."""
45
+
46
+ def __init__(self, file: str | os.PathLike, encoding: str = "utf-8"):
47
+ super().__init__()
48
+ self._file = os.fspath(file)
49
+ self.encoding = encoding # unused
50
+ self._zip = zipfile.ZipFile(file, "r")
51
+ self._directory_fs = None
52
+
53
+ def __repr__(self) -> str:
54
+ return f"ReadZipFS({self._file!r})"
55
+
56
+ def __str__(self) -> str:
57
+ return f"<zipfs '{self._file}'>"
58
+
59
+ def _path_to_zip_name(self, path: str) -> str:
60
+ """Convert a path to a zip file name."""
61
+ path = relpath(normpath(path))
62
+ if self._directory.isdir(path):
63
+ path = forcedir(path)
64
+ return path
65
+
66
+ @property
67
+ def _directory(self) -> TempFS:
68
+ if self._directory_fs is None:
69
+ self._directory_fs = _fs = TempFS()
70
+ for zip_name in self._zip.namelist():
71
+ resource_name = zip_name
72
+ if resource_name.endswith("/"):
73
+ _fs.makedirs(resource_name, recreate=True)
74
+ else:
75
+ _fs.makedirs(dirname(resource_name), recreate=True)
76
+ _fs.create(resource_name)
77
+ return self._directory_fs
78
+
79
+ def close(self):
80
+ super(ReadZipFS, self).close()
81
+ self._zip.close()
82
+ if self._directory_fs is not None:
83
+ self._directory_fs.close()
84
+
85
+ def getinfo(self, path: str, namespaces: Collection[str] | None = None) -> Info:
86
+ namespaces = namespaces or ()
87
+ raw_info = {}
88
+
89
+ if path == "/":
90
+ raw_info["basic"] = {"name": "", "is_dir": True}
91
+ if "details" in namespaces:
92
+ raw_info["details"] = {"type": stat.S_IFDIR}
93
+ else:
94
+ basic_info = self._directory.getinfo(path)
95
+ raw_info["basic"] = {"name": basic_info.name, "is_dir": basic_info.is_dir}
96
+
97
+ if "details" in namespaces:
98
+ zip_name = self._path_to_zip_name(path)
99
+ try:
100
+ zip_info = self._zip.getinfo(zip_name)
101
+ except KeyError:
102
+ pass
103
+ else:
104
+ if "details" in namespaces:
105
+ raw_info["details"] = {
106
+ "size": zip_info.file_size,
107
+ "type": int(
108
+ stat.S_IFDIR if basic_info.is_dir else stat.S_IFREG
109
+ ),
110
+ "modified": datetime(*zip_info.date_time).timestamp(),
111
+ }
112
+
113
+ return Info(raw_info)
114
+
115
+ def exists(self, path: str) -> bool:
116
+ self.check()
117
+ return self._directory.exists(path)
118
+
119
+ def isdir(self, path: str) -> bool:
120
+ self.check()
121
+ return self._directory.isdir(path)
122
+
123
+ def isfile(self, path: str) -> bool:
124
+ self.check()
125
+ return self._directory.isfile(path)
126
+
127
+ def listdir(self, path: str) -> str:
128
+ self.check()
129
+ return self._directory.listdir(path)
130
+
131
+ def makedir(self, path: str, recreate: bool = False) -> SubFS:
132
+ self.check()
133
+ raise ResourceReadOnly(path)
134
+
135
+ def makedirs(self, path: str, recreate: bool = False) -> SubFS:
136
+ self.check()
137
+ raise ResourceReadOnly(path)
138
+
139
+ def remove(self, path: str):
140
+ self.check()
141
+ raise ResourceReadOnly(path)
142
+
143
+ def removedir(self, path: str):
144
+ self.check()
145
+ raise ResourceReadOnly(path)
146
+
147
+ def removetree(self, path: str):
148
+ self.check()
149
+ raise ResourceReadOnly(path)
150
+
151
+ def movedir(self, src: str, dst: str, create: bool = False):
152
+ self.check()
153
+ raise ResourceReadOnly(src)
154
+
155
+ def readbytes(self, path: str) -> bytes:
156
+ self.check()
157
+ if not self._directory.isfile(path):
158
+ raise ResourceNotFound(path)
159
+ zip_name = self._path_to_zip_name(path)
160
+ zip_bytes = self._zip.read(zip_name)
161
+ return zip_bytes
162
+
163
+ def open(self, path: str, mode: str = "rb", **kwargs) -> IO[Any]:
164
+ self.check()
165
+ if self._directory.isdir(path):
166
+ raise FileExpected(f"{path!r} is a directory")
167
+
168
+ zip_mode = mode[0]
169
+ if zip_mode == "r" and not self._directory.exists(path):
170
+ raise ResourceNotFound(f"No such file or directory: {path!r}")
171
+
172
+ if any(m in mode for m in "wax+"):
173
+ raise ResourceReadOnly(path)
174
+
175
+ zip_name = self._path_to_zip_name(path)
176
+ stream = self._zip.open(zip_name, zip_mode)
177
+ if "b" in mode:
178
+ if kwargs:
179
+ raise ValueError("encoding args invalid for binary operation")
180
+ return stream
181
+ # Text mode
182
+ return io.TextIOWrapper(stream, **kwargs)
183
+
184
+
185
+ class WriteZipFS(TempFS):
186
+ """A writable zip file."""
187
+
188
+ def __init__(self, file: str | os.PathLike, encoding: str = "utf-8"):
189
+ super().__init__()
190
+ self._file = os.fspath(file)
191
+ self.encoding = encoding # unused
192
+
193
+ def __repr__(self) -> str:
194
+ return f"WriteZipFS({self._file!r})"
195
+
196
+ def __str__(self) -> str:
197
+ return f"<zipfs-write '{self._file}'>"
198
+
199
+ def close(self):
200
+ base_name = os.path.splitext(self._file)[0]
201
+ shutil.make_archive(base_name, format="zip", root_dir=self._temp_dir)
202
+ if self._file != base_name + ".zip":
203
+ shutil.move(base_name + ".zip", self._file)
204
+ super().close()
fontTools/misc/sstruct.py CHANGED
@@ -64,10 +64,7 @@ def pack(fmt, obj):
64
64
  elements = []
65
65
  if not isinstance(obj, dict):
66
66
  obj = obj.__dict__
67
- string_index = formatstring
68
- if formatstring.startswith(">"):
69
- string_index = formatstring[1:]
70
- for ix, name in enumerate(names.keys()):
67
+ for name in names.keys():
71
68
  value = obj[name]
72
69
  if name in fixes:
73
70
  # fixed point conversion
@@ -96,8 +93,7 @@ def unpack(fmt, data, obj=None):
96
93
  else:
97
94
  d = obj.__dict__
98
95
  elements = struct.unpack(formatstring, data)
99
- for i in range(len(names)):
100
- name = list(names.keys())[i]
96
+ for i, name in enumerate(names.keys()):
101
97
  value = elements[i]
102
98
  if name in fixes:
103
99
  # fixed point conversion
@@ -4,8 +4,22 @@ from fontTools.misc.textTools import byteord, strjoin, tobytes, tostr
4
4
  import sys
5
5
  import os
6
6
  import string
7
+ import logging
8
+ import itertools
7
9
 
8
10
  INDENT = " "
11
+ TTX_LOG = logging.getLogger("fontTools.ttx")
12
+ REPLACEMENT = "?"
13
+ ILLEGAL_XML_CHARS = dict.fromkeys(
14
+ itertools.chain(
15
+ range(0x00, 0x09),
16
+ (0x0B, 0x0C),
17
+ range(0x0E, 0x20),
18
+ range(0xD800, 0xE000),
19
+ (0xFFFE, 0xFFFF),
20
+ ),
21
+ REPLACEMENT,
22
+ )
9
23
 
10
24
 
11
25
  class XMLWriter(object):
@@ -168,12 +182,25 @@ class XMLWriter(object):
168
182
 
169
183
 
170
184
  def escape(data):
185
+ """Escape characters not allowed in `XML 1.0 <https://www.w3.org/TR/xml/#NT-Char>`_."""
171
186
  data = tostr(data, "utf_8")
172
187
  data = data.replace("&", "&amp;")
173
188
  data = data.replace("<", "&lt;")
174
189
  data = data.replace(">", "&gt;")
175
190
  data = data.replace("\r", "&#13;")
176
- return data
191
+
192
+ newData = data.translate(ILLEGAL_XML_CHARS)
193
+ if newData != data:
194
+ maxLen = 10
195
+ preview = repr(data)
196
+ if len(data) > maxLen:
197
+ preview = repr(data[:maxLen])[1:-1] + "..."
198
+ TTX_LOG.warning(
199
+ "Illegal XML character(s) found; replacing offending " "string %r with %r",
200
+ preview,
201
+ REPLACEMENT,
202
+ )
203
+ return newData
177
204
 
178
205
 
179
206
  def escapeattr(data):
Binary file
@@ -116,8 +116,8 @@ class RoundingPointPen(FilterPointPen):
116
116
  def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs):
117
117
  xx, xy, yx, yy, dx, dy = transformation
118
118
  self._outPen.addComponent(
119
- baseGlyphName=baseGlyphName,
120
- transformation=Transform(
119
+ baseGlyphName,
120
+ Transform(
121
121
  self.transformRoundFunc(xx),
122
122
  self.transformRoundFunc(xy),
123
123
  self.transformRoundFunc(yx),
Binary file
@@ -27,16 +27,16 @@ from collections import Counter, defaultdict
27
27
  from functools import reduce
28
28
  from types import MethodType
29
29
 
30
- __usage__ = "pyftsubset font-file [glyph...] [--option=value]..."
30
+ __usage__ = "fonttools subset font-file [glyph...] [--option=value]..."
31
31
 
32
32
  __doc__ = (
33
33
  """\
34
- pyftsubset -- OpenType font subsetter and optimizer
34
+ fonttools subset -- OpenType font subsetter and optimizer
35
35
 
36
- pyftsubset is an OpenType font subsetter and optimizer, based on fontTools.
37
- It accepts any TT- or CFF-flavored OpenType (.otf or .ttf) or WOFF (.woff)
38
- font file. The subsetted glyph set is based on the specified glyphs
39
- or characters, and specified OpenType layout features.
36
+ fonttools subset is an OpenType font subsetter and optimizer, based on
37
+ fontTools. It accepts any TT- or CFF-flavored OpenType (.otf or .ttf)
38
+ or WOFF (.woff) font file. The subsetted glyph set is based on the
39
+ specified glyphs or characters, and specified OpenType layout features.
40
40
 
41
41
  The tool also performs some size-reducing optimizations, aimed for using
42
42
  subset fonts as webfonts. Individual optimizations can be enabled or
@@ -130,11 +130,11 @@ you might need to escape the question mark, like this: '--glyph-names\\?'.
130
130
 
131
131
  Examples::
132
132
 
133
- $ pyftsubset --glyph-names?
133
+ $ fonttools subset --glyph-names?
134
134
  Current setting for 'glyph-names' is: False
135
- $ pyftsubset --name-IDs=?
135
+ $ fonttools subset --name-IDs=?
136
136
  Current setting for 'name-IDs' is: [0, 1, 2, 3, 4, 5, 6]
137
- $ pyftsubset --hinting? --no-hinting --hinting?
137
+ $ fonttools subset --hinting? --no-hinting --hinting?
138
138
  Current setting for 'hinting' is: True
139
139
  Current setting for 'hinting' is: False
140
140
 
@@ -445,7 +445,7 @@ Example
445
445
  Produce a subset containing the characters ' !"#$%' without performing
446
446
  size-reducing optimizations::
447
447
 
448
- $ pyftsubset font.ttf --unicodes="U+0020-0025" \\
448
+ $ fonttools subset font.ttf --unicodes="U+0020-0025" \\
449
449
  --layout-features=* --glyph-names --symbol-cmap --legacy-cmap \\
450
450
  --notdef-glyph --notdef-outline --recommended-glyphs \\
451
451
  --name-IDs=* --name-legacy --name-languages=*
@@ -3768,7 +3768,7 @@ def parse_glyphs(s):
3768
3768
 
3769
3769
  def usage():
3770
3770
  print("usage:", __usage__, file=sys.stderr)
3771
- print("Try pyftsubset --help for more information.\n", file=sys.stderr)
3771
+ print("Try fonttools subset --help for more information.\n", file=sys.stderr)
3772
3772
 
3773
3773
 
3774
3774
  @timer("make one with everything (TOTAL TIME)")
fontTools/ttLib/sfnt.py CHANGED
@@ -375,10 +375,9 @@ class SFNTWriter(object):
375
375
 
376
376
  def _calcMasterChecksum(self, directory):
377
377
  # calculate checkSumAdjustment
378
- tags = list(self.tables.keys())
379
378
  checksums = []
380
- for i in range(len(tags)):
381
- checksums.append(self.tables[tags[i]].checkSum)
379
+ for tag in self.tables.keys():
380
+ checksums.append(self.tables[tag].checkSum)
382
381
 
383
382
  if self.DirectoryEntry != SFNTDirectoryEntry:
384
383
  # Create a SFNT directory for checksum calculation purposes
@@ -948,7 +948,7 @@ class Pass(object):
948
948
  writer.newline()
949
949
  writer.begintag("rules")
950
950
  writer.newline()
951
- for i in range(len(self.actions)):
951
+ for i, action in enumerate(self.actions):
952
952
  writer.begintag(
953
953
  "rule",
954
954
  index=i,
@@ -958,7 +958,7 @@ class Pass(object):
958
958
  writer.newline()
959
959
  if len(self.ruleConstraints[i]):
960
960
  writecode("constraint", writer, self.ruleConstraints[i])
961
- writecode("action", writer, self.actions[i])
961
+ writecode("action", writer, action)
962
962
  writer.endtag("rule")
963
963
  writer.newline()
964
964
  writer.endtag("rules")
@@ -91,12 +91,11 @@ class table_T_S_I__1(LogMixin, DefaultTable.DefaultTable):
91
91
  glyphNames = ttFont.getGlyphOrder()
92
92
 
93
93
  indices = []
94
- for i in range(len(glyphNames)):
94
+ for i, name in enumerate(glyphNames):
95
95
  if len(data) % 2:
96
96
  data = (
97
97
  data + b"\015"
98
98
  ) # align on 2-byte boundaries, fill with return chars. Yum.
99
- name = glyphNames[i]
100
99
  if name in self.glyphPrograms:
101
100
  text = tobytes(self.glyphPrograms[name], encoding="utf-8")
102
101
  else:
@@ -108,13 +107,11 @@ class table_T_S_I__1(LogMixin, DefaultTable.DefaultTable):
108
107
  data = data + text
109
108
 
110
109
  extra_indices = []
111
- codes = sorted(self.extras.items())
112
- for i in range(len(codes)):
110
+ for code, name in sorted(self.extras.items()):
113
111
  if len(data) % 2:
114
112
  data = (
115
113
  data + b"\015"
116
114
  ) # align on 2-byte boundaries, fill with return chars.
117
- code, name = codes[i]
118
115
  if name in self.extraPrograms:
119
116
  text = tobytes(self.extraPrograms[name], encoding="utf-8")
120
117
  else:
@@ -38,8 +38,8 @@ class table_T_S_I__5(DefaultTable.DefaultTable):
38
38
  def compile(self, ttFont):
39
39
  glyphNames = ttFont.getGlyphOrder()
40
40
  a = array.array("H")
41
- for i in range(len(glyphNames)):
42
- a.append(self.glyphGrouping.get(glyphNames[i], 0))
41
+ for glyphName in glyphNames:
42
+ a.append(self.glyphGrouping.get(glyphName, 0))
43
43
  if sys.byteorder != "big":
44
44
  a.byteswap()
45
45
  return a.tobytes()
@@ -398,7 +398,7 @@ class cmap_format_0(CmapSubtable):
398
398
  assert 262 == self.length, "Format 0 cmap subtable not 262 bytes"
399
399
  gids = array.array("B")
400
400
  gids.frombytes(self.data)
401
- charCodes = list(range(len(gids)))
401
+ charCodes = range(len(gids))
402
402
  self.cmap = _make_map(self.ttFont, charCodes, gids)
403
403
 
404
404
  def compile(self, ttFont):
@@ -29,8 +29,7 @@ class table__c_v_t(DefaultTable.DefaultTable):
29
29
  return values.tobytes()
30
30
 
31
31
  def toXML(self, writer, ttFont):
32
- for i in range(len(self.values)):
33
- value = self.values[i]
32
+ for i, value in enumerate(self.values):
34
33
  writer.simpletag("cv", value=value, index=i)
35
34
  writer.newline()
36
35