Resolve circular imports for CuraAPI

This commit is contained in:
Lipu Fei 2018-09-28 12:06:57 +02:00
parent 3b70e5eb6b
commit dd150bbab9
8 changed files with 81 additions and 31 deletions

View file

@ -1,15 +1,18 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional, Dict from typing import Optional, Dict, TYPE_CHECKING
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty
from UM.i18n import i18nCatalog
from UM.Message import Message from UM.Message import Message
from cura.OAuth2.AuthorizationService import AuthorizationService from cura.OAuth2.AuthorizationService import AuthorizationService
from cura.OAuth2.Models import OAuth2Settings from cura.OAuth2.Models import OAuth2Settings
from UM.Application import Application
from UM.i18n import i18nCatalog if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
@ -26,8 +29,9 @@ class Account(QObject):
# Signal emitted when user logged in or out. # Signal emitted when user logged in or out.
loginStateChanged = pyqtSignal(bool) loginStateChanged = pyqtSignal(bool)
def __init__(self, parent = None) -> None: def __init__(self, application: "CuraApplication", parent = None) -> None:
super().__init__(parent) super().__init__(parent)
self._application = application
self._error_message = None # type: Optional[Message] self._error_message = None # type: Optional[Message]
self._logged_in = False self._logged_in = False
@ -47,7 +51,11 @@ class Account(QObject):
AUTH_FAILED_REDIRECT="{}/app/auth-error".format(self._oauth_root) AUTH_FAILED_REDIRECT="{}/app/auth-error".format(self._oauth_root)
) )
self._authorization_service = AuthorizationService(Application.getInstance().getPreferences(), self._oauth_settings) self._authorization_service = AuthorizationService(self._oauth_settings)
def initialize(self) -> None:
self._authorization_service.initialize(self._application.getPreferences())
self._authorization_service.onAuthStateChanged.connect(self._onLoginStateChanged) self._authorization_service.onAuthStateChanged.connect(self._onLoginStateChanged)
self._authorization_service.onAuthenticationError.connect(self._onLoginStateChanged) self._authorization_service.onAuthenticationError.connect(self._onLoginStateChanged)
self._authorization_service.loadAuthDataFromPreferences() self._authorization_service.loadAuthDataFromPreferences()

View file

@ -1,9 +1,12 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Tuple, Optional from typing import Tuple, Optional, TYPE_CHECKING
from cura.Backups.BackupsManager import BackupsManager from cura.Backups.BackupsManager import BackupsManager
if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
## The back-ups API provides a version-proof bridge between Cura's ## The back-ups API provides a version-proof bridge between Cura's
# BackupManager and plug-ins that hook into it. # BackupManager and plug-ins that hook into it.
@ -13,9 +16,10 @@ from cura.Backups.BackupsManager import BackupsManager
# api = CuraAPI() # api = CuraAPI()
# api.backups.createBackup() # api.backups.createBackup()
# api.backups.restoreBackup(my_zip_file, {"cura_release": "3.1"})`` # api.backups.restoreBackup(my_zip_file, {"cura_release": "3.1"})``
class Backups: class Backups:
manager = BackupsManager() # Re-used instance of the backups manager.
def __init__(self, application: "CuraApplication") -> None:
self.manager = BackupsManager(application)
## Create a new back-up using the BackupsManager. ## Create a new back-up using the BackupsManager.
# \return Tuple containing a ZIP file with the back-up data and a dict # \return Tuple containing a ZIP file with the back-up data and a dict

View file

@ -1,7 +1,11 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from cura.CuraApplication import CuraApplication from typing import TYPE_CHECKING
if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
## The Interface.Settings API provides a version-proof bridge between Cura's ## The Interface.Settings API provides a version-proof bridge between Cura's
# (currently) sidebar UI and plug-ins that hook into it. # (currently) sidebar UI and plug-ins that hook into it.
@ -19,8 +23,9 @@ from cura.CuraApplication import CuraApplication
# api.interface.settings.addContextMenuItem(data)`` # api.interface.settings.addContextMenuItem(data)``
class Settings: class Settings:
# Re-used instance of Cura:
application = CuraApplication.getInstance() # type: CuraApplication def __init__(self, application: "CuraApplication") -> None:
self.application = application
## Add items to the sidebar context menu. ## Add items to the sidebar context menu.
# \param menu_item dict containing the menu item to add. # \param menu_item dict containing the menu item to add.

View file

@ -1,9 +1,15 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import TYPE_CHECKING
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from cura.API.Interface.Settings import Settings from cura.API.Interface.Settings import Settings
if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
## The Interface class serves as a common root for the specific API ## The Interface class serves as a common root for the specific API
# methods for each interface element. # methods for each interface element.
# #
@ -20,5 +26,6 @@ class Interface:
# For now we use the same API version to be consistent. # For now we use the same API version to be consistent.
VERSION = PluginRegistry.APIVersion VERSION = PluginRegistry.APIVersion
def __init__(self, application: "CuraApplication") -> None:
# API methods specific to the settings portion of the UI # API methods specific to the settings portion of the UI
settings = Settings() self.settings = Settings(application)

View file

@ -1,5 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional, TYPE_CHECKING
from PyQt5.QtCore import QObject, pyqtProperty from PyQt5.QtCore import QObject, pyqtProperty
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
@ -7,6 +9,9 @@ from cura.API.Backups import Backups
from cura.API.Interface import Interface from cura.API.Interface import Interface
from cura.API.Account import Account from cura.API.Account import Account
if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
## The official Cura API that plug-ins can use to interact with Cura. ## The official Cura API that plug-ins can use to interact with Cura.
# #
@ -19,14 +24,30 @@ class CuraAPI(QObject):
# For now we use the same API version to be consistent. # For now we use the same API version to be consistent.
VERSION = PluginRegistry.APIVersion VERSION = PluginRegistry.APIVersion
def __init__(self, application: "CuraApplication") -> None:
super().__init__(parent = application)
self._application = application
# Accounts API
self._account = Account(self._application)
# Backups API # Backups API
backups = Backups() self._backups = Backups(self._application)
# Interface API # Interface API
interface = Interface() self._interface = Interface(self._application)
_account = Account() def initialize(self) -> None:
self._account.initialize()
@pyqtProperty(QObject, constant = True) @pyqtProperty(QObject, constant = True)
def account(self) -> Account: def account(self) -> "Account":
return CuraAPI._account return self._account
@property
def backups(self) -> "Backups":
return self._backups
@property
def interface(self) -> "Interface":
return self._interface

View file

@ -1,11 +1,13 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Dict, Optional, Tuple from typing import Dict, Optional, Tuple, TYPE_CHECKING
from UM.Logger import Logger from UM.Logger import Logger
from cura.Backups.Backup import Backup from cura.Backups.Backup import Backup
from cura.CuraApplication import CuraApplication
if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
## The BackupsManager is responsible for managing the creating and restoring of ## The BackupsManager is responsible for managing the creating and restoring of
@ -13,8 +15,8 @@ from cura.CuraApplication import CuraApplication
# #
# Back-ups themselves are represented in a different class. # Back-ups themselves are represented in a different class.
class BackupsManager: class BackupsManager:
def __init__(self): def __init__(self, application: "CuraApplication") -> None:
self._application = CuraApplication.getInstance() self._application = application
## Get a back-up of the current configuration. ## Get a back-up of the current configuration.
# \return A tuple containing a ZipFile (the actual back-up) and a dict # \return A tuple containing a ZipFile (the actual back-up) and a dict

View file

@ -44,6 +44,7 @@ from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
from UM.Operations.GroupedOperation import GroupedOperation from UM.Operations.GroupedOperation import GroupedOperation
from UM.Operations.SetTransformOperation import SetTransformOperation from UM.Operations.SetTransformOperation import SetTransformOperation
from cura.API import CuraAPI
from cura.Arranging.Arrange import Arrange from cura.Arranging.Arrange import Arrange
from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob
from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob
@ -204,7 +205,7 @@ class CuraApplication(QtApplication):
self._quality_profile_drop_down_menu_model = None self._quality_profile_drop_down_menu_model = None
self._custom_quality_profile_drop_down_menu_model = None self._custom_quality_profile_drop_down_menu_model = None
self._cura_API = None self._cura_API = CuraAPI(self)
self._physics = None self._physics = None
self._volume = None self._volume = None
@ -713,6 +714,9 @@ class CuraApplication(QtApplication):
default_visibility_profile = self._setting_visibility_presets_model.getItem(0) default_visibility_profile = self._setting_visibility_presets_model.getItem(0)
self.getPreferences().setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"])) self.getPreferences().setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"]))
# Initialize Cura API
self._cura_API.initialize()
# Detect in which mode to run and execute that mode # Detect in which mode to run and execute that mode
if self._is_headless: if self._is_headless:
self.runWithoutGUI() self.runWithoutGUI()
@ -900,10 +904,7 @@ class CuraApplication(QtApplication):
self._custom_quality_profile_drop_down_menu_model = CustomQualityProfilesDropDownMenuModel(self) self._custom_quality_profile_drop_down_menu_model = CustomQualityProfilesDropDownMenuModel(self)
return self._custom_quality_profile_drop_down_menu_model return self._custom_quality_profile_drop_down_menu_model
def getCuraAPI(self, *args, **kwargs): def getCuraAPI(self, *args, **kwargs) -> "CuraAPI":
if self._cura_API is None:
from cura.API import CuraAPI
self._cura_API = CuraAPI()
return self._cura_API return self._cura_API
## Registers objects for the QML engine to use. ## Registers objects for the QML engine to use.

View file

@ -29,7 +29,7 @@ class AuthorizationService:
# Emit signal when authentication failed. # Emit signal when authentication failed.
onAuthenticationError = Signal() onAuthenticationError = Signal()
def __init__(self, preferences: Optional["Preferences"], settings: "OAuth2Settings") -> None: def __init__(self, settings: "OAuth2Settings", preferences: Optional["Preferences"] = None) -> None:
self._settings = settings self._settings = settings
self._auth_helpers = AuthorizationHelpers(settings) self._auth_helpers = AuthorizationHelpers(settings)
self._auth_url = "{}/authorize".format(self._settings.OAUTH_SERVER_URL) self._auth_url = "{}/authorize".format(self._settings.OAUTH_SERVER_URL)
@ -38,6 +38,8 @@ class AuthorizationService:
self._preferences = preferences self._preferences = preferences
self._server = LocalAuthorizationServer(self._auth_helpers, self._onAuthStateChanged, daemon=True) self._server = LocalAuthorizationServer(self._auth_helpers, self._onAuthStateChanged, daemon=True)
def initialize(self, preferences: Optional["Preferences"] = None) -> None:
self._preferences = preferences
if self._preferences: if self._preferences:
self._preferences.addPreference(self._settings.AUTH_DATA_PREFERENCE_KEY, "{}") self._preferences.addPreference(self._settings.AUTH_DATA_PREFERENCE_KEY, "{}")