fonttools 4.57.0__cp310-cp310-macosx_10_9_universal2.whl → 4.58.1__cp310-cp310-macosx_10_9_universal2.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/__init__.py +61 -26
  3. fontTools/cffLib/specializer.py +4 -1
  4. fontTools/cu2qu/cu2qu.c +4578 -4050
  5. fontTools/cu2qu/cu2qu.cpython-310-darwin.so +0 -0
  6. fontTools/designspaceLib/statNames.py +14 -7
  7. fontTools/feaLib/ast.py +12 -9
  8. fontTools/feaLib/builder.py +75 -49
  9. fontTools/feaLib/lexer.c +6290 -7116
  10. fontTools/feaLib/lexer.cpython-310-darwin.so +0 -0
  11. fontTools/feaLib/parser.py +1 -39
  12. fontTools/fontBuilder.py +6 -0
  13. fontTools/merge/cmap.py +33 -1
  14. fontTools/merge/tables.py +12 -1
  15. fontTools/misc/bezierTools.c +13668 -15551
  16. fontTools/misc/bezierTools.cpython-310-darwin.so +0 -0
  17. fontTools/misc/etree.py +4 -27
  18. fontTools/misc/loggingTools.py +1 -1
  19. fontTools/misc/symfont.py +6 -8
  20. fontTools/mtiLib/__init__.py +1 -3
  21. fontTools/otlLib/builder.py +359 -145
  22. fontTools/otlLib/optimize/gpos.py +42 -62
  23. fontTools/pens/momentsPen.c +4509 -4674
  24. fontTools/pens/momentsPen.cpython-310-darwin.so +0 -0
  25. fontTools/pens/pointPen.py +21 -12
  26. fontTools/pens/t2CharStringPen.py +31 -11
  27. fontTools/qu2cu/qu2cu.c +5746 -5465
  28. fontTools/qu2cu/qu2cu.cpython-310-darwin.so +0 -0
  29. fontTools/subset/__init__.py +12 -1
  30. fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  31. fontTools/ttLib/tables/T_S_I__0.py +14 -3
  32. fontTools/ttLib/tables/T_S_I__5.py +16 -5
  33. fontTools/ttLib/tables/__init__.py +1 -0
  34. fontTools/ttLib/tables/_c_v_t.py +2 -0
  35. fontTools/ttLib/tables/_f_p_g_m.py +3 -1
  36. fontTools/ttLib/tables/_g_l_y_f.py +2 -6
  37. fontTools/ttLib/tables/_g_v_a_r.py +58 -15
  38. fontTools/ttLib/tables/_p_o_s_t.py +5 -2
  39. fontTools/ttLib/tables/otBase.py +1 -0
  40. fontTools/ufoLib/__init__.py +3 -3
  41. fontTools/ufoLib/converters.py +89 -25
  42. fontTools/ufoLib/errors.py +8 -0
  43. fontTools/ufoLib/etree.py +1 -1
  44. fontTools/ufoLib/filenames.py +155 -100
  45. fontTools/ufoLib/glifLib.py +9 -2
  46. fontTools/ufoLib/kerning.py +66 -36
  47. fontTools/ufoLib/utils.py +5 -2
  48. fontTools/unicodedata/Mirrored.py +446 -0
  49. fontTools/unicodedata/__init__.py +6 -2
  50. fontTools/varLib/__init__.py +20 -6
  51. fontTools/varLib/featureVars.py +13 -7
  52. fontTools/varLib/hvar.py +1 -1
  53. fontTools/varLib/instancer/__init__.py +14 -5
  54. fontTools/varLib/iup.c +6851 -6363
  55. fontTools/varLib/iup.cpython-310-darwin.so +0 -0
  56. fontTools/voltLib/__main__.py +206 -0
  57. fontTools/voltLib/ast.py +4 -0
  58. fontTools/voltLib/parser.py +16 -8
  59. fontTools/voltLib/voltToFea.py +347 -166
  60. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/METADATA +64 -11
  61. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/RECORD +67 -63
  62. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/WHEEL +1 -1
  63. fonttools-4.58.1.dist-info/licenses/LICENSE.external +359 -0
  64. {fonttools-4.57.0.data → fonttools-4.58.1.data}/data/share/man/man1/ttx.1 +0 -0
  65. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/entry_points.txt +0 -0
  66. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/licenses/LICENSE +0 -0
  67. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,22 @@
1
1
  """
2
- User name to file name conversion.
3
- This was taken from the UFO 3 spec.
2
+ Convert user-provided internal UFO names to spec-compliant filenames.
3
+
4
+ This module implements the algorithm for converting between a "user name" -
5
+ something that a user can choose arbitrarily inside a font editor - and a file
6
+ name suitable for use in a wide range of operating systems and filesystems.
7
+
8
+ The `UFO 3 specification <http://unifiedfontobject.org/versions/ufo3/conventions/>`_
9
+ provides an example of an algorithm for such conversion, which avoids illegal
10
+ characters, reserved file names, ambiguity between upper- and lower-case
11
+ characters, and clashes with existing files.
12
+
13
+ This code was originally copied from
14
+ `ufoLib <https://github.com/unified-font-object/ufoLib/blob/8747da7/Lib/ufoLib/filenames.py>`_
15
+ by Tal Leming and is copyright (c) 2005-2016, The RoboFab Developers:
16
+
17
+ - Erik van Blokland
18
+ - Tal Leming
19
+ - Just van Rossum
4
20
  """
5
21
 
6
22
  # Restrictions are taken mostly from
@@ -93,53 +109,69 @@ class NameTranslationError(Exception):
93
109
 
94
110
 
95
111
  def userNameToFileName(userName: str, existing=(), prefix="", suffix=""):
96
- """
97
- `existing` should be a set-like object.
98
-
99
- >>> userNameToFileName("a") == "a"
100
- True
101
- >>> userNameToFileName("A") == "A_"
102
- True
103
- >>> userNameToFileName("AE") == "A_E_"
104
- True
105
- >>> userNameToFileName("Ae") == "A_e"
106
- True
107
- >>> userNameToFileName("ae") == "ae"
108
- True
109
- >>> userNameToFileName("aE") == "aE_"
110
- True
111
- >>> userNameToFileName("a.alt") == "a.alt"
112
- True
113
- >>> userNameToFileName("A.alt") == "A_.alt"
114
- True
115
- >>> userNameToFileName("A.Alt") == "A_.A_lt"
116
- True
117
- >>> userNameToFileName("A.aLt") == "A_.aL_t"
118
- True
119
- >>> userNameToFileName(u"A.alT") == "A_.alT_"
120
- True
121
- >>> userNameToFileName("T_H") == "T__H_"
122
- True
123
- >>> userNameToFileName("T_h") == "T__h"
124
- True
125
- >>> userNameToFileName("t_h") == "t_h"
126
- True
127
- >>> userNameToFileName("F_F_I") == "F__F__I_"
128
- True
129
- >>> userNameToFileName("f_f_i") == "f_f_i"
130
- True
131
- >>> userNameToFileName("Aacute_V.swash") == "A_acute_V_.swash"
132
- True
133
- >>> userNameToFileName(".notdef") == "_notdef"
134
- True
135
- >>> userNameToFileName("con") == "_con"
136
- True
137
- >>> userNameToFileName("CON") == "C_O_N_"
138
- True
139
- >>> userNameToFileName("con.alt") == "_con.alt"
140
- True
141
- >>> userNameToFileName("alt.con") == "alt._con"
142
- True
112
+ """Converts from a user name to a file name.
113
+
114
+ Takes care to avoid illegal characters, reserved file names, ambiguity between
115
+ upper- and lower-case characters, and clashes with existing files.
116
+
117
+ Args:
118
+ userName (str): The input file name.
119
+ existing: A case-insensitive list of all existing file names.
120
+ prefix: Prefix to be prepended to the file name.
121
+ suffix: Suffix to be appended to the file name.
122
+
123
+ Returns:
124
+ A suitable filename.
125
+
126
+ Raises:
127
+ NameTranslationError: If no suitable name could be generated.
128
+
129
+ Examples::
130
+
131
+ >>> userNameToFileName("a") == "a"
132
+ True
133
+ >>> userNameToFileName("A") == "A_"
134
+ True
135
+ >>> userNameToFileName("AE") == "A_E_"
136
+ True
137
+ >>> userNameToFileName("Ae") == "A_e"
138
+ True
139
+ >>> userNameToFileName("ae") == "ae"
140
+ True
141
+ >>> userNameToFileName("aE") == "aE_"
142
+ True
143
+ >>> userNameToFileName("a.alt") == "a.alt"
144
+ True
145
+ >>> userNameToFileName("A.alt") == "A_.alt"
146
+ True
147
+ >>> userNameToFileName("A.Alt") == "A_.A_lt"
148
+ True
149
+ >>> userNameToFileName("A.aLt") == "A_.aL_t"
150
+ True
151
+ >>> userNameToFileName(u"A.alT") == "A_.alT_"
152
+ True
153
+ >>> userNameToFileName("T_H") == "T__H_"
154
+ True
155
+ >>> userNameToFileName("T_h") == "T__h"
156
+ True
157
+ >>> userNameToFileName("t_h") == "t_h"
158
+ True
159
+ >>> userNameToFileName("F_F_I") == "F__F__I_"
160
+ True
161
+ >>> userNameToFileName("f_f_i") == "f_f_i"
162
+ True
163
+ >>> userNameToFileName("Aacute_V.swash") == "A_acute_V_.swash"
164
+ True
165
+ >>> userNameToFileName(".notdef") == "_notdef"
166
+ True
167
+ >>> userNameToFileName("con") == "_con"
168
+ True
169
+ >>> userNameToFileName("CON") == "C_O_N_"
170
+ True
171
+ >>> userNameToFileName("con.alt") == "_con.alt"
172
+ True
173
+ >>> userNameToFileName("alt.con") == "alt._con"
174
+ True
143
175
  """
144
176
  # the incoming name must be a string
145
177
  if not isinstance(userName, str):
@@ -181,33 +213,42 @@ def userNameToFileName(userName: str, existing=(), prefix="", suffix=""):
181
213
 
182
214
 
183
215
  def handleClash1(userName, existing=[], prefix="", suffix=""):
184
- """
185
- existing should be a case-insensitive list
186
- of all existing file names.
187
-
188
- >>> prefix = ("0" * 5) + "."
189
- >>> suffix = "." + ("0" * 10)
190
- >>> existing = ["a" * 5]
191
-
192
- >>> e = list(existing)
193
- >>> handleClash1(userName="A" * 5, existing=e,
194
- ... prefix=prefix, suffix=suffix) == (
195
- ... '00000.AAAAA000000000000001.0000000000')
196
- True
197
-
198
- >>> e = list(existing)
199
- >>> e.append(prefix + "aaaaa" + "1".zfill(15) + suffix)
200
- >>> handleClash1(userName="A" * 5, existing=e,
201
- ... prefix=prefix, suffix=suffix) == (
202
- ... '00000.AAAAA000000000000002.0000000000')
203
- True
204
-
205
- >>> e = list(existing)
206
- >>> e.append(prefix + "AAAAA" + "2".zfill(15) + suffix)
207
- >>> handleClash1(userName="A" * 5, existing=e,
208
- ... prefix=prefix, suffix=suffix) == (
209
- ... '00000.AAAAA000000000000001.0000000000')
210
- True
216
+ """A helper function that resolves collisions with existing names when choosing a filename.
217
+
218
+ This function attempts to append an unused integer counter to the filename.
219
+
220
+ Args:
221
+ userName (str): The input file name.
222
+ existing: A case-insensitive list of all existing file names.
223
+ prefix: Prefix to be prepended to the file name.
224
+ suffix: Suffix to be appended to the file name.
225
+
226
+ Returns:
227
+ A suitable filename.
228
+
229
+ >>> prefix = ("0" * 5) + "."
230
+ >>> suffix = "." + ("0" * 10)
231
+ >>> existing = ["a" * 5]
232
+
233
+ >>> e = list(existing)
234
+ >>> handleClash1(userName="A" * 5, existing=e,
235
+ ... prefix=prefix, suffix=suffix) == (
236
+ ... '00000.AAAAA000000000000001.0000000000')
237
+ True
238
+
239
+ >>> e = list(existing)
240
+ >>> e.append(prefix + "aaaaa" + "1".zfill(15) + suffix)
241
+ >>> handleClash1(userName="A" * 5, existing=e,
242
+ ... prefix=prefix, suffix=suffix) == (
243
+ ... '00000.AAAAA000000000000002.0000000000')
244
+ True
245
+
246
+ >>> e = list(existing)
247
+ >>> e.append(prefix + "AAAAA" + "2".zfill(15) + suffix)
248
+ >>> handleClash1(userName="A" * 5, existing=e,
249
+ ... prefix=prefix, suffix=suffix) == (
250
+ ... '00000.AAAAA000000000000001.0000000000')
251
+ True
211
252
  """
212
253
  # if the prefix length + user name length + suffix length + 15 is at
213
254
  # or past the maximum length, silce 15 characters off of the user name
@@ -238,30 +279,44 @@ def handleClash1(userName, existing=[], prefix="", suffix=""):
238
279
 
239
280
 
240
281
  def handleClash2(existing=[], prefix="", suffix=""):
241
- """
242
- existing should be a case-insensitive list
243
- of all existing file names.
244
-
245
- >>> prefix = ("0" * 5) + "."
246
- >>> suffix = "." + ("0" * 10)
247
- >>> existing = [prefix + str(i) + suffix for i in range(100)]
248
-
249
- >>> e = list(existing)
250
- >>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
251
- ... '00000.100.0000000000')
252
- True
253
-
254
- >>> e = list(existing)
255
- >>> e.remove(prefix + "1" + suffix)
256
- >>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
257
- ... '00000.1.0000000000')
258
- True
259
-
260
- >>> e = list(existing)
261
- >>> e.remove(prefix + "2" + suffix)
262
- >>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
263
- ... '00000.2.0000000000')
264
- True
282
+ """A helper function that resolves collisions with existing names when choosing a filename.
283
+
284
+ This function is a fallback to :func:`handleClash1`. It attempts to append an unused integer counter to the filename.
285
+
286
+ Args:
287
+ userName (str): The input file name.
288
+ existing: A case-insensitive list of all existing file names.
289
+ prefix: Prefix to be prepended to the file name.
290
+ suffix: Suffix to be appended to the file name.
291
+
292
+ Returns:
293
+ A suitable filename.
294
+
295
+ Raises:
296
+ NameTranslationError: If no suitable name could be generated.
297
+
298
+ Examples::
299
+
300
+ >>> prefix = ("0" * 5) + "."
301
+ >>> suffix = "." + ("0" * 10)
302
+ >>> existing = [prefix + str(i) + suffix for i in range(100)]
303
+
304
+ >>> e = list(existing)
305
+ >>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
306
+ ... '00000.100.0000000000')
307
+ True
308
+
309
+ >>> e = list(existing)
310
+ >>> e.remove(prefix + "1" + suffix)
311
+ >>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
312
+ ... '00000.1.0000000000')
313
+ True
314
+
315
+ >>> e = list(existing)
316
+ >>> e.remove(prefix + "2" + suffix)
317
+ >>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
318
+ ... '00000.2.0000000000')
319
+ True
265
320
  """
266
321
  # calculate the longest possible string
267
322
  maxLength = maxFileNameLength - len(prefix) - len(suffix)
@@ -1,11 +1,11 @@
1
1
  """
2
- glifLib.py -- Generic module for reading and writing the .glif format.
2
+ Generic module for reading and writing the .glif format.
3
3
 
4
4
  More info about the .glif format (GLyphInterchangeFormat) can be found here:
5
5
 
6
6
  http://unifiedfontobject.org
7
7
 
8
- The main class in this module is GlyphSet. It manages a set of .glif files
8
+ The main class in this module is :class:`GlyphSet`. It manages a set of .glif files
9
9
  in a folder. It offers two ways to read glyph data, and one way to write
10
10
  glyph data. See the class doc string for details.
11
11
  """
@@ -60,6 +60,13 @@ LAYERINFO_FILENAME = "layerinfo.plist"
60
60
 
61
61
 
62
62
  class GLIFFormatVersion(tuple, _VersionTupleEnumMixin, enum.Enum):
63
+ """Class representing the versions of the .glif format supported by the UFO version in use.
64
+
65
+ For a given :mod:`fontTools.ufoLib.UFOFormatVersion`, the :func:`supported_versions` method will
66
+ return the supported versions of the GLIF file format. If the UFO version is unspecified, the
67
+ :func:`supported_versions` method will return all available GLIF format versions.
68
+ """
69
+
63
70
  FORMAT_1_0 = (1, 0)
64
71
  FORMAT_2_0 = (2, 0)
65
72
 
@@ -1,43 +1,73 @@
1
1
  def lookupKerningValue(
2
2
  pair, kerning, groups, fallback=0, glyphToFirstGroup=None, glyphToSecondGroup=None
3
3
  ):
4
- """
5
- Note: This expects kerning to be a flat dictionary
6
- of kerning pairs, not the nested structure used
7
- in kerning.plist.
4
+ """Retrieve the kerning value (if any) between a pair of elements.
5
+
6
+ The elments can be either individual glyphs (by name) or kerning
7
+ groups (by name), or any combination of the two.
8
+
9
+ Args:
10
+ pair:
11
+ A tuple, in logical order (first, second) with respect
12
+ to the reading direction, to query the font for kerning
13
+ information on. Each element in the tuple can be either
14
+ a glyph name or a kerning group name.
15
+ kerning:
16
+ A dictionary of kerning pairs.
17
+ groups:
18
+ A set of kerning groups.
19
+ fallback:
20
+ The fallback value to return if no kern is found between
21
+ the elements in ``pair``. Defaults to 0.
22
+ glyphToFirstGroup:
23
+ A dictionary mapping glyph names to the first-glyph kerning
24
+ groups to which they belong. Defaults to ``None``.
25
+ glyphToSecondGroup:
26
+ A dictionary mapping glyph names to the second-glyph kerning
27
+ groups to which they belong. Defaults to ``None``.
28
+
29
+ Returns:
30
+ The kerning value between the element pair. If no kerning for
31
+ the pair is found, the fallback value is returned.
32
+
33
+ Note: This function expects the ``kerning`` argument to be a flat
34
+ dictionary of kerning pairs, not the nested structure used in a
35
+ kerning.plist file.
36
+
37
+ Examples::
8
38
 
9
- >>> groups = {
10
- ... "public.kern1.O" : ["O", "D", "Q"],
11
- ... "public.kern2.E" : ["E", "F"]
12
- ... }
13
- >>> kerning = {
14
- ... ("public.kern1.O", "public.kern2.E") : -100,
15
- ... ("public.kern1.O", "F") : -200,
16
- ... ("D", "F") : -300
17
- ... }
18
- >>> lookupKerningValue(("D", "F"), kerning, groups)
19
- -300
20
- >>> lookupKerningValue(("O", "F"), kerning, groups)
21
- -200
22
- >>> lookupKerningValue(("O", "E"), kerning, groups)
23
- -100
24
- >>> lookupKerningValue(("O", "O"), kerning, groups)
25
- 0
26
- >>> lookupKerningValue(("E", "E"), kerning, groups)
27
- 0
28
- >>> lookupKerningValue(("E", "O"), kerning, groups)
29
- 0
30
- >>> lookupKerningValue(("X", "X"), kerning, groups)
31
- 0
32
- >>> lookupKerningValue(("public.kern1.O", "public.kern2.E"),
33
- ... kerning, groups)
34
- -100
35
- >>> lookupKerningValue(("public.kern1.O", "F"), kerning, groups)
36
- -200
37
- >>> lookupKerningValue(("O", "public.kern2.E"), kerning, groups)
38
- -100
39
- >>> lookupKerningValue(("public.kern1.X", "public.kern2.X"), kerning, groups)
40
- 0
39
+ >>> groups = {
40
+ ... "public.kern1.O" : ["O", "D", "Q"],
41
+ ... "public.kern2.E" : ["E", "F"]
42
+ ... }
43
+ >>> kerning = {
44
+ ... ("public.kern1.O", "public.kern2.E") : -100,
45
+ ... ("public.kern1.O", "F") : -200,
46
+ ... ("D", "F") : -300
47
+ ... }
48
+ >>> lookupKerningValue(("D", "F"), kerning, groups)
49
+ -300
50
+ >>> lookupKerningValue(("O", "F"), kerning, groups)
51
+ -200
52
+ >>> lookupKerningValue(("O", "E"), kerning, groups)
53
+ -100
54
+ >>> lookupKerningValue(("O", "O"), kerning, groups)
55
+ 0
56
+ >>> lookupKerningValue(("E", "E"), kerning, groups)
57
+ 0
58
+ >>> lookupKerningValue(("E", "O"), kerning, groups)
59
+ 0
60
+ >>> lookupKerningValue(("X", "X"), kerning, groups)
61
+ 0
62
+ >>> lookupKerningValue(("public.kern1.O", "public.kern2.E"),
63
+ ... kerning, groups)
64
+ -100
65
+ >>> lookupKerningValue(("public.kern1.O", "F"), kerning, groups)
66
+ -200
67
+ >>> lookupKerningValue(("O", "public.kern2.E"), kerning, groups)
68
+ -100
69
+ >>> lookupKerningValue(("public.kern1.X", "public.kern2.X"), kerning, groups)
70
+ 0
41
71
  """
42
72
  # quickly check to see if the pair is in the kerning dictionary
43
73
  if pair in kerning:
fontTools/ufoLib/utils.py CHANGED
@@ -1,5 +1,8 @@
1
- """The module contains miscellaneous helpers.
2
- It's not considered part of the public ufoLib API.
1
+ """This module contains miscellaneous helpers.
2
+
3
+ It is not considered part of the public ufoLib API. It does, however,
4
+ define the :py:obj:`.deprecated` decorator that is used elsewhere in
5
+ the module.
3
6
  """
4
7
 
5
8
  import warnings