Exemplo n.º 1
0
 def __establish_profile(
     self, profile_path: pathlib.Path
 ) -> typing.Tuple[typing.Optional[Profile.Profile], bool]:
     assert profile_path.is_absolute(
     )  # prevents tests from creating temporary files in test directory
     create_new_profile = not profile_path.exists()
     if create_new_profile:
         logging.getLogger("loader").info(
             f"Creating new profile {profile_path}")
         profile_json = json.dumps({
             "version": FileStorageSystem.PROFILE_VERSION,
             "uuid": str(uuid.uuid4())
         })
         profile_path.write_text(profile_json, "utf-8")
     else:
         logging.getLogger("loader").info(
             f"Using existing profile {profile_path}")
     storage_system = FileStorageSystem.FilePersistentStorageSystem(
         profile_path)
     storage_system.load_properties()
     cache_path = profile_path.parent / pathlib.Path(
         profile_path.stem + " Cache").with_suffix(".nscache")
     logging.getLogger("loader").info(f"Using cache {cache_path}")
     storage_cache = Cache.DbStorageCache(cache_path)
     profile = Profile.Profile(storage_system=storage_system,
                               storage_cache=storage_cache)
     profile.read_profile()
     return profile, create_new_profile
Exemplo n.º 2
0
 def __init__(self, file_path):
     file_path = pathlib.Path(file_path)
     if file_path.suffix == ".nsproj":
         r = Profile.IndexProjectReference()
         r.project_path = file_path
     else:
         r = Profile.FolderProjectReference()
         r.project_folder_path = file_path
     r.persistent_object_context = Persistence.PersistentObjectContext()
     r.load_project(None)
     #r.project._raw_properties["version"] = 3
     r.project.read_project()
     r.project.read_project()
     self.project = r.project
     self._data_items_properties = [
         di.properties for di in self.project.data_items
     ]
Exemplo n.º 3
0
    def start(self, skip_choose=False, fixed_workspace_dir=None):
        """
            Start the application.

            Looks for workspace_location persistent string. If it doesn't find it, uses a default
            workspace location.

            Then checks to see if that workspace exists. If not and if skip_choose has not been
            set to True, asks the user for a workspace location. User may choose new folder or
            existing location. This works by putting up the dialog which will either call start
            again or exit.

            Creates workspace in location if it doesn't exist.

            Migrates database to latest version.

            Creates document model, resources path, etc.
        """
        logging.getLogger("migration").setLevel(logging.INFO)
        if fixed_workspace_dir:
            workspace_dir = fixed_workspace_dir
        else:
            documents_dir = self.ui.get_document_location()
            workspace_dir = os.path.join(documents_dir, "Nion Swift Libraries")
            workspace_dir = self.ui.get_persistent_string("workspace_location", workspace_dir)
        welcome_message_enabled = fixed_workspace_dir is None
        profile, is_created = Profile.create_profile(pathlib.Path(workspace_dir), welcome_message_enabled, skip_choose)
        if not profile:
            self.choose_library()
            return True
        self.workspace_dir = workspace_dir
        DocumentModel.DocumentModel.computation_min_period = 0.2
        DocumentModel.DocumentModel.computation_min_factor = 1.0
        document_model = DocumentModel.DocumentModel(profile=profile)
        document_model.create_default_data_groups()
        document_model.start_dispatcher()
        # parse the hardware aliases file
        alias_path = os.path.join(self.workspace_dir, "aliases.ini")
        HardwareSource.parse_hardware_aliases_config_file(alias_path)
        # create the document controller
        document_controller = self.create_document_controller(document_model, "library")
        if self.__resources_path is not None:
            document_model.create_sample_images(self.__resources_path)
        workspace_history = self.ui.get_persistent_object("workspace_history", list())
        if workspace_dir in workspace_history:
            workspace_history.remove(workspace_dir)
        workspace_history.insert(0, workspace_dir)
        self.ui.set_persistent_object("workspace_history", workspace_history)
        self.ui.set_persistent_string("workspace_location", workspace_dir)
        if welcome_message_enabled:
            logging.info("Welcome to Nion Swift.")
        if is_created and len(document_model.display_items) > 0:
            document_controller.selected_display_panel.set_display_panel_display_item(document_model.display_items[0])
            document_controller.selected_display_panel.perform_action("set_fill_mode")
        return True
Exemplo n.º 4
0
 def add_clicked() -> None:
     assert self.__profile
     add_dir = self.ui.get_persistent_string("import_directory", "")
     file_paths, filter_str, directory = self.get_file_paths_dialog(_("Add Scripts"), add_dir, "Python Files (*.py)", "Python Files (*.py)")
     self.ui.set_persistent_string("import_directory", directory)
     items = list(self.scripts_list_widget.items)
     for file_path_str in file_paths:
         script_item = Profile.FileScriptItem(pathlib.Path(file_path_str))
         self.__profile.append_script_item(script_item)
         script_list_item = ScriptListItem(file_path_str)
         script_list_item.script_item = script_item
         items.append(script_list_item)
     self.update_scripts_list(items)
Exemplo n.º 5
0
def get_storage_system(workspace_dir):
    # This function is adapted from Swift's profile
    workspace_dir = pathlib.Path(workspace_dir)
    library_path = Profile._migrate_library(workspace_dir, do_logging=True)
    this_storage_version = DataItem.DataItem.storage_version
    auto_migrations = list()
    auto_migrations.append(
        Profile.AutoMigration(
            pathlib.Path(workspace_dir) / "Nion Swift Workspace.nslib",
            [pathlib.Path(workspace_dir) / "Nion Swift Data"]))
    auto_migrations.append(
        Profile.AutoMigration(
            pathlib.Path(workspace_dir) / "Nion Swift Workspace.nslib",
            [pathlib.Path(workspace_dir) / "Nion Swift Data 10"]))
    auto_migrations.append(
        Profile.AutoMigration(
            pathlib.Path(workspace_dir) / "Nion Swift Workspace.nslib",
            [pathlib.Path(workspace_dir) / "Nion Swift Data 11"]))
    # Attemp at being future proof
    if this_storage_version > 12:
        for storage_version in range(12, this_storage_version):
            auto_migrations.append(
                Profile.AutoMigration(
                    pathlib.Path(workspace_dir) /
                    f"Nion Swift Library {storage_version}.nslib", [
                        pathlib.Path(workspace_dir) /
                        f"Nion Swift Data {storage_version}"
                    ]))

    # NOTE: when adding an AutoMigration here, also add the corresponding file
    # copy in _migrate_library
    storage_system = FileStorageSystem.FileStorageSystem(
        library_path, [
            pathlib.Path(workspace_dir) /
            f"Nion Swift Data {this_storage_version}"
        ],
        auto_migrations=auto_migrations)
    return storage_system
Exemplo n.º 6
0
 def create_profile(self, add_project: bool = True) -> Profile.Profile:
     if not self.__profile:
         library_properties = {"version": FileStorageSystem.PROFILE_VERSION}
         storage_system = self.__storage_system
         storage_system.set_library_properties(library_properties)
         profile = Profile.Profile(storage_system=storage_system,
                                   storage_cache=self.storage_cache)
         profile.storage_system = storage_system
         profile.profile_context = self
         if add_project:
             add_project_memory(profile, self.project_uuid)
         self.__profile = profile
         self.__items_exit.append(profile.close)
         return profile
     else:
         storage_system = self.__storage_system
         storage_system.load_properties()
         profile = Profile.Profile(storage_system=storage_system,
                                   storage_cache=self.storage_cache)
         profile.storage_system = storage_system
         profile.profile_context = self
         self.__items_exit.append(profile.close)
         return profile
Exemplo n.º 7
0
 def test_adding_same_project_raises_error_during_append(self):
     # create two data items in different projects. select the two items in the data panel
     # and create a computation from the two inputs. compute and make sure no errors occur.
     with create_memory_profile_context() as profile_context:
         profile = profile_context.create_profile()
         profile.add_project_memory()
         document_model = DocumentModel.DocumentModel(profile=profile)
         document_controller = DocumentController.DocumentController(
             self.app.ui, document_model, workspace_id="library")
         with contextlib.closing(document_controller):
             project_reference = Profile.MemoryProjectReference()
             project_reference.project_uuid = document_model.profile.projects[
                 0].uuid
             with self.assertRaises(Exception):
                 document_model.profile.append_project_reference(
                     project_reference)
Exemplo n.º 8
0
 def add_folder_clicked() -> None:
     assert self.__profile
     add_dir = self.ui.get_persistent_string("import_directory", "")
     existing_directory, directory = self.ui.get_existing_directory_dialog(_("Add Scripts Folder"), add_dir)
     if existing_directory:
         folder_list_item = FolderListItem(existing_directory)
         folder_list_item.update_content_from_file_system(filter_pattern=self.script_filter_pattern)
         full_path = folder_list_item.full_path
         if full_path not in sys.path:
             sys.path.append(full_path)
             self.__new_path_entries.append(full_path)
         items = list(self.scripts_list_widget.items)
         script_item = Profile.FolderScriptItem(pathlib.Path(existing_directory))
         self.__profile.append_script_item(script_item)
         folder_list_item.script_item = script_item
         items.append(folder_list_item)
         self.update_scripts_list(items)
     else:
         self.rebuild_scripts_list()
Exemplo n.º 9
0
def create_memory_profile_context():
    return Profile.MemoryProfileContext()
Exemplo n.º 10
0
    def start(self,
              *,
              profile_dir: pathlib.Path = None,
              profile: Profile.Profile = None) -> bool:
        """Start the application.

        Creates the profile object using profile_path parameter (for testing), the profile path constructed from the
        name stored in preferences, or a default profile path.

        Attaches recent projects if profile is freshly created. The recent projects will initially be disabled and
        will require the user to explicitly upgrade them.

        Creates the document model with the profile.

        Creates the document window (aka document controller) with the document model.
        """
        logging.getLogger("migration").setLevel(logging.INFO)
        logging.getLogger("loader").setLevel(logging.INFO)

        # create or load the profile object. allow test to override profile.
        is_created = False
        if not profile:
            # determine the profile_path
            if profile_dir:
                profile_path = profile_dir / pathlib.Path(
                    "Profile").with_suffix(".nsproj")
            else:
                data_dir = pathlib.Path(self.ui.get_data_location())
                profile_name = pathlib.Path(
                    self.ui.get_persistent_string("profile_name", "Profile"))
                profile_path = data_dir / profile_name.with_suffix(".nsproj")
            # create the profile
            profile, is_created = self.__establish_profile(profile_path)
        self.__profile = profile

        # test code to reset script items
        # self.__profile.script_items_updated = False
        # while self.__profile.script_items:
        #     self.__profile.remove_script_item(self.__profile.script_items[-1])

        # migrate the interactive scripts persistent object
        if not self.__profile.script_items_updated:
            items_str = self.ui.get_persistent_string("interactive_scripts_1")
            if items_str:
                for item_dict in json.loads(items_str):
                    item_type = item_dict.get("__type__", None)
                    if item_type == "FolderListItem":
                        folder_path_str = item_dict.get("full_path", None)
                        folder_path = pathlib.Path(
                            folder_path_str) if folder_path_str else None
                        if folder_path:
                            profile.append_script_item(
                                Profile.FolderScriptItem(
                                    pathlib.Path(folder_path)))
                    elif item_type == "ScriptListItem" and item_dict.get(
                            "indent_level", None) == 0:
                        script_path_str = item_dict.get("full_path", None)
                        script_path = pathlib.Path(
                            script_path_str) if script_path_str else None
                        if script_path:
                            profile.append_script_item(
                                Profile.FileScriptItem(
                                    pathlib.Path(script_path)))
            else:
                items_old = self.ui.get_persistent_object(
                    "interactive_scripts_0", list())
                for script_path_str in items_old:
                    script_path = pathlib.Path(
                        script_path_str) if script_path_str else None
                    if script_path:
                        profile.append_script_item(
                            Profile.FileScriptItem(pathlib.Path(script_path)))
            self.__profile.script_items_updated = True

        # configure the document model object.
        DocumentModel.DocumentModel.computation_min_period = 0.1
        DocumentModel.DocumentModel.computation_min_factor = 1.0

        # if it was created, it probably means it is migrating from an old version. so add all recent projects.
        # they will initially be disabled and the user will have to explicitly upgrade them.
        if is_created:
            # present a dialog for showing progress while finding existing projects
            u = Declarative.DeclarativeUI()
            task_message = u.create_label(
                text=_("Looking for existing projects..."))
            progress = u.create_progress_bar(
                value="@binding(progress_value_model.value)", width=300 - 24)
            progress_message = u.create_label(
                text="@binding(message_str_model.value)")
            main_column = u.create_column(task_message,
                                          progress,
                                          progress_message,
                                          spacing=8,
                                          width=300)
            window = u.create_window(main_column,
                                     title=_("Locating Existing Projects"),
                                     margin=12,
                                     window_style="tool")

            # handler for the progress window. defines two value models: progress, an int 0-100; and message, a string.
            class FindExistingProjectsWindowHandler(Declarative.WindowHandler):
                def __init__(self,
                             *,
                             completion_fn: typing.Optional[typing.Callable[
                                 [], None]] = None):
                    super().__init__(completion_fn=completion_fn)
                    self.progress_value_model = Model.PropertyModel(0)
                    self.message_str_model = Model.PropertyModel(str())

            # construct the window handler and run it. when the dialog closes, it will continue by
            # calling open default project.
            window_handler = FindExistingProjectsWindowHandler(
                completion_fn=functools.partial(self.__open_default_project,
                                                profile_dir, is_created))
            window_handler.run(window, app=self)

            # define an async routine that will perform the finding of the existing projects.
            # this is just a loop that yields via asyncio.sleep periodically. the loop loads
            # the projects and updates the progress and message value models in the dialog.
            # when finished, it asks the window to close on its next periodic call. it is
            # necessary to close this way because the close request may close the event loop
            # in which we're executing. so queueing the close request avoids that.
            async def find_existing_projects():
                recent_library_paths = self.get_recent_library_paths()
                for index, library_path in enumerate(recent_library_paths):
                    window_handler.progress_value_model.value = 100 * index // len(
                        recent_library_paths)
                    window_handler.message_str_model.value = str(
                        library_path.name)
                    logging.getLogger("loader").info(
                        f"Adding existing project {index + 1}/{len(recent_library_paths)} {library_path}"
                    )
                    await asyncio.sleep(0)
                    profile.add_project_folder(pathlib.Path(library_path),
                                               load=False)
                window_handler.progress_value_model.value = 100
                window_handler.message_str_model.value = _("Finished")
                await asyncio.sleep(1)
                window_handler.window.queue_request_close()

            # launch the find existing projects task asynchronously.
            window_handler.window.event_loop.create_task(
                find_existing_projects())
            return True
        else:
            # continue with opening the default project
            return self.__open_default_project(profile_dir, is_created)