Ejemplo n.º 1
0
    def test_update(self):
        notes2 = get_table(self.db_read, "notes")
        notes = get_table(self.db_read, "notes")
        for mode in ["update", "replace", "append"]:
            with self.subTest(mode=mode):
                self._reset()
                notes2.loc[notes2["id"] == 1555579337683,
                           "tags"] = "definitelynew!"
                set_table(self.db_write, notes2, "notes", mode)
                if mode == "append":
                    self._check_db_equal()
                else:
                    notes2r = get_table(self.db_write, "notes")
                    chtag = notes2r.loc[notes2r["id"] == 1555579337683, "tags"]
                    self.assertListEqual(list(chtag.values.tolist()),
                                         ["definitelynew!"])
                    unchanged = notes.loc[notes["id"] != 1555579337683, :]
                    unchanged2 = notes2r.loc[notes2["id"] != 1555579337683, :]

                    self.assertListEqual(
                        list(unchanged.values.tolist()),
                        list(unchanged2.values.tolist()),
                    )
Ejemplo n.º 2
0
 def test_rw_identical(self):
     notes = get_table(self.db_read, "notes")
     cards = get_table(self.db_read, "cards")
     revlog = get_table(self.db_read, "revs")
     for mode in ["update", "replace", "append"]:
         with self.subTest(mode=mode):
             self._reset()
             set_table(self.db_write, notes, "notes", mode)
             set_table(self.db_write, cards, "cards", mode)
             set_table(self.db_write, revlog, "revs", mode)
             self._check_db_equal()
Ejemplo n.º 3
0
 def test_update_append_does_not_delete(self):
     notes = get_table(self.db_read, "notes")
     cards = get_table(self.db_read, "cards")
     revs = get_table(self.db_read, "revs")
     notes.drop(notes.index)
     cards.drop(cards.index)
     revs.drop(revs.index)
     for mode in ["update", "append"]:
         with self.subTest(mode=mode):
             self._reset()
             set_table(self.db_write, notes, "notes", mode)
             set_table(self.db_write, cards, "cards", mode)
             set_table(self.db_write, revs, "revs", mode)
             self._check_db_equal()
Ejemplo n.º 4
0
 def test_replace_deletes(self):
     notes = get_table(self.db_read, "notes")
     cards = get_table(self.db_read, "cards")
     revs = get_table(self.db_read, "revs")
     notes = notes.drop(notes.index)
     cards = cards.drop(cards.index)
     revs = revs.drop(revs.index)
     self._reset()
     set_table(self.db_write, notes, "notes", "replace")
     set_table(self.db_write, cards, "cards", "replace")
     set_table(self.db_write, revs, "revs", "replace")
     notes = get_table(self.db_write, "notes")
     cards = get_table(self.db_write, "cards")
     revs = get_table(self.db_write, "revs")
     self.assertEqual(len(notes), 0)
     self.assertEqual(len(revs), 0)
     self.assertEqual(len(cards), 0)
Ejemplo n.º 5
0
    def write(
        self,
        modify=False,
        add=False,
        delete=False,
        backup_folder: Union[PurePath, str] = None,
    ):
        """ Creates a backup of the database and then writes back the new
        data.

        .. danger::

            The switches ``modify``, ``add`` and ``delete`` will run additional
            cross-checks, but do not rely on them to 100%!

        .. warning::

            It is recommended to run :meth:`summarize_changes` before to check
            whether the changes match your expectation.

        .. note::

            Please make sure to thoroughly check your collection in Anki after
            every write process!

        Args:
            modify: Allow modification of existing items (notes, cards, etc.)
            add: Allow adding of new items (notes, cards, etc.)
            delete: Allow deletion of items (notes, cards, etc.)
            backup_folder: Path to backup folder. If None is given, the backup
                is created in the Anki backup directory (if found).

        Returns:
            None
        """
        if not modify and not add and not delete:
            log.warning(
                "Please set modify=True, add=True or delete=True, you're"
                " literally not allowing me any modification at all."
            )
            return None

        try:
            prepared = self._prepare_write_data(
                modify=modify, add=add, delete=delete
            )

            info = self._get_and_update_info()
        except Exception as e:
            log.critical(
                "Something went wrong preparing the data for writing. "
                "However, no data has been written out, so your"
                "database is save!"
            )
            raise e
        else:
            log.debug("Successfully prepared data for writing.")

        backup_path = ankipandas.paths.backup_db(
            self.path, backup_folder=backup_folder
        )
        log.info("Backup created at {}.".format(backup_path.resolve()))

        # Actually setting values here, after all conversion tasks have been
        # carried out. That way if any of them fails, we don't have a
        # partially written collection.
        log.debug("Now actually writing to database.")
        try:
            for table, values in prepared.items():
                raw.set_table(
                    self.db, values["raw"], table=table, mode=values["mode"]
                )
            # Actually only needed if we actually modify the info.
            # This will trigger a complete re-upload, so we want to avoid this
            # if possible.
            # raw.set_info(self.db, info)
        except Exception as e:
            log.critical(
                "Error while writing data to database at {path}"
                "This means that your database might have become corrupted. "
                "It's STRONGLY adviced that you manually restore the database "
                "by replacing it with the backup from {backup_path} and restart"
                " from scratch. "
                "Please also open a bug report at "
                "https://github.com/klieret/AnkiPandas/issues/, as errors "
                "during the actual writing process should never occurr!".format(
                    path=self.path.resolve(), backup_path=backup_path.resolve()
                )
            )
            raise e
Ejemplo n.º 6
0
    def write(
        self,
        modify=False,
        add=False,
        delete=False,
        backup_folder: Union[PurePath, str] = None,
    ):
        """ Creates a backup of the database and then writes back the new
        data.

        .. danger::

            The switches ``modify``, ``add`` and ``delete`` will run additional
            cross-checks, but do not rely on them to 100%!

        .. warning::

            It is recommended to run :meth:`summarize_changes` before to check
            whether the changes match your expectation.

        .. note::

            Please make sure to thoroughly check your collection in Anki after
            every write process!

        Args:
            modify: Allow modification of existing items (notes, cards, etc.)
            add: Allow adding of new items (notes, cards, etc.)
            delete: Allow deletion of items (notes, cards, etc.)
            backup_folder: Path to backup folder. If None is given, the backup
                is created in the Anki backup directory (if found).

        Returns:
            None
        """
        if not modify and not add and not delete:
            log.warning(
                "Please set modify=True, add=True or delete=True, you're"
                " literally not allowing me any modification at all.")
            return None

        try:
            prepared = self._prepare_write_data(modify=modify,
                                                add=add,
                                                delete=delete)
            log.debug("Now getting & updating info.")
            info = self._get_and_update_info()
        except Exception as e:
            log.critical(
                "Something went wrong preparing the data for writing. "
                "However, no data has been written out, so your "
                "database is save!")
            raise e
        else:
            log.debug("Successfully prepared data for writing.")

        if prepared == {}:
            log.warning(
                "Nothing seems to have been changed. Will not do anything!")
            return None

        backup_path = ankipandas.paths.backup_db(self.path,
                                                 backup_folder=backup_folder)
        log.info(f"Backup created at {backup_path.resolve()}.")
        log.warning(
            "Currently AnkiPandas might not be able to tell Anki to"
            " sync its database. "
            "You might have to manually tell Anki to sync everything "
            "to AnkiDroid.\n"
            "Furthermore, if you run into issues with tag searches not working"
            "anymore, please first do Notes > Clear unused notes and then "
            "Tools > Check Database (from the main menu). This should get them"
            " to work (sorry about this issue).")

        # Actually setting values here, after all conversion tasks have been
        # carried out. That way if any of them fails, we don't have a
        # partially written collection.
        log.debug("Now actually writing to database.")
        try:
            for table, values in prepared.items():
                log.debug(f"Now setting table {table}.")
                raw.set_table(self.db,
                              values["raw"],
                              table=table,
                              mode=values["mode"])
                log.debug(f"Setting table {table} successful.")
            # log.debug("Now setting info")
            # raw.set_info(self.db, info)
            # log.debug("Setting info successful.")
        except Exception as e:
            log.critical(
                "Error while writing data to database at {path}"
                "This means that your database might have become corrupted. "
                "It's STRONGLY advised that you manually restore the database "
                "by replacing it with the backup from {backup_path} and restart"
                " from scratch. "
                "Please also open a bug report at "
                "https://github.com/klieret/AnkiPandas/issues/, as errors "
                "during the actual writing process should never occur!".format(
                    path=self.path.resolve(),
                    backup_path=backup_path.resolve()))
            raise e