CuraProfileReader.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import configparser
  4. from UM.PluginRegistry import PluginRegistry
  5. from UM.Logger import Logger
  6. from UM.Settings.ContainerFormatError import ContainerFormatError
  7. from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make.
  8. from cura.ReaderWriters.ProfileReader import ProfileReader
  9. import zipfile
  10. ## A plugin that reads profile data from Cura profile files.
  11. #
  12. # It reads a profile from a .curaprofile file, and returns it as a profile
  13. # instance.
  14. class CuraProfileReader(ProfileReader):
  15. ## Initialises the cura profile reader.
  16. # This does nothing since the only other function is basically stateless.
  17. def __init__(self):
  18. super().__init__()
  19. ## Reads a cura profile from a file and returns it.
  20. #
  21. # \param file_name The file to read the cura profile from.
  22. # \return The cura profile that was in the file, if any. If the file could
  23. # not be read or didn't contain a valid profile, \code None \endcode is
  24. # returned.
  25. def read(self, file_name):
  26. try:
  27. with zipfile.ZipFile(file_name, "r") as archive:
  28. results = []
  29. for profile_id in archive.namelist():
  30. with archive.open(profile_id) as f:
  31. serialized = f.read()
  32. profile = self._loadProfile(serialized.decode("utf-8"), profile_id)
  33. if profile is not None:
  34. results.append(profile)
  35. return results
  36. except zipfile.BadZipFile:
  37. # It must be an older profile from Cura 2.1.
  38. with open(file_name, encoding = "utf-8") as fhandle:
  39. serialized = fhandle.read()
  40. return [self._loadProfile(serialized, profile_id) for serialized, profile_id in self._upgradeProfile(serialized, file_name)]
  41. ## Convert a profile from an old Cura to this Cura if needed.
  42. #
  43. # \param serialized \type{str} The profile data to convert in the serialized on-disk format.
  44. # \param profile_id \type{str} The name of the profile.
  45. # \return \type{List[Tuple[str,str]]} List of serialized profile strings and matching profile names.
  46. def _upgradeProfile(self, serialized, profile_id):
  47. parser = configparser.ConfigParser(interpolation=None)
  48. parser.read_string(serialized)
  49. if "general" not in parser:
  50. Logger.log("w", "Missing required section 'general'.")
  51. return []
  52. if "version" not in parser["general"]:
  53. Logger.log("w", "Missing required 'version' property")
  54. return []
  55. version = int(parser["general"]["version"])
  56. if InstanceContainer.Version != version:
  57. name = parser["general"]["name"]
  58. return self._upgradeProfileVersion(serialized, name, version)
  59. else:
  60. return [(serialized, profile_id)]
  61. ## Load a profile from a serialized string.
  62. #
  63. # \param serialized \type{str} The profile data to read.
  64. # \param profile_id \type{str} The name of the profile.
  65. # \return \type{InstanceContainer|None}
  66. def _loadProfile(self, serialized, profile_id):
  67. # Create an empty profile.
  68. profile = InstanceContainer(profile_id)
  69. profile.addMetaDataEntry("type", "quality_changes")
  70. try:
  71. profile.deserialize(serialized)
  72. except ContainerFormatError as e:
  73. Logger.log("e", "Error in the format of a container: %s", str(e))
  74. return None
  75. except Exception as e:
  76. Logger.log("e", "Error while trying to parse profile: %s", str(e))
  77. return None
  78. return profile
  79. ## Upgrade a serialized profile to the current profile format.
  80. #
  81. # \param serialized \type{str} The profile data to convert.
  82. # \param profile_id \type{str} The name of the profile.
  83. # \param source_version \type{int} The profile version of 'serialized'.
  84. # \return \type{List[Tuple[str,str]]} List of serialized profile strings and matching profile names.
  85. def _upgradeProfileVersion(self, serialized, profile_id, source_version):
  86. converter_plugins = PluginRegistry.getInstance().getAllMetaData(filter={"version_upgrade": {} }, active_only=True)
  87. source_format = ("profile", source_version)
  88. profile_convert_funcs = [plugin["version_upgrade"][source_format][2] for plugin in converter_plugins
  89. if source_format in plugin["version_upgrade"] and plugin["version_upgrade"][source_format][1] == InstanceContainer.Version]
  90. if not profile_convert_funcs:
  91. return []
  92. filenames, outputs = profile_convert_funcs[0](serialized, profile_id)
  93. if filenames is None and outputs is None:
  94. return []
  95. return list(zip(outputs, filenames))