def __init__(self, file_name: str) -> None: super().__init__() self._logger = logging.getLogger(self._name) # Create python logger self._logger.setLevel(logging.DEBUG) self._show_once = set() # type: Set[str] # Do not try to save to the app dir as it may not be writeable or may not be the right # location to save the log file. Instead, try and save in the settings location since # that should be writeable. self.setFileName(Resources.getStoragePath(Resources.Resources, file_name)) VersionUpgradeManager.getInstance().registerIgnoredFile(file_name)
def __init__(self, file_name): super().__init__() self._logger = logging.getLogger(self._name) # Create python logger self._logger.setLevel(logging.DEBUG) # Do not try to save to the app dir as it may not be writeable or may not be the right # location to save the log file. Instead, try and save in the settings location since # that should be writeable. self.setFileName( Resources.getStoragePath(Resources.Resources, file_name)) VersionUpgradeManager.getInstance().registerIgnoredFile(file_name)
def __updateSerialized(self, serialized: str) -> str: configuration_type = "preferences" try: from UM.VersionUpgradeManager import VersionUpgradeManager version = VersionUpgradeManager.getInstance().getFileVersion(configuration_type, serialized) if version is not None: result = VersionUpgradeManager.getInstance().updateFilesData(configuration_type, version, [serialized], [""]) if result is not None: serialized = result.files_data[0] except: Logger.logException("d", "An exception occurred while trying to update the preferences.") return serialized
def initialize(self, check_if_trusted: bool = False) -> None: super().initialize() preferences = Application.getInstance().getPreferences() if check_if_trusted: # Need to do this before the preferences are read for the first time, but after obj-creation, which is here. preferences.indicateUntrustedPreference("general", "theme", lambda value: self._isPathSecure(Resources.getPath(Resources.Themes, value))) preferences.indicateUntrustedPreference("backend", "location", lambda value: self._isPathSecure(os.path.abspath(value))) preferences.addPreference("view/force_empty_shader_cache", False) preferences.addPreference("view/opengl_version_detect", OpenGLContext.OpenGlVersionDetect.Autodetect) # Read preferences here (upgrade won't work) to get: # - The language in use, so the splash window can be shown in the correct language. # - The OpenGL 'force' parameters. try: self.readPreferencesFromConfiguration() except FileNotFoundError: Logger.log("i", "Preferences file not found, ignore and use default language '%s'", self._default_language) # Initialize the package manager to remove and install scheduled packages. self._package_manager = self._package_manager_class(self, parent = self) # If a plugin is removed, check if the matching package is also removed. self._plugin_registry.pluginRemoved.connect(lambda plugin_id: self._package_manager.removePackage(plugin_id)) self._mesh_file_handler = MeshFileHandler(self) #type: MeshFileHandler self._workspace_file_handler = WorkspaceFileHandler(self) #type: WorkspaceFileHandler if preferences.getValue("view/force_empty_shader_cache"): self.setAttribute(Qt.ApplicationAttribute.AA_DisableShaderDiskCache) if preferences.getValue("view/opengl_version_detect") != OpenGLContext.OpenGlVersionDetect.ForceModern: major_version, minor_version, profile = OpenGLContext.detectBestOpenGLVersion( preferences.getValue("view/opengl_version_detect") == OpenGLContext.OpenGlVersionDetect.ForceLegacy) else: Logger.info("Force 'modern' OpenGL (4.1 core) -- overrides 'force legacy opengl' preference.") major_version, minor_version, profile = (4, 1, QSurfaceFormat.OpenGLContextProfile.CoreProfile) if major_version is None or minor_version is None or profile is None: Logger.log("e", "Startup failed because OpenGL version probing has failed: tried to create a 2.0 and 4.1 context. Exiting") if not self.getIsHeadLess(): QMessageBox.critical(None, "Failed to probe OpenGL", "Could not probe OpenGL. This program requires OpenGL 2.0 or higher. Please check your video card drivers.") sys.exit(1) else: opengl_version_str = OpenGLContext.versionAsText(major_version, minor_version, profile) Logger.log("d", "Detected most suitable OpenGL context version: %s", opengl_version_str) if not self.getIsHeadLess(): OpenGLContext.setDefaultFormat(major_version, minor_version, profile = profile) self._qml_import_paths.append(os.path.join(os.path.dirname(sys.executable), "qml")) self._qml_import_paths.append(os.path.join(self.getInstallPrefix(), "Resources", "qml")) Logger.log("i", "Initializing job queue ...") self._job_queue = JobQueue() self._job_queue.jobFinished.connect(self._onJobFinished) Logger.log("i", "Initializing version upgrade manager ...") self._version_upgrade_manager = VersionUpgradeManager(self)
def _upgradeProfileVersion(self, serialized: str, profile_id: str, main_version: int, setting_version: int) -> List[Tuple[str, str]]: source_version = main_version * 1000000 + setting_version from UM.VersionUpgradeManager import VersionUpgradeManager results = VersionUpgradeManager.getInstance().updateFilesData( "quality_changes", source_version, [serialized], [profile_id]) if results is None: return [] serialized = results.files_data[0] parser = configparser.ConfigParser(interpolation=None) parser.read_string(serialized) if "general" not in parser: Logger.log("w", "Missing required section 'general'.") return [] new_source_version = results.version if int( new_source_version / 1000000 ) != InstanceContainer.Version or new_source_version % 1000000 != CuraApplication.SettingVersion: Logger.log("e", "Failed to upgrade profile [%s]", profile_id) if int(parser["general"]["version"]) != InstanceContainer.Version: Logger.log("e", "Failed to upgrade profile [%s]", profile_id) return [] return [(serialized, profile_id)]
def initialize(self) -> None: super().initialize() # Initialize the package manager to remove and install scheduled packages. self._package_manager = self._package_manager_class(self, parent = self) self._mesh_file_handler = MeshFileHandler(self) #type: MeshFileHandler self._workspace_file_handler = WorkspaceFileHandler(self) #type: WorkspaceFileHandler # Remove this and you will get Windows 95 style for all widgets if you are using Qt 5.10+ self.setStyle("fusion") self.setAttribute(Qt.AA_UseDesktopOpenGL) major_version, minor_version, profile = OpenGLContext.detectBestOpenGLVersion() if major_version is None or minor_version is None or profile is None: Logger.log("e", "Startup failed because OpenGL version probing has failed: tried to create a 2.0 and 4.1 context. Exiting") if not self.getIsHeadLess(): QMessageBox.critical(None, "Failed to probe OpenGL", "Could not probe OpenGL. This program requires OpenGL 2.0 or higher. Please check your video card drivers.") sys.exit(1) else: opengl_version_str = OpenGLContext.versionAsText(major_version, minor_version, profile) Logger.log("d", "Detected most suitable OpenGL context version: %s", opengl_version_str) if not self.getIsHeadLess(): OpenGLContext.setDefaultFormat(major_version, minor_version, profile = profile) self._qml_import_paths.append(os.path.join(os.path.dirname(sys.executable), "qml")) self._qml_import_paths.append(os.path.join(self.getInstallPrefix(), "Resources", "qml")) Logger.log("i", "Initializing job queue ...") self._job_queue = JobQueue() self._job_queue.jobFinished.connect(self._onJobFinished) Logger.log("i", "Initializing version upgrade manager ...") self._version_upgrade_manager = VersionUpgradeManager(self)
def collectAllSettingIds(): VersionUpgradeManager._VersionUpgradeManager__instance = VersionUpgradeManager(MagicMock()) CuraApplication._initializeSettingDefinitions() definition_container = DefinitionContainer("whatever") with open(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions", "fdmprinter.def.json"), encoding = "utf-8") as data: definition_container.deserialize(data.read()) return definition_container.getAllKeys()
def initialize(self) -> None: super().initialize() preferences = Application.getInstance().getPreferences() preferences.addPreference("view/force_empty_shader_cache", False) preferences.addPreference("view/opengl_version_detect", OpenGLContext.OpenGlVersionDetect.Autodetect) # Read preferences here (upgrade won't work) to get: # - The language in use, so the splash window can be shown in the correct language. # - The OpenGL 'force' parameters. try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(preferences_filename) except FileNotFoundError: Logger.log("i", "Preferences file not found, ignore and use default language '%s'", self._default_language) # Initialize the package manager to remove and install scheduled packages. self._package_manager = self._package_manager_class(self, parent = self) self._mesh_file_handler = MeshFileHandler(self) #type: MeshFileHandler self._workspace_file_handler = WorkspaceFileHandler(self) #type: WorkspaceFileHandler # Remove this and you will get Windows 95 style for all widgets if you are using Qt 5.10+ self.setStyle("fusion") if preferences.getValue("view/force_empty_shader_cache"): self.setAttribute(Qt.AA_DisableShaderDiskCache) self.setAttribute(Qt.AA_UseDesktopOpenGL) if preferences.getValue("view/opengl_version_detect") != OpenGLContext.OpenGlVersionDetect.ForceModern: major_version, minor_version, profile = OpenGLContext.detectBestOpenGLVersion( preferences.getValue("view/opengl_version_detect") == OpenGLContext.OpenGlVersionDetect.ForceLegacy) else: Logger.info("Force 'modern' OpenGL (4.1 core) -- overrides 'force legacy opengl' preference.") major_version, minor_version, profile = (4, 1, QSurfaceFormat.CoreProfile) if major_version is None or minor_version is None or profile is None: Logger.log("e", "Startup failed because OpenGL version probing has failed: tried to create a 2.0 and 4.1 context. Exiting") if not self.getIsHeadLess(): QMessageBox.critical(None, "Failed to probe OpenGL", "Could not probe OpenGL. This program requires OpenGL 2.0 or higher. Please check your video card drivers.") sys.exit(1) else: opengl_version_str = OpenGLContext.versionAsText(major_version, minor_version, profile) Logger.log("d", "Detected most suitable OpenGL context version: %s", opengl_version_str) if not self.getIsHeadLess(): OpenGLContext.setDefaultFormat(major_version, minor_version, profile = profile) self._qml_import_paths.append(os.path.join(os.path.dirname(sys.executable), "qml")) self._qml_import_paths.append(os.path.join(self.getInstallPrefix(), "Resources", "qml")) Logger.log("i", "Initializing job queue ...") self._job_queue = JobQueue() self._job_queue.jobFinished.connect(self._onJobFinished) Logger.log("i", "Initializing version upgrade manager ...") self._version_upgrade_manager = VersionUpgradeManager(self)
def __updateSerialized(self, serialized: str) -> str: configuration_type = self.getConfigurationTypeFromSerialized(serialized) version = self.getVersionFromSerialized(serialized) if configuration_type is not None and version is not None: from UM.VersionUpgradeManager import VersionUpgradeManager result = VersionUpgradeManager.getInstance().updateFilesData(configuration_type, version, [serialized], [""]) if result is not None: serialized = result.files_data[0] return serialized
def register(app): # add Mime type mime_type = MimeType( name = "application/x-ultimaker-material-profile", comment = "Ultimaker Material Profile", suffixes = [ "xml.fdm_material" ] ) MimeTypeDatabase.addMimeType(mime_type) # add upgrade version from cura.CuraApplication import CuraApplication from UM.VersionUpgradeManager import VersionUpgradeManager VersionUpgradeManager.getInstance().registerCurrentVersion( ("materials", XmlMaterialProfile.XmlMaterialProfile.Version * 1000000 + CuraApplication.SettingVersion), (CuraApplication.ResourceTypes.MaterialInstanceContainer, "application/x-ultimaker-material-profile") ) return {"version_upgrade": upgrader, "settings_container": XmlMaterialProfile.XmlMaterialProfile("default_xml_material_profile"), }
def _updateSerialized(cls, serialized: str, file_name: Optional[str] = None) -> str: configuration_type = cls.getConfigurationTypeFromSerialized(serialized) version = cls.getVersionFromSerialized(serialized) if configuration_type is not None and version is not None: from UM.VersionUpgradeManager import VersionUpgradeManager result = VersionUpgradeManager.getInstance().updateFilesData(configuration_type, version, [serialized], [file_name if file_name else ""]) if result is not None: serialized = result.files_data[0] return serialized
def _updateSerialized(cls, serialized: str, file_name: Optional[str] = None) -> str: configuration_type = cls.getConfigurationTypeFromSerialized(serialized) version = cls.getVersionFromSerialized(serialized) if configuration_type is not None and version is not None: from UM.VersionUpgradeManager import VersionUpgradeManager result = VersionUpgradeManager.getInstance().updateFilesData( configuration_type, version, [serialized], [file_name if file_name else ""]) if result is not None: serialized = result.files_data[0] return serialized
def getVersionFromSerialized(cls, serialized: str) -> Optional[int]: configuration_type = cls.getConfigurationTypeFromSerialized(serialized) if not configuration_type: Logger.log("d", "Could not get type from serialized.") return None # Get version version = None try: from UM.VersionUpgradeManager import VersionUpgradeManager version = VersionUpgradeManager.getInstance().getFileVersion(configuration_type, serialized) except Exception as e: Logger.log("d", "Could not get version from serialized: %s", e) return version
def initialize(self) -> None: super().initialize() self._mesh_file_handler = MeshFileHandler(self) #type: MeshFileHandler self._workspace_file_handler = WorkspaceFileHandler(self) #type: WorkspaceFileHandler # For some reason, with Qt 5.9 and up, the default "windows" style seems like Windows 95. We have to set the # style to "fusion" so it looks less ugly. pyqt_version_parts = [int(n) for n in PYQT_VERSION_STR.split(".")] if len(pyqt_version_parts) < 2: # Make sure there are at less 2 parts in the version pyqt_version_parts += [0 for _ in range(2 - len(pyqt_version_parts))] if pyqt_version_parts[0] == 5 and pyqt_version_parts[1] > 8: self.setStyle("fusion") # For some reason, with Qt 5.9 and up, the default "windows" style seems like Windows 95. We have to set the # style to "fusion" so it looks less ugly. pyqt_version_parts = [int(n) for n in PYQT_VERSION_STR.split(".")] if len(pyqt_version_parts) < 2: # Make sure there are at less 2 parts in the version pyqt_version_parts += [0 for _ in range(2 - len(pyqt_version_parts))] if pyqt_version_parts[0] == 5 and pyqt_version_parts[1] > 8: self.setStyle("fusion") self.setAttribute(Qt.AA_UseDesktopOpenGL) major_version, minor_version, profile = OpenGLContext.detectBestOpenGLVersion() if major_version is None and minor_version is None and profile is None: Logger.log("e", "Startup failed because OpenGL version probing has failed: tried to create a 2.0 and 4.1 context. Exiting") QMessageBox.critical(None, "Failed to probe OpenGL", "Could not probe OpenGL. This program requires OpenGL 2.0 or higher. Please check your video card drivers.") sys.exit(1) else: opengl_version_str = OpenGLContext.versionAsText(major_version, minor_version, profile) Logger.log("d", "Detected most suitable OpenGL context version: %s", opengl_version_str) OpenGLContext.setDefaultFormat(major_version, minor_version, profile = profile) self._qml_import_paths.append(os.path.join(os.path.dirname(sys.executable), "qml")) self._qml_import_paths.append(os.path.join(self.getInstallPrefix(), "Resources", "qml")) Logger.log("i", "Initializing job queue ...") self._job_queue = JobQueue() self._job_queue.jobFinished.connect(self._onJobFinished) Logger.log("i", "Initializing version upgrade manager ...") self._version_upgrade_manager = VersionUpgradeManager(self)
def initialize(self) -> None: super().initialize() self._mesh_file_handler = MeshFileHandler(self) #type: MeshFileHandler self._workspace_file_handler = WorkspaceFileHandler( self) #type: WorkspaceFileHandler self.setAttribute(Qt.AA_UseDesktopOpenGL) major_version, minor_version, profile = OpenGLContext.detectBestOpenGLVersion( ) if major_version is None and minor_version is None and profile is None: Logger.log( "e", "Startup failed because OpenGL version probing has failed: tried to create a 2.0 and 4.1 context. Exiting" ) QMessageBox.critical( None, "Failed to probe OpenGL", "Could not probe OpenGL. This program requires OpenGL 2.0 or higher. Please check your video card drivers." ) sys.exit(1) else: opengl_version_str = OpenGLContext.versionAsText( major_version, minor_version, profile) Logger.log("d", "Detected most suitable OpenGL context version: %s", opengl_version_str) OpenGLContext.setDefaultFormat(major_version, minor_version, profile=profile) self._qml_import_paths.append( os.path.join(os.path.dirname(sys.executable), "qml")) self._qml_import_paths.append( os.path.join(self.getInstallPrefix(), "Resources", "qml")) Logger.log("i", "Initializing job queue ...") self._job_queue = JobQueue() self._job_queue.jobFinished.connect(self._onJobFinished) Logger.log("i", "Initializing version upgrade manager ...") self._version_upgrade_manager = VersionUpgradeManager(self)
def setup_method(self, method): self._upgrade_manager = VersionUpgradeManager()
class TestVersionUpgradeManager(): ## Executed before the first test function is executed. def setup_method(self, method): self._upgrade_manager = VersionUpgradeManager() ## Executed after the last test function was executed. def teardown_method(self, method): pass ## The individual test cases for shortest upgrade paths. # # Each entry contains a list of possible upgrades. Each upgrade has a # from_version, a to_version and a preference_type field. Each entry also # has a destination version to upgrade to and a preference type to filter # on. Each entry has a list of possible answers, each of which is a # mapping of version numbers to indices referring to upgrades in the input # list. Lastly, each entry has a name for debugging. test_shortest_paths_data = [ ({ "name": "two-step", "upgrades": [ { "from_version": 0, "to_version": 1, "preference_type": "a" }, { "from_version": 1, "to_version": 2, "preference_type": "a" } ], "destination": 2, "preference_type": "a", "answers": [ { 0: 0, 1: 1 } ] }), ({ "name": "two-options", "upgrades": [ { "from_version": 0, "to_version": 1, "preference_type": "a" }, { "from_version": 0, "to_version": 1, "preference_type": "a" } ], "destination": 1, "preference_type": "a", "answers": [ { 0: 0 }, { 0: 1 } ] }), ({ "name": "shortcut", "upgrades": [ { "from_version": 0, "to_version": 1, "preference_type": "a" }, { "from_version": 1, "to_version": 2, "preference_type": "a" }, { "from_version": 0, "to_version": 2, "preference_type": "a" } ], "destination": 2, "preference_type": "a", "answers": [ { 0: 2, 1: 1 } ] }), ({ "name": "preference-type-filter", "upgrades": [ { "from_version": 0, "to_version": 2, "preference_type": "b" }, { "from_version": 1, "to_version": 2, "preference_type": "a" }, { "from_version": 0, "to_version": 1, "preference_type": "a" } ], "destination": 2, "preference_type": "a", "answers": [ { 0: 2, 1: 1 } ] }) ] ## Tests the algorithm to find shortest paths to update plug-ins. # # This function is normally not "exposed" (though Python puts no # limitations on that). However, since the accuracy of this function # should only affect the execution speed, it is wise to test this function # nonetheless. # # \param data The data containing individual tests. @pytest.mark.parametrize("data", test_shortest_paths_data) def test_shortest_paths(self, data): registry = Application.getInstance().getPluginRegistry() self._loadUpgrades(data["upgrades"]) shortest_paths = self._upgrade_manager._findShortestUpgradePaths(data["preference_type"], data["destination"]) # Find the shortest path. # Convert the upgrades in the path to indices in our original data. to_indices = {} for version, upgrade in shortest_paths.items(): metadata = registry.getMetaData(upgrade.getPluginId())["version_upgrade"] for key, value in metadata.items(): # Get just the first element of the dict. There is always only one. preference_type = key from_version = metadata[preference_type]["from"] to_version = metadata[preference_type]["to"] break for i in range(0, len(data["upgrades"])): # Which index does it have? if data["upgrades"][i]["from_version"] == from_version and data["upgrades"][i]["to_version"] == to_version and data["upgrades"][i]["preference_type"] == preference_type: to_indices[from_version] = i break # Compare with the answers. for answer in data["answers"]: if len(answer) != len(to_indices): # Not the same amount of source versions. continue # Incorrect answer. for version, upgrade in answer.items(): if version not in to_indices: # Key is missing! break # Incorrect answer. if answer[version] != to_indices[version]: # Different plug-in for this version! break # Incorrect answer. else: # No indices were different. Answer is correct. break else: # No answers were correct. assert False # Incorrect path. ## Create a plug-in registry with the specified upgrade plug-ins in it. # # \param upgrades Metadata of upgrades to fill the registry with, as # obtained from test_shortest_paths_data. def _loadUpgrades(self, upgrades): registry = Application.getInstance().getPluginRegistry() for upgrade in upgrades: # Artificially fill the plug-in registry with my own metadata! plugin_object = PluginObject() metadata = { # Correctly fill the metadata for this plug-in. "plugin": { "name": "Upgrade Test", # Note: Don't use internationalisation here, lest it be grabbed by gettext. "author": "Ultimaker", "version": "1.0", "description": "Upgrade plug-in to test with.", "api": 2 }, "version_upgrade": {} } metadata["version_upgrade"][upgrade["preference_type"]] = {} metadata["version_upgrade"][upgrade["preference_type"]]["from"] = upgrade["from_version"] metadata["version_upgrade"][upgrade["preference_type"]]["to"] = upgrade["to_version"] id = upgrade["preference_type"] + "-from-" + str(upgrade["from_version"]) + "-to-" + str(upgrade["to_version"]) # ID becomes "type-from-#-to-#". plugin_object.setPluginId(id) registry._plugins[id] = plugin_object registry._meta_data[id] = metadata self._upgrade_manager._addVersionUpgrade(plugin_object)
def upgrade_manager(application): VersionUpgradeManager._VersionUpgradeManager__instance = None upgrade_manager = VersionUpgradeManager(application) return upgrade_manager
def startSplashWindowPhase(self) -> None: super().startSplashWindowPhase() i18n_catalog = i18nCatalog("uranium") self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Initializing package manager...")) self._package_manager.initialize() # Read preferences here (upgrade won't work) to get the language in use, so the splash window can be shown in # the correct language. try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(preferences_filename) except FileNotFoundError: Logger.log( "i", "Preferences file not found, ignore and use default language '%s'", self._default_language) signal.signal(signal.SIGINT, signal.SIG_DFL) # This is done here as a lot of plugins require a correct gl context. If you want to change the framework, # these checks need to be done in your <framework>Application.py class __init__(). self._configuration_error_message = ConfigurationErrorMessage( self, i18n_catalog.i18nc("@info:status", "Your configuration seems to be corrupt."), lifetime=0, title=i18n_catalog.i18nc("@info:title", "Configuration errors")) # Remove, install, and then loading plugins self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading plugins...")) # Remove and install the plugins that have been scheduled self._plugin_registry.initializeBeforePluginsAreLoaded() self._loadPlugins() self._plugin_registry.checkRequiredPlugins(self.getRequiredPlugins()) self.pluginsLoaded.emit() self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Updating configuration...")) with self._container_registry.lockFile(): VersionUpgradeManager.getInstance().upgrade() # Load preferences again because before we have loaded the plugins, we don't have the upgrade routine for # the preferences file. Now that we have, load the preferences file again so it can be upgraded and loaded. self.showSplashMessage( i18n_catalog.i18nc("@info:progress", "Loading preferences...")) try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") with open(preferences_filename, "r", encoding="utf-8") as f: serialized = f.read() # This performs the upgrade for Preferences self._preferences.deserialize(serialized) self._preferences.setValue("general/plugins_to_remove", "") self._preferences.writeToFile(preferences_filename) except (FileNotFoundError, UnicodeDecodeError): Logger.log( "i", "The preferences file cannot be found or it is corrupted, so we will use default values" ) self.processEvents() # Force the configuration file to be written again since the list of plugins to remove maybe changed try: self._preferences_filename = Resources.getPath( Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(self._preferences_filename) except FileNotFoundError: Logger.log( "i", "The preferences file '%s' cannot be found, will use default values", self._preferences_filename) self._preferences_filename = Resources.getStoragePath( Resources.Preferences, self._app_name + ".cfg") # FIXME: This is done here because we now use "plugins.json" to manage plugins instead of the Preferences file, # but the PluginRegistry will still import data from the Preferences files if present, such as disabled plugins, # so we need to reset those values AFTER the Preferences file is loaded. self._plugin_registry.initializeAfterPluginsAreLoaded() # Check if we have just updated from an older version self._preferences.addPreference("general/last_run_version", "") last_run_version_str = self._preferences.getValue( "general/last_run_version") if not last_run_version_str: last_run_version_str = self._version last_run_version = Version(last_run_version_str) current_version = Version(self._version) if last_run_version < current_version: self._just_updated_from_old_version = True self._preferences.setValue("general/last_run_version", str(current_version)) self._preferences.writeToFile(self._preferences_filename) # Preferences: recent files self._preferences.addPreference("%s/recent_files" % self._app_name, "") file_names = self._preferences.getValue("%s/recent_files" % self._app_name).split(";") for file_name in file_names: if not os.path.isfile(file_name): continue self._recent_files.append(QUrl.fromLocalFile(file_name)) if not self.getIsHeadLess(): # Initialize System tray icon and make it invisible because it is used only to show pop up messages self._tray_icon = None if self._tray_icon_name: self._tray_icon = QIcon( Resources.getPath(Resources.Images, self._tray_icon_name)) self._tray_icon_widget = QSystemTrayIcon(self._tray_icon) self._tray_icon_widget.setVisible(False)
class TestVersionUpgradeManager(): ## Executed before the first test function is executed. def setup_method(self, method): self._upgrade_manager = VersionUpgradeManager() ## Executed after the last test function was executed. def teardown_method(self, method): pass ## The individual test cases for shortest upgrade paths. # # Each entry contains a list of possible upgrades. Each upgrade has a # from_version, a to_version and a preference_type field. Each entry also # has a destination version to upgrade to and a preference type to filter # on. Each entry has a list of possible answers, each of which is a # mapping of version numbers to indices referring to upgrades in the input # list. Lastly, each entry has a name for debugging. test_shortest_paths_data = [({ "name": "two-step", "upgrades": [{ "from_version": 0, "to_version": 1, "preference_type": "a" }, { "from_version": 1, "to_version": 2, "preference_type": "a" }], "destination": 2, "preference_type": "a", "answers": [{ 0: 0, 1: 1 }] }), ({ "name": "two-options", "upgrades": [{ "from_version": 0, "to_version": 1, "preference_type": "a" }, { "from_version": 0, "to_version": 1, "preference_type": "a" }], "destination": 1, "preference_type": "a", "answers": [{ 0: 0 }, { 0: 1 }] }), ({ "name": "shortcut", "upgrades": [{ "from_version": 0, "to_version": 1, "preference_type": "a" }, { "from_version": 1, "to_version": 2, "preference_type": "a" }, { "from_version": 0, "to_version": 2, "preference_type": "a" }], "destination": 2, "preference_type": "a", "answers": [{ 0: 2, 1: 1 }] }), ({ "name": "preference-type-filter", "upgrades": [{ "from_version": 0, "to_version": 2, "preference_type": "b" }, { "from_version": 1, "to_version": 2, "preference_type": "a" }, { "from_version": 0, "to_version": 1, "preference_type": "a" }], "destination": 2, "preference_type": "a", "answers": [{ 0: 2, 1: 1 }] })] ## Tests the algorithm to find shortest paths to update plug-ins. # # This function is normally not "exposed" (though Python puts no # limitations on that). However, since the accuracy of this function # should only affect the execution speed, it is wise to test this function # nonetheless. # # \param data The data containing individual tests. @pytest.mark.parametrize("data", test_shortest_paths_data) def test_shortest_paths(self, data): registry = Application.getInstance().getPluginRegistry() self._loadUpgrades(data["upgrades"]) shortest_paths = self._upgrade_manager._findShortestUpgradePaths( data["preference_type"], data["destination"]) # Find the shortest path. # Convert the upgrades in the path to indices in our original data. to_indices = {} for version, upgrade in shortest_paths.items(): metadata = registry.getMetaData( upgrade.getPluginId())["version_upgrade"] for key, value in metadata.items( ): # Get just the first element of the dict. There is always only one. preference_type = key from_version = metadata[preference_type]["from"] to_version = metadata[preference_type]["to"] break for i in range(0, len(data["upgrades"])): # Which index does it have? if data["upgrades"][i]["from_version"] == from_version and data[ "upgrades"][i]["to_version"] == to_version and data[ "upgrades"][i][ "preference_type"] == preference_type: to_indices[from_version] = i break # Compare with the answers. for answer in data["answers"]: if len(answer) != len( to_indices): # Not the same amount of source versions. continue # Incorrect answer. for version, upgrade in answer.items(): if version not in to_indices: # Key is missing! break # Incorrect answer. if answer[version] != to_indices[ version]: # Different plug-in for this version! break # Incorrect answer. else: # No indices were different. Answer is correct. break else: # No answers were correct. assert False # Incorrect path. ## Create a plug-in registry with the specified upgrade plug-ins in it. # # \param upgrades Metadata of upgrades to fill the registry with, as # obtained from test_shortest_paths_data. def _loadUpgrades(self, upgrades): registry = Application.getInstance().getPluginRegistry() for upgrade in upgrades: # Artificially fill the plug-in registry with my own metadata! plugin_object = PluginObject() metadata = { # Correctly fill the metadata for this plug-in. "plugin": { "name": "Upgrade Test", # Note: Don't use internationalisation here, lest it be grabbed by gettext. "author": "Ultimaker", "version": "1.0", "description": "Upgrade plug-in to test with.", "api": 2 }, "version_upgrade": {} } metadata["version_upgrade"][upgrade["preference_type"]] = {} metadata["version_upgrade"][ upgrade["preference_type"]]["from"] = upgrade["from_version"] metadata["version_upgrade"][ upgrade["preference_type"]]["to"] = upgrade["to_version"] id = upgrade["preference_type"] + "-from-" + str( upgrade["from_version"]) + "-to-" + str( upgrade["to_version"]) # ID becomes "type-from-#-to-#". plugin_object.setPluginId(id) registry._plugins[id] = plugin_object registry._meta_data[id] = metadata self._upgrade_manager._addVersionUpgrade(plugin_object)
def startSplashWindowPhase(self) -> None: super().startSplashWindowPhase() self._package_manager.initialize() # Read preferences here (upgrade won't work) to get the language in use, so the splash window can be shown in # the correct language. try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(preferences_filename) except FileNotFoundError: Logger.log("i", "Preferences file not found, ignore and use default language '%s'", self._default_language) signal.signal(signal.SIGINT, signal.SIG_DFL) # This is done here as a lot of plugins require a correct gl context. If you want to change the framework, # these checks need to be done in your <framework>Application.py class __init__(). i18n_catalog = i18nCatalog("uranium") self._configuration_error_message = ConfigurationErrorMessage(self, i18n_catalog.i18nc("@info:status", "Your configuration seems to be corrupt."), lifetime = 0, title = i18n_catalog.i18nc("@info:title", "Configuration errors") ) # Remove, install, and then loading plugins self.showSplashMessage(i18n_catalog.i18nc("@info:progress", "Loading plugins...")) # Remove and install the plugins that have been scheduled self._plugin_registry.initializeBeforePluginsAreLoaded() self._loadPlugins() self._plugin_registry.checkRequiredPlugins(self.getRequiredPlugins()) self.pluginsLoaded.emit() self.showSplashMessage(i18n_catalog.i18nc("@info:progress", "Updating configuration...")) with self._container_registry.lockFile(): VersionUpgradeManager.getInstance().upgrade() # Load preferences again because before we have loaded the plugins, we don't have the upgrade routine for # the preferences file. Now that we have, load the preferences file again so it can be upgraded and loaded. try: preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") with open(preferences_filename, "r", encoding = "utf-8") as f: serialized = f.read() # This performs the upgrade for Preferences self._preferences.deserialize(serialized) self._preferences.setValue("general/plugins_to_remove", "") self._preferences.writeToFile(preferences_filename) except FileNotFoundError: Logger.log("i", "The preferences file cannot be found, will use default values") # Force the configuration file to be written again since the list of plugins to remove maybe changed self.showSplashMessage(i18n_catalog.i18nc("@info:progress", "Loading preferences...")) try: self._preferences_filename = Resources.getPath(Resources.Preferences, self._app_name + ".cfg") self._preferences.readFromFile(self._preferences_filename) except FileNotFoundError: Logger.log("i", "The preferences file '%s' cannot be found, will use default values", self._preferences_filename) self._preferences_filename = Resources.getStoragePath(Resources.Preferences, self._app_name + ".cfg") # FIXME: This is done here because we now use "plugins.json" to manage plugins instead of the Preferences file, # but the PluginRegistry will still import data from the Preferences files if present, such as disabled plugins, # so we need to reset those values AFTER the Preferences file is loaded. self._plugin_registry.initializeAfterPluginsAreLoaded() # Check if we have just updated from an older version self._preferences.addPreference("general/last_run_version", "") last_run_version_str = self._preferences.getValue("general/last_run_version") if not last_run_version_str: last_run_version_str = self._version last_run_version = Version(last_run_version_str) current_version = Version(self._version) if last_run_version < current_version: self._just_updated_from_old_version = True self._preferences.setValue("general/last_run_version", str(current_version)) self._preferences.writeToFile(self._preferences_filename) # Preferences: recent files self._preferences.addPreference("%s/recent_files" % self._app_name, "") file_names = self._preferences.getValue("%s/recent_files" % self._app_name).split(";") for file_name in file_names: if not os.path.isfile(file_name): continue self._recent_files.append(QUrl.fromLocalFile(file_name)) if not self.getIsHeadLess(): # Initialize System tray icon and make it invisible because it is used only to show pop up messages self._tray_icon = None if self._tray_icon_name: self._tray_icon = QIcon(Resources.getPath(Resources.Images, self._tray_icon_name)) self._tray_icon_widget = QSystemTrayIcon(self._tray_icon) self._tray_icon_widget.setVisible(False)