ankigammon 1.0.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.

Potentially problematic release.


This version of ankigammon might be problematic. Click here for more details.

Files changed (56) hide show
  1. ankigammon/__init__.py +7 -0
  2. ankigammon/__main__.py +6 -0
  3. ankigammon/analysis/__init__.py +13 -0
  4. ankigammon/analysis/score_matrix.py +373 -0
  5. ankigammon/anki/__init__.py +6 -0
  6. ankigammon/anki/ankiconnect.py +224 -0
  7. ankigammon/anki/apkg_exporter.py +123 -0
  8. ankigammon/anki/card_generator.py +1307 -0
  9. ankigammon/anki/card_styles.py +1034 -0
  10. ankigammon/gui/__init__.py +8 -0
  11. ankigammon/gui/app.py +209 -0
  12. ankigammon/gui/dialogs/__init__.py +10 -0
  13. ankigammon/gui/dialogs/export_dialog.py +597 -0
  14. ankigammon/gui/dialogs/import_options_dialog.py +163 -0
  15. ankigammon/gui/dialogs/input_dialog.py +776 -0
  16. ankigammon/gui/dialogs/note_dialog.py +93 -0
  17. ankigammon/gui/dialogs/settings_dialog.py +384 -0
  18. ankigammon/gui/format_detector.py +292 -0
  19. ankigammon/gui/main_window.py +1071 -0
  20. ankigammon/gui/resources/icon.icns +0 -0
  21. ankigammon/gui/resources/icon.ico +0 -0
  22. ankigammon/gui/resources/icon.png +0 -0
  23. ankigammon/gui/resources/style.qss +394 -0
  24. ankigammon/gui/resources.py +26 -0
  25. ankigammon/gui/widgets/__init__.py +8 -0
  26. ankigammon/gui/widgets/position_list.py +193 -0
  27. ankigammon/gui/widgets/smart_input.py +268 -0
  28. ankigammon/models.py +322 -0
  29. ankigammon/parsers/__init__.py +7 -0
  30. ankigammon/parsers/gnubg_parser.py +454 -0
  31. ankigammon/parsers/xg_binary_parser.py +870 -0
  32. ankigammon/parsers/xg_text_parser.py +729 -0
  33. ankigammon/renderer/__init__.py +5 -0
  34. ankigammon/renderer/animation_controller.py +406 -0
  35. ankigammon/renderer/animation_helper.py +221 -0
  36. ankigammon/renderer/color_schemes.py +145 -0
  37. ankigammon/renderer/svg_board_renderer.py +824 -0
  38. ankigammon/settings.py +239 -0
  39. ankigammon/thirdparty/__init__.py +7 -0
  40. ankigammon/thirdparty/xgdatatools/__init__.py +17 -0
  41. ankigammon/thirdparty/xgdatatools/xgimport.py +160 -0
  42. ankigammon/thirdparty/xgdatatools/xgstruct.py +1032 -0
  43. ankigammon/thirdparty/xgdatatools/xgutils.py +118 -0
  44. ankigammon/thirdparty/xgdatatools/xgzarc.py +260 -0
  45. ankigammon/utils/__init__.py +13 -0
  46. ankigammon/utils/gnubg_analyzer.py +431 -0
  47. ankigammon/utils/gnuid.py +622 -0
  48. ankigammon/utils/move_parser.py +239 -0
  49. ankigammon/utils/ogid.py +335 -0
  50. ankigammon/utils/xgid.py +419 -0
  51. ankigammon-1.0.0.dist-info/METADATA +370 -0
  52. ankigammon-1.0.0.dist-info/RECORD +56 -0
  53. ankigammon-1.0.0.dist-info/WHEEL +5 -0
  54. ankigammon-1.0.0.dist-info/entry_points.txt +2 -0
  55. ankigammon-1.0.0.dist-info/licenses/LICENSE +21 -0
  56. ankigammon-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,118 @@
1
+ #
2
+ # xgutils.py - XG related utility functions
3
+ # Copyright (C) 2013 Michael Petch <mpetch@gnubg.org>
4
+ # <mpetch@capp-sysware.com>
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ #
20
+
21
+ import sys as _sys
22
+ import zlib as _zlib
23
+ import datetime as _datetime
24
+
25
+
26
+ def streamcrc32(stream, numbytes=None, startpos=None, blksize=32768):
27
+ """Compute the CRC32 on a given stream. Restore the original
28
+ position in the stream upon finishing. Process the stream in
29
+ chunks defined by blksize
30
+ """
31
+
32
+ crc32 = 0
33
+ curstreampos = stream.tell()
34
+
35
+ if startpos is not None:
36
+ stream.seek(startpos, 0)
37
+
38
+ if numbytes is None:
39
+ block = stream.read(blksize)
40
+ while len(block) > 0:
41
+ crc32 = _zlib.crc32(block, crc32)
42
+ block = stream.read(blksize)
43
+ else:
44
+ bytesleft = numbytes
45
+ while True:
46
+ if bytesleft < blksize:
47
+ blksize = bytesleft
48
+
49
+ block = stream.read(blksize)
50
+ crc32 = _zlib.crc32(block, crc32)
51
+ bytesleft = bytesleft - blksize
52
+
53
+ if bytesleft == 0:
54
+ break
55
+
56
+ stream.seek(curstreampos)
57
+ return crc32 & 0xffffffff
58
+
59
+
60
+ def utf16intarraytostr3x(intarray):
61
+ """Python 3.x - Convert an array of integers (UTF16) to a
62
+ string. Input array is null terminated.
63
+ """
64
+ newstr = []
65
+ for intval in intarray:
66
+ if intval == 0:
67
+ break
68
+ newstr += [chr(intval).encode('utf-8')]
69
+
70
+ return (b''.join([x for x in newstr]))
71
+
72
+
73
+ def utf16intarraytostr2x(intarray):
74
+ """Python 2.x - Convert an array of integers (UTF16) to a
75
+ string. Input array is null terminated.
76
+ """
77
+ newstr = []
78
+ for intval in intarray:
79
+ if intval == 0:
80
+ break
81
+ newstr += [unichr(intval).encode('utf-8')]
82
+
83
+ return ''.join(newstr)
84
+
85
+ def delphidatetimeconv(delphi_datetime):
86
+ """Convert a double float Delphi style timedate object to a Python
87
+ datetime object. Delphi uses the number of days since
88
+ Dec 30th, 1899 in the whole number component. The fractional
89
+ component represents the fraction of a day (multiply by 86400
90
+ to translate to seconds)
91
+ """
92
+
93
+ delta = _datetime.timedelta(
94
+ days=int(delphi_datetime),
95
+ seconds=int(86400 * (delphi_datetime % 1)))
96
+ return _datetime.datetime(1899, 12, 30) + delta
97
+
98
+
99
+ def delphishortstrtostr(shortstring_abytes):
100
+ """Convert Delphi Pascal style shortstring to a Python string.
101
+ shortstring is a single byte (length of string) followed by
102
+ length number of bytes. shortstrings are not null terminated.
103
+ """
104
+
105
+ return ''.join([chr(char) for char in
106
+ shortstring_abytes[1:(shortstring_abytes[0] + 1)]])
107
+
108
+
109
+ if __name__ == '__main__':
110
+ pass
111
+ else:
112
+ # Map the utf16intarraytostr function depending on whether
113
+ # we are using Python 3.x or 2.x
114
+ if _sys.version_info >= (3, 0):
115
+ utf16intarraytostr = utf16intarraytostr3x
116
+ else:
117
+ utf16intarraytostr = utf16intarraytostr2x
118
+
@@ -0,0 +1,260 @@
1
+ #
2
+ # xgzarc.py - XG ZLib archive module
3
+ # Copyright (C) 2013,2014 Michael Petch <mpetch@gnubg.org>
4
+ # <mpetch@capp-sysware.com>
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ #
20
+ # This library is an interpretation of ZLBArchive 1.52 data structures.
21
+ # Please see: http://www.delphipages.com/comp/zlibarchive-2104.html
22
+ #
23
+
24
+ from __future__ import with_statement as _with
25
+ import tempfile as _tempfile
26
+ import struct as _struct
27
+ import zlib as _zlib
28
+ import os as _os
29
+ from . import xgutils as _xgutils
30
+
31
+
32
+ class Error(Exception):
33
+
34
+ def __init__(self, error):
35
+ self.value = "Zlib archive: %s" % str(error)
36
+ self.error = error
37
+
38
+ def __str__(self):
39
+ return repr(self.value)
40
+
41
+
42
+ class ArchiveRecord(dict):
43
+
44
+ SIZEOFREC = 36
45
+
46
+ def __init__(self, **kw):
47
+ defaults = {
48
+ 'crc': 0,
49
+ 'filecount': 0,
50
+ 'version': 0,
51
+ 'registrysize': 0,
52
+ 'archivesize': 0,
53
+ 'compressedregistry': False,
54
+ 'reserved': []
55
+ }
56
+ super(ArchiveRecord, self).__init__(defaults, **kw)
57
+
58
+ def __setattr__(self, key, value):
59
+ self[key] = value
60
+
61
+ def __getattr__(self, key):
62
+ return self[key]
63
+
64
+ def fromstream(self, stream):
65
+ unpacked_data = _struct.unpack('<llllll12B',
66
+ stream.read(self.SIZEOFREC))
67
+ self.crc = unpacked_data[0] & 0xffffffff
68
+ self.filecount = unpacked_data[1]
69
+ self.version = unpacked_data[2]
70
+ self.registrysize = unpacked_data[3]
71
+ self.archivesize = unpacked_data[4]
72
+ self.compressedregistry = bool(unpacked_data[5])
73
+ self.reserved = unpacked_data[6:]
74
+
75
+
76
+ class FileRecord(dict):
77
+
78
+ SIZEOFREC = 532
79
+
80
+ def __init__(self, **kw):
81
+ defaults = {
82
+ 'name': None,
83
+ 'path': None,
84
+ 'osize': 0,
85
+ 'csize': 0,
86
+ 'start': 0,
87
+ 'crc': 0,
88
+ 'compressed': False,
89
+ 'stored': False,
90
+ 'compressionlevel': 0
91
+ }
92
+ super(FileRecord, self).__init__(defaults, **kw)
93
+
94
+ def __setattr__(self, key, value):
95
+ self[key] = value
96
+
97
+ def __getattr__(self, key):
98
+ return self[key]
99
+
100
+ def fromstream(self, stream):
101
+ unpacked_data = _struct.unpack('<256B256BllllBBxx',
102
+ stream.read(self.SIZEOFREC))
103
+ self.name = _xgutils.delphishortstrtostr(unpacked_data[0:256])
104
+ self.path = _xgutils.delphishortstrtostr(unpacked_data[256:512])
105
+ self.osize = unpacked_data[512]
106
+ self.csize = unpacked_data[513]
107
+ self.start = unpacked_data[514]
108
+ self.crc = unpacked_data[515] & 0xffffffff
109
+ self.compressed = bool(unpacked_data[516] == 0)
110
+ self.compressionlevel = unpacked_data[517]
111
+
112
+ def __str__(self):
113
+ return str(self.todict())
114
+
115
+
116
+ class ZlibArchive(object):
117
+ __MAXBUFSIZE = 32768
118
+ __TMP_PREFIX = 'tmpXGI'
119
+
120
+ def __init__(self, stream=None, filename=None):
121
+ self.arcrec = ArchiveRecord()
122
+ self.arcregistry = []
123
+ self.startofarcdata = -1
124
+ self.endofarcdata = -1
125
+
126
+ self.filename = filename
127
+ self.stream = stream
128
+ if stream is None:
129
+ self.stream = open(filename, 'rb')
130
+
131
+ self.__getarchiveindex()
132
+
133
+ def __extractsegment(self, iscompressed=True, numbytes=None):
134
+ # Extract a stored segment
135
+ filename = None
136
+ stream = []
137
+
138
+ try:
139
+ tmpfd, filename = _tempfile.mkstemp(prefix=self.__TMP_PREFIX)
140
+ with _os.fdopen(tmpfd, "wb") as tmpfile:
141
+
142
+ if (iscompressed):
143
+ # Extract a compressed segment
144
+ decomp = _zlib.decompressobj()
145
+ buf = self.stream.read(self.__MAXBUFSIZE)
146
+ stream = decomp.decompress(buf)
147
+
148
+ if len(stream) <= 0:
149
+ raise IOError()
150
+
151
+ tmpfile.write(stream)
152
+
153
+ # Read until we have uncompressed a complete segment
154
+ while len(decomp.unused_data) == 0:
155
+ block = self.stream.read(self.__MAXBUFSIZE)
156
+ if len(block) > 0:
157
+ try:
158
+ stream = decomp.decompress(block)
159
+ tmpfile.write(stream)
160
+ except:
161
+ break
162
+ else:
163
+ # EOF reached
164
+ break
165
+
166
+ else:
167
+ # Extract an uncompressed segment
168
+ # Uncompressed segment needs numbytes specified
169
+ if numbytes is None:
170
+ raise IOError()
171
+
172
+ blksize = self.__MAXBUFSIZE
173
+ bytesleft = numbytes
174
+ while True:
175
+ if bytesleft < blksize:
176
+ blksize = bytesleft
177
+
178
+ block = self.stream.read(blksize)
179
+ tmpfile.write(block)
180
+ bytesleft = bytesleft - blksize
181
+
182
+ if bytesleft == 0:
183
+ break
184
+
185
+ except (_zlib.error, IOError) as e:
186
+ _os.unlink(filename)
187
+ return None
188
+
189
+ return filename
190
+
191
+ def __getarchiveindex(self):
192
+
193
+ try:
194
+ # Advance to the archive record at the end and retrieve it
195
+ filerecords = []
196
+ curstreampos = self.stream.tell()
197
+
198
+ self.stream.seek(-ArchiveRecord.SIZEOFREC, _os.SEEK_END)
199
+ self.endofarcdata = self.stream.tell()
200
+ self.arcrec.fromstream(self.stream)
201
+
202
+ # Position ourselves at the beginning of the archive file index
203
+ self.stream.seek(-ArchiveRecord.SIZEOFREC -
204
+ self.arcrec.registrysize, _os.SEEK_END)
205
+ self.startofarcdata = self.stream.tell() - self.arcrec.archivesize
206
+
207
+ # Compute the CRC32 of all the archive data including file index
208
+ streamcrc = _xgutils.streamcrc32(
209
+ self.stream,
210
+ startpos=self.startofarcdata,
211
+ numbytes=(self.endofarcdata - self.startofarcdata))
212
+ if streamcrc != self.arcrec.crc:
213
+ raise Error("Archive CRC check failed - file corrupt")
214
+
215
+ # Decompress the index into a temporary file
216
+ idx_filename = self.__extractsegment(
217
+ iscompressed=self.arcrec.compressedregistry)
218
+ if idx_filename is None:
219
+ raise Error("Error extracting archive index")
220
+
221
+ # Retrieve all the files in the index
222
+ with open(idx_filename, "rb") as idx_file:
223
+ for recordnum in range(0, self.arcrec.filecount):
224
+ curidxpos = self.stream.tell()
225
+
226
+ # Retrieve next file index record
227
+ filerec = FileRecord()
228
+ filerec.fromstream(idx_file)
229
+ filerecords.append(filerec)
230
+
231
+ self.stream.seek(curidxpos, 0)
232
+
233
+ _os.unlink(idx_filename)
234
+ finally:
235
+ self.stream.seek(curstreampos, 0)
236
+
237
+ self.arcregistry = filerecords
238
+
239
+ def getarchivefile(self, filerec):
240
+ # Do processing on the temporary file
241
+ self.stream.seek(filerec.start + self.startofarcdata)
242
+ tmpfilename = self.__extractsegment(iscompressed=filerec.compressed,
243
+ numbytes=filerec.csize)
244
+ if tmpfilename is None:
245
+ raise Error("Error extracting archived file")
246
+ tmpfile = open(tmpfilename, "rb")
247
+
248
+ # Compute the CRC32 on the uncompressed file
249
+ streamcrc = _xgutils.streamcrc32(tmpfile)
250
+ if streamcrc != filerec.crc:
251
+ raise Error("File CRC check failed - file corrupt")
252
+
253
+ return tmpfile, tmpfilename
254
+
255
+ def setblocksize(self, blksize):
256
+ self.__MAXBUFSIZE = blksize
257
+
258
+
259
+ if __name__ == '__main__':
260
+ pass
@@ -0,0 +1,13 @@
1
+ """Utility functions."""
2
+
3
+ from ankigammon.utils.move_parser import MoveParser
4
+ from ankigammon.utils.xgid import parse_xgid, encode_xgid
5
+ from ankigammon.utils.ogid import parse_ogid, encode_ogid
6
+ from ankigammon.utils.gnuid import parse_gnuid, encode_gnuid
7
+
8
+ __all__ = [
9
+ "MoveParser",
10
+ "parse_xgid", "encode_xgid",
11
+ "parse_ogid", "encode_ogid",
12
+ "parse_gnuid", "encode_gnuid",
13
+ ]