genanki2 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. genanki2/__init__.py +136 -0
  2. genanki2/_default_rows.py +94 -0
  3. genanki2/_dummy_collection.anki2 +0 -0
  4. genanki2/_proto/__init__.py +94 -0
  5. genanki2/_proto/descriptors.binpb +0 -0
  6. genanki2/_schema.py +167 -0
  7. genanki2/_typed_schema.py +145 -0
  8. genanki2/_unicode_ages.py +54 -0
  9. genanki2/api.py +271 -0
  10. genanki2/builtins.py +213 -0
  11. genanki2/datetime.py +103 -0
  12. genanki2/errors.py +35 -0
  13. genanki2/freezable.py +238 -0
  14. genanki2/idgen.py +123 -0
  15. genanki2/io_utils.py +230 -0
  16. genanki2/models/__init__.py +0 -0
  17. genanki2/models/_card_maker.py +248 -0
  18. genanki2/models/annotations.py +154 -0
  19. genanki2/models/base.py +737 -0
  20. genanki2/models/card.py +995 -0
  21. genanki2/models/collection.py +2124 -0
  22. genanki2/models/collection_metadata.py +154 -0
  23. genanki2/models/config.py +131 -0
  24. genanki2/models/deck.py +679 -0
  25. genanki2/models/deck_config.py +647 -0
  26. genanki2/models/field.py +175 -0
  27. genanki2/models/grave.py +103 -0
  28. genanki2/models/media_entries.py +623 -0
  29. genanki2/models/note.py +601 -0
  30. genanki2/models/notetype.py +1080 -0
  31. genanki2/models/package.py +1337 -0
  32. genanki2/models/package_metadata.py +172 -0
  33. genanki2/models/review.py +285 -0
  34. genanki2/models/serialization_context.py +33 -0
  35. genanki2/models/tag.py +61 -0
  36. genanki2/models/template.py +371 -0
  37. genanki2/py.typed +0 -0
  38. genanki2/settings.py +159 -0
  39. genanki2/sqlite.py +299 -0
  40. genanki2/text.py +1109 -0
  41. genanki2/time.py +19 -0
  42. genanki2/utils.py +90 -0
  43. genanki2-0.1.0.dist-info/METADATA +474 -0
  44. genanki2-0.1.0.dist-info/RECORD +48 -0
  45. genanki2-0.1.0.dist-info/WHEEL +4 -0
  46. genanki2-0.1.0.dist-info/licenses/LICENSE +7 -0
  47. genanki2-0.1.0.dist-info/licenses/LICENSES/AGPL-3.0-or-later.txt +661 -0
  48. genanki2-0.1.0.dist-info/licenses/LICENSES/UNICODE-LICENSE-V3.txt +39 -0
genanki2/__init__.py ADDED
@@ -0,0 +1,136 @@
1
+ import importlib.metadata
2
+
3
+ from .api import (
4
+ deck,
5
+ deck_config,
6
+ field,
7
+ filtered_deck,
8
+ note,
9
+ notetype,
10
+ package,
11
+ template,
12
+ )
13
+ from .builtins import (
14
+ BASIC_AND_REVERSED_NOTETYPE,
15
+ BASIC_NOTETYPE,
16
+ BASIC_OPTIONAL_REVERSED_NOTETYPE,
17
+ BASIC_TYPE_IN_THE_ANSWER_NOTETYPE,
18
+ BUILTIN_NOTETYPES,
19
+ CLOZE_NOTETYPE,
20
+ DEFAULT_DECK,
21
+ DEFAULT_DECK_CONFIG,
22
+ IMAGE_OCCLUSION_NOTETYPE,
23
+ builtin_notetype,
24
+ default_collection_metadata,
25
+ default_config_entries,
26
+ default_deck,
27
+ default_deck_config,
28
+ )
29
+ from .errors import (
30
+ CollectionReadError,
31
+ Genanki2Error,
32
+ Genanki2Warning,
33
+ PackageReadError,
34
+ )
35
+ from .idgen import guid, guid_for, monotonic_id
36
+ from .models.card import Card, CardData, CardFlag, CardQueue, CardType
37
+ from .models.collection import Collection
38
+ from .models.collection_metadata import CollectionMetadata
39
+ from .models.config import ConfigEntry
40
+ from .models.deck import Deck, DeckCommon, DeckFilteredKind, DeckNormalKind
41
+ from .models.deck_config import DeckConfig, DeckConfigInner
42
+ from .models.field import Field, FieldConfig
43
+ from .models.grave import Grave, GraveType
44
+ from .models.media_entries import MediaEntries, MediaEntry
45
+ from .models.note import Note
46
+ from .models.notetype import Notetype, NotetypeConfig
47
+ from .models.package import CollectionPackage, Package
48
+ from .models.package_metadata import PackageMetadata
49
+ from .models.review import Review, ReviewRating, ReviewType
50
+ from .models.tag import Tag
51
+ from .models.template import Template, TemplateConfig
52
+ from .settings import (
53
+ checks_disabled,
54
+ checks_enabled,
55
+ dbcheck_repairs_disabled,
56
+ dbcheck_repairs_enabled,
57
+ timestamping_disabled,
58
+ timestamping_enabled,
59
+ warnings_disabled,
60
+ warnings_enabled,
61
+ )
62
+
63
+ __version__: str = importlib.metadata.version("genanki2")
64
+
65
+ __all__ = [
66
+ "BASIC_AND_REVERSED_NOTETYPE",
67
+ "BASIC_NOTETYPE",
68
+ "BASIC_OPTIONAL_REVERSED_NOTETYPE",
69
+ "BASIC_TYPE_IN_THE_ANSWER_NOTETYPE",
70
+ "BUILTIN_NOTETYPES",
71
+ "CLOZE_NOTETYPE",
72
+ "DEFAULT_DECK",
73
+ "DEFAULT_DECK_CONFIG",
74
+ "IMAGE_OCCLUSION_NOTETYPE",
75
+ "Card",
76
+ "CardData",
77
+ "CardFlag",
78
+ "CardQueue",
79
+ "CardType",
80
+ "Collection",
81
+ "CollectionMetadata",
82
+ "CollectionPackage",
83
+ "CollectionReadError",
84
+ "ConfigEntry",
85
+ "Deck",
86
+ "DeckCommon",
87
+ "DeckConfig",
88
+ "DeckConfigInner",
89
+ "DeckFilteredKind",
90
+ "DeckNormalKind",
91
+ "Field",
92
+ "FieldConfig",
93
+ "Genanki2Error",
94
+ "Genanki2Warning",
95
+ "Grave",
96
+ "GraveType",
97
+ "MediaEntries",
98
+ "MediaEntry",
99
+ "Note",
100
+ "Notetype",
101
+ "NotetypeConfig",
102
+ "Package",
103
+ "PackageMetadata",
104
+ "PackageReadError",
105
+ "Review",
106
+ "ReviewRating",
107
+ "ReviewType",
108
+ "Tag",
109
+ "Template",
110
+ "TemplateConfig",
111
+ "__version__",
112
+ "builtin_notetype",
113
+ "checks_disabled",
114
+ "checks_enabled",
115
+ "dbcheck_repairs_disabled",
116
+ "dbcheck_repairs_enabled",
117
+ "deck",
118
+ "deck_config",
119
+ "default_collection_metadata",
120
+ "default_config_entries",
121
+ "default_deck",
122
+ "default_deck_config",
123
+ "field",
124
+ "filtered_deck",
125
+ "guid",
126
+ "guid_for",
127
+ "monotonic_id",
128
+ "note",
129
+ "notetype",
130
+ "package",
131
+ "template",
132
+ "timestamping_disabled",
133
+ "timestamping_enabled",
134
+ "warnings_disabled",
135
+ "warnings_enabled",
136
+ ]
@@ -0,0 +1,94 @@
1
+ # Generated by scripts/dump_empty_collection_rows.py, do not edit.
2
+ # anki 26.08.1, collection schema version 18
3
+
4
+ # ========= TABLE col =========
5
+ table_col = [
6
+ {'id': 1, 'crt': 0, 'mod': 0, 'scm': 0, 'ver': 18, 'dty': 0, 'usn': 0, 'ls': 0, 'conf': '', 'models': '', 'decks': '', 'dconf': '', 'tags': ''},
7
+ ]
8
+
9
+ # ========= TABLE notes =========
10
+ table_notes = []
11
+
12
+ # ========= TABLE cards =========
13
+ table_cards = []
14
+
15
+ # ========= TABLE revlog =========
16
+ table_revlog = []
17
+
18
+ # ========= TABLE deck_config =========
19
+ table_deck_config = [
20
+ {'id': 1, 'name': 'Default', 'mtime_secs': 0, 'usn': 0, 'config': b'\n\x08\x00\x00\x80?\x00\x00 A\x12\x04\x00\x00 A"\x1c\x00\x00\x80?\x00\x00\x80?\x00\x00\x80?\x00\x00\x80?\x00\x00\x80?\x00\x00\x80?\x00\x00\x80?H\x14P\xc8\x01]\x00\x00 @eff\xa6?m\x9a\x99\x99?}\x00\x00\x80?\x80\x01\x94\x9d\x02\x88\x01\x01\x90\x01\x01\x98\x01\x04\xa8\x01\x01\xb0\x01\x08\xc0\x01<\xad\x02fff?\xc5\x02fff?\xe0\x02\x01'},
21
+ ]
22
+
23
+ # ========= TABLE config =========
24
+ table_config = [
25
+ {'KEY': 'activeDecks', 'usn': 0, 'mtime_secs': 0, 'val': b'[1]'},
26
+ {'KEY': 'addToCur', 'usn': 0, 'mtime_secs': 0, 'val': b'true'},
27
+ {'KEY': 'collapseTime', 'usn': 0, 'mtime_secs': 0, 'val': b'1200'},
28
+ {'KEY': 'creationOffset', 'usn': 0, 'mtime_secs': 0, 'val': b'0'},
29
+ {'KEY': 'curDeck', 'usn': 0, 'mtime_secs': 0, 'val': b'1'},
30
+ {'KEY': 'curModel', 'usn': -1, 'mtime_secs': 0, 'val': b'1'},
31
+ {'KEY': 'dayLearnFirst', 'usn': 0, 'mtime_secs': 0, 'val': b'false'},
32
+ {'KEY': 'dueCounts', 'usn': 0, 'mtime_secs': 0, 'val': b'true'},
33
+ {'KEY': 'estTimes', 'usn': 0, 'mtime_secs': 0, 'val': b'true'},
34
+ {'KEY': 'newSpread', 'usn': 0, 'mtime_secs': 0, 'val': b'0'},
35
+ {'KEY': 'nextPos', 'usn': 0, 'mtime_secs': 0, 'val': b'1'},
36
+ {'KEY': 'sched2021', 'usn': 0, 'mtime_secs': 0, 'val': b'true'},
37
+ {'KEY': 'schedVer', 'usn': 0, 'mtime_secs': 0, 'val': b'2'},
38
+ {'KEY': 'sortBackwards', 'usn': 0, 'mtime_secs': 0, 'val': b'false'},
39
+ {'KEY': 'sortType', 'usn': 0, 'mtime_secs': 0, 'val': b'"noteFld"'},
40
+ {'KEY': 'timeLim', 'usn': 0, 'mtime_secs': 0, 'val': b'0'},
41
+ ]
42
+
43
+ # ========= TABLE fields =========
44
+ table_fields = [
45
+ {'ntid': 1, 'ord': 0, 'name': 'Front', 'config': b'\x1a\x05Arial \x14'},
46
+ {'ntid': 1, 'ord': 1, 'name': 'Back', 'config': b'\x1a\x05Arial \x14'},
47
+ {'ntid': 2, 'ord': 0, 'name': 'Front', 'config': b'\x1a\x05Arial \x14'},
48
+ {'ntid': 2, 'ord': 1, 'name': 'Back', 'config': b'\x1a\x05Arial \x14'},
49
+ {'ntid': 3, 'ord': 0, 'name': 'Front', 'config': b'\x1a\x05Arial \x14'},
50
+ {'ntid': 3, 'ord': 1, 'name': 'Back', 'config': b'\x1a\x05Arial \x14'},
51
+ {'ntid': 3, 'ord': 2, 'name': 'Add Reverse', 'config': b'\x1a\x05Arial \x14'},
52
+ {'ntid': 4, 'ord': 0, 'name': 'Front', 'config': b'\x1a\x05Arial \x14'},
53
+ {'ntid': 4, 'ord': 1, 'name': 'Back', 'config': b'\x1a\x05Arial \x14'},
54
+ {'ntid': 5, 'ord': 0, 'name': 'Text', 'config': b'\x1a\x05Arial \x14P\x00X\x01'},
55
+ {'ntid': 5, 'ord': 1, 'name': 'Back Extra', 'config': b'\x1a\x05Arial \x14P\x01'},
56
+ {'ntid': 6, 'ord': 0, 'name': 'Occlusion', 'config': b'\x1a\x05Arial \x14P\x00X\x01'},
57
+ {'ntid': 6, 'ord': 1, 'name': 'Image', 'config': b'\x1a\x05Arial \x14P\x01X\x01'},
58
+ {'ntid': 6, 'ord': 2, 'name': 'Header', 'config': b'\x1a\x05Arial \x14P\x02X\x01'},
59
+ {'ntid': 6, 'ord': 3, 'name': 'Back Extra', 'config': b'\x1a\x05Arial \x14P\x03X\x01'},
60
+ {'ntid': 6, 'ord': 4, 'name': 'Comments', 'config': b'\x1a\x05Arial \x14P\x04'},
61
+ ]
62
+
63
+ # ========= TABLE templates =========
64
+ table_templates = [
65
+ {'ntid': 1, 'ord': 0, 'name': 'Card 1', 'mtime_secs': 0, 'usn': 0, 'config': b"\n\t{{Front}}\x12'{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}"},
66
+ {'ntid': 2, 'ord': 0, 'name': 'Card 1', 'mtime_secs': 0, 'usn': 0, 'config': b"\n\t{{Front}}\x12'{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}"},
67
+ {'ntid': 2, 'ord': 1, 'name': 'Card 2', 'mtime_secs': 0, 'usn': 0, 'config': b'\n\x08{{Back}}\x12({{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}'},
68
+ {'ntid': 3, 'ord': 0, 'name': 'Card 1', 'mtime_secs': 0, 'usn': 0, 'config': b"\n\t{{Front}}\x12'{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}"},
69
+ {'ntid': 3, 'ord': 1, 'name': 'Card 2', 'mtime_secs': 0, 'usn': 0, 'config': b'\n({{#Add Reverse}}{{Back}}{{/Add Reverse}}\x12({{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}'},
70
+ {'ntid': 4, 'ord': 0, 'name': 'Card 1', 'mtime_secs': 0, 'usn': 0, 'config': b'\n\x18{{Front}}\n\n{{type:Back}}\x12({{Front}}\n\n<hr id=answer>\n\n{{type:Back}}'},
71
+ {'ntid': 5, 'ord': 0, 'name': 'Cloze', 'mtime_secs': 0, 'usn': 0, 'config': b'\n\x0e{{cloze:Text}}\x12!{{cloze:Text}}<br>\n{{Back Extra}}'},
72
+ {'ntid': 6, 'ord': 0, 'name': 'Image Occlusion', 'mtime_secs': 0, 'usn': 0, 'config': b'\n\xae\x03{{#Header}}<div>{{Header}}</div>{{/Header}}\n<div style="display: none">{{cloze:Occlusion}}</div>\n<div id="err"></div>\n<div id="image-occlusion-container">\n {{Image}}\n <canvas id="image-occlusion-canvas"></canvas>\n</div>\n<script>\ntry {\n anki.imageOcclusion.setup();\n} catch (exc) {\n document.getElementById("err").innerHTML = `Error loading image occlusion. Is your Anki version up to date?<br><br>${exc}`;\n}\n</script>\n\x12\x9c\x04{{#Header}}<div>{{Header}}</div>{{/Header}}\n<div style="display: none">{{cloze:Occlusion}}</div>\n<div id="err"></div>\n<div id="image-occlusion-container">\n {{Image}}\n <canvas id="image-occlusion-canvas"></canvas>\n</div>\n<script>\ntry {\n anki.imageOcclusion.setup();\n} catch (exc) {\n document.getElementById("err").innerHTML = `Error loading image occlusion. Is your Anki version up to date?<br><br>${exc}`;\n}\n</script>\n\n<div><button id="toggle">Toggle Masks</button></div>\n{{#Back Extra}}<div>{{Back Extra}}</div>{{/Back Extra}}\n'},
73
+ ]
74
+
75
+ # ========= TABLE notetypes =========
76
+ table_notetypes = [
77
+ {'id': 1, 'name': 'Basic (genanki2)', 'mtime_secs': 0, 'usn': 0, 'config': b'\x1a\x94\x01.card {\n font-family: arial;\n font-size: 20px;\n line-height: 1.5;\n text-align: center;\n color: black;\n background-color: white;\n}\n*\xb2\x01\\documentclass[12pt]{article}\n\\special{papersize=3in,5in}\n\\usepackage[utf8]{inputenc}\n\\usepackage{amssymb,amsmath}\n\\pagestyle{empty}\n\\setlength{\\parindent}{0in}\n\\begin{document}\n2\x0e\\end{document}B\x05\x10\x01\x1a\x01\x00H\x01'},
78
+ {'id': 2, 'name': 'Basic (and reversed card) (genanki2)', 'mtime_secs': 0, 'usn': 0, 'config': b'\x1a\x94\x01.card {\n font-family: arial;\n font-size: 20px;\n line-height: 1.5;\n text-align: center;\n color: black;\n background-color: white;\n}\n*\xb2\x01\\documentclass[12pt]{article}\n\\special{papersize=3in,5in}\n\\usepackage[utf8]{inputenc}\n\\usepackage{amssymb,amsmath}\n\\pagestyle{empty}\n\\setlength{\\parindent}{0in}\n\\begin{document}\n2\x0e\\end{document}B\x05\x10\x01\x1a\x01\x00B\x07\x08\x01\x10\x01\x1a\x01\x01H\x02'},
79
+ {'id': 3, 'name': 'Basic (optional reversed card) (genanki2)', 'mtime_secs': 0, 'usn': 0, 'config': b'\x1a\x94\x01.card {\n font-family: arial;\n font-size: 20px;\n line-height: 1.5;\n text-align: center;\n color: black;\n background-color: white;\n}\n*\xb2\x01\\documentclass[12pt]{article}\n\\special{papersize=3in,5in}\n\\usepackage[utf8]{inputenc}\n\\usepackage{amssymb,amsmath}\n\\pagestyle{empty}\n\\setlength{\\parindent}{0in}\n\\begin{document}\n2\x0e\\end{document}B\x05\x10\x01\x1a\x01\x00B\x08\x08\x01\x10\x02\x1a\x02\x01\x02H\x03'},
80
+ {'id': 4, 'name': 'Basic (type in the answer) (genanki2)', 'mtime_secs': 0, 'usn': 0, 'config': b'\x1a\x94\x01.card {\n font-family: arial;\n font-size: 20px;\n line-height: 1.5;\n text-align: center;\n color: black;\n background-color: white;\n}\n*\xb2\x01\\documentclass[12pt]{article}\n\\special{papersize=3in,5in}\n\\usepackage[utf8]{inputenc}\n\\usepackage{amssymb,amsmath}\n\\pagestyle{empty}\n\\setlength{\\parindent}{0in}\n\\begin{document}\n2\x0e\\end{document}B\x06\x10\x01\x1a\x02\x00\x01H\x04'},
81
+ {'id': 5, 'name': 'Cloze (genanki2)', 'mtime_secs': 0, 'usn': 0, 'config': b'\x08\x01\x1a\xf3\x01.card {\n font-family: arial;\n font-size: 20px;\n line-height: 1.5;\n text-align: center;\n color: black;\n background-color: white;\n}\n.cloze {\n font-weight: bold;\n color: blue;\n}\n.nightMode .cloze {\n color: lightblue;\n}\n*\xb2\x01\\documentclass[12pt]{article}\n\\special{papersize=3in,5in}\n\\usepackage[utf8]{inputenc}\n\\usepackage{amssymb,amsmath}\n\\pagestyle{empty}\n\\setlength{\\parindent}{0in}\n\\begin{document}\n2\x0e\\end{document}B\x05\x10\x01\x1a\x01\x00H\x05'},
82
+ {'id': 6, 'name': 'Image Occlusion (genanki2)', 'mtime_secs': 0, 'usn': 0, 'config': b'\x08\x01\x1a\x88\x03#image-occlusion-canvas {\n --inactive-shape-color: #ffeba2;\n --active-shape-color: #ff8e8e;\n --inactive-shape-border: 1px #212121;\n --active-shape-border: 1px #212121;\n --highlight-shape-color: #ff8e8e00;\n --highlight-shape-border: 1px #ff8e8e;\n}\n\n.card {\n font-family: arial;\n font-size: 20px;\n text-align: center;\n color: black;\n background-color: white;\n}\n*\xb2\x01\\documentclass[12pt]{article}\n\\special{papersize=3in,5in}\n\\usepackage[utf8]{inputenc}\n\\usepackage{amssymb,amsmath}\n\\pagestyle{empty}\n\\setlength{\\parindent}{0in}\n\\begin{document}\n2\x0e\\end{document}B\x07\x10\x01\x1a\x03\x00\x01\x02H\x06'},
83
+ ]
84
+
85
+ # ========= TABLE decks =========
86
+ table_decks = [
87
+ {'id': 1, 'name': 'Default', 'mtime_secs': 0, 'usn': 0, 'common': b'\x08\x01\x10\x01', 'kind': b'\n\x02\x08\x01'},
88
+ ]
89
+
90
+ # ========= TABLE tags =========
91
+ table_tags = []
92
+
93
+ # ========= TABLE graves =========
94
+ table_graves = []
Binary file
@@ -0,0 +1,94 @@
1
+ """Anki's protobuf definitions, as message classes.
2
+
3
+ A v18 collection stores several columns as serialized protobuf: the three notetype
4
+ configurations, a deck's `common` and `kind`, and a deck preset's `config`. A package
5
+ adds two more, the `meta` entry and the media map.
6
+
7
+ The definitions come from `descriptors.binpb`, written by
8
+ scripts/dump_proto_descriptors.py, and are loaded into a private descriptor pool.
9
+ The pool is private because protobuf's default one is process-wide and keyed by
10
+ proto file name: a second registration of `anki/notetypes.proto` is aliased to the
11
+ first, so with the `anki` package installed as a test oracle, whichever import ran
12
+ first would decide which definitions everything else sees.
13
+
14
+ The definitions are Anki's, Copyright Ankitects Pty Ltd and contributors, licensed
15
+ under the GNU AGPL, version 3 or later.
16
+ """
17
+
18
+ from importlib import resources
19
+
20
+ from google.protobuf.descriptor import Descriptor
21
+ from google.protobuf.descriptor_pb2 import FileDescriptorSet
22
+ from google.protobuf.descriptor_pool import DescriptorPool
23
+ from google.protobuf.message import Message
24
+ from google.protobuf.message_factory import GetMessageClass
25
+
26
+ __all__ = [
27
+ "CardRequirement",
28
+ "DayLimit",
29
+ "DeckCommon",
30
+ "DeckConfigConfig",
31
+ "DeckFiltered",
32
+ "DeckKindContainer",
33
+ "DeckNormal",
34
+ "FieldConfig",
35
+ "MediaEntries",
36
+ "MediaEntry",
37
+ "NotetypeConfig",
38
+ "PackageMetadata",
39
+ "SearchTerm",
40
+ "TemplateConfig",
41
+ ]
42
+
43
+
44
+ def _descriptor_set() -> FileDescriptorSet:
45
+ """Parse the vendored `descriptors.binpb`."""
46
+ descriptors_path = resources.files(__name__).joinpath("descriptors.binpb")
47
+ return FileDescriptorSet.FromString(descriptors_path.read_bytes())
48
+
49
+
50
+ def _pool() -> DescriptorPool:
51
+ """Return a descriptor pool holding the vendored definitions.
52
+
53
+ Files are added in the order the dump wrote them, which is imports first, because a
54
+ pool refuses a file whose imports it has not been given yet.
55
+ """
56
+ pool: DescriptorPool = DescriptorPool()
57
+ for file_descriptor in _descriptor_set().file:
58
+ pool.Add(file_descriptor)
59
+ return pool
60
+
61
+
62
+ def _set_module(descriptor: Descriptor) -> None:
63
+ """Set `__module__` on the Message type and on any nested type.
64
+
65
+ Pydantic `BaseModel.model_validate(..., from_attributes=True)` fails without
66
+ `__module__` set.
67
+ """
68
+ GetMessageClass(descriptor).__module__ = __name__
69
+ for nested in descriptor.nested_types:
70
+ _set_module(nested)
71
+
72
+
73
+ def _message(name: str) -> type[Message]:
74
+ """Return the message class registered under `name`."""
75
+ message = GetMessageClass(_POOL.FindMessageTypeByName(name))
76
+ _set_module(message.DESCRIPTOR) # pyright: ignore[reportArgumentType]
77
+ return message
78
+
79
+
80
+ _POOL = _pool()
81
+ FieldConfig = _message("anki.notetypes.Notetype.Field.Config")
82
+ TemplateConfig = _message("anki.notetypes.Notetype.Template.Config")
83
+ NotetypeConfig = _message("anki.notetypes.Notetype.Config")
84
+ CardRequirement = _message("anki.notetypes.Notetype.Config.CardRequirement")
85
+ DeckConfigConfig = _message("anki.deck_config.DeckConfig.Config")
86
+ DeckCommon = _message("anki.decks.Deck.Common")
87
+ DeckKindContainer = _message("anki.decks.Deck.KindContainer")
88
+ DeckNormal = _message("anki.decks.Deck.Normal")
89
+ DayLimit = _message("anki.decks.Deck.Normal.DayLimit")
90
+ DeckFiltered = _message("anki.decks.Deck.Filtered")
91
+ SearchTerm = _message("anki.decks.Deck.Filtered.SearchTerm")
92
+ MediaEntries = _message("anki.import_export.MediaEntries")
93
+ MediaEntry = _message("anki.import_export.MediaEntries.MediaEntry")
94
+ PackageMetadata = _message("anki.import_export.PackageMetadata")
Binary file
genanki2/_schema.py ADDED
@@ -0,0 +1,167 @@
1
+ # Generated by scripts/dump_anki_schema.py, do not edit.
2
+ # anki 26.08, collection schema version 18
3
+
4
+ SCHEMA = """
5
+ CREATE TABLE cards (
6
+ id integer PRIMARY KEY,
7
+ nid integer NOT NULL,
8
+ did integer NOT NULL,
9
+ ord integer NOT NULL,
10
+ mod integer NOT NULL,
11
+ usn integer NOT NULL,
12
+ type integer NOT NULL,
13
+ queue integer NOT NULL,
14
+ due integer NOT NULL,
15
+ ivl integer NOT NULL,
16
+ factor integer NOT NULL,
17
+ reps integer NOT NULL,
18
+ lapses integer NOT NULL,
19
+ left integer NOT NULL,
20
+ odue integer NOT NULL,
21
+ odid integer NOT NULL,
22
+ flags integer NOT NULL,
23
+ data text NOT NULL
24
+ );
25
+
26
+ CREATE TABLE col (
27
+ id integer PRIMARY KEY,
28
+ crt integer NOT NULL,
29
+ mod integer NOT NULL,
30
+ scm integer NOT NULL,
31
+ ver integer NOT NULL,
32
+ dty integer NOT NULL,
33
+ usn integer NOT NULL,
34
+ ls integer NOT NULL,
35
+ conf text NOT NULL,
36
+ models text NOT NULL,
37
+ decks text NOT NULL,
38
+ dconf text NOT NULL,
39
+ tags text NOT NULL
40
+ );
41
+
42
+ CREATE TABLE config (
43
+ KEY text NOT NULL PRIMARY KEY,
44
+ usn integer NOT NULL,
45
+ mtime_secs integer NOT NULL,
46
+ val blob NOT NULL
47
+ ) without rowid;
48
+
49
+ CREATE TABLE deck_config (
50
+ id integer PRIMARY KEY NOT NULL,
51
+ name text NOT NULL COLLATE unicase,
52
+ mtime_secs integer NOT NULL,
53
+ usn integer NOT NULL,
54
+ config blob NOT NULL
55
+ );
56
+
57
+ CREATE TABLE decks (
58
+ id integer PRIMARY KEY NOT NULL,
59
+ name text NOT NULL COLLATE unicase,
60
+ mtime_secs integer NOT NULL,
61
+ usn integer NOT NULL,
62
+ common blob NOT NULL,
63
+ kind blob NOT NULL
64
+ );
65
+
66
+ CREATE TABLE fields (
67
+ ntid integer NOT NULL,
68
+ ord integer NOT NULL,
69
+ name text NOT NULL COLLATE unicase,
70
+ config blob NOT NULL,
71
+ PRIMARY KEY (ntid, ord)
72
+ ) without rowid;
73
+
74
+ CREATE TABLE graves (
75
+ oid integer NOT NULL,
76
+ type integer NOT NULL,
77
+ usn integer NOT NULL,
78
+ PRIMARY KEY (oid, type)
79
+ ) WITHOUT ROWID;
80
+
81
+ CREATE TABLE notes (
82
+ id integer PRIMARY KEY,
83
+ guid text NOT NULL,
84
+ mid integer NOT NULL,
85
+ mod integer NOT NULL,
86
+ usn integer NOT NULL,
87
+ tags text NOT NULL,
88
+ flds text NOT NULL,
89
+ -- The use of type integer for sfld is deliberate, because it means that integer values in this
90
+ -- field will sort numerically.
91
+ sfld integer NOT NULL,
92
+ csum integer NOT NULL,
93
+ flags integer NOT NULL,
94
+ data text NOT NULL
95
+ );
96
+
97
+ CREATE TABLE notetypes (
98
+ id integer NOT NULL PRIMARY KEY,
99
+ name text NOT NULL COLLATE unicase,
100
+ mtime_secs integer NOT NULL,
101
+ usn integer NOT NULL,
102
+ config blob NOT NULL
103
+ );
104
+
105
+ CREATE TABLE revlog (
106
+ id integer PRIMARY KEY,
107
+ cid integer NOT NULL,
108
+ usn integer NOT NULL,
109
+ ease integer NOT NULL,
110
+ ivl integer NOT NULL,
111
+ lastIvl integer NOT NULL,
112
+ factor integer NOT NULL,
113
+ time integer NOT NULL,
114
+ type integer NOT NULL
115
+ );
116
+
117
+ CREATE TABLE tags (
118
+ tag text NOT NULL PRIMARY KEY COLLATE unicase,
119
+ usn integer NOT NULL,
120
+ collapsed boolean NOT NULL,
121
+ config blob NULL
122
+ ) without rowid;
123
+
124
+ CREATE TABLE templates (
125
+ ntid integer NOT NULL,
126
+ ord integer NOT NULL,
127
+ name text NOT NULL COLLATE unicase,
128
+ mtime_secs integer NOT NULL,
129
+ usn integer NOT NULL,
130
+ config blob NOT NULL,
131
+ PRIMARY KEY (ntid, ord)
132
+ ) without rowid;
133
+
134
+ CREATE INDEX idx_cards_odid ON cards (odid)
135
+ WHERE odid != 0;
136
+
137
+ CREATE UNIQUE INDEX idx_decks_name ON decks (name);
138
+
139
+ CREATE UNIQUE INDEX idx_fields_name_ntid ON fields (name, ntid);
140
+
141
+ CREATE INDEX idx_graves_pending ON graves (usn);
142
+
143
+ CREATE INDEX idx_notes_mid ON notes (mid);
144
+
145
+ CREATE UNIQUE INDEX idx_notetypes_name ON notetypes (name);
146
+
147
+ CREATE INDEX idx_notetypes_usn ON notetypes (usn);
148
+
149
+ CREATE UNIQUE INDEX idx_templates_name_ntid ON templates (name, ntid);
150
+
151
+ CREATE INDEX idx_templates_usn ON templates (usn);
152
+
153
+ CREATE INDEX ix_cards_nid ON cards (nid);
154
+
155
+ CREATE INDEX ix_cards_sched ON cards (did, queue, due);
156
+
157
+ CREATE INDEX ix_cards_usn ON cards (usn);
158
+
159
+ CREATE INDEX ix_notes_csum ON notes (csum);
160
+
161
+ CREATE INDEX ix_notes_usn ON notes (usn);
162
+
163
+ CREATE INDEX ix_revlog_cid ON revlog (cid);
164
+
165
+ CREATE INDEX ix_revlog_usn ON revlog (usn);
166
+
167
+ """
@@ -0,0 +1,145 @@
1
+ # Generated by scripts/dump_anki_schema_as_typed_dicts.py, do not edit.
2
+ # anki 26.09.2, collection schema version 18
3
+
4
+ from collections.abc import Sequence
5
+ from typing import TypeAlias
6
+
7
+ from typing_extensions import TypedDict
8
+
9
+
10
+ class ColRow(TypedDict):
11
+ id: int
12
+ crt: int
13
+ mod: int
14
+ scm: int
15
+ ver: int
16
+ dty: int
17
+ usn: int
18
+ ls: int
19
+ conf: str
20
+ models: str
21
+ decks: str
22
+ dconf: str
23
+ tags: str
24
+
25
+
26
+ class NoteRow(TypedDict):
27
+ id: int
28
+ guid: str
29
+ mid: int
30
+ mod: int
31
+ usn: int
32
+ tags: str
33
+ flds: str
34
+ sfld: str
35
+ csum: int
36
+ flags: int
37
+ data: str
38
+
39
+
40
+ class CardRow(TypedDict):
41
+ id: int
42
+ nid: int
43
+ did: int
44
+ ord: int
45
+ mod: int
46
+ usn: int
47
+ type: int
48
+ queue: int
49
+ due: int
50
+ ivl: int
51
+ factor: int
52
+ reps: int
53
+ lapses: int
54
+ left: int
55
+ odue: int
56
+ odid: int
57
+ flags: int
58
+ data: str
59
+
60
+
61
+ class RevlogRow(TypedDict):
62
+ id: int
63
+ cid: int
64
+ usn: int
65
+ ease: int
66
+ ivl: int
67
+ lastIvl: int
68
+ factor: int
69
+ time: int
70
+ type: int
71
+
72
+
73
+ class DeckConfigRow(TypedDict):
74
+ id: int
75
+ name: str
76
+ mtime_secs: int
77
+ usn: int
78
+ config: bytes
79
+
80
+
81
+ class ConfigRow(TypedDict):
82
+ KEY: str
83
+ usn: int
84
+ mtime_secs: int
85
+ val: bytes
86
+
87
+
88
+ class FieldRow(TypedDict):
89
+ ntid: int
90
+ ord: int
91
+ name: str
92
+ config: bytes
93
+
94
+
95
+ class TemplateRow(TypedDict):
96
+ ntid: int
97
+ ord: int
98
+ name: str
99
+ mtime_secs: int
100
+ usn: int
101
+ config: bytes
102
+
103
+
104
+ class NotetypeRow(TypedDict):
105
+ id: int
106
+ name: str
107
+ mtime_secs: int
108
+ usn: int
109
+ config: bytes
110
+
111
+
112
+ class DeckRow(TypedDict):
113
+ id: int
114
+ name: str
115
+ mtime_secs: int
116
+ usn: int
117
+ common: bytes
118
+ kind: bytes
119
+
120
+
121
+ class TagRow(TypedDict):
122
+ tag: str
123
+ usn: int
124
+ collapsed: int
125
+ config: bytes | None
126
+
127
+
128
+ class GraveRow(TypedDict):
129
+ oid: int
130
+ type: int
131
+ usn: int
132
+
133
+
134
+ ColRows: TypeAlias = Sequence[ColRow]
135
+ NoteRows: TypeAlias = Sequence[NoteRow]
136
+ CardRows: TypeAlias = Sequence[CardRow]
137
+ RevlogRows: TypeAlias = Sequence[RevlogRow]
138
+ DeckConfigRows: TypeAlias = Sequence[DeckConfigRow]
139
+ ConfigRows: TypeAlias = Sequence[ConfigRow]
140
+ FieldRows: TypeAlias = Sequence[FieldRow]
141
+ TemplateRows: TypeAlias = Sequence[TemplateRow]
142
+ NotetypeRows: TypeAlias = Sequence[NotetypeRow]
143
+ DeckRows: TypeAlias = Sequence[DeckRow]
144
+ TagRows: TypeAlias = Sequence[TagRow]
145
+ GraveRows: TypeAlias = Sequence[GraveRow]