metadata.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. from data import Tag, Fixed, LongDateTime
  2. from validate.data import validatePostScriptName
  3. checkDocMsg = "Check the documentation to make sure you're doing the manifest right'."
  4. def compileNameRecords(nameRecords, outputFormats):
  5. """
  6. Creates a quick structure for the name records for searching and validation.
  7. """
  8. compiledNameRecords = dict()
  9. # make a dict for each format the user is exporting to.
  10. for f in outputFormats:
  11. compiledNameRecords[f] = dict()
  12. # create initial round of records based on default.
  13. for index, record in nameRecords['default'].items():
  14. compiledNameRecords[f][index] = record
  15. # overwrite that initial round if there are specific overlapping
  16. # name records for this format.
  17. if f in nameRecords:
  18. for index, record in nameRecords[f].items():
  19. compiledNameRecords[f][index] = record
  20. return compiledNameRecords
  21. def compileFinalNameRecords(compiledNameRecords, version):
  22. """
  23. Compiles a final name record package for data by applying version data according to guidelines.
  24. """
  25. for format, records in compiledNameRecords.items():
  26. if "5" in records:
  27. records["5"] = "Version " + str(version) + " " + records["5"]
  28. else:
  29. records["5"] = "Version " + str(version)
  30. return compiledNameRecords
  31. def checkTransformMetadata(metadata, outputFormats):
  32. """
  33. Checks and transforms manifest metadata, ready for font assembly.
  34. """
  35. # Created
  36. # --------------------------------------------------
  37. if not "created" in metadata:
  38. raise ValueError(f"You don't have a metadata.created in your manifest. It has to have this, even if it's a blank string.")
  39. try:
  40. # try to convert this to a LongDateTime format.
  41. metadata['created'] = LongDateTime(metadata['created'])
  42. except ValueError as e:
  43. raise ValueError(f"Something is wrong with the formatting of metadata.created in your manifest. -> {e}")
  44. # Font Version
  45. # ---------------------------------------------------
  46. if not "version" in metadata:
  47. raise ValueError(f"You don't have a metadata.version in your manifest. It has to have this.")
  48. version = metadata['version']
  49. if type(metadata["version"]) is not str:
  50. raise ValueError(f"metadata.version is not formatted as a string. It needs to be formatted as a string.")
  51. try:
  52. float(version)
  53. except ValueError:
  54. raise ValueError(f"metadata.version is not a number that has 3 decimal places. It needs to have 3 decimal places.")
  55. versionComponents = version.split('.')
  56. if not len(versionComponents[1]) == 3:
  57. raise ValueError(f"metadata.version needs to have 3 decimal places. The one you gave has {len(versionComponents[1])}.")
  58. if versionComponents[0] == "0":
  59. raise ValueError(f"metadata.version is not correct. The Major Version (the number before the decimal place) is 0. It should be 1 or higher. Certain environments act weird if you don't. If you need to mark it as a beta, consider marking at such in the version notes in the manifest.")
  60. metadata['version'] = Fixed(metadata['version'])
  61. # OS2VendorID
  62. # ---------------------------------------------------
  63. if 'OS2VendorID' in metadata:
  64. try:
  65. # try to overwrite the string version with a tag data type version.
  66. metadata['OS2VendorID'] = Tag(metadata['OS2VendorID'])
  67. except ValueError as e:
  68. raise ValueError(f"metadata.OS2VendorID doesn't conform to it's data type correctly. → {e}")
  69. # Filenames
  70. # ---------------------------------------------------
  71. # filenames are currently optional.
  72. # if the user doesn't set filenames, forc will just use the format name for the filename.
  73. if "filenames" in metadata:
  74. filenames = metadata['filenames']
  75. # make sure they are set.
  76. for format in outputFormats:
  77. if not format in filenames:
  78. raise ValueError(f"You haven't set a filename for your font for the {format} format in metadata.filenames. {checkDocMsg}")
  79. # check for duplicate filenames.
  80. for format1, filename1 in filenames.items():
  81. for format2, filename2 in filenames.items():
  82. if format2 != format1:
  83. if filename1 == filename2:
  84. raise ValueError(f" The filenames you've set for the formats {format1} and {format2} are the same. There can't be any duplicates in your custom filenames.")
  85. # Name Records
  86. # ---------------------------------------------------
  87. if not "nameRecords" in metadata:
  88. raise ValueError(f"There is no metadata.nameRecords. Your manifest has to have this.")
  89. compiledNameRecords = compileNameRecords(metadata['nameRecords'], outputFormats)
  90. requiredNameRecords = [1,2,3,4,6,16,17]
  91. # make sure all keys and values are strings.
  92. for format, formatRecords in compiledNameRecords.items():
  93. if type(format) is not str:
  94. raise ValueError(f"The format '{format}' in your metadata.nameRecords is not a string.")
  95. for key, record in formatRecords.items():
  96. if type(key) is not str:
  97. raise ValueError(f"There's a problem with metadata.nameRecords. The name record key '{key}' that corresponds to the format '{format}' is not a string.")
  98. try:
  99. int(key)
  100. except ValueError:
  101. raise ValueError(f"There's a problem with metadata.nameRecords. The name record key '{key}' that corresponds to the format '{format}' is not a string that represents a valid integer.")
  102. if int(key) > 25:
  103. raise ValueError(f"There's a problem with metadata.nameRecords. The name record key '{key}' that corresponds to the format '{format}' represents an integer that is not between 0 and 25. It must be between 0 and 25.")
  104. if type(record) is not str:
  105. raise ValueError(f"There's a problem with metadata.nameRecords. The name record '{record}' for the key {key} that corresponds to the format '{format}' is not a string.")
  106. # see if the required name records are here.
  107. for format, formatRecords in compiledNameRecords.items():
  108. for f in requiredNameRecords:
  109. if not str(f) in formatRecords:
  110. raise ValueError(f"There's something wrong with metadata.nameRecords. When compiled, your name records for the '{format}' format are missing a necessary name record type ({str(f)})")
  111. # PostScript Names
  112. for format, formatRecords in compiledNameRecords.items():
  113. try:
  114. validatePostScriptName(formatRecords["6"])
  115. except ValueError as e:
  116. raise ValueError(f"There's something wrong with metadata.nameRecords. When compiled, name record 6 for the '{format}' format doesn't match the data type requirements. {e}")
  117. metadata['nameRecords'] = compileFinalNameRecords(compiledNameRecords, metadata['version'])