Anki/pylib/anki/importing/apkg.py
Abdo f94d05bcbe
Switch to Ruff (#4119)
* Add check:ruff build action

* Add fix:ruff action

* Add Ruff config

Mostly generated by Cursor

* Handle rest of lints

* Fix formatting

* Replace black and isort with ruff-format

* Run ruff-format

* Fix lint errors

* Remove pylint disables

* Remove .pylintrc

* Update docs

* Fix check:format not just checking

* Fix isort rule being ignored

* Sort imports

* Ensure ./ninja format also handles import sorting

* Remove unused isort cfg

* Enable unsafe fixes in fix:ruff, and enable unused var warning

* Re-run on config change; enable unnecessary ARG ignores

* Use all pycodestyle errors, and add some more commented-out ones

Latter logged on https://github.com/ankitects/anki/issues/4135
2025-06-29 14:38:35 +07:00

66 lines
2.2 KiB
Python

# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from __future__ import annotations
import json
import os
import unicodedata
import zipfile
from typing import Any
from anki.importing.anki2 import Anki2Importer, MediaMapInvalid
from anki.utils import tmpfile
class AnkiPackageImporter(Anki2Importer):
nameToNum: dict[str, str]
zip: zipfile.ZipFile | None
def run(self) -> None: # type: ignore
# extract the deck from the zip file
self.zip = z = zipfile.ZipFile(self.file)
# v2 scheduler?
try:
z.getinfo("collection.anki21")
suffix = ".anki21"
except KeyError:
suffix = ".anki2"
col = z.read(f"collection{suffix}")
colpath = tmpfile(suffix=".anki2")
with open(colpath, "wb") as f:
f.write(col)
self.file = colpath
# we need the media dict in advance, and we'll need a map of fname ->
# number to use during the import
self.nameToNum = {}
dir = self.col.media.dir()
try:
media_dict = json.loads(z.read("media").decode("utf8"))
except Exception as exc:
raise MediaMapInvalid() from exc
for k, v in list(media_dict.items()):
path = os.path.abspath(os.path.join(dir, v))
if os.path.commonprefix([path, dir]) != dir:
raise Exception("Invalid file")
self.nameToNum[unicodedata.normalize("NFC", v)] = k
# run anki2 importer
Anki2Importer.run(self, importing_v2=suffix == ".anki21")
# import static media
for file, c in list(self.nameToNum.items()):
if not file.startswith("_") and not file.startswith("latex-"):
continue
path = os.path.join(self.col.media.dir(), file)
if not os.path.exists(path):
with open(path, "wb") as f:
f.write(z.read(c))
def _srcMediaData(self, fname: str) -> Any:
if fname in self.nameToNum:
return self.zip.read(
self.nameToNum[fname]
) # pytype: disable=attribute-error
return None