def setUp(self): set_debug_log_level() self.db_folder = (pathlib.Path(__file__).parent / "data" / "few_basic_cards") self.version2db = { 0: load_db(self.db_folder / "collection.anki2"), 1: load_db(self.db_folder / "collection_v1.anki2"), }
def setUp(self): set_debug_log_level() self.db_read = load_db(self.db_read_path) self.db_write_dir = tempfile.TemporaryDirectory() self.db_write_path = (pathlib.Path(self.db_write_dir.name) / "collection.anki2") self._reset()
def __init__(self, path=None, user=None): """ Initialize :class:`~ankipandas.collection.Collection` object. Args: path: (Search) path to database see :py:func:`~ankipandas.paths.db_path_input` for more information. user: Anki user name. See :py:func:`~ankipandas.paths.db_path_input` for more information. Examples: .. code-block:: python from ankipandas import Collection # Let ankipandas find the db for you col = Collection() # Let ankipandas find the db for this user (important if you have # more than one user account in Anki) col = Collection(user="******") # Specify full path to Anki's database col = Collection("/full/path/to/collection.anki2") # Speficy partial path to Anki's database and specify user col = Collection("/partial/path/to/collection", user="******") """ path = ankipandas.paths.db_path_input(path, user=user) #: Path to currently loaded database self.path = path # type: Path log.info("Loaded db from {}".format(self.path)) #: Opened Anki database (:class:`sqlite3.Connection`) self.db = raw.load_db(self.path) # type: sqlite3.Connection #: Should be accessed with _get_item! self.__items = { "notes": None, "cards": None, "revs": None, } # type: Dict[str, AnkiDataFrame] #: Should be accessed with _get_original_item! self.__original_items = { "notes": None, "cards": None, "revs": None, } # type: Dict[str, AnkiDataFrame]
def setUp(self): set_debug_log_level() self.db = raw.load_db(self.db_path) self.col = Collection(self.db_path) # Do not modify this one! self.notes = self.col.notes self.cards = self.col.cards self.revs = self.col.revs self.table2adf = { "notes": self.notes, "cards": self.cards, "revs": self.revs, } self.adfs = [self.notes, self.cards, self.revs] self.empty_notes = self.col.empty_notes() self.empty_cards = self.col.empty_cards() self.empty_revs = self.col.empty_revs()
def setUp(self): self.db_path = (pathlib.Path(__file__).parent / "data" / "few_basic_cards" / "collection.anki2") self.db = raw.load_db(self.db_path) self.col = Collection(self.db_path) # Do not modify this one! self.notes = self.col.notes self.cards = self.col.cards self.revs = self.col.revs self.table2adf = { "notes": self.notes, "cards": self.cards, "revs": self.revs, } self.adfs = [self.notes, self.cards, self.revs] self.empty_notes = self.col.empty_notes() self.empty_cards = self.col.empty_cards() self.empty_revs = self.col.empty_revs()
def db(self) -> sqlite3.Connection: """Opened Anki database. Make sure to call `db.close()` after you're done. Better still, use `contextlib.closing`. """ log.debug(f"Opening Db from {self._path}") return raw.load_db(self._path)
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.") 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("Backup created at %s", 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("Now setting table %s.", table) with closing(self.db) as db: raw.set_table(db, values["raw"], table=table, mode=values["mode"]) log.debug("Setting table %s successful.", table) # 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 %s. " "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 %s 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!", self.path.resolve(), backup_path.resolve(), ) raise e # This is important, because we have written to the database but still # have it opened, which can cause DatabaseErrors. log.debug("I will now drop all copies of the tables") for key in self.__items: self.__items[key] = None for key in self.__original_items: self.__original_items[key] = None log.debug("I will now reload the connection.") self._db = raw.load_db(self.path) log.info( "In case you're running this from a Jupyter notebook, make " "sure to shutdown the kernel or delete all ankipandas objects" " before you open anki to take a look at the result (only one " "application can use the database at a time).")
def _reset(self): shutil.copy(str(self.db_read_path), str(self.db_write_path)) self.db_write = load_db(self.db_write_path)