fonttools 4.59.1__cp314-cp314-musllinux_1_2_x86_64.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 (346) hide show
  1. fontTools/__init__.py +8 -0
  2. fontTools/__main__.py +35 -0
  3. fontTools/afmLib.py +439 -0
  4. fontTools/agl.py +5233 -0
  5. fontTools/cffLib/CFF2ToCFF.py +233 -0
  6. fontTools/cffLib/CFFToCFF2.py +305 -0
  7. fontTools/cffLib/__init__.py +3694 -0
  8. fontTools/cffLib/specializer.py +927 -0
  9. fontTools/cffLib/transforms.py +495 -0
  10. fontTools/cffLib/width.py +210 -0
  11. fontTools/colorLib/__init__.py +0 -0
  12. fontTools/colorLib/builder.py +664 -0
  13. fontTools/colorLib/errors.py +2 -0
  14. fontTools/colorLib/geometry.py +143 -0
  15. fontTools/colorLib/table_builder.py +223 -0
  16. fontTools/colorLib/unbuilder.py +81 -0
  17. fontTools/config/__init__.py +90 -0
  18. fontTools/cu2qu/__init__.py +15 -0
  19. fontTools/cu2qu/__main__.py +6 -0
  20. fontTools/cu2qu/benchmark.py +54 -0
  21. fontTools/cu2qu/cli.py +198 -0
  22. fontTools/cu2qu/cu2qu.c +15560 -0
  23. fontTools/cu2qu/cu2qu.cpython-314-x86_64-linux-musl.so +0 -0
  24. fontTools/cu2qu/cu2qu.py +531 -0
  25. fontTools/cu2qu/errors.py +77 -0
  26. fontTools/cu2qu/ufo.py +349 -0
  27. fontTools/designspaceLib/__init__.py +3338 -0
  28. fontTools/designspaceLib/__main__.py +6 -0
  29. fontTools/designspaceLib/split.py +475 -0
  30. fontTools/designspaceLib/statNames.py +260 -0
  31. fontTools/designspaceLib/types.py +147 -0
  32. fontTools/encodings/MacRoman.py +258 -0
  33. fontTools/encodings/StandardEncoding.py +258 -0
  34. fontTools/encodings/__init__.py +1 -0
  35. fontTools/encodings/codecs.py +135 -0
  36. fontTools/feaLib/__init__.py +4 -0
  37. fontTools/feaLib/__main__.py +78 -0
  38. fontTools/feaLib/ast.py +2143 -0
  39. fontTools/feaLib/builder.py +1802 -0
  40. fontTools/feaLib/error.py +22 -0
  41. fontTools/feaLib/lexer.c +17351 -0
  42. fontTools/feaLib/lexer.cpython-314-x86_64-linux-musl.so +0 -0
  43. fontTools/feaLib/lexer.py +287 -0
  44. fontTools/feaLib/location.py +12 -0
  45. fontTools/feaLib/lookupDebugInfo.py +12 -0
  46. fontTools/feaLib/parser.py +2379 -0
  47. fontTools/feaLib/variableScalar.py +113 -0
  48. fontTools/fontBuilder.py +1014 -0
  49. fontTools/help.py +36 -0
  50. fontTools/merge/__init__.py +248 -0
  51. fontTools/merge/__main__.py +6 -0
  52. fontTools/merge/base.py +81 -0
  53. fontTools/merge/cmap.py +173 -0
  54. fontTools/merge/layout.py +526 -0
  55. fontTools/merge/options.py +85 -0
  56. fontTools/merge/tables.py +352 -0
  57. fontTools/merge/unicode.py +78 -0
  58. fontTools/merge/util.py +143 -0
  59. fontTools/misc/__init__.py +1 -0
  60. fontTools/misc/arrayTools.py +424 -0
  61. fontTools/misc/bezierTools.c +40151 -0
  62. fontTools/misc/bezierTools.cpython-314-x86_64-linux-musl.so +0 -0
  63. fontTools/misc/bezierTools.py +1497 -0
  64. fontTools/misc/classifyTools.py +170 -0
  65. fontTools/misc/cliTools.py +53 -0
  66. fontTools/misc/configTools.py +349 -0
  67. fontTools/misc/cython.py +27 -0
  68. fontTools/misc/dictTools.py +83 -0
  69. fontTools/misc/eexec.py +119 -0
  70. fontTools/misc/encodingTools.py +72 -0
  71. fontTools/misc/etree.py +456 -0
  72. fontTools/misc/filenames.py +245 -0
  73. fontTools/misc/filesystem/__init__.py +68 -0
  74. fontTools/misc/filesystem/_base.py +134 -0
  75. fontTools/misc/filesystem/_copy.py +45 -0
  76. fontTools/misc/filesystem/_errors.py +54 -0
  77. fontTools/misc/filesystem/_info.py +75 -0
  78. fontTools/misc/filesystem/_osfs.py +164 -0
  79. fontTools/misc/filesystem/_path.py +67 -0
  80. fontTools/misc/filesystem/_subfs.py +92 -0
  81. fontTools/misc/filesystem/_tempfs.py +34 -0
  82. fontTools/misc/filesystem/_tools.py +34 -0
  83. fontTools/misc/filesystem/_walk.py +55 -0
  84. fontTools/misc/filesystem/_zipfs.py +204 -0
  85. fontTools/misc/fixedTools.py +253 -0
  86. fontTools/misc/intTools.py +25 -0
  87. fontTools/misc/iterTools.py +12 -0
  88. fontTools/misc/lazyTools.py +42 -0
  89. fontTools/misc/loggingTools.py +543 -0
  90. fontTools/misc/macCreatorType.py +56 -0
  91. fontTools/misc/macRes.py +261 -0
  92. fontTools/misc/plistlib/__init__.py +681 -0
  93. fontTools/misc/plistlib/py.typed +0 -0
  94. fontTools/misc/psCharStrings.py +1511 -0
  95. fontTools/misc/psLib.py +398 -0
  96. fontTools/misc/psOperators.py +572 -0
  97. fontTools/misc/py23.py +96 -0
  98. fontTools/misc/roundTools.py +110 -0
  99. fontTools/misc/sstruct.py +227 -0
  100. fontTools/misc/symfont.py +242 -0
  101. fontTools/misc/testTools.py +233 -0
  102. fontTools/misc/textTools.py +154 -0
  103. fontTools/misc/timeTools.py +88 -0
  104. fontTools/misc/transform.py +516 -0
  105. fontTools/misc/treeTools.py +45 -0
  106. fontTools/misc/vector.py +147 -0
  107. fontTools/misc/visitor.py +150 -0
  108. fontTools/misc/xmlReader.py +188 -0
  109. fontTools/misc/xmlWriter.py +231 -0
  110. fontTools/mtiLib/__init__.py +1400 -0
  111. fontTools/mtiLib/__main__.py +5 -0
  112. fontTools/otlLib/__init__.py +1 -0
  113. fontTools/otlLib/builder.py +3465 -0
  114. fontTools/otlLib/error.py +11 -0
  115. fontTools/otlLib/maxContextCalc.py +96 -0
  116. fontTools/otlLib/optimize/__init__.py +53 -0
  117. fontTools/otlLib/optimize/__main__.py +6 -0
  118. fontTools/otlLib/optimize/gpos.py +439 -0
  119. fontTools/pens/__init__.py +1 -0
  120. fontTools/pens/areaPen.py +52 -0
  121. fontTools/pens/basePen.py +475 -0
  122. fontTools/pens/boundsPen.py +98 -0
  123. fontTools/pens/cairoPen.py +26 -0
  124. fontTools/pens/cocoaPen.py +26 -0
  125. fontTools/pens/cu2quPen.py +325 -0
  126. fontTools/pens/explicitClosingLinePen.py +101 -0
  127. fontTools/pens/filterPen.py +241 -0
  128. fontTools/pens/freetypePen.py +462 -0
  129. fontTools/pens/hashPointPen.py +89 -0
  130. fontTools/pens/momentsPen.c +13466 -0
  131. fontTools/pens/momentsPen.cpython-314-x86_64-linux-musl.so +0 -0
  132. fontTools/pens/momentsPen.py +879 -0
  133. fontTools/pens/perimeterPen.py +69 -0
  134. fontTools/pens/pointInsidePen.py +192 -0
  135. fontTools/pens/pointPen.py +609 -0
  136. fontTools/pens/qtPen.py +29 -0
  137. fontTools/pens/qu2cuPen.py +105 -0
  138. fontTools/pens/quartzPen.py +43 -0
  139. fontTools/pens/recordingPen.py +335 -0
  140. fontTools/pens/reportLabPen.py +79 -0
  141. fontTools/pens/reverseContourPen.py +96 -0
  142. fontTools/pens/roundingPen.py +130 -0
  143. fontTools/pens/statisticsPen.py +312 -0
  144. fontTools/pens/svgPathPen.py +310 -0
  145. fontTools/pens/t2CharStringPen.py +88 -0
  146. fontTools/pens/teePen.py +55 -0
  147. fontTools/pens/transformPen.py +115 -0
  148. fontTools/pens/ttGlyphPen.py +335 -0
  149. fontTools/pens/wxPen.py +29 -0
  150. fontTools/qu2cu/__init__.py +15 -0
  151. fontTools/qu2cu/__main__.py +7 -0
  152. fontTools/qu2cu/benchmark.py +56 -0
  153. fontTools/qu2cu/cli.py +125 -0
  154. fontTools/qu2cu/qu2cu.c +16753 -0
  155. fontTools/qu2cu/qu2cu.cpython-314-x86_64-linux-musl.so +0 -0
  156. fontTools/qu2cu/qu2cu.py +405 -0
  157. fontTools/subset/__init__.py +3929 -0
  158. fontTools/subset/__main__.py +6 -0
  159. fontTools/subset/cff.py +184 -0
  160. fontTools/subset/svg.py +253 -0
  161. fontTools/subset/util.py +25 -0
  162. fontTools/svgLib/__init__.py +3 -0
  163. fontTools/svgLib/path/__init__.py +65 -0
  164. fontTools/svgLib/path/arc.py +154 -0
  165. fontTools/svgLib/path/parser.py +322 -0
  166. fontTools/svgLib/path/shapes.py +183 -0
  167. fontTools/t1Lib/__init__.py +648 -0
  168. fontTools/tfmLib.py +460 -0
  169. fontTools/ttLib/__init__.py +30 -0
  170. fontTools/ttLib/__main__.py +148 -0
  171. fontTools/ttLib/macUtils.py +54 -0
  172. fontTools/ttLib/removeOverlaps.py +393 -0
  173. fontTools/ttLib/reorderGlyphs.py +285 -0
  174. fontTools/ttLib/scaleUpem.py +436 -0
  175. fontTools/ttLib/sfnt.py +661 -0
  176. fontTools/ttLib/standardGlyphOrder.py +271 -0
  177. fontTools/ttLib/tables/B_A_S_E_.py +14 -0
  178. fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
  179. fontTools/ttLib/tables/C_B_D_T_.py +113 -0
  180. fontTools/ttLib/tables/C_B_L_C_.py +19 -0
  181. fontTools/ttLib/tables/C_F_F_.py +61 -0
  182. fontTools/ttLib/tables/C_F_F__2.py +26 -0
  183. fontTools/ttLib/tables/C_O_L_R_.py +165 -0
  184. fontTools/ttLib/tables/C_P_A_L_.py +305 -0
  185. fontTools/ttLib/tables/D_S_I_G_.py +158 -0
  186. fontTools/ttLib/tables/D__e_b_g.py +35 -0
  187. fontTools/ttLib/tables/DefaultTable.py +49 -0
  188. fontTools/ttLib/tables/E_B_D_T_.py +835 -0
  189. fontTools/ttLib/tables/E_B_L_C_.py +718 -0
  190. fontTools/ttLib/tables/F_F_T_M_.py +52 -0
  191. fontTools/ttLib/tables/F__e_a_t.py +149 -0
  192. fontTools/ttLib/tables/G_D_E_F_.py +13 -0
  193. fontTools/ttLib/tables/G_M_A_P_.py +148 -0
  194. fontTools/ttLib/tables/G_P_K_G_.py +133 -0
  195. fontTools/ttLib/tables/G_P_O_S_.py +14 -0
  196. fontTools/ttLib/tables/G_S_U_B_.py +13 -0
  197. fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  198. fontTools/ttLib/tables/G__l_a_t.py +235 -0
  199. fontTools/ttLib/tables/G__l_o_c.py +85 -0
  200. fontTools/ttLib/tables/H_V_A_R_.py +13 -0
  201. fontTools/ttLib/tables/J_S_T_F_.py +13 -0
  202. fontTools/ttLib/tables/L_T_S_H_.py +58 -0
  203. fontTools/ttLib/tables/M_A_T_H_.py +13 -0
  204. fontTools/ttLib/tables/M_E_T_A_.py +352 -0
  205. fontTools/ttLib/tables/M_V_A_R_.py +13 -0
  206. fontTools/ttLib/tables/O_S_2f_2.py +752 -0
  207. fontTools/ttLib/tables/S_I_N_G_.py +99 -0
  208. fontTools/ttLib/tables/S_T_A_T_.py +15 -0
  209. fontTools/ttLib/tables/S_V_G_.py +223 -0
  210. fontTools/ttLib/tables/S__i_l_f.py +1040 -0
  211. fontTools/ttLib/tables/S__i_l_l.py +92 -0
  212. fontTools/ttLib/tables/T_S_I_B_.py +13 -0
  213. fontTools/ttLib/tables/T_S_I_C_.py +14 -0
  214. fontTools/ttLib/tables/T_S_I_D_.py +13 -0
  215. fontTools/ttLib/tables/T_S_I_J_.py +13 -0
  216. fontTools/ttLib/tables/T_S_I_P_.py +13 -0
  217. fontTools/ttLib/tables/T_S_I_S_.py +13 -0
  218. fontTools/ttLib/tables/T_S_I_V_.py +26 -0
  219. fontTools/ttLib/tables/T_S_I__0.py +70 -0
  220. fontTools/ttLib/tables/T_S_I__1.py +163 -0
  221. fontTools/ttLib/tables/T_S_I__2.py +17 -0
  222. fontTools/ttLib/tables/T_S_I__3.py +22 -0
  223. fontTools/ttLib/tables/T_S_I__5.py +60 -0
  224. fontTools/ttLib/tables/T_T_F_A_.py +14 -0
  225. fontTools/ttLib/tables/TupleVariation.py +884 -0
  226. fontTools/ttLib/tables/V_A_R_C_.py +12 -0
  227. fontTools/ttLib/tables/V_D_M_X_.py +249 -0
  228. fontTools/ttLib/tables/V_O_R_G_.py +165 -0
  229. fontTools/ttLib/tables/V_V_A_R_.py +13 -0
  230. fontTools/ttLib/tables/__init__.py +98 -0
  231. fontTools/ttLib/tables/_a_n_k_r.py +15 -0
  232. fontTools/ttLib/tables/_a_v_a_r.py +191 -0
  233. fontTools/ttLib/tables/_b_s_l_n.py +15 -0
  234. fontTools/ttLib/tables/_c_i_d_g.py +24 -0
  235. fontTools/ttLib/tables/_c_m_a_p.py +1591 -0
  236. fontTools/ttLib/tables/_c_v_a_r.py +94 -0
  237. fontTools/ttLib/tables/_c_v_t.py +56 -0
  238. fontTools/ttLib/tables/_f_e_a_t.py +15 -0
  239. fontTools/ttLib/tables/_f_p_g_m.py +62 -0
  240. fontTools/ttLib/tables/_f_v_a_r.py +261 -0
  241. fontTools/ttLib/tables/_g_a_s_p.py +63 -0
  242. fontTools/ttLib/tables/_g_c_i_d.py +13 -0
  243. fontTools/ttLib/tables/_g_l_y_f.py +2311 -0
  244. fontTools/ttLib/tables/_g_v_a_r.py +340 -0
  245. fontTools/ttLib/tables/_h_d_m_x.py +127 -0
  246. fontTools/ttLib/tables/_h_e_a_d.py +130 -0
  247. fontTools/ttLib/tables/_h_h_e_a.py +147 -0
  248. fontTools/ttLib/tables/_h_m_t_x.py +164 -0
  249. fontTools/ttLib/tables/_k_e_r_n.py +289 -0
  250. fontTools/ttLib/tables/_l_c_a_r.py +13 -0
  251. fontTools/ttLib/tables/_l_o_c_a.py +70 -0
  252. fontTools/ttLib/tables/_l_t_a_g.py +72 -0
  253. fontTools/ttLib/tables/_m_a_x_p.py +147 -0
  254. fontTools/ttLib/tables/_m_e_t_a.py +112 -0
  255. fontTools/ttLib/tables/_m_o_r_t.py +14 -0
  256. fontTools/ttLib/tables/_m_o_r_x.py +15 -0
  257. fontTools/ttLib/tables/_n_a_m_e.py +1237 -0
  258. fontTools/ttLib/tables/_o_p_b_d.py +14 -0
  259. fontTools/ttLib/tables/_p_o_s_t.py +319 -0
  260. fontTools/ttLib/tables/_p_r_e_p.py +16 -0
  261. fontTools/ttLib/tables/_p_r_o_p.py +12 -0
  262. fontTools/ttLib/tables/_s_b_i_x.py +129 -0
  263. fontTools/ttLib/tables/_t_r_a_k.py +332 -0
  264. fontTools/ttLib/tables/_v_h_e_a.py +139 -0
  265. fontTools/ttLib/tables/_v_m_t_x.py +19 -0
  266. fontTools/ttLib/tables/asciiTable.py +20 -0
  267. fontTools/ttLib/tables/grUtils.py +92 -0
  268. fontTools/ttLib/tables/otBase.py +1464 -0
  269. fontTools/ttLib/tables/otConverters.py +2068 -0
  270. fontTools/ttLib/tables/otData.py +6400 -0
  271. fontTools/ttLib/tables/otTables.py +2703 -0
  272. fontTools/ttLib/tables/otTraverse.py +163 -0
  273. fontTools/ttLib/tables/sbixGlyph.py +149 -0
  274. fontTools/ttLib/tables/sbixStrike.py +177 -0
  275. fontTools/ttLib/tables/table_API_readme.txt +91 -0
  276. fontTools/ttLib/tables/ttProgram.py +594 -0
  277. fontTools/ttLib/ttCollection.py +125 -0
  278. fontTools/ttLib/ttFont.py +1148 -0
  279. fontTools/ttLib/ttGlyphSet.py +490 -0
  280. fontTools/ttLib/ttVisitor.py +32 -0
  281. fontTools/ttLib/woff2.py +1680 -0
  282. fontTools/ttx.py +479 -0
  283. fontTools/ufoLib/__init__.py +2472 -0
  284. fontTools/ufoLib/converters.py +398 -0
  285. fontTools/ufoLib/errors.py +30 -0
  286. fontTools/ufoLib/etree.py +6 -0
  287. fontTools/ufoLib/filenames.py +346 -0
  288. fontTools/ufoLib/glifLib.py +2024 -0
  289. fontTools/ufoLib/kerning.py +121 -0
  290. fontTools/ufoLib/plistlib.py +47 -0
  291. fontTools/ufoLib/pointPen.py +6 -0
  292. fontTools/ufoLib/utils.py +79 -0
  293. fontTools/ufoLib/validators.py +1184 -0
  294. fontTools/unicode.py +50 -0
  295. fontTools/unicodedata/Blocks.py +801 -0
  296. fontTools/unicodedata/Mirrored.py +446 -0
  297. fontTools/unicodedata/OTTags.py +50 -0
  298. fontTools/unicodedata/ScriptExtensions.py +826 -0
  299. fontTools/unicodedata/Scripts.py +3617 -0
  300. fontTools/unicodedata/__init__.py +304 -0
  301. fontTools/varLib/__init__.py +1517 -0
  302. fontTools/varLib/__main__.py +6 -0
  303. fontTools/varLib/avar.py +260 -0
  304. fontTools/varLib/avarPlanner.py +1004 -0
  305. fontTools/varLib/builder.py +215 -0
  306. fontTools/varLib/cff.py +631 -0
  307. fontTools/varLib/errors.py +219 -0
  308. fontTools/varLib/featureVars.py +703 -0
  309. fontTools/varLib/hvar.py +113 -0
  310. fontTools/varLib/instancer/__init__.py +2014 -0
  311. fontTools/varLib/instancer/__main__.py +5 -0
  312. fontTools/varLib/instancer/featureVars.py +190 -0
  313. fontTools/varLib/instancer/names.py +388 -0
  314. fontTools/varLib/instancer/solver.py +309 -0
  315. fontTools/varLib/interpolatable.py +1209 -0
  316. fontTools/varLib/interpolatableHelpers.py +396 -0
  317. fontTools/varLib/interpolatablePlot.py +1269 -0
  318. fontTools/varLib/interpolatableTestContourOrder.py +82 -0
  319. fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
  320. fontTools/varLib/interpolate_layout.py +124 -0
  321. fontTools/varLib/iup.c +19845 -0
  322. fontTools/varLib/iup.cpython-314-x86_64-linux-musl.so +0 -0
  323. fontTools/varLib/iup.py +490 -0
  324. fontTools/varLib/merger.py +1717 -0
  325. fontTools/varLib/models.py +642 -0
  326. fontTools/varLib/multiVarStore.py +253 -0
  327. fontTools/varLib/mutator.py +529 -0
  328. fontTools/varLib/mvar.py +40 -0
  329. fontTools/varLib/plot.py +238 -0
  330. fontTools/varLib/stat.py +149 -0
  331. fontTools/varLib/varStore.py +739 -0
  332. fontTools/voltLib/__init__.py +5 -0
  333. fontTools/voltLib/__main__.py +206 -0
  334. fontTools/voltLib/ast.py +452 -0
  335. fontTools/voltLib/error.py +12 -0
  336. fontTools/voltLib/lexer.py +99 -0
  337. fontTools/voltLib/parser.py +664 -0
  338. fontTools/voltLib/voltToFea.py +911 -0
  339. fonttools-4.59.1.data/data/share/man/man1/ttx.1 +225 -0
  340. fonttools-4.59.1.dist-info/METADATA +2175 -0
  341. fonttools-4.59.1.dist-info/RECORD +346 -0
  342. fonttools-4.59.1.dist-info/WHEEL +5 -0
  343. fonttools-4.59.1.dist-info/entry_points.txt +5 -0
  344. fonttools-4.59.1.dist-info/licenses/LICENSE +21 -0
  345. fonttools-4.59.1.dist-info/licenses/LICENSE.external +388 -0
  346. fonttools-4.59.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,346 @@
1
+ """
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
20
+ """
21
+
22
+ # Restrictions are taken mostly from
23
+ # https://docs.microsoft.com/en-gb/windows/win32/fileio/naming-a-file#naming-conventions.
24
+ #
25
+ # 1. Integer value zero, sometimes referred to as the ASCII NUL character.
26
+ # 2. Characters whose integer representations are in the range 1 to 31,
27
+ # inclusive.
28
+ # 3. Various characters that (mostly) Windows and POSIX-y filesystems don't
29
+ # allow, plus "(" and ")", as per the specification.
30
+ illegalCharacters = {
31
+ "\x00",
32
+ "\x01",
33
+ "\x02",
34
+ "\x03",
35
+ "\x04",
36
+ "\x05",
37
+ "\x06",
38
+ "\x07",
39
+ "\x08",
40
+ "\t",
41
+ "\n",
42
+ "\x0b",
43
+ "\x0c",
44
+ "\r",
45
+ "\x0e",
46
+ "\x0f",
47
+ "\x10",
48
+ "\x11",
49
+ "\x12",
50
+ "\x13",
51
+ "\x14",
52
+ "\x15",
53
+ "\x16",
54
+ "\x17",
55
+ "\x18",
56
+ "\x19",
57
+ "\x1a",
58
+ "\x1b",
59
+ "\x1c",
60
+ "\x1d",
61
+ "\x1e",
62
+ "\x1f",
63
+ '"',
64
+ "*",
65
+ "+",
66
+ "/",
67
+ ":",
68
+ "<",
69
+ ">",
70
+ "?",
71
+ "[",
72
+ "\\",
73
+ "]",
74
+ "(",
75
+ ")",
76
+ "|",
77
+ "\x7f",
78
+ }
79
+ reservedFileNames = {
80
+ "aux",
81
+ "clock$",
82
+ "com1",
83
+ "com2",
84
+ "com3",
85
+ "com4",
86
+ "com5",
87
+ "com6",
88
+ "com7",
89
+ "com8",
90
+ "com9",
91
+ "con",
92
+ "lpt1",
93
+ "lpt2",
94
+ "lpt3",
95
+ "lpt4",
96
+ "lpt5",
97
+ "lpt6",
98
+ "lpt7",
99
+ "lpt8",
100
+ "lpt9",
101
+ "nul",
102
+ "prn",
103
+ }
104
+ maxFileNameLength = 255
105
+
106
+
107
+ class NameTranslationError(Exception):
108
+ pass
109
+
110
+
111
+ def userNameToFileName(userName: str, existing=(), prefix="", suffix=""):
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
175
+ """
176
+ # the incoming name must be a string
177
+ if not isinstance(userName, str):
178
+ raise ValueError("The value for userName must be a string.")
179
+ # establish the prefix and suffix lengths
180
+ prefixLength = len(prefix)
181
+ suffixLength = len(suffix)
182
+ # replace an initial period with an _
183
+ # if no prefix is to be added
184
+ if not prefix and userName[0] == ".":
185
+ userName = "_" + userName[1:]
186
+ # filter the user name
187
+ filteredUserName = []
188
+ for character in userName:
189
+ # replace illegal characters with _
190
+ if character in illegalCharacters:
191
+ character = "_"
192
+ # add _ to all non-lower characters
193
+ elif character != character.lower():
194
+ character += "_"
195
+ filteredUserName.append(character)
196
+ userName = "".join(filteredUserName)
197
+ # clip to 255
198
+ sliceLength = maxFileNameLength - prefixLength - suffixLength
199
+ userName = userName[:sliceLength]
200
+ # test for illegal files names
201
+ parts = []
202
+ for part in userName.split("."):
203
+ if part.lower() in reservedFileNames:
204
+ part = "_" + part
205
+ parts.append(part)
206
+ userName = ".".join(parts)
207
+ # test for clash
208
+ fullName = prefix + userName + suffix
209
+ if fullName.lower() in existing:
210
+ fullName = handleClash1(userName, existing, prefix, suffix)
211
+ # finished
212
+ return fullName
213
+
214
+
215
+ def handleClash1(userName, existing=[], prefix="", suffix=""):
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
252
+ """
253
+ # if the prefix length + user name length + suffix length + 15 is at
254
+ # or past the maximum length, silce 15 characters off of the user name
255
+ prefixLength = len(prefix)
256
+ suffixLength = len(suffix)
257
+ if prefixLength + len(userName) + suffixLength + 15 > maxFileNameLength:
258
+ l = prefixLength + len(userName) + suffixLength + 15
259
+ sliceLength = maxFileNameLength - l
260
+ userName = userName[:sliceLength]
261
+ finalName = None
262
+ # try to add numbers to create a unique name
263
+ counter = 1
264
+ while finalName is None:
265
+ name = userName + str(counter).zfill(15)
266
+ fullName = prefix + name + suffix
267
+ if fullName.lower() not in existing:
268
+ finalName = fullName
269
+ break
270
+ else:
271
+ counter += 1
272
+ if counter >= 999999999999999:
273
+ break
274
+ # if there is a clash, go to the next fallback
275
+ if finalName is None:
276
+ finalName = handleClash2(existing, prefix, suffix)
277
+ # finished
278
+ return finalName
279
+
280
+
281
+ def handleClash2(existing=[], prefix="", suffix=""):
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
320
+ """
321
+ # calculate the longest possible string
322
+ maxLength = maxFileNameLength - len(prefix) - len(suffix)
323
+ maxValue = int("9" * maxLength)
324
+ # try to find a number
325
+ finalName = None
326
+ counter = 1
327
+ while finalName is None:
328
+ fullName = prefix + str(counter) + suffix
329
+ if fullName.lower() not in existing:
330
+ finalName = fullName
331
+ break
332
+ else:
333
+ counter += 1
334
+ if counter >= maxValue:
335
+ break
336
+ # raise an error if nothing has been found
337
+ if finalName is None:
338
+ raise NameTranslationError("No unique name could be found.")
339
+ # finished
340
+ return finalName
341
+
342
+
343
+ if __name__ == "__main__":
344
+ import doctest
345
+
346
+ doctest.testmod()