fonttools 4.58.5__cp311-cp311-win32.whl → 4.59.1__cp311-cp311-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 (67) hide show
  1. fontTools/__init__.py +1 -1
  2. fontTools/cffLib/CFF2ToCFF.py +40 -10
  3. fontTools/cffLib/transforms.py +11 -6
  4. fontTools/cu2qu/cu2qu.c +30 -16
  5. fontTools/cu2qu/cu2qu.cp311-win32.pyd +0 -0
  6. fontTools/feaLib/builder.py +6 -1
  7. fontTools/feaLib/lexer.c +30 -16
  8. fontTools/feaLib/lexer.cp311-win32.pyd +0 -0
  9. fontTools/merge/__init__.py +1 -1
  10. fontTools/misc/bezierTools.c +33 -19
  11. fontTools/misc/bezierTools.cp311-win32.pyd +0 -0
  12. fontTools/misc/filesystem/__init__.py +68 -0
  13. fontTools/misc/filesystem/_base.py +134 -0
  14. fontTools/misc/filesystem/_copy.py +45 -0
  15. fontTools/misc/filesystem/_errors.py +54 -0
  16. fontTools/misc/filesystem/_info.py +75 -0
  17. fontTools/misc/filesystem/_osfs.py +164 -0
  18. fontTools/misc/filesystem/_path.py +67 -0
  19. fontTools/misc/filesystem/_subfs.py +92 -0
  20. fontTools/misc/filesystem/_tempfs.py +34 -0
  21. fontTools/misc/filesystem/_tools.py +34 -0
  22. fontTools/misc/filesystem/_walk.py +55 -0
  23. fontTools/misc/filesystem/_zipfs.py +204 -0
  24. fontTools/misc/psCharStrings.py +17 -2
  25. fontTools/misc/sstruct.py +2 -6
  26. fontTools/misc/xmlWriter.py +28 -1
  27. fontTools/pens/momentsPen.c +20 -14
  28. fontTools/pens/momentsPen.cp311-win32.pyd +0 -0
  29. fontTools/pens/roundingPen.py +2 -2
  30. fontTools/qu2cu/qu2cu.c +32 -18
  31. fontTools/qu2cu/qu2cu.cp311-win32.pyd +0 -0
  32. fontTools/subset/__init__.py +11 -11
  33. fontTools/ttLib/sfnt.py +2 -3
  34. fontTools/ttLib/tables/S__i_l_f.py +2 -2
  35. fontTools/ttLib/tables/T_S_I__1.py +2 -5
  36. fontTools/ttLib/tables/T_S_I__5.py +2 -2
  37. fontTools/ttLib/tables/_c_m_a_p.py +1 -1
  38. fontTools/ttLib/tables/_c_v_t.py +1 -2
  39. fontTools/ttLib/tables/_g_l_y_f.py +9 -10
  40. fontTools/ttLib/tables/_g_v_a_r.py +6 -3
  41. fontTools/ttLib/tables/_h_d_m_x.py +4 -4
  42. fontTools/ttLib/tables/_h_m_t_x.py +7 -3
  43. fontTools/ttLib/tables/_l_o_c_a.py +2 -2
  44. fontTools/ttLib/tables/_p_o_s_t.py +3 -4
  45. fontTools/ttLib/tables/otBase.py +2 -4
  46. fontTools/ttLib/tables/otTables.py +7 -12
  47. fontTools/ttLib/tables/sbixStrike.py +3 -3
  48. fontTools/ttLib/ttFont.py +7 -16
  49. fontTools/ttLib/woff2.py +10 -13
  50. fontTools/ufoLib/__init__.py +20 -25
  51. fontTools/ufoLib/glifLib.py +12 -17
  52. fontTools/ufoLib/validators.py +2 -4
  53. fontTools/unicodedata/__init__.py +2 -0
  54. fontTools/varLib/featureVars.py +8 -0
  55. fontTools/varLib/hvar.py +1 -1
  56. fontTools/varLib/instancer/__init__.py +65 -5
  57. fontTools/varLib/iup.c +32 -18
  58. fontTools/varLib/iup.cp311-win32.pyd +0 -0
  59. fontTools/varLib/mutator.py +11 -0
  60. {fonttools-4.58.5.dist-info → fonttools-4.59.1.dist-info}/METADATA +42 -12
  61. {fonttools-4.58.5.dist-info → fonttools-4.59.1.dist-info}/RECORD +67 -55
  62. {fonttools-4.58.5.dist-info → fonttools-4.59.1.dist-info}/licenses/LICENSE.external +29 -0
  63. {fonttools-4.58.5.data → fonttools-4.59.1.data}/data/share/man/man1/ttx.1 +0 -0
  64. {fonttools-4.58.5.dist-info → fonttools-4.59.1.dist-info}/WHEEL +0 -0
  65. {fonttools-4.58.5.dist-info → fonttools-4.59.1.dist-info}/entry_points.txt +0 -0
  66. {fonttools-4.58.5.dist-info → fonttools-4.59.1.dist-info}/licenses/LICENSE +0 -0
  67. {fonttools-4.58.5.dist-info → fonttools-4.59.1.dist-info}/top_level.txt +0 -0
@@ -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()
@@ -338,7 +338,7 @@ class SimpleT2Decompiler(object):
338
338
  self.numRegions = 0
339
339
  self.vsIndex = 0
340
340
 
341
- def execute(self, charString):
341
+ def execute(self, charString, *, pushToStack=None):
342
342
  self.callingStack.append(charString)
343
343
  needsDecompilation = charString.needsDecompilation()
344
344
  if needsDecompilation:
@@ -346,7 +346,8 @@ class SimpleT2Decompiler(object):
346
346
  pushToProgram = program.append
347
347
  else:
348
348
  pushToProgram = lambda x: None
349
- pushToStack = self.operandStack.append
349
+ if pushToStack is None:
350
+ pushToStack = self.operandStack.append
350
351
  index = 0
351
352
  while True:
352
353
  token, isOperator, index = charString.getToken(index)
@@ -551,6 +552,20 @@ t1Operators = [
551
552
  ]
552
553
 
553
554
 
555
+ class T2StackUseExtractor(SimpleT2Decompiler):
556
+
557
+ def execute(self, charString):
558
+ maxStackUse = 0
559
+
560
+ def pushToStack(value):
561
+ nonlocal maxStackUse
562
+ self.operandStack.append(value)
563
+ maxStackUse = max(maxStackUse, len(self.operandStack))
564
+
565
+ super().execute(charString, pushToStack=pushToStack)
566
+ return maxStackUse
567
+
568
+
554
569
  class T2WidthExtractor(SimpleT2Decompiler):
555
570
  def __init__(
556
571
  self,
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):
@@ -1,4 +1,4 @@
1
- /* Generated by Cython 3.1.2 */
1
+ /* Generated by Cython 3.1.3 */
2
2
 
3
3
  /* BEGIN: Cython Metadata
4
4
  {
@@ -26,8 +26,8 @@ END: Cython Metadata */
26
26
  #elif PY_VERSION_HEX < 0x03080000
27
27
  #error Cython requires Python 3.8+.
28
28
  #else
29
- #define __PYX_ABI_VERSION "3_1_2"
30
- #define CYTHON_HEX_VERSION 0x030102F0
29
+ #define __PYX_ABI_VERSION "3_1_3"
30
+ #define CYTHON_HEX_VERSION 0x030103F0
31
31
  #define CYTHON_FUTURE_DIVISION 1
32
32
  /* CModulePreamble */
33
33
  #include <stddef.h>
@@ -390,6 +390,9 @@ END: Cython Metadata */
390
390
  enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) };
391
391
  #endif
392
392
  #endif
393
+ #ifndef CYTHON_LOCK_AND_GIL_DEADLOCK_AVOIDANCE_TIME
394
+ #define CYTHON_LOCK_AND_GIL_DEADLOCK_AVOIDANCE_TIME 100
395
+ #endif
393
396
  #ifndef __has_attribute
394
397
  #define __has_attribute(x) 0
395
398
  #endif
@@ -8294,16 +8297,15 @@ static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) {
8294
8297
  return -1;
8295
8298
  }
8296
8299
  /* #### Code section: init_codeobjects ### */
8297
- \
8298
- typedef struct {
8299
- unsigned int argcount : 3;
8300
- unsigned int num_posonly_args : 1;
8301
- unsigned int num_kwonly_args : 1;
8302
- unsigned int nlocals : 8;
8303
- unsigned int flags : 10;
8304
- unsigned int first_line : 9;
8305
- unsigned int line_table_length : 17;
8306
- } __Pyx_PyCode_New_function_description;
8300
+ typedef struct {
8301
+ unsigned int argcount : 3;
8302
+ unsigned int num_posonly_args : 1;
8303
+ unsigned int num_kwonly_args : 1;
8304
+ unsigned int nlocals : 8;
8305
+ unsigned int flags : 10;
8306
+ unsigned int first_line : 9;
8307
+ unsigned int line_table_length : 17;
8308
+ } __Pyx_PyCode_New_function_description;
8307
8309
  /* NewCodeObj.proto */
8308
8310
  static PyObject* __Pyx_PyCode_New(
8309
8311
  const __Pyx_PyCode_New_function_description descr,
@@ -10172,6 +10174,7 @@ static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject
10172
10174
  changed = 1;
10173
10175
  }
10174
10176
  #endif // CYTHON_METH_FASTCALL
10177
+ #if !CYTHON_COMPILING_IN_PYPY
10175
10178
  else if (strcmp(memb->name, "__module__") == 0) {
10176
10179
  PyObject *descr;
10177
10180
  assert(memb->type == T_OBJECT);
@@ -10186,11 +10189,13 @@ static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject
10186
10189
  }
10187
10190
  changed = 1;
10188
10191
  }
10192
+ #endif // !CYTHON_COMPILING_IN_PYPY
10189
10193
  }
10190
10194
  memb++;
10191
10195
  }
10192
10196
  }
10193
10197
  #endif // !CYTHON_COMPILING_IN_LIMITED_API
10198
+ #if !CYTHON_COMPILING_IN_PYPY
10194
10199
  slot = spec->slots;
10195
10200
  while (slot && slot->slot && slot->slot != Py_tp_getset)
10196
10201
  slot++;
@@ -10222,6 +10227,7 @@ static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject
10222
10227
  ++getset;
10223
10228
  }
10224
10229
  }
10230
+ #endif // !CYTHON_COMPILING_IN_PYPY
10225
10231
  if (changed)
10226
10232
  PyType_Modified(type);
10227
10233
  #endif // PY_VERSION_HEX > 0x030900B1
@@ -10354,7 +10360,7 @@ bad:
10354
10360
  }
10355
10361
 
10356
10362
  /* CommonTypesMetaclass */
10357
- PyObject* __pyx_CommonTypesMetaclass_get_module(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED void* context) {
10363
+ static PyObject* __pyx_CommonTypesMetaclass_get_module(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED void* context) {
10358
10364
  return PyUnicode_FromString(__PYX_ABI_MODULE_NAME);
10359
10365
  }
10360
10366
  static PyGetSetDef __pyx_CommonTypesMetaclass_getset[] = {
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),