[LYN-2470] Integrate resource mapping tool with engine python environment (#17)

1. Add support to use engine python runtime environment. Ideally we should use project executable directory which contains required qt binaries after build. But currently Qt plugins are not put under proper subdirectory which causes huge overhead of loading plugin binaries (see details in this jira https://jira.agscollab.com/browse/LYN-2669 ). The temporary solution is to use AWSCore.Editor target to create a subdirectory for our use case.   
2. **Minor Fix** After migrating to engine python environment, see boto3 warning while using debug mode, seems like a existing issue for a long time https://github.com/boto/boto3/issues/454. Register a after call event to close connection   
3. **Minor Fix** After migrating to engine python environment, see Qt multithread warning while using debug mode, change direct setter function call to qt signal
This commit is contained in:
Vincent Liu
2021-04-23 11:34:37 -07:00
committed by GitHub
parent 16ca036ea8
commit a4e1abf6df
20 changed files with 343 additions and 126 deletions
@@ -28,13 +28,12 @@ logger = logging.getLogger(__name__)
class ImportResourcesController(QObject):
add_import_resources = Signal(list)
add_import_resources_sender: Signal = Signal(list)
set_notification_frame_text_sender: Signal = Signal(str)
"""
ImportResourcesController is the place to bind ImportResource view with its
corresponding behavior
TODO: add error handling once it is ready
"""
def __init__(self) -> None:
@@ -44,6 +43,8 @@ class ImportResourcesController(QObject):
self._view_manager: ViewManager = ViewManager.get_instance()
# Initialize view and model related references
self._import_resources_page: ImportResourcesPage = self._view_manager.get_import_resources_page()
self.set_notification_frame_text_sender.connect(
self._import_resources_page.notification_frame.set_frame_text_receiver)
self._tree_view: ResourceTreeView = self._import_resources_page.tree_view
self._proxy_model: ResourceProxyModel = self._tree_view.resource_proxy_model
@@ -60,11 +61,10 @@ class ImportResourcesController(QObject):
self._proxy_model.deduplicate_selected_import_resources(self._tree_view.selectedIndexes())
if unique_resources:
logger.debug(f"Importing selected resources: {unique_resources} ...")
self.add_import_resources.emit(unique_resources)
self.add_import_resources_sender.emit(unique_resources)
self._back_to_view_edit_page()
else:
self._import_resources_page.set_notification_frame_text(
error_messages.IMPORT_RESOURCES_PAGE_NO_RESOURCES_SELECTED_ERROR_MESSAGE)
self.set_notification_frame_text_sender.emit(error_messages.IMPORT_RESOURCES_PAGE_NO_RESOURCES_SELECTED_ERROR_MESSAGE)
def _start_search_resources_async(self) -> None:
configuration: Configuration = self._configuration_manager.configuration
@@ -77,8 +77,7 @@ class ImportResourcesController(QObject):
async_worker = FunctionWorker(self._request_cfn_resources_callback, configuration.region)
async_worker.signals.result.connect(self._load_cfn_resources_callback)
else:
self._import_resources_page.set_notification_frame_text(
error_messages.IMPORT_RESOURCES_PAGE_SEARCH_VERSION_ERROR_MESSAGE)
self.set_notification_frame_text_sender.emit(error_messages.IMPORT_RESOURCES_PAGE_SEARCH_VERSION_ERROR_MESSAGE)
return
self._tree_view.reset_view()
@@ -100,7 +99,7 @@ class ImportResourcesController(QObject):
resources[stack_name] = resource_type_and_names
return resources
except RuntimeError as e:
self._import_resources_page.set_notification_frame_text(str(e))
self.set_notification_frame_text_sender.emit(str(e))
def _request_typed_resources_callback(self, region: str) -> List[str]:
resource_type_index: int = self._import_resources_page.typed_resources_combobox.currentIndex()
@@ -115,12 +114,11 @@ class ImportResourcesController(QObject):
elif resource_type_index == constants.AWS_RESOURCE_S3_BUCKET_INDEX:
resources = aws_utils.list_s3_buckets(region)
else:
self._import_resources_page.set_notification_frame_text(
error_messages.IMPORT_RESOURCES_PAGE_RESOURCE_TYPE_ERROR_MESSAGE)
self.set_notification_frame_text_sender.emit(error_messages.IMPORT_RESOURCES_PAGE_RESOURCE_TYPE_ERROR_MESSAGE)
return resources
except RuntimeError as e:
self._import_resources_page.set_notification_frame_text(str(e))
self.set_notification_frame_text_sender.emit(str(e))
def _load_cfn_resources_callback(self, resources: Dict[str, List[BasicResourceAttributes]]) -> None:
if not resources:
@@ -179,7 +177,7 @@ class ImportResourcesController(QObject):
def reset_page(self):
"""Reset import resources page to its default state"""
self._tree_view.reset_view()
self._import_resources_page.hide_notification_frame()
self._import_resources_page.notification_frame.setVisible(False)
self._import_resources_page.set_current_main_view_index(ImportResourcesPageConstants.TREE_VIEW_PAGE_INDEX)
self._import_resources_page.typed_resources_combobox.setCurrentIndex(-1)
self._import_resources_page.search_version = None
@@ -10,7 +10,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import logging
from PySide2.QtCore import (QCoreApplication, QModelIndex, QObject, Slot)
from PySide2.QtCore import (QCoreApplication, QModelIndex, QObject, Signal, Slot)
from PySide2.QtWidgets import QFileDialog
from typing import (Dict, List)
@@ -32,6 +32,9 @@ logger = logging.getLogger(__name__)
class ViewEditController(QObject):
set_notification_frame_text_sender: Signal = Signal(str)
set_notification_page_frame_text_sender: Signal = Signal(str)
"""
ViewEditController is the place to bind ViewEdit view with its
corresponding behavior
@@ -45,6 +48,10 @@ class ViewEditController(QObject):
self._view_manager: ViewManager = ViewManager.get_instance()
# Initialize view and model related references
self._view_edit_page: ViewEditPage = self._view_manager.get_view_edit_page()
self.set_notification_frame_text_sender.connect(
self._view_edit_page.notification_frame.set_frame_text_receiver)
self.set_notification_page_frame_text_sender.connect(
self._view_edit_page.notification_page_frame.set_frame_text_receiver)
self._table_view: ResourceTableView = self._view_edit_page.table_view
self._proxy_model: ResourceProxyModel = self._table_view.resource_proxy_model
@@ -78,7 +85,7 @@ class ViewEditController(QObject):
return True
except IOError as e:
logger.exception(e)
self._view_edit_page.set_notification_frame_text(str(e))
self.set_notification_frame_text_sender.emit(str(e))
return False
def _convert_and_load_into_model(self, config_file_name: str) -> None:
@@ -92,7 +99,7 @@ class ViewEditController(QObject):
resources = json_utils.convert_json_dict_to_resources(self._config_file_json_source)
except (IOError, ValueError, KeyError) as e:
logger.exception(e)
self._view_edit_page.set_notification_frame_text(str(e))
self.set_notification_frame_text_sender.emit(str(e))
self._view_edit_page.set_table_view_page_interactions_enabled(False)
# load resources into model
@@ -109,7 +116,7 @@ class ViewEditController(QObject):
new_config_file_path, configuration.account_id, configuration.region)
except IOError as e:
logger.exception(e)
self._view_edit_page.set_notification_frame_text(str(e))
self.set_notification_frame_text_sender.emit(str(e))
return
self._rescan_config_directory()
@@ -145,7 +152,7 @@ class ViewEditController(QObject):
self._start_search_config_files_async(new_config_directory)
except RuntimeError as e:
logger.exception(e)
self._view_edit_page.set_notification_frame_text(str(e))
self.set_notification_frame_text_sender.emit(str(e))
def _rescan_config_directory(self) -> None:
configuration: Configuration = self._configuration_manager.configuration
@@ -155,14 +162,14 @@ class ViewEditController(QObject):
configuration.config_directory, constants.RESOURCE_MAPPING_CONFIG_FILE_NAME_SUFFIX)
except FileNotFoundError as e:
logger.exception(e)
self._view_edit_page.set_notification_frame_text(str(e))
self.set_notification_frame_text_sender.emit(str(e))
return
self._configuration_manager.configuration.config_files = config_files
self._view_edit_page.set_config_files(config_files)
def _reset_page(self) -> None:
self._view_edit_page.hide_notification_frame()
self._view_edit_page.notification_frame.setVisible(False)
self._view_edit_page.set_table_view_page_interactions_enabled(True)
def _save_changes(self) -> None:
@@ -178,14 +185,14 @@ class ViewEditController(QObject):
self._proxy_model.override_all_resources_status(
ResourceMappingAttributesStatus(ResourceMappingAttributesStatus.SUCCESS_STATUS_VALUE,
[ResourceMappingAttributesStatus.SUCCESS_STATUS_VALUE]))
self._view_edit_page.set_notification_frame_text(
self.set_notification_frame_text_sender.emit(
notification_label_text.VIEW_EDIT_PAGE_SAVING_SUCCEED_MESSAGE.format(config_file))
def _search_complete_callback(self) -> None:
self._reset_page()
def _start_search_config_files_async(self, config_directory: str) -> None:
self._view_edit_page.set_notification_page_text(notification_label_text.NOTIFICATION_LOADING_MESSAGE)
self.set_notification_page_frame_text_sender.emit(notification_label_text.NOTIFICATION_LOADING_MESSAGE)
self._view_edit_page.set_current_main_view_index(ViewEditPageConstants.NOTIFICATION_PAGE_INDEX)
self._config_file_json_source.clear()
self._table_view.reset_view()
@@ -202,7 +209,7 @@ class ViewEditController(QObject):
config_directory, constants.RESOURCE_MAPPING_CONFIG_FILE_NAME_SUFFIX)
except FileNotFoundError as e:
logger.exception(e)
self._view_edit_page.set_notification_frame_text(str(e))
self.set_notification_frame_text_sender.emit(str(e))
def _select_config_file(self) -> None:
if self._view_edit_page.config_file_combobox.currentIndex() == -1:
@@ -219,7 +226,7 @@ class ViewEditController(QObject):
self._proxy_model.emit_source_model_layout_changed()
else:
self._view_edit_page.set_table_view_page_interactions_enabled(False)
self._view_edit_page.set_notification_frame_text(
self.set_notification_frame_text_sender.emit(
error_messages.VIEW_EDIT_PAGE_READ_FROM_JSON_FAILED_WITH_UNEXPECTED_FILE_ERROR_MESSAGE.format(config_file_name))
self._view_edit_page.set_current_main_view_index(ViewEditPageConstants.TABLE_VIEW_PAGE_INDEX)
@@ -262,13 +269,13 @@ class ViewEditController(QObject):
invalid_details))
invalid_proxy_rows: List[int] = self._proxy_model.map_from_source_rows(list(invalid_sources.keys()))
self._view_edit_page.set_notification_frame_text(
self.set_notification_frame_text_sender.emit(
error_messages.VIEW_EDIT_PAGE_SAVING_FAILED_WITH_INVALID_ROW_ERROR_MESSAGE.format(invalid_proxy_rows))
return False
return True
@Slot(list)
def add_import_resources(self, resources: List[BasicResourceAttributes]) -> None:
def add_import_resources_receiver(self, resources: List[BasicResourceAttributes]) -> None:
resource: BasicResourceAttributes
for resource in resources:
resource_builder: ResourceMappingAttributesBuilder = ResourceMappingAttributesBuilder() \